1/*******************************************************************
2* kfinddlg.cpp
3*
4* This program is free software; you can redistribute it and/or
5* modify it under the terms of the GNU General Public License as
6* published by the Free Software Foundation; either version 2 of
7* the License, or (at your option) any later version.
8*
9* This program is distributed in the hope that it will be useful,
10* but WITHOUT ANY WARRANTY; without even the implied warranty of
11* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12* GNU General Public License for more details.
13*
14* You should have received a copy of the GNU General Public License
15* along with this program. If not, see <http://www.gnu.org/licenses/>.
16*
17******************************************************************/
18
19#include "kfinddlg.h"
20#include "kfinddlg.moc"
21
22#include <QLayout>
23#include <QPushButton>
24
25#include <klocale.h>
26#include <kglobal.h>
27#include <kguiitem.h>
28#include <kstatusbar.h>
29#include <kmessagebox.h>
30#include <kdebug.h>
31#include <kaboutapplicationdialog.h>
32#include <kstandarddirs.h>
33#include <khelpmenu.h>
34#include <kmenu.h>
35
36#include "kftabdlg.h"
37#include "kquery.h"
38#include "kfindtreeview.h"
39
40KfindDlg::KfindDlg(const KUrl & url, QWidget *parent)
41 : KDialog( parent )
42{
43 setButtons( User1 | User2 | User3 | Close | Help );
44 setDefaultButton( User3 );
45 setModal( true );
46
47 setButtonGuiItem( User3, KStandardGuiItem::find());
48 setButtonGuiItem( User2, KStandardGuiItem::stop() );
49 setButtonGuiItem( User1, KStandardGuiItem::saveAs() );
50
51 QWidget::setWindowTitle( i18nc("@title:window", "Find Files/Folders" ) );
52 setButtonsOrientation(Qt::Vertical);
53
54 enableButton(User3, true); // Enable "Find"
55 enableButton(User2, false); // Disable "Stop"
56 enableButton(User1, false); // Disable "Save As..."
57
58 isResultReported = false;
59
60 QFrame *frame = new QFrame;
61 setMainWidget( frame );
62
63 // create tabwidget
64 tabWidget = new KfindTabWidget( frame );
65 tabWidget->setURL( url );
66 tabWidget->setFocus();
67
68 // prepare window for find results
69 win = new KFindTreeView(frame, this);
70
71 mStatusBar = new KStatusBar(frame);
72 mStatusBar->insertItem("AMiddleLengthText...", 0);
73 setStatusMsg( i18nc("the application is currently idle, there is no active search", "Idle.") );
74 mStatusBar->setItemAlignment(0, Qt::AlignLeft | Qt::AlignVCenter);
75 mStatusBar->insertPermanentItem(QString(), 1, 1);
76 mStatusBar->setItemAlignment(1, Qt::AlignRight | Qt::AlignVCenter);
77
78 QVBoxLayout *vBox = new QVBoxLayout(frame);
79 vBox->addWidget(tabWidget, 0);
80 vBox->addWidget(win, 1);
81 vBox->addWidget(mStatusBar, 0);
82
83 connect(tabWidget, SIGNAL(startSearch()),
84 this, SLOT(startSearch()));
85 connect(this, SIGNAL(user3Clicked()),
86 this, SLOT(startSearch()));
87 connect(this, SIGNAL(user2Clicked()),
88 this, SLOT(stopSearch()));
89 connect(this, SIGNAL(user1Clicked()),
90 win, SLOT(saveResults()));
91
92 connect( this, SIGNAL(closeClicked()), this, SLOT(finishAndClose()) );
93
94 connect(win ,SIGNAL(resultSelected(bool)),
95 this,SIGNAL(resultSelected(bool)));
96
97 query = new KQuery(frame);
98 connect(query, SIGNAL(result(int)), SLOT(slotResult(int)));
99 connect(query, SIGNAL(foundFileList(QList<QPair<KFileItem,QString> >)), SLOT(addFiles(QList<QPair<KFileItem,QString> >)));
100
101 KHelpMenu *helpMenu = new KHelpMenu(this, KGlobal::mainComponent().aboutData(), true);
102 setButtonMenu( Help, helpMenu->menu() );
103 dirwatch=NULL;
104}
105
106KfindDlg::~KfindDlg()
107{
108 stopSearch();
109
110 delete dirwatch;
111}
112
113void KfindDlg::finishAndClose()
114{
115 //Stop the current search and closes the dialog
116 stopSearch();
117 close();
118}
119
120void KfindDlg::setProgressMsg(const QString &msg)
121{
122 mStatusBar->changeItem(msg, 1);
123}
124
125void KfindDlg::setStatusMsg(const QString &msg)
126{
127 mStatusBar->changeItem(msg, 0);
128}
129
130
131void KfindDlg::startSearch()
132{
133 tabWidget->setQuery(query);
134
135 isResultReported = false;
136
137 // Reset count - use the same i18n as below
138 setProgressMsg(i18np("one file found", "%1 files found", 0));
139
140 emit resultSelected(false);
141 emit haveResults(false);
142
143 enableButton(User3, false); // Disable "Find"
144 enableButton(User2, true); // Enable "Stop"
145 enableButton(User1, false); // Disable "Save As..."
146
147 delete dirwatch;
148 dirwatch=new KDirWatch();
149 connect(dirwatch, SIGNAL(created(QString)), this, SLOT(slotNewItems(QString)));
150 connect(dirwatch, SIGNAL(deleted(QString)), this, SLOT(slotDeleteItem(QString)));
151 dirwatch->addDir(query->url().path(), KDirWatch::WatchFiles);
152
153#if 0
154 // waba: Watching for updates is disabled for now because even with FAM it causes too
155 // much problems. See BR68220, BR77854, BR77846, BR79512 and BR85802
156 // There are 3 problems:
157 // 1) addDir() keeps looping on recursive symlinks
158 // 2) addDir() scans all subdirectories, so it basically does the same as the process that
159 // is started by KQuery but in-process, undoing the advantages of using a separate find process
160 // A solution could be to let KQuery emit all the directories it has searched in.
161 // Either way, putting dirwatchers on a whole file system is probably just too much.
162 // 3) FAM has a tendency to deadlock with so many files (See BR77854) This has hopefully
163 // been fixed in KDirWatch, but that has not yet been confirmed.
164
165 //Getting a list of all subdirs
166 if(tabWidget->isSearchRecursive() && (dirwatch->internalMethod() == KDirWatch::FAM))
167 {
168 const QStringList subdirs=getAllSubdirs(query->url().path());
169 for(QStringList::const_iterator it = subdirs.constBegin(); it != subdirs.constEnd(); ++it)
170 dirwatch->addDir(*it,true);
171 }
172#endif
173
174 win->beginSearch(query->url());
175 tabWidget->beginSearch();
176
177 setStatusMsg(i18n("Searching..."));
178 query->start();
179}
180
181void KfindDlg::stopSearch()
182{
183 query->kill();
184}
185
186void KfindDlg::newSearch()
187{
188 // WABA: Not used any longer?
189 stopSearch();
190
191 tabWidget->setDefaults();
192
193 emit haveResults(false);
194 emit resultSelected(false);
195
196 setFocus();
197}
198
199void KfindDlg::slotResult(int errorCode)
200{
201 if (errorCode == 0)
202 setStatusMsg( i18nc("the application is currently idle, there is no active search", "Idle.") );
203 else if (errorCode == KIO::ERR_USER_CANCELED)
204 setStatusMsg(i18n("Canceled."));
205 else if (errorCode == KIO::ERR_MALFORMED_URL)
206 {
207 setStatusMsg(i18n("Error."));
208 KMessageBox::sorry( this, i18n("Please specify an absolute path in the \"Look in\" box."));
209 }
210 else if (errorCode == KIO::ERR_DOES_NOT_EXIST)
211 {
212 setStatusMsg(i18n("Error."));
213 KMessageBox::sorry( this, i18n("Could not find the specified folder."));
214 }
215 else
216 {
217 kDebug()<<"KIO error code: "<<errorCode;
218 setStatusMsg(i18n("Error."));
219 };
220
221 enableButton(User3, true); // Enable "Find"
222 enableButton(User2, false); // Disable "Stop"
223 enableButton(User1, true); // Enable "Save As..."
224
225 win->endSearch();
226 tabWidget->endSearch();
227 setFocus();
228
229}
230
231void KfindDlg::addFiles( const QList< QPair<KFileItem,QString> > & pairs)
232{
233 win->insertItems( pairs );
234
235 if (!isResultReported)
236 {
237 emit haveResults(true);
238 isResultReported = true;
239 }
240
241 QString str = i18np("one file found", "%1 files found", win->itemCount());
242 setProgressMsg( str );
243}
244
245void KfindDlg::setFocus()
246{
247 tabWidget->setFocus();
248}
249
250void KfindDlg::copySelection()
251{
252 win->copySelection();
253}
254
255void KfindDlg::about ()
256{
257 KAboutApplicationDialog dlg(0, this);
258 dlg.exec ();
259}
260
261void KfindDlg::slotDeleteItem(const QString& file)
262{
263 kDebug()<<QString("Will remove one item: %1").arg(file);
264
265 KUrl url;
266 url.setPath( file );
267
268 win->removeItem( url );
269
270 QString str = i18np("one file found", "%1 files found", win->itemCount());
271 setProgressMsg( str );
272}
273
274void KfindDlg::slotNewItems( const QString& file )
275{
276 kDebug()<<QString("Will add this item") << file;
277
278 if( file.indexOf(query->url().path(KUrl::AddTrailingSlash))==0 )
279 {
280 KUrl url;
281 url.setPath ( file );
282 if ( !win->isInserted( url ) )
283 query->slotListEntries( QStringList() << file );
284 }
285}
286
287QStringList KfindDlg::getAllSubdirs(QDir d)
288{
289 QStringList dirs;
290 QStringList subdirs;
291
292 d.setFilter( QDir::Dirs );
293 dirs = d.entryList();
294
295 for(QStringList::const_iterator it = dirs.constBegin(); it != dirs.constEnd(); ++it)
296 {
297 if((*it==".")||(*it==".."))
298 continue;
299 subdirs.append(d.path()+'/'+*it);
300 subdirs+=getAllSubdirs(QString(d.path()+QLatin1Char('/')+*it));
301 }
302 return subdirs;
303}
304