OSDN Git Service

It's 2011 now.
[qt-creator-jp/qt-creator-jp.git] / src / plugins / cpptools / cppfilesettingspage.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 **
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include "cppfilesettingspage.h"
35 #include "cpptoolsconstants.h"
36 #include "ui_cppfilesettingspage.h"
37
38 #include <coreplugin/icore.h>
39 #include <coreplugin/editormanager/editormanager.h>
40 #include <coreplugin/mimedatabase.h>
41 #include <cppeditor/cppeditorconstants.h>
42
43 #include <extensionsystem/pluginmanager.h>
44
45 #include <QtCore/QSettings>
46 #include <QtCore/QDebug>
47 #include <QtCore/QFile>
48 #include <QtCore/QFileInfo>
49 #include <QtCore/QCoreApplication>
50 #include <QtCore/QDate>
51 #include <QtCore/QLocale>
52 #include <QtCore/QTextCodec>
53 #include <QtCore/QTextStream>
54
55 #include <QtGui/QFileDialog>
56 #include <QtGui/QMessageBox>
57
58 static const char *headerSuffixKeyC = "HeaderSuffix";
59 static const char *sourceSuffixKeyC = "SourceSuffix";
60 static const char *licenseTemplatePathKeyC = "LicenseTemplate";
61
62 const char *licenseTemplateTemplate = QT_TRANSLATE_NOOP("CppTools::Internal::CppFileSettingsWidget",
63 "/**************************************************************************\n"
64 "** Qt Creator license header template\n"
65 "**   Special keywords: %USER% %DATE% %YEAR%\n"
66 "**   Environment variables: %$VARIABLE%\n"
67 "**   To protect a percent sign, use '%%'.\n"
68 "**************************************************************************/\n");
69
70 namespace CppTools {
71 namespace Internal {
72
73 CppFileSettings::CppFileSettings() :
74     lowerCaseFiles(false)
75 {
76 }
77
78 void CppFileSettings::toSettings(QSettings *s) const
79 {
80     s->beginGroup(QLatin1String(Constants::CPPTOOLS_SETTINGSGROUP));
81     s->setValue(QLatin1String(headerSuffixKeyC), headerSuffix);
82     s->setValue(QLatin1String(sourceSuffixKeyC), sourceSuffix);
83     s->setValue(QLatin1String(Constants::LOWERCASE_CPPFILES_KEY), lowerCaseFiles);
84     s->setValue(QLatin1String(licenseTemplatePathKeyC), licenseTemplatePath);
85     s->endGroup();
86 }
87
88 void CppFileSettings::fromSettings(QSettings *s)
89 {
90     s->beginGroup(QLatin1String(Constants::CPPTOOLS_SETTINGSGROUP));
91     headerSuffix= s->value(QLatin1String(headerSuffixKeyC), QLatin1String("h")).toString();
92     sourceSuffix = s->value(QLatin1String(sourceSuffixKeyC), QLatin1String("cpp")).toString();
93     const bool lowerCaseDefault = Constants::lowerCaseFilesDefault;
94     lowerCaseFiles = s->value(QLatin1String(Constants::LOWERCASE_CPPFILES_KEY), QVariant(lowerCaseDefault)).toBool();
95     licenseTemplatePath = s->value(QLatin1String(licenseTemplatePathKeyC), QString()).toString();
96     s->endGroup();
97 }
98
99 bool CppFileSettings::applySuffixesToMimeDB()
100 {
101     Core::MimeDatabase *mdb = Core::ICore::instance()->mimeDatabase();
102     return mdb->setPreferredSuffix(QLatin1String(CppTools::Constants::CPP_SOURCE_MIMETYPE), sourceSuffix)
103             && mdb->setPreferredSuffix(QLatin1String(CppTools::Constants::CPP_HEADER_MIMETYPE), headerSuffix);
104 }
105
106 bool CppFileSettings::equals(const CppFileSettings &rhs) const
107 {
108     return lowerCaseFiles == rhs.lowerCaseFiles
109            && headerSuffix == rhs.headerSuffix
110            && sourceSuffix == rhs.sourceSuffix
111            && licenseTemplatePath == rhs.licenseTemplatePath;
112 }
113
114 // Replacements of special license template keywords.
115 static bool keyWordReplacement(const QString &keyWord,
116                                const QString &file,
117                                const QString &className,
118                                QString *value)
119 {
120     if (keyWord == QLatin1String("%YEAR%")) {
121         *value = QString::number(QDate::currentDate().year());
122         return true;
123     }
124     if (keyWord == QLatin1String("%MONTH%")) {
125         *value = QString::number(QDate::currentDate().month());
126         return true;
127     }
128     if (keyWord == QLatin1String("%DAY%")) {
129         *value = QString::number(QDate::currentDate().day());
130         return true;
131     }
132     if (keyWord == QLatin1String("%CLASS%")) {
133         *value = className;
134         return true;
135     }
136     if (keyWord == QLatin1String("%FILENAME%")) {
137         *value = QFileInfo(file).fileName();
138         return true;
139     }
140     if (keyWord == QLatin1String("%DATE%")) {
141         static QString format;
142         // ensure a format with 4 year digits. Some have locales have 2.
143         if (format.isEmpty()) {
144             QLocale loc;
145             format = loc.dateFormat(QLocale::ShortFormat);
146             const QChar ypsilon = QLatin1Char('y');
147             if (format.count(ypsilon) == 2)
148                 format.insert(format.indexOf(ypsilon), QString(2, ypsilon));
149         }
150         *value = QDate::currentDate().toString(format);
151         return true;
152     }
153     if (keyWord == QLatin1String("%USER%")) {
154 #ifdef Q_OS_WIN
155         *value = QString::fromLocal8Bit(qgetenv("USERNAME"));
156 #else
157         *value = QString::fromLocal8Bit(qgetenv("USER"));
158 #endif
159         return true;
160     }
161     // Environment variables (for example '%$EMAIL%').
162     if (keyWord.startsWith(QLatin1String("%$"))) {
163         const QString varName = keyWord.mid(2, keyWord.size() - 3);
164         *value = QString::fromLocal8Bit(qgetenv(varName.toLocal8Bit()));
165         return true;
166     }
167     return false;
168 }
169
170 // Parse a license template, scan for %KEYWORD% and replace if known.
171 // Replace '%%' by '%'.
172 static void parseLicenseTemplatePlaceholders(QString *t, const QString &file, const QString &className)
173 {
174     int pos = 0;
175     const QChar placeHolder = QLatin1Char('%');
176     do {
177         const int placeHolderPos = t->indexOf(placeHolder, pos);
178         if (placeHolderPos == -1)
179             break;
180         const int endPlaceHolderPos = t->indexOf(placeHolder, placeHolderPos + 1);
181         if (endPlaceHolderPos == -1)
182             break;
183         if (endPlaceHolderPos == placeHolderPos + 1) { // '%%' -> '%'
184             t->remove(placeHolderPos, 1);
185             pos = placeHolderPos + 1;
186         } else {
187             const QString keyWord = t->mid(placeHolderPos, endPlaceHolderPos + 1 - placeHolderPos);
188             QString replacement;
189             if (keyWordReplacement(keyWord, file, className, &replacement)) {
190                 t->replace(placeHolderPos, keyWord.size(), replacement);
191                 pos = placeHolderPos + replacement.size();
192             } else {
193                 // Leave invalid keywords as is.
194                 pos = endPlaceHolderPos + 1;
195             }
196         }
197     } while (pos < t->size());
198 }
199
200 // Convenience that returns the formatted license template.
201 QString CppFileSettings::licenseTemplate(const QString &fileName, const QString &className)
202 {
203
204     const QSettings *s = Core::ICore::instance()->settings();
205     QString key = QLatin1String(Constants::CPPTOOLS_SETTINGSGROUP);
206     key += QLatin1Char('/');
207     key += QLatin1String(licenseTemplatePathKeyC);
208     const QString path = s->value(key, QString()).toString();
209     if (path.isEmpty())
210         return QString();
211     QFile file(path);
212     if (!file.open(QIODevice::ReadOnly|QIODevice::Text)) {
213         qWarning("Unable to open the license template %s: %s", qPrintable(path), qPrintable(file.errorString()));
214         return QString();
215     }
216
217     QTextCodec *codec = Core::EditorManager::instance()->defaultTextEncoding();
218     QTextStream licenseStream(&file);
219     licenseStream.setCodec(codec);
220     licenseStream.setAutoDetectUnicode(true);
221     QString license = licenseStream.readAll();
222
223     parseLicenseTemplatePlaceholders(&license, fileName, className);
224     // Ensure exactly one additional new line separating stuff
225     const QChar newLine = QLatin1Char('\n');
226     if (!license.endsWith(newLine))
227         license += newLine;
228     license += newLine;
229     return license;
230 }
231
232 // ------------------ CppFileSettingsWidget
233
234 CppFileSettingsWidget::CppFileSettingsWidget(QWidget *parent) :
235     QWidget(parent),
236     m_ui(new Ui::CppFileSettingsPage)
237 {
238     m_ui->setupUi(this);
239     const Core::MimeDatabase *mdb = Core::ICore::instance()->mimeDatabase();
240     // populate suffix combos
241     if (const Core::MimeType sourceMt = mdb->findByType(QLatin1String(CppTools::Constants::CPP_SOURCE_MIMETYPE)))
242         foreach (const QString &suffix, sourceMt.suffixes())
243             m_ui->sourceSuffixComboBox->addItem(suffix);
244
245     if (const Core::MimeType headerMt = mdb->findByType(QLatin1String(CppTools::Constants::CPP_HEADER_MIMETYPE)))
246         foreach (const QString &suffix, headerMt.suffixes())
247             m_ui->headerSuffixComboBox->addItem(suffix);
248     m_ui->licenseTemplatePathChooser->setExpectedKind(Utils::PathChooser::File);
249     m_ui->licenseTemplatePathChooser->addButton(tr("Edit..."), this, SLOT(slotEdit()));
250 }
251
252 CppFileSettingsWidget::~CppFileSettingsWidget()
253 {
254     delete m_ui;
255 }
256
257 QString CppFileSettingsWidget::licenseTemplatePath() const
258 {
259     return m_ui->licenseTemplatePathChooser->path();
260 }
261
262 void CppFileSettingsWidget::setLicenseTemplatePath(const QString &lp)
263 {
264     m_ui->licenseTemplatePathChooser->setPath(lp);
265 }
266
267 CppFileSettings CppFileSettingsWidget::settings() const
268 {
269     CppFileSettings rc;
270     rc.lowerCaseFiles = m_ui->lowerCaseFileNamesCheckBox->isChecked();
271     rc.headerSuffix = m_ui->headerSuffixComboBox->currentText();
272     rc.sourceSuffix = m_ui->sourceSuffixComboBox->currentText();
273     rc.licenseTemplatePath = licenseTemplatePath();
274     return rc;
275 }
276
277 QString CppFileSettingsWidget::searchKeywords() const
278 {
279     QString rc;
280     QTextStream(&rc) << m_ui->headerSuffixLabel->text()
281             << ' ' << m_ui->sourceSuffixLabel->text()
282             << ' ' << m_ui->lowerCaseFileNamesCheckBox->text()
283             << ' ' << m_ui->licenseTemplateLabel->text();
284     rc.remove(QLatin1Char('&'));
285     return rc;
286 }
287
288 static inline void setComboText(QComboBox *cb, const QString &text, int defaultIndex = 0)
289 {
290     const int index = cb->findText(text);
291     cb->setCurrentIndex(index == -1 ? defaultIndex: index);
292 }
293
294 void CppFileSettingsWidget::setSettings(const CppFileSettings &s)
295 {
296     m_ui->lowerCaseFileNamesCheckBox->setChecked(s.lowerCaseFiles);
297     setComboText(m_ui->headerSuffixComboBox, s.headerSuffix);
298     setComboText(m_ui->sourceSuffixComboBox, s.sourceSuffix);
299     setLicenseTemplatePath(s.licenseTemplatePath);
300 }
301
302 void CppFileSettingsWidget::slotEdit()
303 {
304     QString path = licenseTemplatePath();
305     // Edit existing file with C++
306     if (!path.isEmpty()) {
307         Core::EditorManager::instance()->openEditor(path, QLatin1String(CppEditor::Constants::CPPEDITOR_ID),
308                                                     Core::EditorManager::ModeSwitch);
309         return;
310     }
311     // Pick a file name and write new template, edit with C++
312     path = QFileDialog::getSaveFileName(this, tr("Choose Location for New License Template File"));
313     if (path.isEmpty())
314         return;
315     QFile file(path);
316     if (!file.open(QIODevice::WriteOnly|QIODevice::Text|QIODevice::Truncate)) {
317         QMessageBox::warning(this, tr("Template write error"),
318                              tr("Cannot write to %1: %2").arg(path, file.errorString()));
319         return;
320     }
321     file.write(tr(licenseTemplateTemplate).toUtf8());
322     file.close();
323     setLicenseTemplatePath(path);
324     Core::EditorManager::instance()->openEditor(path, QLatin1String(CppEditor::Constants::CPPEDITOR_ID),
325                                                 Core::EditorManager::ModeSwitch);
326 }
327
328 // --------------- CppFileSettingsPage
329 CppFileSettingsPage::CppFileSettingsPage(QSharedPointer<CppFileSettings> &settings,
330                                          QObject *parent) :
331     Core::IOptionsPage(parent),
332     m_settings(settings)
333 {
334 }
335
336 CppFileSettingsPage::~CppFileSettingsPage()
337 {
338 }
339
340 QString CppFileSettingsPage::id() const
341 {
342     return QLatin1String(Constants::CPP_SETTINGS_ID);
343 }
344
345 QString CppFileSettingsPage::displayName() const
346 {
347     return QCoreApplication::translate("CppTools", Constants::CPP_SETTINGS_NAME);
348 }
349
350 QString CppFileSettingsPage::category() const
351 {
352     return QLatin1String(Constants::CPP_SETTINGS_CATEGORY);
353 }
354
355 QString CppFileSettingsPage::displayCategory() const
356 {
357     return QCoreApplication::translate("CppTools", Constants::CPP_SETTINGS_TR_CATEGORY);
358 }
359
360 QIcon CppFileSettingsPage::categoryIcon() const
361 {
362     return QIcon(QLatin1String(Constants::SETTINGS_CATEGORY_CPP_ICON));
363 }
364
365 QWidget *CppFileSettingsPage::createPage(QWidget *parent)
366 {
367
368     m_widget = new CppFileSettingsWidget(parent);
369     m_widget->setSettings(*m_settings);
370     if (m_searchKeywords.isEmpty())
371         m_searchKeywords = m_widget->searchKeywords();
372     return m_widget;
373 }
374
375 void CppFileSettingsPage::apply()
376 {
377     if (m_widget) {
378         const CppFileSettings newSettings = m_widget->settings();
379         if (newSettings != *m_settings) {
380             *m_settings = newSettings;
381             m_settings->toSettings(Core::ICore::instance()->settings());
382             m_settings->applySuffixesToMimeDB();
383         }
384     }
385 }
386
387 bool CppFileSettingsPage::matches(const QString &s) const
388 {
389     return m_searchKeywords.contains(s, Qt::CaseInsensitive);
390 }
391
392 } // namespace Internal
393 } // namespace CppTools