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

Last change on this file since 1165 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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