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