#include "Application.h" #include "utility/interprocess/SharedMemoryGarbageCollector.h" #include "utility/logging/logging.h" #include "utility/logging/LogManager.h" #include "utility/messaging/filter_types/MessageFilterFocusInOut.h" #include "utility/messaging/filter_types/MessageFilterNewErrors.h" #include "utility/messaging/filter_types/MessageFilterSearchAutocomplete.h" #include "utility/messaging/MessageQueue.h" #include "utility/messaging/type/MessageForceEnterLicense.h" #include "utility/messaging/type/MessageQuitApplication.h" #include "utility/messaging/type/MessageStatus.h" #include "utility/scheduling/TaskScheduler.h" #include "utility/tracing.h" #include "utility/UserPaths.h" #include "utility/utilityString.h" #include "utility/utilityUuid.h" #include "utility/Version.h" #include "component/controller/IDECommunicationController.h" #include "component/NetworkFactory.h" #include "component/view/DialogView.h" #include "component/view/GraphViewStyle.h" #include "component/view/MainView.h" #include "component/view/ViewFactory.h" #include "data/storage/StorageCache.h" #include "LicenseChecker.h" #include "settings/ApplicationSettings.h" #include "settings/ProjectSettings.h" #include "settings/ColorScheme.h" #include "UpdateChecker.h" std::shared_ptr Application::s_instance; std::string Application::s_uuid; void Application::createInstance( const Version& version, ViewFactory* viewFactory, NetworkFactory* networkFactory ){ Version::setApplicationVersion(version); loadSettings(); SharedMemoryGarbageCollector* collector = SharedMemoryGarbageCollector::createInstance(); if (collector) { collector->run(Application::getUUID()); } TaskScheduler::getInstance(); MessageQueue::getInstance(); bool hasGui = (viewFactory != nullptr); s_instance = std::shared_ptr(new Application(hasGui)); s_instance->m_storageCache = std::make_shared(); if (hasGui) { s_instance->m_componentManager = ComponentManager::create(viewFactory, s_instance->m_storageCache.get()); s_instance->m_mainView = viewFactory->createMainView(); s_instance->updateTitle(); s_instance->m_componentManager->setup(s_instance->m_mainView.get()); s_instance->m_mainView->loadLayout(); s_instance->m_componentManager->refreshViews(); } if (networkFactory != nullptr) { s_instance->m_ideCommunicationController = networkFactory->createIDECommunicationController(s_instance->m_storageCache.get()); s_instance->m_ideCommunicationController->startListening(); s_instance->m_updateChecker = networkFactory->createUpdateChecker(); } s_instance->startMessagingAndScheduling(); } std::shared_ptr Application::getInstance() { return s_instance; } void Application::destroyInstance() { s_instance.reset(); } std::string Application::getUUID() { if (!s_uuid.size()) { s_uuid = utility::getUuidString(); } return s_uuid; } void Application::loadSettings() { MessageStatus(L"Load settings: " + UserPaths::getAppSettingsPath().wstr()).dispatch(); std::shared_ptr settings = ApplicationSettings::getInstance(); settings->load(UserPaths::getAppSettingsPath()); LogManager::getInstance()->setLoggingEnabled(settings->getLoggingEnabled()); loadStyle(settings->getColorSchemePath()); } void Application::loadStyle(const FilePath& colorSchemePath) { ColorScheme::getInstance()->load(colorSchemePath); GraphViewStyle::loadStyleSettings(); } Application::Application(bool withGUI) : m_hasGUI(withGUI) , m_licenseType(MessageEnteredLicense::LICENSE_NONE) , m_lastLicenseCheck(TimeStamp::now()) { LicenseChecker::createInstance(); } Application::~Application() { MessageQueue::getInstance()->stopMessageLoop(); TaskScheduler::getInstance()->stopSchedulerLoop(); if (m_hasGUI) { m_mainView->saveLayout(); } SharedMemoryGarbageCollector* collector = SharedMemoryGarbageCollector::createInstance(); if (collector) { collector->stop(); } } const std::shared_ptr Application::getCurrentProject() { return m_project; } bool Application::hasGUI() { return m_hasGUI; } int Application::handleDialog(const std::string& message) { return getDialogView()->confirm(message); } int Application::handleDialog(const std::string& message, const std::vector& options) { return getDialogView()->confirm(message, options); } int Application::handleDialog(const std::wstring& message) { return getDialogView()->confirm(message); } int Application::handleDialog(const std::wstring& message, const std::vector& options) { return getDialogView()->confirm(message, options); } std::shared_ptr Application::getDialogView() { if (m_componentManager) { return m_componentManager->getDialogView(); } return std::make_shared(nullptr); } void Application::updateHistory(const std::vector& history) { m_mainView->updateHistoryMenu(history); } void Application::updateBookmarks(const std::vector>& bookmarks) { m_mainView->updateBookmarksMenu(bookmarks); } void Application::createAndLoadProject(const FilePath& projectSettingsFilePath) { MessageStatus(L"Loading Project: " + projectSettingsFilePath.wstr(), false, true).dispatch(); try { updateRecentProjects(projectSettingsFilePath); m_storageCache->clear(); m_storageCache->setSubject(nullptr); m_project = std::make_shared( std::make_shared(projectSettingsFilePath), m_storageCache.get(), hasGUI()); if (m_project) { m_project->load(); } else { LOG_ERROR_STREAM(<< "Failed to load project."); MessageStatus(L"Failed to load project: " + projectSettingsFilePath.wstr(), true).dispatch(); } updateTitle(); } catch (std::exception& e) { LOG_ERROR_STREAM(<< "Failed to load project, exception thrown: " << e.what()); MessageStatus(L"Failed to load project, exception was thrown: " + projectSettingsFilePath.wstr(), true).dispatch(); } catch (...) { LOG_ERROR_STREAM(<< "Failed to load project, unknown exception thrown."); MessageStatus(L"Failed to load project, unknown exception was thrown: " + projectSettingsFilePath.wstr(), true).dispatch(); } if (m_hasGUI) { m_componentManager->clearComponents(); } } void Application::refreshProject(RefreshMode refreshMode) { if (m_project && checkSharedMemory()) { m_project->refresh(refreshMode, getDialogView().get()); } } void Application::handleMessage(MessageActivateWindow* message) { if (m_hasGUI) { m_mainView->activateWindow(); } } void Application::handleMessage(MessageEnteredLicense* message) { MessageStatus(L"Found valid license key, unlocked application.").dispatch(); m_licenseType = message->type; updateTitle(); } void Application::handleMessage(MessageFinishedParsing* message) { logStorageStats(); if (m_hasGUI) { MessageRefresh().refreshUiOnly().dispatch(); } else { MessageQuitApplication().dispatch(); } } void Application::handleMessage(MessageLoadProject* message) { TRACE("app load project"); FilePath projectSettingsFilePath(message->projectSettingsFilePath); if (projectSettingsFilePath.empty()) { return; } if (m_project && projectSettingsFilePath == m_project->getProjectSettingsFilePath()) { if (message->settingsChanged && m_hasGUI) { m_project->setStateOutdated(); refreshProject(REFRESH_ALL_FILES); } } else { createAndLoadProject(projectSettingsFilePath); if (message->refreshMode != REFRESH_NONE) { refreshProject(message->refreshMode); } } } void Application::handleMessage(MessageRefresh* message) { TRACE("app refresh"); if (m_hasGUI && message->uiOnly) { if (message->loadStyle) { loadStyle(ApplicationSettings::getInstance()->getColorSchemePath()); } m_mainView->refreshView(); m_componentManager->refreshViews(); } if (!message->uiOnly) { refreshProject(message->all ? REFRESH_ALL_FILES : REFRESH_UPDATED_FILES); } } void Application::handleMessage(MessageSwitchColorScheme* message) { MessageStatus(L"Switch color scheme: " + message->colorSchemePath.wstr()).dispatch(); loadStyle(message->colorSchemePath); MessageRefresh().refreshUiOnly().noReloadStyle().dispatch(); } void Application::handleMessage(MessageWindowFocus* message) { if (!message->focusIn) { return; } if (m_project && ApplicationSettings::getInstance()->getAutomaticUpdateCheck()) { m_updateChecker->checkUpdate(); } if (!ApplicationSettings::getInstance()->getNonCommercialUse() && TimeStamp::now().deltaHours(m_lastLicenseCheck) > 1) { m_lastLicenseCheck = TimeStamp::now(); LicenseChecker::LicenseState state = LicenseChecker::getInstance()->checkCurrentLicense(); if (state != LicenseChecker::LICENSE_VALID && state != LicenseChecker::LICENSE_MOVED) { MessageForceEnterLicense(state).dispatch(); } } } void Application::startMessagingAndScheduling() { TaskScheduler::getInstance()->startSchedulerLoopThreaded(); MessageQueue* queue = MessageQueue::getInstance().get(); queue->addMessageFilter(std::make_shared()); queue->addMessageFilter(std::make_shared()); queue->addMessageFilter(std::make_shared()); queue->setSendMessagesAsTasks(true); queue->startMessageLoopThreaded(); } void Application::updateRecentProjects(const FilePath& projectSettingsFilePath) { if (m_hasGUI) { ApplicationSettings* appSettings = ApplicationSettings::getInstance().get(); std::vector recentProjects = appSettings->getRecentProjects(); if (recentProjects.size()) { std::vector::iterator it = std::find(recentProjects.begin(), recentProjects.end(), projectSettingsFilePath); if (it != recentProjects.end()) { recentProjects.erase(it); } } recentProjects.insert(recentProjects.begin(), projectSettingsFilePath); while (recentProjects.size() > 7) { recentProjects.pop_back(); } appSettings->setRecentProjects(recentProjects); appSettings->save(UserPaths::getAppSettingsPath()); m_mainView->updateRecentProjectMenu(); } } void Application::logStorageStats() const { if (!ApplicationSettings::getInstance()->getLoggingEnabled()) { return; } std::stringstream ss; StorageStats stats = m_storageCache->getStorageStats(); ss << "\nGraph:\n"; ss << "\t" << stats.nodeCount << " Nodes\n"; ss << "\t" << stats.edgeCount << " Edges\n"; ss << "\nCode:\n"; ss << "\t" << stats.fileCount << " Files\n"; ss << "\t" << stats.fileLOCCount << " Lines of Code\n"; ErrorCountInfo errorCount = m_storageCache->getErrorCount(); ss << "\nErrors:\n"; ss << "\t" << errorCount.total << " Errors\n"; ss << "\t" << errorCount.fatal << " Fatal Errors\n"; LOG_INFO(ss.str()); } void Application::updateTitle() { if (m_hasGUI) { std::wstring title = L"Sourcetrail"; switch (m_licenseType) { case MessageEnteredLicense::LICENSE_TEST: title += L" [test]"; break; case MessageEnteredLicense::LICENSE_NONE: case MessageEnteredLicense::LICENSE_NON_COMMERCIAL: title += L" [non-commercial]"; break; case MessageEnteredLicense::LICENSE_COMMERCIAL: break; } if (m_project) { FilePath projectPath = m_project->getProjectSettingsFilePath(); if (!projectPath.empty()) { title += L" - " + projectPath.fileName(); } } m_mainView->setTitle(title); } } bool Application::checkSharedMemory() { std::wstring error = utility::decodeFromUtf8(SharedMemory::checkSharedMemory(getUUID())); if (error.size()) { MessageStatus(L"Error on accessing shared memory. Indexing not possible. Please restart computer or run as admin: " + error, true).dispatch(); handleDialog( L"There was an error accessing shared memory on your computer: " + error + L"\n\n" "Project indexing is not possible. Please restart your computer or try running Sourcetrail as admin. If the " "issue persists contact mail@sourcetrail.com"); return false; } return true; }