Merge branch 'develop' of github.com:MultiMC/MultiMC5 into develop
This commit is contained in:
		
							
								
								
									
										229
									
								
								CMakeLists.txt
									
									
									
									
									
								
							
							
						
						
									
										229
									
								
								CMakeLists.txt
									
									
									
									
									
								
							| @@ -27,14 +27,14 @@ ENDIF() | ||||
| ######## Set compiler flags ######## | ||||
| IF(APPLE) | ||||
| 	message(STATUS "Using APPLE CMAKE_CXX_FLAGS") | ||||
| 	SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") | ||||
| 	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++0x") | ||||
| 	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++0x") | ||||
| 	SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -Wall") | ||||
| ENDIF() | ||||
|  | ||||
| ################################ INCLUDE LIBRARIES ################################ | ||||
| @@ -48,6 +48,23 @@ find_package(Qt5LinguistTools REQUIRED) | ||||
|  | ||||
| include_directories(${Qt5Widgets_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) | ||||
| endfunction(QUERY_QMAKE) | ||||
|  | ||||
| query_qmake(QT_INSTALL_PLUGINS QT_PLUGINS_DIR) | ||||
| query_qmake(QT_INSTALL_IMPORTS QT_IMPORTS_DIR) | ||||
| query_qmake(QT_INSTALL_LIBS QT_LIBS_DIR) | ||||
| query_qmake(QT_HOST_DATA QT_DATA_DIR) | ||||
| set(QT_MKSPECS_DIR ${QT_DATA_DIR}/mkspecs) | ||||
|  | ||||
|  | ||||
| ######## Included Libs ######## | ||||
|  | ||||
| # Add quazip | ||||
| @@ -289,11 +306,14 @@ logic/auth/MojangAccount.h | ||||
| logic/auth/MojangAccount.cpp | ||||
| logic/auth/YggdrasilTask.h | ||||
| logic/auth/YggdrasilTask.cpp | ||||
| logic/auth/AuthenticateTask.h | ||||
| logic/auth/AuthenticateTask.cpp | ||||
| logic/auth/ValidateTask.h | ||||
| logic/auth/ValidateTask.cpp | ||||
|  | ||||
| logic/auth/flows/AuthenticateTask.h | ||||
| logic/auth/flows/AuthenticateTask.cpp | ||||
| logic/auth/flows/RefreshTask.cpp | ||||
| logic/auth/flows/RefreshTask.cpp | ||||
| logic/auth/flows/ValidateTask.h | ||||
| logic/auth/flows/ValidateTask.cpp | ||||
| logic/auth/flows/InvalidateTask.h | ||||
| logic/auth/flows/InvalidateTask.cpp | ||||
|  | ||||
| # legacy instances | ||||
| logic/LegacyInstance.h | ||||
| @@ -439,7 +459,6 @@ CONFIGURE_FILE(generated.qrc.in generated.qrc) | ||||
| QT5_ADD_RESOURCES(GENERATED_QRC ${CMAKE_CURRENT_BINARY_DIR}/generated.qrc) | ||||
| QT5_ADD_RESOURCES(GRAPHICS_QRC graphics.qrc) | ||||
|  | ||||
|  | ||||
| # Add executable | ||||
| ADD_EXECUTABLE(MultiMC MACOSX_BUNDLE WIN32 | ||||
| 	${MULTIMC_SOURCES} ${MULTIMC_UI} ${GRAPHICS_QRC} ${GENERATED_QRC} ${MULTIMC_RCS}) | ||||
| @@ -449,110 +468,122 @@ TARGET_LINK_LIBRARIES(MultiMC xz-embedded unpack200 quazip libUtil libSettings l | ||||
| QT5_USE_MODULES(MultiMC Core Widgets Network Xml ${MultiMC_QT_ADDITIONAL_MODULES}) | ||||
| ADD_DEPENDENCIES(MultiMC MultiMCLauncher JavaCheck) | ||||
|  | ||||
| option(BUILD_KEYRING_TEST "Build the simple keyring test binary" OFF) | ||||
| IF(BUILD_KEYRING_TEST) | ||||
| 	# test.cpp | ||||
| 	ADD_EXECUTABLE(Test test.cpp) | ||||
| 	QT5_USE_MODULES(Test Core) | ||||
| 	TARGET_LINK_LIBRARIES(Test libUtil libSettings) | ||||
| ENDIF() | ||||
|  | ||||
| ################################ INSTALLATION AND PACKAGING ################################ | ||||
| # use QtCreator's QTDIR var | ||||
| IF(DEFINED ENV{QTDIR}) | ||||
| 	SET(Qt5_DIR $ENV{QTDIR}) | ||||
| ENDIF() | ||||
|  | ||||
| ######## Plugin and library folders ######## | ||||
| ######## Packaging/install paths setup ######## | ||||
|  | ||||
| SET(PLUGIN_DEST_DIR plugins) | ||||
| SET(QTCONF_DEST_DIR .) | ||||
| SET(APPS "\${CMAKE_INSTALL_PREFIX}/MultiMC") | ||||
| IF(UNIX AND APPLE) | ||||
| 	SET(PLUGIN_DEST_DIR MultiMC.app/Contents/MacOS) | ||||
| 	SET(QTCONF_DEST_DIR MultiMC.app/Contents/Resources) | ||||
| 	SET(APPS "\${CMAKE_INSTALL_PREFIX}/MultiMC.app") | ||||
|  | ||||
| IF(WIN32) | ||||
| 	SET(MACOSX_BUNDLE_BUNDLE_NAME "MultiMC") | ||||
| 	SET(MACOSX_BUNDLE_INFO_STRING "MultiMC Minecraft launcher and management utility.") | ||||
| 	SET(MACOSX_BUNDLE_BUNDLE_VERSION "${MultiMC_VERSION_MAJOR}.${MultiMC_VERSION_MINOR}.${MultiMC_VERSION_REV}.${MultiMC_VERSION_BUILD}") | ||||
| 	#SET(MACOSX_BUNDLE_GUI_IDENTIFIER "") | ||||
| 	SET(MACOSX_BUNDLE_ICON_FILE MultiMC.icns) | ||||
| ELSEIF(UNIX) | ||||
| 	SET(PLUGIN_DEST_DIR plugins) | ||||
| 	SET(QTCONF_DEST_DIR .) | ||||
| 	SET(APPS "\${CMAKE_INSTALL_PREFIX}/bin/MultiMC") | ||||
| ELSEIF(WIN32) | ||||
| 	SET(PLUGIN_DEST_DIR .) | ||||
| 	SET(QTCONF_DEST_DIR .) | ||||
| 	SET(APPS "\${CMAKE_INSTALL_PREFIX}/MultiMC.exe") | ||||
| ENDIF() | ||||
|  | ||||
| IF(UNIX) | ||||
| IF(APPLE) | ||||
| 	SET(PLUGIN_DEST_DIR MultiMC.app/Contents/MacOS) | ||||
| 	SET(QTCONF_DEST_DIR MultiMC.app/Contents/Resources) | ||||
| 		SET(APPS "\${CMAKE_INSTALL_PREFIX}/MultiMC.app") | ||||
| ELSE() | ||||
| 	SET(APPS "\${CMAKE_INSTALL_PREFIX}/bin/MultiMC") | ||||
| ENDIF() | ||||
| ENDIF() | ||||
|  | ||||
| SET(QT_PLUGINS_DIR ${Qt5_DIR}/plugins) | ||||
| SET(QT_LIBRARY_DIRS ${Qt5_DIR}/lib) | ||||
|  | ||||
|  | ||||
| ######## OS X Bundle Info ######## | ||||
|  | ||||
| IF(APPLE) | ||||
| 	SET(MACOSX_BUNDLE_BUNDLE_NAME "MultiMC") | ||||
| 	SET(MACOSX_BUNDLE_INFO_STRING "MultiMC Minecraft launcher and management utility.") | ||||
| 	SET(MACOSX_BUNDLE_BUNDLE_VERSION  | ||||
| 		"${MultiMC_VERSION_MAJOR}.${MultiMC_VERSION_MINOR}.${MultiMC_VERSION_REV}.${MultiMC_VERSION_BUILD}") | ||||
| 	#SET(MACOSX_BUNDLE_GUI_IDENTIFIER "") | ||||
| 	SET(MACOSX_BUNDLE_ICON_FILE MultiMC.icns) | ||||
| ENDIF(APPLE) | ||||
| # directories to look for dependencies | ||||
| SET(DIRS "${QT_LIBS_DIR}") | ||||
|  | ||||
| ######## Install ######## | ||||
|  | ||||
| #### Executable #### | ||||
| IF(WIN32) | ||||
| INSTALL(TARGETS MultiMC  | ||||
| 	BUNDLE DESTINATION . COMPONENT Runtime | ||||
| 	LIBRARY DESTINATION . COMPONENT Runtime | ||||
| 	RUNTIME DESTINATION . COMPONENT Runtime | ||||
| IF(APPLE AND UNIX) ## OSX | ||||
| 	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 .) | ||||
|  | ||||
| ELSEIF(WIN32) ## WINDOWS | ||||
| 	INSTALL(TARGETS MultiMC  | ||||
| 		BUNDLE DESTINATION . COMPONENT Runtime | ||||
| 		LIBRARY DESTINATION . COMPONENT Runtime | ||||
| 		RUNTIME DESTINATION . COMPONENT Runtime | ||||
| 	) | ||||
| ENDIF() | ||||
|  | ||||
| #### Dist package logic #### | ||||
|  | ||||
| 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 | ||||
| ) | ||||
| ENDIF() | ||||
| IF(UNIX) | ||||
| IF(APPLE) | ||||
| INSTALL(TARGETS MultiMC  | ||||
| 	BUNDLE DESTINATION . COMPONENT Runtime | ||||
| 	RUNTIME DESTINATION MultiMC.app/Contents/MacOS COMPONENT Runtime | ||||
|  | ||||
| # Platform plugins | ||||
| INSTALL( | ||||
| 	DIRECTORY "${QT_PLUGINS_DIR}/platforms" | ||||
| 	DESTINATION ${PLUGIN_DEST_DIR} | ||||
| 	COMPONENT Runtime | ||||
| 	REGEX "minimal|linuxfb|offscreen" EXCLUDE | ||||
| ) | ||||
| ELSE() | ||||
| INSTALL(TARGETS MultiMC  | ||||
| 	BUNDLE DESTINATION . COMPONENT Runtime | ||||
| 	RUNTIME DESTINATION bin COMPONENT Runtime | ||||
| 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 | ||||
| ) | ||||
|  | ||||
| # 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 | ||||
| ) | ||||
| endif() | ||||
|  | ||||
| # qtconf | ||||
| INSTALL( | ||||
| 	CODE " | ||||
| FILE(WRITE \"\${CMAKE_INSTALL_PREFIX}/${QTCONF_DEST_DIR}/qt.conf\" \"\") | ||||
| " | ||||
| 	COMPONENT Runtime | ||||
| ) | ||||
| INSTALL(PROGRAMS package/linux/MultiMC DESTINATION .) | ||||
| ENDIF() | ||||
| ENDIF() | ||||
|  | ||||
|  | ||||
| #### Plugins #### | ||||
| INSTALL( | ||||
| 	CODE " | ||||
| FILE(GLOB_RECURSE	QTPLUGINS \"\${CMAKE_INSTALL_PREFIX}/${PLUGIN_DEST_DIR}/*${CMAKE_SHARED_LIBRARY_SUFFIX}\") | ||||
| function(gp_resolved_file_type_override resolved_file type_var) | ||||
| 	if(resolved_file MATCHES \"^/usr/lib/libQt\") | ||||
| 		message(\"resolving \${resolved_file} as other\") | ||||
| 		set(\${type_var} other PARENT_SCOPE) | ||||
|     endif() | ||||
| endfunction() | ||||
|  | ||||
| OPTION(MultiMC_INSTALL_SHARED_LIBS "if set, Qt's shared libraries will be copied to the installation directory on install") | ||||
| include(BundleUtilities) | ||||
| fixup_bundle(\"${APPS}\" \"\${QTPLUGINS}\" \"${DIRS}\") | ||||
| " | ||||
| 	COMPONENT Runtime | ||||
| ) | ||||
|  | ||||
| IF (MultiMC_INSTALL_SHARED_LIBS) | ||||
| 	# Image formats | ||||
| 	INSTALL(DIRECTORY "${QT_PLUGINS_DIR}/imageformats" DESTINATION ${PLUGIN_DEST_DIR} COMPONENT Runtime) | ||||
|  | ||||
| 	# Platform plugins | ||||
| 	INSTALL(DIRECTORY "${QT_PLUGINS_DIR}/platforms" DESTINATION ${PLUGIN_DEST_DIR} COMPONENT Runtime) | ||||
|  | ||||
| 	# qtconf | ||||
| 	INSTALL(CODE " | ||||
| 		FILE(WRITE \"\${CMAKE_INSTALL_PREFIX}/${QTCONF_DEST_DIR}/qt.conf\" \"\") | ||||
| 		" COMPONENT Runtime) | ||||
|  | ||||
|  | ||||
| 	# Dirs to look for dependencies. | ||||
| 	SET(DIRS "${QT_LIBRARY_DIRS}") | ||||
|  | ||||
| 	INSTALL(CODE " | ||||
| 		file(GLOB_RECURSE QTPLUGINS | ||||
| 			\"\${CMAKE_INSTALL_PREFIX}/${PLUGIN_DEST_DIR}/plugins/*${CMAKE_SHARED_LIBRARY_SUFFIX}\") | ||||
| 		include(BundleUtilities) | ||||
| 		fixup_bundle(\"${APPS}\" \"\${QTPLUGINS}\" \"${DIRS}\") | ||||
| 		" COMPONENT Runtime) | ||||
| ENDIF() | ||||
|  | ||||
|  | ||||
| ######## Package ######## | ||||
| @@ -596,14 +627,12 @@ include_directories(${PROJECT_BINARY_DIR}/include) | ||||
| 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}) | ||||
| else (UPDATE_TRANSLATIONS) | ||||
|   qt5_add_translation(QM_FILES ${TRANSLATIONS_FILES}) | ||||
| endif (UPDATE_TRANSLATIONS)  | ||||
| IF(UPDATE_TRANSLATIONS) | ||||
| 	qt5_create_translation(QM_FILES ${FILES_TO_TRANSLATE} ${TRANSLATIONS_FILES}) | ||||
| ELSE() | ||||
| 	qt5_add_translation(QM_FILES ${TRANSLATIONS_FILES}) | ||||
| ENDIF() | ||||
|  | ||||
| add_custom_target (translations DEPENDS ${QM_FILES}) | ||||
|  | ||||
| install(FILES ${QM_FILES} DESTINATION ${CMAKE_INSTALL_PREFIX}/translations) | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -189,6 +189,9 @@ MultiMC::MultiMC(int &argc, char **argv) : QApplication(argc, argv), | ||||
| 		case QNetworkProxy::FtpCachingProxy: | ||||
| 			proxyDesc = "FTP caching: "; | ||||
| 			break; | ||||
| 		default: | ||||
| 			proxyDesc = "DERP proxy: "; | ||||
| 			break; | ||||
| 		} | ||||
| 		proxyDesc += QString("%3@%1:%2 pass %4") | ||||
| 						 .arg(proxy.hostName()) | ||||
| @@ -326,6 +329,7 @@ void MultiMC::initGlobalSettings() | ||||
|  | ||||
|  | ||||
| 	m_settings->registerSetting(new Setting("InstSortMode", "Name")); | ||||
| 	m_settings->registerSetting(new Setting("SelectedInstance", QString())); | ||||
|  | ||||
| 	// Persistent value for the client ID | ||||
| 	m_settings->registerSetting(new Setting("YggdrasilClientToken", "")); | ||||
|   | ||||
| @@ -58,18 +58,6 @@ struct KCategorizedView::Private::Item | ||||
|  | ||||
| struct KCategorizedView::Private::Block | ||||
| { | ||||
| 	Block() | ||||
| 		: topLeft ( QPoint() ) | ||||
| 		, height ( -1 ) | ||||
| 		, firstIndex ( QModelIndex() ) | ||||
| 		, quarantineStart ( QModelIndex() ) | ||||
| 		, items ( QList<Item>() ) | ||||
| 		, outOfQuarantine ( false ) | ||||
| 		, alternate ( false ) | ||||
| 		, collapsed ( false ) | ||||
| 	{ | ||||
| 	} | ||||
|  | ||||
| 	bool operator!= ( const Block &rhs ) const | ||||
| 	{ | ||||
| 		return firstIndex != rhs.firstIndex; | ||||
| @@ -83,7 +71,7 @@ struct KCategorizedView::Private::Block | ||||
| 	} | ||||
|  | ||||
| 	QPoint topLeft; | ||||
| 	int height; | ||||
| 	int height = -1; | ||||
| 	QPersistentModelIndex firstIndex; | ||||
| 	// if we have n elements on this block, and we inserted an element at position i. The quarantine | ||||
| 	// will start at index (i, column, parent). This means that for all elements j where i <= j <= n, the | ||||
| @@ -97,25 +85,16 @@ struct KCategorizedView::Private::Block | ||||
| 	// this affects the whole block, not items separately. items contain the topLeft point relative | ||||
| 	// to the block. Because of insertions or removals a whole block can be moved, so the whole block | ||||
| 	// will enter in quarantine, what is faster than moving all items in absolute terms. | ||||
| 	bool outOfQuarantine; | ||||
| 	bool outOfQuarantine = false; | ||||
|  | ||||
| 	// should we alternate its color ? is just a hint, could not be used | ||||
| 	bool alternate; | ||||
| 	bool collapsed; | ||||
| 	bool alternate = false; | ||||
| 	bool collapsed = false; | ||||
| }; | ||||
|  | ||||
| KCategorizedView::Private::Private ( KCategorizedView *q ) | ||||
| 	: q ( q ) | ||||
| 	, proxyModel ( 0 ) | ||||
| 	, categoryDrawer ( 0 ) | ||||
| 	, categorySpacing ( 5 ) | ||||
| 	, alternatingBlockColors ( false ) | ||||
| 	, collapsibleBlocks ( false ) | ||||
| 	, hoveredBlock ( new Block() ) | ||||
| 	, hoveredIndex ( QModelIndex() ) | ||||
| 	, pressedPosition ( QPoint() ) | ||||
| 	, rubberBandRect ( QRect() ) | ||||
| 	, constantItemWidth( 0 ) | ||||
| { | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -137,14 +137,15 @@ public: | ||||
| 	  */ | ||||
| 	void _k_slotCollapseOrExpandClicked(QModelIndex); | ||||
|  | ||||
| 	KCategorizedView *q; | ||||
| 	KCategorizedSortFilterProxyModel *proxyModel; | ||||
| 	KCategoryDrawer *categoryDrawer; | ||||
| 	int categorySpacing; | ||||
| 	bool alternatingBlockColors; | ||||
| 	bool collapsibleBlocks; | ||||
| 	bool constantItemWidth; | ||||
| 	KCategorizedView *q = nullptr; | ||||
| 	KCategorizedSortFilterProxyModel *proxyModel = nullptr; | ||||
| 	KCategoryDrawer *categoryDrawer = nullptr; | ||||
| 	int categorySpacing = 5; | ||||
| 	bool alternatingBlockColors = false; | ||||
| 	bool collapsibleBlocks = false; | ||||
| 	bool constantItemWidth = false; | ||||
|  | ||||
| 	// FIXME: this is some really weird logic. Investigate. | ||||
| 	Block *hoveredBlock; | ||||
| 	QString hoveredCategory; | ||||
| 	QModelIndex hoveredIndex; | ||||
|   | ||||
| @@ -42,9 +42,9 @@ public: | ||||
|     ~Private() | ||||
|     { | ||||
|     } | ||||
|     KCategorizedView *view; | ||||
|     int leftMargin; | ||||
|     int rightMargin; | ||||
|     KCategorizedView *view; | ||||
| }; | ||||
|  | ||||
| KCategoryDrawer::KCategoryDrawer(KCategorizedView *view) | ||||
|   | ||||
| @@ -79,7 +79,6 @@ void band::readData(int expectedLength) | ||||
|  | ||||
| 	// Read one value to see what it might be. | ||||
| 	int XB = _meta_default; | ||||
| 	int cp1 = 0, cp2 = 0; | ||||
| 	if (!is_BYTE1) | ||||
| 	{ | ||||
| 		// must be a variable-length coding | ||||
| @@ -109,7 +108,6 @@ void band::readData(int expectedLength) | ||||
| 		{ | ||||
| 			// Skip over the escape value. | ||||
| 			u->rp = xvs.rp; | ||||
| 			cp1 = 1; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
|   | ||||
| @@ -87,7 +87,7 @@ struct bytes | ||||
| 		bytes res; | ||||
| 		res.ptr = ptr + beg; | ||||
| 		res.len = end - beg; | ||||
| 		assert(res.len == 0 || inBounds(res.ptr) && inBounds(res.limit() - 1)); | ||||
| 		assert(res.len == 0 ||(inBounds(res.ptr) && inBounds(res.limit() - 1))); | ||||
| 		return res; | ||||
| 	} | ||||
| 	// building C strings inside byte buffers: | ||||
|   | ||||
| @@ -121,7 +121,6 @@ coding *coding::init() | ||||
| 		this->min = this->umin = 0; | ||||
| 		if (S != 0 && range != 0) | ||||
| 		{ | ||||
| 			int Smask = (1 << S) - 1; | ||||
| 			int64_t maxPosCode = range - 1; | ||||
| 			int64_t maxNegCode = range - 1; | ||||
| 			while (IS_NEG_CODE(S, maxPosCode)) | ||||
|   | ||||
| @@ -483,10 +483,6 @@ void unpacker::putu1ref(entry *e) | ||||
| 	putu1_at(put_space(1), oidx); | ||||
| } | ||||
|  | ||||
| static int total_cp_size[] = {0, 0}; | ||||
| static int largest_cp_ref[] = {0, 0}; | ||||
| static int hash_probes[] = {0, 0}; | ||||
|  | ||||
| // Allocation of small and large blocks. | ||||
|  | ||||
| enum | ||||
| @@ -705,7 +701,7 @@ void unpacker::read_file_header() | ||||
| 			unpack_abort("impossible archive size"); // bad input data | ||||
| 			return; | ||||
| 		} | ||||
| 		if (archive_size < header_size_1) | ||||
| 		if (archive_size < (size_t)header_size_1) | ||||
| 		{ | ||||
| 			unpack_abort("too much read-ahead"); // somehow we pre-fetched too much? | ||||
| 			return; | ||||
| @@ -1316,8 +1312,6 @@ void unpacker::read_signature_values(entry *cpMap, int len) | ||||
| // Cf. PackageReader.readConstantPool | ||||
| void unpacker::read_cp() | ||||
| { | ||||
| 	byte *rp0 = rp; | ||||
|  | ||||
| 	int i; | ||||
|  | ||||
| 	for (int k = 0; k < (int)N_TAGS_IN_ORDER; k++) | ||||
| @@ -1596,7 +1590,6 @@ band **unpacker::attr_definitions::buildBands(unpacker::layout_definition *lo) | ||||
| const char *unpacker::attr_definitions::parseIntLayout(const char *lp, band *&res, byte le_kind, | ||||
| 													   bool can_be_signed) | ||||
| { | ||||
| 	const char *lp0 = lp; | ||||
| 	band *b = U_NEW(band, 1); | ||||
| 	char le = *lp++; | ||||
| 	int spec = UNSIGNED5_spec; | ||||
| @@ -1638,7 +1631,6 @@ const char *unpacker::attr_definitions::parseIntLayout(const char *lp, band *&re | ||||
|  | ||||
| const char *unpacker::attr_definitions::parseNumeral(const char *lp, int &res) | ||||
| { | ||||
| 	const char *lp0 = lp; | ||||
| 	bool sgn = false; | ||||
| 	if (*lp == '0') | ||||
| 	{ | ||||
| @@ -1703,7 +1695,6 @@ band **unpacker::attr_definitions::popBody(int bs_base) | ||||
|  | ||||
| const char *unpacker::attr_definitions::parseLayout(const char *lp, band **&res, int curCble) | ||||
| { | ||||
| 	const char *lp0 = lp; | ||||
| 	int bs_base = band_stack.length(); | ||||
| 	bool top_level = (bs_base == 0); | ||||
| 	band *b; | ||||
| @@ -3135,8 +3126,6 @@ unpacker::read_bcs() | ||||
|  | ||||
| void unpacker::read_bands() | ||||
| { | ||||
| 	byte *rp0 = rp; | ||||
|  | ||||
| 	read_file_header(); | ||||
|  | ||||
| 	if (cp.nentries == 0) | ||||
| @@ -3312,7 +3301,7 @@ void constant_pool::initMemberIndexes() | ||||
|  | ||||
| 	// Get the pre-existing indexes: | ||||
| 	int nclasses = tag_count[CONSTANT_Class]; | ||||
| 	entry *classes = tag_base[CONSTANT_Class] + entries; | ||||
| 	// entry *classes = tag_base[CONSTANT_Class] + entries; // UNUSED | ||||
| 	int nfields = tag_count[CONSTANT_Fieldref]; | ||||
| 	entry *fields = tag_base[CONSTANT_Fieldref] + entries; | ||||
| 	int nmethods = tag_count[CONSTANT_Methodref]; | ||||
| @@ -3563,8 +3552,6 @@ void unpacker::start(void *packptr, size_t len) | ||||
|  | ||||
| void unpacker::check_options() | ||||
| { | ||||
| 	const char *strue = "true"; | ||||
| 	const char *sfalse = "false"; | ||||
| 	if (deflate_hint_or_zero != 0) | ||||
| 	{ | ||||
| 		bool force_deflate_hint = (deflate_hint_or_zero > 0); | ||||
|   | ||||
| @@ -97,8 +97,6 @@ static int read_magic(unpacker *u, char peek[], int peeklen) | ||||
| void unpack_200(std::string input_path, std::string output_path) | ||||
| { | ||||
| 	unpacker u; | ||||
| 	int status = 0; | ||||
|  | ||||
| 	FILE *input = fopen(input_path.c_str(), "rb"); | ||||
| 	if (!input) | ||||
| 	{ | ||||
|   | ||||
| @@ -1173,7 +1173,7 @@ extern int ZEXPORT unzOpenCurrentFile3 (file, method, level, raw, password) | ||||
|     if (password != NULL) | ||||
|     { | ||||
|         int i; | ||||
|         s->pcrc_32_tab = get_crc_table(); | ||||
|         s->pcrc_32_tab = (const unsigned long*) get_crc_table(); | ||||
|         init_keys(password,s->keys,s->pcrc_32_tab); | ||||
|         if (ZSEEK(s->z_filefunc, s->filestream, | ||||
|                   s->pfile_in_zip_read->pos_in_zipfile + | ||||
|   | ||||
| @@ -903,7 +903,7 @@ extern int ZEXPORT zipOpenNewFileInZip3 (file, filename, zipfi, | ||||
|         unsigned char bufHead[RAND_HEAD_LEN]; | ||||
|         unsigned int sizeHead; | ||||
|         zi->ci.encrypt = 1; | ||||
|         zi->ci.pcrc_32_tab = get_crc_table(); | ||||
|         zi->ci.pcrc_32_tab = (const unsigned long*) get_crc_table(); | ||||
|         /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/ | ||||
|  | ||||
|         crcForCrypting = (uLong)zi->ci.dosDate << 16; // ATTANTION! Without this row, you don't unpack your password protected archive in other app. | ||||
|   | ||||
| @@ -33,6 +33,11 @@ | ||||
| class LIBSETTINGS_EXPORT Keyring | ||||
| { | ||||
| public: | ||||
| 	/** | ||||
| 	 * @brief virtual dtor | ||||
| 	 */ | ||||
| 	virtual ~Keyring() {}; | ||||
|  | ||||
| 	/** | ||||
| 	 * @brief the System Keyring instance | ||||
| 	 * @return the Keyring instance | ||||
|   | ||||
| @@ -24,6 +24,11 @@ | ||||
| class StubKeyring : public Keyring | ||||
| { | ||||
| public: | ||||
| 	/** | ||||
| 	 * @brief virtual dtor | ||||
| 	 */ | ||||
| 	virtual ~StubKeyring() {}; | ||||
|  | ||||
| 	virtual bool storePassword(QString service, QString username, QString password); | ||||
| 	virtual QString getPassword(QString service, QString username); | ||||
| 	virtual bool hasPassword(QString service, QString username); | ||||
|   | ||||
| @@ -58,13 +58,23 @@ void ConsoleWindow::writeColor(QString text, const char *color) | ||||
| 		ui->text->appendHtml(QString("<font color=\"%1\">%2</font>").arg(color).arg(text)); | ||||
| 	else | ||||
| 		ui->text->appendPlainText(text); | ||||
| 	// scroll down | ||||
| 	QScrollBar *bar = ui->text->verticalScrollBar(); | ||||
| 	bar->setValue(bar->maximum()); | ||||
| } | ||||
|  | ||||
| void ConsoleWindow::write(QString data, MessageLevel::Enum mode) | ||||
| { | ||||
| 	QScrollBar *bar = ui->text->verticalScrollBar(); | ||||
| 	int max_bar = bar->maximum(); | ||||
| 	int val_bar = bar->value(); | ||||
| 	if(m_scroll_active) | ||||
| 	{ | ||||
| 		if(m_last_scroll_value > val_bar) | ||||
| 			m_scroll_active = false; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		m_scroll_active = val_bar == max_bar; | ||||
| 	} | ||||
|  | ||||
| 	if (data.endsWith('\n')) | ||||
| 		data = data.left(data.length() - 1); | ||||
| 	QStringList paragraphs = data.split('\n'); | ||||
| @@ -93,6 +103,11 @@ void ConsoleWindow::write(QString data, MessageLevel::Enum mode) | ||||
| 	else | ||||
| 		while (iter.hasNext()) | ||||
| 			writeColor(iter.next()); | ||||
| 	if(m_scroll_active) | ||||
| 	{ | ||||
| 		bar->setValue(bar->maximum()); | ||||
| 	} | ||||
| 	m_last_scroll_value = bar->value(); | ||||
| } | ||||
|  | ||||
| void ConsoleWindow::clear() | ||||
|   | ||||
| @@ -38,6 +38,16 @@ public: | ||||
| 	 */ | ||||
| 	void setMayClose(bool mayclose); | ||||
|  | ||||
| private: | ||||
| 	/** | ||||
| 	 * @brief write a colored paragraph | ||||
| 	 * @param data the string | ||||
| 	 * @param color the css color name | ||||
| 	 * this will only insert a single paragraph. | ||||
| 	 * \n are ignored. a real \n is always appended. | ||||
| 	 */ | ||||
| 	void writeColor(QString data, const char *color = nullptr); | ||||
|  | ||||
| signals: | ||||
| 	void isClosing(); | ||||
|  | ||||
| @@ -51,15 +61,6 @@ slots: | ||||
| 	 */ | ||||
| 	void write(QString data, MessageLevel::Enum level = MessageLevel::MultiMC); | ||||
|  | ||||
| 	/** | ||||
| 	 * @brief write a colored paragraph | ||||
| 	 * @param data the string | ||||
| 	 * @param color the css color name | ||||
| 	 * this will only insert a single paragraph. | ||||
| 	 * \n are ignored. a real \n is always appended. | ||||
| 	 */ | ||||
| 	void writeColor(QString data, const char *color = nullptr); | ||||
|  | ||||
| 	/** | ||||
| 	 * @brief clear the text widget | ||||
| 	 */ | ||||
| @@ -82,4 +83,6 @@ private: | ||||
| 	Ui::ConsoleWindow *ui = nullptr; | ||||
| 	MinecraftProcess *proc = nullptr; | ||||
| 	bool m_mayclose = true; | ||||
| 	int m_last_scroll_value = 0; | ||||
| 	bool m_scroll_active = true; | ||||
| }; | ||||
|   | ||||
| @@ -69,8 +69,9 @@ | ||||
| #include "logic/lists/IconList.h" | ||||
| #include "logic/lists/JavaVersionList.h" | ||||
|  | ||||
| #include "logic/auth/AuthenticateTask.h" | ||||
| #include "logic/auth/ValidateTask.h" | ||||
| #include "logic/auth/flows/AuthenticateTask.h" | ||||
| #include "logic/auth/flows/RefreshTask.h" | ||||
| #include "logic/auth/flows/ValidateTask.h" | ||||
|  | ||||
| #include "logic/BaseInstance.h" | ||||
| #include "logic/InstanceFactory.h" | ||||
| @@ -244,6 +245,28 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi | ||||
| 		connect(assets_downloader, SIGNAL(finished()), SLOT(assetsFinished())); | ||||
| 		assets_downloader->start(); | ||||
| 	} | ||||
|  | ||||
| 	const QString currentInstanceId = MMC->settings()->get("SelectedInstance").toString(); | ||||
| 	if (!currentInstanceId.isNull()) | ||||
| 	{ | ||||
| 		const QModelIndex index = MMC->instances()->getInstanceIndexById(currentInstanceId); | ||||
| 		if (index.isValid()) | ||||
| 		{ | ||||
| 			const QModelIndex mappedIndex = proxymodel->mapFromSource(index); | ||||
| 			view->setCurrentIndex(mappedIndex); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			view->setCurrentIndex(proxymodel->index(0, 0)); | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		view->setCurrentIndex(proxymodel->index(0, 0)); | ||||
| 	} | ||||
|  | ||||
| 	// removing this looks stupid | ||||
| 	view->setFocus(); | ||||
| } | ||||
|  | ||||
| MainWindow::~MainWindow() | ||||
| @@ -254,7 +277,6 @@ MainWindow::~MainWindow() | ||||
| 	delete assets_downloader; | ||||
| } | ||||
|  | ||||
|  | ||||
| void MainWindow::repopulateAccountsMenu() | ||||
| { | ||||
| 	accountMenu->clear(); | ||||
| @@ -769,16 +791,16 @@ void MainWindow::doLaunchInst(BaseInstance* instance, MojangAccountPtr account) | ||||
| { | ||||
| 	// We'll need to validate the access token to make sure the account is still logged in. | ||||
| 	ProgressDialog progDialog(this); | ||||
| 	ValidateTask validateTask(account, &progDialog); | ||||
| 	progDialog.exec(&validateTask); | ||||
| 	 | ||||
| 	if (validateTask.successful()) | ||||
| 	RefreshTask refreshtask(account, &progDialog); | ||||
| 	progDialog.exec(&refreshtask); | ||||
|  | ||||
| 	if (refreshtask.successful()) | ||||
| 	{ | ||||
| 		prepareLaunch(m_selectedInstance, account); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		YggdrasilTask::Error* error = validateTask.getError(); | ||||
| 		YggdrasilTask::Error *error = refreshtask.getError(); | ||||
|  | ||||
| 		if (error != nullptr) | ||||
| 		{ | ||||
| @@ -790,17 +812,20 @@ void MainWindow::doLaunchInst(BaseInstance* instance, MojangAccountPtr account) | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				CustomMessageBox::selectable(this, tr("Access Token Validation Error"), | ||||
| 				CustomMessageBox::selectable( | ||||
| 					this, tr("Access Token Validation Error"), | ||||
| 					tr("There was an error when trying to validate your access token.\n" | ||||
| 						"Details: %s").arg(error->getDisplayMessage()), | ||||
| 					   "Details: %s").arg(error->getDisplayMessage()), | ||||
| 					QMessageBox::Warning, QMessageBox::Ok)->exec(); | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			CustomMessageBox::selectable(this, tr("Access Token Validation Error"), | ||||
| 			CustomMessageBox::selectable( | ||||
| 				this, tr("Access Token Validation Error"), | ||||
| 				tr("There was an unknown error when trying to validate your access token." | ||||
| 					"The authentication server might be down, or you might not be connected to the Internet."), | ||||
| 				   "The authentication server might be down, or you might not be connected to " | ||||
| 				   "the Internet."), | ||||
| 				QMessageBox::Warning, QMessageBox::Ok)->exec(); | ||||
| 		} | ||||
| 	} | ||||
| @@ -857,10 +882,7 @@ void MainWindow::launchInstance(BaseInstance *instance, MojangAccountPtr account | ||||
| 	console = new ConsoleWindow(proc); | ||||
| 	connect(console, SIGNAL(isClosing()), this, SLOT(instanceEnded())); | ||||
|  | ||||
| 	// I think this will work... | ||||
| 	QString username = account->username(); | ||||
| 	QString session_id = account->accessToken(); | ||||
| 	proc->setLogin(username, session_id); | ||||
| 	proc->setLogin(account); | ||||
| 	proc->launch(); | ||||
| } | ||||
|  | ||||
| @@ -983,10 +1005,14 @@ void MainWindow::instanceChanged(const QModelIndex ¤t, const QModelIndex & | ||||
| 		m_statusLeft->setText(m_selectedInstance->getStatusbarDescription()); | ||||
| 		auto ico = MMC->icons()->getIcon(iconKey); | ||||
| 		ui->actionChangeInstIcon->setIcon(ico); | ||||
|  | ||||
| 		MMC->settings()->set("SelectedInstance", m_selectedInstance->id()); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		selectionBad(); | ||||
|  | ||||
| 		MMC->settings()->set("SelectedInstance", QString()); | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -20,7 +20,7 @@ | ||||
|  | ||||
| #include <logger/QsLog.h> | ||||
|  | ||||
| #include <logic/auth/AuthenticateTask.h> | ||||
| #include <logic/auth/flows/AuthenticateTask.h> | ||||
| #include <logic/net/NetJob.h> | ||||
|  | ||||
| #include <gui/dialogs/EditAccountDialog.h> | ||||
| @@ -29,9 +29,8 @@ | ||||
|  | ||||
| #include <MultiMC.h> | ||||
|  | ||||
| AccountListDialog::AccountListDialog(QWidget *parent) : | ||||
| 	QDialog(parent), | ||||
| 	ui(new Ui::AccountListDialog) | ||||
| AccountListDialog::AccountListDialog(QWidget *parent) | ||||
| 	: QDialog(parent), ui(new Ui::AccountListDialog) | ||||
| { | ||||
| 	ui->setupUi(this); | ||||
|  | ||||
| @@ -44,8 +43,8 @@ AccountListDialog::AccountListDialog(QWidget *parent) : | ||||
| 	connect(selectionModel, &QItemSelectionModel::selectionChanged,  | ||||
| 			[this] (const QItemSelection& sel, const QItemSelection& dsel) { updateButtonStates(); }); | ||||
|  | ||||
| 	connect(m_accounts.get(), SIGNAL(listChanged), SLOT(listChanged)); | ||||
| 	connect(m_accounts.get(), SIGNAL(activeAccountChanged), SLOT(listChanged)); | ||||
| 	connect(m_accounts.get(), SIGNAL(listChanged()), SLOT(listChanged())); | ||||
| 	connect(m_accounts.get(), SIGNAL(activeAccountChanged()), SLOT(listChanged())); | ||||
|  | ||||
| 	updateButtonStates(); | ||||
| } | ||||
| @@ -60,7 +59,6 @@ void AccountListDialog::listChanged() | ||||
| 	updateButtonStates(); | ||||
| } | ||||
|  | ||||
|  | ||||
| void AccountListDialog::on_addAccountBtn_clicked() | ||||
| { | ||||
| 	addAccount(tr("Please enter your Mojang or Minecraft account username and password to add your account.")); | ||||
| @@ -84,7 +82,7 @@ void AccountListDialog::on_setDefaultBtn_clicked() | ||||
| 		QModelIndex selected = selection.first(); | ||||
| 		MojangAccountPtr account = selected.data(MojangAccountList::PointerRole).value<MojangAccountPtr>(); | ||||
| 		m_accounts->setActiveAccount(account->username()); | ||||
| 	}	 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void AccountListDialog::on_noDefaultBtn_clicked() | ||||
| @@ -104,7 +102,7 @@ void AccountListDialog::updateButtonStates() | ||||
|  | ||||
| 	ui->rmAccountBtn->setEnabled(selection.size() > 0); | ||||
| 	ui->setDefaultBtn->setEnabled(selection.size() > 0); | ||||
| 	 | ||||
|  | ||||
| 	ui->noDefaultBtn->setDown(m_accounts->activeAccount().get() == nullptr); | ||||
| } | ||||
|  | ||||
| @@ -146,4 +144,3 @@ void AccountListDialog::addAccount(const QString& errMsg) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -21,7 +21,8 @@ | ||||
|  | ||||
| #include "logic/lists/MojangAccountList.h" | ||||
|  | ||||
| namespace Ui { | ||||
| namespace Ui | ||||
| { | ||||
| class AccountListDialog; | ||||
| } | ||||
|  | ||||
| @@ -29,7 +30,7 @@ class AuthenticateTask; | ||||
|  | ||||
| class AccountListDialog : public QDialog | ||||
| { | ||||
| Q_OBJECT | ||||
| 	Q_OBJECT | ||||
| public: | ||||
| 	explicit AccountListDialog(QWidget *parent = 0); | ||||
| 	~AccountListDialog(); | ||||
| @@ -62,4 +63,3 @@ slots: | ||||
| private: | ||||
| 	Ui::AccountListDialog *ui; | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -20,15 +20,14 @@ | ||||
|  | ||||
| #include <logger/QsLog.h> | ||||
|  | ||||
| #include <logic/auth/AuthenticateTask.h> | ||||
| #include <logic/auth/flows/AuthenticateTask.h> | ||||
|  | ||||
| #include <gui/dialogs/ProgressDialog.h> | ||||
|  | ||||
| #include <MultiMC.h> | ||||
|  | ||||
| AccountSelectDialog::AccountSelectDialog(const QString& message, int flags, QWidget *parent) : | ||||
| 	QDialog(parent), | ||||
| 	ui(new Ui::AccountSelectDialog) | ||||
| AccountSelectDialog::AccountSelectDialog(const QString &message, int flags, QWidget *parent) | ||||
| 	: QDialog(parent), ui(new Ui::AccountSelectDialog) | ||||
| { | ||||
| 	ui->setupUi(this); | ||||
|  | ||||
| @@ -85,4 +84,3 @@ void AccountSelectDialog::on_buttonBox_rejected() | ||||
| { | ||||
| 	close(); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -21,17 +21,18 @@ | ||||
|  | ||||
| #include "logic/lists/MojangAccountList.h" | ||||
|  | ||||
| namespace Ui { | ||||
| namespace Ui | ||||
| { | ||||
| class AccountSelectDialog; | ||||
| } | ||||
|  | ||||
| class AccountSelectDialog : public QDialog | ||||
| { | ||||
| Q_OBJECT | ||||
| 	Q_OBJECT | ||||
| public: | ||||
| 	enum Flags | ||||
| 	{ | ||||
| 		NoFlags=0, | ||||
| 		NoFlags = 0, | ||||
|  | ||||
| 		/*! | ||||
| 		 * Shows a check box on the dialog that allows the user to specify that the account | ||||
| @@ -75,7 +76,7 @@ public: | ||||
| public | ||||
| slots: | ||||
| 	void on_buttonBox_accepted(); | ||||
| 	 | ||||
|  | ||||
| 	void on_buttonBox_rejected(); | ||||
|  | ||||
| protected: | ||||
| @@ -87,4 +88,3 @@ protected: | ||||
| private: | ||||
| 	Ui::AccountSelectDialog *ui; | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -33,7 +33,7 @@ | ||||
| #include "logic/BaseInstance.h" | ||||
|  | ||||
| CopyInstanceDialog::CopyInstanceDialog(BaseInstance *original, QWidget *parent) | ||||
| 	: m_original(original), QDialog(parent), ui(new Ui::CopyInstanceDialog) | ||||
| 	:QDialog(parent), ui(new Ui::CopyInstanceDialog), m_original(original) | ||||
| { | ||||
| 	MultiMCPlatform::fixWM_CLASS(this); | ||||
| 	ui->setupUi(this); | ||||
|   | ||||
| @@ -16,11 +16,10 @@ | ||||
| #include "EditAccountDialog.h" | ||||
| #include "ui_EditAccountDialog.h" | ||||
|  | ||||
| EditAccountDialog::EditAccountDialog(const QString& text, QWidget *parent, int flags) : | ||||
|     QDialog(parent), | ||||
|     ui(new Ui::EditAccountDialog) | ||||
| EditAccountDialog::EditAccountDialog(const QString &text, QWidget *parent, int flags) | ||||
| 	: QDialog(parent), ui(new Ui::EditAccountDialog) | ||||
| { | ||||
|     ui->setupUi(this); | ||||
| 	ui->setupUi(this); | ||||
|  | ||||
| 	ui->label->setText(text); | ||||
| 	ui->label->setVisible(!text.isEmpty()); | ||||
| @@ -31,7 +30,7 @@ EditAccountDialog::EditAccountDialog(const QString& text, QWidget *parent, int f | ||||
|  | ||||
| EditAccountDialog::~EditAccountDialog() | ||||
| { | ||||
|     delete ui; | ||||
| 	delete ui; | ||||
| } | ||||
|  | ||||
| QString EditAccountDialog::username() const | ||||
| @@ -43,4 +42,3 @@ QString EditAccountDialog::password() const | ||||
| { | ||||
| 	return ui->passTextBox->text(); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -17,16 +17,18 @@ | ||||
|  | ||||
| #include <QDialog> | ||||
|  | ||||
| namespace Ui { | ||||
| namespace Ui | ||||
| { | ||||
| class EditAccountDialog; | ||||
| } | ||||
|  | ||||
| class EditAccountDialog : public QDialog | ||||
| { | ||||
| Q_OBJECT | ||||
| 	Q_OBJECT | ||||
|  | ||||
| public: | ||||
| 	explicit EditAccountDialog(const QString& text="", QWidget *parent = 0, int flags=UsernameField | PasswordField); | ||||
| 	explicit EditAccountDialog(const QString &text = "", QWidget *parent = 0, | ||||
| 							   int flags = UsernameField | PasswordField); | ||||
| 	~EditAccountDialog(); | ||||
|  | ||||
| 	/*! | ||||
| @@ -41,7 +43,7 @@ public: | ||||
|  | ||||
| 	enum Flags | ||||
| 	{ | ||||
| 		NoFlags=0, | ||||
| 		NoFlags = 0, | ||||
|  | ||||
| 		//! Specifies that the dialog should have a username field. | ||||
| 		UsernameField, | ||||
| @@ -53,4 +55,3 @@ public: | ||||
| private: | ||||
| 	Ui::EditAccountDialog *ui; | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -21,8 +21,8 @@ | ||||
| #include <QApplication> | ||||
|  | ||||
| EditNotesDialog::EditNotesDialog(QString notes, QString name, QWidget *parent) | ||||
| 	: m_instance_notes(notes), m_instance_name(name), QDialog(parent), | ||||
| 	  ui(new Ui::EditNotesDialog) | ||||
| 	: QDialog(parent), ui(new Ui::EditNotesDialog), m_instance_name(name), | ||||
| 	  m_instance_notes(notes) | ||||
| { | ||||
| 	MultiMCPlatform::fixWM_CLASS(this); | ||||
| 	ui->setupUi(this); | ||||
|   | ||||
| @@ -32,7 +32,7 @@ | ||||
| #include <QMessageBox> | ||||
|  | ||||
| InstanceSettings::InstanceSettings(SettingsObject *obj, QWidget *parent) | ||||
| 	: m_obj(obj), QDialog(parent), ui(new Ui::InstanceSettings) | ||||
| 	: QDialog(parent), ui(new Ui::InstanceSettings), m_obj(obj) | ||||
| { | ||||
| 	MultiMCPlatform::fixWM_CLASS(this); | ||||
| 	ui->setupUi(this); | ||||
|   | ||||
| @@ -31,7 +31,7 @@ | ||||
| #include <QKeyEvent> | ||||
|  | ||||
| LegacyModEditDialog::LegacyModEditDialog(LegacyInstance *inst, QWidget *parent) | ||||
| 	: m_inst(inst), QDialog(parent), ui(new Ui::LegacyModEditDialog) | ||||
| 	: QDialog(parent), ui(new Ui::LegacyModEditDialog), m_inst(inst) | ||||
| { | ||||
| 	MultiMCPlatform::fixWM_CLASS(this); | ||||
| 	ui->setupUi(this); | ||||
|   | ||||
| @@ -40,7 +40,7 @@ | ||||
| #include "logic/ForgeInstaller.h" | ||||
|  | ||||
| OneSixModEditDialog::OneSixModEditDialog(OneSixInstance *inst, QWidget *parent) | ||||
| 	: m_inst(inst), QDialog(parent), ui(new Ui::OneSixModEditDialog) | ||||
| 	: QDialog(parent), ui(new Ui::OneSixModEditDialog), m_inst(inst) | ||||
| { | ||||
| 	MultiMCPlatform::fixWM_CLASS(this); | ||||
| 	ui->setupUi(this); | ||||
|   | ||||
| @@ -21,45 +21,45 @@ | ||||
| #include <QtCore/qmath.h> | ||||
|  | ||||
| // Origin: Qt | ||||
| static void viewItemTextLayout ( QTextLayout &textLayout, int lineWidth, qreal &height, qreal &widthUsed ) | ||||
| static void viewItemTextLayout(QTextLayout &textLayout, int lineWidth, qreal &height, | ||||
| 							   qreal &widthUsed) | ||||
| { | ||||
| 	height = 0; | ||||
| 	widthUsed = 0; | ||||
| 	textLayout.beginLayout(); | ||||
| 	QString str = textLayout.text(); | ||||
| 	while ( true ) | ||||
| 	while (true) | ||||
| 	{ | ||||
| 		QTextLine line = textLayout.createLine(); | ||||
| 		if ( !line.isValid() ) | ||||
| 		if (!line.isValid()) | ||||
| 			break; | ||||
| 		if(line.textLength() == 0) | ||||
| 		if (line.textLength() == 0) | ||||
| 			break; | ||||
| 		line.setLineWidth ( lineWidth ); | ||||
| 		line.setPosition ( QPointF ( 0, height ) ); | ||||
| 		line.setLineWidth(lineWidth); | ||||
| 		line.setPosition(QPointF(0, height)); | ||||
| 		height += line.height(); | ||||
| 		widthUsed = qMax ( widthUsed, line.naturalTextWidth() ); | ||||
| 		widthUsed = qMax(widthUsed, line.naturalTextWidth()); | ||||
| 	} | ||||
| 	textLayout.endLayout(); | ||||
| } | ||||
|  | ||||
| #define QFIXED_MAX (INT_MAX/256) | ||||
| #define QFIXED_MAX (INT_MAX / 256) | ||||
|  | ||||
| ListViewDelegate::ListViewDelegate ( QObject* parent ) : QStyledItemDelegate ( parent ) | ||||
| ListViewDelegate::ListViewDelegate(QObject *parent) : QStyledItemDelegate(parent) | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| void drawSelectionRect(QPainter *painter, const QStyleOptionViewItemV4 &option, const QRect &rect) | ||||
| void drawSelectionRect(QPainter *painter, const QStyleOptionViewItemV4 &option, | ||||
| 					   const QRect &rect) | ||||
| { | ||||
| 	if ((option.state & QStyle::State_Selected)) | ||||
| 		painter->fillRect ( rect, option.palette.brush ( QPalette::Highlight ) ); | ||||
| 		painter->fillRect(rect, option.palette.brush(QPalette::Highlight)); | ||||
| 	else | ||||
| 	{ | ||||
| 		QColor backgroundColor = option.palette.color(QPalette::Background); | ||||
| 		backgroundColor.setAlpha(160); | ||||
| 		painter->fillRect ( rect, QBrush(backgroundColor) ); | ||||
| 		painter->fillRect(rect, QBrush(backgroundColor)); | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| void drawFocusRect(QPainter *painter, const QStyleOptionViewItemV4 &option, const QRect &rect) | ||||
| @@ -67,11 +67,12 @@ void drawFocusRect(QPainter *painter, const QStyleOptionViewItemV4 &option, cons | ||||
| 	if (!(option.state & QStyle::State_HasFocus)) | ||||
| 		return; | ||||
| 	QStyleOptionFocusRect opt; | ||||
| 	opt.direction       = option.direction; | ||||
| 	opt.fontMetrics     = option.fontMetrics; | ||||
| 	opt.palette         = option.palette; | ||||
| 	opt.rect            = rect; | ||||
| 	//opt.state           = option.state | QStyle::State_KeyboardFocusChange | QStyle::State_Item; | ||||
| 	opt.direction = option.direction; | ||||
| 	opt.fontMetrics = option.fontMetrics; | ||||
| 	opt.palette = option.palette; | ||||
| 	opt.rect = rect; | ||||
| 	// opt.state           = option.state | QStyle::State_KeyboardFocusChange | | ||||
| 	// QStyle::State_Item; | ||||
| 	auto col = option.state & QStyle::State_Selected ? QPalette::Highlight : QPalette::Base; | ||||
| 	opt.backgroundColor = option.palette.color(col); | ||||
| 	// Apparently some widget styles expect this hint to not be set | ||||
| @@ -84,29 +85,31 @@ void drawFocusRect(QPainter *painter, const QStyleOptionViewItemV4 &option, cons | ||||
| 	painter->setRenderHint(QPainter::Antialiasing); | ||||
| } | ||||
|  | ||||
| static QSize viewItemTextSize ( const QStyleOptionViewItemV4 *option ) | ||||
| static QSize viewItemTextSize(const QStyleOptionViewItemV4 *option) | ||||
| { | ||||
| 	QStyle *style = option->widget ? option->widget->style() : QApplication::style(); | ||||
| 	QTextOption textOption; | ||||
| 	textOption.setWrapMode ( QTextOption::WrapAtWordBoundaryOrAnywhere ); | ||||
| 	textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); | ||||
| 	QTextLayout textLayout; | ||||
| 	textLayout.setTextOption ( textOption ); | ||||
| 	textLayout.setFont ( option->font ); | ||||
| 	textLayout.setText ( option->text ); | ||||
| 	const int textMargin = style->pixelMetric ( QStyle::PM_FocusFrameHMargin, option, option->widget ) + 1; | ||||
| 	QRect bounds ( 0,0,100 - 2*textMargin,600 ); | ||||
| 	textLayout.setTextOption(textOption); | ||||
| 	textLayout.setFont(option->font); | ||||
| 	textLayout.setText(option->text); | ||||
| 	const int textMargin = | ||||
| 		style->pixelMetric(QStyle::PM_FocusFrameHMargin, option, option->widget) + 1; | ||||
| 	QRect bounds(0, 0, 100 - 2 * textMargin, 600); | ||||
| 	qreal height = 0, widthUsed = 0; | ||||
| 	viewItemTextLayout ( textLayout, bounds.width(), height, widthUsed ); | ||||
| 	const QSize size ( qCeil ( widthUsed ), qCeil ( height ) ); | ||||
| 	return QSize ( size.width() + 2 * textMargin, size.height() ); | ||||
| 	viewItemTextLayout(textLayout, bounds.width(), height, widthUsed); | ||||
| 	const QSize size(qCeil(widthUsed), qCeil(height)); | ||||
| 	return QSize(size.width() + 2 * textMargin, size.height()); | ||||
| } | ||||
|  | ||||
| void ListViewDelegate::paint ( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const | ||||
| void ListViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, | ||||
| 							 const QModelIndex &index) const | ||||
| { | ||||
| 	QStyleOptionViewItemV4 opt = option; | ||||
| 	initStyleOption ( &opt, index ); | ||||
| 	initStyleOption(&opt, index); | ||||
| 	painter->save(); | ||||
| 	painter->setClipRect ( opt.rect ); | ||||
| 	painter->setClipRect(opt.rect); | ||||
|  | ||||
| 	opt.features |= QStyleOptionViewItem::WrapText; | ||||
| 	opt.text = index.data().toString(); | ||||
| @@ -115,26 +118,27 @@ void ListViewDelegate::paint ( QPainter* painter, const QStyleOptionViewItem& op | ||||
|  | ||||
| 	QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); | ||||
|  | ||||
| 	//const int iconSize =  style->pixelMetric(QStyle::PM_IconViewIconSize); | ||||
| 	// const int iconSize =  style->pixelMetric(QStyle::PM_IconViewIconSize); | ||||
| 	const int iconSize = 48; | ||||
| 	QRect iconbox = opt.rect; | ||||
| 	const int textMargin = style->pixelMetric ( QStyle::PM_FocusFrameHMargin, 0, opt.widget ) + 1; | ||||
| 	const int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, opt.widget) + 1; | ||||
| 	QRect textRect = opt.rect; | ||||
| 	QRect textHighlightRect = textRect; | ||||
| 	// clip the decoration on top, remove width padding | ||||
| 	textRect.adjust ( textMargin,iconSize + textMargin + 5,-textMargin,0 ); | ||||
| 	 | ||||
| 	textHighlightRect.adjust ( 0,iconSize + 5,0,0 ); | ||||
| 	textRect.adjust(textMargin, iconSize + textMargin + 5, -textMargin, 0); | ||||
|  | ||||
| 	textHighlightRect.adjust(0, iconSize + 5, 0, 0); | ||||
|  | ||||
| 	// draw background | ||||
| 	{ | ||||
| 		QSize textSize = viewItemTextSize ( &opt ); | ||||
| 		// FIXME: unused | ||||
| 		// QSize textSize = viewItemTextSize ( &opt ); | ||||
| 		QPalette::ColorGroup cg; | ||||
| 		QStyleOptionViewItemV4 opt2(opt); | ||||
| 		 | ||||
| 		if((opt.widget && opt.widget->isEnabled()) || (opt.state & QStyle::State_Enabled)) | ||||
|  | ||||
| 		if ((opt.widget && opt.widget->isEnabled()) || (opt.state & QStyle::State_Enabled)) | ||||
| 		{ | ||||
| 			if(! ( opt.state & QStyle::State_Active )) | ||||
| 			if (!(opt.state & QStyle::State_Active)) | ||||
| 				cg = QPalette::Inactive; | ||||
| 			else | ||||
| 				cg = QPalette::Normal; | ||||
| @@ -144,31 +148,33 @@ void ListViewDelegate::paint ( QPainter* painter, const QStyleOptionViewItem& op | ||||
| 			cg = QPalette::Disabled; | ||||
| 		} | ||||
| 		opt2.palette.setCurrentColorGroup(cg); | ||||
| 		 | ||||
|  | ||||
| 		// fill in background, if any | ||||
| 		if ( opt.backgroundBrush.style() != Qt::NoBrush ) | ||||
| 		if (opt.backgroundBrush.style() != Qt::NoBrush) | ||||
| 		{ | ||||
| 			QPointF oldBO = painter->brushOrigin(); | ||||
| 			painter->setBrushOrigin ( opt.rect.topLeft() ); | ||||
| 			painter->fillRect ( opt.rect, opt.backgroundBrush ); | ||||
| 			painter->setBrushOrigin ( oldBO ); | ||||
| 			painter->setBrushOrigin(opt.rect.topLeft()); | ||||
| 			painter->fillRect(opt.rect, opt.backgroundBrush); | ||||
| 			painter->setBrushOrigin(oldBO); | ||||
| 		} | ||||
| 		 | ||||
| 		if ( opt.showDecorationSelected ) | ||||
|  | ||||
| 		if (opt.showDecorationSelected) | ||||
| 		{ | ||||
| 			drawSelectionRect(painter,opt2, opt.rect); | ||||
| 			drawFocusRect(painter,opt2, opt.rect); | ||||
| 			//painter->fillRect ( opt.rect, opt.palette.brush ( cg, QPalette::Highlight ) ); | ||||
| 			drawSelectionRect(painter, opt2, opt.rect); | ||||
| 			drawFocusRect(painter, opt2, opt.rect); | ||||
| 			// painter->fillRect ( opt.rect, opt.palette.brush ( cg, QPalette::Highlight ) ); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			 | ||||
| 			//if ( opt.state & QStyle::State_Selected ) | ||||
|  | ||||
| 			// if ( opt.state & QStyle::State_Selected ) | ||||
| 			{ | ||||
| 				//QRect textRect = subElementRect ( QStyle::SE_ItemViewItemText,  opt, opt.widget ); | ||||
| 				//painter->fillRect ( textHighlightRect, opt.palette.brush ( cg, QPalette::Highlight ) ); | ||||
| 				drawSelectionRect(painter,opt2, textHighlightRect); | ||||
| 				drawFocusRect(painter,opt2, textHighlightRect); | ||||
| 				// QRect textRect = subElementRect ( QStyle::SE_ItemViewItemText,  opt, | ||||
| 				// opt.widget ); | ||||
| 				// painter->fillRect ( textHighlightRect, opt.palette.brush ( cg, | ||||
| 				// QPalette::Highlight ) ); | ||||
| 				drawSelectionRect(painter, opt2, textHighlightRect); | ||||
| 				drawFocusRect(painter, opt2, textHighlightRect); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| @@ -176,71 +182,73 @@ void ListViewDelegate::paint ( QPainter* painter, const QStyleOptionViewItem& op | ||||
| 	// draw the icon | ||||
| 	{ | ||||
| 		QIcon::Mode mode = QIcon::Normal; | ||||
| 		if ( ! ( opt.state & QStyle::State_Enabled ) ) | ||||
| 		if (!(opt.state & QStyle::State_Enabled)) | ||||
| 			mode = QIcon::Disabled; | ||||
| 		else if ( opt.state & QStyle::State_Selected ) | ||||
| 		else if (opt.state & QStyle::State_Selected) | ||||
| 			mode = QIcon::Selected; | ||||
| 		QIcon::State state = opt.state & QStyle::State_Open ? QIcon::On : QIcon::Off; | ||||
|  | ||||
| 		iconbox.setHeight ( iconSize ); | ||||
| 		opt.icon.paint ( painter, iconbox, Qt::AlignCenter, mode, state ); | ||||
| 		iconbox.setHeight(iconSize); | ||||
| 		opt.icon.paint(painter, iconbox, Qt::AlignCenter, mode, state); | ||||
| 	} | ||||
| 	// set the text colors | ||||
| 	QPalette::ColorGroup cg = opt.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; | ||||
| 	if ( cg == QPalette::Normal && ! ( opt.state & QStyle::State_Active ) ) | ||||
| 	QPalette::ColorGroup cg = | ||||
| 		opt.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; | ||||
| 	if (cg == QPalette::Normal && !(opt.state & QStyle::State_Active)) | ||||
| 		cg = QPalette::Inactive; | ||||
| 	if ( opt.state & QStyle::State_Selected ) | ||||
| 	if (opt.state & QStyle::State_Selected) | ||||
| 	{ | ||||
| 		painter->setPen ( opt.palette.color ( cg, QPalette::HighlightedText ) ); | ||||
| 		painter->setPen(opt.palette.color(cg, QPalette::HighlightedText)); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		painter->setPen ( opt.palette.color ( cg, QPalette::Text ) ); | ||||
| 		painter->setPen(opt.palette.color(cg, QPalette::Text)); | ||||
| 	} | ||||
|  | ||||
| 	// draw the text | ||||
| 	QTextOption textOption; | ||||
| 	textOption.setWrapMode ( QTextOption::WrapAtWordBoundaryOrAnywhere ); | ||||
| 	textOption.setTextDirection ( opt.direction ); | ||||
| 	textOption.setAlignment ( QStyle::visualAlignment ( opt.direction, opt.displayAlignment ) ); | ||||
| 	textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); | ||||
| 	textOption.setTextDirection(opt.direction); | ||||
| 	textOption.setAlignment(QStyle::visualAlignment(opt.direction, opt.displayAlignment)); | ||||
| 	QTextLayout textLayout; | ||||
| 	textLayout.setTextOption ( textOption ); | ||||
| 	textLayout.setFont ( opt.font ); | ||||
| 	textLayout.setText ( opt.text ); | ||||
| 	textLayout.setTextOption(textOption); | ||||
| 	textLayout.setFont(opt.font); | ||||
| 	textLayout.setText(opt.text); | ||||
|  | ||||
| 	qreal width, height; | ||||
| 	viewItemTextLayout ( textLayout, textRect.width(), height, width ); | ||||
| 	viewItemTextLayout(textLayout, textRect.width(), height, width); | ||||
|  | ||||
| 	const int lineCount = textLayout.lineCount(); | ||||
|  | ||||
| 	const QRect layoutRect = QStyle::alignedRect ( opt.direction, opt.displayAlignment, QSize ( textRect.width(), int ( height ) ), textRect ); | ||||
| 	const QRect layoutRect = QStyle::alignedRect( | ||||
| 		opt.direction, opt.displayAlignment, QSize(textRect.width(), int(height)), textRect); | ||||
| 	const QPointF position = layoutRect.topLeft(); | ||||
| 	for ( int i = 0; i < lineCount; ++i ) | ||||
| 	for (int i = 0; i < lineCount; ++i) | ||||
| 	{ | ||||
| 		const QTextLine line = textLayout.lineAt ( i ); | ||||
| 		line.draw ( painter, position ); | ||||
| 		const QTextLine line = textLayout.lineAt(i); | ||||
| 		line.draw(painter, position); | ||||
| 	} | ||||
|  | ||||
| 	painter->restore(); | ||||
| } | ||||
|  | ||||
|  | ||||
| QSize ListViewDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const | ||||
| QSize ListViewDelegate::sizeHint(const QStyleOptionViewItem &option, | ||||
| 								 const QModelIndex &index) const | ||||
| { | ||||
| 	QStyleOptionViewItemV4 opt = option; | ||||
| 	initStyleOption ( &opt, index ); | ||||
| 	initStyleOption(&opt, index); | ||||
| 	opt.features |= QStyleOptionViewItem::WrapText; | ||||
| 	opt.text = index.data().toString(); | ||||
| 	opt.textElideMode = Qt::ElideRight; | ||||
| 	opt.displayAlignment = Qt::AlignTop | Qt::AlignHCenter; | ||||
|  | ||||
| 	QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); | ||||
| 	const int textMargin = style->pixelMetric ( QStyle::PM_FocusFrameHMargin, &option, opt.widget ) + 1; | ||||
| 	const int textMargin = | ||||
| 		style->pixelMetric(QStyle::PM_FocusFrameHMargin, &option, opt.widget) + 1; | ||||
| 	int height = 48 + textMargin * 2 + 5; // TODO: turn constants into variables | ||||
| 	QSize szz = viewItemTextSize ( &opt ); | ||||
| 	QSize szz = viewItemTextSize(&opt); | ||||
| 	height += szz.height(); | ||||
| 	// FIXME: maybe the icon items could scale and keep proportions? | ||||
| 	QSize sz ( 100,height ); | ||||
| 	QSize sz(100, height); | ||||
| 	return sz; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -30,7 +30,7 @@ | ||||
|  | ||||
| BaseInstance::BaseInstance(BaseInstancePrivate *d_in, const QString &rootDir, | ||||
| 						   SettingsObject *settings_obj, QObject *parent) | ||||
| 	: inst_d(d_in), QObject(parent) | ||||
| 	: QObject(parent), inst_d(d_in) | ||||
| { | ||||
| 	I_D(BaseInstance); | ||||
| 	d->m_settings = settings_obj; | ||||
|   | ||||
| @@ -133,16 +133,12 @@ InstanceFactory::InstCreateError InstanceFactory::copyInstance(BaseInstance *&ne | ||||
| 	{ | ||||
| 	case NoLoadError: | ||||
| 		return NoCreateError; | ||||
| 	case UnknownLoadError: | ||||
| 	{ | ||||
| 		rootDir.removeRecursively(); | ||||
| 		return UnknownCreateError; | ||||
| 	} | ||||
| 	case NotAnInstance: | ||||
| 	{ | ||||
| 		rootDir.removeRecursively(); | ||||
| 		return CantCreateDir; | ||||
| 	default: | ||||
| 	case UnknownLoadError: | ||||
| 		rootDir.removeRecursively(); | ||||
| 		return UnknownCreateError;	 | ||||
| 	} | ||||
| 	} | ||||
| 	; | ||||
| } | ||||
|   | ||||
| @@ -8,7 +8,7 @@ JavaChecker::JavaChecker(QObject *parent) : QObject(parent) | ||||
| { | ||||
| } | ||||
|  | ||||
| int JavaChecker::performCheck(QString path) | ||||
| void JavaChecker::performCheck(QString path) | ||||
| { | ||||
| 	if(QFile::exists(CHECKER_FILE)) | ||||
| 	{ | ||||
|   | ||||
| @@ -17,7 +17,7 @@ class JavaChecker : public QObject | ||||
| 	Q_OBJECT | ||||
| public: | ||||
| 	explicit JavaChecker(QObject *parent = 0); | ||||
| 	int performCheck(QString path); | ||||
| 	void performCheck(QString path); | ||||
|  | ||||
| signals: | ||||
| 	void checkFinished(JavaCheckResult result); | ||||
|   | ||||
| @@ -274,7 +274,6 @@ bool LegacyInstance::setIntendedVersionId(QString version) | ||||
|  | ||||
| bool LegacyInstance::shouldUpdate() const | ||||
| { | ||||
| 	I_D(LegacyInstance); | ||||
| 	QVariant var = settings().get("ShouldUpdate"); | ||||
| 	if (!var.isValid() || var.toBool() == false) | ||||
| 	{ | ||||
|   | ||||
| @@ -71,6 +71,26 @@ void MinecraftProcess::setWorkdir(QString path) | ||||
| 	m_prepostlaunchprocess.setWorkingDirectory(mcDir.absolutePath()); | ||||
| } | ||||
|  | ||||
| QString MinecraftProcess::censorPrivateInfo(QString in) | ||||
| { | ||||
| 	if(!m_account) | ||||
| 		return in; | ||||
| 	else | ||||
| 	{ | ||||
| 		QString sessionId = m_account->sessionId(); | ||||
| 		QString accessToken = m_account->accessToken(); | ||||
| 		QString clientToken = m_account->clientToken(); | ||||
| 		QString profileId = m_account->currentProfile()->id(); | ||||
| 		QString profileName = m_account->currentProfile()->name(); | ||||
| 		in.replace(sessionId, "<SESSION ID>"); | ||||
| 		in.replace(accessToken, "<ACCESS TOKEN>"); | ||||
| 		in.replace(clientToken, "<CLIENT TOKEN>"); | ||||
| 		in.replace(profileId, "<PROFILE ID>"); | ||||
| 		in.replace(profileName, "<PROFILE NAME>"); | ||||
| 		return in; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // console window | ||||
| void MinecraftProcess::on_stdErr() | ||||
| { | ||||
| @@ -83,8 +103,7 @@ void MinecraftProcess::on_stdErr() | ||||
| 	for (int i = 0; i < lines.size() - 1; i++) | ||||
| 	{ | ||||
| 		QString &line = lines[i]; | ||||
| 		emit log(line /*.replace(username, "<Username>").replace(sessionID, "<Session ID>")*/, | ||||
| 				 getLevel(line, MessageLevel::Error)); | ||||
| 		emit log(censorPrivateInfo(line), getLevel(line, MessageLevel::Error)); | ||||
| 	} | ||||
| 	if (!complete) | ||||
| 		m_err_leftover = lines.last(); | ||||
| @@ -101,8 +120,7 @@ void MinecraftProcess::on_stdOut() | ||||
| 	for (int i = 0; i < lines.size() - 1; i++) | ||||
| 	{ | ||||
| 		QString &line = lines[i]; | ||||
| 		emit log(line.replace(username, "<Username>").replace(sessionID, "<Session ID>"), | ||||
| 				 getLevel(line, MessageLevel::Message)); | ||||
| 		emit log(censorPrivateInfo(line), getLevel(line, MessageLevel::Message)); | ||||
| 	} | ||||
| 	if (!complete) | ||||
| 		m_out_leftover = lines.last(); | ||||
| @@ -173,8 +191,8 @@ void MinecraftProcess::launch() | ||||
| 	emit log(QString("Minecraft folder is: '%1'").arg(workingDirectory())); | ||||
| 	QString JavaPath = m_instance->settings().get("JavaPath").toString(); | ||||
| 	emit log(QString("Java path: '%1'").arg(JavaPath)); | ||||
| 	emit log(QString("Arguments: '%1'").arg( | ||||
| 		m_args.join("' '").replace(username, "<Username>").replace(sessionID, "<Session ID>"))); | ||||
| 	QString allArgs = m_args.join("' '"); | ||||
| 	emit log(QString("Arguments: '%1'").arg(censorPrivateInfo(allArgs))); | ||||
| 	start(JavaPath, m_args); | ||||
| 	if (!waitForStarted()) | ||||
| 	{ | ||||
|   | ||||
| @@ -69,10 +69,9 @@ public: | ||||
|  | ||||
| 	void killMinecraft(); | ||||
|  | ||||
| 	inline void setLogin(QString user, QString sid) | ||||
| 	inline void setLogin(MojangAccountPtr account) | ||||
| 	{ | ||||
| 		username = user; | ||||
| 		sessionID = sid; | ||||
| 		m_account = account; | ||||
| 	} | ||||
|  | ||||
| signals: | ||||
| @@ -104,11 +103,13 @@ signals: | ||||
| 	void log(QString text, MessageLevel::Enum level = MessageLevel::MultiMC); | ||||
|  | ||||
| protected: | ||||
| 	BaseInstance *m_instance; | ||||
| 	BaseInstance *m_instance = nullptr; | ||||
| 	QStringList m_args; | ||||
| 	QString m_err_leftover; | ||||
| 	QString m_out_leftover; | ||||
| 	QProcess m_prepostlaunchprocess; | ||||
| 	bool killed = false; | ||||
| 	MojangAccountPtr m_account; | ||||
|  | ||||
| protected | ||||
| slots: | ||||
| @@ -117,8 +118,7 @@ slots: | ||||
| 	void on_stdOut(); | ||||
|  | ||||
| private: | ||||
| 	bool killed; | ||||
| 	QString censorPrivateInfo(QString in); | ||||
| 	MessageLevel::Enum getLevel(const QString &message, MessageLevel::Enum defaultLevel); | ||||
| 	QString sessionID; | ||||
| 	QString username; | ||||
| 	 | ||||
| }; | ||||
|   | ||||
| @@ -39,18 +39,26 @@ void ModList::startWatching() | ||||
| { | ||||
| 	is_watching = m_watcher->addPath(m_dir.absolutePath()); | ||||
| 	if (is_watching) | ||||
| 	{ | ||||
| 		QLOG_INFO() << "Started watching " << m_dir.absolutePath(); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		QLOG_INFO() << "Failed to start watching " << m_dir.absolutePath(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void ModList::stopWatching() | ||||
| { | ||||
| 	is_watching = !m_watcher->removePath(m_dir.absolutePath()); | ||||
| 	if (!is_watching) | ||||
| 	{ | ||||
| 		QLOG_INFO() << "Stopped watching " << m_dir.absolutePath(); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		QLOG_INFO() << "Failed to stop watching " << m_dir.absolutePath(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| bool ModList::update() | ||||
| @@ -64,7 +72,6 @@ bool ModList::update() | ||||
| 	bool orderWasInvalid = false; | ||||
|  | ||||
| 	// first, process the ordered items (if any) | ||||
| 	int currentOrderIndex = 0; | ||||
| 	QStringList listOrder = readListFile(); | ||||
| 	for (auto item : listOrder) | ||||
| 	{ | ||||
| @@ -363,6 +370,7 @@ QVariant ModList::headerData(int section, Qt::Orientation orientation, int role) | ||||
| 	case 2: | ||||
| 		return QString("Minecraft"); | ||||
| 	} | ||||
| 	return QString(); | ||||
| } | ||||
|  | ||||
| Qt::ItemFlags ModList::flags(const QModelIndex &index) const | ||||
|   | ||||
| @@ -235,7 +235,6 @@ void OneSixInstance::setShouldUpdate(bool val) | ||||
|  | ||||
| bool OneSixInstance::shouldUpdate() const | ||||
| { | ||||
| 	I_D(OneSixInstance); | ||||
| 	QVariant var = settings().get("ShouldUpdate"); | ||||
| 	if (!var.isValid() || var.toBool() == false) | ||||
| 	{ | ||||
|   | ||||
| @@ -198,7 +198,6 @@ void OneSixUpdate::jarlibStart() | ||||
|  | ||||
| 	auto metacache = MMC->metacache(); | ||||
| 	QList<ForgeXzDownloadPtr> ForgeLibs; | ||||
| 	bool already_forge_xz = false; | ||||
| 	for (auto lib : libs) | ||||
| 	{ | ||||
| 		if (lib->hint() == "local") | ||||
|   | ||||
| @@ -23,8 +23,7 @@ | ||||
|  | ||||
| #include <logger/QsLog.h> | ||||
|  | ||||
| MojangAccount::MojangAccount(const QString& username, QObject* parent) : | ||||
| 	QObject(parent) | ||||
| MojangAccount::MojangAccount(const QString &username, QObject *parent) : QObject(parent) | ||||
| { | ||||
| 	// Generate a client token. | ||||
| 	m_clientToken = QUuid::createUuid().toString(); | ||||
| @@ -34,9 +33,9 @@ MojangAccount::MojangAccount(const QString& username, QObject* parent) : | ||||
| 	m_currentProfile = -1; | ||||
| } | ||||
|  | ||||
| MojangAccount::MojangAccount(const QString& username, const QString& clientToken,  | ||||
| 							 const QString& accessToken, QObject* parent) : | ||||
| 	QObject(parent) | ||||
| MojangAccount::MojangAccount(const QString &username, const QString &clientToken, | ||||
| 							 const QString &accessToken, QObject *parent) | ||||
| 	: QObject(parent) | ||||
| { | ||||
| 	m_username = username; | ||||
| 	m_clientToken = clientToken; | ||||
| @@ -45,7 +44,7 @@ MojangAccount::MojangAccount(const QString& username, const QString& clientToken | ||||
| 	m_currentProfile = -1; | ||||
| } | ||||
|  | ||||
| MojangAccount::MojangAccount(const MojangAccount& other, QObject* parent) | ||||
| MojangAccount::MojangAccount(const MojangAccount &other, QObject *parent) | ||||
| { | ||||
| 	m_username = other.username(); | ||||
| 	m_clientToken = other.clientToken(); | ||||
| @@ -55,7 +54,6 @@ MojangAccount::MojangAccount(const MojangAccount& other, QObject* parent) | ||||
| 	m_currentProfile = other.m_currentProfile; | ||||
| } | ||||
|  | ||||
|  | ||||
| QString MojangAccount::username() const | ||||
| { | ||||
| 	return m_username; | ||||
| @@ -66,18 +64,17 @@ QString MojangAccount::clientToken() const | ||||
| 	return m_clientToken; | ||||
| } | ||||
|  | ||||
| void MojangAccount::setClientToken(const QString& clientToken) | ||||
| void MojangAccount::setClientToken(const QString &clientToken) | ||||
| { | ||||
| 	m_clientToken = clientToken; | ||||
| } | ||||
|  | ||||
|  | ||||
| QString MojangAccount::accessToken() const | ||||
| { | ||||
| 	return m_accessToken; | ||||
| } | ||||
|  | ||||
| void MojangAccount::setAccessToken(const QString& accessToken) | ||||
| void MojangAccount::setAccessToken(const QString &accessToken) | ||||
| { | ||||
| 	m_accessToken = accessToken; | ||||
| } | ||||
| @@ -92,7 +89,7 @@ const QList<AccountProfile> MojangAccount::profiles() const | ||||
| 	return m_profiles; | ||||
| } | ||||
|  | ||||
| const AccountProfile* MojangAccount::currentProfile() const | ||||
| const AccountProfile *MojangAccount::currentProfile() const | ||||
| { | ||||
| 	if (m_currentProfile < 0) | ||||
| 	{ | ||||
| @@ -105,9 +102,9 @@ const AccountProfile* MojangAccount::currentProfile() const | ||||
| 		return &m_profiles.at(m_currentProfile); | ||||
| } | ||||
|  | ||||
| bool MojangAccount::setProfile(const QString& profileId) | ||||
| bool MojangAccount::setProfile(const QString &profileId) | ||||
| { | ||||
| 	const QList<AccountProfile>& profiles = this->profiles(); | ||||
| 	const QList<AccountProfile> &profiles = this->profiles(); | ||||
| 	for (int i = 0; i < profiles.length(); i++) | ||||
| 	{ | ||||
| 		if (profiles.at(i).id() == profileId) | ||||
| @@ -119,14 +116,14 @@ bool MojangAccount::setProfile(const QString& profileId) | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| void MojangAccount::loadProfiles(const ProfileList& profiles) | ||||
| void MojangAccount::loadProfiles(const ProfileList &profiles) | ||||
| { | ||||
| 	m_profiles.clear(); | ||||
| 	for (auto profile : profiles) | ||||
| 		m_profiles.append(profile); | ||||
| } | ||||
|  | ||||
| MojangAccountPtr MojangAccount::loadFromJson(const QJsonObject& object) | ||||
| MojangAccountPtr MojangAccount::loadFromJson(const QJsonObject &object) | ||||
| { | ||||
| 	// The JSON object must at least have a username for it to be valid. | ||||
| 	if (!object.value("username").isString()) | ||||
| @@ -134,7 +131,7 @@ MojangAccountPtr MojangAccount::loadFromJson(const QJsonObject& object) | ||||
| 		QLOG_ERROR() << "Can't load Mojang account info from JSON object. Username field is missing or of the wrong type."; | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	QString username = object.value("username").toString(""); | ||||
| 	QString clientToken = object.value("clientToken").toString(""); | ||||
| 	QString accessToken = object.value("accessToken").toString(""); | ||||
| @@ -201,7 +198,7 @@ AccountProfile::AccountProfile(const QString& id, const QString& name) | ||||
| 	m_name = name; | ||||
| } | ||||
|  | ||||
| AccountProfile::AccountProfile(const AccountProfile& other) | ||||
| AccountProfile::AccountProfile(const AccountProfile &other) | ||||
| { | ||||
| 	m_id = other.m_id; | ||||
| 	m_name = other.m_name; | ||||
| @@ -217,4 +214,7 @@ QString AccountProfile::name() const | ||||
| 	return m_name; | ||||
| } | ||||
|  | ||||
|  | ||||
| void MojangAccount::propagateChange() | ||||
| { | ||||
| 	emit changed(); | ||||
| } | ||||
|   | ||||
| @@ -19,6 +19,7 @@ | ||||
| #include <QString> | ||||
| #include <QList> | ||||
| #include <QJsonObject> | ||||
| #include <QPair> | ||||
|  | ||||
| #include <memory> | ||||
|  | ||||
| @@ -27,7 +28,6 @@ class MojangAccount; | ||||
| typedef std::shared_ptr<MojangAccount> MojangAccountPtr; | ||||
| Q_DECLARE_METATYPE(MojangAccountPtr) | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * Class that represents a profile within someone's Mojang account. | ||||
|  * | ||||
| @@ -38,56 +38,69 @@ Q_DECLARE_METATYPE(MojangAccountPtr) | ||||
| class AccountProfile | ||||
| { | ||||
| public: | ||||
| 	AccountProfile(const QString& id, const QString& name); | ||||
| 	AccountProfile(const AccountProfile& other); | ||||
| 	AccountProfile(const QString &id, const QString &name); | ||||
| 	AccountProfile(const AccountProfile &other); | ||||
|  | ||||
| 	QString id() const; | ||||
| 	QString name() const; | ||||
|  | ||||
| protected: | ||||
| 	QString m_id; | ||||
| 	QString m_name; | ||||
| }; | ||||
|  | ||||
|  | ||||
| typedef QList<AccountProfile> ProfileList; | ||||
|  | ||||
| struct User | ||||
| { | ||||
| 	QString id; | ||||
| 	// pair of key:value | ||||
| 	// we don't know if the keys:value mapping is 1:1, so a list is used. | ||||
| 	QList<QPair<QString, QString>> properties; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * Object that stores information about a certain Mojang account. | ||||
|  * | ||||
|  * Said information may include things such as that account's username, client token, and access  | ||||
|  * Said information may include things such as that account's username, client token, and access | ||||
|  * token if the user chose to stay logged in. | ||||
|  */ | ||||
| class MojangAccount : public QObject | ||||
| { | ||||
| Q_OBJECT | ||||
| 	Q_OBJECT | ||||
| public: | ||||
| 	/** | ||||
| 	 * Constructs a new MojangAccount with the given username. | ||||
| 	 * The client token will be generated automatically and the access token will be blank. | ||||
| 	 */ | ||||
| 	explicit MojangAccount(const QString& username, QObject* parent = 0); | ||||
| 	explicit MojangAccount(const QString &username, QObject *parent = 0); | ||||
|  | ||||
| 	/** | ||||
| 	 * Constructs a new MojangAccount with the given username, client token, and access token. | ||||
| 	 */ | ||||
| 	explicit MojangAccount(const QString& username, const QString& clientToken, const QString& accessToken, QObject* parent = 0); | ||||
| 	explicit MojangAccount(const QString &username, const QString &clientToken, | ||||
| 						   const QString &accessToken, QObject *parent = 0); | ||||
|  | ||||
| 	/** | ||||
| 	 * Constructs a new MojangAccount matching the given account. | ||||
| 	 */ | ||||
| 	MojangAccount(const MojangAccount& other, QObject* parent); | ||||
| 	MojangAccount(const MojangAccount &other, QObject *parent); | ||||
|  | ||||
| 	/** | ||||
| 	 * Loads a MojangAccount from the given JSON object. | ||||
| 	 */ | ||||
| 	static MojangAccountPtr loadFromJson(const QJsonObject& json); | ||||
| 	static MojangAccountPtr loadFromJson(const QJsonObject &json); | ||||
|  | ||||
| 	/** | ||||
| 	 * Saves a MojangAccount to a JSON object and returns it. | ||||
| 	 */ | ||||
| 	QJsonObject saveToJson(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Update the account on disk and lists (it changed, for whatever reason) | ||||
| 	 * This is called by various Yggdrasil tasks. | ||||
| 	 */ | ||||
| 	void propagateChange(); | ||||
|  | ||||
| 	/** | ||||
| 	 * This MojangAccount's username. May be an email address if the account is migrated. | ||||
| @@ -103,7 +116,7 @@ public: | ||||
| 	/** | ||||
| 	 * Sets the MojangAccount's client token to the given value. | ||||
| 	 */ | ||||
| 	void setClientToken(const QString& token); | ||||
| 	void setClientToken(const QString &token); | ||||
|  | ||||
| 	/** | ||||
| 	 * This MojangAccount's access token. | ||||
| @@ -114,7 +127,7 @@ public: | ||||
| 	/** | ||||
| 	 * Changes this MojangAccount's access token to the given value. | ||||
| 	 */ | ||||
| 	void setAccessToken(const QString& token); | ||||
| 	void setAccessToken(const QString &token); | ||||
|  | ||||
| 	/** | ||||
| 	 * Get full session ID | ||||
| @@ -130,25 +143,31 @@ public: | ||||
| 	 * Returns a pointer to the currently selected profile. | ||||
| 	 * If no profile is selected, returns the first profile in the profile list or nullptr if there are none. | ||||
| 	 */ | ||||
| 	const AccountProfile* currentProfile() const; | ||||
| 	const AccountProfile *currentProfile() const; | ||||
|  | ||||
| 	/** | ||||
| 	 * Sets the currently selected profile to the profile with the given ID string. | ||||
| 	 * If profileId is not in the list of available profiles, the function will simply return false. | ||||
| 	 */ | ||||
| 	bool setProfile(const QString& profileId); | ||||
| 	bool setProfile(const QString &profileId); | ||||
|  | ||||
| 	/** | ||||
| 	 * Clears the current account profile list and replaces it with the given profile list. | ||||
| 	 */ | ||||
| 	void loadProfiles(const ProfileList& profiles); | ||||
| 	void loadProfiles(const ProfileList &profiles); | ||||
|  | ||||
| signals: | ||||
| 	/** | ||||
| 	 * This isgnal is emitted whrn the account changes | ||||
| 	 */ | ||||
| 	void changed(); | ||||
|  | ||||
| protected: | ||||
| 	QString m_username; | ||||
| 	QString m_clientToken; | ||||
| 	QString m_accessToken; // Blank if not logged in. | ||||
| 	int m_currentProfile; // Index of the selected profile within the list of available profiles. -1 if nothing is selected. | ||||
| 	QString m_accessToken;  // Blank if not logged in. | ||||
| 	int m_currentProfile;   // Index of the selected profile within the list of available | ||||
| 							// profiles. -1 if nothing is selected. | ||||
| 	ProfileList m_profiles; // List of available profiles. | ||||
| 	User m_user;			// the user structure, whatever it is. | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -25,13 +25,12 @@ | ||||
| #include <MultiMC.h> | ||||
| #include <logic/auth/MojangAccount.h> | ||||
|  | ||||
| YggdrasilTask::YggdrasilTask(MojangAccountPtr account, QObject* parent) : Task(parent) | ||||
| YggdrasilTask::YggdrasilTask(MojangAccountPtr account, QObject *parent) : Task(parent) | ||||
| { | ||||
| 	m_error = nullptr; | ||||
| 	m_account = account; | ||||
| } | ||||
|  | ||||
|  | ||||
| YggdrasilTask::~YggdrasilTask() | ||||
| { | ||||
| 	if (m_error) | ||||
| @@ -46,17 +45,18 @@ void YggdrasilTask::executeTask() | ||||
| 	QJsonDocument doc(getRequestContent()); | ||||
|  | ||||
| 	auto worker = MMC->qnam(); | ||||
| 	connect(worker.get(), SIGNAL(finished(QNetworkReply*)), this, | ||||
| 			SLOT(processReply(QNetworkReply*))); | ||||
| 	connect(worker.get(), SIGNAL(finished(QNetworkReply *)), this, | ||||
| 			SLOT(processReply(QNetworkReply *))); | ||||
|  | ||||
| 	QUrl reqUrl("https://authserver.mojang.com/" + getEndpoint()); | ||||
| 	QNetworkRequest netRequest(reqUrl); | ||||
| 	netRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); | ||||
| 	 | ||||
| 	m_netReply = worker->post(netRequest, doc.toJson()); | ||||
|  | ||||
| 	QByteArray requestData = doc.toJson(); | ||||
| 	m_netReply = worker->post(netRequest, requestData); | ||||
| } | ||||
|  | ||||
| void YggdrasilTask::processReply(QNetworkReply* reply) | ||||
| void YggdrasilTask::processReply(QNetworkReply *reply) | ||||
| { | ||||
| 	setStatus(getStateMessage(STATE_PROCESSING_RESPONSE)); | ||||
|  | ||||
| @@ -76,7 +76,6 @@ void YggdrasilTask::processReply(QNetworkReply* reply) | ||||
| 		QJsonParseError jsonError; | ||||
| 		QByteArray replyData = reply->readAll(); | ||||
| 		QJsonDocument doc = QJsonDocument::fromJson(replyData, &jsonError); | ||||
|  | ||||
| 		// Check the response code. | ||||
| 		int responseCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); | ||||
|  | ||||
| @@ -85,15 +84,16 @@ void YggdrasilTask::processReply(QNetworkReply* reply) | ||||
| 			// If the response code was 200, then there shouldn't be an error. Make sure anyways. | ||||
| 			// Also, sometimes an empty reply indicates success. If there was no data received,  | ||||
| 			// pass an empty json object to the processResponse function. | ||||
| 			if (jsonError.error  == QJsonParseError::NoError || replyData.size() == 0) | ||||
| 			if (jsonError.error == QJsonParseError::NoError || replyData.size() == 0) | ||||
| 			{ | ||||
| 				if (!processResponse(replyData.size() > 0 ? doc.object() : QJsonObject())) | ||||
| 				{ | ||||
| 					YggdrasilTask::Error* err = getError(); | ||||
| 					YggdrasilTask::Error *err = getError(); | ||||
| 					if (err) | ||||
| 						emitFailed(err->getErrorMessage()); | ||||
| 					else | ||||
| 						emitFailed(tr("An unknown error occurred when processing the response from the authentication server.")); | ||||
| 						emitFailed(tr("An unknown error occurred when processing the response " | ||||
| 									  "from the authentication server.")); | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| @@ -166,4 +166,3 @@ MojangAccountPtr YggdrasilTask::getMojangAccount() const | ||||
| { | ||||
| 	return this->m_account; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -24,15 +24,14 @@ | ||||
|  | ||||
| class QNetworkReply; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * A Yggdrasil task is a task that performs an operation on a given mojang account. | ||||
|  */ | ||||
| class YggdrasilTask : public Task | ||||
| { | ||||
| Q_OBJECT | ||||
| 	Q_OBJECT | ||||
| public: | ||||
| 	explicit YggdrasilTask(MojangAccountPtr account, QObject* parent=0); | ||||
| 	explicit YggdrasilTask(MojangAccountPtr account, QObject *parent = 0); | ||||
| 	~YggdrasilTask(); | ||||
|  | ||||
| 	/** | ||||
| @@ -49,7 +48,10 @@ public: | ||||
| 		QString getCause() const { return m_cause; } | ||||
|  | ||||
| 		/// Gets the string to display in the GUI for describing this error. | ||||
| 		QString getDisplayMessage() { return getErrorMessage(); } | ||||
| 		QString getDisplayMessage() | ||||
| 		{ | ||||
| 			return getErrorMessage(); | ||||
| 		} | ||||
|  | ||||
| 	protected: | ||||
| 		QString m_shortError; | ||||
| @@ -66,7 +68,7 @@ public: | ||||
| 	 * Returns a pointer to a YggdrasilTask::Error object if an error has occurred. | ||||
| 	 * If no error has occurred, returns a null pointer. | ||||
| 	 */ | ||||
| 	virtual Error* getError() const; | ||||
| 	virtual Error *getError() const; | ||||
|  | ||||
| protected: | ||||
| 	/** | ||||
| @@ -120,11 +122,11 @@ protected: | ||||
|  | ||||
| 	MojangAccountPtr m_account; | ||||
|  | ||||
| 	QNetworkReply* m_netReply; | ||||
| 	QNetworkReply *m_netReply; | ||||
|  | ||||
| 	Error* m_error; | ||||
| 	Error *m_error; | ||||
|  | ||||
| protected slots: | ||||
| 	void processReply(QNetworkReply* reply); | ||||
| protected | ||||
| slots: | ||||
| 	void processReply(QNetworkReply *reply); | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -14,7 +14,7 @@ | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| #include <logic/auth/AuthenticateTask.h> | ||||
| #include <logic/auth/flows/AuthenticateTask.h> | ||||
| 
 | ||||
| #include <logic/auth/MojangAccount.h> | ||||
| 
 | ||||
| @@ -26,8 +26,9 @@ | ||||
| 
 | ||||
| #include "logger/QsLog.h" | ||||
| 
 | ||||
| AuthenticateTask::AuthenticateTask(MojangAccountPtr account, const QString& password, QObject* parent) : | ||||
| 	YggdrasilTask(account, parent), m_password(password) | ||||
| AuthenticateTask::AuthenticateTask(MojangAccountPtr account, const QString &password, | ||||
| 								   QObject *parent) | ||||
| 	: YggdrasilTask(account, parent), m_password(password) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| @@ -37,20 +38,22 @@ QJsonObject AuthenticateTask::getRequestContent() const | ||||
| 	 * { | ||||
| 	 *   "agent": {								// optional
 | ||||
| 	 *   "name": "Minecraft",					// So far this is the only encountered value
 | ||||
|  	 *   "version": 1							// This number might be increased
 | ||||
| 	 *   "version": 1							// This number might be increased
 | ||||
| 	 * 											// by the vanilla client in the future
 | ||||
| 	 *   }, | ||||
| 	 *   "username": "mojang account name",		// Can be an email address or player name for
 | ||||
| 												// unmigrated accounts
 | ||||
| 	 *  "password": "mojang account password", | ||||
| 	 *  "clientToken": "client identifier"		// optional
 | ||||
| 	 *  "requestUser": true/false               // request the user structure
 | ||||
| 	 * } | ||||
| 	 */ | ||||
| 	QJsonObject req; | ||||
| 
 | ||||
| 	{ | ||||
| 		QJsonObject agent; | ||||
| 		// C++ makes string literals void* for some stupid reason, so we have to tell it QString... Thanks Obama.
 | ||||
| 		// C++ makes string literals void* for some stupid reason, so we have to tell it
 | ||||
| 		// QString... Thanks Obama.
 | ||||
| 		agent.insert("name", QString("Minecraft")); | ||||
| 		agent.insert("version", 1); | ||||
| 		req.insert("agent", agent); | ||||
| @@ -58,6 +61,7 @@ QJsonObject AuthenticateTask::getRequestContent() const | ||||
| 
 | ||||
| 	req.insert("username", getMojangAccount()->username()); | ||||
| 	req.insert("password", m_password); | ||||
| 	req.insert("requestUser", true); | ||||
| 
 | ||||
| 	// If we already have a client token, give it to the server.
 | ||||
| 	// Otherwise, let the server give us one.
 | ||||
| @@ -69,10 +73,12 @@ QJsonObject AuthenticateTask::getRequestContent() const | ||||
| 
 | ||||
| bool AuthenticateTask::processResponse(QJsonObject responseData) | ||||
| { | ||||
| 	// Read the response data. We need to get the client token, access token, and the selected profile.
 | ||||
| 	// Read the response data. We need to get the client token, access token, and the selected
 | ||||
| 	// profile.
 | ||||
| 	QLOG_DEBUG() << "Processing authentication response."; | ||||
| 	 | ||||
| 	// If we already have a client token, make sure the one the server gave us matches our existing one.
 | ||||
| 
 | ||||
| 	// If we already have a client token, make sure the one the server gave us matches our
 | ||||
| 	// existing one.
 | ||||
| 	QLOG_DEBUG() << "Getting client token."; | ||||
| 	QString clientToken = responseData.value("clientToken").toString(""); | ||||
| 	if (clientToken.isEmpty()) | ||||
| @@ -82,16 +88,17 @@ bool AuthenticateTask::processResponse(QJsonObject responseData) | ||||
| 		QLOG_ERROR() << "Server didn't send a client token."; | ||||
| 		return false; | ||||
| 	} | ||||
| 	if (!getMojangAccount()->clientToken().isEmpty() && clientToken != getMojangAccount()->clientToken()) | ||||
| 	if (!getMojangAccount()->clientToken().isEmpty() && | ||||
| 		clientToken != getMojangAccount()->clientToken()) | ||||
| 	{ | ||||
| 		// The server changed our client token! Obey its wishes, but complain. That's what I do for my parents, so...
 | ||||
| 		QLOG_WARN() << "Server changed our client token to '" << clientToken  | ||||
| 		// The server changed our client token! Obey its wishes, but complain. That's what I do
 | ||||
| 		// for my parents, so...
 | ||||
| 		QLOG_WARN() << "Server changed our client token to '" << clientToken | ||||
| 					<< "'. This shouldn't happen, but it isn't really a big deal."; | ||||
| 	} | ||||
| 	// Set the client token.
 | ||||
| 	getMojangAccount()->setClientToken(clientToken); | ||||
| 
 | ||||
| 
 | ||||
| 	// Now, we set the access token.
 | ||||
| 	QLOG_DEBUG() << "Getting access token."; | ||||
| 	QString accessToken = responseData.value("accessToken").toString(""); | ||||
| @@ -104,10 +111,9 @@ bool AuthenticateTask::processResponse(QJsonObject responseData) | ||||
| 	// Set the access token.
 | ||||
| 	getMojangAccount()->setAccessToken(accessToken); | ||||
| 
 | ||||
| 
 | ||||
| 	// Now we load the list of available profiles.
 | ||||
| 	// Mojang hasn't yet implemented the profile system, 
 | ||||
| 	// but we might as well support what's there so we 
 | ||||
| 	// Mojang hasn't yet implemented the profile system,
 | ||||
| 	// but we might as well support what's there so we
 | ||||
| 	// don't have trouble implementing it later.
 | ||||
| 	QLOG_DEBUG() << "Loading profile list."; | ||||
| 	QJsonArray availableProfiles = responseData.value("availableProfiles").toArray(); | ||||
| @@ -121,10 +127,11 @@ bool AuthenticateTask::processResponse(QJsonObject responseData) | ||||
| 
 | ||||
| 		if (id.isEmpty() || name.isEmpty()) | ||||
| 		{ | ||||
| 			// This should never happen, but we might as well 
 | ||||
| 			// This should never happen, but we might as well
 | ||||
| 			// warn about it if it does so we can debug it easily.
 | ||||
| 			// You never know when Mojang might do something truly derpy.
 | ||||
| 			QLOG_WARN() << "Found entry in available profiles list with missing ID or name field. Ignoring it."; | ||||
| 			QLOG_WARN() << "Found entry in available profiles list with missing ID or name " | ||||
| 						   "field. Ignoring it."; | ||||
| 		} | ||||
| 
 | ||||
| 		// Now, add a new AccountProfile entry to the list.
 | ||||
| @@ -133,10 +140,8 @@ bool AuthenticateTask::processResponse(QJsonObject responseData) | ||||
| 	// Put the list of profiles we loaded into the MojangAccount object.
 | ||||
| 	getMojangAccount()->loadProfiles(loadedProfiles); | ||||
| 
 | ||||
| 	 | ||||
| 
 | ||||
| 	// Finally, we set the current profile to the correct value. This is pretty simple.
 | ||||
| 	// We do need to make sure that the current profile that the server gave us 
 | ||||
| 	// We do need to make sure that the current profile that the server gave us
 | ||||
| 	// is actually in the available profiles list.
 | ||||
| 	// If it isn't, we'll just fail horribly (*shouldn't* ever happen, but you never know).
 | ||||
| 	QLOG_DEBUG() << "Setting current profile."; | ||||
| @@ -151,51 +156,23 @@ bool AuthenticateTask::processResponse(QJsonObject responseData) | ||||
| 	if (!getMojangAccount()->setProfile(currentProfileId)) | ||||
| 	{ | ||||
| 		// TODO: Set an error to display to the user.
 | ||||
| 		QLOG_ERROR() << "Server specified a selected profile that wasn't in the available profiles list."; | ||||
| 		QLOG_ERROR() << "Server specified a selected profile that wasn't in the available " | ||||
| 						"profiles list."; | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| public class User | ||||
| { | ||||
|   private String id; | ||||
|   private List<Property> properties; | ||||
| 
 | ||||
|   public String getId() | ||||
|   { | ||||
|     return this.id; | ||||
|   } | ||||
| 
 | ||||
|   public List<Property> getProperties() { | ||||
|     return this.properties; | ||||
|   } | ||||
|   public class Property { | ||||
|     private String name; | ||||
|     private String value; | ||||
| 
 | ||||
|     public Property() {  }  | ||||
|     public String getKey() { return this.name; } | ||||
| 
 | ||||
|     public String getValue() | ||||
|     { | ||||
|       return this.value; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| */ | ||||
| 	 | ||||
| 	// this is what the vanilla launcher passes to the userProperties launch param
 | ||||
| 	// doesn't seem to be used for anything so far? I don't get any of this data on my account
 | ||||
| 	// (peterixxx)
 | ||||
| 	// is it a good idea to log this?
 | ||||
| 	if(responseData.contains("user")) | ||||
| 	if (responseData.contains("user")) | ||||
| 	{ | ||||
| 		auto obj = responseData.value("user").toObject(); | ||||
| 		auto userId = obj.value("id").toString(); | ||||
| 		auto propArray = obj.value("properties").toArray(); | ||||
| 		QLOG_DEBUG() << "User ID: " << userId; | ||||
| 		QLOG_DEBUG() << "User Properties: "; | ||||
| 		for(auto prop: propArray) | ||||
| 		for (auto prop : propArray) | ||||
| 		{ | ||||
| 			auto propTuple = prop.toObject(); | ||||
| 			auto name = propTuple.value("name").toString(); | ||||
| @@ -203,8 +180,9 @@ public class User | ||||
| 			QLOG_DEBUG() << name << " : " << value; | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	// We've made it through the minefield of possible errors. Return true to indicate that we've succeeded.
 | ||||
| 
 | ||||
| 	// We've made it through the minefield of possible errors. Return true to indicate that
 | ||||
| 	// we've succeeded.
 | ||||
| 	QLOG_DEBUG() << "Finished reading authentication response."; | ||||
| 	return true; | ||||
| } | ||||
| @@ -226,5 +204,3 @@ QString AuthenticateTask::getStateMessage(const YggdrasilTask::State state) cons | ||||
| 		return YggdrasilTask::getStateMessage(state); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @@ -22,25 +22,25 @@ | ||||
| #include <QJsonObject> | ||||
| 
 | ||||
| /**
 | ||||
|  * The authenticate task takes a MojangAccount with no access token and password and attempts to authenticate with Mojang's servers. | ||||
|  * The authenticate task takes a MojangAccount with no access token and password and attempts to | ||||
|  * authenticate with Mojang's servers. | ||||
|  * If successful, it will set the MojangAccount's access token. | ||||
|  */ | ||||
| class AuthenticateTask : public YggdrasilTask | ||||
| { | ||||
| Q_OBJECT | ||||
| 	Q_OBJECT | ||||
| public: | ||||
| 	AuthenticateTask(MojangAccountPtr account, const QString& password, QObject* parent=0); | ||||
| 	AuthenticateTask(MojangAccountPtr account, const QString &password, QObject *parent = 0); | ||||
| 
 | ||||
| protected: | ||||
| 	virtual QJsonObject getRequestContent() const; | ||||
| 	 | ||||
| 
 | ||||
| 	virtual QString getEndpoint() const; | ||||
| 
 | ||||
| 	virtual bool processResponse(QJsonObject responseData); | ||||
| 	 | ||||
| 
 | ||||
| 	QString getStateMessage(const YggdrasilTask::State state) const; | ||||
| 
 | ||||
| private: | ||||
| 	QString m_password; | ||||
| }; | ||||
| 
 | ||||
							
								
								
									
										0
									
								
								logic/auth/flows/InvalidateTask.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								logic/auth/flows/InvalidateTask.cpp
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								logic/auth/flows/InvalidateTask.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								logic/auth/flows/InvalidateTask.h
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										156
									
								
								logic/auth/flows/RefreshTask.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								logic/auth/flows/RefreshTask.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,156 @@ | ||||
| /* Copyright 2013 MultiMC Contributors | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| #include <logic/auth/flows/RefreshTask.h> | ||||
|  | ||||
| #include <logic/auth/MojangAccount.h> | ||||
|  | ||||
| #include <QJsonDocument> | ||||
| #include <QJsonObject> | ||||
| #include <QJsonArray> | ||||
| #include <QVariant> | ||||
| #include <QDebug> | ||||
|  | ||||
| #include "logger/QsLog.h" | ||||
|  | ||||
| RefreshTask::RefreshTask(MojangAccountPtr account, QObject *parent) | ||||
| 	: YggdrasilTask(account, parent) | ||||
| { | ||||
| } | ||||
|  | ||||
| QJsonObject RefreshTask::getRequestContent() const | ||||
| { | ||||
| 	/* | ||||
| 	 * { | ||||
| 	 *  "clientToken": "client identifier" | ||||
| 	 *  "accessToken": "current access token to be refreshed" | ||||
| 	 *  "selectedProfile":                      // specifying this causes errors | ||||
| 	 *  { | ||||
| 	 *   "id": "profile ID" | ||||
| 	 *   "name": "profile name" | ||||
| 	 *  } | ||||
| 	 *  "requestUser": true/false               // request the user structure | ||||
| 	 * } | ||||
| 	 */ | ||||
| 	auto account = getMojangAccount(); | ||||
| 	QJsonObject req; | ||||
| 	req.insert("clientToken", account->clientToken()); | ||||
| 	req.insert("accessToken", account->accessToken()); | ||||
| 	/* | ||||
| 	{ | ||||
| 		auto currentProfile = account->currentProfile(); | ||||
| 		QJsonObject profile; | ||||
| 		profile.insert("id", currentProfile->id()); | ||||
| 		profile.insert("name", currentProfile->name()); | ||||
| 		req.insert("selectedProfile", profile); | ||||
| 	} | ||||
| 	*/ | ||||
| 	req.insert("requestUser", true); | ||||
|  | ||||
| 	return req; | ||||
| } | ||||
|  | ||||
| bool RefreshTask::processResponse(QJsonObject responseData) | ||||
| { | ||||
| 	auto account = getMojangAccount(); | ||||
|  | ||||
| 	// Read the response data. We need to get the client token, access token, and the selected | ||||
| 	// profile. | ||||
| 	QLOG_DEBUG() << "Processing authentication response."; | ||||
|  | ||||
| 	// If we already have a client token, make sure the one the server gave us matches our | ||||
| 	// existing one. | ||||
| 	QString clientToken = responseData.value("clientToken").toString(""); | ||||
| 	if (clientToken.isEmpty()) | ||||
| 	{ | ||||
| 		// Fail if the server gave us an empty client token | ||||
| 		// TODO: Set an error properly to display to the user. | ||||
| 		QLOG_ERROR() << "Server didn't send a client token."; | ||||
| 		return false; | ||||
| 	} | ||||
| 	if (!account->clientToken().isEmpty() && clientToken != account->clientToken()) | ||||
| 	{ | ||||
| 		// The server changed our client token! Obey its wishes, but complain. That's what I do | ||||
| 		// for my parents, so... | ||||
| 		QLOG_ERROR() << "Server changed our client token to '" << clientToken | ||||
| 					 << "'. This shouldn't happen, but it isn't really a big deal."; | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	// Now, we set the access token. | ||||
| 	QLOG_DEBUG() << "Getting new access token."; | ||||
| 	QString accessToken = responseData.value("accessToken").toString(""); | ||||
| 	if (accessToken.isEmpty()) | ||||
| 	{ | ||||
| 		// Fail if the server didn't give us an access token. | ||||
| 		// TODO: Set an error properly to display to the user. | ||||
| 		QLOG_ERROR() << "Server didn't send an access token."; | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	// we validate that the server responded right. (our current profile = returned current | ||||
| 	// profile) | ||||
| 	QJsonObject currentProfile = responseData.value("selectedProfile").toObject(); | ||||
| 	QString currentProfileId = currentProfile.value("id").toString(""); | ||||
| 	if (account->currentProfile()->id() != currentProfileId) | ||||
| 	{ | ||||
| 		// TODO: Set an error to display to the user. | ||||
| 		QLOG_ERROR() << "Server didn't specify the same selected profile as ours."; | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	// this is what the vanilla launcher passes to the userProperties launch param | ||||
| 	if (responseData.contains("user")) | ||||
| 	{ | ||||
| 		auto obj = responseData.value("user").toObject(); | ||||
| 		auto userId = obj.value("id").toString(); | ||||
| 		auto propArray = obj.value("properties").toArray(); | ||||
| 		QLOG_DEBUG() << "User ID: " << userId; | ||||
| 		QLOG_DEBUG() << "User Properties: "; | ||||
| 		for (auto prop : propArray) | ||||
| 		{ | ||||
| 			auto propTuple = prop.toObject(); | ||||
| 			auto name = propTuple.value("name").toString(); | ||||
| 			auto value = propTuple.value("value").toString(); | ||||
| 			QLOG_DEBUG() << name << " : " << value; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// We've made it through the minefield of possible errors. Return true to indicate that | ||||
| 	// we've succeeded. | ||||
| 	QLOG_DEBUG() << "Finished reading refresh response."; | ||||
| 	// Reset the access token. | ||||
| 	account->setAccessToken(accessToken); | ||||
| 	account->propagateChange(); | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| QString RefreshTask::getEndpoint() const | ||||
| { | ||||
| 	return "refresh"; | ||||
| } | ||||
|  | ||||
| QString RefreshTask::getStateMessage(const YggdrasilTask::State state) const | ||||
| { | ||||
| 	switch (state) | ||||
| 	{ | ||||
| 	case STATE_SENDING_REQUEST: | ||||
| 		return tr("Refreshing: Sending request."); | ||||
| 	case STATE_PROCESSING_RESPONSE: | ||||
| 		return tr("Refreshing: Processing response."); | ||||
| 	default: | ||||
| 		return YggdrasilTask::getStateMessage(state); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										43
									
								
								logic/auth/flows/RefreshTask.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								logic/auth/flows/RefreshTask.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| /* Copyright 2013 MultiMC Contributors | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <logic/auth/YggdrasilTask.h> | ||||
|  | ||||
| #include <QObject> | ||||
| #include <QString> | ||||
| #include <QJsonObject> | ||||
|  | ||||
| /** | ||||
|  * The authenticate task takes a MojangAccount with a possibly timed-out access token | ||||
|  * and attempts to authenticate with Mojang's servers. | ||||
|  * If successful, it will set the new access token. The token is considered validated. | ||||
|  */ | ||||
| class RefreshTask : public YggdrasilTask | ||||
| { | ||||
| 	Q_OBJECT | ||||
| public: | ||||
| 	RefreshTask(MojangAccountPtr account, QObject *parent = 0); | ||||
|  | ||||
| protected: | ||||
| 	virtual QJsonObject getRequestContent() const; | ||||
|  | ||||
| 	virtual QString getEndpoint() const; | ||||
|  | ||||
| 	virtual bool processResponse(QJsonObject responseData); | ||||
|  | ||||
| 	QString getStateMessage(const YggdrasilTask::State state) const; | ||||
| }; | ||||
| @@ -14,7 +14,7 @@ | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| #include <logic/auth/ValidateTask.h> | ||||
| #include <logic/auth/flows/ValidateTask.h> | ||||
| 
 | ||||
| #include <logic/auth/MojangAccount.h> | ||||
| 
 | ||||
| @@ -26,8 +26,8 @@ | ||||
| 
 | ||||
| #include "logger/QsLog.h" | ||||
| 
 | ||||
| ValidateTask::ValidateTask(MojangAccountPtr account, QObject* parent) : | ||||
| 	YggdrasilTask(account, parent) | ||||
| ValidateTask::ValidateTask(MojangAccountPtr account, QObject *parent) | ||||
| 	: YggdrasilTask(account, parent) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| @@ -62,5 +62,3 @@ QString ValidateTask::getStateMessage(const YggdrasilTask::State state) const | ||||
| 		return YggdrasilTask::getStateMessage(state); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @@ -26,19 +26,18 @@ | ||||
|  */ | ||||
| class ValidateTask : public YggdrasilTask | ||||
| { | ||||
| Q_OBJECT | ||||
| 	Q_OBJECT | ||||
| public: | ||||
| 	ValidateTask(MojangAccountPtr account, QObject* parent=0); | ||||
| 	ValidateTask(MojangAccountPtr account, QObject *parent = 0); | ||||
| 
 | ||||
| protected: | ||||
| 	virtual QJsonObject getRequestContent() const; | ||||
| 	 | ||||
| 
 | ||||
| 	virtual QString getEndpoint() const; | ||||
| 
 | ||||
| 	virtual bool processResponse(QJsonObject responseData); | ||||
| 	 | ||||
| 
 | ||||
| 	QString getStateMessage(const YggdrasilTask::State state) const; | ||||
| 
 | ||||
| private: | ||||
| }; | ||||
| 
 | ||||
| @@ -281,14 +281,6 @@ InstanceList::InstListError InstanceList::loadList() | ||||
| 		auto &loader = InstanceFactory::get(); | ||||
| 		auto error = loader.loadInstance(instPtr, subDir); | ||||
|  | ||||
| 		switch (error) | ||||
| 		{ | ||||
| 		case InstanceFactory::NoLoadError: | ||||
| 			break; | ||||
| 		case InstanceFactory::NotAnInstance: | ||||
| 			break; | ||||
| 		} | ||||
|  | ||||
| 		if (error != InstanceFactory::NoLoadError && error != InstanceFactory::NotAnInstance) | ||||
| 		{ | ||||
| 			QString errorMsg = QString("Failed to load instance %1: ") | ||||
| @@ -362,8 +354,13 @@ int InstanceList::add(InstancePtr t) | ||||
| 	return count() - 1; | ||||
| } | ||||
|  | ||||
| InstancePtr InstanceList::getInstanceById(QString instId) | ||||
| InstancePtr InstanceList::getInstanceById(QString instId) const | ||||
| { | ||||
| 	if (m_instances.isEmpty()) | ||||
| 	{ | ||||
| 		return InstancePtr(); | ||||
| 	} | ||||
|  | ||||
| 	QListIterator<InstancePtr> iter(m_instances); | ||||
| 	InstancePtr inst; | ||||
| 	while (iter.hasNext()) | ||||
| @@ -378,7 +375,12 @@ InstancePtr InstanceList::getInstanceById(QString instId) | ||||
| 		return iter.peekPrevious(); | ||||
| } | ||||
|  | ||||
| int InstanceList::getInstIndex(BaseInstance *inst) | ||||
| QModelIndex InstanceList::getInstanceIndexById(const QString &id) const | ||||
| { | ||||
| 	return index(getInstIndex(getInstanceById(id).get())); | ||||
| } | ||||
|  | ||||
| int InstanceList::getInstIndex(BaseInstance *inst) const | ||||
| { | ||||
| 	for (int i = 0; i < m_instances.count(); i++) | ||||
| 	{ | ||||
|   | ||||
| @@ -91,7 +91,9 @@ public: | ||||
| 	int add(InstancePtr t); | ||||
|  | ||||
| 	/// Get an instance by ID | ||||
| 	InstancePtr getInstanceById(QString id); | ||||
| 	InstancePtr getInstanceById(QString id) const; | ||||
|  | ||||
| 	QModelIndex getInstanceIndexById(const QString &id) const; | ||||
| signals: | ||||
| 	void dataIsInvalid(); | ||||
|  | ||||
| @@ -106,7 +108,7 @@ slots: | ||||
| 	void groupChanged(); | ||||
|  | ||||
| private: | ||||
| 	int getInstIndex(BaseInstance *inst); | ||||
| 	int getInstIndex(BaseInstance *inst) const; | ||||
|  | ||||
| protected: | ||||
| 	QString m_instDir; | ||||
|   | ||||
| @@ -44,7 +44,6 @@ MojangAccountPtr MojangAccountList::findAccount(const QString &username) const | ||||
| 	return nullptr; | ||||
| } | ||||
|  | ||||
|  | ||||
| const MojangAccountPtr MojangAccountList::at(int i) const | ||||
| { | ||||
| 	return MojangAccountPtr(m_accounts.at(i)); | ||||
| @@ -53,12 +52,13 @@ const MojangAccountPtr MojangAccountList::at(int i) const | ||||
| void MojangAccountList::addAccount(const MojangAccountPtr account) | ||||
| { | ||||
| 	beginResetModel(); | ||||
| 	connect(account.get(), SIGNAL(changed()), SLOT(accountChanged())); | ||||
| 	m_accounts.append(account); | ||||
| 	endResetModel(); | ||||
| 	onListChanged(); | ||||
| } | ||||
|  | ||||
| void MojangAccountList::removeAccount(const QString& username) | ||||
| void MojangAccountList::removeAccount(const QString &username) | ||||
| { | ||||
| 	beginResetModel(); | ||||
| 	for (auto account : m_accounts) | ||||
| @@ -81,7 +81,6 @@ void MojangAccountList::removeAccount(QModelIndex index) | ||||
| 	onListChanged(); | ||||
| } | ||||
|  | ||||
|  | ||||
| MojangAccountPtr MojangAccountList::activeAccount() const | ||||
| { | ||||
| 	if (m_activeAccount.isEmpty()) | ||||
| @@ -90,7 +89,7 @@ MojangAccountPtr MojangAccountList::activeAccount() const | ||||
| 		return findAccount(m_activeAccount); | ||||
| } | ||||
|  | ||||
| void MojangAccountList::setActiveAccount(const QString& username) | ||||
| void MojangAccountList::setActiveAccount(const QString &username) | ||||
| { | ||||
| 	beginResetModel(); | ||||
| 	if (username.isEmpty()) | ||||
| @@ -109,6 +108,11 @@ void MojangAccountList::setActiveAccount(const QString& username) | ||||
| 	onActiveChanged(); | ||||
| } | ||||
|  | ||||
| void MojangAccountList::accountChanged() | ||||
| { | ||||
| 	// the list changed. there is no doubt. | ||||
| 	onListChanged(); | ||||
| } | ||||
|  | ||||
| void MojangAccountList::onListChanged() | ||||
| { | ||||
| @@ -127,13 +131,11 @@ void MojangAccountList::onActiveChanged() | ||||
| 	emit activeAccountChanged(); | ||||
| } | ||||
|  | ||||
|  | ||||
| int MojangAccountList::count() const | ||||
| { | ||||
| 	return m_accounts.count(); | ||||
| } | ||||
|  | ||||
|  | ||||
| QVariant MojangAccountList::data(const QModelIndex &index, int role) const | ||||
| { | ||||
| 	if (!index.isValid()) | ||||
| @@ -220,10 +222,11 @@ void MojangAccountList::updateListData(QList<MojangAccountPtr> versions) | ||||
| 	endResetModel(); | ||||
| } | ||||
|  | ||||
| bool MojangAccountList::loadList(const QString& filePath) | ||||
| bool MojangAccountList::loadList(const QString &filePath) | ||||
| { | ||||
| 	QString path = filePath; | ||||
| 	if (path.isEmpty()) path = m_listFilePath; | ||||
| 	if (path.isEmpty()) | ||||
| 		path = m_listFilePath; | ||||
| 	if (path.isEmpty()) | ||||
| 	{ | ||||
| 		QLOG_ERROR() << "Can't load Mojang account list. No file path given and no default set."; | ||||
| @@ -231,7 +234,7 @@ bool MojangAccountList::loadList(const QString& filePath) | ||||
| 	} | ||||
|  | ||||
| 	QFile file(path); | ||||
| 	 | ||||
|  | ||||
| 	// Try to open the file and fail if we can't. | ||||
| 	// TODO: We should probably report this error to the user. | ||||
| 	if (!file.open(QIODevice::ReadOnly)) | ||||
| @@ -286,6 +289,7 @@ bool MojangAccountList::loadList(const QString& filePath) | ||||
| 		MojangAccountPtr account = MojangAccount::loadFromJson(accountObj); | ||||
| 		if (account.get() != nullptr) | ||||
| 		{ | ||||
| 			connect(account.get(), SIGNAL(changed()), SLOT(accountChanged())); | ||||
| 			m_accounts.append(account); | ||||
| 		} | ||||
| 		else | ||||
| @@ -297,14 +301,15 @@ bool MojangAccountList::loadList(const QString& filePath) | ||||
|  | ||||
| 	// Load the active account. | ||||
| 	m_activeAccount = root.value("activeAccount").toString(""); | ||||
| 	 | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| bool MojangAccountList::saveList(const QString& filePath) | ||||
| bool MojangAccountList::saveList(const QString &filePath) | ||||
| { | ||||
| 	QString path(filePath); | ||||
| 	if (path.isEmpty()) path = m_listFilePath; | ||||
| 	if (path.isEmpty()) | ||||
| 		path = m_listFilePath; | ||||
| 	if (path.isEmpty()) | ||||
| 	{ | ||||
| 		QLOG_ERROR() << "Can't save Mojang account list. No file path given and no default set."; | ||||
| @@ -337,7 +342,6 @@ bool MojangAccountList::saveList(const QString& filePath) | ||||
| 	// Create a JSON document object to convert our JSON to bytes. | ||||
| 	QJsonDocument doc(root); | ||||
|  | ||||
|  | ||||
| 	// Now that we're done building the JSON object, we can write it to the file. | ||||
| 	QLOG_DEBUG() << "Writing account list to file."; | ||||
| 	QFile file(path); | ||||
| @@ -362,6 +366,5 @@ bool MojangAccountList::saveList(const QString& filePath) | ||||
| void MojangAccountList::setListFilePath(QString path, bool autosave) | ||||
| { | ||||
| 	m_listFilePath = path; | ||||
| 	autosave = autosave; | ||||
| 	m_autosave = autosave; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -22,7 +22,6 @@ | ||||
|  | ||||
| #include "logic/auth/MojangAccount.h" | ||||
|  | ||||
|  | ||||
| /*! | ||||
|  * \brief List of available Mojang accounts. | ||||
|  * This should be loaded in the background by MultiMC on startup. | ||||
| @@ -44,10 +43,10 @@ public: | ||||
| 	enum VListColumns | ||||
| 	{ | ||||
| 		// TODO: Add icon column. | ||||
| 		 | ||||
|  | ||||
| 		// First column - Active? | ||||
| 		ActiveColumn = 0, | ||||
| 		 | ||||
|  | ||||
| 		// Second column - Name | ||||
| 		NameColumn, | ||||
| 	}; | ||||
| @@ -74,7 +73,7 @@ public: | ||||
| 	/*! | ||||
| 	 * Removes the mojang account with the given username from the account list. | ||||
| 	 */ | ||||
| 	virtual void removeAccount(const QString& username); | ||||
| 	virtual void removeAccount(const QString &username); | ||||
|  | ||||
| 	/*! | ||||
| 	 * Removes the account at the given QModelIndex. | ||||
| @@ -88,7 +87,7 @@ public: | ||||
| 	 * one doesn't exist. | ||||
| 	 */ | ||||
| 	virtual MojangAccountPtr findAccount(const QString &username) const; | ||||
| 	 | ||||
|  | ||||
| 	/*! | ||||
| 	 * Sets the default path to save the list file to. | ||||
| 	 * If autosave is true, this list will automatically save to the given path whenever it changes. | ||||
| @@ -96,21 +95,21 @@ public: | ||||
| 	 * after calling this function to ensure an autosaved change doesn't overwrite the list you intended | ||||
| 	 * to load. | ||||
| 	 */ | ||||
| 	virtual void setListFilePath(QString path, bool autosave=false); | ||||
| 	virtual void setListFilePath(QString path, bool autosave = false); | ||||
|  | ||||
| 	/*! | ||||
| 	 * \brief Loads the account list from the given file path. | ||||
| 	 * If the given file is an empty string (default), will load from the default account list file. | ||||
| 	 * \return True if successful, otherwise false. | ||||
| 	 */ | ||||
| 	virtual bool loadList(const QString& file=""); | ||||
| 	virtual bool loadList(const QString &file = ""); | ||||
|  | ||||
| 	/*! | ||||
| 	 * \brief Saves the account list to the given file. | ||||
| 	 * If the given file is an empty string (default), will save from the default account list file. | ||||
| 	 * \return True if successful, otherwise false. | ||||
| 	 */ | ||||
| 	virtual bool saveList(const QString& file=""); | ||||
| 	virtual bool saveList(const QString &file = ""); | ||||
|  | ||||
| 	/*! | ||||
| 	 * \brief Gets a pointer to the account that the user has selected as their "active" account. | ||||
| @@ -124,12 +123,13 @@ public: | ||||
| 	 * Sets the given account as the current active account. | ||||
| 	 * If the username given is an empty string, sets the active account to nothing. | ||||
| 	 */ | ||||
| 	virtual void setActiveAccount(const QString& username); | ||||
| 	virtual void setActiveAccount(const QString &username); | ||||
|  | ||||
| signals: | ||||
| 	/*! | ||||
| 	 * Signal emitted to indicate that the account list has changed. | ||||
| 	 * This will also fire if the value of an element in the list changes (will be implemented later). | ||||
| 	 * This will also fire if the value of an element in the list changes (will be implemented | ||||
| 	 * later). | ||||
| 	 */ | ||||
| 	void listChanged(); | ||||
|  | ||||
| @@ -138,6 +138,13 @@ signals: | ||||
| 	 */ | ||||
| 	void activeAccountChanged(); | ||||
|  | ||||
| public | ||||
| slots: | ||||
| 	/** | ||||
| 	 * This is called when one of the accounts changes and the list needs to be updated | ||||
| 	 */ | ||||
| 	void accountChanged(); | ||||
|  | ||||
| protected: | ||||
| 	/*! | ||||
| 	 * Called whenever the list changes. | ||||
| @@ -166,7 +173,7 @@ protected: | ||||
| 	 * If true, the account list will automatically save to the account list path when it changes. | ||||
| 	 * Ignored if m_listFilePath is blank. | ||||
| 	 */ | ||||
| 	bool m_autosave; | ||||
| 	bool m_autosave = false; | ||||
|  | ||||
| protected | ||||
| slots: | ||||
| @@ -184,4 +191,3 @@ slots: | ||||
| 	 */ | ||||
| 	virtual void updateListData(QList<MojangAccountPtr> versions); | ||||
| }; | ||||
|  | ||||
|   | ||||
							
								
								
									
										60
									
								
								test.cpp
									
									
									
									
									
								
							
							
						
						
									
										60
									
								
								test.cpp
									
									
									
									
									
								
							| @@ -1,60 +0,0 @@ | ||||
|  | ||||
| #include <iostream> | ||||
|  | ||||
| #include "keyring.h" | ||||
| #include "cmdutils.h" | ||||
|  | ||||
| using namespace Util::Commandline; | ||||
|  | ||||
| #include <QCoreApplication> | ||||
|  | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
| 	QCoreApplication app(argc, argv); | ||||
| 	app.setApplicationName("MMC Keyring test"); | ||||
| 	app.setOrganizationName("Orochimarufan"); | ||||
|  | ||||
| 	Parser p; | ||||
| 	p.addArgument("user", false); | ||||
| 	p.addArgument("password", false); | ||||
| 	p.addSwitch("set"); | ||||
| 	p.addSwitch("get"); | ||||
| 	p.addSwitch("list"); | ||||
| 	p.addOption("service", "Test"); | ||||
| 	p.addShortOpt("service", 's'); | ||||
|  | ||||
| 	QHash<QString, QVariant> args; | ||||
| 	try { | ||||
| 		args = p.parse(app.arguments()); | ||||
| 	} catch (ParsingError) { | ||||
| 		std::cout << "Syntax error." << std::endl; | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	if (args["set"].toBool()) { | ||||
| 		if (args["user"].isNull() || args["password"].isNull()) { | ||||
| 			std::cout << "set operation needs bot user and password set" << std::endl; | ||||
| 			return 1; | ||||
| 		} | ||||
|  | ||||
| 		return Keyring::instance()->storePassword(args["service"].toString(), | ||||
| 				args["user"].toString(), args["password"].toString()); | ||||
| 	} else if (args["get"].toBool()) { | ||||
| 		if (args["user"].isNull()) { | ||||
| 			std::cout << "get operation needs user set" << std::endl; | ||||
| 			return 1; | ||||
| 		} | ||||
|  | ||||
| 		std::cout << "Password: " << qPrintable(Keyring::instance()->getPassword(args["service"].toString(), | ||||
| 				args["user"].toString())) << std::endl; | ||||
| 		return 0; | ||||
| 	} else if (args["list"].toBool()) { | ||||
| 		QStringList accounts = Keyring::instance()->getStoredAccounts(args["service"].toString()); | ||||
| 		std::cout << "stored accounts:" << std::endl << '\t' << qPrintable(accounts.join("\n\t")) << std::endl; | ||||
| 		return 0; | ||||
| 	} else { | ||||
| 		std::cout << "No operation given!" << std::endl; | ||||
| 		std::cout << qPrintable(p.compileHelp(argv[0])) << std::endl; | ||||
| 		return 1; | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user