1/*****************************************************************************
2 kfilereplaceview.cpp - description
3 -------------------
4 begin : sam oct 16 15:28:00 CEST 1999
5 copyright : (C) 1999 by François Dupoux <dupoux@dupoux.com>
6 (C) 2004 Emiliano Gulmini <emi_barbarossa@yahoo.it>
7*****************************************************************************/
8
9/*****************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 *****************************************************************************/
17
18// Qt
19
20#include <qmap.h>
21#include <qfileinfo.h>
22//Added by qt3to4:
23#include <QTextStream>
24
25// KDE
26#include <k3listview.h>
27#include <kmessagebox.h>
28#include <klocale.h>
29#include <kmenu.h>
30#include <krun.h>
31#include <kpropertiesdialog.h>
32#include <kapplication.h>
33#include <QDBusConnection>
34#include <QDBusReply>
35#include <QDBusConnectionInterface>
36//#include <kdebug.h>
37#include <kiconloader.h>
38#include <kled.h>
39#include <kfiledialog.h>
40
41// local
42#include "kfilereplaceview.h"
43#include "kfilereplacelib.h"
44#include "kaddstringdlg.h"
45#include "whatthis.h"
46
47using namespace whatthisNameSpace;
48
49KFileReplaceView::KFileReplaceView(RCOptions* info, QWidget *parent,const char *name):KFileReplaceViewWdg(parent,name)
50{
51 m_option = info;
52
53 initGUI();
54
55 // connect events
56 connect(m_lvResults, SIGNAL(mouseButtonClicked(int, Q3ListViewItem *, const QPoint &, int)), this, SLOT(slotMouseButtonClicked(int, Q3ListViewItem *, const QPoint &)));
57 connect(m_lvResults_2, SIGNAL(mouseButtonClicked(int, Q3ListViewItem *, const QPoint &, int)), this, SLOT(slotMouseButtonClicked(int, Q3ListViewItem *, const QPoint &)));
58 connect(m_lvStrings, SIGNAL(doubleClicked(Q3ListViewItem *)), this, SLOT(slotStringsEdit()));
59 connect(m_lvStrings_2, SIGNAL(doubleClicked(Q3ListViewItem *)), this, SLOT(slotStringsEdit()));
60
61 whatsThis();
62}
63
64QString KFileReplaceView::currentPath()
65{
66 Q3ListViewItem *lvi;
67
68 if(! m_lviCurrent) lvi = m_rv->currentItem();
69 else lvi = (Q3ListViewItem*) m_lviCurrent;
70
71 while (lvi->parent())
72 lvi = lvi->parent();
73
74 return QString(lvi->text(1)+'/'+lvi->text(0));
75}
76
77void KFileReplaceView::showSemaphore(const QString &s)
78{
79 if(s == "green")
80 {
81 m_ledGo->setState(KLed::On);
82 m_ledWait->setState(KLed::Off);
83 m_ledStop->setState(KLed::Off);
84 }
85 else
86 if(s == "yellow")
87 {
88 m_ledGo->setState(KLed::Off);
89 m_ledWait->setState(KLed::On);
90 m_ledStop->setState(KLed::Off);
91 }
92 else
93 if(s == "red")
94 {
95 m_ledGo->setState(KLed::Off);
96 m_ledWait->setState(KLed::Off);
97 m_ledStop->setState(KLed::On);
98 }
99}
100
101void KFileReplaceView::stringsInvert(bool invertAll)
102{
103 Q3ListViewItem* lviCurItem,
104 * lviFirst;
105 K3ListView* sv = getStringsView();
106
107 if(invertAll)
108 lviCurItem = lviFirst = sv->firstChild();
109 else
110 lviCurItem = lviFirst = sv->currentItem();
111
112 if(lviCurItem == 0)
113 return ;
114
115 do
116 {
117 QString searchText = lviCurItem->text(0),
118 replaceText = lviCurItem->text(1);
119
120 // Cannot invert the string when search string is empty
121 if (replaceText.isEmpty())
122 {
123 KMessageBox::error(0, i18n("<qt>Cannot invert string <b>%1</b>, because the search string would be empty.</qt>", searchText));
124 return;
125 }
126
127 lviCurItem->setText(0, replaceText);
128 lviCurItem->setText(1, searchText);
129
130 lviCurItem = lviCurItem->nextSibling();
131 if(!invertAll)
132 break;
133 } while(lviCurItem && lviCurItem != lviFirst);
134 setCurrentStringsViewMap();
135}
136
137void KFileReplaceView::changeView(bool searchingOnlyMode)
138{
139 if(searchingOnlyMode)
140 {
141 m_stackResults->raiseWidget(m_lvResults_2);
142 m_stackStrings->raiseWidget(m_lvStrings_2);
143 m_rv = m_lvResults_2;
144 m_sv = m_lvStrings_2;
145 }
146 else
147 {
148 m_stackResults->raiseWidget(m_lvResults);
149 m_stackStrings->raiseWidget(m_lvStrings);
150 m_rv = m_lvResults;
151 m_sv = m_lvStrings;
152 }
153}
154
155K3ListView* KFileReplaceView::getResultsView()
156{
157 if(m_option->m_searchingOnlyMode)
158 m_rv = m_lvResults_2;
159 else
160 m_rv = m_lvResults;
161
162 return m_rv;
163}
164
165K3ListView* KFileReplaceView::getStringsView()
166{
167 if(m_option->m_searchingOnlyMode)
168 m_sv = m_lvStrings_2;
169 else
170 m_sv = m_lvStrings;
171 return m_sv;
172}
173
174//PUBLIC SLOTS
175void KFileReplaceView::slotMouseButtonClicked (int button, Q3ListViewItem *lvi, const QPoint &pos)
176{
177 if (lvi == 0) // No item selected
178 return;
179
180 // RIGHT BUTTON
181 if (button == Qt::RightButton)
182 {
183 m_lviCurrent = static_cast<K3ListViewItem*>(lvi);
184 m_menuResult->popup(pos);
185 }
186}
187
188void KFileReplaceView::slotResultProperties()
189{
190 QString currItem = currentPath();
191 if(! currItem.isEmpty())
192 {
193 KUrl item_url(currItem);
194 KPropertiesDialog dlg(item_url, this);
195 dlg.exec();
196 m_lviCurrent = 0;
197 }
198}
199
200void KFileReplaceView::slotResultOpen()
201{
202 QString currItem = currentPath();
203 if(!currItem.isEmpty())
204 {
205 (void) new KRun(KUrl(currItem), 0, true, true);
206 m_lviCurrent = 0;
207 }
208}
209
210void KFileReplaceView::slotResultOpenWith()
211{
212 QString currItem = currentPath();
213 if(!currItem.isEmpty())
214 {
215 KUrl::List kurls;
216 kurls.append(KUrl(currItem));
217 KRun::displayOpenWithDialog(kurls, this);
218 m_lviCurrent = 0;
219 }
220}
221
222void KFileReplaceView::slotResultDirOpen()
223{
224 QString currItem = currentPath();
225 if(!currItem.isEmpty())
226 {
227 QFileInfo fi;
228 fi.setFile(currItem);
229 (void) new KRun (KUrl::fromPathOrUrl(fi.path()), 0, true, true);
230 m_lviCurrent = 0;
231 }
232}
233
234void KFileReplaceView::slotResultEdit()
235{
236#ifdef __GNUC__
237#warning "Port to DBUS"
238#endif
239 //FIXME: Port to DBUS
240/*
241 Q3ListViewItem *lvi = m_rv->firstChild();
242
243 while (lvi)
244 {
245 DCOPClient *client = kapp->dcopClient();
246 DCOPRef quanta(client->appId(),"WindowManagerIf");
247 QString path = QString(lvi->text(1)+'/'+lvi->text(0));
248 Q3ListViewItem *lviChild = lvi;
249
250 while(lviChild)
251 {
252 if(lviChild->isSelected())
253 {
254 coord c;
255 if(lviChild == lvi)
256 {
257 c.line = 0;
258 c.column = 0;
259 }
260 else
261 {
262 c= extractWordCoordinates(lviChild);
263 }
264 bool success = quanta.send("openFile", path, c.line, c.column);
265
266 if(!success)
267 {
268 QString message = i18n("File %1 cannot be opened. Might be a DCOP problem.", path);
269 KMessageBox::error(parentWidget(), message);
270 }
271 }
272 if (lviChild == lvi)
273 lviChild = lviChild->firstChild();
274 else
275 lviChild = lviChild->nextSibling();
276 }
277
278 lvi = lvi->nextSibling();
279 }
280
281 m_lviCurrent = 0;
282*/
283}
284
285void KFileReplaceView::slotResultDelete()
286{
287 QString currItem = currentPath();
288 if (!currItem.isEmpty())
289 {
290 QFile fi;
291 int answer = KMessageBox::warningContinueCancel(this, i18n("Do you really want to delete %1?", currItem),
292 QString::null,KStandardGuiItem::del()); //krazy:exclude=nullstrassign for old broken gcc
293
294 if(answer == KMessageBox::Continue)
295 {
296 fi.setFileName(currItem);
297 fi.remove();
298
299 delete m_lviCurrent;
300 m_lviCurrent = 0;
301 }
302 }
303}
304
305void KFileReplaceView::slotResultTreeExpand()
306{
307 Q3ListViewItem *lviRoot = getResultsView()->firstChild();
308
309 if(lviRoot)
310 expand(lviRoot, true);
311}
312
313void KFileReplaceView::slotResultTreeReduce()
314{
315 Q3ListViewItem *lviRoot = getResultsView()->firstChild();
316
317 if(lviRoot)
318 expand(lviRoot, false);
319}
320
321void KFileReplaceView::slotStringsAdd()
322{
323 KeyValueMap oldMap(m_option->m_mapStringsView);
324
325 KAddStringDlg addStringDlg(m_option, false);
326
327 if(!addStringDlg.exec())
328 return;
329
330 KeyValueMap addedStringsMap(m_option->m_mapStringsView);
331 KeyValueMap::Iterator itMap;
332
333 for(itMap = oldMap.begin(); itMap != oldMap.end(); ++itMap)
334 addedStringsMap.insert(itMap.key(),itMap.data());
335
336 m_option->m_mapStringsView = addedStringsMap;
337
338 raiseResultsView();
339 raiseStringsView();
340
341 loadMapIntoView(addedStringsMap);
342}
343
344void KFileReplaceView::slotQuickStringsAdd(const QString& quickSearch, const QString& quickReplace)
345{
346 if(!quickSearch.isEmpty())
347 {
348 KeyValueMap map;
349 if(quickReplace.isEmpty())
350 {
351 map[quickSearch] = QString::null; //krazy:exclude=nullstrassign for old broken gcc
352 m_option->m_searchingOnlyMode = true;
353 }
354 else
355 {
356 map[quickSearch] = quickReplace;
357 m_option->m_searchingOnlyMode = false;
358 }
359
360 m_option->m_mapStringsView = map;
361
362 raiseResultsView();
363 raiseStringsView();
364
365 loadMapIntoView(map);
366 }
367}
368
369void KFileReplaceView::slotStringsEdit()
370{
371 KeyValueMap oldMap(m_option->m_mapStringsView);
372 if(oldMap.isEmpty()) return;
373 bool oldSearchFlagValue = m_option->m_searchingOnlyMode;
374
375 oldMap.remove(m_sv->currentItem()->text(0));
376
377 m_option->m_mapStringsView.clear();
378
379 m_option->m_mapStringsView.insert(m_sv->currentItem()->text(0), m_sv->currentItem()->text(1));
380
381 KAddStringDlg addStringDlg(m_option, true);
382
383 if(!addStringDlg.exec())
384 return;
385
386 KeyValueMap newMap(m_option->m_mapStringsView);
387 if(oldSearchFlagValue == m_option->m_searchingOnlyMode)
388 {
389 KeyValueMap::Iterator itMap;
390
391 //merges the two maps
392 for(itMap = oldMap.begin(); itMap != oldMap.end(); ++itMap)
393 newMap.insert(itMap.key(),itMap.data());
394 }
395
396 m_option->m_mapStringsView = newMap;
397
398 raiseResultsView();
399 raiseStringsView();
400
401 loadMapIntoView(newMap);
402}
403
404void KFileReplaceView::slotStringsSave()
405{
406 // Check there are strings in the list
407 K3ListView* sv = getStringsView();
408
409 if (sv->firstChild() == 0)
410 {
411 KMessageBox::error(0, i18n("No strings to save as the list is empty."));
412 return ;
413 }
414
415 QString header("<?xml version=\"1.0\" ?>\n<kfr>"),
416 footer("\n</kfr>"),
417 body;
418 if(m_option->m_searchingOnlyMode)
419 header += "\n\t<mode search=\"true\"/>";
420 else
421 header += "\n\t<mode search=\"false\"/>";
422
423 Q3ListViewItem* lvi = sv->firstChild();
424
425 while( lvi )
426 {
427 body += QString("\n\t<replacement>"
428 "\n\t\t<oldstring><![CDATA[%1]]></oldstring>"
429 "\n\t\t<newstring><![CDATA[%2]]></newstring>"
430 "\n\t</replacement>").arg(lvi->text(0)).arg(lvi->text(1));
431 lvi = lvi->nextSibling();
432 }
433
434 // Selects the file where strings will be saved
435 QString menu = "*.kfr|" + i18n("KFileReplace Strings") + " (*.kfr)\n*|" + i18n("All Files") + " (*)";
436 QString fileName = KFileDialog::getSaveFileName(KUrl(), menu, 0, i18n("Save Strings to File"));
437 if (fileName.isEmpty())
438 return;
439
440 // Forces the extension to be "kfr" == KFileReplace extension
441
442 fileName = KFileReplaceLib::addExtension(fileName, "kfr");
443
444 QFile file( fileName );
445 if(!file.open( QIODevice::WriteOnly ))
446 {
447 KMessageBox::error(0, i18n("File %1 cannot be saved.", fileName));
448 return ;
449 }
450 QTextStream oTStream( &file );
451 oTStream.setCodec(QTextCodec::codecForName("UTF-8"));
452 oTStream << header
453 << body
454 << footer;
455 file.close();
456}
457
458void KFileReplaceView::slotStringsDeleteItem()
459{
460 Q3ListViewItem* item = m_sv->currentItem();
461 if(item != 0)
462 {
463 KeyValueMap m = m_option->m_mapStringsView;
464 m.remove(item->text(0));
465 m_option->m_mapStringsView = m;
466 delete item;
467 }
468}
469
470void KFileReplaceView::slotStringsEmpty()
471{
472 Q3ListViewItem * myChild = m_sv->firstChild();
473 while( myChild )
474 {
475 Q3ListViewItem* item = myChild;
476 myChild = myChild->nextSibling();
477 delete item;
478 }
479 KeyValueMap m;
480 m_option->m_mapStringsView = m;
481}
482
483//PRIVATE
484void KFileReplaceView::initGUI()
485{
486 m_option->m_searchingOnlyMode = true;
487
488 m_stackResults->addWidget(m_lvResults);
489 m_stackResults->addWidget(m_lvResults_2);
490 m_stackStrings->addWidget(m_lvStrings);
491 m_stackStrings->addWidget(m_lvStrings_2);
492
493 bool quantaFound = false;
494 QDBusConnection dbus = QDBusConnection::sessionBus();
495 QDBusReply<QStringList> reply = dbus.interface()->registeredServiceNames();
496 if ( !reply.isValid() )
497 return;
498
499 const QStringList allServices = reply;
500 for ( QStringList::const_iterator it = allServices.begin(), end = allServices.end() ; it != end ; ++it ) {
501 const QString service = *it;
502 if ( service.startsWith( "org.kde.quanta" ) ) {
503 quantaFound = true;
504 break;
505 }
506 }
507
508 m_menuResult = new KMenu(this);
509
510
511
512 m_menuResult->insertItem(SmallIconSet(QString::fromLatin1("document-open")),
513 i18n("&Open"),
514 this,
515 SLOT(slotResultOpen()));
516 if(!quantaFound)
517 {
518 m_menuResult->insertItem(i18n("Open &With..."),
519 this,
520 SLOT(slotResultOpenWith()));
521 }
522
523 if(quantaFound)
524 {
525 m_menuResult->insertItem(SmallIconSet("quanta"),
526 i18n("&Edit in Quanta"),
527 this,
528 SLOT(slotResultEdit()));
529 }
530
531 m_menuResult->insertItem(SmallIconSet(QString::fromLatin1("go-up")),
532 i18n("Open Parent &Folder"),
533 this,
534 SLOT(slotResultDirOpen()));
535 m_menuResult->insertItem(SmallIconSet(QString::fromLatin1("edit-delete")),
536 i18n("&Delete"),
537 this,
538 SLOT(slotResultDelete()));
539 m_menuResult->insertSeparator();
540 m_menuResult->insertItem(SmallIconSet(QString::fromLatin1("document-properties")),
541 i18n("&Properties"),
542 this,
543 SLOT(slotResultProperties()));
544 raiseResultsView();
545 raiseStringsView();
546}
547
548void KFileReplaceView::raiseStringsView()
549{
550 if(m_option->m_searchingOnlyMode)
551 m_sv = m_lvStrings_2;
552 else
553 m_sv = m_lvStrings;
554
555 m_stackStrings->raiseWidget(m_sv);
556}
557
558void KFileReplaceView::raiseResultsView()
559{
560 if(m_option->m_searchingOnlyMode)
561 m_rv = m_lvResults_2;
562 else
563 m_rv = m_lvResults;
564
565 m_stackResults->raiseWidget(m_rv);
566}
567
568coord KFileReplaceView::extractWordCoordinates(Q3ListViewItem* lvi)
569{
570 //get coordinates of the first string of the current selected file
571 coord c;
572 c.line = 0;
573 c.column = 0;
574 QString s = lvi->text(0);
575 //qWarning("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW=%s",s.latin1());
576 /* if(lvi->parent()) s = lvi->text(0);
577 else return c;*/
578
579 QString temp;
580 int i = 0;
581
582 //extracts line and column from lvi->text(0)
583 //FIXME: Don't get the line and column number from the text as it's translated and it will
584 //fail for non-English languages!
585
586 //EMILIANO: This is not a good fixing but for now it should reduce the problems
587 while(true)
588 {
589 if(s[i] < '0' || s[i] > '9')
590 i++;
591 else
592 break;
593 }
594 while(true)
595 {
596 if(s[i] >= '0' && s[i] <= '9')
597 {
598 temp += s[i];
599 i++;
600 }
601 else
602 break;
603 }
604 c.line = temp.toInt();
605 temp.clear();
606
607 while(true)
608 {
609 if(s[i] < '0' || s[i] > '9')
610 i++;
611 else
612 break;
613 }
614 while(true)
615 {
616 if(s[i] >= '0' && s[i] <= '9')
617 {
618 temp += s[i];
619 i++;
620 }
621 else
622 break;
623 }
624 c.column = temp.toInt();
625
626 if(c.line > 0) c.line--;
627 if(c.column > 0) c.column--;
628
629 return c;
630}
631
632void KFileReplaceView::expand(Q3ListViewItem *lviCurrent, bool b)
633{
634 // current item
635 lviCurrent->setOpen(b);
636
637 // recursivity
638 while((lviCurrent = lviCurrent->nextSibling()) != 0)
639 {
640 lviCurrent->setOpen(b);
641
642 if (lviCurrent->firstChild())
643 expand(lviCurrent->firstChild(), b);
644 }
645}
646
647void KFileReplaceView::setMap()
648{
649 KeyValueMap map;
650 Q3ListViewItem* i = m_sv->firstChild();
651 while(i != 0)
652 {
653 if(m_option->m_searchingOnlyMode)
654 map[i->text(0)] = QString::null; //krazy:exclude=nullstrassign for old broken gcc
655 else
656 map[i->text(0)] = i->text(1);
657 i = i->nextSibling();
658 }
659 m_option->m_mapStringsView = map;
660}
661
662void KFileReplaceView::loadMapIntoView(KeyValueMap map)
663{
664 m_sv->clear();
665 KeyValueMap::Iterator itMap;
666
667 for(itMap = map.begin(); itMap != map.end(); ++itMap)
668 {
669 Q3ListViewItem* lvi = new Q3ListViewItem(m_sv);
670 lvi->setMultiLinesEnabled(true);
671 lvi->setText(0,itMap.key());
672 if(!m_option->m_searchingOnlyMode)
673 lvi->setText(1,itMap.data());
674 }
675
676}
677
678void KFileReplaceView::whatsThis()
679{
680 getResultsView()->setWhatsThis( lvResultWhatthis);
681 getStringsView()->setWhatsThis( lvStringsWhatthis);
682}
683#include "kfilereplaceview.moc"
684