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 "saveitemsdialog.h"
27
28 #include <coreplugin/diffservice.h>
29 #include <coreplugin/fileiconprovider.h>
30 #include <coreplugin/idocument.h>
31
32 #include <utils/fileutils.h>
33 #include <utils/hostosinfo.h>
34
35 #include <extensionsystem/pluginmanager.h>
36
37 #include <QDir>
38 #include <QFileInfo>
39 #include <QPushButton>
40 #include <QDebug>
41
42 Q_DECLARE_METATYPE(Core::IDocument*)
43
44 using namespace Core;
45 using namespace Core::Internal;
46
SaveItemsDialog(QWidget * parent,QList<IDocument * > items)47 SaveItemsDialog::SaveItemsDialog(QWidget *parent,
48 QList<IDocument *> items)
49 : QDialog(parent)
50 {
51 m_ui.setupUi(this);
52
53 // QDialogButtonBox's behavior for "destructive" is wrong, the "do not save" should be left-aligned
54 const QDialogButtonBox::ButtonRole discardButtonRole = Utils::HostOsInfo::isMacHost()
55 ? QDialogButtonBox::ResetRole : QDialogButtonBox::DestructiveRole;
56
57 if (DiffService::instance()) {
58 m_diffButton = m_ui.buttonBox->addButton(tr("&Diff"), discardButtonRole);
59 connect(m_diffButton, &QAbstractButton::clicked, this, &SaveItemsDialog::collectFilesToDiff);
60 }
61
62 QPushButton *discardButton = m_ui.buttonBox->addButton(tr("Do &Not Save"), discardButtonRole);
63 m_ui.buttonBox->button(QDialogButtonBox::Save)->setDefault(true);
64 m_ui.treeWidget->setFocus();
65
66 m_ui.saveBeforeBuildCheckBox->setVisible(false);
67
68 foreach (IDocument *document, items) {
69 QString visibleName;
70 QString directory;
71 Utils::FilePath filePath = document->filePath();
72 if (filePath.isEmpty()) {
73 visibleName = document->fallbackSaveAsFileName();
74 } else {
75 directory = filePath.absolutePath().toUserOutput();
76 visibleName = filePath.fileName();
77 }
78 QTreeWidgetItem *item = new QTreeWidgetItem(m_ui.treeWidget, QStringList()
79 << visibleName << QDir::toNativeSeparators(directory));
80 if (!filePath.isEmpty())
81 item->setIcon(0, FileIconProvider::icon(filePath));
82 item->setData(0, Qt::UserRole, QVariant::fromValue(document));
83 }
84
85 m_ui.treeWidget->resizeColumnToContents(0);
86 m_ui.treeWidget->selectAll();
87 if (Utils::HostOsInfo::isMacHost())
88 m_ui.treeWidget->setAlternatingRowColors(true);
89 adjustButtonWidths();
90 updateButtons();
91
92 connect(m_ui.buttonBox->button(QDialogButtonBox::Save), &QAbstractButton::clicked,
93 this, &SaveItemsDialog::collectItemsToSave);
94 connect(discardButton, &QAbstractButton::clicked, this, &SaveItemsDialog::discardAll);
95 connect(m_ui.treeWidget, &QTreeWidget::itemSelectionChanged,
96 this, &SaveItemsDialog::updateButtons);
97 }
98
setMessage(const QString & msg)99 void SaveItemsDialog::setMessage(const QString &msg)
100 {
101 m_ui.msgLabel->setText(msg);
102 }
103
updateButtons()104 void SaveItemsDialog::updateButtons()
105 {
106 int count = m_ui.treeWidget->selectedItems().count();
107 QPushButton *saveButton = m_ui.buttonBox->button(QDialogButtonBox::Save);
108 bool buttonsEnabled = true;
109 QString saveText = tr("&Save");
110 QString diffText = tr("&Diff && Cancel");
111 if (count == m_ui.treeWidget->topLevelItemCount()) {
112 saveText = tr("&Save All");
113 diffText = tr("&Diff All && Cancel");
114 } else if (count == 0) {
115 buttonsEnabled = false;
116 } else {
117 saveText = tr("&Save Selected");
118 diffText = tr("&Diff Selected && Cancel");
119 }
120 saveButton->setEnabled(buttonsEnabled);
121 saveButton->setText(saveText);
122 if (m_diffButton) {
123 m_diffButton->setEnabled(buttonsEnabled);
124 m_diffButton->setText(diffText);
125 }
126 }
127
adjustButtonWidths()128 void SaveItemsDialog::adjustButtonWidths()
129 {
130 // give save button a size that all texts fit in, so it doesn't get resized
131 // Mac: make cancel + save button same size (work around dialog button box issue)
132 QStringList possibleTexts;
133 possibleTexts << tr("Save") << tr("Save All");
134 if (m_ui.treeWidget->topLevelItemCount() > 1)
135 possibleTexts << tr("Save Selected");
136 int maxTextWidth = 0;
137 QPushButton *saveButton = m_ui.buttonBox->button(QDialogButtonBox::Save);
138 foreach (const QString &text, possibleTexts) {
139 saveButton->setText(text);
140 int hint = saveButton->sizeHint().width();
141 if (hint > maxTextWidth)
142 maxTextWidth = hint;
143 }
144 if (Utils::HostOsInfo::isMacHost()) {
145 QPushButton *cancelButton = m_ui.buttonBox->button(QDialogButtonBox::Cancel);
146 int cancelButtonWidth = cancelButton->sizeHint().width();
147 if (cancelButtonWidth > maxTextWidth)
148 maxTextWidth = cancelButtonWidth;
149 cancelButton->setMinimumWidth(maxTextWidth);
150 }
151 saveButton->setMinimumWidth(maxTextWidth);
152 }
153
collectItemsToSave()154 void SaveItemsDialog::collectItemsToSave()
155 {
156 m_itemsToSave.clear();
157 foreach (QTreeWidgetItem *item, m_ui.treeWidget->selectedItems()) {
158 m_itemsToSave.append(item->data(0, Qt::UserRole).value<IDocument*>());
159 }
160 accept();
161 }
162
collectFilesToDiff()163 void SaveItemsDialog::collectFilesToDiff()
164 {
165 m_filesToDiff.clear();
166 foreach (QTreeWidgetItem *item, m_ui.treeWidget->selectedItems()) {
167 if (auto doc = item->data(0, Qt::UserRole).value<IDocument*>())
168 m_filesToDiff.append(doc->filePath().toString());
169 }
170 reject();
171 }
172
discardAll()173 void SaveItemsDialog::discardAll()
174 {
175 m_ui.treeWidget->clearSelection();
176 collectItemsToSave();
177 }
178
itemsToSave() const179 QList<IDocument*> SaveItemsDialog::itemsToSave() const
180 {
181 return m_itemsToSave;
182 }
183
filesToDiff() const184 QStringList SaveItemsDialog::filesToDiff() const
185 {
186 return m_filesToDiff;
187 }
188
setAlwaysSaveMessage(const QString & msg)189 void SaveItemsDialog::setAlwaysSaveMessage(const QString &msg)
190 {
191 m_ui.saveBeforeBuildCheckBox->setText(msg);
192 m_ui.saveBeforeBuildCheckBox->setVisible(true);
193 }
194
alwaysSaveChecked()195 bool SaveItemsDialog::alwaysSaveChecked()
196 {
197 return m_ui.saveBeforeBuildCheckBox->isChecked();
198 }
199