diff --git a/CMakeLists.txt b/CMakeLists.txt index 0045a41b1..54a4be19a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,8 @@ cmake_minimum_required(VERSION 2.8.9) IF(WIN32) - # In Qt 5.1+ we have our own main() function, don't autolink to qtmain on Windows - cmake_policy(SET CMP0020 OLD) + # In Qt 5.1+ we have our own main() function, don't autolink to qtmain on Windows + cmake_policy(SET CMP0020 OLD) ENDIF() project(MultiMC) @@ -22,22 +22,22 @@ SET(MMC_BIN "${PROJECT_BINARY_DIR}") SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) IF(UNIX) - SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) + SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) ENDIF() set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${PROJECT_BINARY_DIR}/jars) ######## Set compiler flags ######## IF(APPLE) - message(STATUS "Using APPLE CMAKE_CXX_FLAGS") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall") + message(STATUS "Using APPLE CMAKE_CXX_FLAGS") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall") ELSEIF(UNIX) - # assume GCC, add C++0x/C++11 stuff - MESSAGE(STATUS "Using UNIX CMAKE_CXX_FLAGS") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall") + # assume GCC, add C++0x/C++11 stuff + MESSAGE(STATUS "Using UNIX CMAKE_CXX_FLAGS") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall") ELSEIF(MINGW) - MESSAGE(STATUS "Using MINGW CMAKE_CXX_FLAGS") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -Wall") + MESSAGE(STATUS "Using MINGW CMAKE_CXX_FLAGS") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -Wall") ENDIF() ################################ 3rd Party Libs ################################ @@ -51,21 +51,21 @@ find_package(Qt5Concurrent REQUIRED) find_package(Qt5LinguistTools REQUIRED) include_directories( - ${Qt5Core_INCLUDE_DIRS} - ${Qt5Widgets_INCLUDE_DIRS} - ${Qt5Concurrent_INCLUDE_DIRS} - ${Qt5Network_INCLUDE_DIRS} - ${Qt5Test_INCLUDE_DIRS} + ${Qt5Core_INCLUDE_DIRS} + ${Qt5Widgets_INCLUDE_DIRS} + ${Qt5Concurrent_INCLUDE_DIRS} + ${Qt5Network_INCLUDE_DIRS} + ${Qt5Test_INCLUDE_DIRS} ) # The Qt5 cmake files don't provide its install paths, so ask qmake. get_target_property(QMAKE_EXECUTABLE Qt5::qmake LOCATION) function(QUERY_QMAKE VAR RESULT) - exec_program(${QMAKE_EXECUTABLE} ARGS "-query ${VAR}" RETURN_VALUE return_code OUTPUT_VARIABLE output ) - if(NOT return_code) - file(TO_CMAKE_PATH "${output}" output) - set(${RESULT} ${output} PARENT_SCOPE) - endif(NOT return_code) + exec_program(${QMAKE_EXECUTABLE} ARGS "-query ${VAR}" RETURN_VALUE return_code OUTPUT_VARIABLE output ) + if(NOT return_code) + file(TO_CMAKE_PATH "${output}" output) + set(${RESULT} ${output} PARENT_SCOPE) + endif(NOT return_code) endfunction(QUERY_QMAKE) query_qmake(QT_INSTALL_PLUGINS QT_PLUGINS_DIR) @@ -81,7 +81,7 @@ set(QT_MKSPECS_DIR ${QT_DATA_DIR}/mkspecs) INCLUDE(TestBigEndian) TEST_BIG_ENDIAN(BIGENDIAN) IF(${BIGENDIAN}) - ADD_DEFINITIONS(-DMULTIMC_BIG_ENDIAN) + ADD_DEFINITIONS(-DMULTIMC_BIG_ENDIAN) ENDIF(${BIGENDIAN}) @@ -118,44 +118,44 @@ SET(MultiMC_NOTIFICATION_URL "" CACHE STRING "URL for checking for notifications SET(MultiMC_RELEASE_VERSION_NAME "${MultiMC_VERSION_MAJOR}.${MultiMC_VERSION_MINOR}") IF (MultiMC_VERSION_HOTFIX GREATER 0) - SET(MultiMC_RELEASE_VERSION_NAME "${MultiMC_RELEASE_VERSION_NAME}.${MultiMC_VERSION_HOTFIX}") + SET(MultiMC_RELEASE_VERSION_NAME "${MultiMC_RELEASE_VERSION_NAME}.${MultiMC_VERSION_HOTFIX}") ENDIF() # Build a version string to display in the configure logs. IF (MultiMC_VERSION_TYPE STREQUAL "Custom") - MESSAGE(STATUS "Version Type: Custom") - SET(MultiMC_VERSION_STRING "${MultiMC_RELEASE_VERSION_NAME}") + MESSAGE(STATUS "Version Type: Custom") + SET(MultiMC_VERSION_STRING "${MultiMC_RELEASE_VERSION_NAME}") ELSEIF (MultiMC_VERSION_TYPE STREQUAL "Release") - MESSAGE(STATUS "Version Type: Stable Release") - SET(MultiMC_VERSION_STRING "${MultiMC_RELEASE_VERSION_NAME}") + MESSAGE(STATUS "Version Type: Stable Release") + SET(MultiMC_VERSION_STRING "${MultiMC_RELEASE_VERSION_NAME}") ELSEIF (MultiMC_VERSION_TYPE STREQUAL "ReleaseCandidate") - MESSAGE(STATUS "Version Type: Release Candidate") - SET(MultiMC_VERSION_STRING "${MultiMC_RELEASE_VERSION_NAME}-rc${MultiMC_VERSION_BUILD}") + MESSAGE(STATUS "Version Type: Release Candidate") + SET(MultiMC_VERSION_STRING "${MultiMC_RELEASE_VERSION_NAME}-rc${MultiMC_VERSION_BUILD}") ELSEIF (MultiMC_VERSION_TYPE STREQUAL "Development") - MESSAGE(STATUS "Version Type: Development") - SET(MultiMC_VERSION_STRING "${MultiMC_RELEASE_VERSION_NAME}-dev${MultiMC_VERSION_BUILD}") + MESSAGE(STATUS "Version Type: Development") + SET(MultiMC_VERSION_STRING "${MultiMC_RELEASE_VERSION_NAME}-dev${MultiMC_VERSION_BUILD}") ELSE () - MESSAGE(ERROR "Invalid build type.") + MESSAGE(ERROR "Invalid build type.") ENDIF () MESSAGE(STATUS "MultiMC 5 Version: ${MultiMC_VERSION_STRING}") # If the update system is enabled, make sure MultiMC_CHANLIST_URL and MultiMC_VERSION_CHANNEL are set. IF (MultiMC_UPDATER) - IF (MultiMC_VERSION_CHANNEL STREQUAL "") - MESSAGE(FATAL_ERROR "Update system is enabled, but MultiMC_VERSION_CHANNEL is not set.\n" - "Please ensure the CMake variables MultiMC_VERSION_CHANNEL, MultiMC_CHANLIST_URL, and MultiMC_VERSION_BUILD are set.") - ENDIF () - IF (MultiMC_CHANLIST_URL STREQUAL "") - MESSAGE(FATAL_ERROR "Update system is enabled, but MultiMC_CHANLIST_URL is not set.\n" - "Please ensure the CMake variables MultiMC_VERSION_CHANNEL, MultiMC_CHANLIST_URL, and MultiMC_VERSION_BUILD are set.") - ENDIF () - IF (MultiMC_VERSION_BUILD LESS 0) - MESSAGE(FATAL_ERROR "Update system is enabled, but MultiMC_VERSION_BUILD is not set.\n" - "Please ensure the CMake variables MultiMC_VERSION_CHANNEL, MultiMC_CHANLIST_URL, and MultiMC_VERSION_BUILD are set.") - ENDIF () + IF (MultiMC_VERSION_CHANNEL STREQUAL "") + MESSAGE(FATAL_ERROR "Update system is enabled, but MultiMC_VERSION_CHANNEL is not set.\n" + "Please ensure the CMake variables MultiMC_VERSION_CHANNEL, MultiMC_CHANLIST_URL, and MultiMC_VERSION_BUILD are set.") + ENDIF () + IF (MultiMC_CHANLIST_URL STREQUAL "") + MESSAGE(FATAL_ERROR "Update system is enabled, but MultiMC_CHANLIST_URL is not set.\n" + "Please ensure the CMake variables MultiMC_VERSION_CHANNEL, MultiMC_CHANLIST_URL, and MultiMC_VERSION_BUILD are set.") + ENDIF () + IF (MultiMC_VERSION_BUILD LESS 0) + MESSAGE(FATAL_ERROR "Update system is enabled, but MultiMC_VERSION_BUILD is not set.\n" + "Please ensure the CMake variables MultiMC_VERSION_CHANNEL, MultiMC_CHANLIST_URL, and MultiMC_VERSION_BUILD are set.") + ENDIF () - MESSAGE(STATUS "Updater is enabled. Channel list URL: ${MultiMC_CHANLIST_URL}") + MESSAGE(STATUS "Updater is enabled. Channel list URL: ${MultiMC_CHANLIST_URL}") ENDIF () #### Custom target to just print the version. @@ -163,18 +163,18 @@ ADD_CUSTOM_TARGET(version echo "Version: ${MultiMC_VERSION_STRING}") #### Check the current Git commit execute_process(COMMAND git rev-parse HEAD - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - RESULT_VARIABLE GIT_COMMIT_CHECK_RESULTVAR - OUTPUT_VARIABLE GIT_COMMIT_CHECK_OUTVAR - OUTPUT_STRIP_TRAILING_WHITESPACE + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + RESULT_VARIABLE GIT_COMMIT_CHECK_RESULTVAR + OUTPUT_VARIABLE GIT_COMMIT_CHECK_OUTVAR + OUTPUT_STRIP_TRAILING_WHITESPACE ) IF(GIT_COMMIT_CHECK_RESULTVAR EQUAL 0) - SET(MultiMC_GIT_COMMIT "${GIT_COMMIT_CHECK_OUTVAR}") - MESSAGE(STATUS "Git commit: ${MultiMC_GIT_COMMIT}") + SET(MultiMC_GIT_COMMIT "${GIT_COMMIT_CHECK_OUTVAR}") + MESSAGE(STATUS "Git commit: ${MultiMC_GIT_COMMIT}") ELSE() - SET(MultiMC_GIT_COMMIT "Unknown") - MESSAGE(STATUS "Failed to check Git commit. ${GIT_COMMIT_CHECK_RESULTVAR}") + SET(MultiMC_GIT_COMMIT "Unknown") + MESSAGE(STATUS "Failed to check Git commit. ${GIT_COMMIT_CHECK_RESULTVAR}") ENDIF() ######## Configure header ######## @@ -190,29 +190,29 @@ ADD_DEFINITIONS(-DLIBUTIL_STATIC) ######## Packaging/install paths setup ######## IF(UNIX AND APPLE) - SET(BINARY_DEST_DIR MultiMC.app/Contents/MacOS) - SET(PLUGIN_DEST_DIR MultiMC.app/Contents/MacOS) - SET(QTCONF_DEST_DIR MultiMC.app/Contents/Resources) - SET(APPS "\${CMAKE_INSTALL_PREFIX}/MultiMC.app") + SET(BINARY_DEST_DIR MultiMC.app/Contents/MacOS) + SET(PLUGIN_DEST_DIR MultiMC.app/Contents/MacOS) + SET(QTCONF_DEST_DIR MultiMC.app/Contents/Resources) + SET(APPS "\${CMAKE_INSTALL_PREFIX}/MultiMC.app") - SET(MACOSX_BUNDLE_BUNDLE_NAME "MultiMC") - SET(MACOSX_BUNDLE_INFO_STRING "MultiMC Minecraft launcher and management utility.") - SET(MACOSX_BUNDLE_GUI_IDENTIFIER "org.multimc.MultiMC5") - SET(MACOSX_BUNDLE_BUNDLE_VERSION "${MultiMC_VERSION_MAJOR}.${MultiMC_VERSION_MINOR}.${MultiMC_VERSION_REV}.${MultiMC_VERSION_BUILD}") - SET(MACOSX_BUNDLE_SHORT_VERSION_STRING "${MultiMC_VERSION_MAJOR}.${MultiMC_VERSION_MINOR}.${MultiMC_VERSION_REV}.${MultiMC_VERSION_BUILD}") - SET(MACOSX_BUNDLE_LONG_VERSION_STRING "${MultiMC_VERSION_MAJOR}.${MultiMC_VERSION_MINOR}.${MultiMC_VERSION_REV}.${MultiMC_VERSION_BUILD}") - SET(MACOSX_BUNDLE_ICON_FILE MultiMC.icns) - SET(MACOSX_BUNDLE_COPYRIGHT "Copyright 2013 MultiMC Contributors") + SET(MACOSX_BUNDLE_BUNDLE_NAME "MultiMC") + SET(MACOSX_BUNDLE_INFO_STRING "MultiMC Minecraft launcher and management utility.") + SET(MACOSX_BUNDLE_GUI_IDENTIFIER "org.multimc.MultiMC5") + SET(MACOSX_BUNDLE_BUNDLE_VERSION "${MultiMC_VERSION_MAJOR}.${MultiMC_VERSION_MINOR}.${MultiMC_VERSION_REV}.${MultiMC_VERSION_BUILD}") + SET(MACOSX_BUNDLE_SHORT_VERSION_STRING "${MultiMC_VERSION_MAJOR}.${MultiMC_VERSION_MINOR}.${MultiMC_VERSION_REV}.${MultiMC_VERSION_BUILD}") + SET(MACOSX_BUNDLE_LONG_VERSION_STRING "${MultiMC_VERSION_MAJOR}.${MultiMC_VERSION_MINOR}.${MultiMC_VERSION_REV}.${MultiMC_VERSION_BUILD}") + SET(MACOSX_BUNDLE_ICON_FILE MultiMC.icns) + SET(MACOSX_BUNDLE_COPYRIGHT "Copyright 2013 MultiMC Contributors") ELSEIF(UNIX) - SET(BINARY_DEST_DIR bin) - SET(PLUGIN_DEST_DIR plugins) - SET(QTCONF_DEST_DIR .) - SET(APPS "\${CMAKE_INSTALL_PREFIX}/bin/MultiMC") + SET(BINARY_DEST_DIR bin) + SET(PLUGIN_DEST_DIR plugins) + SET(QTCONF_DEST_DIR .) + SET(APPS "\${CMAKE_INSTALL_PREFIX}/bin/MultiMC") ELSEIF(WIN32) - SET(BINARY_DEST_DIR .) - SET(PLUGIN_DEST_DIR .) - SET(QTCONF_DEST_DIR .) - SET(APPS "\${CMAKE_INSTALL_PREFIX}/MultiMC.exe") + SET(BINARY_DEST_DIR .) + SET(PLUGIN_DEST_DIR .) + SET(QTCONF_DEST_DIR .) + SET(APPS "\${CMAKE_INSTALL_PREFIX}/MultiMC.exe") ENDIF() # directories to look for dependencies @@ -308,6 +308,8 @@ gui/dialogs/AccountSelectDialog.h gui/dialogs/AccountSelectDialog.cpp gui/dialogs/UpdateDialog.h gui/dialogs/UpdateDialog.cpp +gui/dialogs/ScreenshotDialog.h +gui/dialogs/ScreenshotDialog.cpp # GUI - widgets gui/widgets/Common.h @@ -370,6 +372,7 @@ logic/net/HttpMetaCache.cpp logic/net/PasteUpload.h logic/net/PasteUpload.cpp logic/net/URLConstants.h +logic/net/URLConstants.cpp # Yggdrasil login stuff logic/auth/AuthSession.h @@ -463,6 +466,16 @@ logic/lists/JavaVersionList.cpp logic/lists/LiteLoaderVersionList.h logic/lists/LiteLoaderVersionList.cpp +# the screenshots feature +logic/screenshots/Screenshot.h +logic/screenshots/Screenshot.cpp +logic/screenshots/ScreenshotList.h +logic/screenshots/ScreenshotList.cpp +logic/screenshots/ImgurUpload.h +logic/screenshots/ImgurUpload.cpp +logic/screenshots/ImgurAlbumCreation.h +logic/screenshots/ImgurAlbumCreation.cpp + # Icons logic/icons/MMCIcon.h logic/icons/MMCIcon.cpp @@ -539,6 +552,7 @@ gui/dialogs/AccountListDialog.ui gui/dialogs/AccountSelectDialog.ui gui/dialogs/EditAccountDialog.ui gui/dialogs/UpdateDialog.ui +gui/dialogs/ScreenshotDialog.ui # Widgets/other gui/widgets/MCModInfoFrame.ui @@ -560,11 +574,11 @@ ENDIF() ####### X11 Stuff ####### IF(UNIX AND NOT APPLE) - SET(MultiMC_QT_ADDITIONAL_MODULES ${MultiMC_QT_ADDITIONAL_MODULES} X11Extras) - SET(MultiMC_LINK_ADDITIONAL_LIBS ${MultiMC_LINK_ADDITIONAL_LIBS} xcb) - LIST(APPEND MULTIMC_SOURCES gui/Platform_X11.cpp) + SET(MultiMC_QT_ADDITIONAL_MODULES ${MultiMC_QT_ADDITIONAL_MODULES} X11Extras) + SET(MultiMC_LINK_ADDITIONAL_LIBS ${MultiMC_LINK_ADDITIONAL_LIBS} xcb) + LIST(APPEND MULTIMC_SOURCES gui/Platform_X11.cpp) ELSE() - LIST(APPEND MULTIMC_SOURCES gui/Platform_Other.cpp) + LIST(APPEND MULTIMC_SOURCES gui/Platform_Other.cpp) ENDIF() @@ -572,9 +586,9 @@ ENDIF() # Link additional libraries IF(WIN32) - SET(MultiMC_LINK_ADDITIONAL_LIBS ${MultiMC_LINK_ADDITIONAL_LIBS} - Qt5::WinMain # Link WinMain - ) + SET(MultiMC_LINK_ADDITIONAL_LIBS ${MultiMC_LINK_ADDITIONAL_LIBS} + Qt5::WinMain # Link WinMain + ) ENDIF(WIN32) OPTION(MultiMC_UPDATER_DRY_RUN "Enable updater dry-run mode -- for updater development." OFF) @@ -582,11 +596,11 @@ OPTION(MultiMC_UPDATER_FORCE_LOCAL "Do not download updated updater -- for updat OPTION(MultiMC_CODE_COVERAGE "Compiles for code coverage" OFF) IF(MultiMC_CODE_COVERAGE) - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 --coverage") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 --coverage") - SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -O0 --coverage") - SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -g -O0 --coverage") - SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -O0 --coverage") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 --coverage") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 --coverage") + SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -O0 --coverage") + SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -g -O0 --coverage") + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -O0 --coverage") ENDIF(MultiMC_CODE_COVERAGE) # Tell CMake that MultiMCLauncher.jar is generated. @@ -615,24 +629,24 @@ QT5_USE_MODULES(MultiMC_common Core Widgets Network Xml Concurrent ${MultiMC_QT_ #### Executable #### IF(APPLE AND UNIX) ## OSX - INSTALL(TARGETS MultiMC - BUNDLE DESTINATION . COMPONENT Runtime - RUNTIME DESTINATION MultiMC.app/Contents/MacOS COMPONENT Runtime - ) + INSTALL(TARGETS MultiMC + BUNDLE DESTINATION . COMPONENT Runtime + RUNTIME DESTINATION MultiMC.app/Contents/MacOS COMPONENT Runtime + ) ELSEIF(UNIX) ## LINUX and similar - INSTALL(TARGETS MultiMC - BUNDLE DESTINATION . COMPONENT Runtime - RUNTIME DESTINATION bin COMPONENT Runtime - ) - INSTALL(PROGRAMS package/linux/MultiMC DESTINATION .) + INSTALL(TARGETS MultiMC + BUNDLE DESTINATION . COMPONENT Runtime + RUNTIME DESTINATION bin COMPONENT Runtime + ) + INSTALL(PROGRAMS package/linux/MultiMC DESTINATION .) ELSEIF(WIN32) ## WINDOWS - INSTALL(TARGETS MultiMC - BUNDLE DESTINATION . COMPONENT Runtime - LIBRARY DESTINATION . COMPONENT Runtime - RUNTIME DESTINATION . COMPONENT Runtime - ) + INSTALL(TARGETS MultiMC + BUNDLE DESTINATION . COMPONENT Runtime + LIBRARY DESTINATION . COMPONENT Runtime + RUNTIME DESTINATION . COMPONENT Runtime + ) ENDIF() #### Dist package logic #### @@ -640,70 +654,70 @@ ENDIF() if (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") # Image formats INSTALL( - DIRECTORY "${QT_PLUGINS_DIR}/imageformats" - DESTINATION ${PLUGIN_DEST_DIR} - COMPONENT Runtime - REGEX "tga|svg|tiff|mng" EXCLUDE + DIRECTORY "${QT_PLUGINS_DIR}/imageformats" + DESTINATION ${PLUGIN_DEST_DIR} + COMPONENT Runtime + REGEX "tga|svg|tiff|mng" EXCLUDE ) # Platform plugins INSTALL( - DIRECTORY "${QT_PLUGINS_DIR}/platforms" - DESTINATION ${PLUGIN_DEST_DIR} - COMPONENT Runtime - REGEX "minimal|linuxfb|offscreen" EXCLUDE + DIRECTORY "${QT_PLUGINS_DIR}/platforms" + DESTINATION ${PLUGIN_DEST_DIR} + COMPONENT Runtime + REGEX "minimal|linuxfb|offscreen" EXCLUDE ) else() # Image formats INSTALL( - DIRECTORY "${QT_PLUGINS_DIR}/imageformats" - DESTINATION ${PLUGIN_DEST_DIR} - COMPONENT Runtime - REGEX "tga|svg|tiff|mng" EXCLUDE - REGEX "d\\." EXCLUDE - REGEX "_debug\\." EXCLUDE + DIRECTORY "${QT_PLUGINS_DIR}/imageformats" + DESTINATION ${PLUGIN_DEST_DIR} + COMPONENT Runtime + REGEX "tga|svg|tiff|mng" EXCLUDE + REGEX "d\\." EXCLUDE + REGEX "_debug\\." EXCLUDE ) # Platform plugins INSTALL( - DIRECTORY "${QT_PLUGINS_DIR}/platforms" - DESTINATION ${PLUGIN_DEST_DIR} - COMPONENT Runtime - REGEX "minimal|linuxfb|offscreen" EXCLUDE - REGEX "d\\." EXCLUDE - REGEX "_debug\\." EXCLUDE + DIRECTORY "${QT_PLUGINS_DIR}/platforms" + DESTINATION ${PLUGIN_DEST_DIR} + COMPONENT Runtime + REGEX "minimal|linuxfb|offscreen" EXCLUDE + REGEX "d\\." EXCLUDE + REGEX "_debug\\." EXCLUDE ) IF(APPLE) - # Accessible plugin to make buttons look decent on osx - INSTALL( - DIRECTORY "${QT_PLUGINS_DIR}/accessible" - DESTINATION ${PLUGIN_DEST_DIR} - COMPONENT Runtime - REGEX "quick" EXCLUDE - REGEX "d\\." EXCLUDE - REGEX "_debug\\." EXCLUDE - ) + # Accessible plugin to make buttons look decent on osx + INSTALL( + DIRECTORY "${QT_PLUGINS_DIR}/accessible" + DESTINATION ${PLUGIN_DEST_DIR} + COMPONENT Runtime + REGEX "quick" EXCLUDE + REGEX "d\\." EXCLUDE + REGEX "_debug\\." EXCLUDE + ) ENDIF() endif() # qtconf INSTALL( - CODE " + CODE " FILE(WRITE \"\${CMAKE_INSTALL_PREFIX}/${QTCONF_DEST_DIR}/qt.conf\" \"\") " - COMPONENT Runtime + COMPONENT Runtime ) # ICNS file for OS X IF(APPLE) - INSTALL(FILES resources/MultiMC.icns DESTINATION MultiMC.app/Contents/Resources) + INSTALL(FILES resources/MultiMC.icns DESTINATION MultiMC.app/Contents/Resources) ENDIF() CONFIGURE_FILE( - "${CMAKE_CURRENT_SOURCE_DIR}/install_prereqs.cmake.in" - "${CMAKE_CURRENT_BINARY_DIR}/install_prereqs.cmake" - @ONLY) + "${CMAKE_CURRENT_SOURCE_DIR}/install_prereqs.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/install_prereqs.cmake" + @ONLY) INSTALL(SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/install_prereqs.cmake" COMPONENT Runtime) @@ -712,13 +726,13 @@ INSTALL(SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/install_prereqs.cmake" COMPONENT Run # Package with CPack IF(UNIX) - if(APPLE) - SET(CPACK_GENERATOR "ZIP") - else() - SET(CPACK_GENERATOR "TGZ") - endif() + if(APPLE) + SET(CPACK_GENERATOR "ZIP") + else() + SET(CPACK_GENERATOR "TGZ") + endif() ELSEIF(WIN32) - SET(CPACK_GENERATOR "ZIP") + SET(CPACK_GENERATOR "ZIP") ENDIF() SET(CPACK_INCLUDE_TOPLEVEL_DIRECTORY 0) @@ -750,16 +764,16 @@ file (GLOB TRANSLATIONS_FILES translations/*.ts) option (UPDATE_TRANSLATIONS "Update source translation translations/*.ts files (WARNING: make clean will delete the source .ts files! Danger!)") IF(UPDATE_TRANSLATIONS) - qt5_create_translation(QM_FILES ${FILES_TO_TRANSLATE} ${TRANSLATIONS_FILES}) + qt5_create_translation(QM_FILES ${FILES_TO_TRANSLATE} ${TRANSLATIONS_FILES}) ELSE() - qt5_add_translation(QM_FILES ${TRANSLATIONS_FILES}) + qt5_add_translation(QM_FILES ${TRANSLATIONS_FILES}) ENDIF() add_custom_target (translations DEPENDS ${QM_FILES}) IF(APPLE AND UNIX) ## OSX - install(FILES ${QM_FILES} DESTINATION MultiMC.app/Contents/MacOS/translations) + install(FILES ${QM_FILES} DESTINATION MultiMC.app/Contents/MacOS/translations) ELSE() - install(FILES ${QM_FILES} DESTINATION translations) + install(FILES ${QM_FILES} DESTINATION translations) ENDIF() diff --git a/gui/ConsoleWindow.cpp b/gui/ConsoleWindow.cpp index ccc037f2a..d11e8aff9 100644 --- a/gui/ConsoleWindow.cpp +++ b/gui/ConsoleWindow.cpp @@ -42,6 +42,8 @@ ConsoleWindow::ConsoleWindow(MinecraftProcess *mcproc, QWidget *parent) connect(mcproc, SIGNAL(launch_failed(BaseInstance *)), this, SLOT(onLaunchFailed(BaseInstance *))); + connect(ui->btnScreenshots, &QPushButton::clicked, this, &ConsoleWindow::uploadScreenshots); + restoreState( QByteArray::fromBase64(MMC->settings()->get("ConsoleWindowState").toByteArray())); restoreGeometry( @@ -52,6 +54,7 @@ ConsoleWindow::ConsoleWindow(MinecraftProcess *mcproc, QWidget *parent) auto icon = MMC->icons()->getIcon(iconKey); setWindowIcon(icon); m_trayIcon = new QSystemTrayIcon(icon, this); + // TODO add screenshot upload as a menu item in the tray icon QString consoleTitle = tr("Console window for ") + name; m_trayIcon->setToolTip(consoleTitle); setWindowTitle(consoleTitle); diff --git a/gui/ConsoleWindow.h b/gui/ConsoleWindow.h index 7fe90c521..e21da33c2 100644 --- a/gui/ConsoleWindow.h +++ b/gui/ConsoleWindow.h @@ -51,6 +51,7 @@ private: signals: void isClosing(); + void uploadScreenshots(); public slots: diff --git a/gui/ConsoleWindow.ui b/gui/ConsoleWindow.ui index c2307ecc5..344cf74d8 100644 --- a/gui/ConsoleWindow.ui +++ b/gui/ConsoleWindow.ui @@ -49,6 +49,13 @@ + + + + Manage Screenshots + + + diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp index 121c2a73f..17d4630b4 100644 --- a/gui/MainWindow.cpp +++ b/gui/MainWindow.cpp @@ -44,7 +44,6 @@ #include "gui/Platform.h" - #include "gui/widgets/LabeledToolButton.h" #include "gui/dialogs/SettingsDialog.h" @@ -62,6 +61,7 @@ #include "gui/dialogs/AccountSelectDialog.h" #include "gui/dialogs/UpdateDialog.h" #include "gui/dialogs/EditAccountDialog.h" +#include "gui/dialogs/ScreenshotDialog.h" #include "gui/ConsoleWindow.h" @@ -81,6 +81,7 @@ #include "logic/status/StatusChecker.h" #include "logic/net/URLConstants.h" +#include "logic/net/NetJob.h" #include "logic/BaseInstance.h" #include "logic/InstanceFactory.h" @@ -146,7 +147,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi { view = new GroupView(ui->centralWidget); - view->setSelectionMode(QAbstractItemView::SingleSelection); // view->setCategoryDrawer(drawer); // view->setCollapsibleBlocks(true); @@ -1284,6 +1284,7 @@ void MainWindow::launchInstance(BaseInstance *instance, AuthSessionPtr session, console = new ConsoleWindow(proc); connect(console, SIGNAL(isClosing()), this, SLOT(instanceEnded())); + connect(console, &ConsoleWindow::uploadScreenshots, this, &MainWindow::on_actionScreenshots_triggered); proc->setLogin(session); proc->arm(); @@ -1600,3 +1601,25 @@ void MainWindow::checkSetDefaultJava() MMC->settings()->set("JavaPath", QString("java")); } } + +void MainWindow::on_actionScreenshots_triggered() +{ + if (!m_selectedInstance) + return; + ScreenshotList *list = new ScreenshotList(m_selectedInstance); + Task *task = list->load(); + ProgressDialog prog(this); + prog.exec(task); + if (!task->successful()) + { + CustomMessageBox::selectable(this, tr("Failed to load screenshots!"), + task->failReason(), QMessageBox::Warning)->exec(); + return; + } + ScreenshotDialog dialog(list, this); + if (dialog.exec() == ScreenshotDialog::Accepted) + { + CustomMessageBox::selectable(this, tr("Done uploading!"), dialog.message(), + QMessageBox::Information)->exec(); + } +} diff --git a/gui/MainWindow.h b/gui/MainWindow.h index 7a29977da..3a2843f8b 100644 --- a/gui/MainWindow.h +++ b/gui/MainWindow.h @@ -139,7 +139,9 @@ slots: // called when an icon is changed in the icon model. void iconUpdated(QString); - void showInstanceContextMenu(const QPoint&); + void showInstanceContextMenu(const QPoint &); + + void on_actionScreenshots_triggered(); void updateToolsMenu(); @@ -170,11 +172,11 @@ slots: void updateStatusFailedUI(); void reloadStatus(); - + /*! * Runs the DownloadUpdateTask and installs updates. */ - void downloadUpdates(QString repo, int versionId, bool installOnExit=false); + void downloadUpdates(QString repo, int versionId, bool installOnExit = false); protected: bool eventFilter(QObject *obj, QEvent *ev); @@ -191,7 +193,7 @@ private: ConsoleWindow *console; LabeledToolButton *renameButton; QToolButton *changeIconButton; - QToolButton* newsLabel; + QToolButton *newsLabel; BaseInstance *m_selectedInstance; QString m_currentInstIcon; diff --git a/gui/MainWindow.ui b/gui/MainWindow.ui index 90c860753..2bd8ec226 100644 --- a/gui/MainWindow.ui +++ b/gui/MainWindow.ui @@ -112,6 +112,8 @@ + + @@ -528,6 +530,14 @@ Launch the selected instance. + + + Manage Screenshots + + + <html><head/><body><p>View and upload screenshots for this instance</p></body></html> + + diff --git a/gui/dialogs/CustomMessageBox.cpp b/gui/dialogs/CustomMessageBox.cpp index 1d2ab58a4..4013db601 100644 --- a/gui/dialogs/CustomMessageBox.cpp +++ b/gui/dialogs/CustomMessageBox.cpp @@ -28,6 +28,7 @@ QMessageBox *selectable(QWidget *parent, const QString &title, const QString &te messageBox->setDefaultButton(defaultButton); messageBox->setTextInteractionFlags(Qt::TextSelectableByMouse); messageBox->setIcon(icon); + messageBox->setTextInteractionFlags(Qt::TextBrowserInteraction); return messageBox; } diff --git a/gui/dialogs/ScreenshotDialog.cpp b/gui/dialogs/ScreenshotDialog.cpp new file mode 100644 index 000000000..a88c8dfd4 --- /dev/null +++ b/gui/dialogs/ScreenshotDialog.cpp @@ -0,0 +1,78 @@ +#include "ScreenshotDialog.h" +#include "ui_ScreenshotDialog.h" + +#include +#include + +#include "ProgressDialog.h" +#include "CustomMessageBox.h" +#include "logic/net/NetJob.h" +#include "logic/screenshots/ImgurUpload.h" +#include "logic/screenshots/ImgurAlbumCreation.h" +#include "logic/tasks/SequentialTask.h" + +ScreenshotDialog::ScreenshotDialog(ScreenshotList *list, QWidget *parent) + : QDialog(parent), ui(new Ui::ScreenshotDialog), m_list(list) +{ + ui->setupUi(this); + ui->listView->setModel(m_list); +} + +ScreenshotDialog::~ScreenshotDialog() +{ + delete ui; +} + +QString ScreenshotDialog::message() const +{ + return tr("Visit album
Delete hash: %2 (save " + "this if you want to be able to edit/delete the album)") + .arg(m_imgurAlbum->id(), m_imgurAlbum->deleteHash()); +} + +QList ScreenshotDialog::selected() const +{ + QList list; + QList first = m_list->screenshots(); + for (QModelIndex index : ui->listView->selectionModel()->selectedRows()) + { + list.append(first.at(index.row())); + } + return list; +} + +void ScreenshotDialog::on_uploadBtn_clicked() +{ + m_uploaded = selected(); + if (m_uploaded.isEmpty()) + { + done(NothingDone); + return; + } + SequentialTask *task = new SequentialTask(this); + NetJob *job = new NetJob("Screenshot Upload"); + for (auto shot : m_uploaded) + { + job->addNetAction(ImgurUpload::make(shot)); + } + NetJob *albumTask = new NetJob("Imgur Album Creation"); + albumTask->addNetAction(m_imgurAlbum = ImgurAlbumCreation::make(m_uploaded)); + task->addTask(NetJobPtr(job)); + task->addTask(NetJobPtr(albumTask)); + ProgressDialog prog(this); + if (prog.exec(task) == QDialog::Accepted) + { + accept(); + } + else + { + CustomMessageBox::selectable(this, tr("Failed to upload screenshots!"), + tr("Unknown error"), QMessageBox::Warning)->exec(); + reject(); + } +} + +void ScreenshotDialog::on_deleteBtn_clicked() +{ + m_list->deleteSelected(this); +} diff --git a/gui/dialogs/ScreenshotDialog.h b/gui/dialogs/ScreenshotDialog.h new file mode 100644 index 000000000..29dd67655 --- /dev/null +++ b/gui/dialogs/ScreenshotDialog.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include "logic/screenshots/ScreenshotList.h" + +class ImgurAlbumCreation; + +namespace Ui +{ +class ScreenshotDialog; +} + +class ScreenshotDialog : public QDialog +{ + Q_OBJECT + +public: + explicit ScreenshotDialog(ScreenshotList *list, QWidget *parent = 0); + ~ScreenshotDialog(); + + enum + { + NothingDone = 0x42 + }; + + QString message() const; + QList selected() const; + +private +slots: + void on_uploadBtn_clicked(); + + void on_deleteBtn_clicked(); + +private: + Ui::ScreenshotDialog *ui; + ScreenshotList *m_list; + QList m_uploaded; + std::shared_ptr m_imgurAlbum; +}; diff --git a/gui/dialogs/ScreenshotDialog.ui b/gui/dialogs/ScreenshotDialog.ui new file mode 100644 index 000000000..eb3dafba5 --- /dev/null +++ b/gui/dialogs/ScreenshotDialog.ui @@ -0,0 +1,110 @@ + + + ScreenshotDialog + + + + 0 + 0 + 470 + 300 + + + + Screenshot Manager + + + + :/icons/multimc/scalable/apps/multimc.svg:/icons/multimc/scalable/apps/multimc.svg + + + + + + QAbstractItemView::ExtendedSelection + + + QAbstractItemView::SelectItems + + + + 120 + 90 + + + + QListView::LeftToRight + + + true + + + QListView::Adjust + + + QListView::IconMode + + + + + + + + + Upload + + + + + + + Delete + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Close + + + + + + + + + + + + + closeBtn + clicked() + ScreenshotDialog + reject() + + + 315 + 272 + + + 271 + 258 + + + + + diff --git a/logic/net/URLConstants.cpp b/logic/net/URLConstants.cpp new file mode 100644 index 000000000..14b280851 --- /dev/null +++ b/logic/net/URLConstants.cpp @@ -0,0 +1,19 @@ +#include "URLConstants.h" +namespace URLConstants +{ +const QString AWS_DOWNLOAD_BASE("s3.amazonaws.com/Minecraft.Download/"); +const QString AWS_DOWNLOAD_VERSIONS(AWS_DOWNLOAD_BASE + "versions/"); +const QString AWS_DOWNLOAD_LIBRARIES(AWS_DOWNLOAD_BASE + "libraries/"); +const QString AWS_DOWNLOAD_INDEXES(AWS_DOWNLOAD_BASE + "indexes/"); +const QString ASSETS_BASE("assets.minecraft.net/"); +const QString RESOURCE_BASE("resources.download.minecraft.net/"); +const QString LIBRARY_BASE("libraries.minecraft.net/"); +const QString SKINS_BASE("skins.minecraft.net/MinecraftSkins/"); +const QString AUTH_BASE("authserver.mojang.com/"); +const QString FORGE_LEGACY_URL("http://files.minecraftforge.net/minecraftforge/json"); +const QString FORGE_GRADLE_URL("http://files.minecraftforge.net/maven/net/minecraftforge/forge/json"); +const QString MOJANG_STATUS_URL("http://status.mojang.com/check"); +const QString MOJANG_STATUS_NEWS_URL("http://status.mojang.com/news"); +const QString LITELOADER_URL("http://dl.liteloader.com/versions/versions.json"); +const QString IMGUR_BASE_URL("https://api.imgur.com/3/"); +} \ No newline at end of file diff --git a/logic/net/URLConstants.h b/logic/net/URLConstants.h index 07b35c4f9..c10641158 100644 --- a/logic/net/URLConstants.h +++ b/logic/net/URLConstants.h @@ -19,19 +19,19 @@ namespace URLConstants { -const QString AWS_DOWNLOAD_BASE("s3.amazonaws.com/Minecraft.Download/"); -const QString AWS_DOWNLOAD_VERSIONS(AWS_DOWNLOAD_BASE + "versions/"); -const QString AWS_DOWNLOAD_LIBRARIES(AWS_DOWNLOAD_BASE + "libraries/"); -const QString AWS_DOWNLOAD_INDEXES(AWS_DOWNLOAD_BASE + "indexes/"); -const QString ASSETS_BASE("assets.minecraft.net/"); -//const QString MCN_BASE("sonicrules.org/mcnweb.py"); -const QString RESOURCE_BASE("resources.download.minecraft.net/"); -const QString LIBRARY_BASE("libraries.minecraft.net/"); -const QString SKINS_BASE("skins.minecraft.net/MinecraftSkins/"); -const QString AUTH_BASE("authserver.mojang.com/"); -const QString FORGE_LEGACY_URL("http://files.minecraftforge.net/minecraftforge/json"); -const QString FORGE_GRADLE_URL("http://files.minecraftforge.net/maven/net/minecraftforge/forge/json"); -const QString MOJANG_STATUS_URL("http://status.mojang.com/check"); -const QString MOJANG_STATUS_NEWS_URL("http://status.mojang.com/news"); -const QString LITELOADER_URL("http://dl.liteloader.com/versions/versions.json"); +extern const QString AWS_DOWNLOAD_BASE; +extern const QString AWS_DOWNLOAD_VERSIONS; +extern const QString AWS_DOWNLOAD_LIBRARIES; +extern const QString AWS_DOWNLOAD_INDEXES; +extern const QString ASSETS_BASE; +extern const QString RESOURCE_BASE; +extern const QString LIBRARY_BASE; +extern const QString SKINS_BASE; +extern const QString AUTH_BASE; +extern const QString FORGE_LEGACY_URL; +extern const QString FORGE_GRADLE_URL; +extern const QString MOJANG_STATUS_URL; +extern const QString MOJANG_STATUS_NEWS_URL; +extern const QString LITELOADER_URL; +extern const QString IMGUR_BASE_URL; } diff --git a/logic/screenshots/ImgurAlbumCreation.cpp b/logic/screenshots/ImgurAlbumCreation.cpp new file mode 100644 index 000000000..e473952e0 --- /dev/null +++ b/logic/screenshots/ImgurAlbumCreation.cpp @@ -0,0 +1,90 @@ +#include "ImgurAlbumCreation.h" + +#include +#include +#include +#include + +#include "logic/screenshots//ScreenshotList.h" +#include "logic/net/URLConstants.h" +#include "MultiMC.h" +#include "logger/QsLog.h" + +ImgurAlbumCreation::ImgurAlbumCreation(QList screenshots) : NetAction(), m_screenshots(screenshots) +{ + m_url = URLConstants::IMGUR_BASE_URL + "album.json"; + m_status = Job_NotStarted; +} + +void ImgurAlbumCreation::start() +{ + m_status = Job_InProgress; + QNetworkRequest request(m_url); + request.setHeader(QNetworkRequest::UserAgentHeader, "MultiMC/5.0 (Uncached)"); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); + request.setRawHeader("Authorization", "Client-ID 5b97b0713fba4a3"); + request.setRawHeader("Accept", "application/json"); + + QStringList ids; + for (auto shot : m_screenshots) + { + ids.append(shot->imgurId); + } + + const QByteArray data = "ids=" + ids.join(',').toUtf8() + "&title=Minecraft%20Screenshots&privacy=hidden"; + + auto worker = MMC->qnam(); + QNetworkReply *rep = worker->post(request, data); + + m_reply = std::shared_ptr(rep); + connect(rep, &QNetworkReply::uploadProgress, this, &ImgurAlbumCreation::downloadProgress); + connect(rep, &QNetworkReply::finished, this, &ImgurAlbumCreation::downloadFinished); + connect(rep, SIGNAL(error(QNetworkReply::NetworkError)), + SLOT(downloadError(QNetworkReply::NetworkError))); +} +void ImgurAlbumCreation::downloadError(QNetworkReply::NetworkError error) +{ + QLOG_DEBUG() << m_reply->errorString(); + m_status = Job_Failed; +} +void ImgurAlbumCreation::downloadFinished() +{ + if (m_status != Job_Failed) + { + QByteArray data = m_reply->readAll(); + m_reply.reset(); + QJsonParseError jsonError; + QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError); + if (jsonError.error != QJsonParseError::NoError) + { + QLOG_DEBUG() << jsonError.errorString(); + emit failed(m_index_within_job); + return; + } + auto object = doc.object(); + if (!object.value("success").toBool()) + { + QLOG_DEBUG() << doc.toJson(); + emit failed(m_index_within_job); + return; + } + m_deleteHash = object.value("data").toObject().value("deletehash").toString(); + m_id = object.value("data").toObject().value("id").toString(); + m_status = Job_Finished; + emit succeeded(m_index_within_job); + return; + } + else + { + QLOG_DEBUG() << m_reply->readAll(); + m_reply.reset(); + emit failed(m_index_within_job); + return; + } +} +void ImgurAlbumCreation::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) +{ + m_total_progress = bytesTotal; + m_progress = bytesReceived; + emit progress(m_index_within_job, bytesReceived, bytesTotal); +} diff --git a/logic/screenshots/ImgurAlbumCreation.h b/logic/screenshots/ImgurAlbumCreation.h new file mode 100644 index 000000000..6e8fbe94c --- /dev/null +++ b/logic/screenshots/ImgurAlbumCreation.h @@ -0,0 +1,42 @@ +#pragma once +#include "logic/net/NetAction.h" +#include "Screenshot.h" + +typedef std::shared_ptr ImgurAlbumCreationPtr; +class ImgurAlbumCreation : public NetAction +{ +public: + explicit ImgurAlbumCreation(QList screenshots); + static ImgurAlbumCreationPtr make(QList screenshots) + { + return ImgurAlbumCreationPtr(new ImgurAlbumCreation(screenshots)); + } + + QString deleteHash() const + { + return m_deleteHash; + } + QString id() const + { + return m_id; + } + +protected +slots: + virtual void downloadProgress(qint64 bytesReceived, qint64 bytesTotal); + virtual void downloadError(QNetworkReply::NetworkError error); + virtual void downloadFinished(); + virtual void downloadReadyRead() + { + } + +public +slots: + virtual void start(); + +private: + QList m_screenshots; + + QString m_deleteHash; + QString m_id; +}; diff --git a/logic/screenshots/ImgurUpload.cpp b/logic/screenshots/ImgurUpload.cpp new file mode 100644 index 000000000..62033ef58 --- /dev/null +++ b/logic/screenshots/ImgurUpload.cpp @@ -0,0 +1,106 @@ +#include "ImgurUpload.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "logic/screenshots/ScreenshotList.h" +#include "logic/net/URLConstants.h" +#include "MultiMC.h" +#include "logger/QsLog.h" + +ImgurUpload::ImgurUpload(ScreenshotPtr shot) : NetAction(), m_shot(shot) +{ + m_url = URLConstants::IMGUR_BASE_URL + "upload.json"; + m_status = Job_NotStarted; +} + +void ImgurUpload::start() +{ + m_status = Job_InProgress; + QNetworkRequest request(m_url); + request.setHeader(QNetworkRequest::UserAgentHeader, "MultiMC/5.0 (Uncached)"); + request.setRawHeader("Authorization", "Client-ID 5b97b0713fba4a3"); + request.setRawHeader("Accept", "application/json"); + + QFile f(m_shot->file); + if (!f.open(QFile::ReadOnly)) + { + emit failed(m_index_within_job); + return; + } + + QHttpMultiPart *multipart = new QHttpMultiPart(QHttpMultiPart::FormDataType); + QHttpPart filePart; + filePart.setBody(f.readAll().toBase64()); + filePart.setHeader(QNetworkRequest::ContentTypeHeader, "image/png"); + filePart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"image\""); + multipart->append(filePart); + QHttpPart typePart; + typePart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"type\""); + typePart.setBody("base64"); + multipart->append(typePart); + QHttpPart namePart; + namePart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"name\""); + namePart.setBody(m_shot->timestamp.toString(Qt::ISODate).toUtf8()); + multipart->append(namePart); + + auto worker = MMC->qnam(); + QNetworkReply *rep = worker->post(request, multipart); + + m_reply = std::shared_ptr(rep); + connect(rep, &QNetworkReply::uploadProgress, this, &ImgurUpload::downloadProgress); + connect(rep, &QNetworkReply::finished, this, &ImgurUpload::downloadFinished); + connect(rep, SIGNAL(error(QNetworkReply::NetworkError)), + SLOT(downloadError(QNetworkReply::NetworkError))); +} +void ImgurUpload::downloadError(QNetworkReply::NetworkError error) +{ + QLOG_DEBUG() << m_reply->errorString(); + m_status = Job_Failed; +} +void ImgurUpload::downloadFinished() +{ + if (m_status != Job_Failed) + { + QByteArray data = m_reply->readAll(); + m_reply.reset(); + QJsonParseError jsonError; + QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError); + if (jsonError.error != QJsonParseError::NoError) + { + QLOG_DEBUG() << jsonError.errorString(); + emit failed(m_index_within_job); + return; + } + auto object = doc.object(); + if (!object.value("success").toBool()) + { + QLOG_DEBUG() << doc.toJson(); + emit failed(m_index_within_job); + return; + } + m_shot->imgurId = object.value("data").toObject().value("id").toString(); + m_shot->url = object.value("data").toObject().value("link").toString(); + m_status = Job_Finished; + emit succeeded(m_index_within_job); + return; + } + else + { + QLOG_DEBUG() << m_reply->readAll(); + m_reply.reset(); + emit failed(m_index_within_job); + return; + } +} +void ImgurUpload::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) +{ + m_total_progress = bytesTotal; + m_progress = bytesReceived; + emit progress(m_index_within_job, bytesReceived, bytesTotal); +} diff --git a/logic/screenshots/ImgurUpload.h b/logic/screenshots/ImgurUpload.h new file mode 100644 index 000000000..1111a8d03 --- /dev/null +++ b/logic/screenshots/ImgurUpload.h @@ -0,0 +1,30 @@ +#pragma once +#include "logic/net/NetAction.h" +#include "Screenshot.h" + +typedef std::shared_ptr ImgurUploadPtr; +class ImgurUpload : public NetAction +{ +public: + explicit ImgurUpload(ScreenshotPtr shot); + static ImgurUploadPtr make(ScreenshotPtr shot) + { + return ImgurUploadPtr(new ImgurUpload(shot)); + } + +protected +slots: + virtual void downloadProgress(qint64 bytesReceived, qint64 bytesTotal); + virtual void downloadError(QNetworkReply::NetworkError error); + virtual void downloadFinished(); + virtual void downloadReadyRead() + { + } + +public +slots: + virtual void start(); + +private: + ScreenshotPtr m_shot; +}; diff --git a/logic/screenshots/Screenshot.cpp b/logic/screenshots/Screenshot.cpp new file mode 100644 index 000000000..882e491ff --- /dev/null +++ b/logic/screenshots/Screenshot.cpp @@ -0,0 +1,14 @@ +#include "Screenshot.h" +#include +#include +QIcon ScreenShot::getImage() +{ + if(!imageloaded) + { + QImage image(file); + QImage thumbnail = image.scaledToWidth(256, Qt::SmoothTransformation); + m_image = QIcon(QPixmap::fromImage(thumbnail)); + imageloaded = true; + } + return m_image; +} diff --git a/logic/screenshots/Screenshot.h b/logic/screenshots/Screenshot.h new file mode 100644 index 000000000..815c0d47b --- /dev/null +++ b/logic/screenshots/Screenshot.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include +#include +#include + +struct ScreenShot +{ + QIcon getImage(); + QIcon m_image; + bool imageloaded = false; + QDateTime timestamp; + QString file; + QString url; + QString imgurId; +}; + +typedef std::shared_ptr ScreenshotPtr; diff --git a/logic/screenshots/ScreenshotList.cpp b/logic/screenshots/ScreenshotList.cpp new file mode 100644 index 000000000..8a64dc36d --- /dev/null +++ b/logic/screenshots/ScreenshotList.cpp @@ -0,0 +1,113 @@ +#include "ScreenshotList.h" +#include "gui/dialogs/ScreenshotDialog.h" + +#include +#include +#include +#include "gui/dialogs/ProgressDialog.h" +#include "gui/dialogs/CustomMessageBox.h" + +ScreenshotList::ScreenshotList(BaseInstance *instance, QObject *parent) + : QAbstractListModel(parent), m_instance(instance) +{ +} + +int ScreenshotList::rowCount(const QModelIndex &) const +{ + return m_screenshots.size(); +} + +QVariant ScreenshotList::data(const QModelIndex &index, int role) const +{ + if (index.row() >= m_screenshots.size() || index.row() < 0) + return QVariant(); + + switch (role) + { + case Qt::DecorationRole: + return m_screenshots.at(index.row())->getImage(); + case Qt::DisplayRole: + return m_screenshots.at(index.row())->timestamp.toString("yyyy-MM-dd HH:mm:ss"); + case Qt::ToolTipRole: + return m_screenshots.at(index.row())->timestamp.toString("yyyy-MM-dd HH:mm:ss"); + case Qt::TextAlignmentRole: + return (int)(Qt::AlignHCenter | Qt::AlignVCenter); + default: + return QVariant(); + } +} + +QVariant ScreenshotList::headerData(int section, Qt::Orientation orientation, int role) const +{ + return QVariant(); +} + +Qt::ItemFlags ScreenshotList::flags(const QModelIndex &index) const +{ + return Qt::ItemIsSelectable | Qt::ItemIsEnabled; +} + +Task *ScreenshotList::load() +{ + return new ScreenshotLoadTask(this); +} + +ScreenshotLoadTask::ScreenshotLoadTask(ScreenshotList *list) : m_list(list) +{ +} + +ScreenshotLoadTask::~ScreenshotLoadTask() +{ +} + +void ScreenshotLoadTask::executeTask() +{ + auto dir = QDir(m_list->instance()->minecraftRoot()); + if (!dir.cd("screenshots")) + { + emitFailed("Selected instance does not have any screenshots!"); + return; + } + dir.setNameFilters(QStringList() << "*.png"); + this->m_results.clear(); + for (auto file : dir.entryList()) + { + ScreenShot *shot = new ScreenShot(); + shot->timestamp = QDateTime::fromString(file, "yyyy-MM-dd_HH.mm.ss.png"); + shot->file = dir.absoluteFilePath(file); + m_results.append(ScreenshotPtr(shot)); + } + m_list->loadShots(m_results); + emitSucceeded(); +} + +void ScreenshotList::deleteSelected(ScreenshotDialog *dialog) +{ + auto screens = dialog->selected(); + if (screens.isEmpty()) + { + return; + } + beginResetModel(); + QList>::const_iterator it; + for (it = screens.cbegin(); it != screens.cend(); it++) + { + auto shot = *it; + if (!QFile(shot->file).remove()) + { + CustomMessageBox::selectable(dialog, tr("Error!"), + tr("Failed to delete screenshots!"), + QMessageBox::Warning)->exec(); + break; + } + } + ProgressDialog refresh(dialog); + Task *t = load(); + if (refresh.exec(t) != QDialog::Accepted) + { + CustomMessageBox::selectable(dialog, tr("Error!"), + tr("Unable to refresh list: %1").arg(t->failReason()), + QMessageBox::Warning)->exec(); + } + endResetModel(); +} diff --git a/logic/screenshots/ScreenshotList.h b/logic/screenshots/ScreenshotList.h new file mode 100644 index 000000000..ca6314e96 --- /dev/null +++ b/logic/screenshots/ScreenshotList.h @@ -0,0 +1,70 @@ +#pragma once + +#include +#include "logic/BaseInstance.h" +#include "logic/tasks/Task.h" + +#include "Screenshot.h" + +class ScreenshotList : public QAbstractListModel +{ + Q_OBJECT +public: + ScreenshotList(BaseInstance *instance, QObject *parent = 0); + + QVariant data(const QModelIndex &index, int role) const; + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + + int rowCount(const QModelIndex &parent) const; + + Qt::ItemFlags flags(const QModelIndex &index) const; + + Task *load(); + + void loadShots(QList shots) + { + m_screenshots = shots; + } + + QList screenshots() const + { + return m_screenshots; + } + + BaseInstance *instance() const + { + return m_instance; + } + + void deleteSelected(class ScreenshotDialog *dialog); + +signals: + +public +slots: + +private: + QList m_screenshots; + BaseInstance *m_instance; +}; + +class ScreenshotLoadTask : public Task +{ + Q_OBJECT + +public: + explicit ScreenshotLoadTask(ScreenshotList *list); + ~ScreenshotLoadTask(); + + QList screenShots() const + { + return m_results; + } + +protected: + virtual void executeTask(); + +private: + ScreenshotList *m_list; + QList m_results; +}; diff --git a/logic/tasks/SequentialTask.cpp b/logic/tasks/SequentialTask.cpp index 63025eee8..e0f8fcdd7 100644 --- a/logic/tasks/SequentialTask.cpp +++ b/logic/tasks/SequentialTask.cpp @@ -28,7 +28,7 @@ void SequentialTask::getProgress(qint64 ¤t, qint64 &total) } } -void SequentialTask::addTask(std::shared_ptr task) +void SequentialTask::addTask(std::shared_ptr task) { m_queue.append(task); } @@ -43,7 +43,7 @@ void SequentialTask::startNext() { if (m_currentIndex != -1) { - std::shared_ptr previous = m_queue[m_currentIndex]; + std::shared_ptr previous = m_queue[m_currentIndex]; disconnect(previous.get(), 0, this, 0); } m_currentIndex++; @@ -52,7 +52,7 @@ void SequentialTask::startNext() emitSucceeded(); return; } - std::shared_ptr next = m_queue[m_currentIndex]; + std::shared_ptr next = m_queue[m_currentIndex]; connect(next.get(), SIGNAL(failed(QString)), this, SLOT(subTaskFailed(QString))); connect(next.get(), SIGNAL(status(QString)), this, SLOT(subTaskStatus(QString))); connect(next.get(), SIGNAL(progress(qint64,qint64)), this, SLOT(subTaskProgress())); @@ -73,5 +73,12 @@ void SequentialTask::subTaskProgress() { qint64 current, total; getProgress(current, total); - setProgress(100 * current / total); + if (total == 0) + { + setProgress(0); + } + else + { + setProgress(100 * current / total); + } } diff --git a/logic/tasks/SequentialTask.h b/logic/tasks/SequentialTask.h index 7f0469289..c405dca37 100644 --- a/logic/tasks/SequentialTask.h +++ b/logic/tasks/SequentialTask.h @@ -14,7 +14,7 @@ public: virtual QString getStatus() const; virtual void getProgress(qint64 ¤t, qint64 &total); - void addTask(std::shared_ptr task); + void addTask(std::shared_ptr task); protected: void executeTask(); @@ -27,6 +27,6 @@ slots: void subTaskProgress(); private: - QQueue > m_queue; + QQueue > m_queue; int m_currentIndex; };