1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25 
26 #include "librarydetailscontroller.h"
27 #include "ui_librarydetailswidget.h"
28 #include "qmakebuildconfiguration.h"
29 #include "qmakeparsernodes.h"
30 #include "qmakeproject.h"
31 
32 #include <projectexplorer/projectexplorer.h>
33 #include <projectexplorer/session.h>
34 #include <projectexplorer/target.h>
35 #include <utils/hostosinfo.h>
36 #include <utils/qtcprocess.h>
37 
38 #include <QFileInfo>
39 #include <QDir>
40 #include <QTextStream>
41 
42 using namespace ProjectExplorer;
43 using namespace QmakeProjectManager;
44 using namespace QmakeProjectManager::Internal;
45 
fillLibraryPlatformTypes(QComboBox * comboBox)46 static void fillLibraryPlatformTypes(QComboBox *comboBox)
47 {
48     comboBox->clear();
49     comboBox->addItem("Windows (*.lib lib*.a)", int(Utils::OsTypeWindows));
50     comboBox->addItem("Linux (lib*.so lib*.a)", int(Utils::OsTypeLinux));
51     comboBox->addItem("macOS (*.dylib *.a *.framework)", int(Utils::OsTypeMac));
52     const int currentIndex = comboBox->findData(int(Utils::HostOsInfo::hostOs()));
53     comboBox->setCurrentIndex(std::max(0, currentIndex));
54 }
55 
LibraryDetailsController(Ui::LibraryDetailsWidget * libraryDetails,const QString & proFile,QObject * parent)56 LibraryDetailsController::LibraryDetailsController(
57         Ui::LibraryDetailsWidget *libraryDetails,
58         const QString &proFile, QObject *parent) :
59     QObject(parent),
60     m_proFile(proFile),
61     m_libraryDetailsWidget(libraryDetails)
62 {
63     fillLibraryPlatformTypes(m_libraryDetailsWidget->libraryTypeComboBox);
64     setPlatformsVisible(true);
65     setLinkageGroupVisible(true);
66     setMacLibraryGroupVisible(true);
67     setPackageLineEditVisible(false);
68     const bool isMacOs = libraryPlatformType() == Utils::OsTypeMac;
69     const bool isWindows = libraryPlatformType() == Utils::OsTypeWindows;
70     setMacLibraryRadiosVisible(!isMacOs);
71     setLinkageRadiosVisible(isWindows);
72 
73     connect(m_libraryDetailsWidget->includePathChooser, &Utils::PathChooser::rawPathChanged,
74             this, &LibraryDetailsController::slotIncludePathChanged);
75     connect(m_libraryDetailsWidget->frameworkRadio, &QAbstractButton::clicked,
76             this, &LibraryDetailsController::slotMacLibraryTypeChanged);
77     connect(m_libraryDetailsWidget->libraryRadio, &QAbstractButton::clicked,
78             this, &LibraryDetailsController::slotMacLibraryTypeChanged);
79     connect(m_libraryDetailsWidget->useSubfoldersCheckBox, &QAbstractButton::toggled,
80             this, &LibraryDetailsController::slotUseSubfoldersChanged);
81     connect(m_libraryDetailsWidget->addSuffixCheckBox, &QAbstractButton::toggled,
82             this, &LibraryDetailsController::slotAddSuffixChanged);
83     connect(m_libraryDetailsWidget->linCheckBox, &QAbstractButton::clicked,
84             this, &LibraryDetailsController::slotPlatformChanged);
85     connect(m_libraryDetailsWidget->macCheckBox, &QAbstractButton::clicked,
86             this, &LibraryDetailsController::slotPlatformChanged);
87     connect(m_libraryDetailsWidget->winCheckBox, &QAbstractButton::clicked,
88             this, &LibraryDetailsController::slotPlatformChanged);
89 }
90 
libraryDetailsWidget() const91 Ui::LibraryDetailsWidget *LibraryDetailsController::libraryDetailsWidget() const
92 {
93     return m_libraryDetailsWidget;
94 }
95 
platforms() const96 AddLibraryWizard::Platforms LibraryDetailsController::platforms() const
97 {
98     return m_platforms;
99 }
100 
linkageType() const101 AddLibraryWizard::LinkageType LibraryDetailsController::linkageType() const
102 {
103     return m_linkageType;
104 }
105 
macLibraryType() const106 AddLibraryWizard::MacLibraryType LibraryDetailsController::macLibraryType() const
107 {
108     return m_macLibraryType;
109 }
110 
libraryPlatformType() const111 Utils::OsType LibraryDetailsController::libraryPlatformType() const
112 {
113     return Utils::OsType(m_libraryDetailsWidget->libraryTypeComboBox->currentData().value<int>());
114 }
115 
libraryPlatformFilter() const116 QString LibraryDetailsController::libraryPlatformFilter() const
117 {
118     return m_libraryDetailsWidget->libraryTypeComboBox->currentText();
119 }
120 
updateGui()121 void LibraryDetailsController::updateGui()
122 {
123     // read values from gui
124     m_platforms = {};
125     if (libraryDetailsWidget()->linCheckBox->isChecked())
126         m_platforms |= AddLibraryWizard::LinuxPlatform;
127     if (libraryDetailsWidget()->macCheckBox->isChecked())
128         m_platforms |= AddLibraryWizard::MacPlatform;
129     if (libraryDetailsWidget()->winCheckBox->isChecked())
130         m_platforms |= AddLibraryWizard::WindowsMinGWPlatform
131                 | AddLibraryWizard::WindowsMSVCPlatform;
132 
133     bool macLibraryTypeUpdated = false;
134     if (!m_linkageRadiosVisible) {
135         m_linkageType = suggestedLinkageType();
136         if (m_linkageType == AddLibraryWizard::StaticLinkage) {
137             m_macLibraryType = AddLibraryWizard::LibraryType;
138             macLibraryTypeUpdated = true;
139         }
140     } else {
141         m_linkageType = AddLibraryWizard::DynamicLinkage; // the default
142         if (libraryDetailsWidget()->staticRadio->isChecked())
143             m_linkageType = AddLibraryWizard::StaticLinkage;
144     }
145 
146     if (!macLibraryTypeUpdated) {
147         if (!m_macLibraryRadiosVisible) {
148             m_macLibraryType = suggestedMacLibraryType();
149         } else {
150             m_macLibraryType = AddLibraryWizard::LibraryType; // the default
151             if (libraryDetailsWidget()->frameworkRadio->isChecked())
152                 m_macLibraryType = AddLibraryWizard::FrameworkType;
153         }
154     }
155 
156     // enable or disable some parts of gui
157     libraryDetailsWidget()->macGroupBox->setEnabled(platforms()
158                                 & AddLibraryWizard::MacPlatform);
159     updateWindowsOptionsEnablement();
160     const bool macRadiosEnabled = m_linkageRadiosVisible ||
161             linkageType() != AddLibraryWizard::StaticLinkage;
162     libraryDetailsWidget()->libraryRadio->setEnabled(macRadiosEnabled);
163     libraryDetailsWidget()->frameworkRadio->setEnabled(macRadiosEnabled);
164 
165     // update values in gui
166     setIgnoreGuiSignals(true);
167 
168     showLinkageType(linkageType());
169     showMacLibraryType(macLibraryType());
170     if (!m_includePathChanged)
171         libraryDetailsWidget()->includePathChooser->setPath(suggestedIncludePath());
172 
173     setIgnoreGuiSignals(false);
174 
175     // UGLY HACK BEGIN
176     //
177     // We need to invoke QWizardPrivate::updateLayout() method to properly
178     // recalculate the new minimum size for the whole wizard.
179     // This is done internally by QWizard e.g. when a new wizard page is being shown.
180     // Unfortunately, QWizard doesn't expose this method currently.
181     // Since the current implementation of QWizard::setTitleFormat() sets the
182     // format and calls QWizardPrivate::updateLayout() unconditionally
183     // we use it as a hacky solution to the above issue.
184     // For reference please see: QTBUG-88666
185     if (!m_wizard) {
186         QWidget *widget = libraryDetailsWidget()->detailsLayout->parentWidget();
187         while (widget) {
188             QWizard *wizard = qobject_cast<QWizard *>(widget);
189             if (wizard) {
190                 m_wizard = wizard;
191                 break;
192             }
193             widget = widget->parentWidget();
194         }
195     }
196     QTC_ASSERT(m_wizard, return);
197     m_wizard->setTitleFormat(m_wizard->titleFormat());
198     // UGLY HACK END
199 }
200 
proFile() const201 QString LibraryDetailsController::proFile() const
202 {
203     return m_proFile;
204 }
205 
isIncludePathChanged() const206 bool LibraryDetailsController::isIncludePathChanged() const
207 {
208     return m_includePathChanged;
209 }
210 
setIgnoreGuiSignals(bool ignore)211 void LibraryDetailsController::setIgnoreGuiSignals(bool ignore)
212 {
213     m_ignoreGuiSignals = ignore;
214 }
215 
guiSignalsIgnored() const216 bool LibraryDetailsController::guiSignalsIgnored() const
217 {
218     return m_ignoreGuiSignals;
219 }
220 
showLinkageType(AddLibraryWizard::LinkageType linkageType)221 void LibraryDetailsController::showLinkageType(
222         AddLibraryWizard::LinkageType linkageType)
223 {
224     const QString linkage(tr("Linkage:"));
225     QString linkageTitle;
226     switch (linkageType) {
227     case AddLibraryWizard::DynamicLinkage:
228         libraryDetailsWidget()->dynamicRadio->setChecked(true);
229         linkageTitle = tr("%1 Dynamic").arg(linkage);
230         break;
231     case AddLibraryWizard::StaticLinkage:
232         libraryDetailsWidget()->staticRadio->setChecked(true);
233         linkageTitle = tr("%1 Static").arg(linkage);
234         break;
235     default:
236         libraryDetailsWidget()->dynamicRadio->setChecked(false);
237         libraryDetailsWidget()->staticRadio->setChecked(false);
238         linkageTitle = linkage;
239         break;
240         }
241     libraryDetailsWidget()->linkageGroupBox->setTitle(linkageTitle);
242 }
243 
showMacLibraryType(AddLibraryWizard::MacLibraryType libType)244 void LibraryDetailsController::showMacLibraryType(
245         AddLibraryWizard::MacLibraryType libType)
246 {
247     const QString libraryType(tr("Mac:"));
248     QString libraryTypeTitle;
249     switch (libType) {
250     case AddLibraryWizard::FrameworkType:
251         libraryDetailsWidget()->frameworkRadio->setChecked(true);
252         libraryTypeTitle = tr("%1 Framework").arg(libraryType);
253         break;
254     case AddLibraryWizard::LibraryType:
255         libraryDetailsWidget()->libraryRadio->setChecked(true);
256         libraryTypeTitle = tr("%1 Library").arg(libraryType);
257         break;
258     default:
259         libraryDetailsWidget()->frameworkRadio->setChecked(false);
260         libraryDetailsWidget()->libraryRadio->setChecked(false);
261         libraryTypeTitle = libraryType;
262         break;
263     }
264     libraryDetailsWidget()->macGroupBox->setTitle(libraryTypeTitle);
265 }
266 
setPlatformsVisible(bool ena)267 void LibraryDetailsController::setPlatformsVisible(bool ena)
268 {
269     libraryDetailsWidget()->platformGroupBox->setVisible(ena);
270 }
271 
setLinkageRadiosVisible(bool ena)272 void LibraryDetailsController::setLinkageRadiosVisible(bool ena)
273 {
274     m_linkageRadiosVisible = ena;
275     libraryDetailsWidget()->staticRadio->setVisible(ena);
276     libraryDetailsWidget()->dynamicRadio->setVisible(ena);
277 }
278 
setLinkageGroupVisible(bool ena)279 void LibraryDetailsController::setLinkageGroupVisible(bool ena)
280 {
281     setLinkageRadiosVisible(ena);
282     libraryDetailsWidget()->linkageGroupBox->setVisible(ena);
283 }
284 
setMacLibraryRadiosVisible(bool ena)285 void LibraryDetailsController::setMacLibraryRadiosVisible(bool ena)
286 {
287     m_macLibraryRadiosVisible = ena;
288     libraryDetailsWidget()->frameworkRadio->setVisible(ena);
289     libraryDetailsWidget()->libraryRadio->setVisible(ena);
290 }
291 
setMacLibraryGroupVisible(bool ena)292 void LibraryDetailsController::setMacLibraryGroupVisible(bool ena)
293 {
294     setMacLibraryRadiosVisible(ena);
295     libraryDetailsWidget()->macGroupBox->setVisible(ena);
296 }
297 
setLibraryPathChooserVisible(bool ena)298 void LibraryDetailsController::setLibraryPathChooserVisible(bool ena)
299 {
300     libraryDetailsWidget()->libraryTypeComboBox->setVisible(ena);
301     libraryDetailsWidget()->libraryTypeLabel->setVisible(ena);
302     libraryDetailsWidget()->libraryPathChooser->setVisible(ena);
303     libraryDetailsWidget()->libraryFileLabel->setVisible(ena);
304 }
305 
setLibraryComboBoxVisible(bool ena)306 void LibraryDetailsController::setLibraryComboBoxVisible(bool ena)
307 {
308     libraryDetailsWidget()->libraryComboBox->setVisible(ena);
309     libraryDetailsWidget()->libraryLabel->setVisible(ena);
310 }
311 
setPackageLineEditVisible(bool ena)312 void LibraryDetailsController::setPackageLineEditVisible(bool ena)
313 {
314     libraryDetailsWidget()->packageLineEdit->setVisible(ena);
315     libraryDetailsWidget()->packageLabel->setVisible(ena);
316 }
317 
setIncludePathVisible(bool ena)318 void LibraryDetailsController::setIncludePathVisible(bool ena)
319 {
320     m_includePathVisible = ena;
321     libraryDetailsWidget()->includeLabel->setVisible(ena);
322     libraryDetailsWidget()->includePathChooser->setVisible(ena);
323 }
324 
setWindowsGroupVisible(bool ena)325 void LibraryDetailsController::setWindowsGroupVisible(bool ena)
326 {
327     m_windowsGroupVisible = ena;
328     libraryDetailsWidget()->winGroupBox->setVisible(ena);
329 }
330 
setRemoveSuffixVisible(bool ena)331 void LibraryDetailsController::setRemoveSuffixVisible(bool ena)
332 {
333     libraryDetailsWidget()->removeSuffixCheckBox->setVisible(ena);
334 }
335 
isMacLibraryRadiosVisible() const336 bool LibraryDetailsController::isMacLibraryRadiosVisible() const
337 {
338     return m_macLibraryRadiosVisible;
339 }
340 
isIncludePathVisible() const341 bool LibraryDetailsController::isIncludePathVisible() const
342 {
343     return m_includePathVisible;
344 }
345 
isWindowsGroupVisible() const346 bool LibraryDetailsController::isWindowsGroupVisible() const
347 {
348     return m_windowsGroupVisible;
349 }
350 
slotIncludePathChanged()351 void LibraryDetailsController::slotIncludePathChanged()
352 {
353     if (m_ignoreGuiSignals)
354         return;
355     m_includePathChanged = true;
356 }
357 
slotPlatformChanged()358 void LibraryDetailsController::slotPlatformChanged()
359 {
360     updateGui();
361     emit completeChanged();
362 }
363 
slotMacLibraryTypeChanged()364 void LibraryDetailsController::slotMacLibraryTypeChanged()
365 {
366     if (guiSignalsIgnored())
367         return;
368 
369     if (m_linkageRadiosVisible
370             && libraryDetailsWidget()->frameworkRadio->isChecked()) {
371         setIgnoreGuiSignals(true);
372         libraryDetailsWidget()->dynamicRadio->setChecked(true);
373         setIgnoreGuiSignals(false);
374     }
375 
376     updateGui();
377 }
378 
slotUseSubfoldersChanged(bool ena)379 void LibraryDetailsController::slotUseSubfoldersChanged(bool ena)
380 {
381     if (ena) {
382         libraryDetailsWidget()->addSuffixCheckBox->setChecked(false);
383         libraryDetailsWidget()->removeSuffixCheckBox->setChecked(false);
384     }
385 }
386 
slotAddSuffixChanged(bool ena)387 void LibraryDetailsController::slotAddSuffixChanged(bool ena)
388 {
389     if (ena) {
390         libraryDetailsWidget()->useSubfoldersCheckBox->setChecked(false);
391         libraryDetailsWidget()->removeSuffixCheckBox->setChecked(false);
392     }
393 }
394 
395 // quote only when the string contains spaces
smartQuote(const QString & aString)396 static QString smartQuote(const QString &aString)
397 {
398     // The OS type is not important in that case, but use always the same
399     // in order not to generate different quoting depending on host platform
400     return Utils::ProcessArgs::quoteArg(aString, Utils::OsTypeLinux);
401 }
402 
appendSeparator(const QString & aString)403 static QString appendSeparator(const QString &aString)
404 {
405     if (aString.isEmpty())
406         return aString;
407     if (aString.at(aString.size() - 1) == QLatin1Char('/'))
408         return aString;
409     return aString + QLatin1Char('/');
410 }
411 
windowsScopes(AddLibraryWizard::Platforms scopes)412 static QString windowsScopes(AddLibraryWizard::Platforms scopes)
413 {
414     QString scopesString;
415     QTextStream str(&scopesString);
416     AddLibraryWizard::Platforms windowsPlatforms = scopes
417             & (AddLibraryWizard::WindowsMinGWPlatform | AddLibraryWizard::WindowsMSVCPlatform);
418     if (windowsPlatforms == AddLibraryWizard::WindowsMinGWPlatform)
419         str << "win32-g++"; // mingw only
420     else if (windowsPlatforms == AddLibraryWizard::WindowsMSVCPlatform)
421         str << "win32:!win32-g++"; // msvc only
422     else if (windowsPlatforms)
423         str << "win32"; // both mingw and msvc
424     return scopesString;
425 }
426 
commonScopes(AddLibraryWizard::Platforms scopes,AddLibraryWizard::Platforms excludedScopes)427 static QString commonScopes(AddLibraryWizard::Platforms scopes,
428                             AddLibraryWizard::Platforms excludedScopes)
429 {
430     QString scopesString;
431     QTextStream str(&scopesString);
432     AddLibraryWizard::Platforms common = scopes | excludedScopes;
433     bool unixLikeScopes = false;
434     if (scopes & ~QFlags<AddLibraryWizard::Platform>(AddLibraryWizard::WindowsMinGWPlatform
435                                                      | AddLibraryWizard::WindowsMSVCPlatform)) {
436         unixLikeScopes = true;
437         if (common & AddLibraryWizard::LinuxPlatform) {
438             str << "unix";
439             if (!(common & AddLibraryWizard::MacPlatform))
440                 str << ":!macx";
441         } else {
442             if (scopes & AddLibraryWizard::MacPlatform)
443                 str << "macx";
444         }
445     }
446     AddLibraryWizard::Platforms windowsPlatforms = scopes
447             & (AddLibraryWizard::WindowsMinGWPlatform | AddLibraryWizard::WindowsMSVCPlatform);
448     if (windowsPlatforms) {
449         if (unixLikeScopes)
450             str << "|";
451         str << windowsScopes(windowsPlatforms);
452     }
453     return scopesString;
454 }
455 
generateLibsSnippet(AddLibraryWizard::Platforms platforms,AddLibraryWizard::MacLibraryType macLibraryType,const QString & libName,const QString & targetRelativePath,const QString & pwd,bool useSubfolders,bool addSuffix,bool generateLibPath)456 static QString generateLibsSnippet(AddLibraryWizard::Platforms platforms,
457                      AddLibraryWizard::MacLibraryType macLibraryType,
458                      const QString &libName,
459                      const QString &targetRelativePath, const QString &pwd,
460                      bool useSubfolders, bool addSuffix, bool generateLibPath)
461 {
462     const QDir targetRelativeDir(targetRelativePath);
463     QString libraryPathSnippet;
464     if (targetRelativeDir.isRelative()) {
465         // it contains: $$[pwd]/
466         libraryPathSnippet = QLatin1String("$$") + pwd + QLatin1Char('/');
467     }
468 
469     AddLibraryWizard::Platforms commonPlatforms = platforms;
470     if (macLibraryType == AddLibraryWizard::FrameworkType) // we will generate a separate -F -framework line
471         commonPlatforms &= ~QFlags<AddLibraryWizard::Platform>(AddLibraryWizard::MacPlatform);
472     if (useSubfolders || addSuffix) // we will generate a separate debug/release conditions
473         commonPlatforms &= ~QFlags<AddLibraryWizard::Platform>(AddLibraryWizard::WindowsMinGWPlatform
474                                                                | AddLibraryWizard::WindowsMSVCPlatform);
475 
476     AddLibraryWizard::Platforms diffPlatforms = platforms ^ commonPlatforms;
477     AddLibraryWizard::Platforms generatedPlatforms;
478 
479     QString snippetMessage;
480     QTextStream str(&snippetMessage);
481 
482     AddLibraryWizard::Platforms windowsPlatforms = diffPlatforms
483             & (AddLibraryWizard::WindowsMinGWPlatform | AddLibraryWizard::WindowsMSVCPlatform);
484     if (windowsPlatforms) {
485         QString windowsString = windowsScopes(windowsPlatforms);
486         str << windowsString << ":CONFIG(release, debug|release): LIBS += ";
487         if (useSubfolders) {
488             if (generateLibPath)
489                 str << "-L" << libraryPathSnippet << smartQuote(targetRelativePath + QLatin1String("release/")) << ' ';
490             str << "-l" << libName << "\n";
491         } else if (addSuffix) {
492             if (generateLibPath)
493                 str << "-L" << libraryPathSnippet << smartQuote(targetRelativePath) << ' ';
494             str << "-l" << libName << "\n";
495         }
496 
497         str << "else:" << windowsString << ":CONFIG(debug, debug|release): LIBS += ";
498         if (useSubfolders) {
499             if (generateLibPath)
500                 str << "-L" << libraryPathSnippet << smartQuote(targetRelativePath + QLatin1String("debug/")) << ' ';
501             str << "-l" << libName << "\n";
502         } else if (addSuffix) {
503             if (generateLibPath)
504                 str << "-L" << libraryPathSnippet << smartQuote(targetRelativePath) << ' ';
505             str << "-l" << libName << "d\n";
506         }
507         generatedPlatforms |= windowsPlatforms;
508     }
509     if (diffPlatforms & AddLibraryWizard::MacPlatform) {
510         if (generatedPlatforms)
511             str << "else:";
512         str << "mac: LIBS += ";
513         if (generateLibPath)
514             str << "-F" << libraryPathSnippet << smartQuote(targetRelativePath) << ' ';
515         str << "-framework " << libName << "\n";
516         generatedPlatforms |= AddLibraryWizard::MacPlatform;
517     }
518 
519     if (commonPlatforms) {
520         if (generatedPlatforms)
521             str << "else:";
522         str << commonScopes(commonPlatforms, generatedPlatforms) << ": LIBS += ";
523         if (generateLibPath)
524             str << "-L" << libraryPathSnippet << smartQuote(targetRelativePath) << ' ';
525         str << "-l" << libName << "\n";
526     }
527     return snippetMessage;
528 }
529 
generateIncludePathSnippet(const QString & includeRelativePath)530 static QString generateIncludePathSnippet(const QString &includeRelativePath)
531 {
532     const QDir includeRelativeDir(includeRelativePath);
533     QString includePathSnippet;
534     if (includeRelativeDir.isRelative()) {
535         includePathSnippet = QLatin1String("$$PWD/");
536     }
537     includePathSnippet += smartQuote(includeRelativePath) + QLatin1Char('\n');
538 
539     return QLatin1String("\nINCLUDEPATH += ") + includePathSnippet
540             + QLatin1String("DEPENDPATH += ") + includePathSnippet;
541 }
542 
generatePreTargetDepsSnippet(AddLibraryWizard::Platforms platforms,AddLibraryWizard::LinkageType linkageType,const QString & libName,const QString & targetRelativePath,const QString & pwd,bool useSubfolders,bool addSuffix)543 static QString generatePreTargetDepsSnippet(AddLibraryWizard::Platforms platforms,
544                                             AddLibraryWizard::LinkageType linkageType,
545                                             const QString &libName,
546                                             const QString &targetRelativePath, const QString &pwd,
547                                             bool useSubfolders, bool addSuffix)
548 {
549     if (linkageType != AddLibraryWizard::StaticLinkage)
550         return QString();
551 
552     const QDir targetRelativeDir(targetRelativePath);
553 
554     QString preTargetDepsSnippet = QLatin1String("PRE_TARGETDEPS += ");
555     if (targetRelativeDir.isRelative()) {
556         // it contains: PRE_TARGETDEPS += $$[pwd]/
557         preTargetDepsSnippet += QLatin1String("$$") + pwd + QLatin1Char('/');
558     }
559 
560     QString snippetMessage;
561     QTextStream str(&snippetMessage);
562     str << "\n";
563     AddLibraryWizard::Platforms generatedPlatforms;
564     AddLibraryWizard::Platforms windowsPlatforms = platforms
565             & (AddLibraryWizard::WindowsMinGWPlatform | AddLibraryWizard::WindowsMSVCPlatform);
566     AddLibraryWizard::Platforms commonPlatforms = platforms;
567     if (useSubfolders || addSuffix) // we will generate a separate debug/release conditions, otherwise mingw is unix like
568         commonPlatforms &= ~QFlags<AddLibraryWizard::Platform>(AddLibraryWizard::WindowsMinGWPlatform);
569     commonPlatforms &= ~QFlags<AddLibraryWizard::Platform>(AddLibraryWizard::WindowsMSVCPlatform); // this case is different from all platforms
570     if (windowsPlatforms) {
571         if (useSubfolders || addSuffix) {
572             if (windowsPlatforms & AddLibraryWizard::WindowsMinGWPlatform) {
573                 str << "win32-g++:CONFIG(release, debug|release): "
574                     << preTargetDepsSnippet;
575                 if (useSubfolders)
576                     str << smartQuote(targetRelativePath + QLatin1String("release/lib") + libName + QLatin1String(".a")) << '\n';
577                 else if (addSuffix)
578                     str << smartQuote(targetRelativePath + QLatin1String("lib") + libName + QLatin1String(".a")) << '\n';
579 
580                 str << "else:win32-g++:CONFIG(debug, debug|release): "
581                     << preTargetDepsSnippet;
582                 if (useSubfolders)
583                     str << smartQuote(targetRelativePath + QLatin1String("debug/lib") + libName + QLatin1String(".a")) << '\n';
584                 else if (addSuffix)
585                     str << smartQuote(targetRelativePath + QLatin1String("lib") + libName + QLatin1String("d.a")) << '\n';
586             }
587             if (windowsPlatforms & AddLibraryWizard::WindowsMSVCPlatform) {
588                 if (windowsPlatforms & AddLibraryWizard::WindowsMinGWPlatform)
589                     str << "else:";
590                 str << "win32:!win32-g++:CONFIG(release, debug|release): "
591                     << preTargetDepsSnippet;
592                 if (useSubfolders)
593                     str << smartQuote(targetRelativePath + QLatin1String("release/") + libName + QLatin1String(".lib")) << '\n';
594                 else if (addSuffix)
595                     str << smartQuote(targetRelativePath + libName + QLatin1String(".lib")) << '\n';
596 
597                 str << "else:win32:!win32-g++:CONFIG(debug, debug|release): "
598                     << preTargetDepsSnippet;
599                 if (useSubfolders)
600                     str << smartQuote(targetRelativePath + QLatin1String("debug/") + libName + QLatin1String(".lib")) << '\n';
601                 else if (addSuffix)
602                     str << smartQuote(targetRelativePath + libName + QLatin1String("d.lib")) << '\n';
603             }
604             generatedPlatforms |= windowsPlatforms;
605         } else {
606             if (windowsPlatforms & AddLibraryWizard::WindowsMSVCPlatform) {
607                 str << "win32:!win32-g++: " << preTargetDepsSnippet
608                     << smartQuote(targetRelativePath + libName + QLatin1String(".lib")) << "\n";
609                 generatedPlatforms |= AddLibraryWizard::WindowsMSVCPlatform; // mingw will be handled with common scopes
610             }
611             // mingw not generated yet, will be joined with unix like
612         }
613     }
614     if (commonPlatforms) {
615         if (generatedPlatforms)
616             str << "else:";
617         str << commonScopes(commonPlatforms, generatedPlatforms) << ": "
618             << preTargetDepsSnippet << smartQuote(targetRelativePath + QLatin1String("lib") + libName + QLatin1String(".a")) << "\n";
619     }
620     return snippetMessage;
621 }
622 
NonInternalLibraryDetailsController(Ui::LibraryDetailsWidget * libraryDetails,const QString & proFile,QObject * parent)623 NonInternalLibraryDetailsController::NonInternalLibraryDetailsController(
624         Ui::LibraryDetailsWidget *libraryDetails,
625         const QString &proFile, QObject *parent) :
626     LibraryDetailsController(libraryDetails, proFile, parent)
627 {
628     setLibraryComboBoxVisible(false);
629     setLibraryPathChooserVisible(true);
630 
631     connect(libraryDetailsWidget()->libraryPathChooser, &Utils::PathChooser::validChanged,
632             this, &LibraryDetailsController::completeChanged);
633     connect(libraryDetailsWidget()->libraryPathChooser, &Utils::PathChooser::rawPathChanged,
634             this, &NonInternalLibraryDetailsController::slotLibraryPathChanged);
635     connect(libraryDetailsWidget()->removeSuffixCheckBox, &QAbstractButton::toggled,
636             this, &NonInternalLibraryDetailsController::slotRemoveSuffixChanged);
637     connect(libraryDetailsWidget()->dynamicRadio, &QAbstractButton::clicked,
638             this, &NonInternalLibraryDetailsController::slotLinkageTypeChanged);
639     connect(libraryDetailsWidget()->staticRadio, &QAbstractButton::clicked,
640             this, &NonInternalLibraryDetailsController::slotLinkageTypeChanged);
641     connect(libraryDetailsWidget()->libraryTypeComboBox, &QComboBox::currentTextChanged,
642             this, &NonInternalLibraryDetailsController::slotLibraryTypeChanged);
643     handleLibraryTypeChange();
644 }
645 
suggestedLinkageType() const646 AddLibraryWizard::LinkageType NonInternalLibraryDetailsController::suggestedLinkageType() const
647 {
648     AddLibraryWizard::LinkageType type = AddLibraryWizard::NoLinkage;
649     if (libraryPlatformType() != Utils::OsTypeWindows) {
650         if (libraryDetailsWidget()->libraryPathChooser->isValid()) {
651             QFileInfo fi(libraryDetailsWidget()->libraryPathChooser->filePath().toString());
652             if (fi.suffix() == QLatin1String("a"))
653                 type = AddLibraryWizard::StaticLinkage;
654             else
655                 type = AddLibraryWizard::DynamicLinkage;
656         }
657     }
658     return type;
659 }
660 
suggestedMacLibraryType() const661 AddLibraryWizard::MacLibraryType NonInternalLibraryDetailsController::suggestedMacLibraryType() const
662 {
663     AddLibraryWizard::MacLibraryType type = AddLibraryWizard::NoLibraryType;
664     if (libraryPlatformType() == Utils::OsTypeMac) {
665         if (libraryDetailsWidget()->libraryPathChooser->isValid()) {
666             QFileInfo fi(libraryDetailsWidget()->libraryPathChooser->filePath().toString());
667             if (fi.suffix() == QLatin1String("framework"))
668                 type = AddLibraryWizard::FrameworkType;
669             else
670                 type = AddLibraryWizard::LibraryType;
671         }
672     }
673     return type;
674 }
675 
suggestedIncludePath() const676 QString NonInternalLibraryDetailsController::suggestedIncludePath() const
677 {
678     QString includePath;
679     if (libraryDetailsWidget()->libraryPathChooser->isValid()) {
680         QFileInfo fi(libraryDetailsWidget()->libraryPathChooser->filePath().toString());
681         includePath = fi.absolutePath();
682         QFileInfo dfi(includePath);
683         // TODO: Win: remove debug or release folder first if appropriate
684         if (dfi.fileName() == QLatin1String("lib")) {
685             QDir dir = dfi.absoluteDir();
686             includePath = dir.absolutePath();
687             QDir includeDir(dir.absoluteFilePath(QLatin1String("include")));
688             if (includeDir.exists())
689                 includePath = includeDir.absolutePath();
690         }
691     }
692     return includePath;
693 }
694 
updateWindowsOptionsEnablement()695 void NonInternalLibraryDetailsController::updateWindowsOptionsEnablement()
696 {
697     bool ena = platforms() & (AddLibraryWizard::WindowsMinGWPlatform | AddLibraryWizard::WindowsMSVCPlatform);
698     if (libraryPlatformType() == Utils::OsTypeWindows) {
699         libraryDetailsWidget()->addSuffixCheckBox->setEnabled(ena);
700         ena = true;
701     }
702     libraryDetailsWidget()->winGroupBox->setEnabled(ena);
703 }
704 
handleLinkageTypeChange()705 void NonInternalLibraryDetailsController::handleLinkageTypeChange()
706 {
707     if (isMacLibraryRadiosVisible()
708             && libraryDetailsWidget()->staticRadio->isChecked()) {
709         setIgnoreGuiSignals(true);
710         libraryDetailsWidget()->libraryRadio->setChecked(true);
711         setIgnoreGuiSignals(false);
712     }
713 }
714 
slotLinkageTypeChanged()715 void NonInternalLibraryDetailsController::slotLinkageTypeChanged()
716 {
717     if (guiSignalsIgnored())
718         return;
719 
720     handleLinkageTypeChange();
721     updateGui();
722 }
723 
slotRemoveSuffixChanged(bool ena)724 void NonInternalLibraryDetailsController::slotRemoveSuffixChanged(bool ena)
725 {
726     if (ena) {
727         libraryDetailsWidget()->useSubfoldersCheckBox->setChecked(false);
728         libraryDetailsWidget()->addSuffixCheckBox->setChecked(false);
729     }
730 }
731 
handleLibraryTypeChange()732 void NonInternalLibraryDetailsController::handleLibraryTypeChange()
733 {
734     libraryDetailsWidget()->libraryPathChooser->setPromptDialogFilter(libraryPlatformFilter());
735     const bool isMacOs = libraryPlatformType() == Utils::OsTypeMac;
736     const bool isWindows = libraryPlatformType() == Utils::OsTypeWindows;
737     libraryDetailsWidget()->libraryPathChooser->setExpectedKind(isMacOs ? Utils::PathChooser::Any
738                                                                         : Utils::PathChooser::File);
739     setMacLibraryRadiosVisible(!isMacOs);
740     setLinkageRadiosVisible(isWindows);
741     setRemoveSuffixVisible(isWindows);
742     handleLibraryPathChange();
743     handleLinkageTypeChange();
744 }
745 
slotLibraryTypeChanged()746 void NonInternalLibraryDetailsController::slotLibraryTypeChanged()
747 {
748     handleLibraryTypeChange();
749     updateGui();
750     emit completeChanged();
751 }
752 
handleLibraryPathChange()753 void NonInternalLibraryDetailsController::handleLibraryPathChange()
754 {
755     if (libraryPlatformType() == Utils::OsTypeWindows) {
756         bool subfoldersEnabled = true;
757         bool removeSuffixEnabled = true;
758         if (libraryDetailsWidget()->libraryPathChooser->isValid()) {
759             QFileInfo fi(libraryDetailsWidget()->libraryPathChooser->filePath().toString());
760             QFileInfo dfi(fi.absolutePath());
761             const QString parentFolderName = dfi.fileName().toLower();
762             if (parentFolderName != QLatin1String("debug") &&
763                 parentFolderName != QLatin1String("release"))
764                 subfoldersEnabled = false;
765             const QString baseName = fi.completeBaseName();
766 
767             if (baseName.isEmpty() || baseName.at(baseName.size() - 1).toLower() != QLatin1Char('d'))
768                 removeSuffixEnabled = false;
769 
770             if (subfoldersEnabled)
771                 libraryDetailsWidget()->useSubfoldersCheckBox->setChecked(true);
772             else if (removeSuffixEnabled)
773                 libraryDetailsWidget()->removeSuffixCheckBox->setChecked(true);
774             else
775                 libraryDetailsWidget()->addSuffixCheckBox->setChecked(true);
776         }
777     }
778 }
779 
slotLibraryPathChanged()780 void NonInternalLibraryDetailsController::slotLibraryPathChanged()
781 {
782     handleLibraryPathChange();
783     updateGui();
784     emit completeChanged();
785 }
786 
isComplete() const787 bool NonInternalLibraryDetailsController::isComplete() const
788 {
789     return libraryDetailsWidget()->libraryPathChooser->isValid() &&
790            platforms();
791 }
792 
snippet() const793 QString NonInternalLibraryDetailsController::snippet() const
794 {
795     QString libPath = libraryDetailsWidget()->libraryPathChooser->filePath().toString();
796     QFileInfo fi(libPath);
797     QString libName;
798     const bool removeSuffix = isWindowsGroupVisible()
799             && libraryDetailsWidget()->removeSuffixCheckBox->isChecked();
800     if (libraryPlatformType() == Utils::OsTypeWindows) {
801         libName = fi.completeBaseName();
802         if (removeSuffix && !libName.isEmpty()) // remove last letter which needs to be "d"
803             libName = libName.left(libName.size() - 1);
804         if (fi.completeSuffix() == QLatin1String("a")) // the mingw lib case
805             libName = libName.mid(3); // cut the "lib" prefix
806     } else if (libraryPlatformType() == Utils::OsTypeMac) {
807         if (macLibraryType() == AddLibraryWizard::FrameworkType)
808             libName = fi.completeBaseName();
809         else
810             libName = fi.completeBaseName().mid(3); // cut the "lib" prefix
811     } else {
812         libName = fi.completeBaseName().mid(3); // cut the "lib" prefix
813     }
814 
815     bool useSubfolders = false;
816     bool addSuffix = false;
817     if (isWindowsGroupVisible()) {
818         // when we are on Win but we don't generate the code for Win
819         // we still need to remove "debug" or "release" subfolder
820         const bool useSubfoldersCondition = (libraryPlatformType() == Utils::OsTypeWindows)
821                                             ? true : platforms() & (AddLibraryWizard::WindowsMinGWPlatform
822                                                                     | AddLibraryWizard::WindowsMSVCPlatform);
823         if (useSubfoldersCondition)
824             useSubfolders = libraryDetailsWidget()->useSubfoldersCheckBox->isChecked();
825         if (platforms() & (AddLibraryWizard::WindowsMinGWPlatform | AddLibraryWizard::WindowsMSVCPlatform))
826             addSuffix = libraryDetailsWidget()->addSuffixCheckBox->isChecked() || removeSuffix;
827     }
828 
829     QString targetRelativePath;
830     QString includeRelativePath;
831     if (isIncludePathVisible()) { // generate also the path to lib
832         QFileInfo pfi(proFile());
833         QDir pdir = pfi.absoluteDir();
834         QString absoluteLibraryPath = fi.absolutePath();
835         if (libraryPlatformType() == Utils::OsTypeWindows && useSubfolders) { // drop last subfolder which needs to be "debug" or "release"
836             QFileInfo libfi(absoluteLibraryPath);
837             absoluteLibraryPath = libfi.absolutePath();
838         }
839         targetRelativePath = appendSeparator(pdir.relativeFilePath(absoluteLibraryPath));
840 
841         const QString includePath = libraryDetailsWidget()->includePathChooser->filePath().toString();
842         if (!includePath.isEmpty())
843             includeRelativePath = pdir.relativeFilePath(includePath);
844     }
845 
846     QString snippetMessage;
847     QTextStream str(&snippetMessage);
848     str << "\n";
849     str << generateLibsSnippet(platforms(), macLibraryType(), libName,
850                                targetRelativePath, QLatin1String("PWD"),
851                                useSubfolders, addSuffix, isIncludePathVisible());
852     if (isIncludePathVisible()) {
853         str << generateIncludePathSnippet(includeRelativePath);
854         str << generatePreTargetDepsSnippet(platforms(), linkageType(), libName,
855                                targetRelativePath, QLatin1String("PWD"),
856                                useSubfolders, addSuffix);
857     }
858     return snippetMessage;
859 }
860 
861 /////////////
862 
PackageLibraryDetailsController(Ui::LibraryDetailsWidget * libraryDetails,const QString & proFile,QObject * parent)863 PackageLibraryDetailsController::PackageLibraryDetailsController(
864     Ui::LibraryDetailsWidget *libraryDetails,
865     const QString &proFile, QObject *parent)
866     : NonInternalLibraryDetailsController(libraryDetails, proFile, parent)
867 {
868     setPlatformsVisible(false);
869     setIncludePathVisible(false);
870     setWindowsGroupVisible(false);
871     setLinkageGroupVisible(false);
872     setMacLibraryGroupVisible(false);
873     setLibraryPathChooserVisible(false);
874     setPackageLineEditVisible(true);
875 
876     connect(libraryDetailsWidget()->packageLineEdit, &QLineEdit::textChanged,
877             this, &LibraryDetailsController::completeChanged);
878 
879     updateGui();
880 }
881 
isComplete() const882 bool PackageLibraryDetailsController::isComplete() const
883 {
884     return !libraryDetailsWidget()->packageLineEdit->text().isEmpty();
885 }
886 
snippet() const887 QString PackageLibraryDetailsController::snippet() const
888 {
889     QString snippetMessage;
890     QTextStream str(&snippetMessage);
891     str << "\n";
892     if (!isLinkPackageGenerated())
893         str << "unix: CONFIG += link_pkgconfig\n";
894     str << "unix: PKGCONFIG += " << libraryDetailsWidget()->packageLineEdit->text() << "\n";
895     return snippetMessage;
896 }
897 
isLinkPackageGenerated() const898 bool PackageLibraryDetailsController::isLinkPackageGenerated() const
899 {
900     const Project *project = SessionManager::projectForFile(Utils::FilePath::fromString(proFile()));
901     if (!project)
902         return false;
903 
904     const ProjectNode *projectNode = project->findNodeForBuildKey(proFile());
905     if (!projectNode)
906         return false;
907 
908     const QmakeProFileNode *currentProject =
909             dynamic_cast<const QmakeProFileNode *>(projectNode);
910     if (!currentProject)
911         return false;
912 
913     const QStringList configVar = currentProject->variableValue(Variable::Config);
914     if (configVar.contains(QLatin1String("link_pkgconfig")))
915         return true;
916 
917     return false;
918 }
919 
920 /////////////
921 
SystemLibraryDetailsController(Ui::LibraryDetailsWidget * libraryDetails,const QString & proFile,QObject * parent)922 SystemLibraryDetailsController::SystemLibraryDetailsController(
923     Ui::LibraryDetailsWidget *libraryDetails,
924     const QString &proFile, QObject *parent)
925     : NonInternalLibraryDetailsController(libraryDetails, proFile, parent)
926 {
927     setIncludePathVisible(false);
928     setWindowsGroupVisible(false);
929 
930     updateGui();
931 }
932 
933 /////////////
934 
ExternalLibraryDetailsController(Ui::LibraryDetailsWidget * libraryDetails,const QString & proFile,QObject * parent)935 ExternalLibraryDetailsController::ExternalLibraryDetailsController(
936     Ui::LibraryDetailsWidget *libraryDetails,
937     const QString &proFile, QObject *parent)
938     : NonInternalLibraryDetailsController(libraryDetails, proFile, parent)
939 {
940     setIncludePathVisible(true);
941     setWindowsGroupVisible(true);
942 
943     updateGui();
944 }
945 
updateWindowsOptionsEnablement()946 void ExternalLibraryDetailsController::updateWindowsOptionsEnablement()
947 {
948     NonInternalLibraryDetailsController::updateWindowsOptionsEnablement();
949 
950     bool subfoldersEnabled = true;
951     bool removeSuffixEnabled = true;
952     if (libraryPlatformType() == Utils::OsTypeWindows
953             && libraryDetailsWidget()->libraryPathChooser->isValid()) {
954         QFileInfo fi(libraryDetailsWidget()->libraryPathChooser->filePath().toString());
955         QFileInfo dfi(fi.absolutePath());
956         const QString parentFolderName = dfi.fileName().toLower();
957         if (parentFolderName != QLatin1String("debug") &&
958                 parentFolderName != QLatin1String("release"))
959             subfoldersEnabled = false;
960         const QString baseName = fi.completeBaseName();
961 
962         if (baseName.isEmpty() || baseName.at(baseName.size() - 1).toLower() != QLatin1Char('d'))
963             removeSuffixEnabled = false;
964     }
965     libraryDetailsWidget()->useSubfoldersCheckBox->setEnabled(subfoldersEnabled);
966     libraryDetailsWidget()->removeSuffixCheckBox->setEnabled(removeSuffixEnabled);
967 }
968 
969 /////////////
970 
InternalLibraryDetailsController(Ui::LibraryDetailsWidget * libraryDetails,const QString & proFile,QObject * parent)971 InternalLibraryDetailsController::InternalLibraryDetailsController(
972         Ui::LibraryDetailsWidget *libraryDetails,
973         const QString &proFile, QObject *parent)
974     : LibraryDetailsController(libraryDetails, proFile, parent)
975 {
976     setLinkageRadiosVisible(false);
977     setLibraryPathChooserVisible(false);
978     setLibraryComboBoxVisible(true);
979     setIncludePathVisible(true);
980     setWindowsGroupVisible(true);
981     setRemoveSuffixVisible(false);
982 
983     if (Utils::HostOsInfo::isWindowsHost())
984         libraryDetailsWidget()->useSubfoldersCheckBox->setEnabled(true);
985 
986     connect(libraryDetailsWidget()->libraryComboBox,
987             QOverload<int>::of(&QComboBox::currentIndexChanged),
988             this, &InternalLibraryDetailsController::slotCurrentLibraryChanged);
989 
990     updateProFile();
991     updateGui();
992 }
993 
suggestedLinkageType() const994 AddLibraryWizard::LinkageType InternalLibraryDetailsController::suggestedLinkageType() const
995 {
996     const int currentIndex = libraryDetailsWidget()->libraryComboBox->currentIndex();
997     AddLibraryWizard::LinkageType type = AddLibraryWizard::NoLinkage;
998     if (currentIndex >= 0) {
999         QmakeProFile *proFile = m_proFiles.at(currentIndex);
1000         const QStringList configVar = proFile->variableValue(Variable::Config);
1001         if (configVar.contains(QLatin1String("staticlib"))
1002                 || configVar.contains(QLatin1String("static")))
1003             type = AddLibraryWizard::StaticLinkage;
1004         else
1005             type = AddLibraryWizard::DynamicLinkage;
1006     }
1007     return type;
1008 }
1009 
suggestedMacLibraryType() const1010 AddLibraryWizard::MacLibraryType InternalLibraryDetailsController::suggestedMacLibraryType() const
1011 {
1012     const int currentIndex = libraryDetailsWidget()->libraryComboBox->currentIndex();
1013     AddLibraryWizard::MacLibraryType type = AddLibraryWizard::NoLibraryType;
1014     if (currentIndex >= 0) {
1015         QmakeProFile *proFile = m_proFiles.at(currentIndex);
1016         const QStringList configVar = proFile->variableValue(Variable::Config);
1017         if (configVar.contains(QLatin1String("lib_bundle")))
1018             type = AddLibraryWizard::FrameworkType;
1019         else
1020             type = AddLibraryWizard::LibraryType;
1021     }
1022     return type;
1023 }
1024 
suggestedIncludePath() const1025 QString InternalLibraryDetailsController::suggestedIncludePath() const
1026 {
1027     const int currentIndex = libraryDetailsWidget()->libraryComboBox->currentIndex();
1028     if (currentIndex >= 0) {
1029         QmakeProFile *proFile = m_proFiles.at(currentIndex);
1030         return proFile->filePath().toFileInfo().absolutePath();
1031     }
1032     return QString();
1033 }
1034 
updateWindowsOptionsEnablement()1035 void InternalLibraryDetailsController::updateWindowsOptionsEnablement()
1036 {
1037     if (Utils::HostOsInfo::isWindowsHost())
1038         libraryDetailsWidget()->addSuffixCheckBox->setEnabled(true);
1039     libraryDetailsWidget()->winGroupBox->setEnabled(platforms()
1040                                 & (AddLibraryWizard::WindowsMinGWPlatform | AddLibraryWizard::WindowsMSVCPlatform));
1041 }
1042 
updateProFile()1043 void InternalLibraryDetailsController::updateProFile()
1044 {
1045     m_rootProjectPath.clear();
1046     m_proFiles.clear();
1047     libraryDetailsWidget()->libraryComboBox->clear();
1048 
1049     const QmakeProject *project
1050             = dynamic_cast<QmakeProject *>(SessionManager::projectForFile(Utils::FilePath::fromString(proFile())));
1051     if (!project)
1052         return;
1053 
1054     setIgnoreGuiSignals(true);
1055 
1056     m_rootProjectPath = project->projectDirectory().toString();
1057 
1058     auto t = project->activeTarget();
1059     auto bs = dynamic_cast<QmakeBuildSystem *>(t ? t->buildSystem() : nullptr);
1060     QTC_ASSERT(bs, return);
1061 
1062     QDir rootDir(m_rootProjectPath);
1063     foreach (QmakeProFile *proFile, bs->rootProFile()->allProFiles()) {
1064         QmakeProjectManager::ProjectType type = proFile->projectType();
1065         if (type != ProjectType::SharedLibraryTemplate && type != ProjectType::StaticLibraryTemplate)
1066             continue;
1067 
1068         const QStringList configVar = proFile->variableValue(Variable::Config);
1069         if (!configVar.contains(QLatin1String("plugin"))) {
1070             const QString relProFilePath = rootDir.relativeFilePath(proFile->filePath().toString());
1071             TargetInformation targetInfo = proFile->targetInformation();
1072             const QString itemToolTip = QString::fromLatin1("%1 (%2)").arg(targetInfo.target).arg(relProFilePath);
1073             m_proFiles.append(proFile);
1074 
1075             libraryDetailsWidget()->libraryComboBox->addItem(targetInfo.target);
1076             libraryDetailsWidget()->libraryComboBox->setItemData(
1077                         libraryDetailsWidget()->libraryComboBox->count() - 1,
1078                         itemToolTip, Qt::ToolTipRole);
1079         }
1080     }
1081 
1082     setIgnoreGuiSignals(false);
1083 }
1084 
slotCurrentLibraryChanged()1085 void InternalLibraryDetailsController::slotCurrentLibraryChanged()
1086 {
1087     const int currentIndex = libraryDetailsWidget()->libraryComboBox->currentIndex();
1088     if (currentIndex >= 0) {
1089         libraryDetailsWidget()->libraryComboBox->setToolTip(
1090                     libraryDetailsWidget()->libraryComboBox->itemData(
1091                         currentIndex, Qt::ToolTipRole).toString());
1092         QmakeProFile *proFile = m_proFiles.at(currentIndex);
1093         const QStringList configVar = proFile->variableValue(Variable::Config);
1094         if (Utils::HostOsInfo::isWindowsHost()) {
1095             bool useSubfolders = false;
1096             if (configVar.contains(QLatin1String("debug_and_release"))
1097                 && configVar.contains(QLatin1String("debug_and_release_target")))
1098                 useSubfolders = true;
1099             libraryDetailsWidget()->useSubfoldersCheckBox->setChecked(useSubfolders);
1100             libraryDetailsWidget()->addSuffixCheckBox->setChecked(!useSubfolders);
1101         }
1102     }
1103 
1104     if (guiSignalsIgnored())
1105         return;
1106 
1107     updateGui();
1108 
1109     emit completeChanged();
1110 }
1111 
isComplete() const1112 bool InternalLibraryDetailsController::isComplete() const
1113 {
1114     return libraryDetailsWidget()->libraryComboBox->count() && platforms();
1115 }
1116 
snippet() const1117 QString InternalLibraryDetailsController::snippet() const
1118 {
1119     const int currentIndex = libraryDetailsWidget()->libraryComboBox->currentIndex();
1120 
1121     if (currentIndex < 0)
1122         return QString();
1123 
1124     if (m_rootProjectPath.isEmpty())
1125         return QString();
1126 
1127 
1128     // dir of the root project
1129     QDir rootDir(m_rootProjectPath);
1130 
1131     // relative path for the project for which we insert the snippet,
1132     // it's relative to the root project
1133     const QString proRelavitePath = rootDir.relativeFilePath(proFile());
1134 
1135     // project for which we insert the snippet
1136     const Project *project = SessionManager::projectForFile(Utils::FilePath::fromString(proFile()));
1137 
1138     // the build directory of the active build configuration
1139     QDir rootBuildDir = rootDir; // If the project is unconfigured use the project dir
1140     if (ProjectExplorer::Target *t = project->activeTarget())
1141         if (ProjectExplorer::BuildConfiguration *bc = t->activeBuildConfiguration())
1142             rootBuildDir.setPath(bc->buildDirectory().toString());
1143 
1144     // the project for which we insert the snippet inside build tree
1145     QFileInfo pfi(rootBuildDir.filePath(proRelavitePath));
1146     // the project dir for which we insert the snippet inside build tree
1147     QDir projectBuildDir(pfi.absolutePath());
1148 
1149     // current project node from combobox
1150     QFileInfo fi(proFile());
1151     QDir projectSrcDir(fi.absolutePath());
1152 
1153     // project node which we want to link against
1154     TargetInformation targetInfo = m_proFiles.at(currentIndex)->targetInformation();
1155 
1156     const QString targetRelativePath = appendSeparator(projectBuildDir.relativeFilePath(targetInfo.buildDir.toString()));
1157     const QString includeRelativePath = projectSrcDir.relativeFilePath(libraryDetailsWidget()->includePathChooser->filePath().toString());
1158 
1159     const bool useSubfolders = libraryDetailsWidget()->useSubfoldersCheckBox->isChecked();
1160     const bool addSuffix = libraryDetailsWidget()->addSuffixCheckBox->isChecked();
1161 
1162     QString snippetMessage;
1163     QTextStream str(&snippetMessage);
1164     str << "\n";
1165 
1166     // replace below to "PRI_OUT_PWD" when task QTBUG-13057 is done
1167     // (end enable adding libraries into .pri files as well).
1168     const QString outPwd = QLatin1String("OUT_PWD");
1169     str << generateLibsSnippet(platforms(), macLibraryType(), targetInfo.target,
1170                                targetRelativePath, outPwd,
1171                                useSubfolders, addSuffix, true);
1172     str << generateIncludePathSnippet(includeRelativePath);
1173     str << generatePreTargetDepsSnippet(platforms(), linkageType(), targetInfo.target,
1174                                targetRelativePath, outPwd,
1175                                useSubfolders, addSuffix);
1176     return snippetMessage;
1177 }
1178