diff --git a/shell/openprojectdialog.h b/shell/openprojectdialog.h --- a/shell/openprojectdialog.h +++ b/shell/openprojectdialog.h @@ -17,6 +17,7 @@ #include class KPageWidgetItem; +class QFileDialog; namespace KIO { class Job; @@ -47,6 +48,8 @@ QString projectName() const; QString projectManager() const; + int exec() override; + private slots: void validateSourcePage( bool ); void validateOpenUrl( const QUrl& ); @@ -61,10 +64,13 @@ QUrl m_selected; QString m_projectName; QString m_projectManager; + // used to select files when we aren't in KDE + QFileDialog* nativeDialog; KPageWidgetItem* sourcePage; KPageWidgetItem* openPage; KPageWidgetItem* projectInfoPage; QStringList m_fileList; + QMap m_projectFilters; KDevelop::OpenProjectPage* openPageWidget; KDevelop::ProjectSourcePage* sourcePageWidget; diff --git a/shell/openprojectdialog.cpp b/shell/openprojectdialog.cpp --- a/shell/openprojectdialog.cpp +++ b/shell/openprojectdialog.cpp @@ -13,6 +13,7 @@ #include "projectinfopage.h" #include +#include #include #include @@ -22,11 +23,50 @@ #include "core.h" #include "uicontroller.h" +#include "plugincontroller.h" #include "mainwindow.h" #include "shellextension.h" #include "projectsourcepage.h" #include +namespace +{ + struct URLInfo + { + bool isValid; + bool isDir; + QString extension; + }; + + URLInfo getUrlInfo(const QUrl& url) + { + URLInfo ret; + ret.isValid = false; + + if (url.isLocalFile()) + { + QFileInfo info(url.toLocalFile()); + ret.isValid = info.exists(); + if (ret.isValid) { + ret.isDir = info.isDir(); + ret.extension = info.suffix(); + } + } + else if (url.isValid()) + { + KIO::StatJob* statJob = KIO::stat(url, KIO::HideProgressInfo); + KJobWidgets::setWindow(statJob, KDevelop::Core::self()->uiControllerInternal()->defaultMainWindow()); + ret.isValid = statJob->exec(); // TODO: do this asynchronously so that the user isn't blocked while typing every letter of the hostname in sftp://hostname + if (ret.isValid) { + KIO::UDSEntry entry = statJob->statResult(); + ret.isDir = entry.isDir(); + ret.extension = QFileInfo(entry.stringValue(KIO::UDSEntry::UDS_NAME)).suffix(); + } + } + return ret; + } +} + namespace KDevelop { @@ -38,6 +78,30 @@ { resize(QSize(700, 500)); + QStringList filters, allEntry; + QString filterFormat = qEnvironmentVariableIsSet("KDE_FULL_SESSION") + ? QStringLiteral("%1|%2 (%1)") + : QStringLiteral("%2 (%1)"); + allEntry << "*." + ShellExtension::getInstance()->projectFileExtension(); + filters << filterFormat.arg("*." + ShellExtension::getInstance()->projectFileExtension(), ShellExtension::getInstance()->projectFileDescription()); + QVector plugins = ICore::self()->pluginController()->queryExtensionPlugins(QStringLiteral("org.kdevelop.IProjectFileManager")); + foreach(const KPluginMetaData& info, plugins) + { + QStringList filter = KPluginMetaData::readStringList(info.rawData(), QStringLiteral("X-KDevelop-ProjectFilesFilter")); + QString desc = info.value(QStringLiteral("X-KDevelop-ProjectFilesFilterDescription")); + + if (!filter.isEmpty() && !desc.isEmpty()) { + m_projectFilters.insert(info.name(), filter); + allEntry += filter; + filters << filterFormat.arg(filter.join(QStringLiteral(" ")), desc); + } + } + + if (qEnvironmentVariableIsSet("KDE_FULL_SESSION")) + filters.prepend(i18n("%1|All Project Files (%1)", allEntry.join(QStringLiteral(" ")))); + else + filters.prepend(i18n("All Project Files (%1)", allEntry.join(QStringLiteral(";;")))); + QUrl start = startUrl.isValid() ? startUrl : Core::self()->projectController()->projectsBaseDirectory(); start = start.adjusted(QUrl::NormalizePathSegments); KPageWidgetItem* currentPage = 0; @@ -49,21 +113,33 @@ currentPage = sourcePage; } - openPageWidget = new OpenProjectPage( start, this ); - connect( openPageWidget, &OpenProjectPage::urlSelected, this, &OpenProjectDialog::validateOpenUrl ); - connect( openPageWidget, &OpenProjectPage::accepted, this, &OpenProjectDialog::openPageAccepted ); - openPage = addPage( openPageWidget, i18n("Select a build system setup file, existing KDevelop project, " - "or any folder to open as a project") ); - - if( !fetch ) { - currentPage = openPage; + if (qEnvironmentVariableIsSet("KDE_FULL_SESSION")) + { + openPageWidget = new OpenProjectPage( start, filters, this ); + connect( openPageWidget, &OpenProjectPage::urlSelected, this, &OpenProjectDialog::validateOpenUrl ); + connect( openPageWidget, &OpenProjectPage::accepted, this, &OpenProjectDialog::openPageAccepted ); + openPage = addPage( openPageWidget, i18n("Select a build system setup file, existing KDevelop project, " + "or any folder to open as a project") ); + + if (!currentPage) { + currentPage = openPage; + } + } else { + nativeDialog = new QFileDialog(this, i18n("Open Project")); + nativeDialog->setDirectoryUrl(start); + nativeDialog->setFileMode(QFileDialog::ExistingFile); + nativeDialog->setNameFilters(filters); } ProjectInfoPage* page = new ProjectInfoPage( this ); connect( page, &ProjectInfoPage::projectNameChanged, this, &OpenProjectDialog::validateProjectName ); connect( page, &ProjectInfoPage::projectManagerChanged, this, &OpenProjectDialog::validateProjectManager ); projectInfoPage = addPage( page, i18n("Project Information") ); + if (!currentPage) { + currentPage = projectInfoPage; + } + setValid( sourcePage, false ); setValid( openPage, false ); setValid( projectInfoPage, false); @@ -73,111 +149,112 @@ setWindowTitle(i18n("Open Project")); } +int OpenProjectDialog::exec() +{ + if (!qEnvironmentVariableIsSet("KDE_FULL_SESSION")) + { + bool ok = false; + while (!ok) + { + if (nativeDialog->exec()) + { + QUrl selectedUrl = nativeDialog->selectedUrls()[0]; + if (getUrlInfo(selectedUrl).isValid) + { + // validate directory first to populate m_projectName and m_projectManager + validateOpenUrl(selectedUrl.adjusted(QUrl::RemoveFilename)); + validateOpenUrl(selectedUrl); + ok = true; + } + } else { + reject(); + return QDialog::Rejected; + } + } + } + return KAssistantDialog::exec(); +} + void OpenProjectDialog::validateSourcePage(bool valid) { setValid(sourcePage, valid); openPageWidget->setUrl(sourcePageWidget->workingDir()); } void OpenProjectDialog::validateOpenUrl( const QUrl& url_ ) { - bool isDir = false; - QString extension; - bool isValid = false; + URLInfo urlInfo = getUrlInfo(url_); const QUrl url = url_.adjusted(QUrl::StripTrailingSlash); - if( url.isLocalFile() ) - { - QFileInfo info( url.toLocalFile() ); - isValid = info.exists(); - if ( isValid ) { - isDir = info.isDir(); - extension = info.suffix(); - } - } else if ( url.isValid() ) - { - KIO::StatJob* statJob = KIO::stat( url, KIO::HideProgressInfo ); - KJobWidgets::setWindow(statJob, Core::self()->uiControllerInternal()->defaultMainWindow() ); - isValid = statJob->exec(); // TODO: do this asynchronously so that the user isn't blocked while typing every letter of the hostname in sftp://hostname - if ( isValid ) { - KIO::UDSEntry entry = statJob->statResult(); - isDir = entry.isDir(); - extension = QFileInfo( entry.stringValue( KIO::UDSEntry::UDS_NAME ) ).suffix(); + // openPage is used only in KDE + if (qEnvironmentVariableIsSet("KDE_FULL_SESSION")) + if ( urlInfo.isValid ) { + // reset header + openPage->setHeader(i18n("Open \"%1\" as project", url.fileName())); + } else { + // report error + KColorScheme scheme(palette().currentColorGroup()); + const QString errorMsg = i18n("Selected URL is invalid"); + openPage->setHeader(QStringLiteral("%2") + .arg(scheme.foreground(KColorScheme::NegativeText).color().name(), errorMsg) + ); + setAppropriate( projectInfoPage, false ); + setAppropriate( openPage, true ); + setValid( openPage, false ); + return; } - } - - if ( isValid ) { - // reset header - openPage->setHeader(i18n("Open \"%1\" as project", url.fileName())); - } else { - // report error - KColorScheme scheme(palette().currentColorGroup()); - const QString errorMsg = i18n("Selected URL is invalid"); - openPage->setHeader(QStringLiteral("%2") - .arg(scheme.foreground(KColorScheme::NegativeText).color().name(), errorMsg) - ); - setAppropriate( projectInfoPage, false ); - setAppropriate( openPage, true ); - setValid( openPage, false ); - return; - } m_selected = url; - if( isDir || extension != ShellExtension::getInstance()->projectFileExtension() ) + if( urlInfo.isDir || urlInfo.extension != ShellExtension::getInstance()->projectFileExtension() ) { setAppropriate( projectInfoPage, true ); m_url = url; - if( !isDir ) { + if( !urlInfo.isDir ) { m_url = m_url.adjusted(QUrl::StripTrailingSlash | QUrl::RemoveFilename); } ProjectInfoPage* page = qobject_cast( projectInfoPage->widget() ); if( page ) { page->setProjectName( m_url.fileName() ); - OpenProjectPage* page2 = qobject_cast( openPage->widget() ); - if( page2 ) + // Default manager + page->setProjectManager( QStringLiteral("Generic Project Manager") ); + // clear the filelist + m_fileList.clear(); + + if( urlInfo.isDir ) { + // If a dir was selected fetch all files in it + KIO::ListJob* job = KIO::listDir( m_url ); + connect( job, &KIO::ListJob::entries, + this, &OpenProjectDialog::storeFileList); + KJobWidgets::setWindow(job, Core::self()->uiController()->activeMainWindow()); + job->exec(); + } else { + // Else we'lll just take the given file + m_fileList << url.fileName(); + } + // Now find a manager for the file(s) in our filelist. + bool managerFound = false; + foreach( const QString& manager, m_projectFilters.keys() ) { - // Default manager - page->setProjectManager( QStringLiteral("Generic Project Manager") ); - // clear the filelist - m_fileList.clear(); - - if( isDir ) { - // If a dir was selected fetch all files in it - KIO::ListJob* job = KIO::listDir( m_url ); - connect( job, &KIO::ListJob::entries, - this, &OpenProjectDialog::storeFileList); - KJobWidgets::setWindow(job, Core::self()->uiController()->activeMainWindow()); - job->exec(); - } else { - // Else we'lll just take the given file - m_fileList << url.fileName(); - } - // Now find a manager for the file(s) in our filelist. - bool managerFound = false; - foreach( const QString& manager, page2->projectFilters().keys() ) + foreach( const QString& filterexp, m_projectFilters.value(manager) ) { - foreach( const QString& filterexp, page2->projectFilters().value(manager) ) + if( !m_fileList.filter( QRegExp( filterexp, Qt::CaseSensitive, QRegExp::Wildcard ) ).isEmpty() ) { - if( !m_fileList.filter( QRegExp( filterexp, Qt::CaseSensitive, QRegExp::Wildcard ) ).isEmpty() ) - { - managerFound = true; - break; - } - } - if( managerFound ) - { - page->setProjectManager( manager ); + managerFound = true; break; } } + if( managerFound ) + { + page->setProjectManager( manager ); + break; + } } } m_url.setPath( m_url.path() + '/' + m_url.fileName() + '.' + ShellExtension::getInstance()->projectFileExtension() ); - } else - { + } else { setAppropriate( projectInfoPage, false ); m_url = url; } diff --git a/shell/openprojectpage.h b/shell/openprojectpage.h --- a/shell/openprojectpage.h +++ b/shell/openprojectpage.h @@ -25,8 +25,8 @@ Q_OBJECT public: - explicit OpenProjectPage( const QUrl& startUrl, QWidget* parent = nullptr ); - QMap projectFilters() const; + explicit OpenProjectPage( const QUrl& startUrl, const QStringList& filters, + QWidget* parent = nullptr ); void setUrl(const QUrl& url); signals: @@ -45,7 +45,6 @@ private: QUrl getAbsoluteUrl(const QString&) const; KFileWidget* fileWidget; - QMap m_projectFilters; }; } diff --git a/shell/openprojectpage.cpp b/shell/openprojectpage.cpp --- a/shell/openprojectpage.cpp +++ b/shell/openprojectpage.cpp @@ -20,37 +20,18 @@ #include "shellextension.h" #include "core.h" -#include "plugincontroller.h" namespace KDevelop { -OpenProjectPage::OpenProjectPage( const QUrl& startUrl, QWidget* parent ) +OpenProjectPage::OpenProjectPage( const QUrl& startUrl, const QStringList& filters, + QWidget* parent ) : QWidget( parent ) { QHBoxLayout* layout = new QHBoxLayout( this ); fileWidget = new KFileWidget( startUrl, this); - QStringList filters; - QStringList allEntry; - allEntry << "*."+ShellExtension::getInstance()->projectFileExtension(); - filters << QStringLiteral( "%1|%2 (%1)").arg("*."+ShellExtension::getInstance()->projectFileExtension(), ShellExtension::getInstance()->projectFileDescription()); - QVector plugins = ICore::self()->pluginController()->queryExtensionPlugins( QStringLiteral( "org.kdevelop.IProjectFileManager" ) ); - foreach(const KPluginMetaData& info, plugins) - { - QStringList filter = KPluginMetaData::readStringList(info.rawData(), QStringLiteral("X-KDevelop-ProjectFilesFilter")); - QString desc = info.value(QStringLiteral("X-KDevelop-ProjectFilesFilterDescription")); - QString filterline; - if(!filter.isEmpty() && !desc.isEmpty()) { - m_projectFilters.insert(info.name(), filter); - allEntry += filter; - filters << QStringLiteral("%1|%2 (%1)").arg(filter.join(QStringLiteral(" ")), desc); - } - } - - filters.prepend( i18n( "%1|All Project Files (%1)", allEntry.join( QStringLiteral(" ") ) ) ); - fileWidget->setFilter( filters.join(QStringLiteral("\n")) ); fileWidget->setMode( KFile::Modes( KFile::File | KFile::Directory | KFile::ExistingOnly ) ); @@ -120,10 +101,5 @@ emit urlSelected( getAbsoluteUrl( file ) ); } -QMap OpenProjectPage::projectFilters() const -{ - return m_projectFilters; -} - }