diff --git a/src/plugins/coreplugin/navigationsubwidget.cpp b/src/plugins/coreplugin/navigationsubwidget.cpp index 00bbd969e00..39c23b45bd3 100644 --- a/src/plugins/coreplugin/navigationsubwidget.cpp +++ b/src/plugins/coreplugin/navigationsubwidget.cpp @@ -194,6 +194,11 @@ void NavigationSubWidget::setCloseIcon(const QIcon &icon) m_closeButton->setIcon(icon); } +QWidget *NavigationSubWidget::widget() +{ + return m_navigationWidget; +} + int NavigationSubWidget::factoryIndex() const { return m_navigationComboBox->currentIndex(); diff --git a/src/plugins/coreplugin/navigationsubwidget.h b/src/plugins/coreplugin/navigationsubwidget.h index 6d49c850269..c19e66b3ecc 100644 --- a/src/plugins/coreplugin/navigationsubwidget.h +++ b/src/plugins/coreplugin/navigationsubwidget.h @@ -72,6 +72,8 @@ public: Command *command(const QString &title) const; void setCloseIcon(const QIcon &icon); + QWidget *widget(); + signals: void splitMe(int factoryIndex); void closeMe(); diff --git a/src/plugins/coreplugin/navigationwidget.cpp b/src/plugins/coreplugin/navigationwidget.cpp index d262591c568..079656fb0d3 100644 --- a/src/plugins/coreplugin/navigationwidget.cpp +++ b/src/plugins/coreplugin/navigationwidget.cpp @@ -270,14 +270,14 @@ void NavigationWidget::activateSubWidget() activateSubWidget(id); } -void NavigationWidget::activateSubWidget(Id factoryId) +QWidget *NavigationWidget::activateSubWidget(Id factoryId) { setShown(true); foreach (Internal::NavigationSubWidget *subWidget, d->m_subWidgets) { if (subWidget->factory()->id() == factoryId) { subWidget->setFocusWidget(); ICore::raiseWindow(this); - return; + return subWidget->widget(); } } @@ -286,6 +286,7 @@ void NavigationWidget::activateSubWidget(Id factoryId) d->m_subWidgets.first()->setFactoryIndex(index); d->m_subWidgets.first()->setFocusWidget(); ICore::raiseWindow(this); + return d->m_subWidgets.first()->widget(); } } diff --git a/src/plugins/coreplugin/navigationwidget.h b/src/plugins/coreplugin/navigationwidget.h index f83356d6d9e..ea9ad776043 100644 --- a/src/plugins/coreplugin/navigationwidget.h +++ b/src/plugins/coreplugin/navigationwidget.h @@ -87,7 +87,7 @@ public: void saveSettings(QSettings *settings); void restoreSettings(QSettings *settings); - void activateSubWidget(Id factoryId); + QWidget *activateSubWidget(Id factoryId); void closeSubWidgets(); bool isShown() const; diff --git a/src/plugins/cpptools/cpptoolstestcase.cpp b/src/plugins/cpptools/cpptoolstestcase.cpp index 8cd7953320e..b54d6c4ace5 100644 --- a/src/plugins/cpptools/cpptoolstestcase.cpp +++ b/src/plugins/cpptools/cpptoolstestcase.cpp @@ -286,13 +286,13 @@ ProjectOpenerAndCloser::~ProjectOpenerAndCloser() ProjectInfo ProjectOpenerAndCloser::open(const QString &projectFile, bool configureAsExampleProject) { - QString error; - Project *project = ProjectExplorerPlugin::openProject(projectFile, &error); - if (!error.isEmpty()) - qWarning() << error; - if (!project) + ProjectExplorerPlugin::OpenProjectResult result = ProjectExplorerPlugin::openProject(projectFile); + if (!result) { + qWarning() << result.errorMessage() << result.alreadyOpen(); return ProjectInfo(); + } + Project *project = result.project(); if (configureAsExampleProject) project->configureAsExampleProject(QStringList()); diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index d072df0c3bd..11875becead 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -3245,15 +3245,15 @@ void DebuggerPluginPrivate::testLoadProject(const QString &proFile, const TestCa this, &DebuggerPluginPrivate::testProjectLoaded); m_testCallbacks.append(cb); - QString error; - if (ProjectExplorerPlugin::openProject(proFile, &error)) { + ProjectExplorerPlugin::OpenProjectResult result = ProjectExplorerPlugin::openProject(proFile); + if (result) { // Will end up in callback below due to the connections to // signal currentProjectChanged(). return; } // Project opening failed. Eat the unused callback. - qWarning("Cannot open %s: %s", qPrintable(proFile), qPrintable(error)); + qWarning("Cannot open %s: %s", qPrintable(proFile), qPrintable(result.errorMessage())); QVERIFY(false); m_testCallbacks.pop_back(); } diff --git a/src/plugins/projectexplorer/customwizard/customwizard.cpp b/src/plugins/projectexplorer/customwizard/customwizard.cpp index 69d24364b82..00fb0d1c686 100644 --- a/src/plugins/projectexplorer/customwizard/customwizard.cpp +++ b/src/plugins/projectexplorer/customwizard/customwizard.cpp @@ -525,8 +525,12 @@ bool CustomProjectWizard::postGenerateOpen(const Core::GeneratedFiles &l, QStrin // Post-Generate: Open the project and the editors as desired foreach (const Core::GeneratedFile &file, l) { if (file.attributes() & Core::GeneratedFile::OpenProjectAttribute) { - if (!ProjectExplorerPlugin::openProject(file.path(), errorMessage)) + ProjectExplorerPlugin::OpenProjectResult result + = ProjectExplorerPlugin::openProject(file.path()); + if (!result) { return false; + *errorMessage = result.errorMessage(); + } } } return BaseFileWizardFactory::postGenerateOpenEditors(l, errorMessage); diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp index 035eae6d64a..982c4b6aee3 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp @@ -309,8 +309,10 @@ void JsonWizard::openFiles(const JsonWizard::GeneratorFiles &files) break; } if (file.attributes() & Core::GeneratedFile::OpenProjectAttribute) { - Project *project = ProjectExplorerPlugin::instance()->openProject(file.path(), &errorMessage); - if (!project) { + ProjectExplorerPlugin::OpenProjectResult result + = ProjectExplorerPlugin::instance()->openProject(file.path()); + if (!result) { + errorMessage = result.errorMessage(); if (errorMessage.isEmpty()) { errorMessage = QCoreApplication::translate("ProjectExplorer::JsonWizard", "Failed to open \"%1\" as a project.") diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 4ee86039e4e..be62a91fbcc 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -1410,11 +1410,11 @@ void ProjectExplorerPluginPrivate::loadAction() dd->m_projectFilterString); if (filename.isEmpty()) return; - QString errorMessage; - ProjectExplorerPlugin::openProject(filename, &errorMessage); - if (!errorMessage.isEmpty()) - QMessageBox::critical(ICore::mainWindow(), tr("Failed to open project."), errorMessage); + ProjectExplorerPlugin::OpenProjectResult result = ProjectExplorerPlugin::openProject(filename); + if (!result) + ProjectExplorerPlugin::showOpenProjectError(result); + updateActions(); } @@ -1495,11 +1495,10 @@ void ProjectExplorerPlugin::extensionsInitialized() auto factory = new IDocumentFactory; factory->setOpener([this](const QString &fileName) -> IDocument* { - QString errorMessage; - ProjectExplorerPlugin::openProject(fileName, &errorMessage); - if (!errorMessage.isEmpty()) - QMessageBox::critical(ICore::mainWindow(), - tr("Failed to open project."), errorMessage); + + OpenProjectResult result = ProjectExplorerPlugin::openProject(fileName); + if (!result) + showOpenProjectError(result); return 0; }); @@ -1653,23 +1652,52 @@ void ProjectExplorerPluginPrivate::savePersistentSettings() void ProjectExplorerPlugin::openProjectWelcomePage(const QString &fileName) { - QString errorMessage; - openProject(fileName, &errorMessage); - if (!errorMessage.isEmpty()) - QMessageBox::critical(ICore::mainWindow(), tr("Failed to Open Project"), errorMessage); + OpenProjectResult result = openProject(fileName); + if (!result) + showOpenProjectError(result); } -Project *ProjectExplorerPlugin::openProject(const QString &fileName, QString *errorString) +ProjectExplorerPlugin::OpenProjectResult ProjectExplorerPlugin::openProject(const QString &fileName) { if (debug) qDebug() << "ProjectExplorerPlugin::openProject"; - QList list = openProjects(QStringList() << fileName, errorString); - if (list.isEmpty()) - return 0; - dd->addToRecentProjects(fileName, list.first()->displayName()); - SessionManager::setStartupProject(list.first()); - return list.first(); + OpenProjectResult result = openProjects(QStringList() << fileName); + Project *project = result.project(); + if (!project) + return result; + dd->addToRecentProjects(fileName, project->displayName()); + SessionManager::setStartupProject(project); + return result; +} + +void ProjectExplorerPlugin::showOpenProjectError(const OpenProjectResult &result) +{ + if (result) + return; + + // Potentially both errorMessage and alreadyOpen could contain information + // that should be shown to the user. + // BUT, if Creator opens only a single project, this can lead + // to either + // - No error + // - A errorMessage + // - A single project in alreadyOpen + + // The only place where multiple projects are opened is in session restore + // where the already open case should never happen, thus + // the following code uses those assumptions to make the code simpler + + QString errorMessage = result.errorMessage(); + if (!errorMessage.isEmpty()) { + // ignore alreadyOpen + QMessageBox::critical(ICore::mainWindow(), tr("Failed to Open Project"), errorMessage); + } else { + // ignore multiple alreadyOpen + Project *alreadyOpen = result.alreadyOpen().first(); + ProjectTree::highlightProject(alreadyOpen, + tr("

Project already open

")); + } } static QList allProjectManagers() @@ -1677,17 +1705,17 @@ static QList allProjectManagers() return ExtensionSystem::PluginManager::getObjects(); } -static void appendError(QString *errorString, const QString &error) +static void appendError(QString &errorString, const QString &error) { - if (!errorString || error.isEmpty()) + if (error.isEmpty()) return; - if (!errorString->isEmpty()) - errorString->append(QLatin1Char('\n')); - errorString->append(error); + if (!errorString.isEmpty()) + errorString.append(QLatin1Char('\n')); + errorString.append(error); } -QList ProjectExplorerPlugin::openProjects(const QStringList &fileNames, QString *errorString) +ProjectExplorerPlugin::OpenProjectResult ProjectExplorerPlugin::openProjects(const QStringList &fileNames) { if (debug) qDebug() << "ProjectExplorerPlugin - opening projects " << fileNames; @@ -1695,6 +1723,8 @@ QList ProjectExplorerPlugin::openProjects(const QStringList &fileName const QList projectManagers = allProjectManagers(); QList openedPro; + QList alreadyOpen; + QString errorString; foreach (const QString &fileName, fileNames) { QTC_ASSERT(!fileName.isEmpty(), continue); @@ -1705,13 +1735,12 @@ QList ProjectExplorerPlugin::openProjects(const QStringList &fileName bool found = false; foreach (Project *pi, SessionManager::projects()) { if (filePath == pi->projectFilePath().toString()) { + alreadyOpen.append(pi); found = true; break; } } if (found) { - appendError(errorString, tr("Failed opening project \"%1\": Project already open.") - .arg(QDir::toNativeSeparators(fileName))); SessionManager::reportProjectLoadingProgress(); continue; } @@ -1767,7 +1796,7 @@ QList ProjectExplorerPlugin::openProjects(const QStringList &fileName ModeManager::setFocusToCurrentMode(); } - return openedPro; + return OpenProjectResult(openedPro, alreadyOpen, errorString); } void ProjectExplorerPluginPrivate::updateWelcomePage() @@ -2900,10 +2929,10 @@ void ProjectExplorerPluginPrivate::openRecentProject(const QString &fileName) qDebug() << "ProjectExplorerPlugin::openRecentProject()"; if (!fileName.isEmpty()) { - QString errorMessage; - ProjectExplorerPlugin::openProject(fileName, &errorMessage); - if (!errorMessage.isEmpty()) - QMessageBox::critical(ICore::mainWindow(), tr("Failed to open project."), errorMessage); + ProjectExplorerPlugin::OpenProjectResult result + = ProjectExplorerPlugin::openProject(fileName); + if (!result) + ProjectExplorerPlugin::showOpenProjectError(result); } } diff --git a/src/plugins/projectexplorer/projectexplorer.h b/src/plugins/projectexplorer/projectexplorer.h index 61d86e65aaa..9491b73bd65 100644 --- a/src/plugins/projectexplorer/projectexplorer.h +++ b/src/plugins/projectexplorer/projectexplorer.h @@ -72,8 +72,48 @@ public: static ProjectExplorerPlugin *instance(); - static Project *openProject(const QString &fileName, QString *error); - static QList openProjects(const QStringList &fileNames, QString *error); + class OpenProjectResult + { + public: + OpenProjectResult(QList projects, QList alreadyOpen, + const QString &errorMessage) + : m_projects(projects), m_alreadyOpen(alreadyOpen), + m_errorMessage(errorMessage) + {} + + explicit operator bool() const + { + return m_errorMessage.isEmpty() && m_alreadyOpen.isEmpty(); + } + + Project *project() const + { + return m_projects.isEmpty() ? 0 : m_projects.first(); + } + + QList projects() const + { + return m_projects; + } + + QString errorMessage() const + { + return m_errorMessage; + } + + QList alreadyOpen() const + { + return m_alreadyOpen; + } + private: + QList m_projects; + QList m_alreadyOpen; + QString m_errorMessage; + }; + + static OpenProjectResult openProject(const QString &fileName); + static OpenProjectResult openProjects(const QStringList &fileNames); + static void showOpenProjectError(const OpenProjectResult &result); Q_SLOT void openProjectWelcomePage(const QString &fileName); static void unloadProject(Project *project); diff --git a/src/plugins/projectexplorer/projectexplorerconstants.h b/src/plugins/projectexplorer/projectexplorerconstants.h index 0efa68577f8..d96c3759b34 100644 --- a/src/plugins/projectexplorer/projectexplorerconstants.h +++ b/src/plugins/projectexplorer/projectexplorerconstants.h @@ -277,6 +277,9 @@ const char QML_PROFILER_RUN_MODE[]="RunConfiguration.QmlProfilerRunMode"; const char DEBUG_RUN_MODE[]="RunConfiguration.DebugRunMode"; const char DEBUG_RUN_MODE_WITH_BREAK_ON_MAIN[]="RunConfiguration.DebugRunModeWithBreakOnMain"; +// Navigation Widget +const char PROJECTTREE_ID[] = "Projects"; + } // namespace Constants } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/projecttree.cpp b/src/plugins/projectexplorer/projecttree.cpp index 691b616b0eb..ddc858835ea 100644 --- a/src/plugins/projectexplorer/projecttree.cpp +++ b/src/plugins/projectexplorer/projecttree.cpp @@ -46,6 +46,8 @@ #include #include #include +#include +#include #include #include @@ -531,6 +533,19 @@ void ProjectTree::showContextMenu(ProjectTreeWidget *focus, const QPoint &global } } +void ProjectTree::highlightProject(Project *project, const QString &message) +{ + + Core::ModeManager::activateMode(Core::Constants::MODE_EDIT); + Core::NavigationWidget *navigation = Core::NavigationWidget::instance(); + + // Shows and focusses a project tree + QWidget *widget = navigation->activateSubWidget(ProjectExplorer::Constants::PROJECTTREE_ID); + + if (auto *projectTreeWidget = qobject_cast(widget)) + projectTreeWidget->showMessage(project->rootProjectNode(), message); +} + void ProjectTree::hideContextMenu() { m_focusForContextMenu = 0; diff --git a/src/plugins/projectexplorer/projecttree.h b/src/plugins/projectexplorer/projecttree.h index 5f74f157188..7e26f436305 100644 --- a/src/plugins/projectexplorer/projecttree.h +++ b/src/plugins/projectexplorer/projecttree.h @@ -66,6 +66,8 @@ public: static void showContextMenu(Internal::ProjectTreeWidget *focus, const QPoint &globalPos, Node *node); + static void highlightProject(Project *project, const QString &message); + signals: void currentProjectChanged(ProjectExplorer::Project *project); void currentNodeChanged(ProjectExplorer::Node *node, ProjectExplorer::Project *project); diff --git a/src/plugins/projectexplorer/projecttreewidget.cpp b/src/plugins/projectexplorer/projecttreewidget.cpp index 29a51c1a734..5b37b09432e 100644 --- a/src/plugins/projectexplorer/projecttreewidget.cpp +++ b/src/plugins/projectexplorer/projecttreewidget.cpp @@ -48,6 +48,7 @@ #include #include +#include #include #include @@ -480,6 +481,17 @@ void ProjectTreeWidget::sync(Node *node) setCurrentItem(node); } +void ProjectTreeWidget::showMessage(Node *node, const QString &message) +{ + QModelIndex idx = m_model->indexForNode(node); + m_view->setCurrentIndex(idx); + m_view->scrollTo(idx); + + QPoint pos = m_view->mapToGlobal(m_view->visualRect(idx).bottomLeft()); + pos -= Utils::ToolTip::offsetFromPosition(); + Utils::ToolTip::show(pos, message); +} + void ProjectTreeWidget::showContextMenu(const QPoint &pos) { QModelIndex index = m_view->indexAt(pos); @@ -563,7 +575,7 @@ ProjectTreeWidgetFactory::ProjectTreeWidgetFactory() { setDisplayName(tr("Projects")); setPriority(100); - setId("Projects"); + setId(ProjectExplorer::Constants::PROJECTTREE_ID); setActivationSequence(QKeySequence(UseMacShortcuts ? tr("Meta+X") : tr("Alt+X"))); } diff --git a/src/plugins/projectexplorer/projecttreewidget.h b/src/plugins/projectexplorer/projecttreewidget.h index 3ebca208e84..8e093cd8d04 100644 --- a/src/plugins/projectexplorer/projecttreewidget.h +++ b/src/plugins/projectexplorer/projecttreewidget.h @@ -68,6 +68,7 @@ public: QToolButton *toggleSync(); Node *currentNode(); void sync(ProjectExplorer::Node *node); + void showMessage(ProjectExplorer::Node *node, const QString &message); static Node *nodeForFile(const Utils::FileName &fileName); static Node *mostExpandedNode(const QList &nodes); diff --git a/src/plugins/projectexplorer/session.cpp b/src/plugins/projectexplorer/session.cpp index 3d70dc9addc..820e0287df7 100644 --- a/src/plugins/projectexplorer/session.cpp +++ b/src/plugins/projectexplorer/session.cpp @@ -870,11 +870,10 @@ void SessionManagerPrivate::restoreProjects(const QStringList &fileList) // Keep projects that failed to load in the session! m_failedProjects = fileList; if (!fileList.isEmpty()) { - QString errors; - QList projects = ProjectExplorerPlugin::openProjects(fileList, &errors); - if (!errors.isEmpty()) - QMessageBox::critical(ICore::mainWindow(), SessionManager::tr("Failed to open project"), errors); - foreach (Project *p, projects) + ProjectExplorerPlugin::OpenProjectResult result = ProjectExplorerPlugin::openProjects(fileList); + if (!result) + ProjectExplorerPlugin::showOpenProjectError(result); + foreach (Project *p, result.projects()) m_failedProjects.removeAll(p->projectFilePath().toString()); } } diff --git a/src/plugins/qtsupport/gettingstartedwelcomepage.cpp b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp index 4268c645ccc..eedda4cea5b 100644 --- a/src/plugins/qtsupport/gettingstartedwelcomepage.cpp +++ b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp @@ -412,18 +412,19 @@ void ExamplesWelcomePage::openProject(const QString &projectFile, } // don't try to load help and files if loading the help request is being cancelled - QString errorMessage; if (proFile.isEmpty()) return; - if (ProjectExplorer::ProjectExplorerPlugin::instance()->openProject(proFile, &errorMessage)) { + ProjectExplorer::ProjectExplorerPlugin::OpenProjectResult result = + ProjectExplorer::ProjectExplorerPlugin::instance()->openProject(proFile); + if (result) { Core::ICore::openFiles(filesToOpen); Core::ModeManager::activateMode(Core::Constants::MODE_EDIT); if (help.isValid()) openHelpInExtraWindow(help.toString()); Core::ModeManager::activateMode(ProjectExplorer::Constants::MODE_SESSION); + } else { + ProjectExplorer::ProjectExplorerPlugin::showOpenProjectError(result); } - if (!errorMessage.isEmpty()) - QMessageBox::critical(Core::ICore::mainWindow(), tr("Failed to Open Project"), errorMessage); } ExamplesListModel *ExamplesWelcomePage::examplesModel() const