|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the demonstration applications of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
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 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "mainwindow.h" |
|
43 #include "colorswatch.h" |
|
44 #include "toolbar.h" |
|
45 |
|
46 #include <QAction> |
|
47 #include <QLayout> |
|
48 #include <QMenu> |
|
49 #include <QMenuBar> |
|
50 #include <QStatusBar> |
|
51 #include <QTextEdit> |
|
52 #include <QFile> |
|
53 #include <QDataStream> |
|
54 #include <QFileDialog> |
|
55 #include <QMessageBox> |
|
56 #include <QSignalMapper> |
|
57 #include <QApplication> |
|
58 #include <QPainter> |
|
59 #include <QMouseEvent> |
|
60 #include <QLineEdit> |
|
61 #include <QComboBox> |
|
62 #include <QLabel> |
|
63 #include <QPushButton> |
|
64 #include <qdebug.h> |
|
65 |
|
66 static const char * const message = |
|
67 "<p><b>Qt Main Window Demo</b></p>" |
|
68 |
|
69 "<p>This is a demonstration of the QMainWindow, QToolBar and " |
|
70 "QDockWidget classes.</p>" |
|
71 |
|
72 "<p>The tool bar and dock widgets can be dragged around and rearranged " |
|
73 "using the mouse or via the menu.</p>" |
|
74 |
|
75 "<p>Each dock widget contains a colored frame and a context " |
|
76 "(right-click) menu.</p>" |
|
77 |
|
78 #ifdef Q_WS_MAC |
|
79 "<p>On Mac OS X, the \"Black\" dock widget has been created as a " |
|
80 "<em>Drawer</em>, which is a special kind of QDockWidget.</p>" |
|
81 #endif |
|
82 ; |
|
83 |
|
84 MainWindow::MainWindow(const QMap<QString, QSize> &customSizeHints, |
|
85 QWidget *parent, Qt::WindowFlags flags) |
|
86 : QMainWindow(parent, flags) |
|
87 { |
|
88 setObjectName("MainWindow"); |
|
89 setWindowTitle("Qt Main Window Demo"); |
|
90 |
|
91 center = new QTextEdit(this); |
|
92 center->setReadOnly(true); |
|
93 center->setMinimumSize(400, 205); |
|
94 setCentralWidget(center); |
|
95 |
|
96 setupToolBar(); |
|
97 setupMenuBar(); |
|
98 setupDockWidgets(customSizeHints); |
|
99 |
|
100 statusBar()->showMessage(tr("Status Bar")); |
|
101 } |
|
102 |
|
103 void MainWindow::actionTriggered(QAction *action) |
|
104 { |
|
105 qDebug("action '%s' triggered", action->text().toLocal8Bit().data()); |
|
106 } |
|
107 |
|
108 void MainWindow::setupToolBar() |
|
109 { |
|
110 for (int i = 0; i < 3; ++i) { |
|
111 ToolBar *tb = new ToolBar(QString::fromLatin1("Tool Bar %1").arg(i + 1), this); |
|
112 toolBars.append(tb); |
|
113 addToolBar(tb); |
|
114 } |
|
115 } |
|
116 |
|
117 void MainWindow::setupMenuBar() |
|
118 { |
|
119 QMenu *menu = menuBar()->addMenu(tr("&File")); |
|
120 |
|
121 QAction *action = menu->addAction(tr("Save layout...")); |
|
122 connect(action, SIGNAL(triggered()), this, SLOT(saveLayout())); |
|
123 |
|
124 action = menu->addAction(tr("Load layout...")); |
|
125 connect(action, SIGNAL(triggered()), this, SLOT(loadLayout())); |
|
126 |
|
127 action = menu->addAction(tr("Switch layout direction")); |
|
128 connect(action, SIGNAL(triggered()), this, SLOT(switchLayoutDirection())); |
|
129 |
|
130 menu->addSeparator(); |
|
131 |
|
132 menu->addAction(tr("&Quit"), this, SLOT(close())); |
|
133 |
|
134 mainWindowMenu = menuBar()->addMenu(tr("Main window")); |
|
135 |
|
136 action = mainWindowMenu->addAction(tr("Animated docks")); |
|
137 action->setCheckable(true); |
|
138 action->setChecked(dockOptions() & AnimatedDocks); |
|
139 connect(action, SIGNAL(toggled(bool)), this, SLOT(setDockOptions())); |
|
140 |
|
141 action = mainWindowMenu->addAction(tr("Allow nested docks")); |
|
142 action->setCheckable(true); |
|
143 action->setChecked(dockOptions() & AllowNestedDocks); |
|
144 connect(action, SIGNAL(toggled(bool)), this, SLOT(setDockOptions())); |
|
145 |
|
146 action = mainWindowMenu->addAction(tr("Allow tabbed docks")); |
|
147 action->setCheckable(true); |
|
148 action->setChecked(dockOptions() & AllowTabbedDocks); |
|
149 connect(action, SIGNAL(toggled(bool)), this, SLOT(setDockOptions())); |
|
150 |
|
151 action = mainWindowMenu->addAction(tr("Force tabbed docks")); |
|
152 action->setCheckable(true); |
|
153 action->setChecked(dockOptions() & ForceTabbedDocks); |
|
154 connect(action, SIGNAL(toggled(bool)), this, SLOT(setDockOptions())); |
|
155 |
|
156 action = mainWindowMenu->addAction(tr("Vertical tabs")); |
|
157 action->setCheckable(true); |
|
158 action->setChecked(dockOptions() & VerticalTabs); |
|
159 connect(action, SIGNAL(toggled(bool)), this, SLOT(setDockOptions())); |
|
160 |
|
161 QMenu *toolBarMenu = menuBar()->addMenu(tr("Tool bars")); |
|
162 for (int i = 0; i < toolBars.count(); ++i) |
|
163 toolBarMenu->addMenu(toolBars.at(i)->menu); |
|
164 |
|
165 dockWidgetMenu = menuBar()->addMenu(tr("&Dock Widgets")); |
|
166 } |
|
167 |
|
168 void MainWindow::setDockOptions() |
|
169 { |
|
170 DockOptions opts; |
|
171 QList<QAction*> actions = mainWindowMenu->actions(); |
|
172 |
|
173 if (actions.at(0)->isChecked()) |
|
174 opts |= AnimatedDocks; |
|
175 if (actions.at(1)->isChecked()) |
|
176 opts |= AllowNestedDocks; |
|
177 if (actions.at(2)->isChecked()) |
|
178 opts |= AllowTabbedDocks; |
|
179 if (actions.at(3)->isChecked()) |
|
180 opts |= ForceTabbedDocks; |
|
181 if (actions.at(4)->isChecked()) |
|
182 opts |= VerticalTabs; |
|
183 |
|
184 QMainWindow::setDockOptions(opts); |
|
185 } |
|
186 |
|
187 void MainWindow::saveLayout() |
|
188 { |
|
189 QString fileName |
|
190 = QFileDialog::getSaveFileName(this, tr("Save layout")); |
|
191 if (fileName.isEmpty()) |
|
192 return; |
|
193 QFile file(fileName); |
|
194 if (!file.open(QFile::WriteOnly)) { |
|
195 QString msg = tr("Failed to open %1\n%2") |
|
196 .arg(fileName) |
|
197 .arg(file.errorString()); |
|
198 QMessageBox::warning(this, tr("Error"), msg); |
|
199 return; |
|
200 } |
|
201 |
|
202 QByteArray geo_data = saveGeometry(); |
|
203 QByteArray layout_data = saveState(); |
|
204 |
|
205 bool ok = file.putChar((uchar)geo_data.size()); |
|
206 if (ok) |
|
207 ok = file.write(geo_data) == geo_data.size(); |
|
208 if (ok) |
|
209 ok = file.write(layout_data) == layout_data.size(); |
|
210 |
|
211 if (!ok) { |
|
212 QString msg = tr("Error writing to %1\n%2") |
|
213 .arg(fileName) |
|
214 .arg(file.errorString()); |
|
215 QMessageBox::warning(this, tr("Error"), msg); |
|
216 return; |
|
217 } |
|
218 } |
|
219 |
|
220 void MainWindow::loadLayout() |
|
221 { |
|
222 QString fileName |
|
223 = QFileDialog::getOpenFileName(this, tr("Load layout")); |
|
224 if (fileName.isEmpty()) |
|
225 return; |
|
226 QFile file(fileName); |
|
227 if (!file.open(QFile::ReadOnly)) { |
|
228 QString msg = tr("Failed to open %1\n%2") |
|
229 .arg(fileName) |
|
230 .arg(file.errorString()); |
|
231 QMessageBox::warning(this, tr("Error"), msg); |
|
232 return; |
|
233 } |
|
234 |
|
235 uchar geo_size; |
|
236 QByteArray geo_data; |
|
237 QByteArray layout_data; |
|
238 |
|
239 bool ok = file.getChar((char*)&geo_size); |
|
240 if (ok) { |
|
241 geo_data = file.read(geo_size); |
|
242 ok = geo_data.size() == geo_size; |
|
243 } |
|
244 if (ok) { |
|
245 layout_data = file.readAll(); |
|
246 ok = layout_data.size() > 0; |
|
247 } |
|
248 |
|
249 if (ok) |
|
250 ok = restoreGeometry(geo_data); |
|
251 if (ok) |
|
252 ok = restoreState(layout_data); |
|
253 |
|
254 if (!ok) { |
|
255 QString msg = tr("Error reading %1") |
|
256 .arg(fileName); |
|
257 QMessageBox::warning(this, tr("Error"), msg); |
|
258 return; |
|
259 } |
|
260 } |
|
261 |
|
262 QAction *addAction(QMenu *menu, const QString &text, QActionGroup *group, QSignalMapper *mapper, |
|
263 int id) |
|
264 { |
|
265 bool first = group->actions().isEmpty(); |
|
266 QAction *result = menu->addAction(text); |
|
267 result->setCheckable(true); |
|
268 result->setChecked(first); |
|
269 group->addAction(result); |
|
270 QObject::connect(result, SIGNAL(triggered()), mapper, SLOT(map())); |
|
271 mapper->setMapping(result, id); |
|
272 return result; |
|
273 } |
|
274 |
|
275 void MainWindow::setupDockWidgets(const QMap<QString, QSize> &customSizeHints) |
|
276 { |
|
277 mapper = new QSignalMapper(this); |
|
278 connect(mapper, SIGNAL(mapped(int)), this, SLOT(setCorner(int))); |
|
279 |
|
280 QMenu *corner_menu = dockWidgetMenu->addMenu(tr("Top left corner")); |
|
281 QActionGroup *group = new QActionGroup(this); |
|
282 group->setExclusive(true); |
|
283 ::addAction(corner_menu, tr("Top dock area"), group, mapper, 0); |
|
284 ::addAction(corner_menu, tr("Left dock area"), group, mapper, 1); |
|
285 |
|
286 corner_menu = dockWidgetMenu->addMenu(tr("Top right corner")); |
|
287 group = new QActionGroup(this); |
|
288 group->setExclusive(true); |
|
289 ::addAction(corner_menu, tr("Top dock area"), group, mapper, 2); |
|
290 ::addAction(corner_menu, tr("Right dock area"), group, mapper, 3); |
|
291 |
|
292 corner_menu = dockWidgetMenu->addMenu(tr("Bottom left corner")); |
|
293 group = new QActionGroup(this); |
|
294 group->setExclusive(true); |
|
295 ::addAction(corner_menu, tr("Bottom dock area"), group, mapper, 4); |
|
296 ::addAction(corner_menu, tr("Left dock area"), group, mapper, 5); |
|
297 |
|
298 corner_menu = dockWidgetMenu->addMenu(tr("Bottom right corner")); |
|
299 group = new QActionGroup(this); |
|
300 group->setExclusive(true); |
|
301 ::addAction(corner_menu, tr("Bottom dock area"), group, mapper, 6); |
|
302 ::addAction(corner_menu, tr("Right dock area"), group, mapper, 7); |
|
303 |
|
304 dockWidgetMenu->addSeparator(); |
|
305 |
|
306 static const struct Set { |
|
307 const char * name; |
|
308 uint flags; |
|
309 Qt::DockWidgetArea area; |
|
310 } sets [] = { |
|
311 #ifndef Q_WS_MAC |
|
312 { "Black", 0, Qt::LeftDockWidgetArea }, |
|
313 #else |
|
314 { "Black", Qt::Drawer, Qt::LeftDockWidgetArea }, |
|
315 #endif |
|
316 { "White", 0, Qt::RightDockWidgetArea }, |
|
317 { "Red", 0, Qt::TopDockWidgetArea }, |
|
318 { "Green", 0, Qt::TopDockWidgetArea }, |
|
319 { "Blue", 0, Qt::BottomDockWidgetArea }, |
|
320 { "Yellow", 0, Qt::BottomDockWidgetArea } |
|
321 }; |
|
322 const int setCount = sizeof(sets) / sizeof(Set); |
|
323 |
|
324 for (int i = 0; i < setCount; ++i) { |
|
325 ColorSwatch *swatch = new ColorSwatch(tr(sets[i].name), this, Qt::WindowFlags(sets[i].flags)); |
|
326 if (i%2) |
|
327 swatch->setWindowIcon(QIcon(QPixmap(":/res/qt.png"))); |
|
328 if (qstrcmp(sets[i].name, "Blue") == 0) { |
|
329 BlueTitleBar *titlebar = new BlueTitleBar(swatch); |
|
330 swatch->setTitleBarWidget(titlebar); |
|
331 connect(swatch, SIGNAL(topLevelChanged(bool)), titlebar, SLOT(updateMask())); |
|
332 connect(swatch, SIGNAL(featuresChanged(QDockWidget::DockWidgetFeatures)), titlebar, SLOT(updateMask())); |
|
333 |
|
334 #ifdef Q_WS_QWS |
|
335 QPalette pal = palette(); |
|
336 pal.setBrush(backgroundRole(), QColor(0,0,0,0)); |
|
337 swatch->setPalette(pal); |
|
338 #endif |
|
339 } |
|
340 |
|
341 QString name = QString::fromLatin1(sets[i].name); |
|
342 if (customSizeHints.contains(name)) |
|
343 swatch->setCustomSizeHint(customSizeHints.value(name)); |
|
344 |
|
345 addDockWidget(sets[i].area, swatch); |
|
346 dockWidgetMenu->addMenu(swatch->menu); |
|
347 } |
|
348 |
|
349 createDockWidgetAction = new QAction(tr("Add dock widget..."), this); |
|
350 connect(createDockWidgetAction, SIGNAL(triggered()), this, SLOT(createDockWidget())); |
|
351 destroyDockWidgetMenu = new QMenu(tr("Destroy dock widget"), this); |
|
352 destroyDockWidgetMenu->setEnabled(false); |
|
353 connect(destroyDockWidgetMenu, SIGNAL(triggered(QAction*)), this, SLOT(destroyDockWidget(QAction*))); |
|
354 |
|
355 dockWidgetMenu->addSeparator(); |
|
356 dockWidgetMenu->addAction(createDockWidgetAction); |
|
357 dockWidgetMenu->addMenu(destroyDockWidgetMenu); |
|
358 } |
|
359 |
|
360 void MainWindow::setCorner(int id) |
|
361 { |
|
362 switch (id) { |
|
363 case 0: |
|
364 QMainWindow::setCorner(Qt::TopLeftCorner, Qt::TopDockWidgetArea); |
|
365 break; |
|
366 case 1: |
|
367 QMainWindow::setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea); |
|
368 break; |
|
369 case 2: |
|
370 QMainWindow::setCorner(Qt::TopRightCorner, Qt::TopDockWidgetArea); |
|
371 break; |
|
372 case 3: |
|
373 QMainWindow::setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea); |
|
374 break; |
|
375 case 4: |
|
376 QMainWindow::setCorner(Qt::BottomLeftCorner, Qt::BottomDockWidgetArea); |
|
377 break; |
|
378 case 5: |
|
379 QMainWindow::setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea); |
|
380 break; |
|
381 case 6: |
|
382 QMainWindow::setCorner(Qt::BottomRightCorner, Qt::BottomDockWidgetArea); |
|
383 break; |
|
384 case 7: |
|
385 QMainWindow::setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea); |
|
386 break; |
|
387 } |
|
388 } |
|
389 |
|
390 void MainWindow::showEvent(QShowEvent *event) |
|
391 { |
|
392 QMainWindow::showEvent(event); |
|
393 } |
|
394 |
|
395 void MainWindow::switchLayoutDirection() |
|
396 { |
|
397 if (layoutDirection() == Qt::LeftToRight) |
|
398 qApp->setLayoutDirection(Qt::RightToLeft); |
|
399 else |
|
400 qApp->setLayoutDirection(Qt::LeftToRight); |
|
401 } |
|
402 |
|
403 class CreateDockWidgetDialog : public QDialog |
|
404 { |
|
405 public: |
|
406 CreateDockWidgetDialog(QWidget *parent = 0); |
|
407 |
|
408 QString objectName() const; |
|
409 Qt::DockWidgetArea location() const; |
|
410 |
|
411 private: |
|
412 QLineEdit *m_objectName; |
|
413 QComboBox *m_location; |
|
414 }; |
|
415 |
|
416 CreateDockWidgetDialog::CreateDockWidgetDialog(QWidget *parent) |
|
417 : QDialog(parent) |
|
418 { |
|
419 QGridLayout *layout = new QGridLayout(this); |
|
420 |
|
421 layout->addWidget(new QLabel(tr("Object name:")), 0, 0); |
|
422 m_objectName = new QLineEdit; |
|
423 layout->addWidget(m_objectName, 0, 1); |
|
424 |
|
425 layout->addWidget(new QLabel(tr("Location:")), 1, 0); |
|
426 m_location = new QComboBox; |
|
427 m_location->setEditable(false); |
|
428 m_location->addItem(tr("Top")); |
|
429 m_location->addItem(tr("Left")); |
|
430 m_location->addItem(tr("Right")); |
|
431 m_location->addItem(tr("Bottom")); |
|
432 m_location->addItem(tr("Restore")); |
|
433 layout->addWidget(m_location, 1, 1); |
|
434 |
|
435 QHBoxLayout *buttonLayout = new QHBoxLayout; |
|
436 layout->addLayout(buttonLayout, 2, 0, 1, 2); |
|
437 buttonLayout->addStretch(); |
|
438 |
|
439 QPushButton *cancelButton = new QPushButton(tr("Cancel")); |
|
440 connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); |
|
441 buttonLayout->addWidget(cancelButton); |
|
442 QPushButton *okButton = new QPushButton(tr("Ok")); |
|
443 connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); |
|
444 buttonLayout->addWidget(okButton); |
|
445 |
|
446 okButton->setDefault(true); |
|
447 } |
|
448 |
|
449 QString CreateDockWidgetDialog::objectName() const |
|
450 { |
|
451 return m_objectName->text(); |
|
452 } |
|
453 |
|
454 Qt::DockWidgetArea CreateDockWidgetDialog::location() const |
|
455 { |
|
456 switch (m_location->currentIndex()) { |
|
457 case 0: return Qt::TopDockWidgetArea; |
|
458 case 1: return Qt::LeftDockWidgetArea; |
|
459 case 2: return Qt::RightDockWidgetArea; |
|
460 case 3: return Qt::BottomDockWidgetArea; |
|
461 default: |
|
462 break; |
|
463 } |
|
464 return Qt::NoDockWidgetArea; |
|
465 } |
|
466 |
|
467 void MainWindow::createDockWidget() |
|
468 { |
|
469 CreateDockWidgetDialog dialog(this); |
|
470 int ret = dialog.exec(); |
|
471 if (ret == QDialog::Rejected) |
|
472 return; |
|
473 |
|
474 QDockWidget *dw = new QDockWidget; |
|
475 dw->setObjectName(dialog.objectName()); |
|
476 dw->setWindowTitle(dialog.objectName()); |
|
477 dw->setWidget(new QTextEdit); |
|
478 |
|
479 Qt::DockWidgetArea area = dialog.location(); |
|
480 switch (area) { |
|
481 case Qt::LeftDockWidgetArea: |
|
482 case Qt::RightDockWidgetArea: |
|
483 case Qt::TopDockWidgetArea: |
|
484 case Qt::BottomDockWidgetArea: |
|
485 addDockWidget(area, dw); |
|
486 break; |
|
487 default: |
|
488 if (!restoreDockWidget(dw)) { |
|
489 QMessageBox::warning(this, QString(), tr("Failed to restore dock widget")); |
|
490 delete dw; |
|
491 return; |
|
492 } |
|
493 break; |
|
494 } |
|
495 |
|
496 extraDockWidgets.append(dw); |
|
497 destroyDockWidgetMenu->setEnabled(true); |
|
498 destroyDockWidgetMenu->addAction(new QAction(dialog.objectName(), this)); |
|
499 } |
|
500 |
|
501 void MainWindow::destroyDockWidget(QAction *action) |
|
502 { |
|
503 int index = destroyDockWidgetMenu->actions().indexOf(action); |
|
504 delete extraDockWidgets.takeAt(index); |
|
505 destroyDockWidgetMenu->removeAction(action); |
|
506 action->deleteLater(); |
|
507 |
|
508 if (destroyDockWidgetMenu->isEmpty()) |
|
509 destroyDockWidgetMenu->setEnabled(false); |
|
510 } |