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