]> cloud.milkyroute.net Git - dolphin.git/blob - src/dolphin.cpp
Let's remove the connect errors because of the KJob/KIO::Job split.
[dolphin.git] / src / dolphin.cpp
1 /***************************************************************************
2 * Copyright (C) 2006 by Peter Penz <peter.penz@gmx.at> *
3 * Copyright (C) 2006 by Stefan Monov <logixoul@gmail.com> *
4 * Copyright (C) 2006 by Cvetoslav Ludmiloff <ludmiloff@gmail.com> *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the *
18 * Free Software Foundation, Inc., *
19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
20 ***************************************************************************/
21
22 #include "dolphin.h"
23
24 #include <assert.h>
25
26 #include <kactioncollection.h>
27 #include <ktoggleaction.h>
28 #include <kbookmarkmanager.h>
29 #include <kglobal.h>
30 #include <kpropertiesdialog.h>
31 #include <kicon.h>
32 #include <kiconloader.h>
33 #include <kdeversion.h>
34 #include <kstatusbar.h>
35 #include <kio/netaccess.h>
36 #include <kfiledialog.h>
37 #include <kconfig.h>
38 #include <kurl.h>
39 #include <kstdaccel.h>
40 #include <kaction.h>
41 #include <kstdaction.h>
42 #include <kmenu.h>
43 #include <kio/renamedlg.h>
44 #include <kinputdialog.h>
45 #include <kshell.h>
46 #include <kdesktopfile.h>
47 #include <kstandarddirs.h>
48 #include <kprotocolinfo.h>
49 #include <kmessagebox.h>
50 #include <kservice.h>
51 #include <kstandarddirs.h>
52 #include <krun.h>
53 #include <klocale.h>
54
55 #include <qclipboard.h>
56 #include <q3dragobject.h>
57 //Added by qt3to4:
58 #include <Q3ValueList>
59 #include <QCloseEvent>
60 #include <QSplitter>
61
62 #include "urlnavigator.h"
63 #include "viewpropertiesdialog.h"
64 #include "viewproperties.h"
65 #include "dolphinsettings.h"
66 #include "dolphinsettingsdialog.h"
67 #include "dolphinstatusbar.h"
68 #include "undomanager.h"
69 #include "progressindicator.h"
70 #include "dolphinsettings.h"
71 #include "sidebar.h"
72 #include "sidebarsettings.h"
73 #include "generalsettings.h"
74
75 Dolphin& Dolphin::mainWin()
76 {
77 static Dolphin* instance = 0;
78 if (instance == 0) {
79 instance = new Dolphin();
80 instance->init();
81 }
82 return *instance;
83 }
84
85 Dolphin::~Dolphin()
86 {
87 }
88
89 void Dolphin::setActiveView(DolphinView* view)
90 {
91 assert((view == m_view[PrimaryIdx]) || (view == m_view[SecondaryIdx]));
92 if (m_activeView == view) {
93 return;
94 }
95
96 m_activeView = view;
97
98 updateHistory();
99 updateEditActions();
100 updateViewActions();
101 updateGoActions();
102
103 setCaption(m_activeView->url().fileName());
104
105 emit activeViewChanged();
106 }
107
108 void Dolphin::dropUrls(const KUrl::List& urls,
109 const KUrl& destination)
110 {
111 int selectedIndex = -1;
112
113 /* KDE4-TODO
114 const ButtonState keyboardState = KApplication::keyboardMouseState();
115 const bool shiftPressed = (keyboardState & ShiftButton) > 0;
116 const bool controlPressed = (keyboardState & ControlButton) > 0;
117
118
119
120 if (shiftPressed && controlPressed) {
121 // shortcut for 'Linke Here' is used
122 selectedIndex = 2;
123 }
124 else if (controlPressed) {
125 // shortcut for 'Copy Here' is used
126 selectedIndex = 1;
127 }
128 else if (shiftPressed) {
129 // shortcut for 'Move Here' is used
130 selectedIndex = 0;
131 }
132 else*/ {
133 // no shortcut is used, hence open a popup menu
134 KMenu popup(this);
135
136 popup.insertItem(SmallIcon("goto"), i18n("&Move Here") + "\t" /* KDE4-TODO: + KKey::modFlagLabel(KKey::SHIFT)*/, 0);
137 popup.insertItem(SmallIcon("editcopy"), i18n( "&Copy Here" ) /* KDE4-TODO + "\t" + KKey::modFlagLabel(KKey::CTRL)*/, 1);
138 popup.insertItem(i18n("&Link Here") /* KDE4-TODO + "\t" + KKey::modFlagLabel((KKey::ModFlag)(KKey::CTRL|KKey::SHIFT)) */, 2);
139 popup.insertSeparator();
140 popup.insertItem(SmallIcon("stop"), i18n("Cancel"), 3);
141 popup.setAccel(i18n("Escape"), 3);
142
143 /* KDE4-TODO: selectedIndex = popup.exec(QCursor::pos()); */
144 popup.exec(QCursor::pos());
145 selectedIndex = 0; // KD4-TODO: use QAction instead of switch below
146 // See libkonq/konq_operations.cc: KonqOperations::doDropFileCopy() (and doDrop, the main method)
147 }
148
149 if (selectedIndex < 0) {
150 return;
151 }
152
153 switch (selectedIndex) {
154 case 0: {
155 // 'Move Here' has been selected
156 updateViewProperties(urls);
157 moveUrls(urls, destination);
158 break;
159 }
160
161 case 1: {
162 // 'Copy Here' has been selected
163 updateViewProperties(urls);
164 copyUrls(urls, destination);
165 break;
166 }
167
168 case 2: {
169 // 'Link Here' has been selected
170 KIO::Job* job = KIO::link(urls, destination);
171 addPendingUndoJob(job, DolphinCommand::Link, urls, destination);
172 break;
173 }
174
175 default:
176 // 'Cancel' has been selected
177 break;
178 }
179 }
180
181 void Dolphin::refreshViews()
182 {
183 const bool split = DolphinSettings::instance().generalSettings()->splitView();
184 const bool isPrimaryViewActive = (m_activeView == m_view[PrimaryIdx]);
185 KUrl url;
186 for (int i = PrimaryIdx; i <= SecondaryIdx; ++i) {
187 if (m_view[i] != 0) {
188 url = m_view[i]->url();
189
190 // delete view instance...
191 m_view[i]->close();
192 m_view[i]->deleteLater();
193 m_view[i] = 0;
194 }
195
196 if (split || (i == PrimaryIdx)) {
197 // ... and recreate it
198 ViewProperties props(url);
199 m_view[i] = new DolphinView(m_splitter,
200 url,
201 props.viewMode(),
202 props.isShowHiddenFilesEnabled());
203 m_view[i]->show();
204 }
205 }
206
207 m_activeView = isPrimaryViewActive ? m_view[PrimaryIdx] : m_view[SecondaryIdx];
208 assert(m_activeView != 0);
209
210 updateViewActions();
211 emit activeViewChanged();
212 }
213
214 void Dolphin::slotHistoryChanged()
215 {
216 updateHistory();
217 }
218
219 void Dolphin::slotUrlChanged(const KUrl& url)
220 {
221 updateEditActions();
222 updateGoActions();
223 setCaption(url.fileName());
224 }
225
226 void Dolphin::slotUrlChangeRequest(const KUrl& url)
227 {
228 clearStatusBar();
229 m_activeView->setUrl(url);
230 }
231
232 void Dolphin::slotViewModeChanged()
233 {
234 updateViewActions();
235 }
236
237 void Dolphin::slotShowHiddenFilesChanged()
238 {
239 KToggleAction* showHiddenFilesAction =
240 static_cast<KToggleAction*>(actionCollection()->action("show_hidden_files"));
241 showHiddenFilesAction->setChecked(m_activeView->isShowHiddenFilesEnabled());
242 }
243
244 void Dolphin::slotShowFilterBarChanged()
245 {
246 KToggleAction* showFilterBarAction =
247 static_cast<KToggleAction*>(actionCollection()->action("show_filter_bar"));
248 showFilterBarAction->setChecked(m_activeView->isFilterBarVisible());
249 }
250
251 void Dolphin::slotSortingChanged(DolphinView::Sorting sorting)
252 {
253 KAction* action = 0;
254 switch (sorting) {
255 case DolphinView::SortByName:
256 action = actionCollection()->action("by_name");
257 break;
258 case DolphinView::SortBySize:
259 action = actionCollection()->action("by_size");
260 break;
261 case DolphinView::SortByDate:
262 action = actionCollection()->action("by_date");
263 break;
264 default:
265 break;
266 }
267
268 if (action != 0) {
269 KToggleAction* toggleAction = static_cast<KToggleAction*>(action);
270 toggleAction->setChecked(true);
271 }
272 }
273
274 void Dolphin::slotSortOrderChanged(Qt::SortOrder order)
275 {
276 KToggleAction* descending = static_cast<KToggleAction*>(actionCollection()->action("descending"));
277 const bool sortDescending = (order == Qt::Descending);
278 descending->setChecked(sortDescending);
279 }
280
281 void Dolphin::slotSelectionChanged()
282 {
283 updateEditActions();
284
285 assert(m_view[PrimaryIdx] != 0);
286 int selectedUrlsCount = m_view[PrimaryIdx]->selectedUrls().count();
287 if (m_view[SecondaryIdx] != 0) {
288 selectedUrlsCount += m_view[SecondaryIdx]->selectedUrls().count();
289 }
290
291 KAction* compareFilesAction = actionCollection()->action("compare_files");
292 compareFilesAction->setEnabled(selectedUrlsCount == 2);
293
294 m_activeView->updateStatusBar();
295
296 emit selectionChanged();
297 }
298
299 void Dolphin::closeEvent(QCloseEvent* event)
300 {
301 // KDE4-TODO
302 //KConfig* config = KGlobal::config();
303 //config->setGroup("General");
304 //config->writeEntry("First Run", false);
305
306 DolphinSettings& settings = DolphinSettings::instance();
307 GeneralSettings* generalSettings = settings.generalSettings();
308 generalSettings->setFirstRun(false);
309
310 SidebarSettings* sidebarSettings = settings.sidebarSettings();
311 const bool isSidebarVisible = (m_sidebar != 0);
312 sidebarSettings->setVisible(isSidebarVisible);
313 if (isSidebarVisible) {
314 sidebarSettings->setWidth(m_sidebar->width());
315 }
316
317 settings.save();
318
319 KMainWindow::closeEvent(event);
320 }
321
322 void Dolphin::saveProperties(KConfig* config)
323 {
324 config->setGroup("Primary view");
325 config->writeEntry("Url", m_view[PrimaryIdx]->url().url());
326 config->writeEntry("Editable Url", m_view[PrimaryIdx]->isUrlEditable());
327 if (m_view[SecondaryIdx] != 0) {
328 config->setGroup("Secondary view");
329 config->writeEntry("Url", m_view[SecondaryIdx]->url().url());
330 config->writeEntry("Editable Url", m_view[SecondaryIdx]->isUrlEditable());
331 }
332 }
333
334 void Dolphin::readProperties(KConfig* config)
335 {
336 config->setGroup("Primary view");
337 m_view[PrimaryIdx]->setUrl(config->readEntry("Url"));
338 m_view[PrimaryIdx]->setUrlEditable(config->readBoolEntry("Editable Url"));
339 if (config->hasGroup("Secondary view")) {
340 config->setGroup("Secondary view");
341 if (m_view[SecondaryIdx] == 0) {
342 toggleSplitView();
343 }
344 m_view[SecondaryIdx]->setUrl(config->readEntry("Url"));
345 m_view[SecondaryIdx]->setUrlEditable(config->readBoolEntry("Editable Url"));
346 }
347 else if (m_view[SecondaryIdx] != 0) {
348 toggleSplitView();
349 }
350 }
351
352 void Dolphin::createFolder()
353 {
354 // Parts of the following code have been taken
355 // from the class KonqPopupMenu located in
356 // libqonq/konq_popupmenu.h of Konqueror.
357 // (Copyright (C) 2000 David Faure <faure@kde.org>,
358 // Copyright (C) 2001 Holger Freyther <freyther@yahoo.com>)
359
360 clearStatusBar();
361
362 DolphinStatusBar* statusBar = m_activeView->statusBar();
363 const KUrl baseUrl(m_activeView->url());
364
365 QString name(i18n("New Folder"));
366 baseUrl.path(KUrl::AddTrailingSlash);
367
368
369 if (baseUrl.isLocalFile() && QFileInfo(baseUrl.path(KUrl::AddTrailingSlash) + name).exists()) {
370 name = KIO::RenameDlg::suggestName(baseUrl, i18n("New Folder"));
371 }
372
373 bool ok = false;
374 name = KInputDialog::getText(i18n("New Folder"),
375 i18n("Enter folder name:" ),
376 name,
377 &ok,
378 this);
379
380 if (!ok) {
381 // the user has pressed 'Cancel'
382 return;
383 }
384
385 assert(!name.isEmpty());
386
387 KUrl url;
388 if ((name[0] == '/') || (name[0] == '~')) {
389 url.setPath(KShell::tildeExpand(name));
390 }
391 else {
392 name = KIO::encodeFileName(name);
393 url = baseUrl;
394 url.addPath(name);
395 }
396 ok = KIO::NetAccess::mkdir(url, this);
397
398 // TODO: provide message type hint
399 if (ok) {
400 statusBar->setMessage(i18n("Created folder %1.",url.path()),
401 DolphinStatusBar::OperationCompleted);
402
403 DolphinCommand command(DolphinCommand::CreateFolder, KUrl::List(), url);
404 UndoManager::instance().addCommand(command);
405 }
406 else {
407 // Creating of the folder has been failed. Check whether the creating
408 // has been failed because a folder with the same name exists...
409 if (KIO::NetAccess::exists(url, true, this)) {
410 statusBar->setMessage(i18n("A folder named %1 already exists.",url.path()),
411 DolphinStatusBar::Error);
412 }
413 else {
414 statusBar->setMessage(i18n("Creating of folder %1 failed.",url.path()),
415 DolphinStatusBar::Error);
416 }
417
418 }
419 }
420
421 void Dolphin::createFile()
422 {
423 // Parts of the following code have been taken
424 // from the class KonqPopupMenu located in
425 // libqonq/konq_popupmenu.h of Konqueror.
426 // (Copyright (C) 2000 David Faure <faure@kde.org>,
427 // Copyright (C) 2001 Holger Freyther <freyther@yahoo.com>)
428
429 clearStatusBar();
430
431 // TODO: const Entry& entry = m_createFileTemplates[QString(sender->name())];
432 // should be enough. Anyway: the implemantation of [] does a linear search internally too.
433 KSortableList<CreateFileEntry, QString>::ConstIterator it = m_createFileTemplates.begin();
434 KSortableList<CreateFileEntry, QString>::ConstIterator end = m_createFileTemplates.end();
435
436 const QString senderName(sender()->name());
437 bool found = false;
438 CreateFileEntry entry;
439 while (!found && (it != end)) {
440 if ((*it).index() == senderName) {
441 entry = (*it).value();
442 found = true;
443 }
444 else {
445 ++it;
446 }
447 }
448
449 DolphinStatusBar* statusBar = m_activeView->statusBar();
450 if (!found || !QFile::exists(entry.templatePath)) {
451 statusBar->setMessage(i18n("Could not create file."), DolphinStatusBar::Error);
452 return;
453 }
454
455 // Get the source path of the template which should be copied.
456 // The source path is part of the Url entry of the desktop file.
457 const int pos = entry.templatePath.findRev('/');
458 QString sourcePath(entry.templatePath.left(pos + 1));
459 sourcePath += KDesktopFile(entry.templatePath, true).readPathEntry("Url");
460
461 QString name(i18n(entry.name.ascii()));
462 // Most entry names end with "..." (e. g. "HTML File..."), which is ok for
463 // menus but no good choice for a new file name -> remove the dots...
464 name.replace("...", QString::null);
465
466 // add the file extension to the name
467 name.append(sourcePath.right(sourcePath.length() - sourcePath.findRev('.')));
468
469 // Check whether a file with the current name already exists. If yes suggest automatically
470 // a unique file name (e. g. "HTML File" will be replaced by "HTML File_1").
471 const KUrl viewUrl(m_activeView->url());
472 const bool fileExists = viewUrl.isLocalFile() &&
473 QFileInfo(viewUrl.path(KUrl::AddTrailingSlash) + KIO::encodeFileName(name)).exists();
474 if (fileExists) {
475 name = KIO::RenameDlg::suggestName(viewUrl, name);
476 }
477
478 // let the user change the suggested file name
479 bool ok = false;
480 name = KInputDialog::getText(entry.name,
481 entry.comment,
482 name,
483 &ok,
484 this);
485 if (!ok) {
486 // the user has pressed 'Cancel'
487 return;
488 }
489
490 // before copying the template to the destination path check whether a file
491 // with the given name already exists
492 const QString destPath(viewUrl.pathOrUrl() + "/" + KIO::encodeFileName(name));
493 const KUrl destUrl(destPath);
494 if (KIO::NetAccess::exists(destUrl, false, this)) {
495 statusBar->setMessage(i18n("A file named %1 already exists.",name),
496 DolphinStatusBar::Error);
497 return;
498 }
499
500 // copy the template to the destination path
501 const KUrl sourceUrl(sourcePath);
502 KIO::CopyJob* job = KIO::copyAs(sourceUrl, destUrl);
503 job->setDefaultPermissions(true);
504 if (KIO::NetAccess::synchronousRun(job, this)) {
505 statusBar->setMessage(i18n("Created file %1.",name),
506 DolphinStatusBar::OperationCompleted);
507
508 KUrl::List list;
509 list.append(sourceUrl);
510 DolphinCommand command(DolphinCommand::CreateFile, list, destUrl);
511 UndoManager::instance().addCommand(command);
512
513 }
514 else {
515 statusBar->setMessage(i18n("Creating of file %1 failed.",name),
516 DolphinStatusBar::Error);
517 }
518 }
519
520 void Dolphin::rename()
521 {
522 clearStatusBar();
523 m_activeView->renameSelectedItems();
524 }
525
526 void Dolphin::moveToTrash()
527 {
528 clearStatusBar();
529 KUrl::List selectedUrls = m_activeView->selectedUrls();
530 KIO::Job* job = KIO::trash(selectedUrls);
531 addPendingUndoJob(job, DolphinCommand::Trash, selectedUrls, m_activeView->url());
532 }
533
534 void Dolphin::deleteItems()
535 {
536 clearStatusBar();
537
538 KUrl::List list = m_activeView->selectedUrls();
539 const uint itemCount = list.count();
540 assert(itemCount >= 1);
541
542 QString text;
543 if (itemCount > 1) {
544 text = i18n("Do you really want to delete the %1 selected items?",itemCount);
545 }
546 else {
547 const KUrl& url = list.first();
548 text = i18n("Do you really want to delete '%1'?",url.fileName());
549 }
550
551 const bool del = KMessageBox::warningContinueCancel(this,
552 text,
553 QString::null,
554 KGuiItem(i18n("Delete"), SmallIcon("editdelete"))
555 ) == KMessageBox::Continue;
556 if (del) {
557 KIO::Job* job = KIO::del(list);
558 connect(job, SIGNAL(result(KJob*)),
559 this, SLOT(slotHandleJobError(KJob*)));
560 connect(job, SIGNAL(result(KJob*)),
561 this, SLOT(slotDeleteFileFinished(KJob*)));
562 }
563 }
564
565 void Dolphin::properties()
566 {
567 const KFileItemList* sourceList = m_activeView->selectedItems();
568 if (sourceList == 0) {
569 return;
570 }
571
572 KFileItemList list;
573 KFileItemList::const_iterator it = sourceList->begin();
574 const KFileItemList::const_iterator end = sourceList->end();
575 KFileItem* item = 0;
576 while (it != end) {
577 list.append(item);
578 ++it;
579 }
580
581 new KPropertiesDialog(list, this);
582 }
583
584 void Dolphin::quit()
585 {
586 close();
587 }
588
589 void Dolphin::slotHandleJobError(KJob* job)
590 {
591 if (job->error() != 0) {
592 m_activeView->statusBar()->setMessage(job->errorString(),
593 DolphinStatusBar::Error);
594 }
595 }
596
597 void Dolphin::slotDeleteFileFinished(KJob* job)
598 {
599 if (job->error() == 0) {
600 m_activeView->statusBar()->setMessage(i18n("Delete operation completed."),
601 DolphinStatusBar::OperationCompleted);
602
603 // TODO: In opposite to the 'Move to Trash' operation in the class KFileIconView
604 // no rearranging of the item position is done when a file has been deleted.
605 // This is bypassed by reloading the view, but it might be worth to investigate
606 // deeper for the root of this issue.
607 m_activeView->reload();
608 }
609 }
610
611 void Dolphin::slotUndoAvailable(bool available)
612 {
613 KAction* undoAction = actionCollection()->action(KStdAction::stdName(KStdAction::Undo));
614 if (undoAction != 0) {
615 undoAction->setEnabled(available);
616 }
617 }
618
619 void Dolphin::slotUndoTextChanged(const QString& text)
620 {
621 KAction* undoAction = actionCollection()->action(KStdAction::stdName(KStdAction::Undo));
622 if (undoAction != 0) {
623 undoAction->setText(text);
624 }
625 }
626
627 void Dolphin::slotRedoAvailable(bool available)
628 {
629 KAction* redoAction = actionCollection()->action(KStdAction::stdName(KStdAction::Redo));
630 if (redoAction != 0) {
631 redoAction->setEnabled(available);
632 }
633 }
634
635 void Dolphin::slotRedoTextChanged(const QString& text)
636 {
637 KAction* redoAction = actionCollection()->action(KStdAction::stdName(KStdAction::Redo));
638 if (redoAction != 0) {
639 redoAction->setText(text);
640 }
641 }
642
643 void Dolphin::cut()
644 {
645 // TODO: this boolean doesn't work between instances of dolphin or with konqueror or with other
646 // apps. The "application/x-kde-cutselection" mimetype should be used instead, see KonqMimeData
647 // in libkonq
648 m_clipboardContainsCutData = true;
649 /* KDE4-TODO: Q3DragObject* data = new KUrlDrag(m_activeView->selectedUrls(),
650 widget());
651 QApplication::clipboard()->setData(data);*/
652 }
653
654 void Dolphin::copy()
655 {
656 m_clipboardContainsCutData = false;
657 /* KDE4-TODO:
658 Q3DragObject* data = new KUrlDrag(m_activeView->selectedUrls(),
659 widget());
660 QApplication::clipboard()->setData(data);*/
661 }
662
663 void Dolphin::paste()
664 {
665 /* KDE4-TODO: - see KonqOperations::doPaste
666 QClipboard* clipboard = QApplication::clipboard();
667 QMimeSource* data = clipboard->data();
668 if (!KUrlDrag::canDecode(data)) {
669 return;
670 }
671
672 clearStatusBar();
673
674 KUrl::List sourceUrls;
675 KUrlDrag::decode(data, sourceUrls);
676
677 // per default the pasting is done into the current Url of the view
678 KUrl destUrl(m_activeView->url());
679
680 // check whether the pasting should be done into a selected directory
681 KUrl::List selectedUrls = m_activeView->selectedUrls();
682 if (selectedUrls.count() == 1) {
683 const KFileItem fileItem(S_IFDIR,
684 KFileItem::Unknown,
685 selectedUrls.first(),
686 true);
687 if (fileItem.isDir()) {
688 // only one item is selected which is a directory, hence paste
689 // into this directory
690 destUrl = selectedUrls.first();
691 }
692 }
693
694
695 updateViewProperties(sourceUrls);
696 if (m_clipboardContainsCutData) {
697 moveUrls(sourceUrls, destUrl);
698 m_clipboardContainsCutData = false;
699 clipboard->clear();
700 }
701 else {
702 copyUrls(sourceUrls, destUrl);
703 }*/
704 }
705
706 void Dolphin::updatePasteAction()
707 {
708 KAction* pasteAction = actionCollection()->action(KStdAction::stdName(KStdAction::Paste));
709 if (pasteAction == 0) {
710 return;
711 }
712
713 QString text(i18n("Paste"));
714 QClipboard* clipboard = QApplication::clipboard();
715 QMimeSource* data = clipboard->data();
716 /* KDE4-TODO:
717 if (KUrlDrag::canDecode(data)) {
718 pasteAction->setEnabled(true);
719
720 KUrl::List urls;
721 KUrlDrag::decode(data, urls);
722 const int count = urls.count();
723 if (count == 1) {
724 pasteAction->setText(i18n("Paste 1 File"));
725 }
726 else {
727 pasteAction->setText(i18n("Paste %1 Files").arg(count));
728 }
729 }
730 else {*/
731 pasteAction->setEnabled(false);
732 pasteAction->setText(i18n("Paste"));
733 //}
734
735 if (pasteAction->isEnabled()) {
736 KUrl::List urls = m_activeView->selectedUrls();
737 const uint count = urls.count();
738 if (count > 1) {
739 // pasting should not be allowed when more than one file
740 // is selected
741 pasteAction->setEnabled(false);
742 }
743 else if (count == 1) {
744 // Only one file is selected. Pasting is only allowed if this
745 // file is a directory.
746 // TODO: this doesn't work with remote protocols; instead we need a
747 // m_activeView->selectedFileItems() to get the real KFileItems
748 const KFileItem fileItem(S_IFDIR,
749 KFileItem::Unknown,
750 urls.first(),
751 true);
752 pasteAction->setEnabled(fileItem.isDir());
753 }
754 }
755 }
756
757 void Dolphin::selectAll()
758 {
759 clearStatusBar();
760 m_activeView->selectAll();
761 }
762
763 void Dolphin::invertSelection()
764 {
765 clearStatusBar();
766 m_activeView->invertSelection();
767 }
768 void Dolphin::setIconsView()
769 {
770 m_activeView->setMode(DolphinView::IconsView);
771 }
772
773 void Dolphin::setDetailsView()
774 {
775 m_activeView->setMode(DolphinView::DetailsView);
776 }
777
778 void Dolphin::setPreviewsView()
779 {
780 m_activeView->setMode(DolphinView::PreviewsView);
781 }
782
783 void Dolphin::sortByName()
784 {
785 m_activeView->setSorting(DolphinView::SortByName);
786 }
787
788 void Dolphin::sortBySize()
789 {
790 m_activeView->setSorting(DolphinView::SortBySize);
791 }
792
793 void Dolphin::sortByDate()
794 {
795 m_activeView->setSorting(DolphinView::SortByDate);
796 }
797
798 void Dolphin::toggleSortOrder()
799 {
800 const Qt::SortOrder order = (m_activeView->sortOrder() == Qt::Ascending) ?
801 Qt::Descending :
802 Qt::Ascending;
803 m_activeView->setSortOrder(order);
804 }
805
806 void Dolphin::toggleSplitView()
807 {
808 if (m_view[SecondaryIdx] == 0) {
809 // create a secondary view
810 m_view[SecondaryIdx] = new DolphinView(m_splitter,
811 m_view[PrimaryIdx]->url(),
812 m_view[PrimaryIdx]->mode(),
813 m_view[PrimaryIdx]->isShowHiddenFilesEnabled());
814 m_view[SecondaryIdx]->show();
815 }
816 else {
817 // remove secondary view
818 if (m_activeView == m_view[PrimaryIdx]) {
819 m_view[SecondaryIdx]->close();
820 m_view[SecondaryIdx]->deleteLater();
821 m_view[SecondaryIdx] = 0;
822 setActiveView(m_view[PrimaryIdx]);
823 }
824 else {
825 // The secondary view is active, hence from the users point of view
826 // the content of the secondary view should be moved to the primary view.
827 // From an implementation point of view it is more efficient to close
828 // the primary view and exchange the internal pointers afterwards.
829 m_view[PrimaryIdx]->close();
830 m_view[PrimaryIdx]->deleteLater();
831 m_view[PrimaryIdx] = m_view[SecondaryIdx];
832 m_view[SecondaryIdx] = 0;
833 setActiveView(m_view[PrimaryIdx]);
834 }
835 }
836 }
837
838 void Dolphin::reloadView()
839 {
840 clearStatusBar();
841 m_activeView->reload();
842 }
843
844 void Dolphin::stopLoading()
845 {
846 }
847
848 void Dolphin::showHiddenFiles()
849 {
850 clearStatusBar();
851
852 const KToggleAction* showHiddenFilesAction =
853 static_cast<KToggleAction*>(actionCollection()->action("show_hidden_files"));
854 const bool show = showHiddenFilesAction->isChecked();
855 m_activeView->setShowHiddenFilesEnabled(show);
856 }
857
858 void Dolphin::showFilterBar()
859 {
860 const KToggleAction* showFilterBarAction =
861 static_cast<KToggleAction*>(actionCollection()->action("show_filter_bar"));
862 const bool show = showFilterBarAction->isChecked();
863 m_activeView->slotShowFilterBar(show);
864 }
865
866 void Dolphin::zoomIn()
867 {
868 m_activeView->zoomIn();
869 updateViewActions();
870 }
871
872 void Dolphin::zoomOut()
873 {
874 m_activeView->zoomOut();
875 updateViewActions();
876 }
877
878 void Dolphin::toggleEditLocation()
879 {
880 clearStatusBar();
881
882 KToggleAction* action = static_cast<KToggleAction*>(actionCollection()->action("editable_location"));
883
884 bool editOrBrowse = action->isChecked();
885 // action->setChecked(action->setChecked);
886 m_activeView->setUrlEditable(editOrBrowse);
887 }
888
889 void Dolphin::editLocation()
890 {
891 KToggleAction* action = static_cast<KToggleAction*>(actionCollection()->action("editable_location"));
892 action->setChecked(true);
893 m_activeView->setUrlEditable(true);
894 }
895
896 void Dolphin::adjustViewProperties()
897 {
898 clearStatusBar();
899 ViewPropertiesDialog dlg(m_activeView);
900 dlg.exec();
901 }
902
903 void Dolphin::goBack()
904 {
905 clearStatusBar();
906 m_activeView->goBack();
907 }
908
909 void Dolphin::goForward()
910 {
911 clearStatusBar();
912 m_activeView->goForward();
913 }
914
915 void Dolphin::goUp()
916 {
917 clearStatusBar();
918 m_activeView->goUp();
919 }
920
921 void Dolphin::goHome()
922 {
923 clearStatusBar();
924 m_activeView->goHome();
925 }
926
927 void Dolphin::openTerminal()
928 {
929 QString command("konsole --workdir \"");
930 command.append(m_activeView->url().path());
931 command.append('\"');
932
933 KRun::runCommand(command, "Konsole", "konsole");
934 }
935
936 void Dolphin::findFile()
937 {
938 KRun::run("kfind", m_activeView->url());
939 }
940
941 void Dolphin::compareFiles()
942 {
943 // The method is only invoked if exactly 2 files have
944 // been selected. The selected files may be:
945 // - both in the primary view
946 // - both in the secondary view
947 // - one in the primary view and the other in the secondary
948 // view
949 assert(m_view[PrimaryIdx] != 0);
950
951 KUrl urlA;
952 KUrl urlB;
953 KUrl::List urls = m_view[PrimaryIdx]->selectedUrls();
954
955 switch (urls.count()) {
956 case 0: {
957 assert(m_view[SecondaryIdx] != 0);
958 urls = m_view[SecondaryIdx]->selectedUrls();
959 assert(urls.count() == 2);
960 urlA = urls[0];
961 urlB = urls[1];
962 break;
963 }
964
965 case 1: {
966 urlA = urls[0];
967 assert(m_view[SecondaryIdx] != 0);
968 urls = m_view[SecondaryIdx]->selectedUrls();
969 assert(urls.count() == 1);
970 urlB = urls[0];
971 break;
972 }
973
974 case 2: {
975 urlA = urls[0];
976 urlB = urls[1];
977 break;
978 }
979
980 default: {
981 // may not happen: compareFiles may only get invoked if 2
982 // files are selected
983 assert(false);
984 }
985 }
986
987 QString command("kompare -c \"");
988 command.append(urlA.pathOrUrl());
989 command.append("\" \"");
990 command.append(urlB.pathOrUrl());
991 command.append('\"');
992 KRun::runCommand(command, "Kompare", "kompare");
993
994 }
995
996 void Dolphin::editSettings()
997 {
998 // TODO: make a static method for opening the settings dialog
999 DolphinSettingsDialog dlg;
1000 dlg.exec();
1001 }
1002
1003 void Dolphin::addUndoOperation(KJob* job)
1004 {
1005 if (job->error() != 0) {
1006 slotHandleJobError(job);
1007 }
1008 else {
1009 const int id = job->progressId();
1010
1011 // set iterator to the executed command with the current id...
1012 Q3ValueList<UndoInfo>::Iterator it = m_pendingUndoJobs.begin();
1013 const Q3ValueList<UndoInfo>::Iterator end = m_pendingUndoJobs.end();
1014 bool found = false;
1015 while (!found && (it != end)) {
1016 if ((*it).id == id) {
1017 found = true;
1018 }
1019 else {
1020 ++it;
1021 }
1022 }
1023
1024 if (found) {
1025 DolphinCommand command = (*it).command;
1026 if (command.type() == DolphinCommand::Trash) {
1027 // To be able to perform an undo for the 'Move to Trash' operation
1028 // all source Urls must be updated with the trash Url. E. g. when moving
1029 // a file "test.txt" and a second file "test.txt" to the trash,
1030 // then the filenames in the trash are "0-test.txt" and "1-test.txt".
1031 QMap<QString, QString> metaData;
1032 KIO::Job *kiojob = qobject_cast<KIO::Job*>( job );
1033 if ( kiojob )
1034 {
1035 metaData = kiojob->metaData();
1036 }
1037 KUrl::List newSourceUrls;
1038
1039 KUrl::List sourceUrls = command.source();
1040 KUrl::List::Iterator sourceIt = sourceUrls.begin();
1041 const KUrl::List::Iterator sourceEnd = sourceUrls.end();
1042
1043 while (sourceIt != sourceEnd) {
1044 QMap<QString, QString>::ConstIterator metaIt = metaData.find("trashUrl-" + (*sourceIt).path());
1045 if (metaIt != metaData.end()) {
1046 newSourceUrls.append(KUrl(metaIt.data()));
1047 }
1048 ++sourceIt;
1049 }
1050 command.setSource(newSourceUrls);
1051 }
1052
1053 UndoManager::instance().addCommand(command);
1054 m_pendingUndoJobs.erase(it);
1055
1056 DolphinStatusBar* statusBar = m_activeView->statusBar();
1057 switch (command.type()) {
1058 case DolphinCommand::Copy:
1059 statusBar->setMessage(i18n("Copy operation completed."),
1060 DolphinStatusBar::OperationCompleted);
1061 break;
1062 case DolphinCommand::Move:
1063 statusBar->setMessage(i18n("Move operation completed."),
1064 DolphinStatusBar::OperationCompleted);
1065 break;
1066 case DolphinCommand::Trash:
1067 statusBar->setMessage(i18n("Move to trash operation completed."),
1068 DolphinStatusBar::OperationCompleted);
1069 break;
1070 default:
1071 break;
1072 }
1073 }
1074 }
1075 }
1076
1077 void Dolphin::toggleSidebar()
1078 {
1079 if (m_sidebar == 0) {
1080 openSidebar();
1081 }
1082 else {
1083 closeSidebar();
1084 }
1085
1086 KToggleAction* sidebarAction = static_cast<KToggleAction*>(actionCollection()->action("sidebar"));
1087 sidebarAction->setChecked(m_sidebar != 0);
1088 }
1089
1090 void Dolphin::closeSidebar()
1091 {
1092 if (m_sidebar == 0) {
1093 // the sidebar has already been closed
1094 return;
1095 }
1096
1097 // store width of sidebar and remember that the sidebar has been closed
1098 SidebarSettings* settings = DolphinSettings::instance().sidebarSettings();
1099 settings->setVisible(false);
1100 settings->setWidth(m_sidebar->width());
1101
1102 m_sidebar->deleteLater();
1103 m_sidebar = 0;
1104 }
1105
1106 Dolphin::Dolphin() :
1107 KMainWindow(0, "Dolphin"),
1108 m_splitter(0),
1109 m_sidebar(0),
1110 m_activeView(0),
1111 m_clipboardContainsCutData(false)
1112 {
1113 m_view[PrimaryIdx] = 0;
1114 m_view[SecondaryIdx] = 0;
1115
1116 m_fileGroupActions.setAutoDelete(true);
1117
1118 // TODO: the following members are not used yet. See documentation
1119 // of Dolphin::linkGroupActions() and Dolphin::linkToDeviceActions()
1120 // in the header file for details.
1121 //m_linkGroupActions.setAutoDelete(true);
1122 //m_linkToDeviceActions.setAutoDelete(true);
1123 }
1124
1125 void Dolphin::init()
1126 {
1127 // Check whether Dolphin runs the first time. If yes then
1128 // a proper default window size is given at the end of Dolphin::init().
1129 GeneralSettings* generalSettings = DolphinSettings::instance().generalSettings();
1130 const bool firstRun = generalSettings->firstRun();
1131
1132 setAcceptDrops(true);
1133
1134 m_splitter = new QSplitter(this);
1135
1136 DolphinSettings& settings = DolphinSettings::instance();
1137
1138 KBookmarkManager* manager = settings.bookmarkManager();
1139 assert(manager != 0);
1140 KBookmarkGroup root = manager->root();
1141 if (root.first().isNull()) {
1142 root.addBookmark(manager, i18n("Home"), settings.generalSettings()->homeUrl(), "folder_home");
1143 root.addBookmark(manager, i18n("Storage Media"), KUrl("media:/"), "blockdevice");
1144 root.addBookmark(manager, i18n("Network"), KUrl("remote:/"), "network_local");
1145 root.addBookmark(manager, i18n("Root"), KUrl("/"), "folder_red");
1146 root.addBookmark(manager, i18n("Trash"), KUrl("trash:/"), "trashcan_full");
1147 }
1148
1149 setupActions();
1150 setupGUI(Keys|Save|Create|ToolBar);
1151
1152 const KUrl& homeUrl = root.first().url();
1153 setCaption(homeUrl.fileName());
1154 ViewProperties props(homeUrl);
1155 m_view[PrimaryIdx] = new DolphinView(m_splitter,
1156 homeUrl,
1157 props.viewMode(),
1158 props.isShowHiddenFilesEnabled());
1159
1160 m_activeView = m_view[PrimaryIdx];
1161
1162 setCentralWidget(m_splitter);
1163
1164 // open sidebar
1165 SidebarSettings* sidebarSettings = settings.sidebarSettings();
1166 assert(sidebarSettings != 0);
1167 if (sidebarSettings->visible()) {
1168 openSidebar();
1169 }
1170
1171 createGUI();
1172
1173 stateChanged("new_file");
1174 setAutoSaveSettings();
1175
1176 QClipboard* clipboard = QApplication::clipboard();
1177 connect(clipboard, SIGNAL(dataChanged()),
1178 this, SLOT(updatePasteAction()));
1179 updatePasteAction();
1180 updateGoActions();
1181
1182 setupCreateNewMenuActions();
1183
1184 loadSettings();
1185
1186 if (firstRun) {
1187 // assure a proper default size if Dolphin runs the first time
1188 resize(640, 480);
1189 }
1190 }
1191
1192 void Dolphin::loadSettings()
1193 {
1194 GeneralSettings* settings = DolphinSettings::instance().generalSettings();
1195
1196 KToggleAction* splitAction = static_cast<KToggleAction*>(actionCollection()->action("split_view"));
1197 if (settings->splitView()) {
1198 splitAction->setChecked(true);
1199 toggleSplitView();
1200 }
1201
1202 updateViewActions();
1203 }
1204
1205 void Dolphin::setupActions()
1206 {
1207 // setup 'File' menu
1208 KAction* createFolder = new KAction(i18n("Folder..."), actionCollection(), "create_folder");
1209 createFolder->setIcon(KIcon("folder"));
1210 createFolder->setShortcut(Qt::Key_N);
1211 connect(createFolder, SIGNAL(triggered()), this, SLOT(createFolder()));
1212
1213 KAction* rename = new KAction(i18n("Rename"), actionCollection(), "rename");
1214 rename->setShortcut(Qt::Key_F2);
1215 connect(rename, SIGNAL(triggered()), this, SLOT(rename()));
1216
1217 KAction* moveToTrash = new KAction(i18n("Move to Trash"), actionCollection(), "move_to_trash");
1218 moveToTrash->setIcon(KIcon("edittrash"));
1219 moveToTrash->setShortcut(QKeySequence::Delete);
1220 connect(moveToTrash, SIGNAL(triggered()), this, SLOT(moveToTrash()));
1221
1222 KAction* deleteAction = new KAction(i18n("Delete"), actionCollection(), "delete");
1223 deleteAction->setShortcut(Qt::ALT | Qt::Key_Delete);
1224 deleteAction->setIcon(KIcon("editdelete"));
1225 connect(deleteAction, SIGNAL(triggered()), this, SLOT(deleteItems()));
1226
1227 KAction* properties = new KAction(i18n("Propert&ies"), actionCollection(), "properties");
1228 properties->setShortcut(Qt::Key_Alt | Qt::Key_Return);
1229 connect(properties, SIGNAL(triggered()), this, SLOT(properties()));
1230
1231 KStdAction::quit(this, SLOT(quit()), actionCollection());
1232
1233 // setup 'Edit' menu
1234 UndoManager& undoManager = UndoManager::instance();
1235 KStdAction::undo(&undoManager,
1236 SLOT(undo()),
1237 actionCollection());
1238 connect(&undoManager, SIGNAL(undoAvailable(bool)),
1239 this, SLOT(slotUndoAvailable(bool)));
1240 connect(&undoManager, SIGNAL(undoTextChanged(const QString&)),
1241 this, SLOT(slotUndoTextChanged(const QString&)));
1242
1243 KStdAction::redo(&undoManager,
1244 SLOT(redo()),
1245 actionCollection());
1246 connect(&undoManager, SIGNAL(redoAvailable(bool)),
1247 this, SLOT(slotRedoAvailable(bool)));
1248 connect(&undoManager, SIGNAL(redoTextChanged(const QString&)),
1249 this, SLOT(slotRedoTextChanged(const QString&)));
1250
1251 KStdAction::cut(this, SLOT(cut()), actionCollection());
1252 KStdAction::copy(this, SLOT(copy()), actionCollection());
1253 KStdAction::paste(this, SLOT(paste()), actionCollection());
1254
1255 KAction* selectAll = new KAction(i18n("Select All"), actionCollection(), "select_all");
1256 selectAll->setShortcut(Qt::CTRL + Qt::Key_A);
1257 connect(selectAll, SIGNAL(triggered()), this, SLOT(selectAll()));
1258
1259 KAction* invertSelection = new KAction(i18n("Invert Selection"), actionCollection(), "invert_selection");
1260 invertSelection->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_A);
1261 connect(invertSelection, SIGNAL(triggered()), this, SLOT(invertSelection()));
1262
1263 // setup 'View' menu
1264 KStdAction::zoomIn(this,
1265 SLOT(zoomIn()),
1266 actionCollection());
1267
1268 KStdAction::zoomOut(this,
1269 SLOT(zoomOut()),
1270 actionCollection());
1271
1272 KToggleAction* iconsView = new KToggleAction(i18n("Icons"), actionCollection(), "icons");
1273 iconsView->setShortcut(Qt::CTRL | Qt::Key_1);
1274 iconsView->setIcon(KIcon("view_icon"));
1275 connect(iconsView, SIGNAL(triggered()), this, SLOT(setIconsView()));
1276
1277 KToggleAction* detailsView = new KToggleAction(i18n("Details"), actionCollection(), "details");
1278 detailsView->setShortcut(Qt::CTRL | Qt::Key_2);
1279 detailsView->setIcon(KIcon("view_text"));
1280 connect(detailsView, SIGNAL(triggered()), this, SLOT(setDetailsView()));
1281
1282 KToggleAction* previewsView = new KToggleAction(i18n("Previews"), actionCollection(), "previews");
1283 previewsView->setShortcut(Qt::CTRL | Qt::Key_3);
1284 previewsView->setIcon(KIcon("gvdirpart"));
1285 connect(previewsView, SIGNAL(triggered()), this, SLOT(setPreviewsView()));
1286
1287 QActionGroup* viewModeGroup = new QActionGroup(this);
1288 viewModeGroup->addAction(iconsView);
1289 viewModeGroup->addAction(detailsView);
1290 viewModeGroup->addAction(previewsView);
1291
1292 KToggleAction* sortByName = new KToggleAction(i18n("By Name"), actionCollection(), "by_name");
1293 connect(sortByName, SIGNAL(triggered()), this, SLOT(sortByName()));
1294
1295 KToggleAction* sortBySize = new KToggleAction(i18n("By Size"), actionCollection(), "by_size");
1296 connect(sortBySize, SIGNAL(triggered()), this, SLOT(sortBySize()));
1297
1298 KToggleAction* sortByDate = new KToggleAction(i18n("By Date"), actionCollection(), "by_date");
1299 connect(sortByDate, SIGNAL(triggered()), this, SLOT(sortByDate()));
1300
1301 QActionGroup* sortGroup = new QActionGroup(this);
1302 sortGroup->addAction(sortByName);
1303 sortGroup->addAction(sortBySize);
1304 sortGroup->addAction(sortByDate);
1305
1306 KToggleAction* sortDescending = new KToggleAction(i18n("Descending"), actionCollection(), "descending");
1307 connect(sortDescending, SIGNAL(triggered()), this, SLOT(toggleSortOrder()));
1308
1309 KToggleAction* showHiddenFiles = new KToggleAction(i18n("Show Hidden Files"), actionCollection(), "show_hidden_files");
1310 //showHiddenFiles->setShortcut(Qt::ALT | Qt::Key_ KDE4-TODO: what Qt-Key represents '.'?
1311 connect(showHiddenFiles, SIGNAL(triggered()), this, SLOT(showHiddenFiles()));
1312
1313 KToggleAction* split = new KToggleAction(i18n("Split View"), actionCollection(), "split_view");
1314 split->setShortcut(Qt::Key_F10);
1315 split->setIcon(KIcon("view_left_right"));
1316 connect(split, SIGNAL(triggered()), this, SLOT(toggleSplitView()));
1317
1318 KAction* reload = new KAction(i18n("Reload"), "F5", actionCollection(), "reload");
1319 reload->setShortcut(Qt::Key_F5);
1320 reload->setIcon(KIcon("reload"));
1321 connect(reload, SIGNAL(triggered()), this, SLOT(reloadView()));
1322
1323 KAction* stop = new KAction(i18n("Stop"), actionCollection(), "stop");
1324 stop->setIcon(KIcon("stop"));
1325 connect(stop, SIGNAL(triggered()), this, SLOT(stopLoading()));
1326
1327 KToggleAction* showFullLocation = new KToggleAction(i18n("Show Full Location"), actionCollection(), "editable_location");
1328 showFullLocation->setShortcut(Qt::CTRL | Qt::Key_L);
1329 connect(showFullLocation, SIGNAL(triggered()), this, SLOT(toggleEditLocation()));
1330
1331 KToggleAction* editLocation = new KToggleAction(i18n("Edit Location"), actionCollection(), "edit_location");
1332 editLocation->setShortcut(Qt::Key_F6);
1333 connect(editLocation, SIGNAL(triggered()), this, SLOT(editLocation()));
1334
1335 KToggleAction* sidebar = new KToggleAction(i18n("Sidebar"), actionCollection(), "sidebar");
1336 sidebar->setShortcut(Qt::Key_F9);
1337 connect(sidebar, SIGNAL(triggered()), this, SLOT(toggleSidebar()));
1338
1339 KAction* adjustViewProps = new KAction(i18n("Adjust View Properties..."), actionCollection(), "view_properties");
1340 connect(adjustViewProps, SIGNAL(triggered()), this, SLOT(adjustViewProperties()));
1341
1342 // setup 'Go' menu
1343 KStdAction::back(this, SLOT(goBack()), actionCollection());
1344 KStdAction::forward(this, SLOT(goForward()), actionCollection());
1345 KStdAction::up(this, SLOT(goUp()), actionCollection());
1346 KStdAction::home(this, SLOT(goHome()), actionCollection());
1347
1348 // setup 'Tools' menu
1349 KAction* openTerminal = new KAction(i18n("Open Terminal"), actionCollection(), "open_terminal");
1350 openTerminal->setShortcut(Qt::Key_F4);
1351 openTerminal->setIcon(KIcon("konsole"));
1352 connect(openTerminal, SIGNAL(triggered()), this, SLOT(openTerminal()));
1353
1354 KAction* findFile = new KAction(i18n("Find File..."), actionCollection(), "find_file");
1355 findFile->setShortcut(Qt::Key_F);
1356 findFile->setIcon(KIcon("filefind"));
1357 connect(findFile, SIGNAL(triggered()), this, SLOT(findFile()));
1358
1359 KToggleAction* showFilterBar = new KToggleAction(i18n("Show Filter Bar"), actionCollection(), "show_filter_bar");
1360 showFilterBar->setShortcut(Qt::Key_Slash);
1361 connect(showFilterBar, SIGNAL(triggered()), this, SLOT(showFilterBar()));
1362
1363 KAction* compareFiles = new KAction(i18n("Compare Files"), actionCollection(), "compare_files");
1364 compareFiles->setIcon(KIcon("kompare"));
1365 compareFiles->setEnabled(false);
1366 connect(compareFiles, SIGNAL(triggered()), this, SLOT(compareFiles()));
1367
1368 // setup 'Settings' menu
1369 KStdAction::preferences(this, SLOT(editSettings()), actionCollection());
1370 }
1371
1372 void Dolphin::setupCreateNewMenuActions()
1373 {
1374 // Parts of the following code have been taken
1375 // from the class KNewMenu located in
1376 // libqonq/knewmenu.h of Konqueror.
1377 // Copyright (C) 1998, 1999 David Faure <faure@kde.org>
1378 // 2003 Sven Leiber <s.leiber@web.de>
1379
1380 QStringList files = actionCollection()->instance()->dirs()->findAllResources("templates");
1381 for (QStringList::Iterator it = files.begin() ; it != files.end(); ++it) {
1382 if ((*it)[0] != '.' ) {
1383 KSimpleConfig config(*it, true);
1384 config.setDesktopGroup();
1385
1386 // tricky solution to ensure that TextFile is at the beginning
1387 // because this filetype is the most used (according kde-core discussion)
1388 const QString name(config.readEntry("Name"));
1389 QString key(name);
1390
1391 const QString path(config.readPathEntry("Url"));
1392 if (!path.endsWith("emptydir")) {
1393 if (path.endsWith("TextFile.txt")) {
1394 key = "1" + key;
1395 }
1396 else if (!KDesktopFile::isDesktopFile(path)) {
1397 key = "2" + key;
1398 }
1399 else if (path.endsWith("Url.desktop")){
1400 key = "3" + key;
1401 }
1402 else if (path.endsWith("Program.desktop")){
1403 key = "4" + key;
1404 }
1405 else {
1406 key = "5";
1407 }
1408
1409 const QString icon(config.readEntry("Icon"));
1410 const QString comment(config.readEntry("Comment"));
1411 const QString type(config.readEntry("Type"));
1412
1413 const QString filePath(*it);
1414
1415
1416 if (type == "Link") {
1417 CreateFileEntry entry;
1418 entry.name = name;
1419 entry.icon = icon;
1420 entry.comment = comment;
1421 entry.templatePath = filePath;
1422 m_createFileTemplates.insert(key, entry);
1423 }
1424 }
1425 }
1426 }
1427 m_createFileTemplates.sort();
1428
1429 unplugActionList("create_actions");
1430 KSortableList<CreateFileEntry, QString>::ConstIterator it = m_createFileTemplates.begin();
1431 KSortableList<CreateFileEntry, QString>::ConstIterator end = m_createFileTemplates.end();
1432 /* KDE4-TODO: don't port this code; use KNewMenu instead
1433 while (it != end) {
1434 CreateFileEntry entry = (*it).value();
1435 KAction* action = new KAction(entry.name);
1436 action->setIcon(entry.icon);
1437 action->setName((*it).index());
1438 connect(action, SIGNAL(activated()),
1439 this, SLOT(createFile()));
1440
1441 const QChar section = ((*it).index()[0]);
1442 switch (section) {
1443 case '1':
1444 case '2': {
1445 m_fileGroupActions.append(action);
1446 break;
1447 }
1448
1449 case '3':
1450 case '4': {
1451 // TODO: not used yet. See documentation of Dolphin::linkGroupActions()
1452 // and Dolphin::linkToDeviceActions() in the header file for details.
1453 //m_linkGroupActions.append(action);
1454 break;
1455 }
1456
1457 case '5': {
1458 // TODO: not used yet. See documentation of Dolphin::linkGroupActions()
1459 // and Dolphin::linkToDeviceActions() in the header file for details.
1460 //m_linkToDeviceActions.append(action);
1461 break;
1462 }
1463 default:
1464 break;
1465 }
1466 ++it;
1467 }
1468
1469 plugActionList("create_file_group", m_fileGroupActions);
1470 //plugActionList("create_link_group", m_linkGroupActions);
1471 //plugActionList("link_to_device", m_linkToDeviceActions);*/
1472 }
1473
1474 void Dolphin::updateHistory()
1475 {
1476 int index = 0;
1477 const Q3ValueList<UrlNavigator::HistoryElem> list = m_activeView->urlHistory(index);
1478
1479 KAction* backAction = actionCollection()->action("go_back");
1480 if (backAction != 0) {
1481 backAction->setEnabled(index < static_cast<int>(list.count()) - 1);
1482 }
1483
1484 KAction* forwardAction = actionCollection()->action("go_forward");
1485 if (forwardAction != 0) {
1486 forwardAction->setEnabled(index > 0);
1487 }
1488 }
1489
1490 void Dolphin::updateEditActions()
1491 {
1492 const KFileItemList* list = m_activeView->selectedItems();
1493 if ((list == 0) || (*list).isEmpty()) {
1494 stateChanged("has_no_selection");
1495 }
1496 else {
1497 stateChanged("has_selection");
1498
1499 KAction* renameAction = actionCollection()->action("rename");
1500 if (renameAction != 0) {
1501 renameAction->setEnabled(list->count() >= 1);
1502 }
1503
1504 bool enableMoveToTrash = true;
1505
1506 KFileItemList::const_iterator it = list->begin();
1507 const KFileItemList::const_iterator end = list->end();
1508 while (it != end) {
1509 KFileItem* item = *it;
1510 const KUrl& url = item->url();
1511 // only enable the 'Move to Trash' action for local files
1512 if (!url.isLocalFile()) {
1513 enableMoveToTrash = false;
1514 }
1515 ++it;
1516 }
1517
1518 KAction* moveToTrashAction = actionCollection()->action("move_to_trash");
1519 moveToTrashAction->setEnabled(enableMoveToTrash);
1520 }
1521 updatePasteAction();
1522 }
1523
1524 void Dolphin::updateViewActions()
1525 {
1526 KAction* zoomInAction = actionCollection()->action(KStdAction::stdName(KStdAction::ZoomIn));
1527 if (zoomInAction != 0) {
1528 zoomInAction->setEnabled(m_activeView->isZoomInPossible());
1529 }
1530
1531 KAction* zoomOutAction = actionCollection()->action(KStdAction::stdName(KStdAction::ZoomOut));
1532 if (zoomOutAction != 0) {
1533 zoomOutAction->setEnabled(m_activeView->isZoomOutPossible());
1534 }
1535
1536 KAction* action = 0;
1537 switch (m_activeView->mode()) {
1538 case DolphinView::IconsView:
1539 action = actionCollection()->action("icons");
1540 break;
1541 case DolphinView::DetailsView:
1542 action = actionCollection()->action("details");
1543 break;
1544 case DolphinView::PreviewsView:
1545 action = actionCollection()->action("previews");
1546 break;
1547 default:
1548 break;
1549 }
1550
1551 if (action != 0) {
1552 KToggleAction* toggleAction = static_cast<KToggleAction*>(action);
1553 toggleAction->setChecked(true);
1554 }
1555
1556 slotSortingChanged(m_activeView->sorting());
1557 slotSortOrderChanged(m_activeView->sortOrder());
1558
1559 KToggleAction* showFilterBarAction =
1560 static_cast<KToggleAction*>(actionCollection()->action("show_filter_bar"));
1561 showFilterBarAction->setChecked(m_activeView->isFilterBarVisible());
1562
1563 KToggleAction* showHiddenFilesAction =
1564 static_cast<KToggleAction*>(actionCollection()->action("show_hidden_files"));
1565 showHiddenFilesAction->setChecked(m_activeView->isShowHiddenFilesEnabled());
1566
1567 KToggleAction* splitAction = static_cast<KToggleAction*>(actionCollection()->action("split_view"));
1568 splitAction->setChecked(m_view[SecondaryIdx] != 0);
1569
1570 KToggleAction* sidebarAction = static_cast<KToggleAction*>(actionCollection()->action("sidebar"));
1571 sidebarAction->setChecked(m_sidebar != 0);
1572 }
1573
1574 void Dolphin::updateGoActions()
1575 {
1576 KAction* goUpAction = actionCollection()->action(KStdAction::stdName(KStdAction::Up));
1577 const KUrl& currentUrl = m_activeView->url();
1578 goUpAction->setEnabled(currentUrl.upUrl() != currentUrl);
1579 }
1580
1581 void Dolphin::updateViewProperties(const KUrl::List& urls)
1582 {
1583 if (urls.isEmpty()) {
1584 return;
1585 }
1586
1587 // Updating the view properties might take up to several seconds
1588 // when dragging several thousand Urls. Writing a KIO slave for this
1589 // use case is not worth the effort, but at least the main widget
1590 // must be disabled and a progress should be shown.
1591 ProgressIndicator progressIndicator(i18n("Updating view properties..."),
1592 QString::null,
1593 urls.count());
1594
1595 KUrl::List::ConstIterator end = urls.end();
1596 for(KUrl::List::ConstIterator it = urls.begin(); it != end; ++it) {
1597 progressIndicator.execOperation();
1598
1599 ViewProperties props(*it);
1600 props.save();
1601 }
1602 }
1603
1604 void Dolphin::copyUrls(const KUrl::List& source, const KUrl& dest)
1605 {
1606 KIO::Job* job = KIO::copy(source, dest);
1607 addPendingUndoJob(job, DolphinCommand::Copy, source, dest);
1608 }
1609
1610 void Dolphin::moveUrls(const KUrl::List& source, const KUrl& dest)
1611 {
1612 KIO::Job* job = KIO::move(source, dest);
1613 addPendingUndoJob(job, DolphinCommand::Move, source, dest);
1614 }
1615
1616 void Dolphin::addPendingUndoJob(KIO::Job* job,
1617 DolphinCommand::Type commandType,
1618 const KUrl::List& source,
1619 const KUrl& dest)
1620 {
1621 connect(job, SIGNAL(result(KJob*)),
1622 this, SLOT(addUndoOperation(KJob*)));
1623
1624 UndoInfo undoInfo;
1625 undoInfo.id = job->progressId();
1626 undoInfo.command = DolphinCommand(commandType, source, dest);
1627 m_pendingUndoJobs.append(undoInfo);
1628 }
1629
1630 void Dolphin::clearStatusBar()
1631 {
1632 m_activeView->statusBar()->clear();
1633 }
1634
1635 void Dolphin::openSidebar()
1636 {
1637 if (m_sidebar != 0) {
1638 // the sidebar is already open
1639 return;
1640 }
1641
1642 m_sidebar = new Sidebar(m_splitter);
1643 m_sidebar->show();
1644
1645 connect(m_sidebar, SIGNAL(urlChanged(const KUrl&)),
1646 this, SLOT(slotUrlChangeRequest(const KUrl&)));
1647 m_splitter->setCollapsible(m_sidebar, false);
1648 m_splitter->setResizeMode(m_sidebar, QSplitter::KeepSize);
1649 m_splitter->moveToFirst(m_sidebar);
1650
1651 SidebarSettings* settings = DolphinSettings::instance().sidebarSettings();
1652 settings->setVisible(true);
1653 }
1654
1655 #include "dolphin.moc"