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 | |
48 | QT_BEGIN_NAMESPACE |
49 | |
50 | static QString defaultPath; |
51 | |
52 | class FeatureTextBrowser : public QTextBrowser { |
53 | Q_OBJECT |
54 | public: |
55 | FeatureTextBrowser(QWidget *parent) : QTextBrowser(parent) { |
56 | QString docRoot; |
57 | docRoot = QLibraryInfo::location(QLibraryInfo::DocumentationPath) |
58 | + "/html"; |
59 | setSearchPaths(searchPaths() << docRoot); |
60 | } |
61 | |
62 | signals: |
63 | void featureClicked(const QString &feature); |
64 | |
65 | public 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 | |
75 | class Main : public QMainWindow { |
76 | Q_OBJECT |
77 | public: |
78 | Main(); |
79 | ~Main(); |
80 | void loadFeatures(const QString& filename); |
81 | void loadConfig(const QString& filename); |
82 | |
83 | public 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 | |
98 | private: |
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 | |
108 | template<typename Func> |
109 | void 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 | |
120 | template<typename Func> |
121 | void 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 | |
131 | struct 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 | |
144 | void Main::disableAll() |
145 | { |
146 | QAbstractItemModel *model = featureTree->model(); |
147 | foreachIndex(model, CheckStateSetter(Qt::Unchecked, model)); |
148 | } |
149 | |
150 | void Main::enableAll() |
151 | { |
152 | QAbstractItemModel *model = featureTree->model(); |
153 | foreachIndex(model, CheckStateSetter(Qt::Checked, model)); |
154 | } |
155 | |
156 | Main::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 | |
226 | Main::~Main() |
227 | { |
228 | delete textBrowser; |
229 | delete featureModel; |
230 | delete featureTree; |
231 | } |
232 | |
233 | void Main::clear() |
234 | { |
235 | QSettings settings; |
236 | settings.clear(); |
237 | featureModel->clear(); |
238 | featureTree->reset(); |
239 | init(); |
240 | } |
241 | |
242 | void 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 | */ |
259 | void 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 | |
269 | void Main::expandView() |
270 | { |
271 | completelyExpandIndex(QModelIndex()); |
272 | } |
273 | |
274 | void 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 | |
284 | void 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 | |
301 | void Main::modelChanged() |
302 | { |
303 | setWindowModified(true); |
304 | } |
305 | |
306 | void 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 | |
329 | void 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 | |
352 | void 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 | |
389 | void 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 | |
411 | void 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( |
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( |
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 | |
475 | void 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 | |
494 | void 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 | |
502 | void 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 | |
513 | void Main::aboutQt() |
514 | { |
515 | QMessageBox::aboutQt( this, tr("qconfig") ); |
516 | } |
517 | |
518 | QT_END_NAMESPACE |
519 | |
520 | int 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.