1//
2//
3// C++ Implementation: kfilereplacepart
4//
5// Description:
6//
7//
8// Author: Andras Mantia <amantia@kde.org>, (C) 2003
9// Maintainer: Emiliano Gulmini <emi_barbarossa@yahoo.it>, (C) 2004
10//
11// Copyright: GPL v2. See COPYING file that comes with this distribution
12//
13//
14
15// QT
16#include <qdir.h>
17#include <qdatastream.h>
18#include <qregexp.h>
19#include <qimage.h>
20#include <qtextcodec.h>
21//Added by qt3to4:
22#include <QTextStream>
23#include <QDBusConnection>
24#include <QDBusReply>
25#include <QDBusConnectionInterface>
26#include <kicon.h>
27
28// KDE
29#include <kaboutapplicationdialog.h>
30#include <kapplication.h>
31#include <kaction.h>
32#include <kbugreport.h>
33#include <kconfig.h>
34#include <kfiledialog.h>
35#include <kcomponentdata.h>
36#include <kio/netaccess.h>
37#include <kmessagebox.h>
38#include <kparts/genericfactory.h>
39#include <kstandarddirs.h>
40#include <kiconloader.h>
41#include <kglobal.h>
42#include <kiconeffect.h>
43#include <k3listview.h>
44#include <kuser.h>
45#include <kcombobox.h>
46#include <kguiitem.h>
47#include <ktoolinvocation.h>
48#include <kactioncollection.h>
49#include <ktoggleaction.h>
50#include <krecentfilesaction.h>
51#include <kio/job.h>
52
53// local
54#include "kfilereplacelib.h"
55#include "kfilereplacepart.h"
56#include "kfilereplaceview.h"
57#include "koptionsdlg.h"
58#include "knewprojectdlg.h"
59#include "report.h"
60#include "commandengine.h"
61#include "whatthis.h"
62
63using namespace whatthisNameSpace;
64
65//PUBLIC CONSTRUCTORS
66// Factory code for KDE 3
67typedef KParts::GenericFactory<KFileReplacePart> FileReplaceFactory;
68
69K_EXPORT_COMPONENT_FACTORY( libkfilereplacepart, FileReplaceFactory )
70
71KFileReplacePart::KFileReplacePart(QWidget* parentWidget, QObject* parent, const QStringList & ) : KParts::ReadOnlyPart(parent)
72{
73 setComponentData(FileReplaceFactory::componentData());
74
75 m_parentWidget = parentWidget;
76 m_config = new KConfig("kfilereplacerc");
77 m_aboutDlg = 0;
78 m_stop = false;
79 m_optionMask = QDir::Files;
80 m_w = widget();
81 m_option = 0;
82
83 loadOptionsFromRC();
84 initView();
85 initGUI();
86
87 whatsThis();
88}
89
90KFileReplacePart::~KFileReplacePart()
91{
92 m_view = 0; //it's already deleted, so set it to NULL
93
94 saveOptionsToRC();
95
96 delete m_aboutDlg;
97 m_aboutDlg = 0;
98 delete m_config;
99 m_config = 0;
100 delete m_w;
101 m_w = 0;
102 delete m_option;
103}
104
105//PRIVATE SLOTS
106void KFileReplacePart::slotSetNewParameters()
107{
108 launchNewProjectDialog(KUrl());
109 m_view->changeView(m_option->m_searchingOnlyMode);
110 emit setStatusBarText(i18n("Ready."));
111}
112
113void KFileReplacePart::slotSearchingOperation()
114{
115 if(!checkBeforeOperation())
116 return;
117
118 K3ListView* rv = m_view->getResultsView();
119
120 rv->clear();
121
122 rv->setSorting(-1);
123
124 // show wait cursor
125 QApplication::setOverrideCursor( Qt::WaitCursor );
126
127 freezeActions();
128
129 setOptionMask();
130
131 QString currentDirectory = m_option->m_directories.split(",", QString::SkipEmptyParts)[0],
132 currentFilter = m_option->m_filters.split(",", QString::SkipEmptyParts)[0];
133
134 //m_currentDir = currentDirectory;
135
136 m_view->showSemaphore("red");
137
138 uint filesNumber = 0;
139
140 if(m_option->m_recursive)
141 recursiveFileSearch(currentDirectory, currentFilter, filesNumber);
142 else
143 fileSearch(currentDirectory, currentFilter);
144
145 m_view->showSemaphore("yellow");
146
147 kapp->processEvents();
148
149 //disabling and enabling sorting... don't ask me why, but it works!
150 rv->setSorting(0);
151 rv->sort();
152 rv->setSorting(-1);
153
154 // restore false status for stop button
155 m_stop = false;
156
157 QApplication::restoreOverrideCursor();
158
159 emit setStatusBarText(i18n("Search completed."));
160
161 m_option->m_searchingOnlyMode = true;
162
163 resetActions();
164
165 m_searchingOperation = true;
166
167 m_view->showSemaphore("green");
168}
169
170void KFileReplacePart::slotReplacingOperation()
171{
172 if (KMessageBox::warningContinueCancel(m_w, i18n("<qt>You have selected <b>%1</b> as the encoding of the files.<br />Selecting the correct encoding is very important as if you have files that have some other encoding than the selected one, after a replace you may damage those files.<br /><br />In case you do not know the encoding of your files, select <i>utf8</i> and <b>enable</b> the creation of backup files. This setting will autodetect <i>utf8</i> and <i>utf16</i> files, but the changed files will be converted to <i>utf8</i>.</qt>", m_option->m_encoding), i18n("File Encoding Warning"), KStandardGuiItem::cont(), KStandardGuiItem::cancel(), "ShowEncodingWarning") == KMessageBox::Cancel)
173 return;
174 if(!checkBeforeOperation())
175 return;
176
177 K3ListView* rv = m_view->getResultsView();
178
179 if(m_option->m_simulation)
180 {
181 emit setStatusBarText(i18n("Replacing files (simulation)..."));
182 rv->setColumnText(4,i18n("Replaced strings (simulation)"));
183 }
184 else
185 {
186 emit setStatusBarText(i18n("Replacing files..."));
187 rv->setColumnText(4,i18n("Replaced strings"));
188 }
189 // show wait cursor
190 QApplication::setOverrideCursor( Qt::WaitCursor );
191
192 freezeActions();
193
194 setOptionMask();
195
196 rv->setSorting(-1);
197
198 m_view->showSemaphore("green");
199
200 QString currentDirectory = m_option->m_directories.split(",", QString::SkipEmptyParts)[0];
201
202 m_view->showSemaphore("red");
203
204 if(m_option->m_recursive)
205 {
206 int filesNumber = 0;
207 recursiveFileReplace(currentDirectory, filesNumber);
208 }
209 else
210 {
211 fileReplace();
212 }
213
214 rv->setSorting(0);
215 rv->sort();
216 rv->setSorting(-1);
217
218 // restore false status for stop button
219 m_stop = false;
220
221 QApplication::restoreOverrideCursor();
222
223 m_option->m_searchingOnlyMode = false;
224
225 resetActions();
226
227 m_searchingOperation = false;
228
229 m_view->showSemaphore("green");
230}
231
232void KFileReplacePart::slotSimulatingOperation()
233{
234 m_option->m_simulation = true;
235 slotReplacingOperation();
236 m_option->m_simulation = false;
237}
238
239void KFileReplacePart::slotStop()
240{
241 emit setStatusBarText(i18n("Stopping..."));
242 m_stop = true;
243 QApplication::restoreOverrideCursor();
244 resetActions();
245}
246
247void KFileReplacePart::slotCreateReport()
248{
249 // Check there are results
250 K3ListView* rv = m_view->getResultsView(),
251 * sv = m_view->getStringsView();
252
253 if(rv->firstChild() == 0)
254 {
255 KMessageBox::error(m_w, i18n("There are no results to save: the result list is empty."));
256 return ;
257 }
258 // Select the file where results will be saved
259 QString documentName = KFileDialog::getSaveFileName(KUrl(), "*.xml|XML " + i18n("Files") + " (*.xml)", m_w, i18n("Save Report"));
260 if (documentName.isEmpty())
261 return ;
262
263 // delete a spourious extension
264 documentName.truncate(documentName.length()-4);
265
266 QFileInfo fileInfo(documentName);
267 if(fileInfo.exists())
268 {
269 KMessageBox::error(m_w, i18n("<qt>A folder or a file named <b>%1</b> already exists.</qt>", documentName));
270 return ;
271 }
272
273 QDir directoryName;
274
275 if(!directoryName.mkdir(documentName))
276 {
277 KMessageBox::error(m_w, i18n("<qt>Cannot create the <b>%1</b> folder.</qt>", documentName));
278 return ;
279 }
280
281 directoryName.cd(documentName);
282
283 QString documentPath = documentName+'/'+directoryName.dirName();
284
285 Report report(m_option, rv, sv);
286 report.createDocument(documentPath);
287
288 //resetActions();
289}
290
291void KFileReplacePart::slotStringsAdd()
292{
293 m_view->slotStringsAdd();
294 resetActions();
295}
296
297void KFileReplacePart::slotQuickStringsAdd()
298{
299 //this slot handles a pair of strings that come from project dialog,
300 //if the control character 'N' is found at the position 0 of the two strings,
301 //then we start the search now.
302 QString qs = m_option->m_quickSearchString;
303 QStringList map;
304
305 map.append(qs.left(1));
306 map.append(qs.right(qs.length()-1));
307 //in this case there is no string to search for, so return
308 if(map[1].isEmpty())
309 return;
310
311 //in this one instead, we must search for a string
312 qs = m_option->m_quickReplaceString;
313 map.append(qs.left(1));
314 map.append(qs.right(qs.length()-1));
315
316 m_view->updateOptions(m_option);
317
318 m_view->slotQuickStringsAdd(map[1],map[3]);
319
320 //if search-only mode == true and search-now mode == true then
321 //search string
322 if(map[0] == "N") {
323 if(m_option->m_searchingOnlyMode)
324 slotSearchingOperation();
325 else
326 slotReplacingOperation();
327 }
328}
329
330void KFileReplacePart::slotStringsDeleteItem()
331{
332 m_view->slotStringsDeleteItem();
333 resetActions();
334}
335
336void KFileReplacePart::slotStringsEmpty()
337{
338 m_view->slotStringsEmpty();
339 resetActions();
340}
341
342void KFileReplacePart::slotStringsEdit()
343{
344 m_view->slotStringsEdit();
345 resetActions();
346}
347
348void KFileReplacePart::slotStringsSave()
349{
350 m_view->slotStringsSave();
351}
352
353void KFileReplacePart::slotStringsLoad()
354{
355 // Selects the file to load from
356 QString menu = "*.kfr|" + i18n("KFileReplace strings") + " (*.kfr)\n*|"+i18n("All Files") + " (*)";
357 QString fileName = KFileDialog::getOpenFileName(KUrl(), menu, m_w, i18n("Load Strings From File"));
358
359 if(!fileName.isEmpty())
360 loadRulesFile(fileName);
361
362 resetActions();
363}
364
365void KFileReplacePart::slotStringsInvertCur()
366{
367 m_view->stringsInvert(false);
368 resetActions();
369}
370
371void KFileReplacePart::slotStringsInvertAll()
372{
373 m_view->stringsInvert(true);
374 resetActions();
375}
376
377void KFileReplacePart::slotOpenRecentStringFile(const KUrl& urlFile)
378{
379 QString fileName;
380
381 // Downloads file if need (if url is "http://...")
382 if (!(KIO::NetAccess::download(urlFile, fileName, 0)))
383 return;
384
385 // Checks it's not a directory
386 QFileInfo fileInfo;
387 fileInfo.setFile(fileName);
388 if(fileInfo.isDir())
389 {
390 KMessageBox::error(m_w, i18n("Cannot open folders."));
391 return;
392 }
393
394 loadRulesFile(fileName);
395 resetActions();
396}
397
398void KFileReplacePart::slotOptionRecursive()
399{
400 m_option->m_recursive = !m_option->m_recursive;
401 resetActions();
402}
403
404void KFileReplacePart::slotOptionBackup()
405{
406 m_option->m_backup = !m_option->m_backup;
407 resetActions();
408}
409
410void KFileReplacePart::slotOptionCaseSensitive()
411{
412 m_option->m_caseSensitive = !m_option->m_caseSensitive;
413 resetActions();
414}
415
416void KFileReplacePart::slotOptionVariables()
417{
418 m_option->m_variables = !m_option->m_variables;
419 resetActions();
420}
421
422void KFileReplacePart::slotOptionRegularExpressions()
423{
424 m_option->m_regularExpressions = !m_option->m_regularExpressions;
425 resetActions();
426}
427
428void KFileReplacePart::slotOptionPreferences()
429{
430 KOptionsDlg dlg(m_option, m_w, 0);
431
432 if(!dlg.exec())
433 return;
434
435 //updating m_view
436 m_view->updateOptions(m_option);
437
438 resetActions();
439}
440
441void KFileReplacePart::showAboutApplication()
442{
443 if (m_aboutDlg == 0)
444 m_aboutDlg = new KAboutApplicationDialog(createAboutData());
445 if(m_aboutDlg == 0)
446 return;
447
448 if(!m_aboutDlg->isVisible())
449 m_aboutDlg->show();
450 else
451 m_aboutDlg->raise();
452}
453
454void KFileReplacePart::appHelpActivated()
455{
456 KToolInvocation::invokeHelp(QString::null, "kfilereplace"); //krazy:exclude=nullstrassign for old broken gcc
457}
458
459void KFileReplacePart::reportBug()
460{
461 KBugReport dlg(m_w, true, createAboutData());
462 dlg.exec();
463}
464
465void KFileReplacePart::resetActions()
466{
467 K3ListView* rv = m_view->getResultsView(),
468 * sv = m_view->getStringsView();
469
470 bool hasItems = (sv->firstChild() != 0),
471 searchOnlyMode = m_option->m_searchingOnlyMode;
472
473 // File
474 actionCollection()->action("new_project")->setEnabled(true);
475 actionCollection()->action("search")->setEnabled(hasItems && searchOnlyMode);
476 actionCollection()->action("file_simulate")->setEnabled(hasItems && !searchOnlyMode);
477 actionCollection()->action("replace")->setEnabled(hasItems && !searchOnlyMode);
478 actionCollection()->action("save_results")->setEnabled(hasItems);
479 actionCollection()->action("stop")->setEnabled(false);
480
481 // Strings
482 actionCollection()->action("strings_add")->setEnabled(true);
483 actionCollection()->action("strings_del")->setEnabled(hasItems);
484 actionCollection()->action("strings_empty")->setEnabled(hasItems);
485 actionCollection()->action("strings_edit")->setEnabled(hasItems);
486 actionCollection()->action("strings_save")->setEnabled(hasItems);
487 actionCollection()->action("strings_load")->setEnabled(true);
488 actionCollection()->action("strings_invert")->setEnabled(hasItems && !searchOnlyMode);
489 actionCollection()->action("strings_invert_all")->setEnabled(hasItems && !searchOnlyMode);
490
491 // Options
492 actionCollection()->action("options_recursive")->setEnabled(true);
493 actionCollection()->action("options_backup")->setEnabled(!searchOnlyMode);
494 actionCollection()->action("options_case")->setEnabled(true);
495 actionCollection()->action("options_var")->setEnabled(!searchOnlyMode);
496 actionCollection()->action("options_regularexpressions")->setEnabled(true);
497 actionCollection()->action("configure_kfilereplace")->setEnabled(true);
498
499 hasItems = (rv->firstChild() != 0);
500
501 // Results
502 actionCollection()->action("results_infos")->setEnabled(hasItems);
503 actionCollection()->action("results_openfile")->setEnabled(hasItems);
504 if (actionCollection()->action("results_editfile"))
505 actionCollection()->action("results_editfile")->setEnabled(hasItems);
506 actionCollection()->action("results_opendir")->setEnabled(hasItems);
507 actionCollection()->action("results_delete")->setEnabled(hasItems);
508 actionCollection()->action("results_treeexpand")->setEnabled(hasItems);
509 actionCollection()->action("results_treereduce")->setEnabled(hasItems);
510
511 // Updates menus and toolbar
512 ((KToggleAction* ) actionCollection()->action("options_recursive"))->setChecked(m_option->m_recursive);
513 ((KToggleAction* ) actionCollection()->action("options_backup"))->setChecked(m_option->m_backup && !searchOnlyMode);
514 ((KToggleAction* ) actionCollection()->action("options_case"))->setChecked(m_option->m_caseSensitive);
515 ((KToggleAction* ) actionCollection()->action("options_var"))->setChecked(m_option->m_variables && !searchOnlyMode);
516 ((KToggleAction* ) actionCollection()->action("options_regularexpressions"))->setChecked(m_option->m_regularExpressions);
517}
518
519//PUBLIC METHODS
520KAboutData* KFileReplacePart::createAboutData()
521{
522 KAboutData * aboutData = new KAboutData("kfilereplacepart", "kfilereplace",
523 ki18n("KFileReplacePart"),
524 KFR_VERSION,
525 ki18n( "Batch search and replace tool."),
526 KAboutData::License_GPL_V2,
527 ki18n("(C) 1999-2002 François Dupoux\n(C) 2003-2004 Andras Mantia\n(C) 2004 Emiliano Gulmini"), ki18n("Part of the KDEWebDev module."), "http://www.kdewebdev.org");
528 aboutData->addAuthor(ki18n("François Dupoux"),
529 ki18n("Original author of the KFileReplace tool"),
530 "dupoux@dupoux.com");
531 aboutData->addAuthor(ki18n("Emiliano Gulmini"),
532 ki18n("Current maintainer, code cleaner and rewriter"),
533 "emi_barbarossa@yahoo.it");
534 aboutData->addAuthor(ki18n("Andras Mantia"),
535 ki18n("Co-maintainer, KPart creator"),
536 "amantia@kde.org");
537 aboutData->addCredit(ki18n("Heiko Goller"),
538 ki18n("Original german translator"),
539 "heiko.goller@tuebingen.mpg.de");
540 return aboutData;
541}
542
543//PROTECTED METHODS
544bool KFileReplacePart::openURL(const KUrl &url)
545{
546 if(!url.isEmpty() && (url.protocol() != "file"))
547 {
548 KMessageBox::sorry(m_w, i18n("Sorry, currently the KFileReplace part works only for local files."), i18n("Non Local File"));
549 emit canceled("");
550 return false;
551 }
552 if(!url.isEmpty())
553 return launchNewProjectDialog(url);
554 else
555 {
556 resetActions();
557 return true;
558 }
559}
560
561//PRIVATE METHODS
562void KFileReplacePart::initGUI()
563{
564 setXMLFile("kfilereplacepartui.rc");
565
566 bool quantaFound = false;
567 QDBusConnection dbus = QDBusConnection::sessionBus();
568 QDBusReply<QStringList> reply = dbus.interface()->registeredServiceNames();
569 if ( !reply.isValid() )
570 return;
571
572 const QStringList allServices = reply;
573 for ( QStringList::const_iterator it = allServices.begin(), end = allServices.end() ; it != end ; ++it ) {
574 const QString service = *it;
575 if ( service.startsWith( "org.kde.quanta" ) ) {
576 quantaFound = true;
577 break;
578 }
579 }
580 // File
581 QAction *action;
582 action = new KAction(KIcon("project-open"), i18n("Customize Search/Replace Session..."), this);
583 actionCollection()->addAction("new_project", action );
584 connect(action, SIGNAL(triggered(bool) ), SLOT(slotSetNewParameters()));
585 action = new KAction(KIcon("edit-find"), i18n("&Search"), this);
586 actionCollection()->addAction("search", action );
587 connect(action, SIGNAL(triggered(bool) ), SLOT(slotSearchingOperation()));
588 action = new KAction(KIcon("filesimulate"), i18n("S&imulate"), this);
589 actionCollection()->addAction("file_simulate", action );
590 connect(action, SIGNAL(triggered(bool) ), SLOT(slotSimulatingOperation()));
591 action = new KAction(KIcon("edit-find-replace"), i18n("&Replace"), this);
592 actionCollection()->addAction("replace", action );
593 connect(action, SIGNAL(triggered(bool) ), SLOT(slotReplacingOperation()));
594 action = new KAction(KIcon("process-stop"), i18n("Sto&p"), this);
595 actionCollection()->addAction("stop", action );
596 connect(action, SIGNAL(triggered(bool) ), SLOT(slotStop()));
597 action = new KAction(KIcon("document-save-as"), i18n("Cre&ate Report File..."), this);
598 actionCollection()->addAction("save_results", action );
599 connect(action, SIGNAL(triggered(bool) ), SLOT(slotCreateReport()));
600
601 // Strings
602 action = new KAction(KIcon("list-add"), i18n("&Add String..."), this);
603 actionCollection()->addAction("strings_add", action );
604 connect(action, SIGNAL(triggered(bool) ), SLOT(slotStringsAdd()));
605
606 action = new KAction(KIcon("list-remove"), i18n("&Delete String"), this);
607 actionCollection()->addAction("strings_del", action );
608 connect(action, SIGNAL(triggered(bool) ), SLOT(slotStringsDeleteItem()));
609 action = new KAction(KIcon("edit-clear"), i18n("&Empty Strings List"), this);
610 actionCollection()->addAction("strings_empty", action );
611 connect(action, SIGNAL(triggered(bool) ), SLOT(slotStringsEmpty()));
612 action = new KAction(KIcon("document-properties"), i18n("Edit Selected String..."), this);
613 actionCollection()->addAction("strings_edit", action );
614 connect(action, SIGNAL(triggered(bool) ), SLOT(slotStringsEdit()));
615 action = new KAction(KIcon("document-save-as"), i18n("&Save Strings List to File..."), this);
616 actionCollection()->addAction("strings_save", action );
617 connect(action, SIGNAL(triggered(bool) ), SLOT(slotStringsSave()));
618 action = new KAction(KIcon("document-import"), i18n("&Load Strings List From File..."), this);
619 actionCollection()->addAction("strings_load", action );
620 connect(action, SIGNAL(triggered(bool) ), SLOT(slotStringsLoad()));
621 KRecentFilesAction *recent = actionCollection()->add<KRecentFilesAction>("strings_load_recent");
622 recent->setText(i18n("&Load Recent Strings Files"));
623 recent->setIcon(KIcon("document-open-recent"));
624 connect(recent, SIGNAL(urlSelected(const KUrl&)),SLOT(slotOpenRecentStringFile(const KUrl&)));
625
626 action = new KAction(KIcon("object-flip-horizontal"), i18n("&Invert Current String (search <--> replace)"), this);
627 actionCollection()->addAction("strings_invert", action );
628 connect(action, SIGNAL(triggered(bool) ), SLOT(slotStringsInvertCur()));
629 action = new KAction(KIcon("object-flip-horizontal"), i18n("&Invert All Strings (search <--> replace)"), this);
630 actionCollection()->addAction("strings_invert_all", action );
631 connect(action, SIGNAL(triggered(bool) ), SLOT(slotStringsInvertAll()));
632
633 // Options
634 action = new KToggleAction(KIcon("recursive_option"), i18n("&Include Sub-Folders"), this);
635 actionCollection()->addAction("options_recursive", action );
636 connect(action, SIGNAL(triggered(bool)), SLOT(slotOptionRecursive()));
637 action = new KToggleAction(KIcon("backup_option"), i18n("Create &Backup Files"), this);
638 actionCollection()->addAction("options_backup", action );
639 connect(action, SIGNAL(triggered(bool)), SLOT(slotOptionBackup()));
640 action = new KToggleAction(KIcon("casesensitive_option"), i18n("Case &Sensitive"), this);
641 actionCollection()->addAction("options_case", action );
642 connect(action, SIGNAL(triggered(bool)), SLOT(slotOptionCaseSensitive()));
643 action = new KToggleAction(KIcon("command_option"), i18n("Enable Commands &in Replace String: [$command:option$]"), this);
644 actionCollection()->addAction("options_var", action );
645 connect(action, SIGNAL(triggered(bool)), SLOT(slotOptionVariables()));
646 action = new KToggleAction(KIcon("regularexpression_option"), i18n("Enable &Regular Expressions"), this);
647 actionCollection()->addAction("options_regularexpressions", action );
648 connect(action, SIGNAL(triggered(bool)), SLOT(slotOptionRegularExpressions()));
649 action = new KAction(KIcon("configure"), i18n("Configure &KFileReplace..."), this);
650 actionCollection()->addAction("configure_kfilereplace", action );
651 connect(action, SIGNAL(triggered(bool) ), SLOT(slotOptionPreferences()));
652
653 // Results
654 action = new KAction(KIcon("document-properties"), i18n("&Properties"), this);
655 actionCollection()->addAction("results_infos", action );
656 connect(action, SIGNAL(triggered(bool) ), m_view, SLOT(slotResultProperties()));
657 action = new KAction(KIcon("document-new"), i18n("&Open"), this);
658 actionCollection()->addAction("results_openfile", action );
659 connect(action, SIGNAL(triggered(bool) ), m_view, SLOT(slotResultOpen()));
660
661 if(quantaFound)
662 {
663 KAction *action = new KAction(KIcon("quanta"), i18n("&Edit in Quanta"), this);
664 actionCollection()->addAction("results_editfile", action );
665 connect(action, SIGNAL(triggered(bool) ), m_view, SLOT(slotResultEdit()));
666 }
667 action = new KAction(KIcon("document-open"), i18n("Open Parent &Folder"), this);
668 actionCollection()->addAction("results_opendir", action );
669 connect(action, SIGNAL(triggered(bool) ), m_view, SLOT(slotResultDirOpen()));
670 action = new KAction(KIcon("edit-delete"), i18n("&Delete"), this);
671 actionCollection()->addAction("results_delete", action );
672 connect(action, SIGNAL(triggered(bool) ), m_view, SLOT(slotResultDelete()));
673 action = new KAction(i18n("E&xpand Tree"), this);
674 actionCollection()->addAction("results_treeexpand", action );
675 connect(action, SIGNAL(triggered(bool)), m_view, SLOT(slotResultTreeExpand()));
676 action = new KAction(i18n("&Reduce Tree"), this);
677 actionCollection()->addAction("results_treereduce", action );
678 connect(action, SIGNAL(triggered(bool)), m_view, SLOT(slotResultTreeReduce()));
679 action = new KAction(KIcon("kfilereplace"), i18n("&About KFileReplace"), this);
680 actionCollection()->addAction("help_about_kfilereplace", action );
681 connect(action, SIGNAL(triggered(bool) ), SLOT(showAboutApplication()));
682 action = new KAction(KIcon("help-contents"), i18n("KFileReplace &Handbook"), this);
683 actionCollection()->addAction("help_kfilereplace", action );
684 connect(action, SIGNAL(triggered(bool) ), SLOT(appHelpActivated()));
685 action = new KAction(i18n("&Report Bug"), this);
686 actionCollection()->addAction("report_bug", action );
687 connect(action, SIGNAL(triggered(bool) ), SLOT(reportBug()));
688
689}
690
691void KFileReplacePart::initView()
692{
693 m_view = new KFileReplaceView(m_option, m_parentWidget, "view");
694
695 setWidget(m_view);
696
697 m_view->setAcceptDrops(false);
698
699 m_view->showSemaphore("green");
700}
701
702void KFileReplacePart::freezeActions()
703{
704 //Disables actions during search/replace operation
705 actionCollection()->action("new_project")->setEnabled(false);
706 actionCollection()->action("stop")->setEnabled(true);
707
708 actionCollection()->action("file_simulate")->setEnabled(false);
709 actionCollection()->action("replace")->setEnabled(false);
710 actionCollection()->action("search")->setEnabled(false);
711 actionCollection()->action("strings_add")->setEnabled(false);
712 actionCollection()->action("strings_del")->setEnabled(false);
713 actionCollection()->action("strings_empty")->setEnabled(false);
714 actionCollection()->action("strings_edit")->setEnabled(false);
715 actionCollection()->action("strings_save")->setEnabled(false);
716 actionCollection()->action("strings_load")->setEnabled(false);
717 actionCollection()->action("strings_invert")->setEnabled(false);
718 actionCollection()->action("strings_invert_all")->setEnabled(false);
719 actionCollection()->action("options_recursive")->setEnabled(false);
720 actionCollection()->action("options_backup")->setEnabled(false);
721 actionCollection()->action("options_case")->setEnabled(false);
722 actionCollection()->action("options_var")->setEnabled(false);
723 actionCollection()->action("options_regularexpressions")->setEnabled(false);
724 actionCollection()->action("configure_kfilereplace")->setEnabled(false);
725 actionCollection()->action("results_infos")->setEnabled(false);
726 actionCollection()->action("results_openfile")->setEnabled(false);
727 if (actionCollection()->action("results_editfile"))
728 actionCollection()->action("results_editfile")->setEnabled(false);
729 actionCollection()->action("results_opendir")->setEnabled(false);
730 actionCollection()->action("results_delete")->setEnabled(false);
731 actionCollection()->action("results_treeexpand")->setEnabled(false);
732 actionCollection()->action("results_treereduce")->setEnabled(false);
733 ((KToggleAction* ) actionCollection()->action("options_recursive"))->setChecked(false);
734 ((KToggleAction* ) actionCollection()->action("options_backup"))->setChecked(false);
735 ((KToggleAction* ) actionCollection()->action("options_case"))->setChecked(false);
736 ((KToggleAction* ) actionCollection()->action("options_var"))->setChecked(false);
737 ((KToggleAction* ) actionCollection()->action("options_regularexpressions"))->setChecked(false);
738}
739
740void KFileReplacePart::loadOptionsFromRC()
741{
742 m_option = new RCOptions();
743
744 loadOptions();
745 loadFileSizeOptions();
746 loadDateAccessOptions();
747 loadOwnerOptions();
748 loadLocationsList();
749 loadFiltersList();
750 loadBackupExtensionOptions();
751}
752
753void KFileReplacePart::loadOptions()
754{
755 KConfigGroup cg( m_config, "General Options");
756
757 m_option->m_recentStringFileList = cg.readEntry(rcRecentFiles, QStringList() );
758
759 m_option->m_searchingOnlyMode = cg.readEntry(rcSearchMode,SearchModeOption);
760
761 cg = m_config->group( "Options" );
762
763 m_option->m_encoding = cg.readEntry(rcEncoding, EncodingOption).toLatin1();
764 m_option->m_recursive = cg.readEntry(rcRecursive, RecursiveOption);
765
766 m_option->m_caseSensitive = cg.readEntry(rcCaseSensitive, CaseSensitiveOption);
767 m_option->m_variables = cg.readEntry(rcVariables, VariablesOption);
768 m_option->m_regularExpressions = cg.readEntry(rcRegularExpressions, RegularExpressionsOption);
769 m_option->m_followSymLinks = cg.readEntry(rcFollowSymLinks, FollowSymbolicLinksOption);
770
771 m_option->m_haltOnFirstOccur = cg.readEntry(rcHaltOnFirstOccur, StopWhenFirstOccurenceOption);
772
773 m_option->m_ignoreHidden = cg.readEntry(rcIgnoreHidden, IgnoreHiddenOption);
774 m_option->m_ignoreFiles = cg.readEntry(rcIgnoreFiles, IgnoreFilesOption);
775
776 cg = m_config->group("Notification Messages");
777
778 m_option->m_notifyOnErrors = cg.readEntry(rcNotifyOnErrors, true);
779
780 m_option->m_askConfirmReplace = cg.readEntry(rcAskConfirmReplace, AskConfirmReplaceOption);
781
782 QString dontAskAgain = cg.readEntry(rcDontAskAgain, QString("no"));
783
784 if(dontAskAgain == "yes")
785 m_option->m_askConfirmReplace = false;
786}
787
788void KFileReplacePart::loadFileSizeOptions()
789{
790 KConfigGroup cg( m_config,"Size options");
791
792 m_option->m_minSize = cg.readEntry(rcMinFileSize, FileSizeOption);
793 m_option->m_maxSize = cg.readEntry(rcMaxFileSize, FileSizeOption);
794}
795
796void KFileReplacePart::loadDateAccessOptions()
797{
798 KConfigGroup cg( m_config,"Access options");
799
800 m_option->m_dateAccess = cg.readEntry(rcValidAccessDate, ValidAccessDateOption);
801 m_option->m_minDate = cg.readEntry(rcMinDate, AccessDateOption);
802 m_option->m_maxDate = cg.readEntry(rcMaxDate, AccessDateOption);
803}
804
805void KFileReplacePart::loadOwnerOptions()
806{
807 KConfigGroup cg( m_config,"Owner options");
808
809 QStringList ownerList = cg.readEntry(rcOwnerUser, OwnerOption).split(",");
810 if(ownerList.value(0) == "true")
811 m_option->m_ownerUserIsChecked = true;
812 else
813 m_option->m_ownerUserIsChecked = false;
814
815 m_option->m_ownerUserType = ownerList.value(1);
816 m_option->m_ownerUserBool = ownerList.value(2);
817 m_option->m_ownerUserValue = ownerList.value(3);
818
819 ownerList = cg.readEntry(rcOwnerGroup, OwnerOption).split(",");
820
821 if(ownerList.value(0) == "true")
822 m_option->m_ownerGroupIsChecked = true;
823 else
824 m_option->m_ownerGroupIsChecked = false;
825
826 m_option->m_ownerGroupType = ownerList.value(1);
827 m_option->m_ownerGroupBool = ownerList.value(2);
828 m_option->m_ownerGroupValue = ownerList.value(3);
829}
830
831void KFileReplacePart::loadLocationsList()
832{
833 KConfigGroup cg( m_config,"Directories");
834 #if KDE_IS_VERSION(3,1,3)
835 QString locationsEntryList = cg.readPathEntry(rcDirectoriesList, QString());
836 #else
837 QString locationsEntryList = cg.readEntry(rcDirectoriesList);
838 #endif
839
840 if(locationsEntryList.isEmpty())
841 locationsEntryList = QDir::current().path();
842
843 m_option->m_directories = locationsEntryList;
844}
845
846void KFileReplacePart::loadFiltersList()
847{
848 KConfigGroup cg( m_config,"Filters");
849 #if KDE_IS_VERSION(3,1,3)
850 QString filtersEntryList = cg.readPathEntry(rcFiltersList, QString());
851 #else
852 QString filtersEntryList = cg.readEntry(rcFiltersList);
853 #endif
854
855 if(filtersEntryList.isEmpty())
856 filtersEntryList = "*.htm;*.html;*.xml;*.xhtml;*.css;*.js;*.php";
857
858 m_option->m_filters = filtersEntryList;
859}
860
861void KFileReplacePart::loadBackupExtensionOptions()
862{
863 KConfigGroup cg( m_config,"Options");
864 QStringList bkList = cg.readEntry(rcBackupExtension, BackupExtensionOption).split(",");
865 if(bkList[0] == "true")
866 m_option->m_backup = true;
867 else
868 m_option->m_backup = false;
869
870 m_option->m_backupExtension = bkList[1];
871}
872
873void KFileReplacePart::saveOptionsToRC()
874{
875 saveOptions();
876 saveFileSizeOptions();
877 saveDateAccessOptions();
878 saveOwnerOptions();
879 saveLocationsList();
880 saveFiltersList();
881 saveBackupExtensionOptions();
882}
883
884void KFileReplacePart::saveOptions()
885{
886 KConfigGroup cg( m_config,"General Options");
887
888 cg.writeEntry(rcRecentFiles, m_option->m_recentStringFileList);
889 cg.writeEntry(rcSearchMode,m_option->m_searchingOnlyMode);
890
891 cg = m_config->group("Options");
892
893 cg.writeEntry(rcEncoding, m_option->m_encoding);
894 cg.writeEntry(rcRecursive, m_option->m_recursive);
895 cg.writeEntry(rcCaseSensitive, m_option->m_caseSensitive);
896 cg.writeEntry(rcVariables, m_option->m_variables);
897 cg.writeEntry(rcRegularExpressions, m_option->m_regularExpressions);
898
899 cg.writeEntry(rcFollowSymLinks, m_option->m_followSymLinks);
900 cg.writeEntry(rcHaltOnFirstOccur, m_option->m_haltOnFirstOccur);
901
902 cg.writeEntry(rcIgnoreHidden, m_option->m_ignoreHidden);
903 cg.writeEntry(rcIgnoreFiles, m_option->m_ignoreFiles);
904
905 cg = m_config->group("Notification Messages");
906 cg.writeEntry(rcNotifyOnErrors, m_option->m_notifyOnErrors);
907 if(cg.readEntry(rcDontAskAgain,QString("no")) == "yes")
908 cg.writeEntry(rcAskConfirmReplace, false);
909 else
910 cg.writeEntry(rcAskConfirmReplace, m_option->m_askConfirmReplace);
911
912 cg.sync();
913}
914
915void KFileReplacePart::saveFileSizeOptions()
916{
917 KConfigGroup cg( m_config,"Size options");
918
919 cg.writeEntry(rcMaxFileSize, m_option->m_maxSize);
920 cg.writeEntry(rcMinFileSize, m_option->m_minSize);
921
922 cg.sync();
923}
924
925void KFileReplacePart::saveDateAccessOptions()
926{
927 KConfigGroup cg( m_config,"Access options");
928
929 cg.writeEntry(rcValidAccessDate, m_option->m_dateAccess);
930 cg.writeEntry(rcMinDate, m_option->m_minDate);
931 cg.writeEntry(rcMaxDate, m_option->m_maxDate);
932
933 cg.sync();
934}
935
936void KFileReplacePart::saveOwnerOptions()
937{
938 KConfigGroup cg( m_config,"Owner options");
939
940 QString list;
941 if(m_option->m_ownerUserIsChecked)
942 list = "true,";
943 else
944 list = "false,";
945
946 list += m_option->m_ownerUserType +
947 ',' +
948 m_option->m_ownerUserBool;
949 if(!m_option->m_ownerUserValue.isEmpty())
950 list += ',' + m_option->m_ownerUserValue;
951
952 cg.writeEntry(rcOwnerUser,list);
953
954 if(m_option->m_ownerGroupIsChecked)
955 list = "true,";
956 else
957 list = "false,";
958
959 list += m_option->m_ownerGroupType +
960 ',' +
961 m_option->m_ownerGroupBool;
962 if(!m_option->m_ownerGroupValue.isEmpty())
963 list += ',' + m_option->m_ownerGroupValue;
964
965 cg.writeEntry(rcOwnerGroup,list);
966 cg.sync();
967}
968
969void KFileReplacePart::saveLocationsList()
970{
971 KConfigGroup cg( m_config,"Directories");
972 cg.writeEntry(rcDirectoriesList, m_option->m_directories);
973 cg.sync();
974}
975
976void KFileReplacePart::saveFiltersList()
977{
978 KConfigGroup cg( m_config,"Filters");
979 cg.writeEntry(rcFiltersList, m_option->m_filters);
980 cg.sync();
981}
982
983void KFileReplacePart::saveBackupExtensionOptions()
984{
985 KConfigGroup cg( m_config,"Options");
986 QString bkOptions;
987 if(m_option->m_backup)
988 bkOptions = "true," + m_option->m_backupExtension;
989 else
990 bkOptions = "false," + m_option->m_backupExtension;
991
992 cg.writeEntry(rcBackupExtension, bkOptions);
993 cg.sync();
994}
995
996void KFileReplacePart::fileReplace()
997{
998 QString directoryName = m_option->m_directories.split(QChar(','))[0];
999 QDir d(directoryName);
1000 d.setFilter(m_optionMask | QDir::AllDirs);
1001
1002 QString currentFilter = m_option->m_filters.split(",", QString::SkipEmptyParts)[0];
1003 QStringList filesList = d.entryList(currentFilter.split(';'));
1004 QStringList::iterator filesIt;
1005 int filesNumber = 0;
1006
1007 m_view->displayScannedFiles(filesNumber);
1008
1009 for (filesIt = filesList.begin(); filesIt != filesList.end() ; ++filesIt)
1010 {
1011 QString fileName = (*filesIt);
1012
1013 // m_stop == true means that we pushed the stop button
1014 if(m_stop)
1015 break;
1016
1017 // Avoids files that not match requirements
1018 if(!KFileReplaceLib::isAnAccessibleFile(d.canonicalPath(), fileName, m_option))
1019 continue;
1020 kapp->processEvents();
1021 if(m_option->m_backup)
1022 replaceAndBackup(d.canonicalPath(), fileName);
1023 else
1024 replaceAndOverwrite(d.canonicalPath(), fileName);
1025
1026 filesNumber++;
1027 m_view->displayScannedFiles(filesNumber);
1028 }
1029}
1030
1031void KFileReplacePart::recursiveFileReplace(const QString& directoryName, int& filesNumber)
1032{
1033 //if m_stop == true then interrupts recursion
1034 if(m_stop)
1035 return;
1036 else
1037 {
1038 QDir d(directoryName);
1039
1040 d.setFilter(m_optionMask | QDir::AllDirs);
1041
1042 QString currentFilter = m_option->m_filters.split(",", QString::SkipEmptyParts)[0];
1043 QStringList filesList = d.entryList(currentFilter.split(';'));
1044 QStringList::iterator filesIt;
1045
1046 for(filesIt = filesList.begin(); filesIt != filesList.end(); ++filesIt)
1047 {
1048 //if m_stop == true then end for-loop
1049 if(m_stop)
1050 break;
1051
1052 QString fileName = (*filesIt);
1053
1054 // Avoids files that not match requirements
1055 if(!KFileReplaceLib::isAnAccessibleFile(d.canonicalPath(),fileName, m_option))
1056 continue;
1057
1058 QString filePath = d.canonicalPath()+'/'+fileName;
1059
1060 QFileInfo qi(filePath);
1061
1062 m_view->displayScannedFiles(filesNumber);
1063
1064 //if filePath is a directory then recursion
1065 if(qi.isDir())
1066 recursiveFileReplace(filePath, filesNumber);
1067 else
1068 {
1069 kapp->processEvents();
1070 if(m_option->m_backup)
1071 replaceAndBackup(d.canonicalPath(), fileName);
1072 else
1073 replaceAndOverwrite(d.canonicalPath(), fileName);
1074
1075 filesNumber++;
1076 m_view->displayScannedFiles(filesNumber);
1077 }
1078 }
1079 }
1080}
1081
1082void KFileReplacePart::replaceAndBackup(const QString& currentDir, const QString& oldFileName)
1083{
1084 //Creates a path string
1085 QString oldPathString = currentDir+'/'+oldFileName;
1086
1087 QFile currentFile(oldPathString);
1088 if(!currentFile.open(QIODevice::ReadOnly))
1089 {
1090 KMessageBox::information(m_w, i18n("<qt>Cannot open file <b>%1</b> for reading.</qt>", oldFileName), QString(), rcNotifyOnErrors);
1091 return ;
1092 }
1093 QTextStream currentStream(&currentFile);
1094 if (m_option->m_encoding == "utf8")
1095 currentStream.setCodec(QTextCodec::codecForName("UTF-8"));
1096 else
1097 currentStream.setCodec(QTextCodec::codecForName(m_option->m_encoding.toUtf8()));
1098 QString line = currentStream.readAll(),
1099 backupLine = line;
1100
1101 QString backupSize = KFileReplaceLib::formatFileSize(currentFile.size());
1102
1103 currentFile.close();
1104
1105 QString backupExtension = m_option->m_backupExtension;
1106
1107 bool atLeastOneStringFound = false;
1108 K3ListViewItem *item = 0;
1109 int occurrence = 0;
1110
1111 replacingLoop(line, &item, atLeastOneStringFound, occurrence, m_option->m_regularExpressions, m_option->m_askConfirmReplace);
1112
1113 //If we are not performing a simulation creates a backup file
1114 if(!m_option->m_simulation)
1115 {
1116 if(atLeastOneStringFound)
1117 {
1118 KIO::FileCopyJob * job = KIO::file_copy(KUrl(oldPathString), KUrl(oldPathString + backupExtension), -1, KIO::Overwrite);
1119 job->exec();
1120 }
1121 }
1122
1123 if(!m_option->m_simulation)
1124 {
1125 if(atLeastOneStringFound)
1126 {
1127 QFile newFile(oldPathString);
1128 if(!newFile.open(QIODevice::WriteOnly))
1129 {
1130 KMessageBox::information(m_w, i18n("<qt>Cannot open file <b>%1</b> for writing.</qt>", oldFileName), QString(), rcNotifyOnErrors);
1131 return ;
1132 }
1133 QTextStream newStream(&newFile);
1134 if (m_option->m_encoding == "utf8")
1135 newStream.setCodec(QTextCodec::codecForName("UTF-8"));
1136 else
1137 newStream.setCodec(QTextCodec::codecForName(m_option->m_encoding.toUtf8()));
1138 newStream << line;
1139 newFile.close();
1140 }
1141 }
1142
1143 if(!m_option->m_ignoreFiles)
1144 atLeastOneStringFound = true;
1145
1146 QFileInfo oldFileInfo(oldPathString);
1147
1148 if(atLeastOneStringFound && item/* && atLeastOneStringConfirmed*/)
1149 {
1150 KFileReplaceLib::setIconForFileEntry(item,currentDir+'/'+oldFileName);
1151 item->setText(0,oldFileName);
1152 item->setText(1,currentDir);
1153 QString newSize = KFileReplaceLib::formatFileSize(oldFileInfo.size());
1154 if(!m_option->m_simulation)
1155 {
1156 item->setText(2, backupSize);
1157 item->setText(3, newSize);
1158 }
1159 else
1160 {
1161 item->setText(2, backupSize);
1162 item->setText(3, "-");
1163 }
1164
1165 item->setText(4,QString::number(occurrence,10));
1166 item->setText(5,QString("%1[%2]").arg(oldFileInfo.owner()).arg(oldFileInfo.ownerId()));
1167 item->setText(6,QString("%1[%2]").arg(oldFileInfo.group()).arg(oldFileInfo.groupId()));
1168 }
1169}
1170
1171void KFileReplacePart::replaceAndOverwrite(const QString& currentDir, const QString& oldFileName)
1172{
1173 QString oldPathString = currentDir+'/'+oldFileName;
1174 QFile oldFile(oldPathString);
1175 QFileInfo oldFileInfo(oldPathString);
1176
1177 if (!oldFile.open(QIODevice::ReadOnly))
1178 {
1179 KMessageBox::information(m_w, i18n("<qt>Cannot open file <b>%1</b> for reading.</qt>", oldFile.fileName()), QString(), rcNotifyOnErrors);
1180 return ;
1181 }
1182
1183 QString fileSizeBeforeReplacing = KFileReplaceLib::formatFileSize(oldFileInfo.size());
1184 K3ListViewItem *item = 0;
1185
1186 QTextStream oldStream( &oldFile );
1187 if (m_option->m_encoding == "utf8")
1188 oldStream.setCodec(QTextCodec::codecForName("UTF-8"));
1189 else
1190 oldStream.setCodec(QTextCodec::codecForName(m_option->m_encoding.toUtf8()));
1191 QString line = oldStream.readAll();
1192
1193 oldFile.close();
1194
1195 bool atLeastOneStringFound = false;
1196 int occurrence = 0;
1197
1198 replacingLoop(line, &item, atLeastOneStringFound, occurrence, m_option->m_regularExpressions, m_option->m_askConfirmReplace);
1199
1200
1201 if(!m_option->m_simulation)
1202 {
1203 if(atLeastOneStringFound)
1204 {
1205 QFile newFile(oldPathString);
1206 if(!newFile.open(QIODevice::WriteOnly))
1207 {
1208 KMessageBox::information(m_w, i18n("<qt>Cannot open file <b>%1</b> for writing.</qt>", newFile.fileName()), QString(), rcNotifyOnErrors);
1209 return ;
1210 }
1211 QTextStream newStream( &newFile );
1212 if (m_option->m_encoding == "utf8")
1213 newStream.setCodec(QTextCodec::codecForName("UTF-8"));
1214 else
1215 newStream.setCodec(QTextCodec::codecForName(m_option->m_encoding.toUtf8()));
1216 newStream << line;
1217 newFile.close();
1218 }
1219 }
1220
1221 QFileInfo nf(oldPathString);
1222 QString fileSizeAfterReplacing = KFileReplaceLib::formatFileSize(nf.size());
1223
1224 //if ignoreFiles == false then every files must be show
1225 if(!m_option->m_ignoreFiles)
1226 atLeastOneStringFound = true;
1227
1228 if(atLeastOneStringFound && item/*&& atLeastOneStringConfirmed*/)
1229 {
1230 KFileReplaceLib::setIconForFileEntry(item,currentDir+'/'+oldFileName);
1231 item->setText(0,oldFileName);
1232 item->setText(1,currentDir);
1233 item->setText(2,fileSizeBeforeReplacing);
1234 if(!m_option->m_simulation)
1235 item->setText(3,fileSizeAfterReplacing);
1236 else
1237 item->setText(3,"-");
1238
1239 item->setText(4,QString::number(occurrence,10));
1240 item->setText(5,QString("%1[%2]").arg(oldFileInfo.owner()).arg(oldFileInfo.ownerId()));
1241 item->setText(6,QString("%1[%2]").arg(oldFileInfo.group()).arg(oldFileInfo.groupId()));
1242 }
1243}
1244
1245void KFileReplacePart::replacingLoop(QString& line, K3ListViewItem** item, bool& atLeastOneStringFound, int& occur, bool regularExpression, bool& askConfirmReplace)
1246{
1247 KeyValueMap tempMap = m_replacementMap;
1248 KeyValueMap::Iterator it;
1249 K3ListView* rv = m_view->getResultsView();
1250
1251 for(it = tempMap.begin(); it != tempMap.end(); ++it)
1252 {
1253 if(m_stop)
1254 break;
1255
1256 ResultViewEntry entry(it.key(), it.value(), regularExpression, m_option->m_caseSensitive);
1257 while(entry.pos(line) != -1)
1258 {
1259 if(m_stop)
1260 break;
1261
1262 if(askConfirmReplace)
1263 {
1264 int answer = KMessageBox::questionYesNo(0,
1265 i18n("<qt>Do you want to replace the string <b>%1</b> with the string <b>%2</b>?</qt>", it.key(), it.value()),
1266 i18n("Confirm Replace"),
1267 KGuiItem(i18n("Replace")),
1268 KGuiItem(i18n("Do Not Replace")),
1269 rcDontAskAgain);
1270 if(answer == KMessageBox::Yes)
1271 {
1272 atLeastOneStringFound = true;
1273 QString msg = entry.message(entry.capturedText(line),
1274 entry.lineNumber(line),
1275 entry.columnNumber(line));
1276
1277 if(!*item)
1278 *item = new K3ListViewItem(rv);
1279 K3ListViewItem* tempItem = new K3ListViewItem(*item);
1280 tempItem->setMultiLinesEnabled(true);
1281 tempItem->setText(0,msg);
1282 occur ++;
1283 entry.updateLine(line);
1284 entry.incPos();
1285 }
1286 else
1287 {
1288 entry.incPos();
1289 }
1290 if(dontAskAgain()) askConfirmReplace = false;
1291 }
1292 else
1293 {
1294 atLeastOneStringFound = true;
1295 QString msg = entry.message(entry.capturedText(line),
1296 entry.lineNumber(line),
1297 entry.columnNumber(line));
1298
1299 if(!*item)
1300 *item = new K3ListViewItem(rv);
1301 K3ListViewItem* tempItem = new K3ListViewItem(*item);
1302 tempItem->setMultiLinesEnabled(true);
1303 tempItem->setText(0,msg);
1304 occur ++;
1305 entry.updateLine(line);
1306 entry.incPos();
1307 }
1308
1309 }
1310 }
1311}
1312
1313void KFileReplacePart::fileSearch(const QString& directoryName, const QString& filters)
1314{
1315 QDir d(directoryName);
1316
1317 d.setFilter(m_optionMask | QDir::AllDirs);
1318
1319 QStringList filesList = d.entryList(filters.split(';'));
1320 QString filePath = d.canonicalPath();
1321 QStringList::iterator filesIt;
1322 uint filesNumber = 0;
1323
1324 m_view->displayScannedFiles(filesNumber);
1325
1326 for (filesIt = filesList.begin(); filesIt != filesList.end() ; ++filesIt)
1327 {
1328 // We pushed stop button
1329 if(m_stop)
1330 break;
1331
1332 QString fileName = (*filesIt);
1333
1334 // Avoids files that not match
1335 if(!KFileReplaceLib::isAnAccessibleFile(filePath, fileName, m_option))
1336 continue;
1337
1338 QFileInfo fileInfo(filePath+'/'+fileName);
1339 if(fileInfo.isDir())
1340 continue;
1341 kapp->processEvents();
1342 search(filePath, fileName);
1343 filesNumber++;
1344 m_view->displayScannedFiles(filesNumber);
1345 }
1346}
1347
1348void KFileReplacePart::recursiveFileSearch(const QString& directoryName, const QString& filters, uint& filesNumber)
1349{
1350 // if m_stop == true then interrupt recursion
1351 if(m_stop)
1352 return;
1353 else
1354 {
1355 QDir d(directoryName);
1356
1357 d.setFilter(m_optionMask | QDir::AllDirs);
1358
1359 QStringList filesList = d.entryList(filters.split(';'));
1360 QString filePath = d.canonicalPath();
1361 QStringList::iterator filesIt;
1362
1363 for(filesIt = filesList.begin(); filesIt != filesList.end(); ++filesIt)
1364 {
1365 // stop polling
1366 if(m_stop)
1367 break;
1368
1369 QString fileName = (*filesIt);
1370 // Avoids files that not match
1371 if(!KFileReplaceLib::isAnAccessibleFile(filePath, fileName, m_option))
1372 continue;
1373
1374 // Composes file path string
1375 QFileInfo fileInfo(filePath+'/'+fileName);
1376
1377 m_view->displayScannedFiles(filesNumber);
1378
1379 // Searchs recursively if "filePath" is a directory
1380 if(fileInfo.isDir())
1381 recursiveFileSearch(filePath+'/'+fileName, filters, filesNumber);
1382 else
1383 {
1384 kapp->processEvents();
1385 search(filePath, fileName);
1386 filesNumber++;
1387 m_view->displayScannedFiles(filesNumber);
1388 }
1389 }
1390 }
1391}
1392
1393void KFileReplacePart::search(const QString& currentDir, const QString& fileName)
1394{
1395 QFile file(currentDir+'/'+fileName);
1396
1397 if(!file.open(QIODevice::ReadOnly))
1398 {
1399 KMessageBox::information(m_w, i18n("<qt>Cannot open file <b>%1</b> for reading.</qt>", fileName), QString(), rcNotifyOnErrors);
1400 return ;
1401 }
1402 // Creates a stream with the file
1403 QTextStream stream( &file );
1404 if (m_option->m_encoding == "utf8")
1405 stream.setCodec(QTextCodec::codecForName("UTF-8"));
1406 else
1407 stream.setCodec(QTextCodec::codecForName(m_option->m_encoding.toUtf8()));
1408 QString line = stream.readAll();
1409 file.close();
1410
1411 QFileInfo fileInfo(currentDir+'/'+fileName);
1412
1413 K3ListViewItem *item = 0;
1414
1415 //Counts occurrences
1416 int occurrence = 0;
1417
1418 //This map contains strings to search
1419 KeyValueMap tempMap = m_replacementMap;
1420 //If no strings has been found, then no lines will be added to the result view
1421 bool atLeastOneStringFound = false;
1422
1423 KeyValueMap::Iterator it = tempMap.begin();
1424
1425 K3ListView* rv = m_view->getResultsView();
1426
1427 while(it != tempMap.end())
1428 {
1429 //stop polling
1430 if(m_stop)
1431 break;
1432
1433 QString key = it.key();
1434 QString strKey;
1435 QRegExp rxKey;
1436
1437 if(m_option->m_regularExpressions)
1438 rxKey = QRegExp('('+key+')', m_option->m_caseSensitive, false);
1439 else
1440 strKey = key;
1441 /* If this option is true then for any string in
1442 * the map we search for the first match*/
1443 if(m_option->m_haltOnFirstOccur)
1444 {
1445 int pos;
1446
1447 if(m_option->m_regularExpressions)
1448 pos = line.indexOf(rxKey);
1449 else
1450 pos = line.find(strKey, 0 ,m_option->m_caseSensitive);
1451
1452 if(pos != -1)
1453 {
1454 atLeastOneStringFound = true;
1455 int lineNumber = line.mid(0,pos).count('\n')+1;
1456 int columnNumber = pos - line.lastIndexOf('\n',pos);
1457
1458 if (!item)
1459 item = new K3ListViewItem(rv);
1460
1461 K3ListViewItem* tempItem= new K3ListViewItem(item);
1462 QString msg,
1463 capturedText;
1464
1465 if(m_option->m_regularExpressions)
1466 capturedText = rxKey.cap(1);
1467 else
1468 capturedText = line.mid(pos,strKey.length());
1469
1470 msg = i18n(" Line:%2, Col:%3 - \"%1\"", capturedText, lineNumber, columnNumber);
1471 tempItem->setMultiLinesEnabled(true);
1472 tempItem->setText(0,msg);
1473 occurrence = 1;
1474 }
1475 }// ends m_option->m_haltOnFirstOccur if-block
1476 else
1477 {
1478 /* This point of the code is reached when we must search for all
1479 * occurrences of all the strings*/
1480
1481 int pos = 0;
1482 if(m_option->m_regularExpressions)
1483 pos = rxKey.search(line,pos);
1484 else
1485 pos = line.find(strKey, pos ,m_option->m_caseSensitive);
1486
1487 while(pos != -1)
1488 {
1489 //stop polling
1490 if(m_stop)
1491 break;
1492
1493 atLeastOneStringFound = true;
1494 QString msg,
1495 capturedText;
1496 int lineNumber = line.mid(0,pos).count('\n')+1;
1497 int columnNumber = pos - line.lastIndexOf('\n',pos);
1498
1499 if(m_option->m_regularExpressions)
1500 {
1501 capturedText = rxKey.cap(1);
1502 pos = rxKey.search(line, pos+rxKey.matchedLength());
1503 }
1504 else
1505 {
1506 capturedText = line.mid(pos,strKey.length());
1507 pos = line.indexOf(strKey,pos+strKey.length());
1508 }
1509
1510 msg = i18n(" Line:%2, Col:%3 - \"%1\"", capturedText, lineNumber, columnNumber);
1511
1512 if(!item)
1513 item = new K3ListViewItem(rv);
1514 K3ListViewItem* tempItem = new K3ListViewItem(item);
1515 tempItem->setMultiLinesEnabled(true);
1516 tempItem->setText(0,msg);
1517 occurrence++;
1518 //we push stop button
1519 if(m_stop)
1520 break;
1521 }
1522 }
1523 //Advances of one position in the strings map
1524 ++it;
1525
1526 //we push stop button
1527 if(m_stop)
1528 break;
1529 }
1530
1531 //if ignoreFiles == false then every files must be show
1532 if(!m_option->m_ignoreFiles)
1533 atLeastOneStringFound = true;
1534
1535 if(atLeastOneStringFound && item)
1536 {
1537 KFileReplaceLib::setIconForFileEntry(item,currentDir+'/'+fileName);
1538 item->setText(0,fileName);
1539 item->setText(1,currentDir);
1540 item->setText(2,KFileReplaceLib::formatFileSize(fileInfo.size()));
1541 item->setText(3,QString::number(occurrence,10));
1542 item->setText(4,QString("%1[%2]").arg(fileInfo.owner()).arg(fileInfo.ownerId()));
1543 item->setText(5,QString("%1[%2]").arg(fileInfo.group()).arg(fileInfo.groupId()));
1544 }
1545}
1546
1547void KFileReplacePart::loadViewContent()
1548{
1549 /* Maps the content of the strings view to a QMap */
1550 KeyValueMap tempMap;
1551 CommandEngine command;
1552
1553 Q3ListViewItemIterator itlv(m_view->getStringsView());
1554 while(itlv.current())
1555 {
1556 Q3ListViewItem *item = itlv.current();
1557 if(m_option->m_variables)
1558 tempMap[item->text(0)] = command.variableValue(item->text(1));
1559 else
1560 tempMap[item->text(0)] = item->text(1);
1561 ++itlv;
1562 }
1563 m_replacementMap = tempMap;
1564}
1565
1566void KFileReplacePart::loadRulesFile(const QString& fileName)
1567{
1568 /* Loads a file with kfr extension.
1569 * creates a xml document and browses it*/
1570 QDomDocument doc("mydocument");
1571 QFile file(fileName);
1572 K3ListView* sv = m_view->getStringsView();
1573
1574 if(!file.open(QIODevice::ReadOnly))
1575 {
1576 KMessageBox::error(m_w, i18n("<qt>Cannot open the file <b>%1</b> and load the string list.</qt>", fileName));
1577 return ;
1578 }
1579
1580 if(!doc.setContent(&file))
1581 {
1582 file.close();
1583
1584 KMessageBox::information(m_w, i18n("<qt>File <b>%1</b> seems not to be written in new kfr format. Remember that the old kfr format will be soon abandoned. You can convert your old rules files by simply saving them with kfilereplace.</qt>", fileName),i18n("Warning"));
1585
1586 KFileReplaceLib::convertOldToNewKFRFormat(fileName, sv);
1587
1588 return;
1589 }
1590 else
1591 file.close();
1592
1593 //clears view
1594 sv->clear();
1595
1596 QDomElement docElem = doc.documentElement();
1597 QDomNode n = docElem.firstChild();
1598 QString searchAttribute = n.toElement().attribute("search").toLatin1();
1599
1600 KeyValueMap docMap;
1601
1602 if(searchAttribute.isNull() || searchAttribute.isEmpty())
1603 {
1604 int answer = KMessageBox::warningYesNo(m_w, i18n("<qt>The format of kfr files has been changed; attempting to load <b>%1</b>. Please see the KFilereplace manual for details. Do you want to load a search-and-replace list of strings?</qt>", fileName),i18n("Warning"),KGuiItem(i18n("Load")),KGuiItem(i18n("Do Not Load")));
1605
1606 if(answer == KMessageBox::Yes)
1607 searchAttribute = "false";
1608 else
1609 searchAttribute = "true";
1610 }
1611 //Verifies the search mode
1612 if(searchAttribute == "true")
1613 m_option->m_searchingOnlyMode = true;
1614 else
1615 m_option->m_searchingOnlyMode = false;
1616
1617 //Refreshes the view appearances
1618 m_view->changeView(m_option->m_searchingOnlyMode);
1619 //Goes to next tag
1620 n = n.nextSibling();
1621 //Reads the string list
1622 while(!n.isNull())
1623 {
1624 QDomElement e = n.toElement(); // tries to convert the node to an element.
1625 if(!e.isNull())
1626 {
1627 QString oldString = e.firstChild().toElement().text(),
1628 newString = e.lastChild().toElement().text();
1629 docMap[oldString] = newString;
1630 }
1631 n = n.nextSibling();
1632 }
1633
1634 // Adds file to "load strings form file" menu
1635 QStringList fileList = m_option->m_recentStringFileList;
1636 if(!fileList.contains(fileName))
1637 {
1638 fileList.append(fileName);
1639 ((KRecentFilesAction* ) actionCollection()->action("strings_load_recent"))->setItems(fileList);
1640 m_option->m_recentStringFileList = fileList;
1641 }
1642
1643 m_view->changeView(m_option->m_searchingOnlyMode);
1644
1645 m_view->loadMap(docMap);
1646
1647 //resetActions();
1648}
1649
1650bool KFileReplacePart::launchNewProjectDialog(const KUrl & startURL)
1651{
1652 if(!startURL.isEmpty())
1653 m_option->m_directories = QString(startURL.path()+','+m_option->m_directories);
1654
1655 /* This dlg reads options from m_option, then execs, finally returns options.*/
1656 KNewProjectDlg dlg(m_option);
1657
1658 if(!dlg.exec())
1659 return false;
1660
1661 dlg.saveRCOptions();
1662
1663 m_config->sync();
1664
1665 slotQuickStringsAdd();
1666
1667 m_view->updateOptions(m_option);
1668
1669 resetActions();
1670
1671 return true;
1672}
1673
1674void KFileReplacePart::setOptionMask()
1675{
1676 m_optionMask |= QDir::Dirs;
1677
1678 if(!m_option->m_ignoreHidden)
1679 m_optionMask |= QDir::Hidden;
1680
1681 if(!m_option->m_followSymLinks)
1682 m_optionMask |= QDir::NoSymLinks;
1683}
1684
1685bool KFileReplacePart::checkBeforeOperation()
1686{
1687 loadViewContent();
1688 K3ListView* sv = m_view->getStringsView();
1689
1690 // Checks if there are strings to replace (not need in search operation)
1691 if (sv->childCount() == 0)
1692 {
1693 KMessageBox::error(m_w, i18n("There are no strings to search and replace."));
1694 return false;
1695 }
1696
1697 // Checks if the main directory can be accessed
1698 QString currentDirectory = m_option->m_directories.split(",", QString::SkipEmptyParts)[0];
1699 QDir dir;
1700
1701 dir.setPath(currentDirectory);
1702 QString directory = dir.absolutePath();
1703
1704 if(!dir.exists())
1705 {
1706 KMessageBox::error(m_w, i18n("<qt>The main folder of the project <b>%1</b> does not exist.</qt>", directory));
1707 return false;
1708 }
1709
1710 QFileInfo dirInfo(directory);
1711 if(!(dirInfo.isReadable() && dirInfo.isExecutable())
1712 || (!m_option->m_searchingOnlyMode && !m_option->m_simulation && !(dirInfo.isWritable())))
1713 {
1714 KMessageBox::error(m_w, i18n("<qt>Access denied in the main folder of the project:<br /><b>%1</b></qt>", directory));
1715 return false;
1716 }
1717
1718 // Clears the list view
1719 m_view->getResultsView()->clear();
1720
1721 return true;
1722}
1723
1724bool KFileReplacePart::dontAskAgain()
1725{
1726 KConfigGroup cg( m_config, "Notification Messages");
1727 QString dontAskAgain = cg.readEntry(rcDontAskAgain, QString("no"));
1728 if(dontAskAgain == "yes")
1729 return true;
1730 else
1731 return false;
1732}
1733
1734void KFileReplacePart::whatsThis()
1735{
1736 actionCollection()->action("options_backup")->setWhatsThis(optionsBackupWhatthis);
1737 actionCollection()->action("options_case")->setWhatsThis(optionsCaseWhatthis);
1738 actionCollection()->action("options_var")->setWhatsThis(optionsVarWhatthis);
1739 actionCollection()->action("options_recursive")->setWhatsThis(optionsRecursiveWhatthis);
1740 actionCollection()->action("options_regularexpressions")->setWhatsThis(optionsRegularExpressionsWhatthis);
1741}
1742
1743#include "kfilereplacepart.moc"
1744