Changeset View
Changeset View
Standalone View
Standalone View
shell/openprojectdialog.cpp
1 | /*************************************************************************** | 1 | /*************************************************************************** | ||
---|---|---|---|---|---|
2 | * Copyright (C) 2008 by Andreas Pakulat <apaku@gmx.de * | 2 | * Copyright (C) 2008 by Andreas Pakulat <apaku@gmx.de * | ||
3 | * * | 3 | * * | ||
4 | * This program is free software; you can redistribute it and/or modify * | 4 | * This program is free software; you can redistribute it and/or modify * | ||
5 | * it under the terms of the GNU General Public License as published by * | 5 | * it under the terms of the GNU General Public License as published by * | ||
6 | * the Free Software Foundation; either version 2 of the License, or * | 6 | * the Free Software Foundation; either version 2 of the License, or * | ||
7 | * (at your option) any later version. * | 7 | * (at your option) any later version. * | ||
8 | * * | 8 | * * | ||
9 | ***************************************************************************/ | 9 | ***************************************************************************/ | ||
10 | 10 | | |||
11 | #include "openprojectdialog.h" | 11 | #include "openprojectdialog.h" | ||
12 | #include "openprojectpage.h" | 12 | #include "openprojectpage.h" | ||
13 | #include "projectinfopage.h" | 13 | #include "projectinfopage.h" | ||
14 | 14 | | |||
15 | #include <QFileInfo> | 15 | #include <QFileInfo> | ||
16 | #include <QFileDialog> | ||||
16 | 17 | | |||
17 | #include <KColorScheme> | 18 | #include <KColorScheme> | ||
18 | #include <KIO/StatJob> | 19 | #include <KIO/StatJob> | ||
19 | #include <KIO/ListJob> | 20 | #include <KIO/ListJob> | ||
20 | #include <KJobWidgets> | 21 | #include <KJobWidgets> | ||
21 | #include <KLocalizedString> | 22 | #include <KLocalizedString> | ||
22 | 23 | | |||
23 | #include "core.h" | 24 | #include "core.h" | ||
24 | #include "uicontroller.h" | 25 | #include "uicontroller.h" | ||
26 | #include "plugincontroller.h" | ||||
25 | #include "mainwindow.h" | 27 | #include "mainwindow.h" | ||
26 | #include "shellextension.h" | 28 | #include "shellextension.h" | ||
27 | #include "projectsourcepage.h" | 29 | #include "projectsourcepage.h" | ||
28 | #include <interfaces/iprojectcontroller.h> | 30 | #include <interfaces/iprojectcontroller.h> | ||
29 | 31 | | |||
32 | namespace | ||||
33 | { | ||||
kfunk: Nitpick: Don't indent inside namespaces. Aids readability in case of multi-page-long namespaces. | |||||
34 | struct URLInfo | ||||
35 | { | ||||
36 | bool isValid; | ||||
37 | bool isDir; | ||||
38 | QString extension; | ||||
39 | }; | ||||
40 | | ||||
41 | URLInfo getUrlInfo(const QUrl& url) | ||||
42 | { | ||||
43 | URLInfo ret; | ||||
44 | ret.isValid = false; | ||||
45 | | ||||
46 | if (url.isLocalFile()) { | ||||
47 | QFileInfo info(url.toLocalFile()); | ||||
48 | ret.isValid = info.exists(); | ||||
49 | if (ret.isValid) { | ||||
50 | ret.isDir = info.isDir(); | ||||
51 | ret.extension = info.suffix(); | ||||
52 | } | ||||
53 | } else if (url.isValid()) { | ||||
54 | KIO::StatJob* statJob = KIO::stat(url, KIO::HideProgressInfo); | ||||
55 | KJobWidgets::setWindow(statJob, KDevelop::Core::self()->uiControllerInternal()->defaultMainWindow()); | ||||
56 | 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 | ||||
57 | if (ret.isValid) { | ||||
58 | KIO::UDSEntry entry = statJob->statResult(); | ||||
59 | ret.isDir = entry.isDir(); | ||||
60 | ret.extension = QFileInfo(entry.stringValue(KIO::UDSEntry::UDS_NAME)).suffix(); | ||||
61 | } | ||||
62 | } | ||||
63 | return ret; | ||||
64 | } | ||||
65 | } | ||||
66 | | ||||
30 | namespace KDevelop | 67 | namespace KDevelop | ||
31 | { | 68 | { | ||
32 | 69 | | |||
33 | OpenProjectDialog::OpenProjectDialog( bool fetch, const QUrl& startUrl, QWidget* parent ) | 70 | OpenProjectDialog::OpenProjectDialog( bool fetch, const QUrl& startUrl, QWidget* parent ) | ||
34 | : KAssistantDialog( parent ) | 71 | : KAssistantDialog( parent ) | ||
35 | , sourcePage(nullptr) | 72 | , sourcePage(nullptr) | ||
36 | , openPage(nullptr) | 73 | , openPage(nullptr) | ||
37 | , projectInfoPage(nullptr) | 74 | , projectInfoPage(nullptr) | ||
38 | { | 75 | { | ||
39 | resize(QSize(700, 500)); | 76 | resize(QSize(700, 500)); | ||
40 | 77 | | |||
78 | const bool useKdeFileDialog = qEnvironmentVariableIsSet("KDE_FULL_SESSION"); | ||||
Just check KDE_FULL_SESSION once. E.g.: kfunk: Just check KDE_FULL_SESSION once.
E.g.:
`const bool useNativeFileDialog =… | |||||
79 | QStringList filters, allEntry; | ||||
80 | QString filterFormat = useKdeFileDialog | ||||
81 | ? QStringLiteral("%1|%2 (%1)") | ||||
82 | : QStringLiteral("%2 (%1)"); | ||||
83 | allEntry << "*." + ShellExtension::getInstance()->projectFileExtension(); | ||||
84 | filters << filterFormat.arg("*." + ShellExtension::getInstance()->projectFileExtension(), ShellExtension::getInstance()->projectFileDescription()); | ||||
85 | QVector<KPluginMetaData> plugins = ICore::self()->pluginController()->queryExtensionPlugins(QStringLiteral("org.kdevelop.IProjectFileManager")); | ||||
86 | foreach(const KPluginMetaData& info, plugins) | ||||
87 | { | ||||
88 | QStringList filter = KPluginMetaData::readStringList(info.rawData(), QStringLiteral("X-KDevelop-ProjectFilesFilter")); | ||||
89 | QString desc = info.value(QStringLiteral("X-KDevelop-ProjectFilesFilterDescription")); | ||||
90 | | ||||
91 | if (!filter.isEmpty() && !desc.isEmpty()) { | ||||
92 | m_projectFilters.insert(info.name(), filter); | ||||
93 | allEntry += filter; | ||||
94 | filters << filterFormat.arg(filter.join(QStringLiteral(" ")), desc); | ||||
95 | } | ||||
96 | } | ||||
97 | | ||||
98 | if (useKdeFileDialog) | ||||
99 | filters.prepend(i18n("%1|All Project Files (%1)", allEntry.join(QStringLiteral(" ")))); | ||||
100 | else | ||||
101 | filters.prepend(i18n("All Project Files (%1)", allEntry.join(QStringLiteral(" ")))); | ||||
Are you sure you need ";;" here? Not " "? kfunk: Are you sure you need ";;" here? Not " "?
http://doc.qt.io/qt-5/qfiledialog.html#setNameFilters | |||||
102 | | ||||
41 | QUrl start = startUrl.isValid() ? startUrl : Core::self()->projectController()->projectsBaseDirectory(); | 103 | QUrl start = startUrl.isValid() ? startUrl : Core::self()->projectController()->projectsBaseDirectory(); | ||
42 | start = start.adjusted(QUrl::NormalizePathSegments); | 104 | start = start.adjusted(QUrl::NormalizePathSegments); | ||
43 | KPageWidgetItem* currentPage = 0; | 105 | KPageWidgetItem* currentPage = 0; | ||
44 | 106 | | |||
45 | if( fetch ) { | 107 | if( fetch ) { | ||
46 | sourcePageWidget = new ProjectSourcePage( start, this ); | 108 | sourcePageWidget = new ProjectSourcePage( start, this ); | ||
47 | connect( sourcePageWidget, &ProjectSourcePage::isCorrect, this, &OpenProjectDialog::validateSourcePage ); | 109 | connect( sourcePageWidget, &ProjectSourcePage::isCorrect, this, &OpenProjectDialog::validateSourcePage ); | ||
48 | sourcePage = addPage( sourcePageWidget, i18n("Select Source") ); | 110 | sourcePage = addPage( sourcePageWidget, i18n("Select Source") ); | ||
49 | currentPage = sourcePage; | 111 | currentPage = sourcePage; | ||
50 | } | 112 | } | ||
51 | 113 | | |||
52 | openPageWidget = new OpenProjectPage( start, this ); | 114 | if (useKdeFileDialog) { | ||
115 | openPageWidget = new OpenProjectPage( start, filters, this ); | ||||
53 | connect( openPageWidget, &OpenProjectPage::urlSelected, this, &OpenProjectDialog::validateOpenUrl ); | 116 | connect( openPageWidget, &OpenProjectPage::urlSelected, this, &OpenProjectDialog::validateOpenUrl ); | ||
54 | connect( openPageWidget, &OpenProjectPage::accepted, this, &OpenProjectDialog::openPageAccepted ); | 117 | connect( openPageWidget, &OpenProjectPage::accepted, this, &OpenProjectDialog::openPageAccepted ); | ||
55 | openPage = addPage( openPageWidget, i18n("Select a build system setup file, existing KDevelop project, " | 118 | openPage = addPage( openPageWidget, i18n("Select a build system setup file, existing KDevelop project, " | ||
56 | "or any folder to open as a project") ); | 119 | "or any folder to open as a project") ); | ||
57 | 120 | | |||
58 | if( !fetch ) { | 121 | if (!currentPage) { | ||
59 | currentPage = openPage; | 122 | currentPage = openPage; | ||
60 | } | 123 | } | ||
124 | } else { | ||||
125 | nativeDialog = new QFileDialog(this, i18n("Open Project")); | ||||
126 | nativeDialog->setDirectoryUrl(start); | ||||
127 | nativeDialog->setFileMode(QFileDialog::ExistingFile); | ||||
128 | nativeDialog->setNameFilters(filters); | ||||
129 | } | ||||
61 | 130 | | |||
62 | ProjectInfoPage* page = new ProjectInfoPage( this ); | 131 | ProjectInfoPage* page = new ProjectInfoPage( this ); | ||
63 | connect( page, &ProjectInfoPage::projectNameChanged, this, &OpenProjectDialog::validateProjectName ); | 132 | connect( page, &ProjectInfoPage::projectNameChanged, this, &OpenProjectDialog::validateProjectName ); | ||
64 | connect( page, &ProjectInfoPage::projectManagerChanged, this, &OpenProjectDialog::validateProjectManager ); | 133 | connect( page, &ProjectInfoPage::projectManagerChanged, this, &OpenProjectDialog::validateProjectManager ); | ||
65 | projectInfoPage = addPage( page, i18n("Project Information") ); | 134 | projectInfoPage = addPage( page, i18n("Project Information") ); | ||
66 | 135 | | |||
136 | if (!currentPage) { | ||||
137 | currentPage = projectInfoPage; | ||||
138 | } | ||||
139 | | ||||
67 | setValid( sourcePage, false ); | 140 | setValid( sourcePage, false ); | ||
68 | setValid( openPage, false ); | 141 | setValid( openPage, false ); | ||
69 | setValid( projectInfoPage, false); | 142 | setValid( projectInfoPage, false); | ||
70 | setAppropriate( projectInfoPage, false ); | 143 | setAppropriate( projectInfoPage, false ); | ||
71 | 144 | | |||
72 | setCurrentPage( currentPage ); | 145 | setCurrentPage( currentPage ); | ||
73 | setWindowTitle(i18n("Open Project")); | 146 | setWindowTitle(i18n("Open Project")); | ||
74 | } | 147 | } | ||
75 | 148 | | |||
149 | bool OpenProjectDialog::execNativeDialog() | ||||
150 | { | ||||
151 | while (true) | ||||
kfunk: `if (nativeDialog) ...` | |||||
kfunk: `if (nativeDialog)` -> then you also don't need to make `useKdeFileDialog` global. | |||||
152 | { | ||||
153 | if (nativeDialog->exec()) { | ||||
Should probably factor out this block into a separate function for increased readability. kfunk: Should probably factor out this block into a separate function for increased readability. | |||||
arrowd: Uh, sorry, didn't get that. You mean factoring whole while loop? | |||||
Yes, so this reads: if (nativeDialog) { if (!execNativeDialog()) { reject(); return QDialog::Rejected; } } ... kfunk: Yes, so this reads:
```
if (nativeDialog) {
if (!execNativeDialog()) {
reject()… | |||||
154 | QUrl selectedUrl = nativeDialog->selectedUrls()[0]; | ||||
155 | if (getUrlInfo(selectedUrl).isValid) { | ||||
156 | // validate directory first to populate m_projectName and m_projectManager | ||||
157 | validateOpenUrl(selectedUrl.adjusted(QUrl::RemoveFilename)); | ||||
158 | validateOpenUrl(selectedUrl); | ||||
159 | return true; | ||||
160 | } | ||||
161 | } | ||||
162 | else { | ||||
kfunk: Style:
```
} else {
return false;
}
``` | |||||
163 | return false; | ||||
164 | } | ||||
165 | } | ||||
166 | } | ||||
167 | | ||||
168 | int OpenProjectDialog::exec() | ||||
169 | { | ||||
170 | if (nativeDialog && !execNativeDialog()) { | ||||
171 | reject(); | ||||
172 | return QDialog::Rejected; | ||||
173 | } | ||||
174 | return KAssistantDialog::exec(); | ||||
175 | } | ||||
176 | | ||||
76 | void OpenProjectDialog::validateSourcePage(bool valid) | 177 | void OpenProjectDialog::validateSourcePage(bool valid) | ||
77 | { | 178 | { | ||
78 | setValid(sourcePage, valid); | 179 | setValid(sourcePage, valid); | ||
79 | openPageWidget->setUrl(sourcePageWidget->workingDir()); | 180 | openPageWidget->setUrl(sourcePageWidget->workingDir()); | ||
80 | } | 181 | } | ||
81 | 182 | | |||
82 | void OpenProjectDialog::validateOpenUrl( const QUrl& url_ ) | 183 | void OpenProjectDialog::validateOpenUrl( const QUrl& url_ ) | ||
83 | { | 184 | { | ||
84 | bool isDir = false; | 185 | URLInfo urlInfo = getUrlInfo(url_); | ||
85 | QString extension; | | |||
86 | bool isValid = false; | | |||
87 | 186 | | |||
88 | const QUrl url = url_.adjusted(QUrl::StripTrailingSlash); | 187 | const QUrl url = url_.adjusted(QUrl::StripTrailingSlash); | ||
89 | 188 | | |||
90 | if( url.isLocalFile() ) | 189 | // openPage is used only in KDE | ||
91 | { | 190 | if (openPage) { | ||
92 | QFileInfo info( url.toLocalFile() ); | 191 | if ( urlInfo.isValid ) { | ||
93 | isValid = info.exists(); | | |||
94 | if ( isValid ) { | | |||
95 | isDir = info.isDir(); | | |||
96 | extension = info.suffix(); | | |||
97 | } | | |||
98 | } else if ( url.isValid() ) | | |||
99 | { | | |||
100 | KIO::StatJob* statJob = KIO::stat( url, KIO::HideProgressInfo ); | | |||
101 | KJobWidgets::setWindow(statJob, Core::self()->uiControllerInternal()->defaultMainWindow() ); | | |||
102 | isValid = statJob->exec(); // TODO: do this asynchronously so that the user isn't blocked while typing every letter of the hostname in sftp://hostname | | |||
103 | if ( isValid ) { | | |||
104 | KIO::UDSEntry entry = statJob->statResult(); | | |||
105 | isDir = entry.isDir(); | | |||
106 | extension = QFileInfo( entry.stringValue( KIO::UDSEntry::UDS_NAME ) ).suffix(); | | |||
107 | } | | |||
108 | } | | |||
109 | | ||||
110 | if ( isValid ) { | | |||
111 | // reset header | 192 | // reset header | ||
112 | openPage->setHeader(i18n("Open \"%1\" as project", url.fileName())); | 193 | openPage->setHeader(i18n("Open \"%1\" as project", url.fileName())); | ||
113 | } else { | 194 | } else { | ||
114 | // report error | 195 | // report error | ||
115 | KColorScheme scheme(palette().currentColorGroup()); | 196 | KColorScheme scheme(palette().currentColorGroup()); | ||
116 | const QString errorMsg = i18n("Selected URL is invalid"); | 197 | const QString errorMsg = i18n("Selected URL is invalid"); | ||
117 | openPage->setHeader(QStringLiteral("<font color='%1'>%2</font>") | 198 | openPage->setHeader(QStringLiteral("<font color='%1'>%2</font>") | ||
118 | .arg(scheme.foreground(KColorScheme::NegativeText).color().name(), errorMsg) | 199 | .arg(scheme.foreground(KColorScheme::NegativeText).color().name(), errorMsg) | ||
119 | ); | 200 | ); | ||
120 | setAppropriate( projectInfoPage, false ); | 201 | setAppropriate( projectInfoPage, false ); | ||
121 | setAppropriate( openPage, true ); | 202 | setAppropriate( openPage, true ); | ||
122 | setValid( openPage, false ); | 203 | setValid( openPage, false ); | ||
123 | return; | 204 | return; | ||
124 | } | 205 | } | ||
206 | } | ||||
kfunk: `if (openPage)` | |||||
125 | 207 | | |||
126 | m_selected = url; | 208 | m_selected = url; | ||
127 | 209 | | |||
128 | if( isDir || extension != ShellExtension::getInstance()->projectFileExtension() ) | 210 | if( urlInfo.isDir || urlInfo.extension != ShellExtension::getInstance()->projectFileExtension() ) | ||
129 | { | 211 | { | ||
130 | setAppropriate( projectInfoPage, true ); | 212 | setAppropriate( projectInfoPage, true ); | ||
131 | m_url = url; | 213 | m_url = url; | ||
132 | if( !isDir ) { | 214 | if( !urlInfo.isDir ) { | ||
133 | m_url = m_url.adjusted(QUrl::StripTrailingSlash | QUrl::RemoveFilename); | 215 | m_url = m_url.adjusted(QUrl::StripTrailingSlash | QUrl::RemoveFilename); | ||
134 | } | 216 | } | ||
135 | ProjectInfoPage* page = qobject_cast<ProjectInfoPage*>( projectInfoPage->widget() ); | 217 | ProjectInfoPage* page = qobject_cast<ProjectInfoPage*>( projectInfoPage->widget() ); | ||
136 | if( page ) | 218 | if( page ) | ||
137 | { | 219 | { | ||
138 | page->setProjectName( m_url.fileName() ); | 220 | page->setProjectName( m_url.fileName() ); | ||
139 | OpenProjectPage* page2 = qobject_cast<OpenProjectPage*>( openPage->widget() ); | | |||
140 | if( page2 ) | | |||
141 | { | | |||
142 | // Default manager | 221 | // Default manager | ||
143 | page->setProjectManager( QStringLiteral("Generic Project Manager") ); | 222 | page->setProjectManager( QStringLiteral("Generic Project Manager") ); | ||
144 | // clear the filelist | 223 | // clear the filelist | ||
145 | m_fileList.clear(); | 224 | m_fileList.clear(); | ||
146 | 225 | | |||
147 | if( isDir ) { | 226 | if( urlInfo.isDir ) { | ||
148 | // If a dir was selected fetch all files in it | 227 | // If a dir was selected fetch all files in it | ||
149 | KIO::ListJob* job = KIO::listDir( m_url ); | 228 | KIO::ListJob* job = KIO::listDir( m_url ); | ||
150 | connect( job, &KIO::ListJob::entries, | 229 | connect( job, &KIO::ListJob::entries, | ||
151 | this, &OpenProjectDialog::storeFileList); | 230 | this, &OpenProjectDialog::storeFileList); | ||
152 | KJobWidgets::setWindow(job, Core::self()->uiController()->activeMainWindow()); | 231 | KJobWidgets::setWindow(job, Core::self()->uiController()->activeMainWindow()); | ||
153 | job->exec(); | 232 | job->exec(); | ||
154 | } else { | 233 | } else { | ||
155 | // Else we'lll just take the given file | 234 | // Else we'lll just take the given file | ||
156 | m_fileList << url.fileName(); | 235 | m_fileList << url.fileName(); | ||
157 | } | 236 | } | ||
158 | // Now find a manager for the file(s) in our filelist. | 237 | // Now find a manager for the file(s) in our filelist. | ||
159 | bool managerFound = false; | 238 | bool managerFound = false; | ||
160 | foreach( const QString& manager, page2->projectFilters().keys() ) | 239 | foreach( const QString& manager, m_projectFilters.keys() ) | ||
161 | { | 240 | { | ||
162 | foreach( const QString& filterexp, page2->projectFilters().value(manager) ) | 241 | foreach( const QString& filterexp, m_projectFilters.value(manager) ) | ||
163 | { | 242 | { | ||
164 | if( !m_fileList.filter( QRegExp( filterexp, Qt::CaseSensitive, QRegExp::Wildcard ) ).isEmpty() ) | 243 | if( !m_fileList.filter( QRegExp( filterexp, Qt::CaseSensitive, QRegExp::Wildcard ) ).isEmpty() ) | ||
165 | { | 244 | { | ||
166 | managerFound = true; | 245 | managerFound = true; | ||
167 | break; | 246 | break; | ||
168 | } | 247 | } | ||
169 | } | 248 | } | ||
170 | if( managerFound ) | 249 | if( managerFound ) { | ||
171 | { | | |||
172 | page->setProjectManager( manager ); | 250 | page->setProjectManager( manager ); | ||
173 | break; | 251 | break; | ||
174 | } | 252 | } | ||
175 | } | 253 | } | ||
176 | } | 254 | } | ||
177 | } | | |||
178 | m_url.setPath( m_url.path() + '/' + m_url.fileName() + '.' + ShellExtension::getInstance()->projectFileExtension() ); | 255 | m_url.setPath( m_url.path() + '/' + m_url.fileName() + '.' + ShellExtension::getInstance()->projectFileExtension() ); | ||
179 | } else | 256 | } else { | ||
180 | { | | |||
181 | setAppropriate( projectInfoPage, false ); | 257 | setAppropriate( projectInfoPage, false ); | ||
182 | m_url = url; | 258 | m_url = url; | ||
183 | } | 259 | } | ||
184 | validateProjectInfo(); | 260 | validateProjectInfo(); | ||
185 | setValid( openPage, true ); | 261 | setValid( openPage, true ); | ||
186 | } | 262 | } | ||
187 | 263 | | |||
188 | void OpenProjectDialog::openPageAccepted() | 264 | void OpenProjectDialog::openPageAccepted() | ||
▲ Show 20 Lines • Show All 58 Lines • Show Last 20 Lines |
Nitpick: Don't indent inside namespaces. Aids readability in case of multi-page-long namespaces.