]> vaikene.ee Git - evaf/blob - src/apps/FileFinder/GUI/gui.cpp
e664dd7703d484f06e62890ee6ccc8f73a2f04c9
[evaf] / src / apps / FileFinder / GUI / gui.cpp
1 /**
2 * @file FileFinder/GUI/gui.cpp
3 * @brief GUI for the FileFinder application
4 * @author Enar Vaikene
5 *
6 * Copyright (c) 2011 Enar Vaikene
7 *
8 * This file is part of the eVaf C++ cross-platform application development framework.
9 *
10 * This file can be used under the terms of the GNU General Public License
11 * version 3.0 as published by the Free Software Foundation and appearing in
12 * the file LICENSE included in the packaging of this file. Please review the
13 * the following information to ensure the GNU General Public License version
14 * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
15 *
16 * Alternatively, this file may be used in accordance with the Commercial License
17 * Agreement provided with the Software.
18 */
19
20 #include "gui.h"
21 #include "version.h"
22
23 #include "Engine/iFileFinder"
24
25 #include <Common/Globals>
26 #include <Common/iLogger>
27 #include <Common/iRegistry>
28 #include <Common/iApp>
29 #include <SdiWindow/iSdiWindow>
30
31 #include <QtGui>
32
33 VER_EXPORT_VERSION_INFO()
34 Q_EXPORT_PLUGIN2(VER_MODULE_NAME_STR, eVaf::FileFinder::GUI::Module)
35
36 using namespace eVaf;
37
38
39 //-------------------------------------------------------------------
40
41 void FileFinder::GUI::Internal::MainWidget::keyPressEvent(QKeyEvent * e)
42 {
43 if (!e->modifiers() || ((e->modifiers() & Qt::KeypadModifier) && e->key() == Qt::Key_Enter)) {
44 switch (e->key()) {
45 case Qt::Key_Enter:
46 case Qt::Key_Return: {
47 QList<QPushButton *> buttons = qFindChildren<QPushButton *>(this);
48 foreach (QPushButton * btn, buttons) {
49 if (btn->isDefault() && btn->isVisible()) {
50 if (btn->isEnabled())
51 btn->click();
52 return;
53 }
54 }
55 break;
56 }
57 case Qt::Key_Escape:
58 emit quit();
59 break;
60 case Qt::Key_Up:
61 focusPreviousChild();
62 break;
63 case Qt::Key_Down:
64 focusNextChild();
65 break;
66 default:
67 e->ignore();
68 }
69 }
70 else {
71 e->ignore();
72 }
73 }
74
75
76 //-------------------------------------------------------------------
77
78 int const FileFinder::GUI::Module::MaxHistoryItems = 20;
79
80 FileFinder::GUI::Module::Module()
81 : Plugins::iPlugin()
82 , mReady(false)
83 , mFinder(0)
84 , mOpenFileAction(0)
85 , mOpenDirectoryAction(0)
86 , mCopyNameAction(0)
87 , mCopyAllNamesAction(0)
88 , wMain(0)
89 , wDirectory(0)
90 , wRecursive(0)
91 , wIncludeNames(0)
92 , wExcludeNames(0)
93 , wIncludeContent(0)
94 , wExcludeContent(0)
95 , wFind(0)
96 {
97 setObjectName(QString("%1.Module").arg(VER_MODULE_NAME_STR));
98
99 EVAF_INFO("%s created", qPrintable(objectName()));
100 }
101
102 FileFinder::GUI::Module::~Module()
103 {
104 EVAF_INFO("%s destroyed", qPrintable(objectName()));
105 }
106
107 bool FileFinder::GUI::Module::init(QString const & args)
108 {
109 Q_UNUSED(args)
110
111 // Get the iFileFinder interface
112 EVAF_TEST_X((mFinder = evafQueryInterface<FileFinder::iFileFinder>("iFileFinder")), "No iFileFinder interface");
113 connect(mFinder, SIGNAL(found(QString,QString)), this, SLOT(found(QString,QString)));
114 connect(mFinder, SIGNAL(finished(bool)), this, SLOT(finished(bool)));
115
116 // Get the main window interface and fill it with widgets
117 SdiWindow::iSdiWindow * win = evafQueryInterface<SdiWindow::iSdiWindow>("iSdiWindow");
118 EVAF_TEST_X(win, "No iSdiWindow interface");
119
120 // Create the main widget for this window
121 wMain = new Internal::MainWidget;
122 connect(wMain, SIGNAL(quit()), qApp, SLOT(quit()));
123 win->addPanel("FileFinder", wMain);
124
125 // Create actions for the window and widgets on it
126 createActions();
127
128 // Create all the other widgets
129 createWidgets();
130
131 // Load stored searches
132 loadHistory();
133
134 mReady = true;
135
136 EVAF_INFO("%s initialized", qPrintable(objectName()));
137
138 return true;
139 }
140
141 void FileFinder::GUI::Module::done()
142 {
143 mReady = false;
144
145 mFinder = 0;
146
147 /*
148 * Widgets are deleted by the SdiWindow module. We use wMain to track calls to done() without
149 * proper init().
150 */
151 if (wMain) {
152 wMain = 0;
153 saveHistory();
154 }
155
156 EVAF_INFO("%s finalized", qPrintable(objectName()));
157 }
158
159 void FileFinder::GUI::Module::saveHistory()
160 {
161 QSettings settings(VER_COMPANY_NAME_STR, Common::iApp::instance()->name());
162
163 QStringList t;
164 for (int i = 0; i < wDirectory->count() && i < MaxHistoryItems; ++i)
165 t.append(wDirectory->itemText(i));
166 settings.setValue("FileFinder/Directories", t);
167
168 t.clear();
169 for (int i = 0; i < wIncludeNames->count() && i < MaxHistoryItems; ++i)
170 t.append(wIncludeNames->itemText(i));
171 settings.setValue("FileFinder/IncludeNames", t);
172
173 t.clear();
174 for (int i = 0; i < wExcludeNames->count() && i < MaxHistoryItems; ++i)
175 t.append(wExcludeNames->itemText(i));
176 settings.setValue("FileFinder/ExcludeNames", t);
177
178 t.clear();
179 for (int i = 0; i < wIncludeContent->count() && i < MaxHistoryItems; ++i)
180 t.append(wIncludeContent->itemText(i));
181 settings.setValue("FileFinder/IncludeContent", t);
182
183 t.clear();
184 for (int i = 0; i < wExcludeContent->count() && i < MaxHistoryItems; ++i)
185 t.append(wExcludeContent->itemText(i));
186 settings.setValue("FileFinder/ExcludeContent", t);
187
188 }
189
190 void FileFinder::GUI::Module::loadHistory()
191 {
192 QSettings settings(VER_COMPANY_NAME_STR, Common::iApp::instance()->name());
193
194 wDirectory->addItems(settings.value("FileFinder/Directories").toStringList());
195 wDirectory->setEditText(QDir::currentPath());
196 mDirModel->setRootPath(QDir::currentPath());
197
198 wIncludeNames->addItems(settings.value("FileFinder/IncludeNames").toStringList());
199 wIncludeNames->setEditText("");
200
201 wExcludeNames->addItems(settings.value("FileFinder/ExcludeNames").toStringList());
202 wExcludeNames->setEditText("");
203
204 wIncludeContent->addItems(settings.value("FileFinder/IncludeContent").toStringList());
205 wIncludeContent->setEditText("");
206
207 wExcludeContent->addItems(settings.value("FileFinder/ExcludeContent").toStringList());
208 wExcludeContent->setEditText("");
209 }
210
211 void FileFinder::GUI::Module::createWidgets()
212 {
213 QVBoxLayout * vbox = new QVBoxLayout;
214 wMain->setLayout(vbox);
215
216 QHBoxLayout * hbox = new QHBoxLayout;
217 vbox->addLayout(hbox);
218
219 QLabel * l = new QLabel(tr("&Directory:"));
220 hbox->addWidget(l);
221
222 wDirectory = new QComboBox;
223 wDirectory->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
224 wDirectory->setEditable(true);
225 wDirectory->setInsertPolicy(QComboBox::InsertAtTop);
226 QCompleter * completer = new QCompleter(wMain);
227 mDirModel = new QFileSystemModel(wMain);
228 mDirModel->setFilter(QDir::AllDirs | QDir::Dirs | QDir::NoDotAndDotDot);
229 completer->setModel(mDirModel);
230 wDirectory->setCompleter(completer);
231 l->setBuddy(wDirectory);
232 hbox->addWidget(wDirectory);
233
234 wBrowse = new QPushButton(tr("&Browse"));
235 connect(wBrowse, SIGNAL(clicked()), this, SLOT(browseDirectory()));
236 hbox->addWidget(wBrowse);
237
238 wRecursive = new QCheckBox(tr("&Recursive"));
239 wRecursive->setChecked(true);
240 hbox->addWidget(wRecursive);
241
242 QGridLayout * gr = new QGridLayout;
243 vbox->addLayout(gr);
244
245 gr->setColumnStretch(1, 1);
246 gr->setColumnStretch(3, 1);
247
248 l = new QLabel(tr("&File filter:"));
249 gr->addWidget(l, 0, 0);
250
251 wIncludeNames = new QComboBox;
252 wIncludeNames->setEditable(true);
253 wIncludeNames->setInsertPolicy(QComboBox::InsertAtTop);
254 l->setBuddy(wIncludeNames);
255 gr->addWidget(wIncludeNames, 0, 1);
256
257 l = new QLabel(tr("&not:"));
258 gr->addWidget(l, 0, 2);
259
260 wExcludeNames = new QComboBox;
261 wExcludeNames->setEditable(true);
262 wExcludeNames->setInsertPolicy(QComboBox::InsertAtTop);
263 l->setBuddy(wExcludeNames);
264 gr->addWidget(wExcludeNames);
265
266 l = new QLabel(tr("C&ontains:"));
267 gr->addWidget(l, 1, 0);
268
269 wIncludeContent = new QComboBox;
270 wIncludeContent->setEditable(true);
271 wIncludeContent->setInsertPolicy(QComboBox::InsertAtTop);
272 l->setBuddy(wIncludeContent);
273 gr->addWidget(wIncludeContent, 1, 1);
274
275 l = new QLabel(tr("no&t:"));
276 gr->addWidget(l, 1, 2);
277
278 wExcludeContent = new QComboBox;
279 wExcludeContent->setEditable(true);
280 wExcludeContent->setInsertPolicy(QComboBox::InsertAtTop);
281 l->setBuddy(wExcludeContent);
282 gr->addWidget(wExcludeContent, 1, 3);
283
284 wResults = new QListWidget;
285 wResults->setContextMenuPolicy(Qt::ActionsContextMenu);
286 wResults->addActions(QList<QAction *>() << mOpenFileAction << mOpenDirectoryAction << mCopyNameAction << mCopyAllNamesAction);
287 connect(wResults, SIGNAL(currentRowChanged(int)), this, SLOT(currentRowChanged(int)));
288 connect(wResults, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(openFile(QModelIndex)));
289 vbox->addWidget(wResults);
290
291 hbox = new QHBoxLayout;
292 vbox->addLayout(hbox);
293 hbox->addStretch();
294
295 wFind = new QPushButton(tr("&Search"));
296 wFind->setDefault(true);
297 connect(wFind, SIGNAL(clicked()), this, SLOT(find()));
298 hbox->addWidget(wFind);
299
300 QPushButton * btn = new QPushButton(tr("&Close"));
301 connect(btn, SIGNAL(clicked()), qApp, SLOT(quit()));
302 hbox->addWidget(btn);
303 }
304
305 void FileFinder::GUI::Module::createActions()
306 {
307 QAction * a = new QAction(wMain);
308 a->setShortcuts(QKeySequence::Quit);
309 connect(a, SIGNAL(triggered()), qApp, SLOT(quit()));
310 wMain->addAction(a);
311
312 mOpenFileAction = new QAction(tr("&Open"), wMain);
313 mOpenFileAction->setEnabled(false);
314 connect(mOpenFileAction, SIGNAL(triggered()), this, SLOT(openFile()));
315
316 mOpenDirectoryAction = new QAction(tr("Open &location"), wMain);
317 mOpenDirectoryAction->setEnabled(false);
318 connect(mOpenDirectoryAction, SIGNAL(triggered()), this, SLOT(openDirectory()));
319
320 mCopyNameAction = new QAction(tr("&Copy name"), wMain);
321 mCopyNameAction->setEnabled(false);
322 connect(mCopyNameAction, SIGNAL(triggered()), this, SLOT(copyName()));
323
324 mCopyAllNamesAction = new QAction(tr("Copy &all names"), wMain);
325 connect(mCopyAllNamesAction, SIGNAL(triggered()), this, SLOT(copyAllNames()));
326
327 }
328
329 void FileFinder::GUI::Module::browseDirectory()
330 {
331 QString s = QFileDialog::getExistingDirectory(wMain, tr("Select the directory"), wDirectory->currentText());
332 if (!s.isEmpty())
333 wDirectory->setEditText(s);
334 }
335
336 void FileFinder::GUI::Module::find()
337 {
338 if (!mFinder)
339 return;
340 if (mFinder->busy()) {
341 mFinder->cancel();
342 }
343 else {
344 wResults->clear();
345
346 if (wDirectory->findText(wDirectory->currentText()) == -1)
347 wDirectory->insertItem(0, wDirectory->currentText());
348 if (wIncludeNames->findText(wIncludeNames->currentText()) == -1)
349 wIncludeNames->insertItem(0, wIncludeNames->currentText());
350 if (wExcludeNames->findText(wExcludeNames->currentText()) == -1)
351 wExcludeNames->insertItem(0, wExcludeNames->currentText());
352 if (wIncludeContent->findText(wIncludeContent->currentText()) == -1)
353 wIncludeContent->insertItem(0, wIncludeContent->currentText());
354 if (wExcludeContent->findText(wExcludeContent->currentText()) == -1)
355 wExcludeContent->insertItem(0, wExcludeContent->currentText());
356
357 // Disable input fields
358 wDirectory->setEnabled(false);
359 wBrowse->setEnabled(false);
360 wRecursive->setEnabled(false);
361 wIncludeNames->setEnabled(false);
362 wExcludeNames->setEnabled(false);
363 wIncludeContent->setEnabled(false);
364 wExcludeContent->setEnabled(false);
365
366 mFinder->search(wDirectory->currentText(),
367 wRecursive->isChecked(),
368 FileFinder::Filter(
369 wIncludeNames->currentText(),
370 wExcludeNames->currentText(),
371 wIncludeContent->currentText(),
372 wExcludeContent->currentText()
373 )
374 );
375
376 wFind->setText(tr("&Stop"));
377 }
378 }
379
380 void FileFinder::GUI::Module::found(QString const & file, QString const & dir)
381 {
382 QString result = dir;
383 if (!result.endsWith(QChar('/')))
384 result.append(QChar('/'));
385 result.append(file);
386 wResults->addItem(result);
387 }
388
389 void FileFinder::GUI::Module::finished(bool canceled)
390 {
391 Q_UNUSED(canceled)
392
393 // Enable input fields
394 wDirectory->setEnabled(true);
395 wBrowse->setEnabled(true);
396 wRecursive->setEnabled(true);
397 wIncludeNames->setEnabled(true);
398 wExcludeNames->setEnabled(true);
399 wIncludeContent->setEnabled(true);
400 wExcludeContent->setEnabled(true);
401
402 wFind->setText(tr("&Search"));
403 }
404
405 void FileFinder::GUI::Module::currentRowChanged(int currentRow)
406 {
407 mOpenFileAction->setEnabled(currentRow >= 0);
408 mOpenDirectoryAction->setEnabled(currentRow >= 0);
409 mCopyNameAction->setEnabled(currentRow >= 0);
410 }
411
412 void FileFinder::GUI::Module::openFile(QModelIndex const & index)
413 {
414 Q_UNUSED(index)
415 if (wResults->currentItem()) {
416 QString t = wResults->currentItem()->text();
417 t.replace("?", "\0453f");
418 QDesktopServices::openUrl(QUrl::fromEncoded(QString("file:///%1").arg(t).toUtf8()));
419 }
420 }
421
422 void FileFinder::GUI::Module::openDirectory()
423 {
424 if (wResults->currentItem()) {
425 QString t = wResults->currentItem()->text();
426 t.replace("?", "\0453f");
427 QFileInfo fi(t);
428 QDesktopServices::openUrl(QUrl::fromEncoded(QString("file:///%1").arg(fi.path()).toUtf8()));
429 }
430 }
431
432 void FileFinder::GUI::Module::copyName()
433 {
434 if (wResults->currentItem()) {
435 QClipboard * cb = QApplication::clipboard();
436 if (cb)
437 cb->setText(wResults->currentItem()->text());
438 }
439 }
440
441 void FileFinder::GUI::Module::copyAllNames()
442 {
443 #ifdef Q_OS_WIN32
444 static char const * const EOLN = "\r\n";
445 #else
446 static char const * const EOLN = "\n";
447 #endif
448
449 QString t;
450 for (int i = 0; i < wResults->count(); ++i)
451 t.append(wResults->item(i)->text() + EOLN);
452 if (!t.isEmpty()) {
453 QClipboard * cb = QApplication::clipboard();
454 if (cb)
455 cb->setText(t);
456 }
457 }