1 //===========================================
2 // Lumina-DE source code
3 // Copyright (c) 2014, Ken Moore
4 // Available under the 3-clause BSD license
5 // See the LICENSE file for full details
6 //===========================================
7 #include "MainUI.h"
8 #include "ui_MainUI.h"
9
10 #include "ConfigUI.h"
11
12 #include <LUtils.h>
13
MainUI()14 MainUI::MainUI() : QMainWindow(), ui(new Ui::MainUI){
15 ui->setupUi(this); //load the designer file
16 //setupIcons();
17 ui->radio_apps->setChecked(true); //always default to starting here
18 ui->tool_stop->setVisible(false); //no search running initially
19 ui->tool_configure->setVisible(false); //app search initially set
20
21 livetime = new QTimer(this);
22 livetime->setInterval(500); //1/2 second for live searches
23 livetime->setSingleShot(true);
24
25 workthread = new QThread(this);
26 workthread->setObjectName("Lumina Search Process");
27
28 searcher = new Worker();
29 searcher->moveToThread(workthread);
30
31 closeShort = new QShortcut(QKeySequence(tr("Esc")), this);
32
33 //Setup the connections
34 connect(livetime, SIGNAL(timeout()), this, SLOT(startSearch()) );
35 connect(this, SIGNAL(SearchTerm(QString, bool)), searcher, SLOT(StartSearch(QString, bool)) );
36 connect(searcher, SIGNAL(FoundItem(QString)), this, SLOT(foundSearchItem(QString)) );
37 connect(searcher, SIGNAL(SearchUpdate(QString)), this, SLOT(searchMessage(QString)) );
38 connect(searcher, SIGNAL(SearchDone()), this, SLOT(searchFinished()) );
39 connect(ui->tool_stop, SIGNAL(clicked()), this, SLOT(stopSearch()) );
40 connect(ui->push_done, SIGNAL(clicked()), this, SLOT(closeApplication()) );
41 connect(ui->push_launch, SIGNAL(clicked()), this, SLOT(LaunchItem()) );
42 connect(ui->line_search, SIGNAL(textEdited(QString)), this, SLOT(searchChanged()) );
43 connect(ui->line_search, SIGNAL(returnPressed()), this, SLOT(LaunchItem()) );
44 connect(ui->radio_apps, SIGNAL(toggled(bool)), this, SLOT(searchTypeChanged()) );
45 connect(ui->listWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(LaunchItem(QListWidgetItem*)) );
46 connect(ui->listWidget, SIGNAL(itemActivated(QListWidgetItem*)), this, SLOT(LaunchItem(QListWidgetItem*)) );
47 connect(ui->tool_configure, SIGNAL(clicked()), this, SLOT(configureSearch()) );
48 connect(closeShort, SIGNAL(activated()), this, SLOT( close() ) );
49
50 //Setup the settings file
51 settings = LUtils::openSettings("lumina-desktop", "lumina-search",this);
52 searcher->startDir = settings->value("StartSearchDir", QDir::homePath()).toString();
53 searcher->skipDirs = settings->value("SkipSearchDirs", QStringList()).toStringList();
54 updateDefaultStatusTip();
55 this->show();
56 workthread->start();
57 QTimer::singleShot(0,this, SLOT(setupIcons()) );
58 }
59
~MainUI()60 MainUI::~MainUI(){
61 searcher->StopSearch();
62 workthread->quit();
63 workthread->wait();
64 }
65
setupIcons()66 void MainUI::setupIcons(){
67 //Setup the icons
68 this->setWindowIcon( LXDG::findIcon("edit-find","") );
69 ui->push_launch->setIcon( LXDG::findIcon("quickopen","") );
70 ui->push_done->setIcon( LXDG::findIcon("window-close","") );
71 ui->tool_stop->setIcon( LXDG::findIcon("dialog-cancel","") );
72 ui->tool_configure->setIcon( LXDG::findIcon("configure","") );
73 }
74
75 // ===============
76 // PUBLIC FUNCTIONS (for input handling primarily)
77 // ===============
disableExcludes()78 void MainUI::disableExcludes(){
79 searcher->skipDirs.clear();
80 updateDefaultStatusTip();
81 }
82
setSearchDirectory(QString path)83 void MainUI::setSearchDirectory(QString path){
84 ui->radio_files->setChecked(true);
85 searcher->startDir = path;
86 updateDefaultStatusTip();
87 }
88
setSearchTerm(QString text)89 void MainUI::setSearchTerm(QString text){
90 ui->line_search->setText(text);
91 }
92
93 //==============
94 // PRIVATE
95 //==============
updateDefaultStatusTip()96 void MainUI::updateDefaultStatusTip(){
97 if(ui->radio_files->isChecked()){
98 QString txt = tr("Search: %1 -- Smart: %2");
99 QString dir = searcher->startDir;
100 dir.replace(QDir::homePath(), "~");
101 QString smart = searcher->skipDirs.isEmpty() ? tr("Off"): tr("On");
102 txt = txt.arg(dir,smart);
103 ui->statusbar->showMessage(txt);
104 }
105 }
106
107 //==============
108 // PRIVATE SLOTS
109 //==============
LaunchItem()110 void MainUI::LaunchItem(){
111 int index = ui->listWidget->currentRow();
112 if(index<0 && ui->listWidget->count()>0){ index = 0; } //grab the first item instead
113 else if(index<0){ return; } //no items available/selected
114 QString item = ui->listWidget->item(index)->whatsThis();
115 QProcess::startDetached("lumina-open \""+item+"\"");
116 //Close the search utility if an application was launched (quick launch functionality)
117 if(ui->radio_apps->isChecked()){ this->close(); }
118 }
119
LaunchItem(QListWidgetItem * item)120 void MainUI::LaunchItem(QListWidgetItem *item){
121 QProcess::startDetached("lumina-open \""+item->whatsThis()+"\"");
122 }
123
searchTypeChanged()124 void MainUI::searchTypeChanged(){
125 startSearch();
126 }
127
configureSearch()128 void MainUI::configureSearch(){
129 ConfigUI dlg(this);
130 dlg.loadInitialValues( settings->value("StartSearchDir",QDir::homePath()).toString(), settings->value("SkipSearchDirs",QStringList()).toStringList());
131 dlg.exec();
132 if(dlg.newStartDir.isEmpty()){ return; }//cancelled
133 QString startdir = dlg.newStartDir;
134 QStringList skipdirs = dlg.newSkipDirs;
135
136 //Save these values for later (if selected)
137 if(dlg.newDefaults){
138 //save these values as the new defaults
139 settings->setValue("StartSearchDir", startdir);
140 settings->setValue("SkipSearchDirs", skipdirs);
141 }
142
143 //Set these values in the searcher
144 searcher->startDir = startdir;
145 searcher->skipDirs = skipdirs;
146 updateDefaultStatusTip();
147 }
148
searchChanged()149 void MainUI::searchChanged(){
150 if(livetime->isActive()){ livetime->stop(); }
151 livetime->start();
152 }
153
154 //Worker Interaction
startSearch()155 void MainUI::startSearch(){
156 ui->listWidget->clear();
157 stopSearch(); //just in case a search is still running
158 if(ui->line_search->text().isEmpty()){ updateDefaultStatusTip(); return; } //nothing to search for
159
160 //emit the proper signal for the worker
161 if(!workthread->isRunning()){ workthread->start(); } //make sure the thread is running
162 emit SearchTerm(ui->line_search->text(), ui->radio_apps->isChecked());
163 ui->tool_stop->setVisible(true);
164 ui->tool_configure->setVisible(false);
165 }
166
foundSearchItem(QString path)167 void MainUI::foundSearchItem(QString path){
168 //To get the worker's results
169 QListWidgetItem *it = new QListWidgetItem;
170 it->setWhatsThis(path);
171 it->setToolTip(path);
172 //Now setup the visuals
173 if(path.simplified().endsWith(".desktop")){
174 bool ok = false;
175 XDGDesktop desk(path);
176 if( !desk.isValid() ){delete it; return; } //invalid file
177 it->setText(desk.name);
178 it->setIcon( LXDG::findIcon(desk.icon, "application-x-desktop") );
179 }else{
180 if(QFileInfo(path).isDir()){
181 it->setIcon( LXDG::findIcon("inode-directory","") );
182 it->setText( path.replace(QDir::homePath(), "~") );
183 }else{
184 if(QFileInfo(path).isExecutable()){
185 it->setIcon( LXDG::findIcon("application-x-executable","") );
186 }else{
187 it->setIcon( LXDG::findMimeIcon(path.section("/",-1).section(".",-1)) );
188 }
189 it->setText( path.section("/",-1) );
190 }
191
192 }
193 //Now add it to the widget
194 ui->listWidget->addItem(it);
195 if(ui->listWidget->count()>100){ searcher->StopSearch(); } //just in case
196 }
197
stopSearch()198 void MainUI::stopSearch(){
199 searcher->StopSearch();
200 ui->tool_stop->setVisible(false);
201 ui->tool_configure->setVisible(ui->radio_files->isChecked());
202 updateDefaultStatusTip();
203 }
204
searchMessage(QString msg)205 void MainUI::searchMessage(QString msg){
206 ui->statusbar->showMessage(msg,2000);
207 }
208
searchFinished()209 void MainUI::searchFinished(){
210 ui->tool_stop->setVisible(false);
211 ui->tool_configure->setVisible(ui->radio_files->isChecked());
212 updateDefaultStatusTip();
213 }
214