Warning: That file was not part of the compilation database. It may have many parsing errors.

1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the tools applications of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
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, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "graphics.h"
43#include "feature.h"
44#include "featuretreemodel.h"
45
46#include <QtGui>
47
48QT_BEGIN_NAMESPACE
49
50static QString defaultPath;
51
52class FeatureTextBrowser : public QTextBrowser {
53 Q_OBJECT
54public:
55 FeatureTextBrowser(QWidget *parent) : QTextBrowser(parent) {
56 QString docRoot;
57 docRoot = QLibraryInfo::location(QLibraryInfo::DocumentationPath)
58 + "/html";
59 setSearchPaths(searchPaths() << docRoot);
60 }
61
62signals:
63 void featureClicked(const QString &feature);
64
65public slots:
66 void setSource(const QUrl &url)
67 {
68 if (url.scheme() == "feature")
69 emit featureClicked(url.authority());
70 else
71 QTextBrowser::setSource(url);
72 }
73};
74
75class Main : public QMainWindow {
76 Q_OBJECT
77public:
78 Main();
79 ~Main();
80 void loadFeatures(const QString& filename);
81 void loadConfig(const QString& filename);
82
83public slots:
84 void modelChanged();
85 void showInfo(const QModelIndex &index);
86 void showInfo(const QString &feature);
87 void openConfig();
88 void saveConfig();
89 void expandView();
90 void collapseView();
91 void about();
92 void aboutQt();
93 void quit();
94 void clear();
95 void enableAll();
96 void disableAll();
97
98private:
99 QTextBrowser *textBrowser;
100 QTreeView *featureTree;
101 FeatureTreeModel *featureModel;
102
103 void init();
104 void updateStatus(int numFeatures = -1);
105 void completelyExpandIndex(const QModelIndex &parent);
106};
107
108template<typename Func>
109void foreachIndex_helper(const QModelIndex &parent, Func func)
110{
111 const QAbstractItemModel *model = parent.model();
112 const int rows = model->rowCount(parent);
113 for (int i = 0; i < rows; ++i) {
114 const QModelIndex child = model->index(i, 0, parent);
115 func(child);
116 foreachIndex_helper(child, func);
117 }
118}
119
120template<typename Func>
121void foreachIndex(const QAbstractItemModel *model, Func func)
122{
123 const int rows = model->rowCount(QModelIndex());
124 for (int i = 0; i < rows; ++i) {
125 const QModelIndex child = model->index(i, 0, QModelIndex());
126 func(child);
127 foreachIndex_helper(child, func);
128 }
129}
130
131struct CheckStateSetter {
132
133 CheckStateSetter(Qt::CheckState state, QAbstractItemModel *m)
134 : checkState(state), model(m) {}
135
136 void operator()(const QModelIndex &index) {
137 model->setData(index, checkState, Qt::CheckStateRole);
138 }
139
140 Qt::CheckState checkState;
141 QAbstractItemModel *model;
142};
143
144void Main::disableAll()
145{
146 QAbstractItemModel *model = featureTree->model();
147 foreachIndex(model, CheckStateSetter(Qt::Unchecked, model));
148}
149
150void Main::enableAll()
151{
152 QAbstractItemModel *model = featureTree->model();
153 foreachIndex(model, CheckStateSetter(Qt::Checked, model));
154}
155
156Main::Main()
157{
158 setWindowIcon(QIcon(QPixmap(logo_xpm)));
159
160 QSplitter *splitter = new QSplitter(this);
161
162 featureModel = new FeatureTreeModel(this);
163 featureTree = new QTreeView(splitter);
164 splitter->addWidget(featureTree);
165 featureTree->setRootIsDecorated(true);
166 featureTree->setModel(featureModel);
167 featureTree->show();
168
169 textBrowser = new FeatureTextBrowser(splitter);
170 textBrowser->setFrameStyle(QFrame::WinPanel|QFrame::Sunken);
171 splitter->addWidget(textBrowser);
172 textBrowser->show();
173
174 connect(textBrowser, SIGNAL(featureClicked(QString)),
175 this, SLOT(showInfo(QString)));
176 connect(featureTree, SIGNAL(activated(QModelIndex)),
177 this, SLOT(showInfo(QModelIndex)));
178 connect(featureModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
179 this, SLOT(modelChanged()));
180 connect(featureTree, SIGNAL(clicked(QModelIndex)),
181 this, SLOT(showInfo(QModelIndex)));
182
183 setCentralWidget(splitter);
184
185 QMenu *file = menuBar()->addMenu("&File");
186 file->addAction("&Open...", this, SLOT(openConfig()),
187 Qt::CTRL + Qt::Key_O);
188 file->addAction("&Save As...", this, SLOT(saveConfig()),
189 Qt::CTRL + Qt::Key_S);
190 file->addSeparator();
191 file->addAction("&Reset", this, SLOT(clear()));
192 file->addSeparator();
193 file->addAction("E&xit", this, SLOT(quit()), Qt::CTRL + Qt::Key_Q);
194
195 QMenu *edit = menuBar()->addMenu("&Tools");
196 edit->addAction("&Enable all features", this, SLOT(enableAll()));
197 edit->addAction("&Disable all features", this, SLOT(disableAll()));
198
199 menuBar()->addSeparator();
200
201 QMenu *help = menuBar()->addMenu("&Help");
202 help->addAction("&About", this, SLOT(about()));
203 help->addAction("About &Qt", this, SLOT(aboutQt()));
204
205 QToolBar *tb = new QToolBar("Expand/Collapse features");
206 QToolButton *button;
207
208 button = new QToolButton(tb);
209 button->setIcon(QIcon(QPixmap(collapsed_xpm)));
210 button->setText("Collapse");
211 button->setToolTip("Collapse");
212 connect(button, SIGNAL(clicked()), this, SLOT(collapseView()));
213 tb->addWidget(button);
214
215 button = new QToolButton(tb);
216 button->setIcon(QIcon(QPixmap(expanded_xpm)));
217 button->setText("Expand");
218 button->setToolTip("Expand");
219 connect(button, SIGNAL(clicked()), this, SLOT(expandView()));
220 tb->addWidget(button);
221 addToolBar(tb);
222
223 init();
224}
225
226Main::~Main()
227{
228 delete textBrowser;
229 delete featureModel;
230 delete featureTree;
231}
232
233void Main::clear()
234{
235 QSettings settings;
236 settings.clear();
237 featureModel->clear();
238 featureTree->reset();
239 init();
240}
241
242void Main::quit()
243{
244 if (isWindowModified()) {
245 int button = QMessageBox::question(this, "Quit Program",
246 "You have unsaved changes.\n"
247 "Do you want to quit anyway?",
248 QMessageBox::Yes,
249 QMessageBox::No);
250 if (static_cast<QMessageBox::Button>(button) != QMessageBox::Yes)
251 return;
252 }
253 QApplication::instance()->quit();
254}
255
256/*
257 Recursively expand expand \a parent and all of its children.
258*/
259void Main::completelyExpandIndex(const QModelIndex &parent)
260{
261 featureTree->setExpanded(parent, true);
262
263 const QAbstractItemModel *model = featureTree->model();
264 const int rows = model->rowCount(parent);
265 for (int i = 0; i < rows; ++i)
266 completelyExpandIndex(model->index(i, 0, parent));
267}
268
269void Main::expandView()
270{
271 completelyExpandIndex(QModelIndex());
272}
273
274void Main::collapseView()
275{
276 const QAbstractItemModel *model = featureTree->model();
277 const int rows = model->rowCount(QModelIndex());
278 for (int i = 0; i < rows; ++i) {
279 QModelIndex index = model->index(i, 0, QModelIndex());
280 featureTree->setExpanded(index, false);
281 }
282}
283
284void Main::updateStatus(int numFeatures)
285{
286 QSettings settings;
287 QString featureFile = settings.value("featureFile").toString();
288 QString configFile = settings.value("lastConfig").toString();
289 QString message("Using features from %1");
290
291 if (numFeatures >= 0) {
292 QString s("%1 features loaded from %2");
293 statusBar()->showMessage(s.arg(numFeatures).arg(featureFile));
294 }
295 QString appName = QApplication::applicationName();
296 if (configFile.isEmpty())
297 configFile = "New File";
298 setWindowTitle(appName + " - " + configFile + "[*]");
299}
300
301void Main::modelChanged()
302{
303 setWindowModified(true);
304}
305
306void Main::init()
307{
308 QSettings settings;
309 QString features = settings.value("featureFile").toString();
310
311 if (features.isEmpty() || !QFileInfo(features).isFile()) {
312 features = QFileDialog::getOpenFileName(this,
313 "Open a feature file",
314 defaultPath,
315 "Qt Features (qfeatures.txt)");
316 }
317 settings.setValue("featureFile", features);
318 loadFeatures(features);
319
320 expandView();
321 collapseView();
322
323 QString confFile = settings.value("lastConfig").toString();
324 if (confFile.isEmpty())
325 return;
326 loadConfig(confFile);
327}
328
329void Main::openConfig()
330{
331 QSettings settings;
332 QString configDir;
333
334 QString prevFile = settings.value("lastConfig").toString();
335 if (!prevFile.isEmpty())
336 configDir = QFileInfo(prevFile).path();
337
338 if (configDir.isEmpty())
339 configDir = defaultPath;
340
341 QString configFile;
342 configFile = QFileDialog::getOpenFileName(this,
343 "Open a configuration file",
344 configDir,
345 "Header files (*.h)");
346 enableAll();
347 if (!configFile.isEmpty())
348 loadConfig(configFile);
349 settings.setValue("lastConfig", QFileInfo(configFile).absoluteFilePath());
350}
351
352void Main::saveConfig()
353{
354 QSettings settings;
355 QString configDir;
356
357 QString prevFile = settings.value("lastConfig").toString();
358 if (!prevFile.isEmpty())
359 configDir = QFileInfo(prevFile).path();
360
361 if (configDir.isEmpty())
362 configDir = defaultPath;
363
364 QString configFile;
365 configFile = QFileDialog::getSaveFileName(this,
366 "Save configuration file",
367 configDir,
368 "Header files (*.h)");
369 if (configFile.isEmpty())
370 return;
371
372 QFile file(configFile);
373 if (!file.open(QIODevice::WriteOnly)) {
374 QMessageBox::warning(this,"Warning",
375 "Cannot write to file " + configFile);
376 return;
377 }
378
379 QTextStream stream(&file);
380 FeatureTreeModel *model;
381 model = static_cast<FeatureTreeModel*>(featureTree->model());
382 model->writeConfig(stream);
383
384 settings.setValue("lastConfig", QFileInfo(configFile).absoluteFilePath());
385 setWindowModified(false);
386 updateStatus();
387}
388
389void Main::loadConfig(const QString &filename)
390{
391 if (!QFileInfo(filename).isFile())
392 return;
393
394 QFile file(filename);
395 if (!file.open(QIODevice::ReadOnly)) {
396 QMessageBox::warning(this,"Warning", "Cannot open file " + filename);
397 return;
398 }
399
400 QTextStream stream(&file);
401 FeatureTreeModel *model;
402 model = static_cast<FeatureTreeModel*>(featureTree->model());
403 model->readConfig(stream);
404
405 QSettings settings;
406 settings.setValue("lastConfig", QFileInfo(filename).absoluteFilePath());
407 setWindowModified(false);
408 updateStatus();
409}
410
411void Main::loadFeatures(const QString &filename)
412{
413 Feature::clear();
414
415 QFile file(filename);
416 if (!file.open(QIODevice::ReadOnly)) {
417 QMessageBox::warning(this,"Warning", "Cannot open file " + filename);
418 return;
419 }
420
421 Feature *feature = 0;
422 int numFeatures = 0;
423 updateStatus(numFeatures);
424 QTextStream s(&file);
425 for (QString line = s.readLine(); !s.atEnd(); line = s.readLine()) {
426 line = line.simplified();
427 if (line.isEmpty())
428 continue;
429 if (line.startsWith('#'))
430 continue;
431
432 int colon = line.indexOf(':');
433 if (colon < 0) { // assume description
434 QString description = feature->description().simplified();
435 description += " " + line;
436 feature->setDescription(description);
437 continue;
438 }
439
440 QString tag = line.left(colon);
441 QString value = line.mid(colon+1).simplified();
442 if (tag == "Feature") {
443 if (feature)
444 featureModel->addFeature(feature);
445 feature = Feature::getInstance(value);
446 updateStatus(++numFeatures);
447 } else if (tag == "Requires") {
448 Q_ASSERT(feature);
449 feature->setDependencies(value.split(' ', QString::SkipEmptyParts));
450 } else if (tag == "Name") {
451 Q_ASSERT(feature);
452 feature->setTitle(value);
453 } else if (tag == "Section") {
454 Q_ASSERT(feature);
455 feature->setSection(value);
456 } else if (tag == "SeeAlso") {
457 Q_ASSERT(feature);
458 feature->setRelations(value.split(' ', QString::SkipEmptyParts));
459 } else if (tag == "Description") {
460 Q_ASSERT(feature);
461 feature->setDescription(value);
462 }
463 }
464 if (feature)
465 featureModel->addFeature(feature);
466
467 featureTree->resizeColumnToContents(0);
468
469 QSettings settings;
470 settings.setValue("featureFile", QFileInfo(filename).absoluteFilePath());
471
472 updateStatus();
473}
474
475void Main::showInfo(const QModelIndex &index)
476{
477 FeatureTreeModel *model;
478 model = static_cast<FeatureTreeModel*>(featureTree->model());
479
480 if (const Feature *feature = model->getFeature(index))
481 textBrowser->setHtml(feature->toHtml());
482
483 // Ensure index is visible
484 QModelIndex parent = model->parent(index);
485 while (parent.isValid()) {
486 featureTree->setExpanded(parent, true);
487 parent = model->parent(parent);
488 }
489
490 featureTree->scrollTo(index);
491 featureTree->setCurrentIndex(index);
492}
493
494void Main::showInfo(const QString &feature)
495{
496 const Feature *f = Feature::getInstance(feature);
497 FeatureTreeModel *model;
498 model = static_cast<FeatureTreeModel*>(featureTree->model());
499 showInfo(model->index(f));
500}
501
502void Main::about()
503{
504 QMessageBox::about(this, "About qconfig",
505 "<p><b><font size=\"+2\">Qtopia Core build configuration</font></b></p>"
506 "<p></p>"
507 "<p>Version 2.0</p>"
508 "<p>Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).</p>"
509 "<p></p>"
510 );
511}
512
513void Main::aboutQt()
514{
515 QMessageBox::aboutQt( this, tr("qconfig") );
516}
517
518QT_END_NAMESPACE
519
520int main(int argc, char** argv)
521{
522 QT_USE_NAMESPACE
523 QApplication app(argc,argv);
524 app.setOrganizationDomain("digia.com");
525 app.setOrganizationName("Digia");
526 app.setApplicationName("QConfig");
527 Main m;
528
529 defaultPath = QLibraryInfo::location(QLibraryInfo::PrefixPath)
530 + "/src/corelib/global";
531
532 for (int i = 1; i < argc; ++i) {
533 QString arg = argv[i];
534 if (arg == "-f" && i+1 < argc)
535 m.loadFeatures(argv[++i]);
536 else if (arg == "-c" && i+1 < argc)
537 m.loadConfig(argv[++i]);
538 }
539 m.resize(m.sizeHint() + QSize(500,300));
540 m.show();
541 return app.exec();
542}
543
544#include "main.moc"
545

Warning: That file was not part of the compilation database. It may have many parsing errors.