Fix sorting of library. Add basic search framework.
[dorian] / librarydialog.cpp
1 #include <QtGui>
2 #include <QDebug>
3 #include <QFileInfo>
4 #include <QDir>
5 #include <QModelIndex>
6
7 #ifdef Q_WS_MAEMO_5
8 #include <QtMaemo5/QMaemo5InformationBox>
9 #endif
10
11 #include "librarydialog.h"
12 #include "library.h"
13 #include "sortedlibrary.h"
14 #include "book.h"
15 #include "infodialog.h"
16 #include "settings.h"
17 #include "listwindow.h"
18 #include "listview.h"
19 #include "trace.h"
20 #include "bookfinder.h"
21 #include "searchdialog.h"
22
23 LibraryDialog::LibraryDialog(QWidget *parent): ListWindow(parent)
24 {
25     setWindowTitle(tr("Library"));
26
27     // Add actions
28
29 #ifndef Q_WS_MAEMO_5
30     addItemAction(tr("Details"), this, SLOT(onDetails()));
31     addItemAction(tr("Read"), this, SLOT(onRead()));
32     addItemAction(tr("Delete"), this, SLOT(onRemove()));
33 #endif // ! Q_WS_MAEMO_5
34
35     addAction(tr("Add book"), this, SLOT(onAdd()), "add");
36     addAction(tr("Add books from folder"), this, SLOT(onAddFolder()), "folder");
37     addAction(tr("Search the Web"), this, SLOT(onSearch()), "search");
38
39     // Create and add list view
40     list = new ListView(this);
41     sortedLibrary = new SortedLibrary(this);
42     list->setModel(sortedLibrary);
43     list->setSelectionMode(QAbstractItemView::SingleSelection);
44     list->setSpacing(1);
45     Library *library = Library::instance();
46     QModelIndex current = library->nowReading();
47     setSelected(current);
48     addList(list);
49
50     progress = new QProgressDialog(tr("Adding books"), "", 0, 0, this);
51     progress->reset();
52     progress->setMinimumDuration(0);
53     progress->setWindowModality(Qt::WindowModal);
54     progress->setCancelButton(0);
55
56     connect(Library::instance(), SIGNAL(nowReadingChanged()),
57             this, SLOT(onCurrentBookChanged()));
58     connect(Library::instance(),
59             SIGNAL(rowsInserted(const QModelIndex &, int, int)),
60             this,
61             SLOT(onBookAdded()));
62     connect(list, SIGNAL(activated(const QModelIndex &)),
63             this, SLOT(onItemActivated(const QModelIndex &)));
64
65     // Create search dialog
66     searchDialog = new SearchDialog(this);
67 }
68
69 void LibraryDialog::onAdd()
70 {
71     Library *library = Library::instance();
72
73     // Figure out directory to show
74     QString lastDir = Settings::instance()->value("lastdir").toString();
75     if (lastDir == "") {
76         lastDir = QDir::homePath();
77     }
78
79     // Get book file name
80     QString path = QFileDialog::getOpenFileName(this, tr("Add Book"),
81                                                 lastDir, "Books (*.epub)");
82     if (path == "") {
83         return;
84     }
85
86     // Save directory selected
87     Settings::instance()->setValue("lastdir", QFileInfo(path).absolutePath());
88
89     // Add book to library
90     QModelIndex index = library->find(path);
91     if (index.isValid()) {
92 #ifdef Q_WS_MAEMO_5
93         QMaemo5InformationBox::information(this,
94             tr("This book is already in the library"),
95             QMaemo5InformationBox::DefaultTimeout);
96 #else
97         (void)QMessageBox::information(this, tr("Dorian"),
98             tr("This book is already in the library"), QMessageBox::Ok);
99 #endif // Q_WS_MAEMO_5
100         setSelected(index);
101     }
102     else {
103         library->add(path);
104     }
105 }
106
107 void LibraryDialog::onBookAdded()
108 {
109     Library *library = Library::instance();
110     setSelected(library->index(library->rowCount() - 1));
111 }
112
113 #ifndef Q_WS_MAEMO_5
114
115 void LibraryDialog::onRemove()
116 {
117     QModelIndex current = sortedLibrary->mapToSource(list->currentIndex());
118     if (current.isValid()) {
119         Book *currentBook = Library::instance()->book(current);
120         QString title = currentBook->name();
121         if (QMessageBox::Yes ==
122             QMessageBox::question(this, tr("Delete book"),
123                 tr("Delete book \"%1\" from library?").
124                     arg(currentBook->shortName()),
125                 QMessageBox::Yes | QMessageBox::No)) {
126             Library::instance()->remove(current);
127         }
128     }
129 }
130
131 void LibraryDialog::onRead()
132 {
133     qDebug() << "LibraryDialog::onRead";
134     QModelIndex current = sortedLibrary->mapToSource(list->currentIndex());
135     if (current.isValid()) {
136         Library::instance()->setNowReading(current);
137     }
138 }
139
140 void LibraryDialog::onDetails()
141 {
142     onItemActivated(list->currentIndex());
143 }
144
145 #endif // Q_WS_MAEMO_5
146
147 void LibraryDialog::onItemActivated(const QModelIndex &index)
148 {
149     qDebug() << "LibraryDialog::onItemActivated";
150     QModelIndex libraryIndex = sortedLibrary->mapToSource(index);
151     Book *book = Library::instance()->book(libraryIndex);
152     (new InfoDialog(book, this))->exec();
153 }
154
155 QString LibraryDialog::createItemText(const Book *book)
156 {
157     QString text = book->title + "\n";
158     if (book->creators.size()) {
159         text += book->creators[0];
160         for (int i = 1; i < book->creators.size(); i++) {
161             text += ", " + book->creators[i];
162         }
163     }
164     return text;
165 }
166
167 void LibraryDialog::onCurrentBookChanged()
168 {
169     close();
170 }
171
172 void LibraryDialog::setSelected(const QModelIndex &libraryIndex)
173 {
174     QModelIndex sortedIndex = sortedLibrary->mapFromSource(libraryIndex);
175     list->selectionModel()->clearSelection();
176     if (sortedIndex.isValid()) {
177         list->selectionModel()->select(sortedIndex,
178                                        QItemSelectionModel::Select);
179         list->setCurrentIndex(sortedIndex);
180     }
181 }
182
183 QModelIndex LibraryDialog::selected() const
184 {
185     QModelIndexList selectedItems = list->selectionModel()->selectedIndexes();
186     if (selectedItems.size()) {
187         return sortedLibrary->mapToSource(selectedItems[0]);
188     }
189     return QModelIndex();
190 }
191
192 void LibraryDialog::onAddFolder()
193 {
194     Trace t("LibraryDialog::onAddFolder");
195
196     // Get folder name
197     Settings *settings = Settings::instance();
198     QString last =
199             settings->value("lastfolderadded", QDir::homePath()).toString();
200     QString path =
201             QFileDialog::getExistingDirectory(this, tr("Select folder"), last);
202     if (path == "") {
203         return;
204     }
205     settings->setValue("lastfolderadded", QFileInfo(path).absolutePath());
206     qDebug() << path;
207
208     // Add books from folder
209     progress->setWindowTitle(tr("Adding books"));
210     BookFinder *bookFinder = new BookFinder(this);
211     Library *library = Library::instance();
212     connect(bookFinder, SIGNAL(begin(int)), progress, SLOT(setMaximum(int)));
213     connect(bookFinder, SIGNAL(add(const QString &)),
214             this, SLOT(onAddFromFolder(const QString &)));
215     connect(bookFinder, SIGNAL(add(const QString &)),
216             library, SLOT(add(const QString &)));
217     connect(bookFinder, SIGNAL(done(int)),
218             this, SLOT(onAddFromFolderDone(int)));
219     bookFinder->find(path, Library::instance()->bookPaths());
220 }
221
222 void LibraryDialog::onAddFromFolderDone(int added)
223 {
224     QString msg;
225
226     switch (added) {
227     case 0: msg = tr("No new books found"); break;
228     case 1: msg = tr("One book added"); break;
229     default: msg = tr("%1 books added").arg(added);
230     }
231
232     progress->reset();
233     qDebug() << "LibraryDialog::onRefreshDone:" << msg;
234 #ifdef Q_WS_MAEMO_5
235     QMaemo5InformationBox::information(this, msg);
236 #else
237     // FIXME
238 #endif
239 }
240
241 void LibraryDialog::onAddFromFolder(const QString &path)
242 {
243     progress->setLabelText(QFileInfo(path).fileName());
244     progress->setValue(progress->value() + 1);
245 }
246
247 void LibraryDialog::onSearch()
248 {
249     int ret = searchDialog->exec();
250     if (ret != QDialog::Accepted) {
251         return;
252     }
253     Search::instance()->start(searchDialog->query());
254 }