source: trunk/examples/sql/masterdetail/mainwindow.cpp@ 440

Last change on this file since 440 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 13.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the examples of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "mainwindow.h"
43#include "dialog.h"
44
45#include <QtGui>
46#include <QtSql>
47#include <QtXml>
48
49extern int uniqueAlbumId;
50extern int uniqueArtistId;
51
52MainWindow::MainWindow(const QString &artistTable, const QString &albumTable,
53 QFile *albumDetails, QWidget *parent)
54 : QMainWindow(parent)
55{
56 file = albumDetails;
57 readAlbumData();
58
59 model = new QSqlRelationalTableModel(this);
60 model->setTable(albumTable);
61 model->setRelation(2, QSqlRelation(artistTable, "id", "artist"));
62 model->select();
63
64 QGroupBox *artists = createArtistGroupBox();
65 QGroupBox *albums = createAlbumGroupBox();
66 QGroupBox *details = createDetailsGroupBox();
67
68 artistView->setCurrentIndex(0);
69 uniqueAlbumId = model->rowCount();
70 uniqueArtistId = artistView->count();
71
72 connect(model, SIGNAL(rowsInserted(QModelIndex, int, int)),
73 this, SLOT(updateHeader(QModelIndex, int, int)));
74 connect(model, SIGNAL(rowsRemoved(QModelIndex, int, int)),
75 this, SLOT(updateHeader(QModelIndex, int, int)));
76
77 QGridLayout *layout = new QGridLayout;
78 layout->addWidget(artists, 0, 0);
79 layout->addWidget(albums, 1, 0);
80 layout->addWidget(details, 0, 1, 2, 1);
81 layout->setColumnStretch(1, 1);
82 layout->setColumnMinimumWidth(0, 500);
83
84 QWidget *widget = new QWidget;
85 widget->setLayout(layout);
86 setCentralWidget(widget);
87 createMenuBar();
88
89 showImageLabel();
90 resize(850, 400);
91 setWindowTitle(tr("Music Archive"));
92}
93
94void MainWindow::changeArtist(int row)
95{
96 if (row > 0) {
97 QModelIndex index = model->relationModel(2)->index(row, 1);
98 model->setFilter("artist = '" + index.data().toString() + '\'') ;
99 showArtistProfile(index);
100 } else if (row == 0) {
101 model->setFilter(QString());
102 showImageLabel();
103 } else {
104 return;
105 }
106}
107
108void MainWindow::showArtistProfile(QModelIndex index)
109{
110 QSqlRecord record = model->relationModel(2)->record(index.row());
111
112 QString name = record.value("artist").toString();
113 QString count = record.value("albumcount").toString();
114 profileLabel->setText(tr("Artist : %1 \n" \
115 "Number of Albums: %2").arg(name).arg(count));
116
117 profileLabel->show();
118 iconLabel->show();
119
120 titleLabel->hide();
121 trackList->hide();
122 imageLabel->hide();
123}
124
125void MainWindow::showAlbumDetails(QModelIndex index)
126{
127 QSqlRecord record = model->record(index.row());
128
129 QString artist = record.value("artist").toString();
130 QString title = record.value("title").toString();
131 QString year = record.value("year").toString();
132 QString albumId = record.value("albumid").toString();
133
134 showArtistProfile(indexOfArtist(artist));
135 titleLabel->setText(tr("Title: %1 (%2)").arg(title).arg(year));
136 titleLabel->show();
137
138 QDomNodeList albums = albumData.elementsByTagName("album");
139 for (int i = 0; i < albums.count(); i++) {
140 QDomNode album = albums.item(i);
141 if (album.toElement().attribute("id") == albumId) {
142 getTrackList(album.toElement());
143 break;
144 }
145 }
146 if (!trackList->count() == 0)
147 trackList->show();
148}
149
150void MainWindow::getTrackList(QDomNode album)
151{
152 trackList->clear();
153
154 QDomNodeList tracks = album.childNodes();
155 QDomNode track;
156 QString trackNumber;
157
158 for (int j = 0; j < tracks.count(); j++) {
159
160 track = tracks.item(j);
161 trackNumber = track.toElement().attribute("number");
162
163 QListWidgetItem *item = new QListWidgetItem(trackList);
164 item->setText(trackNumber + ": " + track.toElement().text());
165 }
166}
167
168void MainWindow::addAlbum()
169{
170 Dialog *dialog = new Dialog(model, albumData, file, this);
171 int accepted = dialog->exec();
172
173 if (accepted == 1) {
174 int lastRow = model->rowCount() - 1;
175 albumView->selectRow(lastRow);
176 albumView->scrollToBottom();
177 showAlbumDetails(model->index(lastRow, 0));
178 }
179}
180
181void MainWindow::deleteAlbum()
182{
183 QModelIndexList selection = albumView->selectionModel()->selectedRows(0);
184
185 if (!selection.empty()) {
186 QModelIndex idIndex = selection.at(0);
187 int id = idIndex.data().toInt();
188 QString title = idIndex.sibling(idIndex.row(), 1).data().toString();
189 QString artist = idIndex.sibling(idIndex.row(), 2).data().toString();
190
191 QMessageBox::StandardButton button;
192 button = QMessageBox::question(this, tr("Delete Album"),
193 QString(tr("Are you sure you want to " \
194 "delete '%1' by '%2'?"))
195 .arg(title).arg(artist),
196 QMessageBox::Yes | QMessageBox::No);
197
198 if (button == QMessageBox::Yes) {
199 removeAlbumFromFile(id);
200 removeAlbumFromDatabase(idIndex);
201 decreaseAlbumCount(indexOfArtist(artist));
202
203 showImageLabel();
204 }
205 } else {
206 QMessageBox::information(this, tr("Delete Album"),
207 tr("Select the album you want to delete."));
208 }
209}
210
211void MainWindow::removeAlbumFromFile(int id)
212{
213
214 QDomNodeList albums = albumData.elementsByTagName("album");
215
216 for (int i = 0; i < albums.count(); i++) {
217 QDomNode node = albums.item(i);
218 if (node.toElement().attribute("id").toInt() == id) {
219 albumData.elementsByTagName("archive").item(0).removeChild(node);
220 break;
221 }
222 }
223/*
224 The following code is commented out since the example uses an in
225 memory database, i.e., altering the XML file will bring the data
226 out of sync.
227
228 if (!file->open(QIODevice::WriteOnly)) {
229 return;
230 } else {
231 QTextStream stream(file);
232 albumData.elementsByTagName("archive").item(0).save(stream, 4);
233 file->close();
234 }
235*/
236}
237
238void MainWindow::removeAlbumFromDatabase(QModelIndex index)
239{
240 model->removeRow(index.row());
241}
242
243void MainWindow::decreaseAlbumCount(QModelIndex artistIndex)
244{
245 int row = artistIndex.row();
246 QModelIndex albumCountIndex = artistIndex.sibling(row, 2);
247 int albumCount = albumCountIndex.data().toInt();
248
249 QSqlTableModel *artists = model->relationModel(2);
250
251 if (albumCount == 1) {
252 artists->removeRow(row);
253 showImageLabel();
254 } else {
255 artists->setData(albumCountIndex, QVariant(albumCount - 1));
256 }
257}
258
259void MainWindow::readAlbumData()
260{
261 if (!file->open(QIODevice::ReadOnly))
262 return;
263
264 if (!albumData.setContent(file)) {
265 file->close();
266 return;
267 }
268 file->close();
269}
270
271QGroupBox* MainWindow::createArtistGroupBox()
272{
273 artistView = new QComboBox;
274 artistView->setModel(model->relationModel(2));
275 artistView->setModelColumn(1);
276
277 connect(artistView, SIGNAL(currentIndexChanged(int)),
278 this, SLOT(changeArtist(int)));
279
280 QGroupBox *box = new QGroupBox(tr("Artist"));
281
282 QGridLayout *layout = new QGridLayout;
283 layout->addWidget(artistView, 0, 0);
284 box->setLayout(layout);
285
286 return box;
287}
288
289QGroupBox* MainWindow::createAlbumGroupBox()
290{
291 QGroupBox *box = new QGroupBox(tr("Album"));
292
293 albumView = new QTableView;
294 albumView->setEditTriggers(QAbstractItemView::NoEditTriggers);
295 albumView->setSortingEnabled(true);
296 albumView->setSelectionBehavior(QAbstractItemView::SelectRows);
297 albumView->setSelectionMode(QAbstractItemView::SingleSelection);
298 albumView->setShowGrid(false);
299 albumView->verticalHeader()->hide();
300 albumView->setAlternatingRowColors(true);
301 albumView->setModel(model);
302 adjustHeader();
303
304 QLocale locale = albumView->locale();
305 locale.setNumberOptions(QLocale::OmitGroupSeparator);
306 albumView->setLocale(locale);
307
308 connect(albumView, SIGNAL(clicked(QModelIndex)),
309 this, SLOT(showAlbumDetails(QModelIndex)));
310 connect(albumView, SIGNAL(activated(QModelIndex)),
311 this, SLOT(showAlbumDetails(QModelIndex)));
312
313 QVBoxLayout *layout = new QVBoxLayout;
314 layout->addWidget(albumView, 0, 0);
315 box->setLayout(layout);
316
317 return box;
318}
319
320QGroupBox* MainWindow::createDetailsGroupBox()
321{
322 QGroupBox *box = new QGroupBox(tr("Details"));
323
324 profileLabel = new QLabel;
325 profileLabel->setWordWrap(true);
326 profileLabel->setAlignment(Qt::AlignBottom);
327
328 titleLabel = new QLabel;
329 titleLabel->setWordWrap(true);
330 titleLabel->setAlignment(Qt::AlignBottom);
331
332 iconLabel = new QLabel();
333 iconLabel->setAlignment(Qt::AlignBottom | Qt::AlignRight);
334 iconLabel->setPixmap(QPixmap(":/images/icon.png"));
335
336 imageLabel = new QLabel;
337 imageLabel->setWordWrap(true);
338 imageLabel->setAlignment(Qt::AlignCenter);
339 imageLabel->setPixmap(QPixmap(":/images/image.png"));
340
341 trackList = new QListWidget;
342
343 QGridLayout *layout = new QGridLayout;
344 layout->addWidget(imageLabel, 0, 0, 3, 2);
345 layout->addWidget(profileLabel, 0, 0);
346 layout->addWidget(iconLabel, 0, 1);
347 layout->addWidget(titleLabel, 1, 0, 1, 2);
348 layout->addWidget(trackList, 2, 0, 1, 2);
349 layout->setRowStretch(2, 1);
350 box->setLayout(layout);
351
352 return box;
353}
354
355void MainWindow::createMenuBar()
356{
357 QAction *addAction = new QAction(tr("&Add album..."), this);
358 QAction *deleteAction = new QAction(tr("&Delete album..."), this);
359 QAction *quitAction = new QAction(tr("&Quit"), this);
360 QAction *aboutAction = new QAction(tr("&About"), this);
361 QAction *aboutQtAction = new QAction(tr("About &Qt"), this);
362
363 addAction->setShortcut(tr("Ctrl+A"));
364 deleteAction->setShortcut(tr("Ctrl+D"));
365 quitAction->setShortcut(tr("Ctrl+Q"));
366
367 QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
368 fileMenu->addAction(addAction);
369 fileMenu->addAction(deleteAction);
370 fileMenu->addSeparator();
371 fileMenu->addAction(quitAction);
372
373 QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
374 helpMenu->addAction(aboutAction);
375 helpMenu->addAction(aboutQtAction);
376
377 connect(addAction, SIGNAL(triggered(bool)), this, SLOT(addAlbum()));
378 connect(deleteAction, SIGNAL(triggered(bool)), this, SLOT(deleteAlbum()));
379 connect(quitAction, SIGNAL(triggered(bool)), this, SLOT(close()));
380 connect(aboutAction, SIGNAL(triggered(bool)), this, SLOT(about()));
381 connect(aboutQtAction, SIGNAL(triggered(bool)), qApp, SLOT(aboutQt()));
382}
383
384void MainWindow::showImageLabel()
385{
386 profileLabel->hide();
387 titleLabel->hide();
388 iconLabel->hide();
389 trackList->hide();
390
391 imageLabel->show();
392}
393
394QModelIndex MainWindow::indexOfArtist(const QString &artist)
395{
396 QSqlTableModel *artistModel = model->relationModel(2);
397
398 for (int i = 0; i < artistModel->rowCount(); i++) {
399 QSqlRecord record = artistModel->record(i);
400 if (record.value("artist") == artist)
401 return artistModel->index(i, 1);
402 }
403 return QModelIndex();
404}
405
406void MainWindow::updateHeader(QModelIndex, int, int)
407{
408 adjustHeader();
409}
410
411void MainWindow::adjustHeader()
412{
413 albumView->hideColumn(0);
414 albumView->horizontalHeader()->setResizeMode(1, QHeaderView::Stretch);
415 albumView->resizeColumnToContents(2);
416 albumView->resizeColumnToContents(3);
417}
418
419void MainWindow::about()
420{
421 QMessageBox::about(this, tr("About Music Archive"),
422 tr("<p>The <b>Music Archive</b> example shows how to present "
423 "data from different data sources in the same application. "
424 "The album titles, and the corresponding artists and release dates, "
425 "are kept in a database, while each album's tracks are stored "
426 "in an XML file. </p><p>The example also shows how to add as "
427 "well as remove data from both the database and the "
428 "associated XML file using the API provided by the QtSql and "
429 "QtXml modules, respectively.</p>"));
430}
Note: See TracBrowser for help on using the repository browser.