1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the examples of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:BSD$
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 The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** BSD License Usage
18** Alternatively, you may use this file under the terms of the BSD license
19** as follows:
20**
21** "Redistribution and use in source and binary forms, with or without
22** modification, are permitted provided that the following conditions are
23** met:
24** * Redistributions of source code must retain the above copyright
25** notice, this list of conditions and the following disclaimer.
26** * Redistributions in binary form must reproduce the above copyright
27** notice, this list of conditions and the following disclaimer in
28** the documentation and/or other materials provided with the
29** distribution.
30** * Neither the name of The Qt Company Ltd nor the names of its
31** contributors may be used to endorse or promote products derived
32** from this software without specific prior written permission.
33**
34**
35** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46**
47** $QT_END_LICENSE$
48**
49****************************************************************************/
50
51#include "dialog.h"
52
53int uniqueAlbumId;
54int uniqueArtistId;
55
56Dialog::Dialog(QSqlRelationalTableModel *albums, QDomDocument details,
57 QFile *output, QWidget *parent)
58 : QDialog(parent)
59{
60 model = albums;
61 albumDetails = details;
62 outputFile = output;
63
64 QGroupBox *inputWidgetBox = createInputWidgets();
65 QDialogButtonBox *buttonBox = createButtons();
66
67 QVBoxLayout *layout = new QVBoxLayout;
68 layout->addWidget(inputWidgetBox);
69 layout->addWidget(buttonBox);
70 setLayout(layout);
71
72 setWindowTitle(tr("Add Album"));
73}
74
75void Dialog::submit()
76{
77 QString artist = artistEditor->text();
78 QString title = titleEditor->text();
79
80 if (artist.isEmpty() || title.isEmpty()) {
81 QString message(tr("Please provide both the name of the artist "
82 "and the title of the album."));
83 QMessageBox::information(this, tr("Add Album"), message);
84 } else {
85 int artistId = findArtistId(artist);
86 int albumId = addNewAlbum(title, artistId);
87
88 QStringList tracks;
89 tracks = tracksEditor->text().split(QLatin1Char(','), Qt::SkipEmptyParts);
90 addTracks(albumId, tracks);
91
92 increaseAlbumCount(indexOfArtist(artist));
93 accept();
94 }
95}
96
97int Dialog::findArtistId(const QString &artist)
98{
99 QSqlTableModel *artistModel = model->relationModel(2);
100 int row = 0;
101
102 while (row < artistModel->rowCount()) {
103 QSqlRecord record = artistModel->record(row);
104 if (record.value("artist") == artist)
105 return record.value("id").toInt();
106 else
107 row++;
108 }
109 return addNewArtist(artist);
110}
111
112
113int Dialog::addNewArtist(const QString &name)
114{
115 QSqlTableModel *artistModel = model->relationModel(2);
116 QSqlRecord record;
117
118 int id = generateArtistId();
119
120 QSqlField f1("id", QMetaType(QMetaType::Int));
121 QSqlField f2("artist", QMetaType(QMetaType::QString));
122 QSqlField f3("albumcount", QMetaType(QMetaType::Int));
123
124 f1.setValue(QVariant(id));
125 f2.setValue(QVariant(name));
126 f3.setValue(QVariant(0));
127 record.append(f1);
128 record.append(f2);
129 record.append(f3);
130
131 artistModel->insertRecord(-1, record);
132 return id;
133}
134
135int Dialog::addNewAlbum(const QString &title, int artistId)
136{
137 int id = generateAlbumId();
138 QSqlRecord record;
139
140 QSqlField f1("albumid", QMetaType(QMetaType::Int));
141 QSqlField f2("title", QMetaType(QMetaType::QString));
142 QSqlField f3("artistid", QMetaType(QMetaType::Int));
143 QSqlField f4("year", QMetaType(QMetaType::Int));
144
145 f1.setValue(QVariant(id));
146 f2.setValue(QVariant(title));
147 f3.setValue(QVariant(artistId));
148 f4.setValue(QVariant(yearEditor->value()));
149 record.append(f1);
150 record.append(f2);
151 record.append(f3);
152 record.append(f4);
153
154 model->insertRecord(-1, record);
155 return id;
156}
157
158void Dialog::addTracks(int albumId, const QStringList &tracks)
159{
160 QDomElement albumNode = albumDetails.createElement("album");
161 albumNode.setAttribute("id", albumId);
162
163 for (int i = 0; i < tracks.count(); ++i) {
164 QString trackNumber = QString::number(i);
165 if (i < 10)
166 trackNumber.prepend('0');
167
168 QDomText textNode = albumDetails.createTextNode(tracks.at(i));
169
170 QDomElement trackNode = albumDetails.createElement("track");
171 trackNode.setAttribute("number", trackNumber);
172 trackNode.appendChild(textNode);
173
174 albumNode.appendChild(trackNode);
175 }
176
177 QDomNodeList archive = albumDetails.elementsByTagName("archive");
178 archive.item(0).appendChild(albumNode);
179
180/*
181 The following code is commented out since the example uses an in
182 memory database, i.e., altering the XML file will bring the data
183 out of sync.
184
185 if (!outputFile->open(QIODevice::WriteOnly)) {
186 return;
187 } else {
188 QTextStream stream(outputFile);
189 archive.item(0).save(stream, 4);
190 outputFile->close();
191 }
192*/
193}
194
195void Dialog::increaseAlbumCount(QModelIndex artistIndex)
196{
197 QSqlTableModel *artistModel = model->relationModel(2);
198
199 QModelIndex albumCountIndex;
200 albumCountIndex = artistIndex.sibling(artistIndex.row(), 2);
201
202 int albumCount = albumCountIndex.data().toInt();
203 artistModel->setData(albumCountIndex, QVariant(albumCount + 1));
204}
205
206
207void Dialog::revert()
208{
209 artistEditor->clear();
210 titleEditor->clear();
211 yearEditor->setValue(QDate::currentDate().year());
212 tracksEditor->clear();
213}
214
215QGroupBox *Dialog::createInputWidgets()
216{
217 QGroupBox *box = new QGroupBox(tr("Add Album"));
218
219 QLabel *artistLabel = new QLabel(tr("Artist:"));
220 QLabel *titleLabel = new QLabel(tr("Title:"));
221 QLabel *yearLabel = new QLabel(tr("Year:"));
222 QLabel *tracksLabel = new QLabel(tr("Tracks (separated by comma):"));
223
224 artistEditor = new QLineEdit;
225 titleEditor = new QLineEdit;
226
227 yearEditor = new QSpinBox;
228 yearEditor->setMinimum(1900);
229 yearEditor->setMaximum(QDate::currentDate().year());
230 yearEditor->setValue(yearEditor->maximum());
231 yearEditor->setReadOnly(false);
232
233 tracksEditor = new QLineEdit;
234
235 QGridLayout *layout = new QGridLayout;
236 layout->addWidget(artistLabel, 0, 0);
237 layout->addWidget(artistEditor, 0, 1);
238 layout->addWidget(titleLabel, 1, 0);
239 layout->addWidget(titleEditor, 1, 1);
240 layout->addWidget(yearLabel, 2, 0);
241 layout->addWidget(yearEditor, 2, 1);
242 layout->addWidget(tracksLabel, 3, 0, 1, 2);
243 layout->addWidget(tracksEditor, 4, 0, 1, 2);
244 box->setLayout(layout);
245
246 return box;
247}
248
249QDialogButtonBox *Dialog::createButtons()
250{
251 QPushButton *closeButton = new QPushButton(tr("&Close"));
252 QPushButton *revertButton = new QPushButton(tr("&Revert"));
253 QPushButton *submitButton = new QPushButton(tr("&Submit"));
254
255 closeButton->setDefault(true);
256
257 connect(closeButton, &QPushButton::clicked, this, &Dialog::close);
258 connect(revertButton, &QPushButton::clicked, this, &Dialog::revert);
259 connect(submitButton, &QPushButton::clicked, this, &Dialog::submit);
260
261 QDialogButtonBox *buttonBox = new QDialogButtonBox;
262 buttonBox->addButton(submitButton, QDialogButtonBox::ResetRole);
263 buttonBox->addButton(revertButton, QDialogButtonBox::ResetRole);
264 buttonBox->addButton(closeButton, QDialogButtonBox::RejectRole);
265
266 return buttonBox;
267}
268
269QModelIndex Dialog::indexOfArtist(const QString &artist)
270{
271 QSqlTableModel *artistModel = model->relationModel(2);
272
273 for (int i = 0; i < artistModel->rowCount(); ++i) {
274 QSqlRecord record = artistModel->record(i);
275 if (record.value("artist") == artist)
276 return artistModel->index(i, 1);
277 }
278
279 return QModelIndex();
280}
281
282int Dialog::generateArtistId()
283{
284 uniqueArtistId += 1;
285 return uniqueArtistId;
286}
287
288int Dialog::generateAlbumId()
289{
290 uniqueAlbumId += 1;
291 return uniqueAlbumId;
292}
293