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