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 | |
40 | KfindDlg::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 * = new KHelpMenu(this, KGlobal::mainComponent().aboutData(), true); |
102 | setButtonMenu( Help, helpMenu->menu() ); |
103 | dirwatch=NULL; |
104 | } |
105 | |
106 | KfindDlg::~KfindDlg() |
107 | { |
108 | stopSearch(); |
109 | |
110 | delete dirwatch; |
111 | } |
112 | |
113 | void KfindDlg::finishAndClose() |
114 | { |
115 | //Stop the current search and closes the dialog |
116 | stopSearch(); |
117 | close(); |
118 | } |
119 | |
120 | void KfindDlg::setProgressMsg(const QString &msg) |
121 | { |
122 | mStatusBar->changeItem(msg, 1); |
123 | } |
124 | |
125 | void KfindDlg::setStatusMsg(const QString &msg) |
126 | { |
127 | mStatusBar->changeItem(msg, 0); |
128 | } |
129 | |
130 | |
131 | void 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 | |
181 | void KfindDlg::stopSearch() |
182 | { |
183 | query->kill(); |
184 | } |
185 | |
186 | void 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 | |
199 | void 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 | |
231 | void 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 | |
245 | void KfindDlg::setFocus() |
246 | { |
247 | tabWidget->setFocus(); |
248 | } |
249 | |
250 | void KfindDlg::copySelection() |
251 | { |
252 | win->copySelection(); |
253 | } |
254 | |
255 | void KfindDlg::about () |
256 | { |
257 | KAboutApplicationDialog dlg(0, this); |
258 | dlg.exec (); |
259 | } |
260 | |
261 | void 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 | |
274 | void 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 | |
287 | QStringList 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 | |