summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am62
-rw-r--r--src/README81
-rw-r--r--src/bookmarkselector.cpp183
-rw-r--r--src/bookmarkselector.h98
-rw-r--r--src/bookmarkssettingspage.cpp314
-rw-r--r--src/bookmarkssettingspage.h93
-rw-r--r--src/bookmarkssidebarpage.cpp331
-rw-r--r--src/bookmarkssidebarpage.h139
-rw-r--r--src/d3lphin.desktop65
-rw-r--r--src/d3lphinui.rc110
-rw-r--r--src/detailsviewsettingspage.cpp155
-rw-r--r--src/detailsviewsettingspage.h65
-rw-r--r--src/dolphin.cpp1711
-rw-r--r--src/dolphin.h456
-rw-r--r--src/dolphin.lsm16
-rw-r--r--src/dolphincontextmenu.cpp494
-rw-r--r--src/dolphincontextmenu.h130
-rw-r--r--src/dolphindetailsview.cpp789
-rw-r--r--src/dolphindetailsview.h216
-rw-r--r--src/dolphindetailsviewsettings.cpp108
-rw-r--r--src/dolphindetailsviewsettings.h71
-rw-r--r--src/dolphindirlister.cpp42
-rw-r--r--src/dolphindirlister.h48
-rw-r--r--src/dolphiniconsview.cpp500
-rw-r--r--src/dolphiniconsview.h168
-rw-r--r--src/dolphiniconsviewsettings.cpp199
-rw-r--r--src/dolphiniconsviewsettings.h126
-rw-r--r--src/dolphinsettings.cpp142
-rw-r--r--src/dolphinsettings.h110
-rw-r--r--src/dolphinsettingsbase.cpp31
-rw-r--r--src/dolphinsettingsbase.h43
-rw-r--r--src/dolphinsettingsdialog.cpp77
-rw-r--r--src/dolphinsettingsdialog.h56
-rw-r--r--src/dolphinstatusbar.cpp166
-rw-r--r--src/dolphinstatusbar.h133
-rw-r--r--src/dolphinview.cpp1065
-rw-r--r--src/dolphinview.h452
-rw-r--r--src/editbookmarkdialog.cpp120
-rw-r--r--src/editbookmarkdialog.h82
-rw-r--r--src/filterbar.cpp90
-rw-r--r--src/filterbar.h65
-rw-r--r--src/generalsettingspage.cpp171
-rw-r--r--src/generalsettingspage.h63
-rw-r--r--src/hi128-app-d3lphin.pngbin0 -> 65872 bytes
-rw-r--r--src/hi16-app-d3lphin.pngbin0 -> 1146 bytes
-rw-r--r--src/hi22-app-d3lphin.pngbin0 -> 2064 bytes
-rw-r--r--src/hi32-app-d3lphin.pngbin0 -> 4234 bytes
-rw-r--r--src/hi48-app-d3lphin.pngbin0 -> 9381 bytes
-rw-r--r--src/hi64-app-d3lphin.pngbin0 -> 16577 bytes
-rw-r--r--src/iconsviewsettingspage.cpp262
-rw-r--r--src/iconsviewsettingspage.h99
-rw-r--r--src/infosidebarpage.cpp630
-rw-r--r--src/infosidebarpage.h194
-rw-r--r--src/itemeffectsmanager.cpp189
-rw-r--r--src/itemeffectsmanager.h120
-rw-r--r--src/main.cpp82
-rw-r--r--src/pics/128x128/Makefile.am3
-rw-r--r--src/pics/128x128/preview.pngbin0 -> 49393 bytes
-rw-r--r--src/pics/16x16/Makefile.am3
-rw-r--r--src/pics/16x16/editurl.pngbin0 -> 227 bytes
-rw-r--r--src/pics/16x16/preview.pngbin0 -> 866 bytes
-rw-r--r--src/pics/22x22/Makefile.am3
-rw-r--r--src/pics/22x22/preview.pngbin0 -> 1555 bytes
-rw-r--r--src/pics/32x32/Makefile.am3
-rw-r--r--src/pics/32x32/preview.pngbin0 -> 3186 bytes
-rw-r--r--src/pics/48x48/Makefile.am3
-rw-r--r--src/pics/48x48/preview.pngbin0 -> 7037 bytes
-rw-r--r--src/pics/64x64/Makefile.am3
-rw-r--r--src/pics/64x64/preview.pngbin0 -> 12439 bytes
-rw-r--r--src/pics/Makefile.am1
-rw-r--r--src/pixmapviewer.cpp56
-rw-r--r--src/pixmapviewer.h50
-rw-r--r--src/progressindicator.cpp80
-rw-r--r--src/progressindicator.h78
-rw-r--r--src/renamedialog.cpp89
-rw-r--r--src/renamedialog.h67
-rw-r--r--src/servicemenus/Makefile.am18
-rw-r--r--src/servicemenus/Makefile.am.new18
-rw-r--r--src/servicemenus/amarok_addaspodcast.desktop8
-rw-r--r--src/servicemenus/amarok_append.desktop96
-rw-r--r--src/servicemenus/amarok_play_audiocd.desktop49
-rw-r--r--src/servicemenus/ark_compress.desktop21
-rw-r--r--src/servicemenus/ark_extract.desktop11
-rw-r--r--src/servicemenus/ark_extract_subdir.desktop11
-rw-r--r--src/servicemenus/compress.desktop21
-rw-r--r--src/servicemenus/d3lphin_su.desktop11
-rw-r--r--src/servicemenus/edit_as_root.desktop12
-rw-r--r--src/servicemenus/encryptfile.desktop59
-rw-r--r--src/servicemenus/encryptfolder.desktop50
-rw-r--r--src/servicemenus/floppy_format.desktop36
-rw-r--r--src/servicemenus/imageconverter.desktop61
-rw-r--r--src/servicemenus/installfont.desktop143
-rw-r--r--src/servicemenus/isoservice.desktop13
-rw-r--r--src/servicemenus/jpegorient.desktop222
-rw-r--r--src/servicemenus/k3b_audiocd_rip.desktop46
-rw-r--r--src/servicemenus/k3b_cd_copy.desktop48
-rw-r--r--src/servicemenus/k3b_create_audio_cd.desktop124
-rw-r--r--src/servicemenus/k3b_create_video_cd.desktop125
-rw-r--r--src/servicemenus/k3b_dvd_copy.desktop48
-rw-r--r--src/servicemenus/k3b_handle_empty_cd.desktop114
-rw-r--r--src/servicemenus/k3b_handle_empty_dvd.desktop103
-rw-r--r--src/servicemenus/k3b_videodvd_rip.desktop45
-rw-r--r--src/servicemenus/k3b_write_bin_image.desktop124
-rw-r--r--src/servicemenus/k3b_write_iso_image.desktop124
-rw-r--r--src/servicemenus/kdesktopSetAsBackground.desktop201
-rw-r--r--src/servicemenus/konqgwenview.desktop53
-rw-r--r--src/servicemenus/konsolehere.desktop123
-rw-r--r--src/servicemenus/mail_as_attachment.desktop10
-rw-r--r--src/servicemenus/media_eject.desktop158
-rw-r--r--src/servicemenus/media_mount.desktop155
-rw-r--r--src/servicemenus/media_realfolder.desktop114
-rw-r--r--src/servicemenus/media_safelyremove.desktop132
-rw-r--r--src/servicemenus/media_unmount.desktop155
-rw-r--r--src/servicemenus/open_in_digikam.desktop29
-rw-r--r--src/servicemenus/run_as_root.desktop17
-rw-r--r--src/servicemenus/smb2rdc.desktop55
-rw-r--r--src/servicemenus/text-ada-print.desktop76
-rw-r--r--src/servicemenus/text-c++-print.desktop76
-rw-r--r--src/servicemenus/text-c++h-print.desktop76
-rw-r--r--src/servicemenus/text-ch-print.desktop76
-rw-r--r--src/servicemenus/text-css-print.desktop76
-rw-r--r--src/servicemenus/text-diff-print.desktop76
-rw-r--r--src/servicemenus/text-html-print.desktop76
-rw-r--r--src/servicemenus/text-java-print.desktop76
-rw-r--r--src/servicemenus/text-log-print.desktop76
-rw-r--r--src/servicemenus/text-makefile-print.desktop76
-rw-r--r--src/servicemenus/text-pas-print.desktop76
-rw-r--r--src/servicemenus/text-perl-print.desktop76
-rw-r--r--src/servicemenus/text-print.desktop76
-rw-r--r--src/servicemenus/text-python-print.desktop76
-rw-r--r--src/servicemenus/text-tcl-print.desktop76
-rw-r--r--src/servicemenus/text-tex-print.desktop76
-rw-r--r--src/servicemenus/text-xml-print.desktop76
-rw-r--r--src/servicemenus/text-xslt-print.desktop76
-rw-r--r--src/settingspagebase.cpp33
-rw-r--r--src/settingspagebase.h46
-rw-r--r--src/sidebarpage.cpp36
-rw-r--r--src/sidebarpage.h49
-rw-r--r--src/sidebars.cpp190
-rw-r--r--src/sidebars.h90
-rw-r--r--src/sidebarssettings.cpp96
-rw-r--r--src/sidebarssettings.h72
-rw-r--r--src/statusbarmessagelabel.cpp215
-rw-r--r--src/statusbarmessagelabel.h92
-rw-r--r--src/statusbarspaceinfo.cpp192
-rw-r--r--src/statusbarspaceinfo.h79
-rw-r--r--src/undomanager.cpp402
-rw-r--r--src/undomanager.h196
-rw-r--r--src/urlbutton.cpp96
-rw-r--r--src/urlbutton.h69
-rw-r--r--src/urlnavigator.cpp501
-rw-r--r--src/urlnavigator.h210
-rw-r--r--src/urlnavigatorbutton.cpp393
-rw-r--r--src/urlnavigatorbutton.h88
-rw-r--r--src/viewproperties.cpp362
-rw-r--r--src/viewproperties.h129
-rw-r--r--src/viewpropertiesdialog.cpp235
-rw-r--r--src/viewpropertiesdialog.h78
-rw-r--r--src/viewsettingspage.cpp66
-rw-r--r--src/viewsettingspage.h55
160 files changed, 20052 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..aaa60fd
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,62 @@
+## Makefile.am for d3lphin
+
+SUBDIRS = pics servicemenus
+
+# this is the program that gets installed. it's name is used for all
+# of the other Makefile.am variables
+bin_PROGRAMS = d3lphin
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+# the library search path.
+d3lphin_LDFLAGS = $(KDE_RPATH) $(all_libraries)
+
+# the libraries to link against.
+d3lphin_LDADD = $(LIB_KFILE) $(LIB_KDEPRINT) -lkonq
+
+# which sources should be compiled for d3lphin
+d3lphin_SOURCES = bookmarkselector.cpp bookmarkssettingspage.cpp \
+ bookmarkssidebarpage.cpp detailsviewsettingspage.cpp dolphin.cpp dolphincontextmenu.cpp \
+ dolphindetailsview.cpp dolphindetailsviewsettings.cpp dolphindirlister.cpp \
+ dolphiniconsview.cpp dolphiniconsviewsettings.cpp dolphinsettings.cpp \
+ dolphinsettingsbase.cpp dolphinsettingsdialog.cpp dolphinstatusbar.cpp dolphinview.cpp \
+ editbookmarkdialog.cpp filterbar.cpp generalsettingspage.cpp iconsviewsettingspage.cpp \
+ infosidebarpage.cpp itemeffectsmanager.cpp main.cpp pixmapviewer.cpp progressindicator.cpp \
+ renamedialog.cpp settingspagebase.cpp sidebarpage.cpp sidebars.cpp sidebarssettings.cpp \
+ statusbarmessagelabel.cpp statusbarspaceinfo.cpp undomanager.cpp urlbutton.cpp urlnavigator.cpp \
+ urlnavigatorbutton.cpp viewproperties.cpp viewpropertiesdialog.cpp viewsettingspage.cpp
+
+
+# these are the headers for your project
+noinst_HEADERS = bookmarkselector.h bookmarkssettingspage.h \
+ bookmarkssidebarpage.h detailsviewsettingspage.h dolphin.h dolphincontextmenu.h \
+ dolphindetailsview.h dolphindetailsviewsettings.h dolphindirlister.h dolphiniconsview.h \
+ dolphiniconsviewsettings.h dolphiniconsviewsettings.h iconsviewsettingspage.h dolphinsettings.h \
+ dolphinsettingsbase.h dolphinsettingsdialog.h dolphinstatusbar.h dolphinview.h \
+ editbookmarkdialog.h filterbar.h generalsettingspage.h iconsviewsettingspage.h \
+ infosidebarpage.h itemeffectsmanager.h pixmapviewer.h renamedialog.h settingspagebase.h \
+ sidebarpage.h sidebars.h statusbarmessagelabel.h statusbarspaceinfo.h undomanager.h \
+ urlbutton.h urlnavigator.h urlnavigatorbutton.h viewproperties.h \
+ viewpropertiesdialog.h viewsettingspage.h
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(EXTRACTRC) `find . -name \*.ui -o -name \*.rc` > rc.cpp
+ $(XGETTEXT) *.cpp -o $(podir)/d3lphin.pot
+
+
+
+# this is where the kdelnk file will go
+kdelnkdir = $(kde_appsdir)/System
+xdg_apps_DATA = d3lphin.desktop
+
+# this is where the XML-GUI resource file goes
+rcdir = $(kde_datadir)/d3lphin
+rc_DATA = d3lphinui.rc
+
+KDE_ICON = AUTO
+kde_icon_KDEICON = hi128-app-d3lphin.png hi16-app-d3lphin.png \
+ hi22-app-d3lphin.png hi32-app-d3lphin.png hi48-app-d3lphin.png hi64-app-d3lphin.png
diff --git a/src/README b/src/README
new file mode 100644
index 0000000..f04a563
--- /dev/null
+++ b/src/README
@@ -0,0 +1,81 @@
+-----------------------------------------------
+Kde application framework template quickstart
+Author: Thomas Nagy
+Date: 2004-03-22
+-----------------------------------------------
+
+This README file explains you basic things for starting with
+this application template.
+
+
+** Building and installing **
+
+* Build the configure script by "make -f Makefile.cvs"
+
+* To clean, use "make clean", and to clean everything
+(remove the makefiles, etc), use "make distclean"
+
+* To distribute your program, try "make dist".
+This will make a compact tarball archive of your release with the
+necessary scripts inside.
+
+* Modifying the auto-tools scripts
+for automake scripts there is an excellent tutorial there :
+http://developer.kde.org/documentation/other/makefile_am_howto.html
+
+* Simplify your life : install the project in your home directory for
+testing purposes.
+./configure --prefix=/home/user/dummyfolder/
+In the end when you finished the development you can
+rm -rf /home/user/dummyfolder/
+without fear.
+
+
+** Technologies **
+
+* Build the menus of your application easily
+kde applications now use an xml file (*ui.rc file) to build the menus.
+This allow a great customization of the application. However, when
+programming the menu is shown only after a "make install"
+
+For more details, consult :
+http://devel-home.kde.org/~larrosa/tutorial/p9.html
+http://developer.kde.org/documentation/tutorials/xmlui/preface.html
+
+* Use KConfig XT to create your configuration dialogs and make
+them more maintainable.
+
+For more details, consult :
+http://developer.kde.org/documentation/tutorials/kconfigxt/kconfigxt.html
+
+* With KParts, you can embed other kde components in your program, or make your program
+embeddable in other apps. For example, the kmplayer kpart can be called to play videos
+in your app.
+
+For more details, consult :
+http://www-106.ibm.com/developerworks/library/l-kparts/
+http://developer.kde.org/documentation/tutorials/dot/writing-plugins.html
+http://developer.kde.org/documentation/tutorials/developing-a-plugin-structure/index.html
+
+* With dcop, you can control your app from other applications
+Make sure to include K_DCOP and a kdcop: section in your .h file
+http://developer.kde.org/documentation/tutorials/dot/dcopiface/dcop-interface.html
+
+
+** Documentation **
+
+* For the translations :
+1. Download a patched gettext which can be found at:
+ http://public.kde.planetmirror.com/pub/kde/devel/gettext-kde/
+2. Install that gettext in ~/bin/
+3. cd ~/yourproject, export PATH=~/bin:$PATH, export
+KDEDIR=/where_your_KDE3_is
+4. make -f admin/Makefile.common package-messages
+5. make package-messages
+6. Translate the po files (not the pot!!) with kbabel or xemacs
+
+* Do not forget to write the documentation for your kde app
+edit the documentation template index.docbook in doc/
+
+
+
diff --git a/src/bookmarkselector.cpp b/src/bookmarkselector.cpp
new file mode 100644
index 0000000..9a0c3cd
--- /dev/null
+++ b/src/bookmarkselector.cpp
@@ -0,0 +1,183 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+
+#include <assert.h>
+#include <qpopupmenu.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+
+#include <kiconloader.h>
+#include <kglobalsettings.h>
+#include <kbookmarkmanager.h>
+
+#include "bookmarkselector.h"
+#include "dolphinsettings.h"
+#include "dolphinview.h"
+#include "dolphin.h"
+#include "urlnavigator.h"
+
+BookmarkSelector::BookmarkSelector(URLNavigator* parent) :
+ URLButton(parent),
+ m_selectedIndex(0)
+{
+ setFocusPolicy(QWidget::NoFocus);
+
+ m_bookmarksMenu = new QPopupMenu(this);
+
+ KBookmarkManager* manager = DolphinSettings::instance().bookmarkManager();
+ connect(manager, SIGNAL(changed(const QString&, const QString&)),
+ this, SLOT(updateBookmarks()));
+
+ updateBookmarks();
+
+ connect(m_bookmarksMenu, SIGNAL(activated(int)),
+ this, SLOT(slotBookmarkActivated(int)));
+
+ setPopup(m_bookmarksMenu);
+}
+
+BookmarkSelector::~BookmarkSelector()
+{
+}
+
+void BookmarkSelector::updateBookmarks()
+{
+ m_bookmarksMenu->clear();
+
+ KBookmarkGroup root = DolphinSettings::instance().bookmarkManager()->root();
+ KBookmark bookmark = root.first();
+ int i = 0;
+ while (!bookmark.isNull()) {
+ m_bookmarksMenu->insertItem(MainBarIcon(bookmark.icon()),
+ bookmark.text(),
+ i);
+ if (i == m_selectedIndex) {
+ QPixmap pixmap = SmallIcon(bookmark.icon());
+ setPixmap(pixmap);
+ setMinimumWidth(pixmap.width() + 2);
+ }
+ bookmark = root.next(bookmark);
+ ++i;
+ }
+
+}
+
+void BookmarkSelector::updateSelection(const KURL& url)
+{
+ KBookmarkGroup root = DolphinSettings::instance().bookmarkManager()->root();
+ KBookmark bookmark = root.first();
+
+ int maxLength = 0;
+ m_selectedIndex = -1;
+
+ // Search the bookmark which is equal to the URL or at least is a parent URL.
+ // If there are more than one possible parent URL candidates, choose the bookmark
+ // which covers the bigger range of the URL.
+ int i = 0;
+ while (!bookmark.isNull()) {
+ const KURL bookmarkURL = bookmark.url();
+ if (bookmarkURL.isParentOf(url)) {
+ const int length = bookmarkURL.prettyURL().length();
+ if (length > maxLength) {
+ m_selectedIndex = i;
+ setPixmap(SmallIcon(bookmark.icon()));
+ maxLength = length;
+ }
+ }
+ bookmark = root.next(bookmark);
+ ++i;
+ }
+
+ if (m_selectedIndex < 0) {
+ // No bookmark has been found which matches to the given URL. Show
+ // a generic folder icon as pixmap for indication:
+ setPixmap(SmallIcon("folder"));
+ }
+}
+
+KBookmark BookmarkSelector::selectedBookmark() const
+{
+ return DolphinSettings::instance().bookmark(m_selectedIndex);
+}
+
+void BookmarkSelector::drawButton(QPainter* painter)
+{
+ const int buttonWidth = width();
+ const int buttonHeight = height();
+
+ QColor backgroundColor;
+ QColor foregroundColor;
+ const bool isHighlighted = isDisplayHintEnabled(EnteredHint) ||
+ isDisplayHintEnabled(DraggedHint);
+ if (isHighlighted) {
+ backgroundColor = KGlobalSettings::highlightColor();
+ foregroundColor = KGlobalSettings::highlightedTextColor();
+ }
+ else {
+ backgroundColor = colorGroup().background();
+ foregroundColor = KGlobalSettings::buttonTextColor();
+ }
+
+ // dimm the colors if the parent view does not have the focus
+ const DolphinView* parentView = urlNavigator()->dolphinView();
+ const Dolphin& dolphin = Dolphin::mainWin();
+
+ const bool isActive = (dolphin.activeView() == parentView);
+ if (!isActive) {
+ QColor dimmColor(colorGroup().background());
+ foregroundColor = mixColors(foregroundColor, dimmColor);
+ if (isHighlighted) {
+ backgroundColor = mixColors(backgroundColor, dimmColor);
+ }
+ }
+
+ if (!(isDisplayHintEnabled(ActivatedHint) && isActive) && !isHighlighted) {
+ // dimm the foreground color by mixing it with the background
+ foregroundColor = mixColors(foregroundColor, backgroundColor);
+ painter->setPen(foregroundColor);
+ }
+
+ // draw button backround
+ painter->setPen(NoPen);
+ painter->setBrush(backgroundColor);
+ painter->drawRect(0, 0, buttonWidth, buttonHeight);
+
+ // draw icon
+ const QPixmap* icon = pixmap();
+ if (icon != 0) {
+ const int x = (buttonWidth - icon->width()) / 2;
+ const int y = (buttonHeight - icon->height()) / 2;
+ painter->drawPixmap(x, y, *icon);
+ }
+}
+
+void BookmarkSelector::slotBookmarkActivated(int index)
+{
+ m_selectedIndex = index;
+
+ KBookmark bookmark = selectedBookmark();
+ setPixmap(SmallIcon(bookmark.icon()));
+
+ emit bookmarkActivated(index);
+}
+
+#include "bookmarkselector.moc"
+
diff --git a/src/bookmarkselector.h b/src/bookmarkselector.h
new file mode 100644
index 0000000..9bede96
--- /dev/null
+++ b/src/bookmarkselector.h
@@ -0,0 +1,98 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef BOOKMARKSELECTOR_H
+#define BOOKMARKSELECTOR_H
+
+#include <kbookmark.h>
+#include <urlbutton.h>
+
+class URLNavigator;
+class QPopupMenu;
+class KURL;
+
+/**
+ * @brief Allows to select a bookmark from a popup menu.
+ *
+ * The icon from the current selected bookmark is shown
+ * inside the bookmark selector.
+ *
+ * @see URLNavigator
+ * @author Peter Penz <[email protected]>
+ */
+class BookmarkSelector : public URLButton
+{
+ Q_OBJECT
+
+public:
+ /**
+ * @param parent Parent widget where the bookmark selector
+ * is embedded into.
+ */
+ BookmarkSelector(URLNavigator* parent);
+
+ virtual ~BookmarkSelector();
+
+ /**
+ * Updates the selection dependent from the given URL \a url. The
+ * URL must not match exactly to one of the available bookmarks:
+ * The bookmark which is equal to the URL or at least is a parent URL
+ * is selected. If there are more than one possible parent URL candidates,
+ * the bookmark which covers the bigger range of the URL is selected.
+ */
+ void updateSelection(const KURL& url);
+
+ /**
+ * Returns the index of the selected bookmark. To get
+ * the bookmark, use BookmarkSelector::selectedBookmark().
+ */
+ int selectedIndex() const { return m_selectedIndex; }
+
+ /** Returns the selected bookmark. */
+ KBookmark selectedBookmark() const;
+
+signals:
+ /**
+ * Is send when a bookmark has been activated by the user.
+ * @param index Index of the selected bookmark.
+ */
+ void bookmarkActivated(int index);
+
+protected:
+ /**
+ * Draws the icon of the selected URL as content of the URL
+ * selector.
+ */
+ virtual void drawButton(QPainter* painter);
+
+private slots:
+ /**
+ * Updates the selected index and the icon if a bookmark
+ * has been activated by the user.
+ */
+ void slotBookmarkActivated(int index);
+ void updateBookmarks();
+
+private:
+ int m_selectedIndex;
+ QPopupMenu* m_bookmarksMenu;
+};
+
+#endif
diff --git a/src/bookmarkssettingspage.cpp b/src/bookmarkssettingspage.cpp
new file mode 100644
index 0000000..5b615f8
--- /dev/null
+++ b/src/bookmarkssettingspage.cpp
@@ -0,0 +1,314 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "bookmarkssettingspage.h"
+
+#include <assert.h>
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qvbox.h>
+
+#include <kbookmark.h>
+#include <kbookmarkmanager.h>
+#include <kdialog.h>
+#include <klistview.h>
+#include <klocale.h>
+#include <kpushbutton.h>
+
+#include "dolphinsettings.h"
+#include "editbookmarkdialog.h"
+
+BookmarksSettingsPage::BookmarksSettingsPage(QWidget*parent) :
+ SettingsPageBase(parent),
+ m_addButton(0),
+ m_removeButton(0),
+ m_moveUpButton(0),
+ m_moveDownButton(0)
+{
+ QVBoxLayout* topLayout = new QVBoxLayout(parent, 2, KDialog::spacingHint());
+
+ const int spacing = KDialog::spacingHint();
+
+ QHBox* hBox = new QHBox(parent);
+ hBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+ hBox->setSpacing(spacing);
+ hBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Ignored);
+
+ m_listView = new KListView(hBox);
+ m_listView->addColumn(i18n("Icon"));
+ m_listView->addColumn(i18n("Name"));
+ m_listView->addColumn(i18n("Location"));
+ m_listView->setResizeMode(QListView::LastColumn);
+ m_listView->setColumnAlignment(0, Qt::AlignHCenter);
+ m_listView->setAllColumnsShowFocus(true);
+ m_listView->setSorting(-1);
+ connect(m_listView, SIGNAL(selectionChanged()),
+ this, SLOT(updateButtons()));
+ connect(m_listView, SIGNAL(pressed(QListViewItem*)),
+ this, SLOT(slotBookmarkPressed(QListViewItem*)));
+ connect(m_listView, SIGNAL(doubleClicked(QListViewItem*, const QPoint&, int)),
+ this, SLOT(slotBookmarkDoubleClicked(QListViewItem*, const QPoint&, int)));
+
+ QVBox* buttonBox = new QVBox(hBox);
+ buttonBox->setSpacing(spacing);
+
+ const QSizePolicy buttonSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
+
+ m_addButton = new KPushButton(i18n("Add..."), buttonBox);
+ connect(m_addButton, SIGNAL(clicked()),
+ this, SLOT(slotAddButtonClicked()));
+ m_addButton->setSizePolicy(buttonSizePolicy);
+
+ m_editButton = new KPushButton(i18n("Edit..."), buttonBox);
+ connect(m_editButton, SIGNAL(clicked()),
+ this, SLOT(slotEditButtonClicked()));
+ m_editButton->setSizePolicy(buttonSizePolicy);
+
+ m_removeButton = new KPushButton(i18n("Remove"), buttonBox);
+ connect(m_removeButton, SIGNAL(clicked()),
+ this, SLOT(slotRemoveButtonClicked()));
+ m_removeButton->setSizePolicy(buttonSizePolicy);
+
+ m_moveUpButton = new KPushButton(i18n("Move Up"), buttonBox);
+ connect(m_moveUpButton, SIGNAL(clicked()),
+ this, SLOT(slotMoveUpButtonClicked()));
+ m_moveUpButton->setSizePolicy(buttonSizePolicy);
+
+ m_moveDownButton = new KPushButton(i18n("Move Down"), buttonBox);
+ connect(m_moveDownButton, SIGNAL(clicked()),
+ this, SLOT(slotMoveDownButtonClicked()));
+ m_moveDownButton->setSizePolicy(buttonSizePolicy);
+
+ // Add a dummy widget with no restriction regarding a vertical resizing.
+ // This assures that the spacing between the buttons is not increased.
+ new QWidget(buttonBox);
+
+ topLayout->addWidget(hBox);
+
+ // insert all editable bookmarks.
+ KBookmarkGroup root = DolphinSettings::instance().bookmarkManager()->root();
+ KBookmark bookmark = root.first();
+
+ QListViewItem* prev = 0;
+ while (!bookmark.isNull()) {
+ QListViewItem* item = new QListViewItem(m_listView);
+ item->setPixmap(PixmapIdx, SmallIcon(bookmark.icon()));
+ item->setText(NameIdx, bookmark.text());
+ item->setText(URLIdx, bookmark.url().prettyURL());
+
+ // add hidden column to be able to retrieve the icon name again
+ item->setText(IconIdx, bookmark.icon());
+
+ m_listView->insertItem(item);
+ if (prev != 0) {
+ item->moveItem(prev);
+ }
+ prev = item;
+
+ bookmark = root.next(bookmark);
+ }
+ m_listView->setSelected(m_listView->firstChild(), true);
+
+ updateButtons();
+}
+
+
+BookmarksSettingsPage::~BookmarksSettingsPage()
+{
+}
+
+void BookmarksSettingsPage::applySettings()
+{
+ // delete all bookmarks
+ KBookmarkManager* manager = DolphinSettings::instance().bookmarkManager();
+ KBookmarkGroup root = manager->root();
+ KBookmark bookmark = root.first();
+ while (!bookmark.isNull()) {
+ root.deleteBookmark(bookmark);
+ bookmark = root.first();
+ }
+
+ // add all items as bookmarks
+ QListViewItem* item = m_listView->firstChild();
+ while (item != 0) {
+ root.addBookmark(manager,
+ item->text(NameIdx),
+ KURL(item->text(URLIdx)),
+ item->text(IconIdx)); // hidden column
+ item = item->itemBelow();
+ }
+
+ manager->emitChanged(root);
+}
+
+void BookmarksSettingsPage::updateButtons()
+{
+ const QListViewItem* selectedItem = m_listView->selectedItem();
+ const bool hasSelection = (selectedItem != 0);
+
+ m_editButton->setEnabled(hasSelection);
+ m_removeButton->setEnabled(hasSelection);
+
+ const bool enableMoveUp = hasSelection &&
+ (selectedItem != m_listView->firstChild());
+ m_moveUpButton->setEnabled(enableMoveUp);
+
+ const bool enableMoveDown = hasSelection &&
+ (selectedItem != m_listView->lastChild());
+ m_moveDownButton->setEnabled(enableMoveDown);
+}
+
+void BookmarksSettingsPage::slotBookmarkDoubleClicked(QListViewItem*,
+ const QPoint&,
+ int)
+{
+ slotEditButtonClicked();
+}
+
+void BookmarksSettingsPage::slotBookmarkPressed(QListViewItem* item)
+{
+ if (item == 0) {
+ m_listView->setSelected(m_listView->currentItem(), true);
+ }
+}
+
+void BookmarksSettingsPage::slotAddButtonClicked()
+{
+ KBookmark bookmark = EditBookmarkDialog::getBookmark(i18n("Add Bookmark"),
+ i18n("New bookmark"),
+ KURL(),
+ "bookmark");
+ if (!bookmark.isNull()) {
+ // insert bookmark into listview
+ QListViewItem* item = new QListViewItem(m_listView);
+ item->setPixmap(PixmapIdx, SmallIcon(bookmark.icon()));
+ item->setText(NameIdx, bookmark.text());
+ item->setText(URLIdx, bookmark.url().prettyURL());
+ item->setText(IconIdx, bookmark.icon());
+ m_listView->insertItem(item);
+
+ QListViewItem* lastItem = m_listView->lastChild();
+ if (lastItem != 0) {
+ item->moveItem(lastItem);
+ }
+
+ m_listView->setSelected(item, true);
+ updateButtons();
+ }
+}
+
+void BookmarksSettingsPage::slotEditButtonClicked()
+{
+ QListViewItem* item = m_listView->selectedItem();
+ assert(item != 0); // 'edit' may not get invoked when having no items
+
+ KBookmark bookmark = EditBookmarkDialog::getBookmark(i18n("Edit Bookmark"),
+ item->text(NameIdx),
+ KURL(item->text(URLIdx)),
+ item->text(IconIdx));
+ if (!bookmark.isNull()) {
+ item->setPixmap(PixmapIdx, SmallIcon(bookmark.icon()));
+ item->setText(NameIdx, bookmark.text());
+ item->setText(URLIdx, bookmark.url().prettyURL());
+ item->setText(IconIdx, bookmark.icon());
+ }
+}
+
+void BookmarksSettingsPage::slotRemoveButtonClicked()
+{
+ QListViewItem* selectedItem = m_listView->selectedItem();
+ assert(selectedItem != 0);
+ QListViewItem* nextItem = selectedItem->itemBelow();
+ if (nextItem == 0) {
+ nextItem = selectedItem->itemAbove();
+ }
+
+ m_listView->takeItem(selectedItem);
+ if (nextItem != 0) {
+ m_listView->setSelected(nextItem, true);
+ }
+}
+
+void BookmarksSettingsPage::slotMoveUpButtonClicked()
+{
+ moveBookmark(-1);
+}
+
+void BookmarksSettingsPage::slotMoveDownButtonClicked()
+{
+ moveBookmark(+1);
+}
+
+int BookmarksSettingsPage::selectedBookmarkIndex() const
+{
+ int index = -1;
+
+ QListViewItem* selectedItem = m_listView->selectedItem();
+ if (selectedItem != 0) {
+ index = 0;
+ QListViewItem* item = m_listView->firstChild();
+ while (item != selectedItem) {
+ item = item->nextSibling();
+ ++index;
+ }
+ }
+
+ return index;
+}
+
+void BookmarksSettingsPage::moveBookmark(int direction)
+{
+ // this implementation currently only allows moving of bookmarks
+ // one step up or down
+ assert((direction >= -1) && (direction <= +1));
+
+ // swap bookmarks in listview
+ QListViewItem* selectedItem = m_listView->selectedItem();
+ assert(selectedItem != 0);
+ QListViewItem* item = (direction < 0) ? selectedItem->itemAbove() :
+ selectedItem->itemBelow();
+ assert(item != 0);
+
+ QPixmap pixmap;
+ if (item->pixmap(0) != 0) {
+ pixmap = *(item->pixmap(0));
+ }
+ QString name(item->text(NameIdx));
+ QString url(item->text(URLIdx));
+ QString icon(item->text(IconIdx));
+
+ if (selectedItem->pixmap(0) != 0) {
+ item->setPixmap(PixmapIdx, *(selectedItem->pixmap(0)));
+ }
+ item->setText(NameIdx, selectedItem->text(NameIdx));
+ item->setText(URLIdx, selectedItem->text(URLIdx));
+ item->setText(IconIdx, selectedItem->text(IconIdx));
+
+ selectedItem->setPixmap(PixmapIdx, pixmap);
+ selectedItem->setText(NameIdx, name);
+ selectedItem->setText(URLIdx, url);
+ selectedItem->setText(IconIdx, icon);
+
+ m_listView->setSelected(item, true);
+}
+
+#include "bookmarkssettingspage.moc"
diff --git a/src/bookmarkssettingspage.h b/src/bookmarkssettingspage.h
new file mode 100644
index 0000000..89f3752
--- /dev/null
+++ b/src/bookmarkssettingspage.h
@@ -0,0 +1,93 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef BOOKMARKSSETTINGSPAGE_H
+#define BOOKMARKSSETTINGSPAGE_H
+
+#include <settingspagebase.h>
+#include <qvaluelist.h>
+
+class KListView;
+class KPushButton;
+class QListViewItem;
+
+/**
+ * @brief Represents the page from the Dolphin Settings which allows
+ * to modify the bookmarks.
+ */
+class BookmarksSettingsPage : public SettingsPageBase
+{
+ Q_OBJECT
+
+public:
+ BookmarksSettingsPage(QWidget* parent);
+
+ virtual ~BookmarksSettingsPage();
+
+ /** @see SettingsPageBase::applySettings */
+ virtual void applySettings();
+
+private slots:
+ void updateButtons();
+ void slotBookmarkDoubleClicked(QListViewItem*, const QPoint&, int);
+ void slotAddButtonClicked();
+ void slotEditButtonClicked();
+ void slotRemoveButtonClicked();
+ void slotMoveUpButtonClicked();
+ void slotMoveDownButtonClicked();
+
+ /**
+ * Is connected with the signal QListView::pressed(QListViewItem* item)
+ * and assures that always one bookmarks stays selected although a
+ * click has been done on the viewport area.
+ * TODO: this is a workaround, possibly there is a more easy approach
+ * doing this...
+ */
+ void slotBookmarkPressed(QListViewItem* item);
+
+private:
+ enum ColumnIndex {
+ PixmapIdx = 0,
+ NameIdx = 1,
+ URLIdx = 2,
+ IconIdx = 3
+ };
+
+ KListView* m_listView;
+ KPushButton* m_addButton;
+ KPushButton* m_editButton;
+ KPushButton* m_removeButton;
+ KPushButton* m_moveUpButton;
+ KPushButton* m_moveDownButton;
+
+ /**
+ * Returns the index of the selected bookmark
+ * inside the bookmarks listview.
+ */
+ int selectedBookmarkIndex() const;
+
+ /**
+ * Moves the currently selected bookmark up, if 'direction'
+ * is < 0, otherwise the bookmark is moved down.
+ */
+ void moveBookmark(int direction);
+};
+
+#endif
diff --git a/src/bookmarkssidebarpage.cpp b/src/bookmarkssidebarpage.cpp
new file mode 100644
index 0000000..34eef5c
--- /dev/null
+++ b/src/bookmarkssidebarpage.cpp
@@ -0,0 +1,331 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz <[email protected]> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "bookmarkssidebarpage.h"
+
+#include <qlistbox.h>
+#include <qlayout.h>
+#include <qpainter.h>
+#include <assert.h>
+#include <qpopupmenu.h>
+
+#include <kbookmarkmanager.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <kurldrag.h>
+
+#include "dolphinsettings.h"
+#include "dolphin.h"
+#include "dolphinview.h"
+#include "editbookmarkdialog.h"
+
+BookmarksSidebarPage::BookmarksSidebarPage(QWidget* parent) :
+ SidebarPage(parent)
+{
+ QVBoxLayout* layout = new QVBoxLayout(this);
+ m_bookmarksList = new BookmarksListBox(this);
+ m_bookmarksList->setPaletteBackgroundColor(colorGroup().background());
+
+ layout->addWidget(m_bookmarksList);
+ connect(m_bookmarksList, SIGNAL(mouseButtonClicked(int, QListBoxItem*, const QPoint&)),
+ this, SLOT(slotMouseButtonClicked(int, QListBoxItem*)));
+ connect(m_bookmarksList, SIGNAL(contextMenuRequested(QListBoxItem*, const QPoint&)),
+ this, SLOT(slotContextMenuRequested(QListBoxItem*, const QPoint&)));
+
+ KBookmarkManager* manager = DolphinSettings::instance().bookmarkManager();
+ connect(manager, SIGNAL(changed(const QString&, const QString&)),
+ this, SLOT(updateBookmarks()));
+
+ updateBookmarks();
+}
+
+BookmarksSidebarPage::~BookmarksSidebarPage()
+{
+}
+
+void BookmarksSidebarPage::activeViewChanged()
+{
+ connectToActiveView();
+}
+
+void BookmarksSidebarPage::updateBookmarks()
+{
+ m_bookmarksList->clear();
+
+ KIconLoader iconLoader;
+
+ KBookmarkGroup root = DolphinSettings::instance().bookmarkManager()->root();
+ KBookmark bookmark = root.first();
+ while (!bookmark.isNull()) {
+ m_bookmarksList->insertItem( BookmarkItem::fromKbookmark(bookmark, iconLoader) );
+
+ bookmark = root.next(bookmark);
+ }
+
+ connectToActiveView();
+}
+
+void BookmarksSidebarPage::slotMouseButtonClicked(int button, QListBoxItem* item)
+{
+ if ((button != Qt::LeftButton) || (item == 0)) {
+ return;
+ }
+
+ const int index = m_bookmarksList->index(item);
+ KBookmark bookmark = DolphinSettings::instance().bookmark(index);
+ Dolphin::mainWin().activeView()->setURL(bookmark.url());
+}
+
+void BookmarksSidebarPage::slotContextMenuRequested(QListBoxItem* item,
+ const QPoint& pos)
+{
+ const int insertID = 1;
+ const int editID = 2;
+ const int deleteID = 3;
+ const int addID = 4;
+
+ QPopupMenu* popup = new QPopupMenu();
+ if (item == 0) {
+ popup->insertItem(SmallIcon("filenew"), i18n("Add Bookmark..."), addID);
+ }
+ else {
+ popup->insertItem(SmallIcon("filenew"), i18n("Insert Bookmark..."), insertID);
+ popup->insertItem(SmallIcon("edit"), i18n("Edit..."), editID);
+ popup->insertItem(SmallIcon("editdelete"), i18n("Delete"), deleteID);
+ }
+
+ KBookmarkManager* manager = DolphinSettings::instance().bookmarkManager();
+ KBookmarkGroup root = manager->root();
+ const int index = m_bookmarksList->index(m_bookmarksList->selectedItem());
+
+ const int result = popup->exec(pos);
+ switch (result) {
+ case insertID: {
+ KBookmark newBookmark = EditBookmarkDialog::getBookmark(i18n("Insert Bookmark"),
+ i18n("New bookmark"),
+ KURL(),
+ "bookmark");
+ if (!newBookmark.isNull()) {
+ root.addBookmark(manager, newBookmark);
+ if (index > 0) {
+ KBookmark prevBookmark = DolphinSettings::instance().bookmark(index - 1);
+ root.moveItem(newBookmark, prevBookmark);
+ }
+ else {
+ // insert bookmark at first position (is a little bit tricky as KBookmarkGroup
+ // only allows to move items after existing items)
+ KBookmark firstBookmark = root.first();
+ root.moveItem(newBookmark, firstBookmark);
+ root.moveItem(firstBookmark, newBookmark);
+ }
+ manager->emitChanged(root);
+ }
+ break;
+ }
+
+ case editID: {
+ KBookmark oldBookmark = DolphinSettings::instance().bookmark(index);
+ KBookmark newBookmark = EditBookmarkDialog::getBookmark(i18n("Edit Bookmark"),
+ oldBookmark.text(),
+ oldBookmark.url(),
+ oldBookmark.icon());
+ if (!newBookmark.isNull()) {
+ root.addBookmark(manager, newBookmark);
+ root.moveItem(newBookmark, oldBookmark);
+ root.deleteBookmark(oldBookmark);
+ manager->emitChanged(root);
+ }
+ break;
+ }
+
+ case deleteID: {
+ KBookmark bookmark = DolphinSettings::instance().bookmark(index);
+ root.deleteBookmark(bookmark);
+ manager->emitChanged(root);
+ break;
+ }
+
+ case addID: {
+ KBookmark bookmark = EditBookmarkDialog::getBookmark(i18n("Add Bookmark"),
+ "New bookmark",
+ KURL(),
+ "bookmark");
+ if (!bookmark.isNull()) {
+ root.addBookmark(manager, bookmark);
+ manager->emitChanged(root);
+ }
+ }
+
+ default: break;
+ }
+
+ delete popup;
+ popup = 0;
+
+ DolphinView* view = Dolphin::mainWin().activeView();
+ adjustSelection(view->url());
+}
+
+
+void BookmarksSidebarPage::adjustSelection(const KURL& url)
+{
+ // TODO (remarked in dolphin/TODO): the following code is quite equal
+ // to BookmarkSelector::updateSelection().
+
+ KBookmarkGroup root = DolphinSettings::instance().bookmarkManager()->root();
+ KBookmark bookmark = root.first();
+
+ int maxLength = 0;
+ int selectedIndex = -1;
+
+ // Search the bookmark which is equal to the URL or at least is a parent URL.
+ // If there are more than one possible parent URL candidates, choose the bookmark
+ // which covers the bigger range of the URL.
+ int i = 0;
+ while (!bookmark.isNull()) {
+ const KURL bookmarkURL = bookmark.url();
+ if (bookmarkURL.isParentOf(url)) {
+ const int length = bookmarkURL.prettyURL().length();
+ if (length > maxLength) {
+ selectedIndex = i;
+ maxLength = length;
+ }
+ }
+ bookmark = root.next(bookmark);
+ ++i;
+ }
+
+ const bool block = m_bookmarksList->signalsBlocked();
+ m_bookmarksList->blockSignals(true);
+ if (selectedIndex < 0) {
+ // no bookmark matches, hence deactivate any selection
+ const int currentIndex = m_bookmarksList->index(m_bookmarksList->selectedItem());
+ m_bookmarksList->setSelected(currentIndex, false);
+ }
+ else {
+ // select the bookmark which is part of the current URL
+ m_bookmarksList->setSelected(selectedIndex, true);
+ }
+ m_bookmarksList->blockSignals(block);
+}
+
+void BookmarksSidebarPage::slotURLChanged(const KURL& url)
+{
+ adjustSelection(url);
+}
+
+void BookmarksSidebarPage::connectToActiveView()
+{
+ DolphinView* view = Dolphin::mainWin().activeView();
+ adjustSelection(view->url());
+ connect(view, SIGNAL(signalURLChanged(const KURL&)),
+ this, SLOT(slotURLChanged(const KURL&)));
+}
+
+BookmarksListBox::BookmarksListBox(QWidget* parent) :
+ QListBox(parent)
+{
+ setAcceptDrops(true);
+}
+BookmarksListBox::~BookmarksListBox()
+{
+}
+
+void BookmarksListBox::paintEvent(QPaintEvent* /* event */)
+{
+ // don't invoke QListBox::paintEvent(event) to prevent
+ // that any kind of frame is drawn
+}
+
+void BookmarksListBox::contentsMousePressEvent(QMouseEvent *event)
+{
+ if (event->button() == LeftButton)
+ dragPos = event->pos();
+ QListBox::contentsMousePressEvent(event);
+}
+
+void BookmarksListBox::contentsMouseMoveEvent(QMouseEvent *event)
+{
+ if (event->state() & LeftButton) {
+ int distance = (event->pos() - dragPos).manhattanLength();
+ if (distance > QApplication::startDragDistance())
+ startDrag();
+ }
+ QListBox::contentsMouseMoveEvent(event);
+}
+
+void BookmarksListBox::startDrag()
+{
+ int currentItem = QListBox::currentItem();
+ if (currentItem != -1) {
+ BookmarkItem* bookmark = (BookmarkItem*)item(currentItem);
+ if (bookmark!=0){
+ KURL::List lst;
+ lst.append( bookmark->url() );
+ KURLDrag *drag = new KURLDrag(lst, this);
+ drag->drag();
+ }
+ }
+}
+
+void BookmarksListBox::dragEnterEvent( QDragEnterEvent *event )
+{
+ event->accept(KURLDrag::canDecode(event));
+}
+
+void BookmarksListBox::dropEvent( QDropEvent *event )
+{
+ KURL::List urls;
+ if (KURLDrag::decode(event, urls) && !urls.isEmpty()) {
+ KBookmarkManager* manager = DolphinSettings::instance().bookmarkManager();
+ KBookmarkGroup root = manager->root();
+
+ KURL::List::iterator it;
+ for(it=urls.begin(); it!=urls.end(); ++it) {
+ root.addBookmark(manager, (*it).fileName(), (*it), "", false);
+ }
+ manager->emitChanged(root);
+ }
+}
+
+BookmarkItem::BookmarkItem(const QPixmap& pixmap, const QString& text, const KURL& url) :
+ QListBoxPixmap(pixmap, text),
+ m_url(url)
+{
+}
+
+BookmarkItem::~BookmarkItem()
+{
+}
+
+int BookmarkItem::height(const QListBox* listBox) const
+{
+ return QListBoxPixmap::height(listBox) + 8;
+}
+
+const KURL& BookmarkItem::url() const
+{
+ return m_url;
+}
+
+BookmarkItem* BookmarkItem::fromKbookmark(const KBookmark& bookmark, const KIconLoader& iconLoader)
+{
+ QPixmap icon(iconLoader.loadIcon(bookmark.icon(), KIcon::NoGroup, KIcon::SizeMedium));
+ return new BookmarkItem(icon, bookmark.text(), bookmark.url());
+}
diff --git a/src/bookmarkssidebarpage.h b/src/bookmarkssidebarpage.h
new file mode 100644
index 0000000..7941fd6
--- /dev/null
+++ b/src/bookmarkssidebarpage.h
@@ -0,0 +1,139 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz <[email protected]>
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+#ifndef _BOOKMARKSSIDEBARPAGE_H_
+#define _BOOKMARKSSIDEBARPAGE_H_
+
+#include <sidebarpage.h>
+#include <qlistbox.h>
+#include <kurl.h>
+#include <kbookmark.h>
+#include <kiconloader.h>
+
+class BookmarksListBox;
+
+/**
+ * @brief Sidebar page for accessing bookmarks.
+ *
+ * It is possible to add, remove and edit bookmarks
+ * by a context menu. The selection of the bookmark
+ * is automatically adjusted to the URL given by
+ * the active view.
+ */
+class BookmarksSidebarPage : public SidebarPage
+{
+ Q_OBJECT
+
+public:
+ BookmarksSidebarPage(QWidget* parent);
+ virtual ~BookmarksSidebarPage();
+
+protected:
+ /** @see SidebarPage::activeViewChanged() */
+ virtual void activeViewChanged();
+
+private slots:
+ /** Fills the listbox with the bookmarks stored in DolphinSettings. */
+ void updateBookmarks();
+
+ /**
+ * Checks whether the left mouse button has been clicked above a bookmark.
+ * If this is the case, the URL for the currently active view is adjusted.
+ */
+ void slotMouseButtonClicked(int button, QListBoxItem* item);
+
+ /** @see QListBox::slotContextMenuRequested */
+ void slotContextMenuRequested(QListBoxItem* item, const QPoint& pos);
+
+ /**
+ * Is invoked whenever the URL of the active view has been changed. Adjusts
+ * the selection of the listbox to the bookmark which is part of the current URL.
+ */
+ void slotURLChanged(const KURL& url);
+
+private:
+ /**
+ * Updates the selection dependent from the given URL \a url. The
+ * URL must not match exactly to one of the available bookmarks:
+ * The bookmark which is equal to the URL or at least is a parent URL
+ * is selected. If there are more than one possible parent URL candidates,
+ * the bookmark which covers the bigger range of the URL is selected.
+ */
+ void adjustSelection(const KURL& url);
+
+ /**
+ * Connects to signals from the currently active Dolphin view to get
+ * informed about URL and bookmark changes.
+ */
+ void connectToActiveView();
+
+ BookmarksListBox* m_bookmarksList;
+};
+
+/**
+ * @brief Listbox which contains a list of bookmarks.
+ *
+ * Only QListBox::paintEvent() has been overwritten to prevent
+ * that a (not wanted) frameborder is drawn.
+ */
+class BookmarksListBox : public QListBox
+{
+ Q_OBJECT
+
+public:
+ BookmarksListBox(QWidget* parent);
+ virtual ~BookmarksListBox();
+
+protected:
+ //drag
+ void contentsMousePressEvent(QMouseEvent *event);
+ void contentsMouseMoveEvent(QMouseEvent *event);
+ //drop
+ void dragEnterEvent( QDragEnterEvent *evt );
+ void dropEvent( QDropEvent *evt );
+// void mousePressEvent( QMouseEvent *evt );
+// void mouseMoveEvent( QMouseEvent * );
+ /** @see QWidget::paintEvent() */
+ virtual void paintEvent(QPaintEvent* event);
+private:
+ QPoint dragPos;
+
+ void startDrag();
+};
+
+/**
+ * @brief Item which can be added to a BookmarksListBox.
+ *
+ * Only QListBoxPixmap::height() has been overwritten to get
+ * a spacing between the items.
+ */
+class BookmarkItem : public QListBoxPixmap
+{
+public:
+ BookmarkItem(const QPixmap& pixmap, const QString& text, const KURL& url);
+ virtual ~BookmarkItem();
+ virtual int height(const QListBox* listBox) const;
+ const KURL& url() const;
+
+ static BookmarkItem* fromKbookmark(const KBookmark& bookmark, const KIconLoader& iconLoader);
+
+private:
+ KURL m_url;
+};
+
+#endif // _BOOKMARKSSIDEBARPAGE_H_
diff --git a/src/d3lphin.desktop b/src/d3lphin.desktop
new file mode 100644
index 0000000..9eae8ad
--- /dev/null
+++ b/src/d3lphin.desktop
@@ -0,0 +1,65 @@
+[Desktop Entry]
+Encoding=UTF-8
+Name=Dolphin
+Name[pa]=ਡਾਲਫਿਨ
+Name[sr]=Делфин
+Name[sr@latin]=Делфин
+Name[uk]=Дельфін
+Name[ar]=الدولفين
+Name[lv]= Dolphin
+Name[ne]=डल्फिन
+Name[pa]=ਡਾਲਫਿਨ
+Exec=d3lphin %i -caption "%c" "%u"
+Icon=d3lphin
+Type=Application
+DocPath=d3lphin/d3lphin.html
+Categories=Qt;KDE;System;FileManager;
+GenericName=File Manager
+GenericName[ar]=مدير الملفات
+GenericName[be]=Кіраўнік файлаў
+GenericName[bg]=Файлов браузър
+GenericName[ca]=Gestor de fitxers
+GenericName[cs]=Správce souborů
+GenericName[csb]=Menadżer lopków
+GenericName[de]=Dateimanager
+GenericName[el]=Διαχειριστής αρχείων
+GenericName[eo]=Dosieradministrilo
+GenericName[es]=Gestor de ficheros
+GenericName[et]=Failihaldur
+GenericName[eu]=Fitxategi kudeatzailea
+GenericName[fa]=مدیر پرونده
+GenericName[ga]=Bainisteoir Comhad
+GenericName[he]=מנהל קבצים
+GenericName[hu]=Fájlkezelő
+GenericName[it]=Gestione file
+GenericName[ja]=ファイルマネージャ
+GenericName[kk]=Файл менеджері
+GenericName[km]=កម្មវិធី​គ្រប់គ្រង​ឯកសារ
+GenericName[ko]=파일 관리자
+GenericName[lv]=Failu pārvaldnieks
+GenericName[nb]=Filbehandler
+GenericName[nds]=Dateipleger
+GenericName[ne]=फाइल प्रबन्धक
+GenericName[nl]=Bestandsbeheerder
+GenericName[nn]=Filhandsamar
+GenericName[oc]=Gestionari de fichièrs
+GenericName[pa]=ਫਾਇਲ ਮੈਨੇਜਰ
+GenericName[pl]=Menedżer plików
+GenericName[pt]=Gestor de Ficheiros
+GenericName[pt_BR]=Gerenciador de Arquivos
+GenericName[ru]=Файловый менеджер
+GenericName[sl]=Upravitelj datotek
+GenericName[sr]=Менаџер фајлова
+GenericName[sr@latin]=Menadžer fajlova
+GenericName[sv]=Filhanterare
+GenericName[tg]=Мудири файл
+GenericName[th]=เครื่องมือจัดการแฟ้ม
+GenericName[uk]=Менеджер файлів
+GenericName[vi]=Bộ quản lý tập tin
+GenericName[wa]=Manaedjeu di fitchîs
+GenericName[x-test]=xxFile Managerxx
+GenericName[zh_CN]=文件管理器
+GenericName[zh_TW]=檔案管理程式
+Terminal=false
+MimeType=inode/directory;
+InitialPreference=10
diff --git a/src/d3lphinui.rc b/src/d3lphinui.rc
new file mode 100644
index 0000000..9280645
--- /dev/null
+++ b/src/d3lphinui.rc
@@ -0,0 +1,110 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui version="1" name="d3lphin" >
+ <MenuBar>
+ <Menu name="file" >
+ <Menu name="create_new" >
+ <text>Create New</text>
+ <Action name="create_folder" />
+ <Separator/>
+ <ActionList name="create_file_group" />
+ </Menu>
+ <Separator/>
+ <Action name="rename" />
+ <Action name="move_to_trash" />
+ <Action name="delete" />
+ <Separator/>
+ <Action name="properties" />
+ </Menu>
+ <Menu name="edit" >
+ <Action name="select_all" />
+ <Action name="invert_selection" />
+ </Menu>
+ <Menu name="view" >
+ <Menu name="view_mode" >
+ <text>View Mode</text>
+ <Action name="icons" />
+ <Action name="details" />
+ <Action name="previews" />
+ </Menu>
+ <Menu name="sort" >
+ <text>Sort</text>
+ <Action name="by_name" />
+ <Action name="by_size" />
+ <Action name="by_date" />
+ <Separator/>
+ <Action name="descending" />
+ </Menu>
+ <Action name="show_hidden_files" />
+ <Separator/>
+ <Action name="split_view" />
+ <Action name="reload" />
+ <Action name="stop" />
+ <Separator/>
+ <Menu name="navigation_bar" >
+ <text>Navigation Bar</text>
+ <Action name="edit_location" />
+ <Action name="browse" />
+ </Menu>
+ <Action name="leftsidebar" />
+ <Action name="rightsidebar" />
+ <Action name="view_properties" />
+ </Menu>
+ <Menu name="tools">
+ <Action name="open_terminal" />
+ <Action name="find_file" />
+ <Action name="show_filter_bar" />
+ <Action name="compare_files" />
+ </Menu>
+</MenuBar>
+<State name="new_file" >
+ <disable>
+ <Action name="edit_undo" />
+ <Action name="edit_redo" />
+ <Action name="edit_cut" />
+ <Action name="edit_copy" />
+ <Action name="rename" />
+ <Action name="move_to_trash" />
+ <Action name="delete" />
+ <Action name="invert_selection" />
+ <Separator/>
+ <Action name="properties" />
+ <Action name="go_back" />
+ <Action name="go_forward" />
+ </disable>
+ </State>
+ <State name="has_selection" >
+ <enable>
+ <Action name="edit_cut" />
+ <Action name="edit_copy" />
+ <Action name="move_to_trash" />
+ <Action name="delete" />
+ <Action name="properties" />
+ <Action name="invert_selection" />
+ </enable>
+ </State>
+ <State name="has_no_selection" >
+ <disable>
+ <Action name="edit_cut" />
+ <Action name="edit_copy" />
+ <Action name="rename" />
+ <Action name="move_to_trash" />
+ <Action name="delete" />
+ <Action name="properties" />
+ <Action name="invert_selection" />
+ </disable>
+ </State>
+ <ToolBar noMerge="1" name="mainToolBar" >
+ <text>Main Toolbar</text>
+ <Action name="go_back" />
+ <Action name="go_forward" />
+ <Separator name="separator_1" />
+ <Action name="icons" />
+ <Action name="details" />
+ <Action name="previews" />
+ <Separator name="separator_0" />
+ <Action name="split_view" />
+ </ToolBar>
+ <ActionProperties>
+ <Action shortcut="Backspace;XF86Back" name="go_back" />
+ </ActionProperties>
+</kpartgui>
diff --git a/src/detailsviewsettingspage.cpp b/src/detailsviewsettingspage.cpp
new file mode 100644
index 0000000..b8c4d97
--- /dev/null
+++ b/src/detailsviewsettingspage.cpp
@@ -0,0 +1,155 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "detailsviewsettingspage.h"
+#include <qcheckbox.h>
+#include <klocale.h>
+#include <kdialog.h>
+#include <kfontcombo.h>
+#include <qspinbox.h>
+#include <qlabel.h>
+#include <qgrid.h>
+#include <assert.h>
+#include <qbuttongroup.h>
+#include <qradiobutton.h>
+#include <qcombobox.h>
+#include <qgroupbox.h>
+#include <qgroupbox.h>
+#include "dolphinsettings.h"
+#include "dolphindetailsviewsettings.h"
+#include "dolphindetailsview.h"
+
+DetailsViewSettingsPage::DetailsViewSettingsPage(QWidget *parent) :
+ QVBox(parent),
+ m_dateBox(0),
+ m_permissionsBox(0),
+ m_ownerBox(0),
+ m_groupBox(0),
+ m_smallIconSize(0),
+ m_mediumIconSize(0),
+ m_largeIconSize(0)
+{
+ const int spacing = KDialog::spacingHint();
+ const int margin = KDialog::marginHint();
+ const QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+
+ setSpacing(spacing);
+ setMargin(margin);
+
+ DolphinDetailsViewSettings* settings = DolphinSettings::instance().detailsView();
+ assert(settings != 0);
+
+ // create "Columns" properties
+ QGroupBox* columnsGroup = new QGroupBox(4, Qt::Vertical, i18n("Columns"), this);
+ columnsGroup->setSizePolicy(sizePolicy);
+ columnsGroup->setMargin(margin);
+
+ QHBox* visibleColumnsLayout = new QHBox(columnsGroup);
+ m_dateBox = new QCheckBox(i18n("Date"), visibleColumnsLayout);
+ m_dateBox->setChecked(settings->isColumnEnabled(DolphinDetailsView::DateColumn));
+
+ m_permissionsBox = new QCheckBox(i18n("Permissions"), visibleColumnsLayout);
+ m_permissionsBox->setChecked(settings->isColumnEnabled(DolphinDetailsView::PermissionsColumn));
+
+ m_ownerBox = new QCheckBox(i18n("Owner"), visibleColumnsLayout);
+ m_ownerBox->setChecked(settings->isColumnEnabled(DolphinDetailsView::OwnerColumn));
+
+ m_groupBox = new QCheckBox(i18n("Group"), visibleColumnsLayout);
+ m_groupBox->setChecked(settings->isColumnEnabled(DolphinDetailsView::GroupColumn));
+
+ // Create "Icon" properties
+ QButtonGroup* iconSizeGroup = new QButtonGroup(3, Qt::Horizontal, i18n("Icon Size"), this);
+ iconSizeGroup->setSizePolicy(sizePolicy);
+ iconSizeGroup->setMargin(margin);
+ m_smallIconSize = new QRadioButton(i18n("Small"), iconSizeGroup);
+ m_mediumIconSize = new QRadioButton(i18n("Medium"), iconSizeGroup);
+ m_largeIconSize = new QRadioButton(i18n("Large"), iconSizeGroup);
+ switch (settings->iconSize()) {
+ case KIcon::SizeLarge:
+ m_largeIconSize->setChecked(true);
+ break;
+
+ case KIcon::SizeMedium:
+ m_mediumIconSize->setChecked(true);
+ break;
+
+ case KIcon::SizeSmall:
+ default:
+ m_smallIconSize->setChecked(true);
+ }
+
+ //new QLabel(i18n("Icon size:"), iconGroup);
+ //m_iconSizeBox = new QComboBox(iconGroup);
+ //m_iconSizeBox->insertItem(i18n("Small"));
+ //m_iconSizeBox->insertItem(i18n("Medium"));
+ //m_iconSizeBox->insertItem(i18n("Large"));
+
+ // create "Text" properties
+ QGroupBox* textGroup = new QGroupBox(2, Qt::Horizontal, i18n("Text"), this);
+ textGroup->setSizePolicy(sizePolicy);
+ textGroup->setMargin(margin);
+
+ new QLabel(i18n("Font family:"), textGroup);
+ m_fontFamilyBox = new KFontCombo(textGroup);
+ m_fontFamilyBox->setCurrentFont(settings->fontFamily());
+
+ new QLabel(i18n("Font size:"), textGroup);
+ m_fontSizeBox = new QSpinBox(6, 99, 1, textGroup);
+ m_fontSizeBox->setValue(settings->fontSize());
+
+ // Add a dummy widget with no restriction regarding
+ // a vertical resizing. This assures that the dialog layout
+ // is not stretched vertically.
+ new QWidget(this);
+}
+
+
+DetailsViewSettingsPage::~DetailsViewSettingsPage()
+{
+}
+
+void DetailsViewSettingsPage::applySettings()
+{
+ DolphinDetailsViewSettings* settings = DolphinSettings::instance().detailsView();
+ assert(settings != 0);
+
+ settings->setColumnEnabled(DolphinDetailsView::DateColumn,
+ m_dateBox->isChecked());
+ settings->setColumnEnabled(DolphinDetailsView::PermissionsColumn,
+ m_permissionsBox->isChecked());
+ settings->setColumnEnabled(DolphinDetailsView::OwnerColumn,
+ m_ownerBox->isChecked());
+ settings->setColumnEnabled(DolphinDetailsView::GroupColumn,
+ m_groupBox->isChecked());
+
+ int iconSize = KIcon::SizeSmall;
+ if (m_mediumIconSize->isChecked()) {
+ iconSize = KIcon::SizeMedium;
+ }
+ else if (m_largeIconSize->isChecked()) {
+ iconSize = KIcon::SizeLarge;
+ }
+ settings->setIconSize(iconSize);
+
+ settings->setFontFamily(m_fontFamilyBox->currentFont());
+ settings->setFontSize(m_fontSizeBox->value());
+}
+
+#include "detailsviewsettingspage.moc"
diff --git a/src/detailsviewsettingspage.h b/src/detailsviewsettingspage.h
new file mode 100644
index 0000000..c9bde55
--- /dev/null
+++ b/src/detailsviewsettingspage.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef DETAILSVIEWSETTINGSPAGE_H
+#define DETAILSVIEWSETTINGSPAGE_H
+
+#include <qvbox.h>
+class QCheckBox;
+class KFontCombo;
+class QSpinBox;
+class QComboBox;
+class QRadioButton;
+
+/**
+ * @brief Represents the page from the Dolphin Settings which allows
+ * to modify the settings for the details view.
+ *
+ * @author Peter Penz <[email protected]>
+ */
+class DetailsViewSettingsPage : public QVBox
+{
+ Q_OBJECT
+
+public:
+ DetailsViewSettingsPage(QWidget* parent);
+ virtual ~DetailsViewSettingsPage();
+
+ /**
+ * Applies the settings for the details view.
+ * The settings are persisted automatically when
+ * closing Dolphin.
+ */
+ void applySettings();
+
+private:
+ QCheckBox* m_dateBox;
+ QCheckBox* m_permissionsBox;
+ QCheckBox* m_ownerBox;
+ QCheckBox* m_groupBox;
+ QRadioButton* m_smallIconSize;
+ QRadioButton* m_mediumIconSize;
+ QRadioButton* m_largeIconSize;
+
+ KFontCombo* m_fontFamilyBox;
+ QSpinBox* m_fontSizeBox;
+};
+
+#endif
diff --git a/src/dolphin.cpp b/src/dolphin.cpp
new file mode 100644
index 0000000..09eeeeb
--- /dev/null
+++ b/src/dolphin.cpp
@@ -0,0 +1,1711 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz <[email protected]> *
+ * Copyright (C) 2006 by Stefan Monov <[email protected]> *
+ * Copyright (C) 2006 by Cvetoslav Ludmiloff <[email protected]> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "dolphin.h"
+
+#include <assert.h>
+
+#include <kbookmarkmanager.h>
+#include <kglobal.h>
+#include <kpropertiesdialog.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kdeversion.h>
+#include <kstatusbar.h>
+#include <kaccel.h>
+#include <kio/netaccess.h>
+#include <kfiledialog.h>
+#include <kconfig.h>
+#include <kurl.h>
+#include <kurldrag.h>
+#include <kstdaccel.h>
+#include <kaction.h>
+#include <kstdaction.h>
+#include <kactionclasses.h>
+#include <kpopupmenu.h>
+#include <kio/renamedlg.h>
+#include <kinputdialog.h>
+#include <kshell.h>
+#include <kdesktopfile.h>
+#include <kstandarddirs.h>
+#include <kprotocolinfo.h>
+#include <kmessagebox.h>
+#include <kservice.h>
+#include <kstandarddirs.h>
+#include <krun.h>
+
+#include <qclipboard.h>
+#include <qdragobject.h>
+
+#include "urlnavigator.h"
+#include "viewpropertiesdialog.h"
+#include "viewproperties.h"
+#include "dolphinsettings.h"
+#include "dolphinsettingsdialog.h"
+#include "dolphinstatusbar.h"
+#include "undomanager.h"
+#include "progressindicator.h"
+#include "dolphinsettings.h"
+#include "sidebars.h"
+#include "sidebarssettings.h"
+
+
+Dolphin& Dolphin::mainWin()
+{
+ static Dolphin* instance = 0;
+ if (instance == 0) {
+ instance = new Dolphin();
+ instance->init();
+ }
+ return *instance;
+}
+
+Dolphin::~Dolphin()
+{
+}
+
+void Dolphin::setActiveView(DolphinView* view)
+{
+ assert((view == m_view[PrimaryIdx]) || (view == m_view[SecondaryIdx]));
+ if (m_activeView == view) {
+ return;
+ }
+
+ m_activeView = view;
+
+ updateHistory();
+ updateEditActions();
+ updateViewActions();
+ updateGoActions();
+
+ setCaption(m_activeView->url().fileName());
+
+ emit activeViewChanged();
+}
+
+void Dolphin::dropURLs(const KURL::List& urls,
+ const KURL& destination)
+{
+ const ButtonState keyboardState = KApplication::keyboardMouseState();
+ const bool shiftPressed = (keyboardState & ShiftButton) > 0;
+ const bool controlPressed = (keyboardState & ControlButton) > 0;
+
+ int selectedIndex = -1;
+ if (shiftPressed && controlPressed) {
+ // shortcut for 'Linke Here' is used
+ selectedIndex = 2;
+ }
+ else if (controlPressed) {
+ // shortcut for 'Copy Here' is used
+ selectedIndex = 1;
+ }
+ else if (shiftPressed) {
+ // shortcut for 'Move Here' is used
+ selectedIndex = 0;
+ }
+ else {
+ // no shortcut is used, hence open a popup menu
+ KPopupMenu popup(this);
+
+ popup.insertItem(SmallIcon("goto"), i18n("&Move Here") + "\t" + KKey::modFlagLabel(KKey::SHIFT), 0);
+ popup.insertItem(SmallIcon("editcopy"), i18n( "&Copy Here" ) + "\t" + KKey::modFlagLabel(KKey::CTRL), 1);
+ popup.insertItem(i18n("&Link Here") + "\t" + KKey::modFlagLabel((KKey::ModFlag)(KKey::CTRL|KKey::SHIFT)), 2);
+ popup.insertSeparator();
+ popup.insertItem(SmallIcon("stop"), i18n("Cancel"), 3);
+ popup.setAccel(i18n("Escape"), 3);
+
+ selectedIndex = popup.exec(QCursor::pos());
+ }
+
+ if (selectedIndex < 0) {
+ return;
+ }
+
+ switch (selectedIndex) {
+ case 0: {
+ // 'Move Here' has been selected
+ updateViewProperties(urls);
+ moveURLs(urls, destination);
+ break;
+ }
+
+ case 1: {
+ // 'Copy Here' has been selected
+ updateViewProperties(urls);
+ copyURLs(urls, destination);
+ break;
+ }
+
+ case 2: {
+ // 'Link Here' has been selected
+ KIO::Job* job = KIO::link(urls, destination);
+ addPendingUndoJob(job, DolphinCommand::Link, urls, destination);
+ break;
+ }
+
+ default:
+ // 'Cancel' has been selected
+ break;
+ }
+}
+
+void Dolphin::refreshViews()
+{
+ const bool split = DolphinSettings::instance().isViewSplit();
+ const bool isPrimaryViewActive = (m_activeView == m_view[PrimaryIdx]);
+ DolphinSettings& settings = DolphinSettings::instance();
+ KURL url;
+ for (int i = PrimaryIdx; i <= SecondaryIdx; ++i) {
+ if (m_view[i] != 0) {
+ url = m_view[i]->url();
+
+ // delete view instance...
+ m_view[i]->close();
+ m_view[i]->deleteLater();
+ m_view[i] = 0;
+ }
+
+ if (split || (i == PrimaryIdx)) {
+ // ... and recreate it
+ ViewProperties props(url);
+ m_view[i] = new DolphinView(m_splitter,
+ url,
+ props.viewMode(),
+ props.isShowHiddenFilesEnabled());
+ m_view[i]->show();
+ }
+
+ rightSidebarSettings* rightsidebarSettings = settings.rightsidebar();
+ assert(rightsidebarSettings != 0);
+ if (rightsidebarSettings->isVisible()) {
+ m_splitter->moveToLast(m_rightsidebar);
+ }
+ }
+
+ m_activeView = isPrimaryViewActive ? m_view[PrimaryIdx] : m_view[SecondaryIdx];
+ assert(m_activeView != 0);
+
+ updateViewActions();
+ emit activeViewChanged();
+}
+
+void Dolphin::slotHistoryChanged()
+{
+ updateHistory();
+}
+
+void Dolphin::slotURLChanged(const KURL& url)
+{
+ updateEditActions();
+ updateGoActions();
+ setCaption(url.fileName());
+}
+
+void Dolphin::slotURLChangeRequest(const KURL& url)
+{
+ clearStatusBar();
+ m_activeView->setURL(url);
+}
+
+void Dolphin::slotViewModeChanged()
+{
+ updateViewActions();
+}
+
+void Dolphin::slotShowHiddenFilesChanged()
+{
+ KToggleAction* showHiddenFilesAction =
+ static_cast<KToggleAction*>(actionCollection()->action("show_hidden_files"));
+ showHiddenFilesAction->setChecked(m_activeView->isShowHiddenFilesEnabled());
+}
+
+void Dolphin::slotShowFilterBarChanged()
+{
+ KToggleAction* showFilterBarAction =
+ static_cast<KToggleAction*>(actionCollection()->action("show_filter_bar"));
+ showFilterBarAction->setChecked(m_activeView->isFilterBarVisible());
+}
+
+void Dolphin::slotSortingChanged(DolphinView::Sorting sorting)
+{
+ KAction* action = 0;
+ switch (sorting) {
+ case DolphinView::SortByName:
+ action = actionCollection()->action("by_name");
+ break;
+ case DolphinView::SortBySize:
+ action = actionCollection()->action("by_size");
+ break;
+ case DolphinView::SortByDate:
+ action = actionCollection()->action("by_date");
+ break;
+ default:
+ break;
+ }
+
+ if (action != 0) {
+ KToggleAction* toggleAction = static_cast<KToggleAction*>(action);
+ toggleAction->setChecked(true);
+ }
+}
+
+void Dolphin::slotSortOrderChanged(Qt::SortOrder order)
+{
+ KToggleAction* descending = static_cast<KToggleAction*>(actionCollection()->action("descending"));
+ const bool sortDescending = (order == Qt::Descending);
+ descending->setChecked(sortDescending);
+}
+
+void Dolphin::slotSelectionChanged()
+{
+ updateEditActions();
+
+ assert(m_view[PrimaryIdx] != 0);
+ int selectedURLsCount = m_view[PrimaryIdx]->selectedURLs().count();
+ if (m_view[SecondaryIdx] != 0) {
+ selectedURLsCount += m_view[SecondaryIdx]->selectedURLs().count();
+ }
+
+ KAction* compareFilesAction = actionCollection()->action("compare_files");
+ compareFilesAction->setEnabled(selectedURLsCount == 2);
+
+ m_activeView->updateStatusBar();
+
+ emit selectionChanged();
+}
+
+void Dolphin::closeEvent(QCloseEvent* event)
+{
+ KConfig* config = kapp->config();
+ config->setGroup("General");
+ config->writeEntry("First Run", false);
+
+ DolphinSettings& settings = DolphinSettings::instance();
+
+ leftSidebarSettings* leftsidebarSettings = settings.leftsidebar();
+ const bool isleftSidebarVisible = (m_leftsidebar != 0);
+ leftsidebarSettings->setVisible(isleftSidebarVisible);
+ if (isleftSidebarVisible) {
+ leftsidebarSettings->setWidth(m_leftsidebar->width());
+ }
+
+ rightSidebarSettings* rightsidebarSettings = settings.rightsidebar();
+ const bool isrightSidebarVisible = (m_rightsidebar != 0);
+ rightsidebarSettings->setVisible(isrightSidebarVisible);
+ if (isrightSidebarVisible) {
+ rightsidebarSettings->setWidth(m_rightsidebar->width());
+ }
+
+ settings.save();
+
+ config->sync();
+ KMainWindow::closeEvent(event);
+}
+
+void Dolphin::saveProperties(KConfig* config)
+{
+ config->setGroup("Primary view");
+ config->writeEntry("URL", m_view[PrimaryIdx]->url().url());
+ config->writeEntry("Editable URL", m_view[PrimaryIdx]->isURLEditable());
+ if (m_view[SecondaryIdx] != 0) {
+ config->setGroup("Secondary view");
+ config->writeEntry("URL", m_view[SecondaryIdx]->url().url());
+ config->writeEntry("Editable URL", m_view[SecondaryIdx]->isURLEditable());
+ }
+}
+
+void Dolphin::readProperties(KConfig* config)
+{
+ config->setGroup("Primary view");
+ m_view[PrimaryIdx]->setURL(config->readEntry("URL"));
+ m_view[PrimaryIdx]->setURLEditable(config->readBoolEntry("Editable URL"));
+ if (config->hasGroup("Secondary view")) {
+ config->setGroup("Secondary view");
+ if (m_view[SecondaryIdx] == 0) {
+ toggleSplitView();
+ }
+ m_view[SecondaryIdx]->setURL(config->readEntry("URL"));
+ m_view[SecondaryIdx]->setURLEditable(config->readBoolEntry("Editable URL"));
+ }
+ else if (m_view[SecondaryIdx] != 0) {
+ toggleSplitView();
+ }
+}
+
+void Dolphin::createFolder()
+{
+ // Parts of the following code have been taken
+ // from the class KonqPopupMenu located in
+ // libqonq/konq_popupmenu.h of Konqueror.
+ // (Copyright (C) 2000 David Faure <[email protected]>,
+ // Copyright (C) 2001 Holger Freyther <[email protected]>)
+
+ clearStatusBar();
+
+ DolphinStatusBar* statusBar = m_activeView->statusBar();
+ const KURL baseURL(m_activeView->url());
+
+ QString name(i18n("New Folder"));
+ if (baseURL.isLocalFile() && QFileInfo(baseURL.path(+1) + name).exists()) {
+ name = KIO::RenameDlg::suggestName(baseURL, i18n("New Folder"));
+ }
+
+ bool ok = false;
+ name = KInputDialog::getText(i18n("New Folder"),
+ i18n("Enter folder name:" ),
+ name,
+ &ok,
+ this);
+
+ if (!ok) {
+ // the user has pressed 'Cancel'
+ return;
+ }
+
+ assert(!name.isEmpty());
+
+ KURL url;
+ if ((name[0] == '/') || (name[0] == '~')) {
+ url.setPath(KShell::tildeExpand(name));
+ }
+ else {
+ name = KIO::encodeFileName(name);
+ url = baseURL;
+ url.addPath(name);
+ }
+ ok = KIO::NetAccess::mkdir(url, this);
+
+ // TODO: provide message type hint
+ if (ok) {
+ statusBar->setMessage(i18n("Created folder %1.").arg(url.path()),
+ DolphinStatusBar::OperationCompleted);
+
+ DolphinCommand command(DolphinCommand::CreateFolder, KURL::List(), url);
+ UndoManager::instance().addCommand(command);
+ }
+ else {
+ // Creating of the folder has been failed. Check whether the creating
+ // has been failed because a folder with the same name exists...
+ if (KIO::NetAccess::exists(url, true, this)) {
+ statusBar->setMessage(i18n("A folder named %1 already exists.").arg(url.path()),
+ DolphinStatusBar::Error);
+ }
+ else {
+ statusBar->setMessage(i18n("Creating of folder %1 failed.").arg(url.path()),
+ DolphinStatusBar::Error);
+ }
+
+ }
+}
+
+void Dolphin::createFile()
+{
+ // Parts of the following code have been taken
+ // from the class KonqPopupMenu located in
+ // libqonq/konq_popupmenu.h of Konqueror.
+ // (Copyright (C) 2000 David Faure <[email protected]>,
+ // Copyright (C) 2001 Holger Freyther <[email protected]>)
+
+ clearStatusBar();
+
+ // TODO: const Entry& entry = m_createFileTemplates[QString(sender->name())];
+ // should be enough. Anyway: the implemantation of [] does a linear search internally too.
+ KSortableValueList<CreateFileEntry, QString>::ConstIterator it = m_createFileTemplates.begin();
+ KSortableValueList<CreateFileEntry, QString>::ConstIterator end = m_createFileTemplates.end();
+
+ const QString senderName(sender()->name());
+ bool found = false;
+ CreateFileEntry entry;
+ while (!found && (it != end)) {
+ if ((*it).index() == senderName) {
+ entry = (*it).value();
+ found = true;
+ }
+ else {
+ ++it;
+ }
+ }
+
+ DolphinStatusBar* statusBar = m_activeView->statusBar();
+ if (!found || !QFile::exists(entry.templatePath)) {
+ statusBar->setMessage(i18n("Could not create file."), DolphinStatusBar::Error);
+ return;
+ }
+
+ // Get the source path of the template which should be copied.
+ // The source path is part of the URL entry of the desktop file.
+ const int pos = entry.templatePath.findRev('/');
+ QString sourcePath(entry.templatePath.left(pos + 1));
+ sourcePath += KDesktopFile(entry.templatePath, true).readPathEntry("URL");
+
+ QString name(i18n(entry.name));
+ // Most entry names end with "..." (e. g. "HTML File..."), which is ok for
+ // menus but no good choice for a new file name -> remove the dots...
+ name.replace("...", QString::null);
+
+ // add the file extension to the name
+ name.append(sourcePath.right(sourcePath.length() - sourcePath.findRev('.')));
+
+ // Check whether a file with the current name already exists. If yes suggest automatically
+ // a unique file name (e. g. "HTML File" will be replaced by "HTML File_1").
+ const KURL viewURL(m_activeView->url());
+ const bool fileExists = viewURL.isLocalFile() &&
+ QFileInfo(viewURL.path(+1) + KIO::encodeFileName(name)).exists();
+ if (fileExists) {
+ name = KIO::RenameDlg::suggestName(viewURL, name);
+ }
+
+ // let the user change the suggested file name
+ bool ok = false;
+ name = KInputDialog::getText(entry.name,
+ entry.comment,
+ name,
+ &ok,
+ this);
+ if (!ok) {
+ // the user has pressed 'Cancel'
+ return;
+ }
+
+ // before copying the template to the destination path check whether a file
+ // with the given name already exists
+ const QString destPath(viewURL.prettyURL() + "/" + KIO::encodeFileName(name));
+ const KURL destURL(destPath);
+ if (KIO::NetAccess::exists(destURL, false, this)) {
+ statusBar->setMessage(i18n("A file named %1 already exists.").arg(name),
+ DolphinStatusBar::Error);
+ return;
+ }
+
+ // copy the template to the destination path
+ const KURL sourceURL(sourcePath);
+ KIO::CopyJob* job = KIO::copyAs(sourceURL, destURL);
+ job->setDefaultPermissions(true);
+ if (KIO::NetAccess::synchronousRun(job, this)) {
+ statusBar->setMessage(i18n("Created file %1.").arg(name),
+ DolphinStatusBar::OperationCompleted);
+
+ KURL::List list;
+ list.append(sourceURL);
+ DolphinCommand command(DolphinCommand::CreateFile, list, destURL);
+ UndoManager::instance().addCommand(command);
+
+ }
+ else {
+ statusBar->setMessage(i18n("Creating of file %1 failed.").arg(name),
+ DolphinStatusBar::Error);
+ }
+}
+
+void Dolphin::rename()
+{
+ clearStatusBar();
+ m_activeView->renameSelectedItems();
+}
+
+void Dolphin::moveToTrash()
+{
+ clearStatusBar();
+ KURL::List selectedURLs = m_activeView->selectedURLs();
+ KIO::Job* job = KIO::trash(selectedURLs);
+ addPendingUndoJob(job, DolphinCommand::Trash, selectedURLs, m_activeView->url());
+}
+
+void Dolphin::deleteItems()
+{
+ clearStatusBar();
+
+ KURL::List list = m_activeView->selectedURLs();
+ const uint itemCount = list.count();
+ assert(itemCount >= 1);
+
+ QString text;
+ if (itemCount > 1) {
+ text = i18n("Do you really want to delete the %1 selected items?").arg(itemCount);
+ }
+ else {
+ const KURL& url = list.first();
+ text = i18n("Do you really want to delete '%1'?").arg(url.fileName());
+ }
+
+ const bool del = KMessageBox::warningContinueCancel(this,
+ text,
+ QString::null,
+ KGuiItem(i18n("Delete"), SmallIcon("editdelete"))
+ ) == KMessageBox::Continue;
+ if (del) {
+ KIO::Job* job = KIO::del(list);
+ connect(job, SIGNAL(result(KIO::Job*)),
+ this, SLOT(slotHandleJobError(KIO::Job*)));
+ connect(job, SIGNAL(result(KIO::Job*)),
+ this, SLOT(slotDeleteFileFinished(KIO::Job*)));
+ }
+}
+
+void Dolphin::properties()
+{
+ const KFileItemList* sourceList = m_activeView->selectedItems();
+ if (sourceList == 0) {
+ return;
+ }
+
+ KFileItemList list;
+ KFileItemListIterator it(*sourceList);
+ KFileItem* item = 0;
+ while ((item = it.current()) != 0) {
+ list.append(item);
+ ++it;
+ }
+
+ new KPropertiesDialog(list, this);
+}
+
+void Dolphin::quit()
+{
+ close();
+}
+
+void Dolphin::slotHandleJobError(KIO::Job* job)
+{
+ if (job->error() != 0) {
+ m_activeView->statusBar()->setMessage(job->errorString(),
+ DolphinStatusBar::Error);
+ }
+}
+
+void Dolphin::slotDeleteFileFinished(KIO::Job* job)
+{
+ if (job->error() == 0) {
+ m_activeView->statusBar()->setMessage(i18n("Delete operation completed."),
+ DolphinStatusBar::OperationCompleted);
+
+ // TODO: In opposite to the 'Move to Trash' operation in the class KFileIconView
+ // no rearranging of the item position is done when a file has been deleted.
+ // This is bypassed by reloading the view, but it might be worth to investigate
+ // deeper for the root of this issue.
+ m_activeView->reload();
+ }
+}
+
+void Dolphin::slotUndoAvailable(bool available)
+{
+ KAction* undoAction = actionCollection()->action(KStdAction::stdName(KStdAction::Undo));
+ if (undoAction != 0) {
+ undoAction->setEnabled(available);
+ }
+}
+
+void Dolphin::slotUndoTextChanged(const QString& text)
+{
+ KAction* undoAction = actionCollection()->action(KStdAction::stdName(KStdAction::Undo));
+ if (undoAction != 0) {
+ undoAction->setText(text);
+ }
+}
+
+void Dolphin::slotRedoAvailable(bool available)
+{
+ KAction* redoAction = actionCollection()->action(KStdAction::stdName(KStdAction::Redo));
+ if (redoAction != 0) {
+ redoAction->setEnabled(available);
+ }
+}
+
+void Dolphin::slotRedoTextChanged(const QString& text)
+{
+ KAction* redoAction = actionCollection()->action(KStdAction::stdName(KStdAction::Redo));
+ if (redoAction != 0) {
+ redoAction->setText(text);
+ }
+}
+
+void Dolphin::cut()
+{
+ m_clipboardContainsCutData = true;
+ QDragObject* data = new KURLDrag(m_activeView->selectedURLs(),
+ widget());
+ QApplication::clipboard()->setData(data);
+}
+
+void Dolphin::copy()
+{
+ m_clipboardContainsCutData = false;
+ QDragObject* data = new KURLDrag(m_activeView->selectedURLs(),
+ widget());
+ QApplication::clipboard()->setData(data);
+}
+
+void Dolphin::paste()
+{
+ QClipboard* clipboard = QApplication::clipboard();
+ QMimeSource* data = clipboard->data();
+ if (!KURLDrag::canDecode(data)) {
+ return;
+ }
+
+ clearStatusBar();
+
+ KURL::List sourceURLs;
+ KURLDrag::decode(data, sourceURLs);
+
+ // per default the pasting is done into the current URL of the view
+ KURL destURL(m_activeView->url());
+
+ // check whether the pasting should be done into a selected directory
+ KURL::List selectedURLs = m_activeView->selectedURLs();
+ if (selectedURLs.count() == 1) {
+ const KFileItem fileItem(S_IFDIR,
+ KFileItem::Unknown,
+ selectedURLs.first(),
+ true);
+ if (fileItem.isDir()) {
+ // only one item is selected which is a directory, hence paste
+ // into this directory
+ destURL = selectedURLs.first();
+ }
+ }
+
+
+ updateViewProperties(sourceURLs);
+ if (m_clipboardContainsCutData) {
+ moveURLs(sourceURLs, destURL);
+ m_clipboardContainsCutData = false;
+ clipboard->clear();
+ }
+ else {
+ copyURLs(sourceURLs, destURL);
+ }
+}
+
+void Dolphin::updatePasteAction()
+{
+ KAction* pasteAction = actionCollection()->action(KStdAction::stdName(KStdAction::Paste));
+ if (pasteAction == 0) {
+ return;
+ }
+
+ QString text(i18n("Paste"));
+ QClipboard* clipboard = QApplication::clipboard();
+ QMimeSource* data = clipboard->data();
+ if (KURLDrag::canDecode(data)) {
+ pasteAction->setEnabled(true);
+
+ KURL::List urls;
+ KURLDrag::decode(data, urls);
+ const int count = urls.count();
+ if (count == 1) {
+ pasteAction->setText(i18n("Paste 1 File"));
+ }
+ else {
+ pasteAction->setText(i18n("Paste %1 Files").arg(count));
+ }
+ }
+ else {
+ pasteAction->setEnabled(false);
+ pasteAction->setText(i18n("Paste"));
+ }
+
+ if (pasteAction->isEnabled()) {
+ KURL::List urls = m_activeView->selectedURLs();
+ const uint count = urls.count();
+ if (count > 1) {
+ // pasting should not be allowed when more than one file
+ // is selected
+ pasteAction->setEnabled(false);
+ }
+ else if (count == 1) {
+ // Only one file is selected. Pasting is only allowed if this
+ // file is a directory.
+ const KFileItem fileItem(S_IFDIR,
+ KFileItem::Unknown,
+ urls.first(),
+ true);
+ pasteAction->setEnabled(fileItem.isDir());
+ }
+ }
+}
+
+void Dolphin::selectAll()
+{
+ clearStatusBar();
+ m_activeView->selectAll();
+}
+
+void Dolphin::invertSelection()
+{
+ clearStatusBar();
+ m_activeView->invertSelection();
+}
+void Dolphin::setIconsView()
+{
+ m_activeView->setMode(DolphinView::IconsView);
+}
+
+void Dolphin::setDetailsView()
+{
+ m_activeView->setMode(DolphinView::DetailsView);
+}
+
+void Dolphin::setPreviewsView()
+{
+ m_activeView->setMode(DolphinView::PreviewsView);
+}
+
+void Dolphin::sortByName()
+{
+ m_activeView->setSorting(DolphinView::SortByName);
+}
+
+void Dolphin::sortBySize()
+{
+ m_activeView->setSorting(DolphinView::SortBySize);
+}
+
+void Dolphin::sortByDate()
+{
+ m_activeView->setSorting(DolphinView::SortByDate);
+}
+
+void Dolphin::toggleSortOrder()
+{
+ const Qt::SortOrder order = (m_activeView->sortOrder() == Qt::Ascending) ?
+ Qt::Descending :
+ Qt::Ascending;
+ m_activeView->setSortOrder(order);
+}
+
+void Dolphin::toggleSplitView()
+{
+ if (m_view[SecondaryIdx] == 0) {
+ const int newWidth = (m_view[PrimaryIdx]->width() - m_splitter->handleWidth()) / 2;
+
+ // create a secondary view
+ m_view[SecondaryIdx] = new DolphinView(m_splitter,
+ m_view[PrimaryIdx]->url(),
+ m_view[PrimaryIdx]->mode(),
+ m_view[PrimaryIdx]->isShowHiddenFilesEnabled());
+
+ QValueList<int> list = m_splitter->sizes();
+ assert(!list.isEmpty());
+ list.pop_back();
+ list.append(newWidth);
+ list.append(newWidth);
+ m_splitter->setSizes(list);
+ m_view[SecondaryIdx]->show();
+ if(m_rightsidebar != 0){
+ closerightSidebar();
+ openrightSidebar();
+ }
+ }
+ else {
+ // remove secondary view
+ if (m_activeView == m_view[PrimaryIdx]) {
+ m_view[SecondaryIdx]->close();
+ m_view[SecondaryIdx]->deleteLater();
+ m_view[SecondaryIdx] = 0;
+ setActiveView(m_view[PrimaryIdx]);
+ }
+ else {
+ // The secondary view is active, hence from the users point of view
+ // the content of the secondary view should be moved to the primary view.
+ // From an implementation point of view it is more efficient to close
+ // the primary view and exchange the internal pointers afterwards.
+ m_view[PrimaryIdx]->close();
+ m_view[PrimaryIdx]->deleteLater();
+ m_view[PrimaryIdx] = m_view[SecondaryIdx];
+ m_view[SecondaryIdx] = 0;
+ setActiveView(m_view[PrimaryIdx]);
+ }
+ }
+}
+
+void Dolphin::reloadView()
+{
+ clearStatusBar();
+ m_activeView->reload();
+}
+
+void Dolphin::stopLoading()
+{
+}
+
+void Dolphin::showHiddenFiles()
+{
+ clearStatusBar();
+
+ const KToggleAction* showHiddenFilesAction =
+ static_cast<KToggleAction*>(actionCollection()->action("show_hidden_files"));
+ const bool show = showHiddenFilesAction->isChecked();
+ m_activeView->setShowHiddenFilesEnabled(show);
+}
+
+void Dolphin::showFilterBar()
+{
+ const KToggleAction* showFilterBarAction =
+ static_cast<KToggleAction*>(actionCollection()->action("show_filter_bar"));
+ const bool show = showFilterBarAction->isChecked();
+ m_activeView->slotShowFilterBar(show);
+}
+
+void Dolphin::zoomIn()
+{
+ m_activeView->zoomIn();
+ updateViewActions();
+}
+
+void Dolphin::zoomOut()
+{
+ m_activeView->zoomOut();
+ updateViewActions();
+}
+
+void Dolphin::editLocation()
+{
+ clearStatusBar();
+ m_activeView->editURL();
+}
+
+void Dolphin::browse()
+{
+ clearStatusBar();
+ m_activeView->setURLEditable(false);
+}
+
+void Dolphin::adjustViewProperties()
+{
+ clearStatusBar();
+ ViewPropertiesDialog dlg(m_activeView);
+ dlg.exec();
+}
+
+void Dolphin::goBack()
+{
+ clearStatusBar();
+ m_activeView->goBack();
+}
+
+void Dolphin::goForward()
+{
+ clearStatusBar();
+ m_activeView->goForward();
+}
+
+void Dolphin::goUp()
+{
+ clearStatusBar();
+ m_activeView->goUp();
+}
+
+void Dolphin::goHome()
+{
+ clearStatusBar();
+ m_activeView->goHome();
+}
+
+void Dolphin::openTerminal()
+{
+ QString command("konsole --workdir \"");
+ command.append(m_activeView->url().path());
+ command.append('\"');
+
+ KRun::runCommand(command, "Konsole", "konsole");
+}
+
+void Dolphin::findFile()
+{
+ KRun::run("kfind", m_activeView->url());
+}
+
+void Dolphin::compareFiles()
+{
+ // The method is only invoked if exactly 2 files have
+ // been selected. The selected files may be:
+ // - both in the primary view
+ // - both in the secondary view
+ // - one in the primary view and the other in the secondary
+ // view
+ assert(m_view[PrimaryIdx] != 0);
+
+ KURL urlA;
+ KURL urlB;
+ KURL::List urls = m_view[PrimaryIdx]->selectedURLs();
+
+ switch (urls.count()) {
+ case 0: {
+ assert(m_view[SecondaryIdx] != 0);
+ urls = m_view[SecondaryIdx]->selectedURLs();
+ assert(urls.count() == 2);
+ urlA = urls[0];
+ urlB = urls[1];
+ break;
+ }
+
+ case 1: {
+ urlA = urls[0];
+ assert(m_view[SecondaryIdx] != 0);
+ urls = m_view[SecondaryIdx]->selectedURLs();
+ assert(urls.count() == 1);
+ urlB = urls[0];
+ break;
+ }
+
+ case 2: {
+ urlA = urls[0];
+ urlB = urls[1];
+ break;
+ }
+
+ default: {
+ // may not happen: compareFiles may only get invoked if 2
+ // files are selected
+ assert(false);
+ }
+ }
+
+ QString command("kompare -c \"");
+ command.append(urlA.prettyURL());
+ command.append("\" \"");
+ command.append(urlB.prettyURL());
+ command.append('\"');
+ KRun::runCommand(command, "Kompare", "kompare");
+
+}
+
+void Dolphin::editSettings()
+{
+ // TODO: make a static method for opening the settings dialog
+ DolphinSettingsDialog dlg;
+ dlg.exec();
+}
+
+void Dolphin::addUndoOperation(KIO::Job* job)
+{
+ if (job->error() != 0) {
+ slotHandleJobError(job);
+ }
+ else {
+ const int id = job->progressId();
+
+ // set iterator to the executed command with the current id...
+ QValueList<UndoInfo>::Iterator it = m_pendingUndoJobs.begin();
+ const QValueList<UndoInfo>::Iterator end = m_pendingUndoJobs.end();
+ bool found = false;
+ while (!found && (it != end)) {
+ if ((*it).id == id) {
+ found = true;
+ }
+ else {
+ ++it;
+ }
+ }
+
+ if (found) {
+ DolphinCommand command = (*it).command;
+ if (command.type() == DolphinCommand::Trash) {
+ // To be able to perform an undo for the 'Move to Trash' operation
+ // all source URLs must be updated with the trash URL. E. g. when moving
+ // a file "test.txt" and a second file "test.txt" to the trash,
+ // then the filenames in the trash are "0-test.txt" and "1-test.txt".
+ QMap<QString, QString> metaData = job->metaData();
+ KURL::List newSourceURLs;
+
+ KURL::List sourceURLs = command.source();
+ KURL::List::Iterator sourceIt = sourceURLs.begin();
+ const KURL::List::Iterator sourceEnd = sourceURLs.end();
+
+ while (sourceIt != sourceEnd) {
+ QMap<QString, QString>::ConstIterator metaIt = metaData.find("trashURL-" + (*sourceIt).path());
+ if (metaIt != metaData.end()) {
+ newSourceURLs.append(KURL(metaIt.data()));
+ }
+ ++sourceIt;
+ }
+ command.setSource(newSourceURLs);
+ }
+
+ UndoManager::instance().addCommand(command);
+ m_pendingUndoJobs.erase(it);
+
+ DolphinStatusBar* statusBar = m_activeView->statusBar();
+ switch (command.type()) {
+ case DolphinCommand::Copy:
+ statusBar->setMessage(i18n("Copy operation completed."),
+ DolphinStatusBar::OperationCompleted);
+ break;
+ case DolphinCommand::Move:
+ statusBar->setMessage(i18n("Move operation completed."),
+ DolphinStatusBar::OperationCompleted);
+ break;
+ case DolphinCommand::Trash:
+ statusBar->setMessage(i18n("Move to trash operation completed."),
+ DolphinStatusBar::OperationCompleted);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+Dolphin::Dolphin() :
+ KMainWindow(0, "D3lphin"),
+ m_splitter(0),
+ m_leftsidebar(0),
+ m_rightsidebar(0),
+ m_activeView(0),
+ m_clipboardContainsCutData(false)
+{
+ m_view[PrimaryIdx] = 0;
+ m_view[SecondaryIdx] = 0;
+
+ m_fileGroupActions.setAutoDelete(true);
+
+ // TODO: the following members are not used yet. See documentation
+ // of Dolphin::linkGroupActions() and Dolphin::linkToDeviceActions()
+ // in the header file for details.
+ //m_linkGroupActions.setAutoDelete(true);
+ //m_linkToDeviceActions.setAutoDelete(true);
+}
+
+void Dolphin::init()
+{
+ // Check whether Dolphin runs the first time. If yes then
+ // a proper default window size is given at the end of Dolphin::init().
+ KConfig* config = kapp->config();
+ config->setGroup("General");
+ const bool firstRun = config->readBoolEntry("First Run", true);
+
+ setAcceptDrops(true);
+
+ m_splitter = new QSplitter(this);
+
+ DolphinSettings& settings = DolphinSettings::instance();
+
+ KBookmarkManager* manager = settings.bookmarkManager();
+ assert(manager != 0);
+ KBookmarkGroup root = manager->root();
+ if (root.first().isNull()) {
+ root.addBookmark(manager, i18n("Home"), settings.homeURL(), "folder_home");
+ root.addBookmark(manager, i18n("System"), KURL("system:/"), "system");
+ root.addBookmark(manager, i18n("Storage Media"), KURL("system:/media"), "blockdevice");
+ root.addBookmark(manager, i18n("Network"), KURL("remote:/"), "network_local");
+ root.addBookmark(manager, i18n("Users' Folders"), KURL("system:/users"), "folder_home2");
+ root.addBookmark(manager, i18n("Root"), KURL("/"), "folder_red");
+ root.addBookmark(manager, i18n("Trash"), KURL("trash:/"), "trashcan_full");
+ }
+
+ const KURL& homeURL = root.first().url();
+ setCaption(homeURL.fileName());
+ ViewProperties props(homeURL);
+ m_view[PrimaryIdx] = new DolphinView(m_splitter,
+ homeURL,
+ props.viewMode(),
+ props.isShowHiddenFilesEnabled());
+
+ m_activeView = m_view[PrimaryIdx];
+
+ setCentralWidget(m_splitter);
+
+ // open sidebars
+ leftSidebarSettings* leftsidebarSettings = settings.leftsidebar();
+ assert(leftsidebarSettings != 0);
+ if (leftsidebarSettings->isVisible()) {
+ openleftSidebar();
+ }
+
+ rightSidebarSettings* rightsidebarSettings = settings.rightsidebar();
+ assert(rightsidebarSettings != 0);
+ if (rightsidebarSettings->isVisible()) {
+ openrightSidebar();
+ }
+
+ setupActions();
+ setupGUI(Keys|Save|Create|ToolBar);
+ createGUI(0, false);
+
+ stateChanged("new_file");
+ setAutoSaveSettings();
+
+ QClipboard* clipboard = QApplication::clipboard();
+ connect(clipboard, SIGNAL(dataChanged()),
+ this, SLOT(updatePasteAction()));
+ updatePasteAction();
+ updateGoActions();
+
+ setupCreateNewMenuActions();
+
+ loadSettings();
+
+ if (firstRun) {
+ // assure a proper default size if Dolphin runs the first time
+ resize(640, 480);
+ }
+}
+
+void Dolphin::loadSettings()
+{
+ DolphinSettings& settings = DolphinSettings::instance();
+
+ KToggleAction* splitAction = static_cast<KToggleAction*>(actionCollection()->action("split_view"));
+ if (settings.isViewSplit()) {
+ splitAction->setChecked(true);
+ toggleSplitView();
+ }
+
+ updateViewActions();
+}
+
+void Dolphin::setupActions()
+{
+ // setup 'File' menu
+ KAction* createFolder = new KAction(i18n("Folder..."), "Ctrl+N",
+ this, SLOT(createFolder()),
+ actionCollection(), "create_folder");
+ createFolder->setIcon("folder");
+
+ new KAction(i18n("Rename"), KKey(Key_F2),
+ this, SLOT(rename()),
+ actionCollection(), "rename");
+
+ KAction* moveToTrashAction = new KAction(i18n("Move to Trash"), KKey(Key_Delete),
+ this, SLOT(moveToTrash()),
+ actionCollection(), "move_to_trash");
+ moveToTrashAction->setIcon("edittrash");
+
+ KAction* deleteAction = new KAction(i18n("Delete"), "Shift+Delete",
+ this, SLOT(deleteItems()),
+ actionCollection(), "delete");
+ deleteAction->setIcon("editdelete");
+
+ new KAction(i18n("Propert&ies"), "Alt+Return",
+ this, SLOT(properties()),
+ actionCollection(), "properties");
+
+ KStdAction::quit(this, SLOT(quit()), actionCollection());
+
+ // setup 'Edit' menu
+ UndoManager& undoManager = UndoManager::instance();
+ KStdAction::undo(&undoManager,
+ SLOT(undo()),
+ actionCollection());
+ connect(&undoManager, SIGNAL(undoAvailable(bool)),
+ this, SLOT(slotUndoAvailable(bool)));
+ connect(&undoManager, SIGNAL(undoTextChanged(const QString&)),
+ this, SLOT(slotUndoTextChanged(const QString&)));
+
+ KStdAction::redo(&undoManager,
+ SLOT(redo()),
+ actionCollection());
+ connect(&undoManager, SIGNAL(redoAvailable(bool)),
+ this, SLOT(slotRedoAvailable(bool)));
+ connect(&undoManager, SIGNAL(redoTextChanged(const QString&)),
+ this, SLOT(slotRedoTextChanged(const QString&)));
+
+ KStdAction::cut(this, SLOT(cut()), actionCollection());
+ KStdAction::copy(this, SLOT(copy()), actionCollection());
+ KStdAction::paste(this, SLOT(paste()), actionCollection());
+
+ new KAction(i18n("Select All"), "Ctrl+A",
+ this, SLOT(selectAll()),
+ actionCollection(), "select_all");
+
+ new KAction(i18n("Invert Selection"), "Ctrl+Shift+A",
+ this, SLOT(invertSelection()),
+ actionCollection(), "invert_selection");
+
+ // setup 'View' menu
+ KStdAction::zoomIn(this,
+ SLOT(zoomIn()),
+ actionCollection());
+
+ KStdAction::zoomOut(this,
+ SLOT(zoomOut()),
+ actionCollection());
+
+ KRadioAction* iconsView = new KRadioAction(i18n("Icons"), "Ctrl+1",
+ this, SLOT(setIconsView()),
+ actionCollection(), "icons");
+ iconsView->setExclusiveGroup("view_mode");
+ iconsView->setIcon("view_icon");
+
+ KRadioAction* detailsView = new KRadioAction(i18n("Details"), "Ctrl+2",
+ this, SLOT(setDetailsView()),
+ actionCollection(), "details");
+ detailsView->setExclusiveGroup("view_mode");
+ detailsView->setIcon("view_text");
+
+ KRadioAction* previewsView = new KRadioAction(i18n("Previews"), "Ctrl+3",
+ this, SLOT(setPreviewsView()),
+ actionCollection(), "previews");
+ previewsView->setExclusiveGroup("view_mode");
+ previewsView->setIcon("gvdirpart");
+
+ KRadioAction* sortByName = new KRadioAction(i18n("By Name"), 0,
+ this, SLOT(sortByName()),
+ actionCollection(), "by_name");
+ sortByName->setExclusiveGroup("sort");
+
+ KRadioAction* sortBySize = new KRadioAction(i18n("By Size"), 0,
+ this, SLOT(sortBySize()),
+ actionCollection(), "by_size");
+ sortBySize->setExclusiveGroup("sort");
+
+ KRadioAction* sortByDate = new KRadioAction(i18n("By Date"), 0,
+ this, SLOT(sortByDate()),
+ actionCollection(), "by_date");
+ sortByDate->setExclusiveGroup("sort");
+
+ new KToggleAction(i18n("Descending"), 0, this, SLOT(toggleSortOrder()),
+ actionCollection(), "descending");
+
+ new KToggleAction(i18n("Show Hidden Files"), "Alt+.",
+ this, SLOT(showHiddenFiles()),
+ actionCollection(), "show_hidden_files");
+
+ KToggleAction* splitAction = new KToggleAction(i18n("Split View"), "F10",
+ this, SLOT(toggleSplitView()),
+ actionCollection(), "split_view");
+ splitAction->setIcon("view_left_right");
+
+ KAction* reloadAction = new KAction(i18n("Reload"), "F5",
+ this, SLOT(reloadView()),
+ actionCollection(), "reload");
+ reloadAction->setIcon("reload");
+
+ KAction* stopAction = new KAction(i18n("Stop"), 0,
+ this, SLOT(stopLoading()),
+ actionCollection(), "stop");
+ stopAction->setIcon("stop");
+
+ new KAction(i18n("Edit Location"), "Ctrl+L",
+ this, SLOT(editLocation()),
+ actionCollection(), "edit_location");
+
+ new KAction(i18n("Browse"), "Ctrl+B",
+ this, SLOT(browse()),
+ actionCollection(), "browse");
+
+ new KToggleAction(i18n("Left Sidebar"), "F8",
+ this, SLOT(toggleleftSidebar()),
+ actionCollection(), "leftsidebar");
+
+ new KToggleAction(i18n("Right Sidebar"), "F9",
+ this, SLOT(togglerightSidebar()),
+ actionCollection(), "rightsidebar");
+
+ new KAction(i18n("Adjust View Properties..."), 0,
+ this, SLOT(adjustViewProperties()),
+ actionCollection(), "view_properties");
+
+ // setup 'Go' menu
+ KStdAction::back(this, SLOT(goBack()), actionCollection());
+ KStdAction::forward(this, SLOT(goForward()), actionCollection());
+ KStdAction::up(this, SLOT(goUp()), actionCollection());
+ KStdAction::home(this, SLOT(goHome()), actionCollection());
+
+ // setup 'Tools' menu
+ KAction* openTerminalAction = new KAction(i18n("Open Terminal"), "F4",
+ this, SLOT(openTerminal()),
+ actionCollection(), "open_terminal");
+ openTerminalAction->setIcon("konsole");
+
+ KAction* findFileAction = new KAction(i18n("Find File..."), "Ctrl+F",
+ this, SLOT(findFile()),
+ actionCollection(), "find_file");
+ findFileAction->setIcon("filefind");
+
+ new KToggleAction(i18n("Show Filter Bar"), "filter", "/",
+ this, SLOT(showFilterBar()),
+ actionCollection(), "show_filter_bar");
+
+ KAction* compareFilesAction = new KAction(i18n("Compare Files"), 0,
+ this, SLOT(compareFiles()),
+ actionCollection(), "compare_files");
+ compareFilesAction->setIcon("kompare");
+ compareFilesAction->setEnabled(false);
+
+ // setup 'Settings' menu
+ KStdAction::preferences(this, SLOT(editSettings()), actionCollection());
+}
+
+void Dolphin::setupCreateNewMenuActions()
+{
+ // Parts of the following code have been taken
+ // from the class KNewMenu located in
+ // libqonq/knewmenu.h of Konqueror.
+ // Copyright (C) 1998, 1999 David Faure <[email protected]>
+ // 2003 Sven Leiber <[email protected]>
+
+ QStringList files = actionCollection()->instance()->dirs()->findAllResources("templates");
+ for (QStringList::Iterator it = files.begin() ; it != files.end(); ++it) {
+ if ((*it)[0] != '.' ) {
+ KSimpleConfig config(*it, true);
+ config.setDesktopGroup();
+
+ // tricky solution to ensure that TextFile is at the beginning
+ // because this filetype is the most used (according kde-core discussion)
+ const QString name(config.readEntry("Name"));
+ QString key(name);
+
+ const QString path(config.readPathEntry("URL"));
+ if (!path.endsWith("emptydir")) {
+ if (path.endsWith("TextFile.txt")) {
+ key = "1" + key;
+ }
+ else if (!KDesktopFile::isDesktopFile(path)) {
+ key = "2" + key;
+ }
+ else if (path.endsWith("URL.desktop")){
+ key = "3" + key;
+ }
+ else if (path.endsWith("Program.desktop")){
+ key = "4" + key;
+ }
+ else {
+ key = "5";
+ }
+
+ const QString icon(config.readEntry("Icon"));
+ const QString comment(config.readEntry("Comment"));
+ const QString type(config.readEntry("Type"));
+
+ const QString filePath(*it);
+
+
+ if (type == "Link") {
+ CreateFileEntry entry;
+ entry.name = name;
+ entry.icon = icon;
+ entry.comment = comment;
+ entry.templatePath = filePath;
+ m_createFileTemplates.insert(key, entry);
+ }
+ }
+ }
+ }
+ m_createFileTemplates.sort();
+
+ unplugActionList("create_actions");
+ KSortableValueList<CreateFileEntry, QString>::ConstIterator it = m_createFileTemplates.begin();
+ KSortableValueList<CreateFileEntry, QString>::ConstIterator end = m_createFileTemplates.end();
+ while (it != end) {
+ CreateFileEntry entry = (*it).value();
+ KAction* action = new KAction(entry.name);
+ action->setIcon(entry.icon);
+ action->setName((*it).index());
+ connect(action, SIGNAL(activated()),
+ this, SLOT(createFile()));
+
+ const QChar section = ((*it).index()[0]);
+ switch (section) {
+ case '1':
+ case '2': {
+ m_fileGroupActions.append(action);
+ break;
+ }
+
+ case '3':
+ case '4': {
+ // TODO: not used yet. See documentation of Dolphin::linkGroupActions()
+ // and Dolphin::linkToDeviceActions() in the header file for details.
+ //m_linkGroupActions.append(action);
+ break;
+ }
+
+ case '5': {
+ // TODO: not used yet. See documentation of Dolphin::linkGroupActions()
+ // and Dolphin::linkToDeviceActions() in the header file for details.
+ //m_linkToDeviceActions.append(action);
+ break;
+ }
+ default:
+ break;
+ }
+ ++it;
+ }
+
+ plugActionList("create_file_group", m_fileGroupActions);
+ //plugActionList("create_link_group", m_linkGroupActions);
+ //plugActionList("link_to_device", m_linkToDeviceActions);
+}
+
+void Dolphin::updateHistory()
+{
+ int index = 0;
+ const QValueList<URLNavigator::HistoryElem> list = m_activeView->urlHistory(index);
+
+ KAction* backAction = actionCollection()->action("go_back");
+ if (backAction != 0) {
+ backAction->setEnabled(index < static_cast<int>(list.count()) - 1);
+ }
+
+ KAction* forwardAction = actionCollection()->action("go_forward");
+ if (forwardAction != 0) {
+ forwardAction->setEnabled(index > 0);
+ }
+}
+
+void Dolphin::updateEditActions()
+{
+ const KFileItemList* list = m_activeView->selectedItems();
+ if ((list == 0) || (*list).isEmpty()) {
+ stateChanged("has_no_selection");
+ }
+ else {
+ stateChanged("has_selection");
+
+ KAction* renameAction = actionCollection()->action("rename");
+ if (renameAction != 0) {
+ renameAction->setEnabled(list->count() >= 1);
+ }
+
+ bool enableMoveToTrash = true;
+
+ KFileItemListIterator it(*list);
+ KFileItem* item = 0;
+ while ((item = it.current()) != 0) {
+ const KURL& url = item->url();
+ // only enable the 'Move to Trash' action for local files
+ if (!url.isLocalFile()) {
+ enableMoveToTrash = false;
+ }
+ ++it;
+ }
+
+ KAction* moveToTrashAction = actionCollection()->action("move_to_trash");
+ moveToTrashAction->setEnabled(enableMoveToTrash);
+ }
+ updatePasteAction();
+}
+
+void Dolphin::updateViewActions()
+{
+ KAction* zoomInAction = actionCollection()->action(KStdAction::stdName(KStdAction::ZoomIn));
+ if (zoomInAction != 0) {
+ zoomInAction->setEnabled(m_activeView->isZoomInPossible());
+ }
+
+ KAction* zoomOutAction = actionCollection()->action(KStdAction::stdName(KStdAction::ZoomOut));
+ if (zoomOutAction != 0) {
+ zoomOutAction->setEnabled(m_activeView->isZoomOutPossible());
+ }
+
+ KAction* action = 0;
+ switch (m_activeView->mode()) {
+ case DolphinView::IconsView:
+ action = actionCollection()->action("icons");
+ break;
+ case DolphinView::DetailsView:
+ action = actionCollection()->action("details");
+ break;
+ case DolphinView::PreviewsView:
+ action = actionCollection()->action("previews");
+ break;
+ default:
+ break;
+ }
+
+ if (action != 0) {
+ KToggleAction* toggleAction = static_cast<KToggleAction*>(action);
+ toggleAction->setChecked(true);
+ }
+
+ slotSortingChanged(m_activeView->sorting());
+ slotSortOrderChanged(m_activeView->sortOrder());
+
+ KToggleAction* showFilterBarAction =
+ static_cast<KToggleAction*>(actionCollection()->action("show_filter_bar"));
+ showFilterBarAction->setChecked(m_activeView->isFilterBarVisible());
+
+ KToggleAction* showHiddenFilesAction =
+ static_cast<KToggleAction*>(actionCollection()->action("show_hidden_files"));
+ showHiddenFilesAction->setChecked(m_activeView->isShowHiddenFilesEnabled());
+
+ KToggleAction* splitAction = static_cast<KToggleAction*>(actionCollection()->action("split_view"));
+ splitAction->setChecked(m_view[SecondaryIdx] != 0);
+
+ KToggleAction* leftsidebarAction = static_cast<KToggleAction*>(actionCollection()->action("leftsidebar"));
+ leftsidebarAction->setChecked(m_leftsidebar != 0);
+
+ KToggleAction* rightsidebarAction = static_cast<KToggleAction*>(actionCollection()->action("rightsidebar"));
+ rightsidebarAction->setChecked(m_rightsidebar != 0);
+}
+
+void Dolphin::updateGoActions()
+{
+ KAction* goUpAction = actionCollection()->action(KStdAction::stdName(KStdAction::Up));
+ const KURL& currentURL = m_activeView->url();
+ goUpAction->setEnabled(currentURL.upURL() != currentURL);
+}
+
+void Dolphin::updateViewProperties(const KURL::List& urls)
+{
+ if (urls.isEmpty()) {
+ return;
+ }
+
+ // Updating the view properties might take up to several seconds
+ // when dragging several thousand URLs. Writing a KIO slave for this
+ // use case is not worth the effort, but at least the main widget
+ // must be disabled and a progress should be shown.
+ ProgressIndicator progressIndicator(i18n("Updating view properties..."),
+ QString::null,
+ urls.count());
+
+ KURL::List::ConstIterator end = urls.end();
+ for(KURL::List::ConstIterator it = urls.begin(); it != end; ++it) {
+ progressIndicator.execOperation();
+
+ ViewProperties props(*it);
+ props.save();
+ }
+}
+
+void Dolphin::copyURLs(const KURL::List& source, const KURL& dest)
+{
+ KIO::Job* job = KIO::copy(source, dest);
+ addPendingUndoJob(job, DolphinCommand::Copy, source, dest);
+}
+
+void Dolphin::moveURLs(const KURL::List& source, const KURL& dest)
+{
+ KIO::Job* job = KIO::move(source, dest);
+ addPendingUndoJob(job, DolphinCommand::Move, source, dest);
+}
+
+void Dolphin::addPendingUndoJob(KIO::Job* job,
+ DolphinCommand::Type commandType,
+ const KURL::List& source,
+ const KURL& dest)
+{
+ connect(job, SIGNAL(result(KIO::Job*)),
+ this, SLOT(addUndoOperation(KIO::Job*)));
+
+ UndoInfo undoInfo;
+ undoInfo.id = job->progressId();
+ undoInfo.command = DolphinCommand(commandType, source, dest);
+ m_pendingUndoJobs.append(undoInfo);
+}
+
+void Dolphin::clearStatusBar()
+{
+ m_activeView->statusBar()->clear();
+}
+
+void Dolphin::openleftSidebar()
+{
+ if (m_leftsidebar != 0) {
+ // the sidebar is already open
+ return;
+ }
+
+ m_leftsidebar = new leftSidebar(m_splitter);
+ m_leftsidebar->show();
+
+ connect(m_leftsidebar, SIGNAL(urlChanged(const KURL&)),
+ this, SLOT(slotURLChangeRequest(const KURL&)));
+ m_splitter->setCollapsible(m_leftsidebar, false);
+ m_splitter->setResizeMode(m_leftsidebar, QSplitter::KeepSize);
+ m_splitter->moveToFirst(m_leftsidebar);
+
+ leftSidebarSettings* settings = DolphinSettings::instance().leftsidebar();
+ settings->setVisible(true);
+}
+
+void Dolphin::openrightSidebar()
+{
+ if (m_rightsidebar != 0) {
+ // the sidebar is already open
+ return;
+ }
+
+ m_rightsidebar = new rightSidebar(m_splitter);
+ m_rightsidebar->show();
+
+ connect(m_rightsidebar, SIGNAL(urlChanged(const KURL&)),
+ this, SLOT(slotURLChangeRequest(const KURL&)));
+ m_splitter->setCollapsible(m_rightsidebar, false);
+ m_splitter->setResizeMode(m_rightsidebar, QSplitter::KeepSize);
+ m_splitter->moveToLast(m_rightsidebar);
+
+ rightSidebarSettings* settings = DolphinSettings::instance().rightsidebar();
+ settings->setVisible(true);
+}
+
+void Dolphin::closeleftSidebar()
+{
+ if (m_leftsidebar == 0) {
+ // the sidebar has already been closed
+ return;
+ }
+
+ // store width of sidebar and remember that the sidebar has been closed
+ leftSidebarSettings* settings = DolphinSettings::instance().leftsidebar();
+ settings->setVisible(false);
+ settings->setWidth(m_leftsidebar->width());
+
+ m_leftsidebar->deleteLater();
+ m_leftsidebar = 0;
+}
+
+void Dolphin::closerightSidebar()
+{
+ if (m_rightsidebar == 0) {
+ // the sidebar has already been closed
+ return;
+ }
+
+ // store width of sidebar and remember that the sidebar has been closed
+ rightSidebarSettings* settings = DolphinSettings::instance().rightsidebar();
+ settings->setVisible(false);
+ settings->setWidth(m_rightsidebar->width());
+
+ m_rightsidebar->deleteLater();
+ m_rightsidebar = 0;
+}
+
+void Dolphin::toggleleftSidebar()
+{
+ if (m_leftsidebar == 0) {
+ openleftSidebar();
+ }
+ else {
+ closeleftSidebar();
+ }
+
+ KToggleAction* leftsidebarAction = static_cast<KToggleAction*>(actionCollection()->action("leftsidebar"));
+ leftsidebarAction->setChecked(m_leftsidebar != 0);
+}
+
+void Dolphin::togglerightSidebar()
+{
+ if (m_rightsidebar == 0) {
+ openrightSidebar();
+ }
+ else {
+ closerightSidebar();
+ }
+
+ KToggleAction* rightsidebarAction = static_cast<KToggleAction*>(actionCollection()->action("rightsidebar"));
+ rightsidebarAction->setChecked(m_rightsidebar != 0);
+}
+
+#include "dolphin.moc"
diff --git a/src/dolphin.h b/src/dolphin.h
new file mode 100644
index 0000000..bccfbba
--- /dev/null
+++ b/src/dolphin.h
@@ -0,0 +1,456 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz <[email protected]> *
+ * Copyright (C) 2006 by Stefan Monov <[email protected]> *
+ * Copyright (C) 2006 by Cvetoslav Ludmiloff <[email protected]> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef _DOLPHIN_H_
+#define _DOLPHIN_H_
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kapplication.h>
+#include <kmainwindow.h>
+#include <qvaluelist.h>
+#include <qptrlist.h>
+#include <qstring.h>
+#include <ksortablevaluelist.h>
+
+#include "dolphinview.h"
+#include "undomanager.h"
+
+class KPrinter;
+class KURL;
+class QLineEdit;
+class KFileIconView;
+class QHBox;
+class QIconViewItem;
+class QSplitter;
+class KAction;
+class URLNavigator;
+class leftSidebar;
+class rightSidebar;
+
+/**
+ * @short Main window for Dolphin.
+ *
+ * Handles the menus, toolbars and Dolphin views.
+ *
+ * @author Peter Penz <[email protected]>
+*/
+class Dolphin : public KMainWindow
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Returns the instance for the Dolphin main window.
+ */
+ // KXMLGUIClient::instance() already in use :-(
+ static Dolphin& mainWin();
+
+ virtual ~Dolphin();
+
+ /**
+ * Activates the given view, which means that
+ * all menu actions are applied to this view. When
+ * having a split view setup the nonactive view
+ * is usually shown in darker colors.
+ */
+ void setActiveView(DolphinView* view);
+
+ /**
+ * Returns the currently active view. See
+ * Dolphin::setActiveView() for more details.
+ */
+ DolphinView* activeView() const { return m_activeView; }
+
+ /**
+ * Handles the dropping of URLs to the given
+ * destination. A context menu with the options
+ * 'Move Here', 'Copy Here', 'Link Here' and
+ * 'Cancel' is offered to the user.
+ * @param urls List of URLs which have been
+ * dropped.
+ * @param destination Destination URL, where the
+ * list or URLs should be moved,
+ * copied or linked to.
+ */
+ void dropURLs(const KURL::List& urls,
+ const KURL& destination);
+
+ /**
+ * Returns 'true', if the clipboard contains data
+ * which has been cutted by the Cut action (Ctrl + X).
+ */
+ bool clipboardContainsCutData() const { return m_clipboardContainsCutData; }
+
+ /**
+ * Returns the list of actions which are part of the file group
+ * of the 'Create New...' sub menu. Usually the list contains actions
+ * for creating folders, text files, HTML files etc.
+ */
+ const QPtrList<KAction>& fileGroupActions() const { return m_fileGroupActions; }
+ //const QPtrList<KAction>& linkGroupActions() const { return m_linkGroupActions; }
+ //const QPtrList<KAction>& linkToDeviceActions() const { return m_linkToDeviceActions; }
+
+ /**
+ * Refreshs the views of the main window by recreating them dependent from
+ * the given Dolphin settings.
+ */
+ void refreshViews();
+
+signals:
+ /**
+ * Is send if the active view has been changed in
+ * the split view mode.
+ */
+ void activeViewChanged();
+
+ /**
+ * Is send if the selection of the currently active view has
+ * been changed.
+ */
+ void selectionChanged();
+
+public slots:
+ /**
+ * Updates the state of the 'Back' and 'Forward' menu
+ * actions corresponding the the current history.
+ */
+ void slotHistoryChanged();
+
+ /**
+ * Updates the caption of the main window and the state
+ * of all menu actions which depend from a changed URL.
+ */
+ void slotURLChanged(const KURL& url);
+
+ /**
+ * Go to the given URL.
+ */
+ void slotURLChangeRequest(const KURL& url);
+
+ /** Updates the state of all 'View' menu actions. */
+ void slotViewModeChanged();
+
+ /** Updates the state of the 'Show hidden files' menu action. */
+ void slotShowHiddenFilesChanged();
+
+ /** Updates the state of the 'Show filter bar' menu action. */
+ void slotShowFilterBarChanged();
+
+ /** Updates the state of the 'Sort by' actions. */
+ void slotSortingChanged(DolphinView::Sorting sorting);
+
+ /** Updates the state of the 'Sort Ascending/Descending' action. */
+ void slotSortOrderChanged(Qt::SortOrder order);
+
+ /** Updates the state of the 'Edit' menu actions. */
+ void slotSelectionChanged();
+
+protected:
+ /** @see QMainWindow::closeEvent */
+ virtual void closeEvent(QCloseEvent* event);
+
+ /**
+ * This method is called when it is time for the app to save its
+ * properties for session management purposes.
+ */
+ void saveProperties(KConfig*);
+
+ /**
+ * This method is called when this app is restored. The KConfig
+ * object points to the session management config file that was saved
+ * with @ref saveProperties
+ */
+ void readProperties(KConfig*);
+
+private slots:
+ /** Opens an input dialog for creating a new folder. */
+ void createFolder();
+
+ /** Creates a file with the MIME type given by the sender. */
+ void createFile();
+
+ /** Renames the selected item of the active view. */
+ void rename();
+
+ /** Moves the selected items of the active view to the trash. */
+ void moveToTrash();
+
+ /** Deletes the selected items of the active view. */
+ void deleteItems();
+
+ /**
+ * Opens the properties window for the selected items of the
+ * active view. The properties windows shows informations
+ * like name, size and permissions.
+ */
+ void properties();
+
+ /** Stores all settings and quits Dolphin. */
+ void quit();
+
+ /**
+ * Shows the error information of the job \a job
+ * in the status bar.
+ */
+ void slotHandleJobError(KIO::Job* job);
+
+ /**
+ * Indicates in the status bar that the delete operation
+ * of the job \a job has been finished.
+ */
+ void slotDeleteFileFinished(KIO::Job* job);
+
+ /**
+ * Updates the state of the 'Undo' menu action dependent
+ * from the parameter \a available.
+ */
+ void slotUndoAvailable(bool available);
+
+ /** Sets the text of the 'Undo' menu action to \a text. */
+ void slotUndoTextChanged(const QString& text);
+
+ /**
+ * Updates the state of the 'Redo' menu action dependent
+ * from the parameter \a available.
+ */
+ void slotRedoAvailable(bool available);
+
+ /** Sets the text of the 'Redo' menu action to \a text. */
+ void slotRedoTextChanged(const QString& text);
+
+ /**
+ * Copies all selected items to the clipboard and marks
+ * the items as cutted.
+ */
+ void cut();
+
+ /** Copies all selected items to the clipboard. */
+ void copy();
+
+ /** Pastes the clipboard data to the active view. */
+ void paste();
+
+ /**
+ * Updates the text of the paste action dependent from
+ * the number of items which are in the clipboard.
+ */
+ void updatePasteAction();
+
+ /** Selects all items from the active view. */
+ void selectAll();
+
+ /**
+ * Inverts the selection of all items of the active view:
+ * Selected items get nonselected and nonselected items get
+ * selected.
+ */
+ void invertSelection();
+
+ /** The current active view is switched to the icons mode. */
+ void setIconsView();
+
+ /** The current active view is switched to the details mode. */
+ void setDetailsView();
+
+ /** The current active view is switched to the previews mode. */
+ void setPreviewsView();
+
+ /** The sorting of the current view should be done by the name. */
+ void sortByName();
+
+ /** The sorting of the current view should be done by the size. */
+ void sortBySize();
+
+ /** The sorting of the current view should be done by the date. */
+ void sortByDate();
+
+ /** Switches between an ascending and descending sorting order. */
+ void toggleSortOrder();
+
+ /**
+ * Switches between one and two views:
+ * If one view is visible, it will get split into two views.
+ * If already two views are visible, the nonactivated view gets closed.
+ */
+ void toggleSplitView();
+
+ /** Reloads the current active view. */
+ void reloadView();
+
+ /** Stops the loading process for the current active view. */
+ void stopLoading();
+
+ /**
+ * Switches between showing and hiding of hidden marked files dependent
+ * from the current state of the 'Show Hidden Files' menu toggle action.
+ */
+ void showHiddenFiles();
+
+ /**
+ * Switches between showing and hiding of the filter bar dependent
+ * from the current state of the 'Show Filter Bar' menu toggle action.
+ */
+ void showFilterBar();
+
+ /** Increases the size of the current set view mode. */
+ void zoomIn();
+
+ /** Decreases the size of the current set view mode. */
+ void zoomOut();
+
+ /**
+ * Switches to the edit mode of the navigation bar. If the edit mode is
+ * already active, it is assured that the navigation bar get focused.
+ */
+ void editLocation();
+
+ /** Switches to the browse mode of the navigation bar. */
+ void browse();
+
+ /**
+ * Opens the view properties dialog, which allows to modify the properties
+ * of the currently active view.
+ */
+ void adjustViewProperties();
+
+ /** Goes back on step of the URL history. */
+ void goBack();
+
+ /** Goes forward one step of the URL history. */
+ void goForward();
+
+ /** Goes up one hierarchy of the current URL. */
+ void goUp();
+
+ /** Goes to the home URL. */
+ void goHome();
+
+ /** Opens a terminal for the current shown directory. */
+ void openTerminal();
+
+ /** Opens KFind for the current shown directory. */
+ void findFile();
+
+ /** Opens Kompare for 2 selected files. */
+ void compareFiles();
+
+ /** Opens the settings dialog for Dolphin. */
+ void editSettings();
+
+ /**
+ * Adds the undo operation given by \a job
+ * to the UndoManager.
+ */
+ void addUndoOperation(KIO::Job* job);
+
+
+ void toggleleftSidebar();
+ void togglerightSidebar();
+
+ /**
+ * Stores the current sidebar width and closes
+ * the sidebar.
+ */
+ void closeleftSidebar();
+ void closerightSidebar();
+
+private:
+ Dolphin();
+ void init();
+ void loadSettings();
+
+ void setupAccel();
+ void setupActions();
+ void setupCreateNewMenuActions();
+ void updateHistory();
+ void updateEditActions();
+ void updateViewActions();
+ void updateGoActions();
+ void updateViewProperties(const KURL::List& urls);
+ void copyURLs(const KURL::List& source, const KURL& dest);
+ void moveURLs(const KURL::List& source, const KURL& dest);
+ void addPendingUndoJob(KIO::Job* job,
+ DolphinCommand::Type commandType,
+ const KURL::List& source,
+ const KURL& dest);
+ void clearStatusBar();
+ void openleftSidebar();
+ void openrightSidebar();
+
+ QSplitter* m_splitter;
+ leftSidebar* m_leftsidebar;
+ rightSidebar* m_rightsidebar;
+ DolphinView* m_activeView;
+
+ /**
+ * Dolphin supports only one or two views, which
+ * are handled internally as primary and secondary view.
+ */
+ enum ViewIndex
+ {
+ PrimaryIdx = 0,
+ SecondaryIdx = 1
+ };
+ DolphinView* m_view[SecondaryIdx + 1];
+
+ /// If set to true, the clipboard contains data which should be cutted after pasting.
+ bool m_clipboardContainsCutData;
+
+ /**
+ * Asynchronous operations like 'Move' and 'Copy' may only be added as undo
+ * operation after they have been finished successfully. When an asynchronous
+ * operation is started, it is added to a pending undo jobs list in the meantime.
+ * As soon as the job has been finished, the operation is added to the undo mangager.
+ * @see UndoManager
+ * @see Dolphin::addPendingUndoJob
+ * @see Dolphin::addUndoOperation
+ */
+ struct UndoInfo
+ {
+ int id;
+ DolphinCommand command;
+ };
+ QValueList<UndoInfo> m_pendingUndoJobs;
+
+ /** Contains meta information for creating files. */
+ struct CreateFileEntry
+ {
+ QString name;
+ QString filePath;
+ QString templatePath;
+ QString icon;
+ QString comment;
+ };
+
+ QPtrList<KAction> m_fileGroupActions;
+ KSortableValueList<CreateFileEntry,QString> m_createFileTemplates;
+
+ // TODO: not used yet. See documentation of Dolphin::linkGroupActions()
+ // and Dolphin::linkToDeviceActions() in for details.
+ //QPtrList<KAction> m_linkGroupActions;
+ //QPtrList<KAction> m_linkToDeviceActions;
+};
+
+#endif // _DOLPHIN_H_
+
diff --git a/src/dolphin.lsm b/src/dolphin.lsm
new file mode 100644
index 0000000..6733258
--- /dev/null
+++ b/src/dolphin.lsm
@@ -0,0 +1,16 @@
+Begin3
+Title: Dolphin -- Some description
+Version: 0.1
+Entered-date:
+Description:
+Keywords: KDE Qt
+Author: Peter Penz <[email protected]>
+Maintained-by: Peter Penz <[email protected]>
+Home-page:
+Alternate-site:
+Primary-site: ftp://ftp.kde.org/pub/kde/unstable/apps/utils
+ xxxxxx dolphin-0.1.tar.gz
+ xxx dolphin-0.1.lsm
+Platform: Linux. Needs KDE
+Copying-policy: GPL
+End
diff --git a/src/dolphincontextmenu.cpp b/src/dolphincontextmenu.cpp
new file mode 100644
index 0000000..7ac2a56
--- /dev/null
+++ b/src/dolphincontextmenu.cpp
@@ -0,0 +1,494 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz ([email protected]) and *
+ * Cvetoslav Ludmiloff *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "dolphincontextmenu.h"
+
+#include <kactioncollection.h>
+#include <kbookmarkmanager.h>
+#include <kbookmark.h>
+#include <ktrader.h>
+#include <klocale.h>
+#include <krun.h>
+#include <qdir.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <kiconloader.h>
+#include <kaction.h>
+#include <kpropertiesdialog.h>
+#include <kdesktopfile.h>
+#include <assert.h>
+#include <ksortablevaluelist.h>
+#include <kio/netaccess.h>
+#include <konq_operations.h>
+
+#include "dolphin.h"
+#include "dolphinview.h"
+#include "editbookmarkdialog.h"
+#include "dolphinsettings.h"
+
+
+DolphinContextMenu::DolphinContextMenu(DolphinView* parent,
+ KFileItem* fileInfo,
+ const QPoint& pos) :
+ m_dolphinView(parent),
+ m_fileInfo(fileInfo),
+ m_pos(pos)
+{
+}
+
+void DolphinContextMenu::open()
+{
+ if (m_fileInfo == 0) {
+ openViewportContextMenu();
+ }
+ else {
+ openItemContextMenu();
+ }
+}
+
+DolphinContextMenu::~DolphinContextMenu()
+{
+}
+
+void DolphinContextMenu::openViewportContextMenu()
+{
+ // Parts of the following code have been taken
+ // from the class KonqOperations located in
+ // libqonq/konq_operations.h of Konqueror.
+ // (Copyright (C) 2000 David Faure <[email protected]>)
+
+ assert(m_fileInfo == 0);
+ const int propertiesID = 100;
+ const int bookmarkID = 101;
+
+ KPopupMenu* popup = new KPopupMenu(m_dolphinView);
+ Dolphin& dolphin = Dolphin::mainWin();
+
+ // setup 'Create New' menu
+ KPopupMenu* createNewMenu = new KPopupMenu();
+
+ KAction* createFolderAction = dolphin.actionCollection()->action("create_folder");
+ if (createFolderAction != 0) {
+ createFolderAction->plug(createNewMenu);
+ }
+
+ createNewMenu->insertSeparator();
+
+ KAction* action = 0;
+
+ QPtrListIterator<KAction> fileGrouptIt(dolphin.fileGroupActions());
+ while ((action = fileGrouptIt.current()) != 0) {
+ action->plug(createNewMenu);
+ ++fileGrouptIt;
+ }
+
+ // TODO: not used yet. See documentation of Dolphin::linkGroupActions()
+ // and Dolphin::linkToDeviceActions() in the header file for details.
+ //
+ //createNewMenu->insertSeparator();
+ //
+ //QPtrListIterator<KAction> linkGroupIt(dolphin.linkGroupActions());
+ //while ((action = linkGroupIt.current()) != 0) {
+ // action->plug(createNewMenu);
+ // ++linkGroupIt;
+ //}
+ //
+ //KPopupMenu* linkToDeviceMenu = new KPopupMenu();
+ //QPtrListIterator<KAction> linkToDeviceIt(dolphin.linkToDeviceActions());
+ //while ((action = linkToDeviceIt.current()) != 0) {
+ // action->plug(linkToDeviceMenu);
+ // ++linkToDeviceIt;
+ //}
+ //
+ //createNewMenu->insertItem(i18n("Link to Device"), linkToDeviceMenu);
+
+ const KURL& url = dolphin.activeView()->url();
+ if (url.protocol() == "trash")
+ {
+ popup->insertItem(i18n("Empty Deleted Items Folder"), emptyID);
+ }
+ else
+ {
+ popup->insertItem(SmallIcon("filenew"), i18n("Create New"), createNewMenu);
+ }
+ popup->insertSeparator();
+
+ KAction* pasteAction = dolphin.actionCollection()->action(KStdAction::stdName(KStdAction::Paste));
+ pasteAction->plug(popup);
+
+ // setup 'View Mode' menu
+ KPopupMenu* viewModeMenu = new KPopupMenu();
+
+ KAction* iconsMode = dolphin.actionCollection()->action("icons");
+ iconsMode->plug(viewModeMenu);
+
+ KAction* detailsMode = dolphin.actionCollection()->action("details");
+ detailsMode->plug(viewModeMenu);
+
+ KAction* previewsMode = dolphin.actionCollection()->action("previews");
+ previewsMode->plug(viewModeMenu);
+
+ popup->insertItem(i18n("View Mode"), viewModeMenu);
+ popup->insertSeparator();
+
+ popup->insertItem(i18n("Bookmark this folder"), bookmarkID);
+ popup->insertSeparator();
+
+ popup->insertItem(i18n("Properties..."), propertiesID);
+
+ int id = popup->exec(m_pos);
+ if (id == emptyID) {
+ KonqOperations::emptyTrash();
+ }
+ else if (id == propertiesID) {
+ new KPropertiesDialog(dolphin.activeView()->url());
+ }
+ else if (id == bookmarkID) {
+ const KURL& url = dolphin.activeView()->url();
+ KBookmark bookmark = EditBookmarkDialog::getBookmark(i18n("Add folder as bookmark"),
+ url.filename(),
+ url,
+ "bookmark");
+ if (!bookmark.isNull()) {
+ KBookmarkManager* manager = DolphinSettings::instance().bookmarkManager();
+ KBookmarkGroup root = manager->root();
+ root.addBookmark(manager, bookmark);
+ manager->emitChanged(root);
+ }
+ }
+
+ popup->deleteLater();
+}
+
+void DolphinContextMenu::openItemContextMenu()
+{
+ // Parts of the following code have been taken
+ // from the class KonqOperations located in
+ // libqonq/konq_operations.h of Konqueror.
+ // (Copyright (C) 2000 David Faure <[email protected]>)
+
+ assert(m_fileInfo != 0);
+
+ KPopupMenu* popup = new KPopupMenu(m_dolphinView);
+ Dolphin& dolphin = Dolphin::mainWin();
+ const KURL::List urls = m_dolphinView->selectedURLs();
+
+ const KURL& url = dolphin.activeView()->url();
+ if (url.protocol() == "trash")
+ {
+ popup->insertItem(i18n("&Restore"), restoreID);
+ }
+
+ // insert 'Cut', 'Copy' and 'Paste'
+ const KStdAction::StdAction actionNames[] = { KStdAction::Cut, KStdAction::Copy, KStdAction::Paste };
+ const int count = sizeof(actionNames) / sizeof(KStdAction::StdAction);
+ for (int i = 0; i < count; ++i) {
+ KAction* action = dolphin.actionCollection()->action(KStdAction::stdName(actionNames[i]));
+ if (action != 0) {
+ action->plug(popup);
+ }
+ }
+ popup->insertSeparator();
+
+ // insert 'Rename'
+ KAction* renameAction = dolphin.actionCollection()->action("rename");
+ renameAction->plug(popup);
+
+ // insert 'Move to Trash' for local URLs, otherwise insert 'Delete'
+ if (url.isLocalFile()) {
+ KAction* moveToTrashAction = dolphin.actionCollection()->action("move_to_trash");
+ moveToTrashAction->plug(popup);
+ }
+ else {
+ KAction* deleteAction = dolphin.actionCollection()->action("delete");
+ deleteAction->plug(popup);
+ }
+
+ // insert 'Bookmark this folder...' entry
+ // urls is a list of selected items, so insert boolmark menu if
+ // urls contains only one item, i.e. no multiple selection made
+ if (m_fileInfo->isDir() && (urls.count() == 1)) {
+ popup->insertItem(i18n("Bookmark this folder"), bookmarkID);
+ }
+
+ popup->insertSeparator();
+
+ // Insert 'Open With...' sub menu
+ QValueVector<KService::Ptr> openWithVector;
+ const int openWithID = insertOpenWithItems(popup, openWithVector);
+
+ // Insert 'Actions' sub menu
+ QValueVector<KDEDesktopMimeType::Service> actionsVector;
+ insertActionItems(popup, actionsVector);
+
+ // insert 'Properties...' entry
+ popup->insertSeparator();
+ KAction* propertiesAction = dolphin.actionCollection()->action("properties");
+ propertiesAction->plug(popup);
+
+ int id = popup->exec(m_pos);
+
+ if (id == restoreID ) {
+ KonqOperations::restoreTrashedItems(urls);
+ }
+ else if (id == bookmarkID) {
+ const KURL selectedURL(m_fileInfo->url());
+ KBookmark bookmark = EditBookmarkDialog::getBookmark(i18n("Add folder as bookmark"),
+ selectedURL.filename(),
+ selectedURL,
+ "bookmark");
+ if (!bookmark.isNull()) {
+ KBookmarkManager* manager = DolphinSettings::instance().bookmarkManager();
+ KBookmarkGroup root = manager->root();
+ root.addBookmark(manager, bookmark);
+ manager->emitChanged(root);
+ }
+ }
+ else if (id >= actionsIDStart) {
+ // one of the 'Actions' items has been selected
+ KDEDesktopMimeType::executeService(urls, actionsVector[id - actionsIDStart]);
+ }
+ else if (id >= openWithIDStart) {
+ // one of the 'Open With' items has been selected
+ if (id == openWithID) {
+ // the item 'Other...' has been selected
+ KRun::displayOpenWithDialog(urls);
+ }
+ else {
+ KService::Ptr servicePtr = openWithVector[id - openWithIDStart];
+ KRun::run(*servicePtr, urls);
+ }
+ }
+
+ openWithVector.clear();
+ actionsVector.clear();
+ popup->deleteLater();
+}
+
+int DolphinContextMenu::insertOpenWithItems(KPopupMenu* popup,
+ QValueVector<KService::Ptr>& openWithVector)
+{
+ // Prepare 'Open With' sub menu. Usually a sub menu is created, where all applications
+ // are listed which are registered to open the item. As last entry "Other..." will be
+ // attached which allows to select a custom application. If no applications are registered
+ // no sub menu is created at all, only "Open With..." will be offered.
+ const KFileItemList* list = m_dolphinView->selectedItems();
+ assert(list != 0);
+
+ bool insertOpenWithItems = true;
+ const QString contextMimeType(m_fileInfo->mimetype());
+ KFileItemListIterator mimeIt(*list);
+ KFileItem* item = 0;
+ while (insertOpenWithItems && ((item = mimeIt.current()) != 0)) {
+ insertOpenWithItems = (contextMimeType == item->mimetype());
+ ++mimeIt;
+ }
+
+ int openWithID = -1;
+
+ if (insertOpenWithItems) {
+ // fill the 'Open with' sub menu with application types
+ const KMimeType::Ptr mimePtr = KMimeType::findByURL(m_fileInfo->url());
+ KTrader::OfferList offers = KTrader::self()->query(mimePtr->name(),
+ "Type == 'Application'");
+ int index = openWithIDStart;
+ if (offers.count() > 0) {
+ KTrader::OfferList::Iterator it;
+ KPopupMenu* openWithMenu = new KPopupMenu();
+ for(it = offers.begin(); it != offers.end(); ++it) {
+ // The offer list from the KTrader returns duplicate
+ // application entries. Although this seems to be a configuration
+ // problem outside the scope of Dolphin, duplicated entries just
+ // will be skipped here.
+ const QString appName((*it)->name());
+ if (!containsEntry(openWithMenu, appName)) {
+ openWithMenu->insertItem((*it)->pixmap(KIcon::Small),
+ appName, index);
+ openWithVector.append(*it);
+ ++index;
+ }
+ }
+
+ openWithMenu->insertSeparator();
+ openWithMenu->insertItem(i18n("&Other..."), index);
+ popup->insertItem(i18n("Open With"), openWithMenu);
+ }
+ else {
+ // No applications are registered, hence just offer
+ // a "Open With..." item instead of a sub menu containing
+ // only one entry.
+ popup->insertItem(i18n("Open With..."), openWithIDStart);
+ }
+ openWithID = index;
+ }
+ else {
+ // At least one of the selected items has a different MIME type. In this case
+ // just show a disabled "Open With..." entry.
+ popup->insertItem(i18n("Open With..."), openWithIDStart);
+ popup->setItemEnabled(openWithIDStart, false);
+ }
+
+ popup->setItemEnabled(openWithID, insertOpenWithItems);
+
+ return openWithID;
+}
+
+void DolphinContextMenu::insertActionItems(KPopupMenu* popup,
+ QValueVector<KDEDesktopMimeType::Service>& actionsVector)
+{
+ KPopupMenu* actionsMenu = new KPopupMenu();
+
+ int actionsIndex = 0;
+
+ QStringList dirs = KGlobal::dirs()->findDirs("data", "d3lphin/servicemenus/");
+
+ KPopupMenu* menu = 0;
+ for (QStringList::ConstIterator dirIt = dirs.begin(); dirIt != dirs.end(); ++dirIt) {
+ QDir dir(*dirIt);
+ QStringList entries = dir.entryList("*.desktop", QDir::Files);
+
+ for (QStringList::ConstIterator entryIt = entries.begin(); entryIt != entries.end(); ++entryIt) {
+ KSimpleConfig cfg(*dirIt + *entryIt, true);
+ cfg.setDesktopGroup();
+ if ((cfg.hasKey("Actions") || cfg.hasKey("X-KDE-GetActionMenu")) && cfg.hasKey("ServiceTypes")) {
+ const QStringList types = cfg.readListEntry("ServiceTypes");
+ for (QStringList::ConstIterator it = types.begin(); it != types.end(); ++it) {
+ // check whether the mime type is equal or whether the
+ // mimegroup (e. g. image/*) is supported
+
+ bool insert = false;
+ if ((*it) == "all/allfiles") {
+ // The service type is valid for all files, but not for directories.
+ // Check whether the selected items only consist of files...
+ const KFileItemList* list = m_dolphinView->selectedItems();
+ assert(list != 0);
+
+ KFileItemListIterator mimeIt(*list);
+ KFileItem* item = 0;
+ insert = true;
+ while (insert && ((item = mimeIt.current()) != 0)) {
+ insert = !item->isDir();
+ ++mimeIt;
+ }
+ }
+
+ if (!insert) {
+ // Check whether the MIME types of all selected files match
+ // to the mimetype of the service action. As soon as one MIME
+ // type does not match, no service menu is shown at all.
+ const KFileItemList* list = m_dolphinView->selectedItems();
+ assert(list != 0);
+
+ KFileItemListIterator mimeIt(*list);
+ KFileItem* item = 0;
+ insert = true;
+ while (insert && ((item = mimeIt.current()) != 0)) {
+ const QString mimeType((*mimeIt)->mimetype());
+ const QString mimeGroup(mimeType.left(mimeType.find('/')));
+
+ insert = (*it == mimeType) ||
+ ((*it).right(1) == "*") &&
+ ((*it).left((*it).find('/')) == mimeGroup);
+ ++mimeIt;
+ }
+ }
+
+ if (insert) {
+ menu = actionsMenu;
+
+ const QString submenuName = cfg.readEntry( "X-KDE-Submenu" );
+ if (!submenuName.isEmpty()) {
+ menu = new KPopupMenu();
+ actionsMenu->insertItem(submenuName, menu, submenuID);
+ }
+
+ QValueList<KDEDesktopMimeType::Service> userServices =
+ KDEDesktopMimeType::userDefinedServices(*dirIt + *entryIt, true);
+
+ QValueList<KDEDesktopMimeType::Service>::Iterator serviceIt;
+ for (serviceIt = userServices.begin(); serviceIt != userServices.end(); ++serviceIt) {
+ KDEDesktopMimeType::Service service = (*serviceIt);
+ if (!service.m_strIcon.isEmpty()) {
+ menu->insertItem(SmallIcon(service.m_strIcon),
+ service.m_strName,
+ actionsIDStart + actionsIndex);
+ }
+ else {
+ menu->insertItem(service.m_strName,
+ actionsIDStart + actionsIndex);
+ }
+ actionsVector.append(service);
+ ++actionsIndex;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ const int itemsCount = actionsMenu->count();
+ if (itemsCount == 0) {
+ // no actions are available at all, hence show the "Actions"
+ // submenu disabled
+ actionsMenu->setEnabled(false);
+ }
+
+ if (itemsCount == 1) {
+ // Exactly one item is available. Instead of showing a sub menu with
+ // only one item, show the item directly in the root menu.
+ if (menu == actionsMenu) {
+ // The item is an action, hence show the action in the root menu.
+ const int id = actionsMenu->idAt(0);
+ const QString text(actionsMenu->text(id));
+ const QIconSet* iconSet = actionsMenu->iconSet(id);
+ if (iconSet == 0) {
+ popup->insertItem(text, id);
+ }
+ else {
+ popup->insertItem(*iconSet, text, id);
+ }
+ }
+ else {
+ // The item is a sub menu, hence show the sub menu in the root menu.
+ popup->insertItem(actionsMenu->text(submenuID), menu);
+ }
+ actionsMenu->deleteLater();
+ actionsMenu = 0;
+ }
+ else {
+ popup->insertItem(i18n("Actions"), actionsMenu);
+ }
+}
+
+bool DolphinContextMenu::containsEntry(const KPopupMenu* menu,
+ const QString& entryName) const
+{
+ assert(menu != 0);
+
+ const uint count = menu->count();
+ for (uint i = 0; i < count; ++i) {
+ const int id = menu->idAt(i);
+ if (menu->text(id) == entryName) {
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/src/dolphincontextmenu.h b/src/dolphincontextmenu.h
new file mode 100644
index 0000000..f14419e
--- /dev/null
+++ b/src/dolphincontextmenu.h
@@ -0,0 +1,130 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef DOLPHINCONTEXTMENU_H
+#define DOLPHINCONTEXTMENU_H
+
+#include <kpopupmenu.h>
+#include <qpoint.h>
+#include <qstring.h>
+#include <qvaluelist.h>
+#include <kmountpoint.h>
+#include <qvaluevector.h>
+#include <kservice.h>
+#include <kpropertiesdialog.h>
+
+class KPopupMenu;
+class KFileItem;
+class QPoint;
+class QWidget;
+class DolphinView;
+
+/**
+ * @brief Represents the context menu which appears when doing a right
+ * click on an item or the viewport of the file manager.
+ *
+ * Beside static menu entries (e. g. 'Paste' or 'Properties') two
+ * dynamic sub menus are shown when opening a context menu above
+ * an item:
+ * - 'Open With': Contains all applications which are registered to
+ * open items of the given MIME type.
+ * - 'Actions': Contains all actions which can be applied to the
+ * given item.
+ *
+ * @author Peter Penz <[email protected]>
+ */
+class DolphinContextMenu
+{
+public:
+ /**
+ * @parent Pointer to the dolphin view the context menu
+ * belongs to.
+ * @fileInfo Pointer to the file item the context menu
+ * is applied. If 0 is passed, the context menu
+ * is above the viewport.
+ * @pos Position of the upper left edge of the context menu.
+ */
+ DolphinContextMenu(DolphinView* parent,
+ KFileItem* fileInfo,
+ const QPoint& pos);
+
+ virtual ~DolphinContextMenu();
+
+ /** Opens the context menu modal. */
+ void open();
+
+private:
+ void openViewportContextMenu();
+ void openItemContextMenu();
+
+ /**
+ * Inserts the 'Open With...' submenu to \a popup.
+ * @param popup Menu where the 'Open With...' sub menu should
+ * be added.
+ * @param openWithVector Output parameter which contains all 'Open with...'
+ * services.
+ * @return Identifier of the first 'Open With...' entry.
+ * All succeeding identifiers have an increased value of 1
+ * to the predecessor.
+ */
+ int insertOpenWithItems(KPopupMenu* popup,
+ QValueVector<KService::Ptr>& openWithVector);
+
+ /**
+ * Inserts the 'Actions...' submenu to \a popup.
+ * @param popup Menu where the 'Actions...' sub menu should
+ * be added.
+ * @param openWithVector Output parameter which contains all 'Actions...'
+ * services.
+ */
+ void insertActionItems(KPopupMenu* popup,
+ QValueVector<KDEDesktopMimeType::Service>& actionsVector);
+
+ /**
+ * Returns true, if 'menu' contains already
+ * an entry with the name 'entryName'.
+ */
+ bool containsEntry(const KPopupMenu* menu,
+ const QString& entryName) const;
+
+ enum {
+ restoreID = 80,
+ emptyID = 85,
+ submenuID = 90,
+ bookmarkID = 91,
+ openWithIDStart = 100,
+ actionsIDStart = 1000,
+ };
+
+ DolphinView* m_dolphinView;
+ KFileItem* m_fileInfo;
+ QPoint m_pos;
+
+ struct Entry {
+ int type;
+ QString name;
+ QString filePath; // empty for separator
+ QString templatePath; // same as filePath for template
+ QString icon;
+ QString comment;
+ };
+};
+
+#endif
diff --git a/src/dolphindetailsview.cpp b/src/dolphindetailsview.cpp
new file mode 100644
index 0000000..66d524e
--- /dev/null
+++ b/src/dolphindetailsview.cpp
@@ -0,0 +1,789 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "dolphindetailsview.h"
+
+#include <kurldrag.h>
+#include <qpainter.h>
+#include <qobjectlist.h>
+#include <qheader.h>
+#include <qclipboard.h>
+#include <qpainter.h>
+#include <klocale.h>
+#include <kglobalsettings.h>
+#include <qscrollbar.h>
+#include <qcursor.h>
+#include <qstyle.h>
+#include <assert.h>
+
+#include "dolphinview.h"
+#include "viewproperties.h"
+#include "dolphin.h"
+#include "kiconeffect.h"
+#include "dolphinsettings.h"
+#include "dolphinstatusbar.h"
+#include "dolphindetailsviewsettings.h"
+
+DolphinDetailsView::DolphinDetailsView(DolphinView* parent) :
+ KFileDetailView(parent, 0),
+ m_dolphinView(parent),
+ m_resizeTimer(0),
+ m_scrollTimer(0),
+ m_rubber(0)
+{
+ m_resizeTimer = new QTimer(this);
+ connect(m_resizeTimer, SIGNAL(timeout()),
+ this, SLOT(updateColumnsWidth()));
+
+ setAcceptDrops(true);
+ setSelectionMode(KFile::Extended);
+ setHScrollBarMode(QScrollView::AlwaysOff);
+
+ setColumnAlignment(SizeColumn, Qt::AlignRight);
+ for (int i = DateColumn; i <= GroupColumn; ++i) {
+ setColumnAlignment(i, Qt::AlignHCenter);
+ }
+
+ Dolphin& dolphin = Dolphin::mainWin();
+
+ connect(this, SIGNAL(onItem(QListViewItem*)),
+ this, SLOT(slotOnItem(QListViewItem*)));
+ connect(this, SIGNAL(onViewport()),
+ this, SLOT(slotOnViewport()));
+ connect(this, SIGNAL(contextMenuRequested(QListViewItem*, const QPoint&, int)),
+ this, SLOT(slotContextMenuRequested(QListViewItem*, const QPoint&, int)));
+ connect(this, SIGNAL(selectionChanged()),
+ &dolphin, SLOT(slotSelectionChanged()));
+ connect(&dolphin, SIGNAL(activeViewChanged()),
+ this, SLOT(slotActivationUpdate()));
+ connect(this, SIGNAL(itemRenamed(QListViewItem*, const QString&, int)),
+ this, SLOT(slotItemRenamed(QListViewItem*, const QString&, int)));
+ connect(this, SIGNAL(dropped(QDropEvent*, const KURL::List&, const KURL&)),
+ parent, SLOT(slotURLListDropped(QDropEvent*, const KURL::List&, const KURL&)));
+
+ QClipboard* clipboard = QApplication::clipboard();
+ connect(clipboard, SIGNAL(dataChanged()),
+ this, SLOT(slotUpdateDisabledItems()));
+
+ QHeader* viewHeader = header();
+ viewHeader->setResizeEnabled(false);
+ viewHeader->setMovingEnabled(false);
+ connect(viewHeader, SIGNAL(clicked(int)),
+ this, SLOT(slotHeaderClicked(int)));
+
+ setMouseTracking(true);
+ setDefaultRenameAction(QListView::Accept);
+
+ refreshSettings();
+}
+
+DolphinDetailsView::~DolphinDetailsView()
+{
+ delete m_rubber;
+ m_rubber = 0;
+}
+
+void DolphinDetailsView::beginItemUpdates()
+{
+}
+
+void DolphinDetailsView::endItemUpdates()
+{
+ updateDisabledItems();
+
+ // Restore the current item. Use the information stored in the history if
+ // available. Otherwise use the first item as current item.
+
+ const KFileListViewItem* item = static_cast<const KFileListViewItem*>(firstChild());
+ if (item != 0) {
+ setCurrentItem(item->fileInfo());
+ }
+
+ int index = 0;
+ const QValueList<URLNavigator::HistoryElem> history = m_dolphinView->urlHistory(index);
+ if (!history.isEmpty()) {
+ KFileView* fileView = static_cast<KFileView*>(this);
+ fileView->setCurrentItem(history[index].currentFileName());
+ setContentsPos(history[index].contentsX(), history[index].contentsY());
+ }
+
+ updateColumnsWidth();
+}
+
+void DolphinDetailsView::insertItem(KFileItem* fileItem)
+{
+ KFileView::insertItem(fileItem);
+
+ DolphinListViewItem* item = new DolphinListViewItem(static_cast<QListView*>(this), fileItem);
+
+ QDir::SortSpec spec = KFileView::sorting();
+ if (spec & QDir::Time) {
+ item->setKey(sortingKey(fileItem->time(KIO::UDS_MODIFICATION_TIME),
+ fileItem->isDir(),
+ spec));
+ }
+ else if (spec & QDir::Size) {
+ item->setKey(sortingKey(fileItem->size(), fileItem->isDir(), spec));
+ }
+ else {
+ item->setKey(sortingKey(fileItem->text(), fileItem->isDir(), spec));
+ }
+
+ fileItem->setExtraData(this, item);
+}
+
+bool DolphinDetailsView::isOnFilename(const QListViewItem* item, const QPoint& pos) const
+{
+ const QPoint absPos(mapToGlobal(QPoint(0, 0)));
+ return (pos.x() - absPos.x()) <= filenameWidth(item);
+}
+
+void DolphinDetailsView::refreshSettings()
+{
+ const DolphinDetailsViewSettings* settings = DolphinSettings::instance().detailsView();
+ assert(settings != 0);
+
+ for (int i = DolphinDetailsView::GroupColumn; i >= DolphinDetailsView::NameColumn; --i) {
+ if (!settings->isColumnEnabled(i)) {
+ removeColumn(i);
+ }
+ }
+
+ QFont adjustedFont(font());
+ adjustedFont.setFamily(settings->fontFamily());
+ adjustedFont.setPointSize(settings->fontSize());
+ setFont(adjustedFont);
+
+ updateView(true);
+}
+
+void DolphinDetailsView::zoomIn()
+{
+ if (isZoomInPossible()) {
+ DolphinDetailsViewSettings* settings = DolphinSettings::instance().detailsView();
+ switch (settings->iconSize()) {
+ case KIcon::SizeSmall: settings->setIconSize(KIcon::SizeMedium); break;
+ case KIcon::SizeMedium: settings->setIconSize(KIcon::SizeLarge); break;
+ default: assert(false); break;
+ }
+ ItemEffectsManager::zoomIn();
+ }
+}
+
+void DolphinDetailsView::zoomOut()
+{
+ if (isZoomOutPossible()) {
+ DolphinDetailsViewSettings* settings = DolphinSettings::instance().detailsView();
+ switch (settings->iconSize()) {
+ case KIcon::SizeLarge: settings->setIconSize(KIcon::SizeMedium); break;
+ case KIcon::SizeMedium: settings->setIconSize(KIcon::SizeSmall); break;
+ default: assert(false); break;
+ }
+ ItemEffectsManager::zoomOut();
+ }
+}
+
+bool DolphinDetailsView::isZoomInPossible() const
+{
+ DolphinDetailsViewSettings* settings = DolphinSettings::instance().detailsView();
+ return settings->iconSize() < KIcon::SizeLarge;
+}
+
+bool DolphinDetailsView::isZoomOutPossible() const
+{
+ DolphinDetailsViewSettings* settings = DolphinSettings::instance().detailsView();
+ return settings->iconSize() > KIcon::SizeSmall;
+}
+
+void DolphinDetailsView::resizeContents(int width, int height)
+{
+ KFileDetailView::resizeContents(width, height);
+
+ // When loading several 1000 items a punch of resize events
+ // drops in. As updating the column width is a quite expensive
+ // operation, this operation will be postponed until there is
+ // no resize event for at least 50 milliseconds.
+ m_resizeTimer->stop();
+ m_resizeTimer->start(50, true);
+}
+
+void DolphinDetailsView::slotOnItem(QListViewItem* item)
+{
+ if (isOnFilename(item, QCursor::pos())) {
+ activateItem(item);
+ KFileItem* fileItem = static_cast<KFileListViewItem*>(item)->fileInfo();
+ m_dolphinView->requestItemInfo(fileItem->url());
+ }
+ else {
+ resetActivatedItem();
+ }
+}
+
+void DolphinDetailsView::slotOnViewport()
+{
+ resetActivatedItem();
+ m_dolphinView->requestItemInfo(KURL());
+}
+
+void DolphinDetailsView::setContextPixmap(void* context,
+ const QPixmap& pixmap)
+{
+ reinterpret_cast<KFileListViewItem*>(context)->setPixmap(0, pixmap);
+}
+
+const QPixmap* DolphinDetailsView::contextPixmap(void* context)
+{
+ return reinterpret_cast<KFileListViewItem*>(context)->pixmap(0);
+}
+
+void* DolphinDetailsView::firstContext()
+{
+ return reinterpret_cast<void*>(firstChild());
+}
+
+void* DolphinDetailsView::nextContext(void* context)
+{
+ KFileListViewItem* listViewItem = reinterpret_cast<KFileListViewItem*>(context);
+ return reinterpret_cast<void*>(listViewItem->nextSibling());
+}
+
+KFileItem* DolphinDetailsView::contextFileInfo(void* context)
+{
+ return reinterpret_cast<KFileListViewItem*>(context)->fileInfo();
+}
+
+
+void DolphinDetailsView::contentsDragMoveEvent(QDragMoveEvent* event)
+{
+ KFileDetailView::contentsDragMoveEvent(event);
+
+ // If a dragging is done above a directory, show the icon as 'active' for
+ // a visual feedback
+ KFileListViewItem* item = static_cast<KFileListViewItem*>(itemAt(event->pos()));
+
+ bool showActive = false;
+ if (item != 0) {
+ const KFileItem* fileInfo = item->fileInfo();
+ showActive = (fileInfo != 0) && fileInfo->isDir();
+ }
+
+ if (showActive) {
+ slotOnItem(item);
+ }
+ else {
+ slotOnViewport();
+ }
+}
+
+void DolphinDetailsView::resizeEvent(QResizeEvent* event)
+{
+ KFileDetailView::resizeEvent(event);
+
+ // When loading several 1000 items a punch of resize events
+ // drops in. As updating the column width is a quite expensive
+ // operation, this operation will be postponed until there is
+ // no resize event for at least 50 milliseconds.
+ m_resizeTimer->stop();
+ m_resizeTimer->start(50, true);
+}
+
+bool DolphinDetailsView::acceptDrag(QDropEvent* event) const
+{
+ bool accept = KURLDrag::canDecode(event) &&
+ (event->action() == QDropEvent::Copy ||
+ event->action() == QDropEvent::Move ||
+ event->action() == QDropEvent::Link);
+ if (accept) {
+ if (static_cast<const QWidget*>(event->source()) == this) {
+ KFileListViewItem* item = static_cast<KFileListViewItem*>(itemAt(event->pos()));
+ accept = (item != 0);
+ if (accept) {
+ KFileItem* fileItem = item->fileInfo();
+ accept = fileItem->isDir();
+ }
+ }
+ }
+
+ return accept;
+}
+
+void DolphinDetailsView::contentsDropEvent(QDropEvent* event)
+{
+ // KFileDetailView::contentsDropEvent does not care whether the mouse
+ // cursor is above a filename or not, the destination URL is always
+ // the URL of the item. This is fixed here in a way that the destination
+ // URL is only the URL of the item if the cursor is above the filename.
+ const QPoint pos(QCursor::pos());
+ const QPoint viewportPos(viewport()->mapToGlobal(QPoint(0, 0)));
+ QListViewItem* item = itemAt(QPoint(pos.x() - viewportPos.x(), pos.y() - viewportPos.y()));
+ if ((item == 0) || ((item != 0) && isOnFilename(item, pos))) {
+ // dropping is done on the viewport or directly above a filename
+ KFileDetailView::contentsDropEvent(event);
+ return;
+ }
+
+ // Dropping is done above an item, but the mouse cursor is not above the file name.
+ // In this case the signals of the base implementation will be blocked and send
+ // in a corrected manner afterwards.
+ assert(item != 0);
+ const bool block = signalsBlocked();
+ blockSignals(true);
+ KFileDetailView::contentsDropEvent(event);
+ blockSignals(block);
+
+ if (!acceptDrag(event)) {
+ return;
+ }
+
+ emit dropped(event, 0);
+ KURL::List urls;
+ if (KURLDrag::decode(event, urls) && !urls.isEmpty()) {
+ emit dropped(event, urls, KURL());
+ sig->dropURLs(0, event, urls);
+ }
+}
+
+void DolphinDetailsView::contentsMousePressEvent(QMouseEvent* event)
+{
+ if (m_rubber != 0) {
+ drawRubber();
+ delete m_rubber;
+ m_rubber = 0;
+ }
+
+ // Swallow the base implementation of the mouse press event
+ // if the mouse cursor is not above the filename. This prevents
+ // that the item gets selected and simulates an equal usability
+ // like in the icon view.
+ const QPoint pos(QCursor::pos());
+ const QPoint viewportPos(viewport()->mapToGlobal(QPoint(0, 0)));
+ QListViewItem* item = itemAt(QPoint(pos.x() - viewportPos.x(), pos.y() - viewportPos.y()));
+ if ((item != 0) && isOnFilename(item, pos)) {
+ KFileDetailView::contentsMousePressEvent(event);
+ }
+ else if (event->button() == Qt::LeftButton) {
+ const ButtonState keyboardState = KApplication::keyboardMouseState();
+ const bool isSelectionActive = (keyboardState & ShiftButton) ||
+ (keyboardState & ControlButton);
+ if (!isSelectionActive) {
+ clearSelection();
+ }
+
+ assert(m_rubber == 0);
+ m_rubber = new QRect(event->x(), event->y(), 0, 0);
+ }
+
+ resetActivatedItem();
+ emit signalRequestActivation();
+
+ m_dolphinView->statusBar()->clear();
+}
+
+void DolphinDetailsView::contentsMouseMoveEvent(QMouseEvent* event)
+{
+ if (m_rubber != 0) {
+ slotAutoScroll();
+ return;
+ }
+
+ KFileDetailView::contentsMouseMoveEvent(event);
+
+ const QPoint& pos = event->globalPos();
+ const QPoint viewportPos = viewport()->mapToGlobal(QPoint(0, 0));
+ QListViewItem* item = itemAt(QPoint(pos.x() - viewportPos.x(), pos.y() - viewportPos.y()));
+ if ((item != 0) && isOnFilename(item, pos)) {
+ activateItem(item);
+ }
+ else {
+ resetActivatedItem();
+ }
+}
+
+void DolphinDetailsView::contentsMouseReleaseEvent(QMouseEvent* event)
+{
+ if (m_rubber != 0) {
+ drawRubber();
+ delete m_rubber;
+ m_rubber = 0;
+ }
+
+ if (m_scrollTimer != 0) {
+ disconnect(m_scrollTimer, SIGNAL(timeout()),
+ this, SLOT(slotAutoScroll()));
+ m_scrollTimer->stop();
+ delete m_scrollTimer;
+ m_scrollTimer = 0;
+ }
+
+ KFileDetailView::contentsMouseReleaseEvent(event);
+}
+
+void DolphinDetailsView::paintEmptyArea(QPainter* painter, const QRect& rect)
+{
+ if (m_dolphinView->isActive()) {
+ KFileDetailView::paintEmptyArea(painter, rect);
+ }
+ else {
+ const QBrush brush(colorGroup().background());
+ painter->fillRect(rect, brush);
+ }
+}
+
+void DolphinDetailsView::drawRubber()
+{
+ // Parts of the following code have been taken
+ // from the class KonqBaseListViewWidget located in
+ // konqueror/listview/konq_listviewwidget.h of Konqueror.
+ // (Copyright (C) 1998, 1999 Torben Weis <[email protected]>
+ // 2001, 2002, 2004 Michael Brade <[email protected]>)
+ if (m_rubber == 0) {
+ return;
+ }
+
+ QPainter p;
+ p.begin(viewport());
+ p.setRasterOp(NotROP);
+ p.setPen(QPen(color0, 1));
+ p.setBrush(NoBrush);
+
+ QPoint point(m_rubber->x(), m_rubber->y());
+ point = contentsToViewport(point);
+ style().drawPrimitive(QStyle::PE_FocusRect, &p,
+ QRect(point.x(), point.y(), m_rubber->width(), m_rubber->height()),
+ colorGroup(), QStyle::Style_Default, colorGroup().base());
+ p.end();
+}
+
+void DolphinDetailsView::viewportPaintEvent(QPaintEvent* paintEvent)
+{
+ drawRubber();
+ KFileDetailView::viewportPaintEvent(paintEvent);
+ drawRubber();
+}
+
+void DolphinDetailsView::leaveEvent(QEvent* event)
+{
+ KFileDetailView::leaveEvent(event);
+ slotOnViewport();
+}
+
+void DolphinDetailsView::slotActivationUpdate()
+{
+ update();
+
+ // TODO: there must be a simpler way to say
+ // "update all children"
+ const QObjectList* list = children();
+ if (list == 0) {
+ return;
+ }
+
+ QObjectListIterator it(*list);
+ QObject* object = 0;
+ while ((object = it.current()) != 0) {
+ if (object->inherits("QWidget")) {
+ QWidget* widget = static_cast<QWidget*>(object);
+ widget->update();
+ }
+ ++it;
+ }
+}
+
+void DolphinDetailsView::slotContextMenuRequested(QListViewItem* item,
+ const QPoint& pos,
+ int /* col */)
+{
+ KFileItem* fileInfo = 0;
+ if ((item != 0) && isOnFilename(item, pos)) {
+ fileInfo = static_cast<KFileListViewItem*>(item)->fileInfo();
+ }
+ m_dolphinView->openContextMenu(fileInfo, pos);
+
+}
+
+void DolphinDetailsView::slotUpdateDisabledItems()
+{
+ updateDisabledItems();
+}
+
+void DolphinDetailsView::slotAutoScroll()
+{
+ // Parts of the following code have been taken
+ // from the class KonqBaseListViewWidget located in
+ // konqueror/listview/konq_listviewwidget.h of Konqueror.
+ // (Copyright (C) 1998, 1999 Torben Weis <[email protected]>
+ // 2001, 2002, 2004 Michael Brade <[email protected]>)
+
+ const QPoint pos(viewport()->mapFromGlobal(QCursor::pos()));
+ const QPoint vc(viewportToContents(pos));
+
+ if (vc == m_rubber->bottomRight()) {
+ return;
+ }
+
+ drawRubber();
+
+ m_rubber->setBottomRight(vc);
+
+ QListViewItem* item = itemAt(QPoint(0,0));
+
+ const bool block = signalsBlocked();
+ blockSignals(true);
+
+ const QRect rubber(m_rubber->normalize());
+ const int bottom = contentsY() + visibleHeight() - 1;
+
+ // select all items which intersect with the rubber, deselect all others
+ bool bottomReached = false;
+ while ((item != 0) && !bottomReached) {
+ QRect rect(itemRect(item));
+ rect.setWidth(filenameWidth(item));
+ rect = QRect(viewportToContents(rect.topLeft()),
+ viewportToContents(rect.bottomRight()));
+ if (rect.isValid() && (rect.top() <= bottom)) {
+ const KFileItem* fileItem = static_cast<KFileListViewItem*>(item)->fileInfo();
+ setSelected(fileItem, rect.intersects(rubber));
+ item = item->itemBelow();
+ }
+ else {
+ bottomReached = true;
+ }
+ }
+
+ blockSignals(block);
+ emit selectionChanged();
+
+ drawRubber();
+
+ // scroll the viewport if the top or bottom margin is reached
+ const int scrollMargin = 40;
+ ensureVisible(vc.x(), vc.y(), scrollMargin, scrollMargin);
+ const bool scroll = !QRect(scrollMargin,
+ scrollMargin,
+ viewport()->width() - 2 * scrollMargin,
+ viewport()->height() - 2 * scrollMargin).contains(pos);
+ if (scroll) {
+ if (m_scrollTimer == 0) {
+ m_scrollTimer = new QTimer( this );
+ connect(m_scrollTimer, SIGNAL(timeout()),
+ this, SLOT(slotAutoScroll()));
+ m_scrollTimer->start(100, false);
+ }
+ }
+ else if (m_scrollTimer != 0) {
+ disconnect(m_scrollTimer, SIGNAL(timeout()),
+ this, SLOT(slotAutoScroll()));
+ m_scrollTimer->stop();
+ delete m_scrollTimer;
+ m_scrollTimer = 0;
+ }
+}
+
+void DolphinDetailsView::updateColumnsWidth()
+{
+ const int columnCount = columns();
+ int requiredWidth = 0;
+ for (int i = 1; i < columnCount; ++i) {
+ // When a directory contains no items, a minimum width for
+ // the column must be available, so that the header is readable.
+ // TODO: use header data instead of the hardcoded 64 value...
+ int columnWidth = 64;
+ QFontMetrics fontMetrics(font());
+ for (QListViewItem* item = firstChild(); item != 0; item = item->nextSibling()) {
+ const int width = item->width(fontMetrics, this, i);
+ if (width > columnWidth) {
+ columnWidth = width;
+ }
+ }
+ columnWidth += 16; // add custom margin
+ setColumnWidth(i, columnWidth);
+ requiredWidth += columnWidth;
+ }
+
+ // resize the first column in a way that the
+ // whole available width is used
+ int firstColumnWidth = visibleWidth() - requiredWidth;
+ if (firstColumnWidth < 128) {
+ firstColumnWidth = 128;
+ }
+ setColumnWidth(0, firstColumnWidth);
+}
+
+void DolphinDetailsView::slotItemRenamed(QListViewItem* item,
+ const QString& name,
+ int /* column */)
+{
+ KFileItem* fileInfo = static_cast<KFileListViewItem*>(item)->fileInfo();
+ m_dolphinView->rename(KURL(fileInfo->url()), name);
+}
+
+void DolphinDetailsView::slotHeaderClicked(int /* section */)
+{
+ // The sorting has already been changed in QListView if this slot is
+ // invoked, but Dolphin was not informed about this (no signal is available
+ // which indicates a change of the sorting). This is bypassed by changing
+ // the sorting and sort order to a temporary other value and readjust it again.
+ const int column = sortColumn();
+ if (column <= DateColumn) {
+ DolphinView::Sorting sorting = DolphinView::SortByName;
+ switch (column) {
+ case SizeColumn: sorting = DolphinView::SortBySize; break;
+ case DateColumn: sorting = DolphinView::SortByDate; break;
+ case NameColumn:
+ default: break;
+ }
+
+ const Qt::SortOrder currSortOrder = sortOrder();
+
+ // temporary adjust the sorting and sort order to different values...
+ const DolphinView::Sorting tempSorting = (sorting == DolphinView::SortByName) ?
+ DolphinView::SortBySize :
+ DolphinView::SortByName;
+ m_dolphinView->setSorting(tempSorting);
+ const Qt::SortOrder tempSortOrder = (currSortOrder == Qt::Ascending) ?
+ Qt::Descending : Qt::Ascending;
+ m_dolphinView->setSortOrder(tempSortOrder);
+
+ // ... so that setting them again results in storing the new setting.
+ m_dolphinView->setSorting(sorting);
+ m_dolphinView->setSortOrder(currSortOrder);
+ }
+}
+
+DolphinDetailsView::DolphinListViewItem::DolphinListViewItem(QListView* parent,
+ KFileItem* fileItem) :
+ KFileListViewItem(parent, fileItem)
+{
+ const int iconSize = DolphinSettings::instance().detailsView()->iconSize();
+ KFileItem* info = fileInfo();
+ setPixmap(DolphinDetailsView::NameColumn, info->pixmap(iconSize));
+
+ // The base class KFileListViewItem represents the column 'Size' only as byte values.
+ // Adjust those values in a way that a mapping to GBytes, MBytes, KBytes and Bytes
+ // is done. As the file size for directories is useless (only the size of the directory i-node
+ // is given), it is removed completely.
+ if (fileItem->isDir()) {
+ setText(SizeColumn, " - ");
+ }
+ else {
+ QString sizeText(KIO::convertSize(fileItem->size()));
+ sizeText.append(" ");
+ setText(SizeColumn, sizeText);
+ }
+
+ // Dolphin allows to remove specific columns, but the base class KFileListViewItem
+ // is not aware about this (or at least the class KFileDetailView does not react on
+ // QListView::remove()). Therefore the columns are rearranged here.
+ const DolphinDetailsViewSettings* settings = DolphinSettings::instance().detailsView();
+ assert(settings != 0);
+
+ int column_idx = DateColumn; // the columns for 'name' and 'size' cannot get removed
+ for (int i = DolphinDetailsView::DateColumn; i <= DolphinDetailsView::GroupColumn; ++i) {
+ if (column_idx < i) {
+ setText(column_idx, text(i));
+ }
+ if (settings->isColumnEnabled(i)) {
+ ++column_idx;
+ }
+ }
+}
+
+DolphinDetailsView::DolphinListViewItem::~DolphinListViewItem()
+{
+}
+
+void DolphinDetailsView::DolphinListViewItem::paintCell(QPainter* painter,
+ const QColorGroup& colorGroup,
+ int column,
+ int cellWidth,
+ int alignment)
+{
+ const QListView* view = listView();
+ const bool isActive = view->parent() == Dolphin::mainWin().activeView();
+ if (isSelected()) {
+ // Per default the selection is drawn above the whole width of the item. As a consistent
+ // behavior with the icon view is wanted, only the the column containing the file name
+ // should be shown as selected.
+ QColorGroup defaultColorGroup(colorGroup);
+ const QColor highlightColor(isActive ? backgroundColor(column) : view->colorGroup().background());
+ defaultColorGroup.setColor(QColorGroup::Highlight , highlightColor);
+ defaultColorGroup.setColor(QColorGroup::HighlightedText, colorGroup.color(QColorGroup::Text));
+ KFileListViewItem::paintCell(painter, defaultColorGroup, column, cellWidth, alignment);
+
+ if (column == 0) {
+ // draw the selection only on the first column
+ QListView* parent = listView();
+ const int itemWidth = width(parent->fontMetrics(), parent, 0);
+ if (isActive) {
+ KFileListViewItem::paintCell(painter, colorGroup, column, itemWidth, alignment);
+ }
+ else {
+ QListViewItem::paintCell(painter, colorGroup, column, itemWidth, alignment);
+ }
+ }
+ }
+ else {
+ if (isActive) {
+ KFileListViewItem::paintCell(painter, colorGroup, column, cellWidth, alignment);
+ }
+ else {
+ QListViewItem::paintCell(painter, colorGroup, column, cellWidth, alignment);
+ }
+ }
+
+ if (column < listView()->columns() - 1) {
+ // draw a separator between columns
+ painter->setPen(KGlobalSettings::buttonBackground());
+ painter->drawLine(cellWidth - 1, 0, cellWidth - 1, height() - 1);
+ }
+}
+
+void DolphinDetailsView::DolphinListViewItem::paintFocus(QPainter* painter,
+ const QColorGroup& colorGroup,
+ const QRect& rect)
+{
+ // draw the focus consistently with the selection (see implementation notes
+ // in DolphinListViewItem::paintCell)
+ QListView* parent = listView();
+ int visibleWidth = width(parent->fontMetrics(), parent, 0);
+ const int colWidth = parent->columnWidth(0);
+ if (visibleWidth > colWidth) {
+ visibleWidth = colWidth;
+ }
+
+ QRect focusRect(rect);
+ focusRect.setWidth(visibleWidth);
+
+ KFileListViewItem::paintFocus(painter, colorGroup, focusRect);
+}
+
+int DolphinDetailsView::filenameWidth(const QListViewItem* item) const
+{
+ assert(item != 0);
+
+ int visibleWidth = item->width(fontMetrics(), this, 0);
+ const int colWidth = columnWidth(0);
+ if (visibleWidth > colWidth) {
+ visibleWidth = colWidth;
+ }
+
+ return visibleWidth;
+}
+#include "dolphindetailsview.moc"
diff --git a/src/dolphindetailsview.h b/src/dolphindetailsview.h
new file mode 100644
index 0000000..e1ee95f
--- /dev/null
+++ b/src/dolphindetailsview.h
@@ -0,0 +1,216 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef DOLPHINDETAILSVIEW_H
+#define DOLPHINDETAILSVIEW_H
+
+#include <kfiledetailview.h>
+#include <itemeffectsmanager.h>
+
+class QRect;
+class QTimer;
+class DolphinView;
+
+/**
+ * @brief Represents the details view which shows the name, size,
+ * date, permissions, owner and group of an item.
+ *
+ * The width of the columns are automatically adjusted in a way
+ * that full available width of the view is used by stretching the width
+ * of the name column.
+ *
+ * @author Peter Penz
+ */
+class DolphinDetailsView : public KFileDetailView, public ItemEffectsManager
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Maps the column indices of KFileDetailView to a
+ * descriptive column name.
+ */
+ enum ColumnName {
+ NameColumn = 0,
+ SizeColumn = 1,
+ DateColumn = 2,
+ PermissionsColumn = 3,
+ OwnerColumn = 4,
+ GroupColumn = 5
+ };
+
+ DolphinDetailsView(DolphinView* parent);
+
+ virtual ~DolphinDetailsView();
+
+ /** @see ItemEffectsManager::updateItems */
+ virtual void beginItemUpdates();
+
+ /** @see ItemEffectsManager::updateItems */
+ virtual void endItemUpdates();
+
+ /** @see KFileView::insertItem */
+ virtual void insertItem(KFileItem* fileItem);
+
+ /**
+ * @return True, if the position \a pos is above the name of
+ * item \a item.
+ */
+ bool isOnFilename(const QListViewItem* item, const QPoint& pos) const;
+
+ /**
+ * Reads out the dolphin settings for the details view and refreshs
+ * the details view.
+ */
+ // TODO: Other view implementations use a similar interface. When using
+ // Interview in Qt4 this method should be moved to a base class (currently
+ // not possible due to having different base classes for the views).
+ void refreshSettings();
+
+ /** @see ItemEffectsManager::zoomIn() */
+ virtual void zoomIn();
+
+ /** @see ItemEffectsManager::zoomOut() */
+ virtual void zoomOut();
+
+ /** @see ItemEffectsManager::isZoomInPossible() */
+ virtual bool isZoomInPossible() const;
+
+ /** @see ItemEffectsManager::isZoomOutPossible() */
+ virtual bool isZoomOutPossible() const;
+
+signals:
+ /**
+ * Is send, if the details view should be activated. Usually an activation
+ * is triggered by a mouse click.
+ */
+ void signalRequestActivation();
+
+public slots:
+ /** @see KFileDetailView::resizeContents */
+ virtual void resizeContents(int width, int height);
+
+ /** Is connected to the onItem-signal from KFileDetailView. */
+ void slotOnItem(QListViewItem* item);
+
+ /** Is connected to the onViewport-signal from KFileDetailView. */
+ void slotOnViewport();
+
+protected:
+ /** @see ItemEffectsManager::setContextPixmap() */
+ virtual void setContextPixmap(void* context,
+ const QPixmap& pixmap);
+
+ /** @see ItemEffectsManager::setContextPixmap() */
+ virtual const QPixmap* contextPixmap(void* context);
+
+ /** @see ItemEffectsManager::setContextPixmap() */
+ virtual void* firstContext();
+
+ /** @see ItemEffectsManager::setContextPixmap() */
+ virtual void* nextContext(void* context);
+
+ /** @see ItemEffectsManager::setContextPixmap() */
+ virtual KFileItem* contextFileInfo(void* context);
+
+ /** @see KFileDetailView::contentsDragMoveEvent() */
+ virtual void contentsDragMoveEvent(QDragMoveEvent* event);
+
+ /** @see KFileDetailView::resizeEvent() */
+ virtual void resizeEvent(QResizeEvent* event);
+
+ /** @see KFileDetailView::acceptDrag() */
+ virtual bool acceptDrag (QDropEvent* event) const;
+
+ /** @see KFileDetailView::contentsDropEvent() */
+ virtual void contentsDropEvent(QDropEvent* event);
+
+ /** @see KFileDetailView::contentsMousePressEvent() */
+ virtual void contentsMousePressEvent(QMouseEvent* event);
+
+ /** @see KFileDetailView::contentsMouseMoveEvent() */
+ virtual void contentsMouseMoveEvent(QMouseEvent* event);
+
+ /** @see KFileDetailView::contentsMouseReleaseEvent() */
+ virtual void contentsMouseReleaseEvent(QMouseEvent* event);
+
+ /** @see QListView::paintEmptyArea() */
+ virtual void paintEmptyArea(QPainter* painter, const QRect& rect);
+
+ /** Draws the selection rubber. */
+ void drawRubber();
+
+ /** @see QListView::viewportPaintEvent() */
+ virtual void viewportPaintEvent(QPaintEvent* paintEvent);
+
+ /** @see QWidget::leaveEvent() */
+ virtual void leaveEvent(QEvent* event);
+
+private slots:
+ void slotActivationUpdate();
+ void slotContextMenuRequested(QListViewItem* item,
+ const QPoint& pos,
+ int col);
+ void slotUpdateDisabledItems();
+ void slotAutoScroll();
+ void updateColumnsWidth();
+ void slotItemRenamed(QListViewItem* item,
+ const QString& name,
+ int column);
+
+ /**
+ * Is invoked when a section from the header has
+ * been clicked and stores the sort column and sort
+ * order.
+ */
+ void slotHeaderClicked(int section);
+
+private:
+ class DolphinListViewItem : public KFileListViewItem {
+ public:
+ DolphinListViewItem(QListView* parent,
+ KFileItem* fileItem);
+ virtual ~DolphinListViewItem();
+ virtual void paintCell(QPainter* painter,
+ const QColorGroup& colorGroup,
+ int column,
+ int cellWidth,
+ int alignment);
+
+ virtual void paintFocus(QPainter* painter,
+ const QColorGroup& colorGroup,
+ const QRect& rect);
+ };
+
+ DolphinView* m_dolphinView;
+ QTimer* m_resizeTimer;
+ QTimer* m_scrollTimer;
+ QRect* m_rubber;
+
+ /**
+ * Returns the width of the filename in pixels including
+ * the icon. It is assured that the returned width is
+ * <= the width of the filename column.
+ */
+ int filenameWidth(const QListViewItem* item) const;
+
+};
+
+#endif
diff --git a/src/dolphindetailsviewsettings.cpp b/src/dolphindetailsviewsettings.cpp
new file mode 100644
index 0000000..005ebf0
--- /dev/null
+++ b/src/dolphindetailsviewsettings.cpp
@@ -0,0 +1,108 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "dolphindetailsviewsettings.h"
+#include "dolphindetailsview.h"
+#include <kglobalsettings.h>
+#include <kapplication.h>
+
+DolphinDetailsViewSettings::DolphinDetailsViewSettings() :
+ m_columnEnabled(0),
+ m_iconSize(0),
+ m_fontSize(0)
+{
+ KConfig* config = kapp->config();
+ config->setGroup("Details Mode");
+
+ // read which columns should be shown
+ const bool showName = config->readBoolEntry("Show Name", true);
+ const bool showSize = config->readBoolEntry("Show Size", true);
+ const bool showDate = config->readBoolEntry("Show Date", true);
+ const bool showPermissions = config->readBoolEntry("Show Permissions", false);
+ const bool showOwner = config->readBoolEntry("Show Owner", false);
+ const bool showGroup = config->readBoolEntry("Show Group", false);
+
+ setColumnEnabled(DolphinDetailsView::NameColumn, showName);
+ setColumnEnabled(DolphinDetailsView::SizeColumn, showSize);
+ setColumnEnabled(DolphinDetailsView::DateColumn, showDate);
+ setColumnEnabled(DolphinDetailsView::PermissionsColumn, showPermissions);
+ setColumnEnabled(DolphinDetailsView::OwnerColumn, showOwner);
+ setColumnEnabled(DolphinDetailsView::GroupColumn, showGroup);
+
+ // read icon size
+ m_iconSize = config->readNumEntry("Icon Size", KIcon::SizeSmall);
+
+ // read font size and font family
+ m_fontSize = config->readNumEntry("Font Size", -1);
+ m_fontFamily = config->readEntry("Font Family");
+
+ const QFont font(KGlobalSettings::generalFont());
+ if (m_fontSize < 0) {
+ m_fontSize = font.pointSize();
+ }
+
+ if (m_fontFamily.isEmpty()) {
+ m_fontFamily = font.family();
+ }
+}
+
+DolphinDetailsViewSettings::~DolphinDetailsViewSettings()
+{
+ m_columnEnabled = 0;
+ m_fontSize = 0;
+}
+
+void DolphinDetailsViewSettings::setColumnEnabled(int column,
+ bool enable)
+{
+ if (enable) {
+ m_columnEnabled = m_columnEnabled | (1 << column);
+ }
+ else {
+ m_columnEnabled = m_columnEnabled & ~(1 << column);
+ }
+}
+
+bool DolphinDetailsViewSettings::isColumnEnabled(int column) const
+{
+ return (m_columnEnabled & (1 << column)) > 0;
+}
+
+void DolphinDetailsViewSettings::save()
+{
+ KConfig* config = kapp->config();
+ config->setGroup("Details Mode");
+
+ config->writeEntry("Show Name",
+ isColumnEnabled(DolphinDetailsView::NameColumn));
+ config->writeEntry("Show Size",
+ isColumnEnabled(DolphinDetailsView::SizeColumn));
+ config->writeEntry("Show Date",
+ isColumnEnabled(DolphinDetailsView::DateColumn));
+ config->writeEntry("Show Permissions",
+ isColumnEnabled(DolphinDetailsView::PermissionsColumn));
+ config->writeEntry("Show Owner",
+ isColumnEnabled(DolphinDetailsView::OwnerColumn));
+ config->writeEntry("Show Group",
+ isColumnEnabled(DolphinDetailsView::GroupColumn));
+ config->writeEntry("Icon Size", m_iconSize);
+ config->writeEntry("Font Size", m_fontSize);
+ config->writeEntry("Font Family", m_fontFamily);
+}
diff --git a/src/dolphindetailsviewsettings.h b/src/dolphindetailsviewsettings.h
new file mode 100644
index 0000000..d296f96
--- /dev/null
+++ b/src/dolphindetailsviewsettings.h
@@ -0,0 +1,71 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef DOLPHINDETAILSVIEWSETTINGS_H
+#define DOLPHINDETAILSVIEWSETTINGS_H
+
+#include <qstring.h>
+#include <qnamespace.h>
+#include <dolphinsettingsbase.h>
+
+/**
+ * @brief Contains the settings for the details view.
+ *
+ * The following properties are stored:
+ * - enabled columns
+ * - sorted column
+ * - sort order for the sorted column
+ * - icon size
+ * - font family
+ * - font size
+ *
+ * @see DolphinDetailsView
+ * @author Peter Penz <[email protected]>
+ */
+class DolphinDetailsViewSettings : public DolphinSettingsBase
+{
+public:
+ DolphinDetailsViewSettings();
+
+ virtual ~DolphinDetailsViewSettings();
+
+ void setColumnEnabled(int column, bool enable);
+ bool isColumnEnabled(int column) const;
+
+ void setIconSize(int size) { m_iconSize = size; }
+ int iconSize() const { return m_iconSize; }
+
+ void setFontFamily(const QString& family) { m_fontFamily = family; }
+ const QString& fontFamily() const { return m_fontFamily; }
+
+ void setFontSize(int size) { m_fontSize = size; }
+ int fontSize() const { return m_fontSize; }
+
+ /** @see DolphinSettingsBase::save() */
+ virtual void save();
+
+private:
+ int m_columnEnabled;
+ int m_iconSize;
+ int m_fontSize;
+ QString m_fontFamily;
+};
+
+#endif
diff --git a/src/dolphindirlister.cpp b/src/dolphindirlister.cpp
new file mode 100644
index 0000000..897b4b4
--- /dev/null
+++ b/src/dolphindirlister.cpp
@@ -0,0 +1,42 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "dolphindirlister.h"
+#include <kio/jobclasses.h>
+
+// TODO:
+#include <stdio.h>
+
+DolphinDirLister::DolphinDirLister() :
+ KDirLister(true)
+{
+}
+
+DolphinDirLister::~DolphinDirLister()
+{
+}
+
+void DolphinDirLister::handleError(KIO::Job* job)
+{
+ // TODO: some error texts should be adjusted manually
+ emit errorMessage(job->errorString());
+}
+
+#include "dolphindirlister.moc"
diff --git a/src/dolphindirlister.h b/src/dolphindirlister.h
new file mode 100644
index 0000000..8d49d98
--- /dev/null
+++ b/src/dolphindirlister.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef DOLPHINDIRLISTER_H
+#define DOLPHINDIRLISTER_H
+
+#include <kdirlister.h>
+
+/**
+ * @brief Extends the class KDirLister by emitting an error
+ * signal containing text.
+ *
+ * @author Peter Penz
+ */
+class DolphinDirLister : public KDirLister
+{
+ Q_OBJECT
+
+public:
+ DolphinDirLister();
+ virtual ~DolphinDirLister();
+
+signals:
+ /** Is emitted whenever an error occured. */
+ void errorMessage(const QString& msg);
+
+protected:
+ virtual void handleError(KIO::Job* job);
+};
+
+#endif
diff --git a/src/dolphiniconsview.cpp b/src/dolphiniconsview.cpp
new file mode 100644
index 0000000..7a2489b
--- /dev/null
+++ b/src/dolphiniconsview.cpp
@@ -0,0 +1,500 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "dolphiniconsview.h"
+#include <qpainter.h>
+#include <kiconeffect.h>
+#include <kapplication.h>
+#include <qobjectlist.h>
+#include <kglobalsettings.h>
+#include <kurldrag.h>
+#include <qclipboard.h>
+#include <assert.h>
+#include <kaction.h>
+#include <kstdaction.h>
+#include <kfileitem.h>
+
+#include "dolphinview.h"
+#include "viewproperties.h"
+#include "dolphin.h"
+#include "dolphinstatusbar.h"
+#include "dolphinsettings.h"
+#include "dolphiniconsviewsettings.h"
+
+DolphinIconsView::DolphinIconsView(DolphinView* parent, LayoutMode layoutMode) :
+ KFileIconView(parent, 0),
+ m_previewIconSize(-1),
+ m_layoutMode(layoutMode),
+ m_dolphinView(parent)
+{
+ setAcceptDrops(true);
+ setMode(KIconView::Execute);
+ setSelectionMode(KFile::Extended);
+ Dolphin& dolphin = Dolphin::mainWin();
+
+ connect(this, SIGNAL(onItem(QIconViewItem*)),
+ this, SLOT(slotOnItem(QIconViewItem*)));
+ connect(this, SIGNAL(onViewport()),
+ this, SLOT(slotOnViewport()));
+ connect(this, SIGNAL(contextMenuRequested(QIconViewItem*, const QPoint&)),
+ this, SLOT(slotContextMenuRequested(QIconViewItem*, const QPoint&)));
+ connect(this, SIGNAL(selectionChanged()),
+ &dolphin, SLOT(slotSelectionChanged()));
+ connect(&dolphin, SIGNAL(activeViewChanged()),
+ this, SLOT(slotActivationUpdate()));
+ connect(this, SIGNAL(itemRenamed(QIconViewItem*, const QString&)),
+ this, SLOT(slotItemRenamed(QIconViewItem*, const QString&)));
+ connect(this, SIGNAL(dropped(QDropEvent*, const KURL::List&, const KURL&)),
+ parent, SLOT(slotURLListDropped(QDropEvent*, const KURL::List&, const KURL&)));
+
+ QClipboard* clipboard = QApplication::clipboard();
+ connect(clipboard, SIGNAL(dataChanged()),
+ this, SLOT(slotUpdateDisabledItems()));
+
+ // KFileIconView creates two actions for zooming, which are directly connected to the
+ // slots KFileIconView::zoomIn() and KFileIconView::zoomOut(). As this behavior is not
+ // wanted and the slots are not virtual, the actions are disabled here.
+ KAction* zoomInAction = actionCollection()->action("zoomIn");
+ assert(zoomInAction != 0);
+ zoomInAction->setEnabled(false);
+
+ KAction* zoomOutAction = actionCollection()->action("zoomOut");
+ assert(zoomOutAction != 0);
+ zoomOutAction->setEnabled(false);
+
+ setItemsMovable(true);
+ setWordWrapIconText(true);
+ if (m_layoutMode == Previews) {
+ showPreviews();
+ }
+ refreshSettings();
+}
+
+DolphinIconsView::~DolphinIconsView()
+{
+}
+
+void DolphinIconsView::setLayoutMode(LayoutMode mode)
+{
+ if (m_layoutMode != mode) {
+ m_layoutMode = mode;
+ refreshSettings();
+ }
+}
+
+void DolphinIconsView::beginItemUpdates()
+{
+}
+
+void DolphinIconsView::endItemUpdates()
+{
+ arrangeItemsInGrid();
+
+ // TODO: KFileIconView does not emit any signal when the preview
+ // has been finished. Using a delay of 300 ms is a temporary workaround
+ // until the DolphinIconsView will implement the previews by it's own in
+ // future releases.
+ QTimer::singleShot(300, this, SLOT(slotUpdateDisabledItems()));
+
+ const KFileIconViewItem* item = static_cast<const KFileIconViewItem*>(firstItem());
+ if (item != 0) {
+ setCurrentItem(item->fileInfo());
+ }
+
+ int index = 0;
+ const QValueList<URLNavigator::HistoryElem> history = m_dolphinView->urlHistory(index);
+ if (!history.isEmpty()) {
+ KFileView* fileView = static_cast<KFileView*>(this);
+ fileView->setCurrentItem(history[index].currentFileName());
+ setContentsPos(history[index].contentsX(), history[index].contentsY());
+ }
+}
+
+void DolphinIconsView::refreshSettings()
+{
+ const DolphinIconsViewSettings* settings = DolphinSettings::instance().iconsView(m_layoutMode);
+ assert(settings != 0);
+
+ setIconSize(settings->iconSize());
+
+ const QIconView::Arrangement arrangement = settings->arrangement();
+ const QIconView::ItemTextPos textPos = (arrangement == QIconView::LeftToRight) ?
+ QIconView::Bottom :
+ QIconView::Right;
+ setArrangement(arrangement);
+ setItemTextPos(textPos);
+
+ setGridX(settings->gridWidth());
+ setGridY(settings->gridHeight());
+ setSpacing(settings->gridSpacing());
+
+ QFont adjustedFont(font());
+ adjustedFont.setFamily(settings->fontFamily());
+ adjustedFont.setPointSize(settings->fontSize());
+ setFont(adjustedFont);
+ setIconTextHeight(settings->textlinesCount());
+
+ if (m_layoutMode == Previews) {
+ // There is no getter method for the current size in KFileIconView. To
+ // prevent a flickering the current size is stored in m_previewIconSize and
+ // setPreviewSize is only invoked if the size really has changed.
+ showPreviews();
+
+ const int size = settings->previewSize();
+ if (size != m_previewIconSize) {
+ m_previewIconSize = size;
+ setPreviewSize(size);
+ }
+ }
+}
+
+void DolphinIconsView::zoomIn()
+{
+ if (isZoomInPossible()) {
+ DolphinIconsViewSettings* settings = DolphinSettings::instance().iconsView(m_layoutMode);
+ const int textWidthHint = settings->textWidthHint();
+
+ const int iconSize = increasedIconSize(settings->iconSize());
+ settings->setIconSize(iconSize);
+
+ if (m_layoutMode == Previews) {
+ const int previewSize = increasedIconSize(settings->previewSize());
+ settings->setPreviewSize(previewSize);
+ }
+
+ settings->calculateGridSize(textWidthHint);
+ ItemEffectsManager::zoomIn();
+ }
+}
+
+void DolphinIconsView::zoomOut()
+{
+ if (isZoomOutPossible()) {
+ DolphinIconsViewSettings* settings = DolphinSettings::instance().iconsView(m_layoutMode);
+ const int textWidthHint = settings->textWidthHint();
+
+ const int iconSize = decreasedIconSize(settings->iconSize());
+ settings->setIconSize(iconSize);
+
+ if (m_layoutMode == Previews) {
+ const int previewSize = decreasedIconSize(settings->previewSize());
+ settings->setPreviewSize(previewSize);
+ }
+
+ settings->calculateGridSize(textWidthHint);
+ ItemEffectsManager::zoomOut();
+ }
+}
+
+bool DolphinIconsView::isZoomInPossible() const
+{
+ DolphinIconsViewSettings* settings = DolphinSettings::instance().iconsView(m_layoutMode);
+ const int size = (m_layoutMode == Icons) ? settings->iconSize() : settings->previewSize();
+ return size < KIcon::SizeEnormous;
+}
+
+bool DolphinIconsView::isZoomOutPossible() const
+{
+ DolphinIconsViewSettings* settings = DolphinSettings::instance().iconsView(m_layoutMode);
+ return settings->iconSize() > KIcon::SizeSmall;
+}
+
+void DolphinIconsView::arrangeItemsInGrid( bool updated )
+{
+
+ KFileIconView::arrangeItemsInGrid(updated);
+
+ if (m_layoutMode == Previews) {
+ // The class KFileIconView has a bug when the size of the previews differs from the size
+ // of the icons: For specific MIME types the y-position and the height is calculated in
+ // a wrong manner. The following code bypasses this issue. No bugreport has been submitted
+ // as this functionality is not used by any KDE3 application and the core developers are
+ // busy enough for KDE4 now :-)
+
+ KFileIconViewItem* item = static_cast<KFileIconViewItem*>(QIconView::firstItem());
+ QString mimetype;
+ while (item != 0) {
+ mimetype = item->fileInfo()->mimetype();
+ const bool fixSize = mimetype.contains("text") ||
+ mimetype.contains("application/x-");
+ if (fixSize) {
+ item->setPixmapSize(QSize(m_previewIconSize, m_previewIconSize));
+ }
+ item = static_cast<KFileIconViewItem *>(item->nextItem());
+ }
+ }
+}
+
+void DolphinIconsView::setContextPixmap(void* context,
+ const QPixmap& pixmap)
+{
+ reinterpret_cast<KFileIconViewItem*>(context)->setPixmap(pixmap);
+}
+
+const QPixmap* DolphinIconsView::contextPixmap(void* context)
+{
+ return reinterpret_cast<KFileIconViewItem*>(context)->pixmap();
+}
+
+void* DolphinIconsView::firstContext()
+{
+ return reinterpret_cast<void*>(firstItem());
+}
+
+void* DolphinIconsView::nextContext(void* context)
+{
+ KFileIconViewItem* iconViewItem = reinterpret_cast<KFileIconViewItem*>(context);
+ return reinterpret_cast<void*>(iconViewItem->nextItem());
+}
+
+KFileItem* DolphinIconsView::contextFileInfo(void* context)
+{
+ return reinterpret_cast<KFileIconViewItem*>(context)->fileInfo();
+}
+
+void DolphinIconsView::contentsMousePressEvent(QMouseEvent* event)
+{
+ KFileIconView::contentsMousePressEvent(event);
+ resetActivatedItem();
+ emit signalRequestActivation();
+ m_dolphinView->statusBar()->clear();
+}
+
+void DolphinIconsView::contentsMouseReleaseEvent(QMouseEvent* event)
+{
+ KFileIconView::contentsMouseReleaseEvent(event);
+
+ // The KFileIconView does not send any selectionChanged signal if
+ // a selection is done by using the "select-during-button-pressed" feature.
+ // Hence inform Dolphin about the selection change manually:
+ Dolphin::mainWin().slotSelectionChanged();
+}
+
+void DolphinIconsView::drawBackground(QPainter* painter, const QRect& rect)
+{
+ if (m_dolphinView->isActive()) {
+ KFileIconView::drawBackground(painter, rect);
+ }
+ else {
+ const QBrush brush(colorGroup().background());
+ painter->fillRect(0, 0, width(), height(), brush);
+ }
+}
+
+QDragObject* DolphinIconsView::dragObject()
+{
+ KURL::List urls;
+ KFileItemListIterator it(*KFileView::selectedItems());
+ while (it.current() != 0) {
+ urls.append((*it)->url());
+ ++it;
+ }
+
+ QPixmap pixmap;
+ if(urls.count() > 1) {
+ pixmap = DesktopIcon("kmultiple", iconSize());
+ }
+ else {
+ KFileIconViewItem* item = static_cast<KFileIconViewItem*>(currentItem());
+ if ((item != 0) && (item->pixmap() != 0)) {
+ pixmap = *(item->pixmap());
+ }
+ }
+
+ if (pixmap.isNull()) {
+ pixmap = currentFileItem()->pixmap(iconSize());
+ }
+
+ QDragObject* dragObj = new KURLDrag(urls, widget());
+ dragObj->setPixmap(pixmap);
+ return dragObj;
+}
+
+void DolphinIconsView::contentsDragEnterEvent(QDragEnterEvent* event)
+{
+ // TODO: The method KFileIconView::contentsDragEnterEvent() does
+ // not allow drag and drop inside itself, which prevents the possability
+ // to move a file into a directory. As the method KFileIconView::acceptDrag()
+ // is not virtual, we must overwrite the method
+ // KFileIconView::contentsDragEnterEvent() and do some cut/copy/paste for this
+ // usecase. Corresponding to the documentation the method KFileIconView::acceptDrag()
+ // will get virtual in KDE 4, which will simplify the code.
+
+ if (event->source() != this) {
+ KFileIconView::contentsDragEnterEvent(event);
+ return;
+ }
+
+ const bool accept = KURLDrag::canDecode(event) &&
+ (event->action() == QDropEvent::Copy ||
+ event->action() == QDropEvent::Move ||
+ event->action() == QDropEvent::Link );
+ if (accept) {
+ event->acceptAction();
+ }
+ else {
+ event->ignore();
+ }
+}
+
+void DolphinIconsView::contentsDragMoveEvent(QDragMoveEvent* event)
+{
+ KFileIconView::contentsDragMoveEvent(event);
+
+ // If a dragging is done above a directory, show the icon as 'active' for
+ // a visual feedback
+ KFileIconViewItem* item = static_cast<KFileIconViewItem*>(findItem(contentsToViewport(event->pos())));
+
+ bool showActive = false;
+ if (item != 0) {
+ const KFileItem* fileInfo = item->fileInfo();
+ showActive = (fileInfo != 0) && fileInfo->isDir();
+ }
+
+ if (showActive) {
+ slotOnItem(item);
+ }
+ else {
+ slotOnViewport();
+ }
+}
+
+void DolphinIconsView::contentsDropEvent(QDropEvent* event)
+{
+ // TODO: Most of the following code is a copy of
+ // KFileIconView::contentsDropEvent. See comment in
+ // DolphinIconsView::contentsDragEnterEvent for details.
+
+ if (event->source() != this) {
+ KFileIconView::contentsDropEvent(event);
+ return;
+ }
+
+ KFileIconViewItem* item = static_cast<KFileIconViewItem*>(findItem(contentsToViewport(event->pos())));
+ const bool accept = KURLDrag::canDecode(event) &&
+ (event->action() == QDropEvent::Copy ||
+ event->action() == QDropEvent::Move ||
+ event->action() == QDropEvent::Link ) &&
+ (item != 0);
+ if (!accept) {
+ return;
+ }
+
+ KFileItem* fileItem = item->fileInfo();
+ if (!fileItem->isDir()) {
+ // the file is not a directory, hence don't accept any drop
+ return;
+ }
+ emit dropped(event, fileItem);
+ KURL::List urls;
+ if (KURLDrag::decode(event, urls) && !urls.isEmpty()) {
+ emit dropped(event, urls, fileItem != 0 ? fileItem->url() : KURL());
+ sig->dropURLs(fileItem, event, urls);
+ }
+}
+
+void DolphinIconsView::slotOnItem(QIconViewItem* item)
+{
+ assert(item != 0);
+ activateItem(reinterpret_cast<void*>(item));
+
+ KFileItem* fileItem = static_cast<KFileIconViewItem*>(item)->fileInfo();
+ m_dolphinView->requestItemInfo(fileItem->url());
+}
+
+void DolphinIconsView::slotOnViewport()
+{
+ resetActivatedItem();
+ m_dolphinView->requestItemInfo(KURL());
+}
+
+void DolphinIconsView::slotContextMenuRequested(QIconViewItem* item,
+ const QPoint& pos)
+{
+ KFileItem* fileInfo = 0;
+ if (item != 0) {
+ fileInfo = static_cast<KFileIconViewItem*>(item)->fileInfo();
+ }
+ m_dolphinView->openContextMenu(fileInfo, pos);
+}
+
+void DolphinIconsView::slotItemRenamed(QIconViewItem* item,
+ const QString& name)
+{
+ KFileItem* fileInfo = static_cast<KFileIconViewItem*>(item)->fileInfo();
+ m_dolphinView->rename(KURL(fileInfo->url()), name);
+}
+
+void DolphinIconsView::slotActivationUpdate()
+{
+ update();
+
+ // TODO: there must be a simpler way to say
+ // "update all children"
+ const QObjectList* list = children();
+ if (list == 0) {
+ return;
+ }
+
+ QObjectListIterator it(*list);
+ QObject* object = 0;
+ while ((object = it.current()) != 0) {
+ if (object->inherits("QWidget")) {
+ QWidget* widget = static_cast<QWidget*>(object);
+ widget->update();
+ }
+ ++it;
+ }
+}
+
+void DolphinIconsView::slotUpdateDisabledItems()
+{
+ updateDisabledItems();
+}
+
+int DolphinIconsView::increasedIconSize(int size) const
+{
+ int incSize = 0;
+ switch (size) {
+ case KIcon::SizeSmall: incSize = KIcon::SizeSmallMedium; break;
+ case KIcon::SizeSmallMedium: incSize = KIcon::SizeMedium; break;
+ case KIcon::SizeMedium: incSize = KIcon::SizeLarge; break;
+ case KIcon::SizeLarge: incSize = KIcon::SizeHuge; break;
+ case KIcon::SizeHuge: incSize = KIcon::SizeEnormous; break;
+ default: assert(false); break;
+ }
+ return incSize;
+}
+
+int DolphinIconsView::decreasedIconSize(int size) const
+{
+ int decSize = 0;
+ switch (size) {
+ case KIcon::SizeSmallMedium: decSize = KIcon::SizeSmall; break;
+ case KIcon::SizeMedium: decSize = KIcon::SizeSmallMedium; break;
+ case KIcon::SizeLarge: decSize = KIcon::SizeMedium; break;
+ case KIcon::SizeHuge: decSize = KIcon::SizeLarge; break;
+ case KIcon::SizeEnormous: decSize = KIcon::SizeHuge; break;
+ default: assert(false); break;
+ }
+ return decSize;
+}
+
+#include "dolphiniconsview.moc"
diff --git a/src/dolphiniconsview.h b/src/dolphiniconsview.h
new file mode 100644
index 0000000..9be2102
--- /dev/null
+++ b/src/dolphiniconsview.h
@@ -0,0 +1,168 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef DOLPHINICONSVIEW_H
+#define DOLPHINICONSVIEW_H
+
+#include <kfileiconview.h>
+#include <qpixmap.h>
+#include <kurl.h>
+#include <itemeffectsmanager.h>
+
+class DolphinView;
+
+/**
+ * @brief Represents the view, where each item is shown as an icon.
+ *
+ * It is also possible that instead of the icon a preview of the item
+ * content is shown.
+ *
+ * @author Peter Penz
+ */
+class DolphinIconsView : public KFileIconView, public ItemEffectsManager
+{
+ Q_OBJECT
+
+public:
+ enum LayoutMode {
+ Icons,
+ Previews
+ };
+
+ DolphinIconsView(DolphinView *parent, LayoutMode layoutMode);
+
+ virtual ~DolphinIconsView();
+
+ void setLayoutMode(LayoutMode mode);
+ LayoutMode layoutMode() const { return m_layoutMode; }
+
+ /** @see ItemEffectsManager::updateItems */
+ virtual void beginItemUpdates();
+
+ /** @see ItemEffectsManager::updateItems */
+ virtual void endItemUpdates();
+
+ /**
+ * Reads out the dolphin settings for the icons view and refreshs
+ * the details view.
+ */
+ // TODO: Other view implementations use a similar interface. When using
+ // Interview in Qt4 this method should be moved to a base class (currently
+ // not possible due to having different base classes for the views).
+ void refreshSettings();
+
+ /** @see ItemEffectsManager::zoomIn() */
+ virtual void zoomIn();
+
+ /** @see ItemEffectsManager::zoomOut() */
+ virtual void zoomOut();
+
+ /** @see ItemEffectsManager::isZoomInPossible() */
+ virtual bool isZoomInPossible() const;
+
+ /** @see ItemEffectsManager::isZoomOutPossible() */
+ virtual bool isZoomOutPossible() const;
+
+public slots:
+ /**
+ * Bypass a layout issue in KFileIconView in combination with previews.
+ * @see KFileIconView::arrangeItemsInGrid
+ */
+ virtual void arrangeItemsInGrid(bool updated = true);
+
+signals:
+ /**
+ * Is send, if the details view should be activated. Usually an activation
+ * is triggered by a mouse click.
+ */
+ void signalRequestActivation();
+
+protected:
+ /** @see ItemEffectsManager::setContextPixmap */
+ virtual void setContextPixmap(void* context,
+ const QPixmap& pixmap);
+
+ /** @see ItemEffectsManager::contextPixmap */
+ virtual const QPixmap* contextPixmap(void* context);
+
+ /** @see ItemEffectsManager::firstContext */
+ virtual void* firstContext();
+
+ /** @see ItemEffectsManager::nextContext */
+ virtual void* nextContext(void* context);
+
+ /** @see ItemEffectsManager::contextFileInfo */
+ virtual KFileItem* contextFileInfo(void* context);
+
+ /** @see KFileIconView::contentsMousePressEvent */
+ virtual void contentsMousePressEvent(QMouseEvent* event);
+
+ /** @see KFileIconView::contentsMouseReleaseEvent */
+ virtual void contentsMouseReleaseEvent(QMouseEvent* event);
+
+ /** @see KFileIconView::drawBackground */
+ virtual void drawBackground(QPainter* painter, const QRect& rect);
+
+ /** @see KFileIconView::dragObject */
+ virtual QDragObject* dragObject();
+
+ /** @see KFileIconView::contentsDragEnterEvent */
+ virtual void contentsDragEnterEvent(QDragEnterEvent* event);
+
+ /** @see KFileIconView::contentsDragMoveEvent */
+ virtual void contentsDragMoveEvent(QDragMoveEvent* event);
+
+ /** @see KFileIconView::contentsDropEvent */
+ virtual void contentsDropEvent(QDropEvent* event);
+
+private slots:
+ /** Is connected to the onItem-signal from KFileIconView. */
+ void slotOnItem(QIconViewItem* item);
+
+ /** Is connected to the onViewport-signal from KFileIconView. */
+ void slotOnViewport();
+
+ /**
+ * Opens the context menu for the item \a item on the given
+ * position \a pos.
+ */
+ void slotContextMenuRequested(QIconViewItem* item,
+ const QPoint& pos);
+
+ /** Renames the item \a item to the name \a name. */
+ void slotItemRenamed(QIconViewItem* item,
+ const QString& name);
+
+ void slotActivationUpdate();
+ void slotUpdateDisabledItems();
+
+private:
+ int m_previewIconSize;
+ LayoutMode m_layoutMode;
+ DolphinView* m_dolphinView;
+
+ /** Returns the increased icon size for the size \a size. */
+ int increasedIconSize(int size) const;
+
+ /** Returns the decreased icon size for the size \a size. */
+ int decreasedIconSize(int size) const;
+};
+
+#endif
diff --git a/src/dolphiniconsviewsettings.cpp b/src/dolphiniconsviewsettings.cpp
new file mode 100644
index 0000000..d47f0f7
--- /dev/null
+++ b/src/dolphiniconsviewsettings.cpp
@@ -0,0 +1,199 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "dolphiniconsviewsettings.h"
+#include <kicontheme.h>
+#include <kglobalsettings.h>
+#include <kapplication.h>
+#include <assert.h>
+
+DolphinIconsViewSettings::DolphinIconsViewSettings(DolphinIconsView::LayoutMode mode) :
+ m_arrangement(QIconView::LeftToRight),
+ m_layoutMode(mode),
+ m_iconSize(KIcon::SizeMedium),
+ m_previewSize(KIcon::SizeMedium),
+ m_gridWidth(0),
+ m_gridHeight(KIcon::SizeMedium),
+ m_gridSpacing(8),
+ m_fontSize(0),
+ m_textlinesCount(2)
+{
+ KConfig* config = kapp->config();
+ setConfigGroup(config);
+
+ // read icon size
+ m_iconSize = config->readNumEntry("Icon Size", -1);
+ if (m_iconSize < 0) {
+ m_iconSize = KIcon::SizeMedium;
+ }
+
+ // read arrangement
+ const QString arrangement(config->readEntry("Arrangement"));
+ if (arrangement == "Left to Right") {
+ m_arrangement = QIconView::LeftToRight;
+ }
+ else if (arrangement == "Top to Bottom") {
+ m_arrangement = QIconView::TopToBottom;
+ }
+
+ // read preview size, grid width and grid height
+ m_previewSize = config->readNumEntry("Preview Size", -1);
+ m_gridWidth = config->readNumEntry("Grid Width", -1);
+ m_gridHeight = config->readNumEntry("Grid Height", -1);
+ m_gridSpacing = config->readNumEntry("Grid Spacing", -1);
+
+ if (mode == DolphinIconsView::Previews) {
+ if (m_previewSize < 0) {
+ m_previewSize = KIcon::SizeEnormous;
+ }
+ if (m_gridWidth < 0) {
+ m_gridWidth = m_previewSize + (m_previewSize / 2);
+ }
+ }
+ else if (m_gridWidth < 0) {
+ m_gridWidth = m_iconSize + (m_iconSize / 2) + (KIcon::SizeLarge * 2);
+ }
+
+ if (m_gridHeight < 0) {
+ m_gridHeight = m_iconSize * 2;
+ }
+
+ // read font size and font family
+ m_fontSize = config->readNumEntry("Font Size", -1);
+ m_fontFamily = config->readEntry("Font Family");
+
+ const QFont font(KGlobalSettings::generalFont());
+ if (m_fontSize < 0) {
+ m_fontSize = font.pointSize();
+ }
+
+ if (m_fontFamily.isEmpty()) {
+ m_fontFamily = font.family();
+ }
+
+ // read textlines count
+ m_textlinesCount = config->readNumEntry("Number of Textlines", 2);
+}
+
+
+DolphinIconsViewSettings::~DolphinIconsViewSettings()
+{
+}
+
+void DolphinIconsViewSettings::setIconSize(int size)
+{
+ // TODO: add boundaries check
+ m_iconSize = size;
+}
+
+void DolphinIconsViewSettings::setPreviewSize(int size)
+{
+ // TODO: add boundaries check
+ m_previewSize = size;
+}
+
+void DolphinIconsViewSettings::setGridSpacing(int spacing)
+{
+ // TODO: add boundaries check
+ m_gridSpacing = spacing;
+}
+
+void DolphinIconsViewSettings::save()
+{
+ KConfig* config = kapp->config();
+ setConfigGroup(config);
+
+ config->writeEntry("Icon Size", m_iconSize);
+ if (m_arrangement == QIconView::LeftToRight) {
+ config->writeEntry("Arrangement", "Left to Right");
+ }
+ else {
+ config->writeEntry("Arrangement", "Top to Bottom");
+ }
+
+ config->writeEntry("Preview Size", m_previewSize);
+ config->writeEntry("Grid Width", m_gridWidth);
+ config->writeEntry("Grid Height", m_gridHeight);
+ config->writeEntry("Grid Spacing", m_gridSpacing);
+ config->writeEntry("Font Size", m_fontSize);
+ config->writeEntry("Font Family", m_fontFamily);
+ config->writeEntry("Number of Textlines", m_textlinesCount);
+}
+
+void DolphinIconsViewSettings::calculateGridSize(int hint)
+{
+ const int maxSize = (m_previewSize > m_iconSize) ? m_previewSize : m_iconSize;
+ if (m_arrangement == QIconView::LeftToRight) {
+ int widthUnit = maxSize + (maxSize / 2);
+ if (widthUnit < KIcon::SizeLarge) {
+ widthUnit = KIcon::SizeLarge;
+ }
+ //m_gridWidth = widthUnit + hint * KIcon::SizeLarge;
+ m_gridWidth = widthUnit + hint * KIcon::SizeLarge;
+
+ m_gridHeight = m_iconSize;
+ if (m_gridHeight <= KIcon::SizeMedium) {
+ m_gridHeight = m_gridHeight * 2;
+ }
+ else {
+ m_gridHeight += maxSize / 2;
+ }
+ }
+ else {
+ assert(m_arrangement == QIconView::TopToBottom);
+ m_gridWidth = maxSize + (hint + 1) * (8 * m_fontSize);
+
+ // The height-setting is ignored yet by KFileIconView if the TopToBottom
+ // arrangement is active. Anyway write the setting to have a defined value.
+ m_gridHeight = maxSize;
+ }
+}
+
+int DolphinIconsViewSettings::textWidthHint() const
+{
+ const int maxSize = (m_previewSize > m_iconSize) ? m_previewSize : m_iconSize;
+ int hint = 0;
+ if (m_arrangement == QIconView::LeftToRight) {
+ int widthUnit = maxSize + (maxSize / 2);
+ if (widthUnit < KIcon::SizeLarge) {
+ widthUnit = KIcon::SizeLarge;
+ }
+ hint = (m_gridWidth - widthUnit) / KIcon::SizeLarge;
+ }
+ else {
+ assert(m_arrangement == QIconView::TopToBottom);
+ hint = (m_gridWidth - maxSize) / (8 * m_fontSize) - 1;
+ if (hint > 2) {
+ hint = 2;
+ }
+ }
+ return hint;
+}
+
+void DolphinIconsViewSettings::setConfigGroup(KConfig* config)
+{
+ if (m_layoutMode == DolphinIconsView::Previews) {
+ config->setGroup("Previews Mode");
+ }
+ else {
+ config->setGroup("Icons Mode");
+ }
+}
+
diff --git a/src/dolphiniconsviewsettings.h b/src/dolphiniconsviewsettings.h
new file mode 100644
index 0000000..ec63677
--- /dev/null
+++ b/src/dolphiniconsviewsettings.h
@@ -0,0 +1,126 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+#ifndef DOLPHINICONSVIEWSETTINGS_H
+#define DOLPHINICONSVIEWSETTINGS_H
+
+#include <qstring.h>
+#include <qiconview.h>
+#include <dolphinview.h>
+#include <dolphiniconsview.h>
+#include <dolphinsettingsbase.h>
+
+/**
+ * @brief Contains the settings for the icons view.
+ *
+ * The following properties are stored:
+ * - layout mode (icons or previews)
+ * - icon size
+ * - preview size
+ * - grid width, height and spacing
+ * - arrangement (left to right or top to bottom)
+ * - font family
+ * - font size
+ * - number of text lines
+ *
+ * @see DolphinIconsView
+ * @author Peter Penz <[email protected]>
+ */
+class DolphinIconsViewSettings : public DolphinSettingsBase
+{
+public:
+ DolphinIconsViewSettings(DolphinIconsView::LayoutMode mode);
+ virtual ~DolphinIconsViewSettings();
+
+ void setIconSize(int size);
+ int iconSize() const { return m_iconSize; }
+
+ void setPreviewSize(int size);
+ int previewSize() const { return m_previewSize; }
+
+ /**
+ * Returns the width of the grid. For setting the width
+ * DolphinIconsviewSettings::calculateGridSize() must be used.
+ */
+ int gridWidth() const { return m_gridWidth; }
+
+ /**
+ * Returns the height of the grid. For setting the height
+ * DolphinIconsviewSettings::calculateGridSize() must be used.
+ */
+ int gridHeight() const { return m_gridHeight; }
+
+ void setGridSpacing(int spacing);
+ int gridSpacing() const { return m_gridSpacing; }
+
+ void setArrangement(QIconView::Arrangement arrangement) { m_arrangement = arrangement; }
+ QIconView::Arrangement arrangement() const { return m_arrangement; }
+
+ void setFontFamily(const QString& family) { m_fontFamily = family; }
+ const QString& fontFamily() const { return m_fontFamily; }
+
+ void setFontSize(int size) { m_fontSize = size; }
+ int fontSize() const { return m_fontSize; }
+
+ void setTextlinesCount(int count) { m_textlinesCount = count; }
+ int textlinesCount() const { return m_textlinesCount; }
+
+ /** @see DolphinSettingsBase::save */
+ virtual void save();
+
+ /**
+ * Calculates the width and the height of the grid dependant from \a hint and
+ * the current settings. The hint gives information about the wanted text
+ * width, where a lower value indicates a smaller text width. Currently
+ * in Dolphin the values 0, 1 and 2 are used. See also
+ * DolhinIconsViewSettings::textWidthHint.
+ *
+ * The calculation of the grid width and grid height is a little bit tricky,
+ * as the user model does not fit to the implementation model of QIconView. The user model
+ * allows to specify icon-, preview- and text width sizes, whereas the implementation
+ * model expects only a grid width and height. The nasty thing is that the specified
+ * width and height varies dependant from the arrangement (e. g. the height is totally
+ * ignored for the top-to-bottom arrangement inside QIconView).
+ */
+ void calculateGridSize(int hint);
+
+ /**
+ * Returns the text width hint dependant from the given settings.
+ * A lower value indicates a smaller text width. Currently
+ * in Dolphin the values 0, 1 and 2 are used. The text width hint can
+ * be used later for DolphinIconsViewSettings::calculateGridSize().
+ */
+ int textWidthHint() const;
+
+private:
+ QIconView::Arrangement m_arrangement;
+ DolphinIconsView::LayoutMode m_layoutMode;
+ int m_iconSize;
+ int m_previewSize;
+ int m_gridWidth;
+ int m_gridHeight;
+ int m_gridSpacing;
+ int m_fontSize;
+ int m_textlinesCount;
+ QString m_fontFamily;
+
+ void setConfigGroup(KConfig* config);
+};
+
+#endif
diff --git a/src/dolphinsettings.cpp b/src/dolphinsettings.cpp
new file mode 100644
index 0000000..01ef80e
--- /dev/null
+++ b/src/dolphinsettings.cpp
@@ -0,0 +1,142 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz ([email protected]), *
+ * Cvetoslav Ludmiloff and Patrice Tremblay *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "dolphinsettings.h"
+#include <qdir.h>
+
+#include <kapplication.h>
+#include <kbookmark.h>
+#include <kbookmarkmanager.h>
+#include <kicontheme.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+
+#include "dolphin.h"
+#include "dolphiniconsviewsettings.h"
+#include "dolphindetailsviewsettings.h"
+#include "sidebarssettings.h"
+
+DolphinSettings& DolphinSettings::instance()
+{
+ static DolphinSettings* instance = 0;
+ if (instance == 0) {
+ instance = new DolphinSettings();
+ }
+ return *instance;
+}
+
+void DolphinSettings::setHomeURL(const KURL& url)
+{
+ m_homeURL = url;
+ // TODO: update home bookmark?
+}
+
+DolphinSettings::DolphinSettings() :
+ m_defaultMode(DolphinView::IconsView),
+ m_isViewSplit(false),
+ m_isURLEditable(false)
+{
+ KConfig* config = kapp->config();
+ config->setGroup("General");
+ m_homeURL = KURL(config->readEntry("Home URL", QDir::homeDirPath()));
+ m_defaultMode = static_cast<DolphinView::Mode>(config->readNumEntry("Default View Mode", DolphinView::IconsView));
+ m_isViewSplit = config->readBoolEntry("Split View", false);
+ m_isSaveView = config->readBoolEntry("Save View", false);
+ m_isURLEditable = config->readBoolEntry("Editable URL", false);
+
+ m_iconsView = new DolphinIconsViewSettings(DolphinIconsView::Icons);
+ m_previewsView = new DolphinIconsViewSettings(DolphinIconsView::Previews);
+ m_detailsView = new DolphinDetailsViewSettings();
+ m_leftsidebar = new leftSidebarSettings();
+ m_rightsidebar = new rightSidebarSettings();
+}
+
+DolphinSettings::~DolphinSettings()
+{
+ delete m_iconsView;
+ m_iconsView = 0;
+
+ delete m_previewsView;
+ m_previewsView = 0;
+
+ delete m_detailsView;
+ m_detailsView = 0;
+
+ delete m_leftsidebar;
+ m_leftsidebar = 0;
+
+ delete m_rightsidebar;
+ m_rightsidebar = 0;
+}
+
+KBookmark DolphinSettings::bookmark(int index) const
+{
+ int i = 0;
+ KBookmarkGroup root = bookmarkManager()->root();
+ KBookmark bookmark = root.first();
+ while (!bookmark.isNull()) {
+ if (i == index) {
+ return bookmark;
+ }
+ ++i;
+ bookmark = root.next(bookmark);
+ }
+
+ return KBookmark();
+}
+
+DolphinIconsViewSettings* DolphinSettings::iconsView(DolphinIconsView::LayoutMode mode) const
+{
+ return (mode == DolphinIconsView::Icons) ? m_iconsView : m_previewsView;
+}
+
+KBookmarkManager* DolphinSettings::bookmarkManager() const
+{
+ QString basePath = KGlobal::instance()->instanceName();
+ basePath.append("/bookmarks.xml");
+ const QString file = locateLocal("data", basePath);
+
+ return KBookmarkManager::managerForFile(file, false);
+}
+
+void DolphinSettings::save()
+{
+ KConfig* config = kapp->config();
+ config->setGroup("General");
+ config->writeEntry("Version", 1); // internal version
+ config->writeEntry("Home URL", m_homeURL.prettyURL());
+ config->writeEntry("Default View Mode", m_defaultMode);
+ config->writeEntry("Split View", m_isViewSplit);
+ config->writeEntry("Save View", m_isSaveView);
+ config->writeEntry("Editable URL", m_isURLEditable);
+
+ m_iconsView->save();
+ m_previewsView->save();
+ m_detailsView->save();
+ m_leftsidebar->save();
+ m_rightsidebar->save();
+
+ QString basePath = KGlobal::instance()->instanceName();
+ basePath.append("/bookmarks.xml");
+ const QString file = locateLocal( "data", basePath);
+
+ KBookmarkManager* manager = KBookmarkManager::managerForFile(file, false);
+ manager->save(false);
+}
diff --git a/src/dolphinsettings.h b/src/dolphinsettings.h
new file mode 100644
index 0000000..3e70fd4
--- /dev/null
+++ b/src/dolphinsettings.h
@@ -0,0 +1,110 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef DOLPHINSETTINGS_H
+#define DOLPHINSETTINGS_H
+
+#include <qvaluelist.h>
+
+#include <dolphiniconsview.h>
+#include <dolphinview.h>
+#include <dolphinsettingsbase.h>
+#include <kurl.h>
+
+class KBookmark;
+class KBookmarkManager;
+class DolphinIconsViewSettings;
+class DolphinDetailsViewSettings;
+class leftSidebarSettings;
+class rightSidebarSettings;
+
+/**
+ * @brief Manages and stores all settings from Dolphin.
+ *
+ * The following properties are stored:
+ * - home URL
+ * - default view mode
+ * - URL navigator state (editable or not)
+ * - split view
+ * - bookmarks
+ * - properties for icons and details view
+ */
+class DolphinSettings : DolphinSettingsBase {
+public:
+ static DolphinSettings& instance();
+
+ void setHomeURL(const KURL& url);
+ const KURL& homeURL() const { return m_homeURL; }
+
+ void setDefaultViewMode(DolphinView::Mode mode) { m_defaultMode = mode; }
+ DolphinView::Mode defaultViewMode() const { return m_defaultMode; }
+
+ void setURLEditable(bool editable) { m_isURLEditable = editable; }
+ bool isURLEditable() const { return m_isURLEditable; }
+
+ void setViewSplit(bool split) { m_isViewSplit = split; }
+ bool isViewSplit() const { return m_isViewSplit; }
+
+ void setSaveView(bool yes) { m_isSaveView = yes; }
+ bool isSaveView() const { return m_isSaveView; }
+
+
+ DolphinIconsViewSettings* iconsView(DolphinIconsView::LayoutMode mode) const;
+
+ DolphinDetailsViewSettings* detailsView() const { return m_detailsView; }
+
+ leftSidebarSettings* leftsidebar() const { return m_leftsidebar; }
+ rightSidebarSettings* rightsidebar() const { return m_rightsidebar; }
+
+ KBookmarkManager* bookmarkManager() const;
+
+ // TODO: should this really belong here or get moved to a derived KBookmarkManager?
+ // Dolphin uses some lists where an index is given and the corresponding bookmark
+ // should get retrieved...
+ KBookmark bookmark(int index) const;
+
+ /** @see DolphinSettingsBase::save */
+ virtual void save();
+
+protected:
+ DolphinSettings();
+ virtual ~DolphinSettings();
+
+private:
+ enum BookmarkHint {
+ Home = 0,
+ Media = 1,
+ Network = 2,
+ Root = 3
+ };
+
+ DolphinView::Mode m_defaultMode;
+ bool m_isViewSplit;
+ bool m_isURLEditable;
+ bool m_isSaveView;
+ KURL m_homeURL;
+ DolphinIconsViewSettings* m_iconsView;
+ DolphinIconsViewSettings* m_previewsView;
+ DolphinDetailsViewSettings* m_detailsView;
+ leftSidebarSettings* m_leftsidebar;
+ rightSidebarSettings* m_rightsidebar;
+};
+
+#endif
diff --git a/src/dolphinsettingsbase.cpp b/src/dolphinsettingsbase.cpp
new file mode 100644
index 0000000..c65297c
--- /dev/null
+++ b/src/dolphinsettingsbase.cpp
@@ -0,0 +1,31 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "dolphinsettingsbase.h"
+
+DolphinSettingsBase::DolphinSettingsBase()
+{
+}
+
+DolphinSettingsBase::~DolphinSettingsBase()
+{
+}
+
+
diff --git a/src/dolphinsettingsbase.h b/src/dolphinsettingsbase.h
new file mode 100644
index 0000000..2c2482e
--- /dev/null
+++ b/src/dolphinsettingsbase.h
@@ -0,0 +1,43 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+#ifndef DOLPHINSETTINGSBASE_H
+#define DOLPHINSETTINGSBASE_H
+
+/**
+ * @brief Base class for all Dolphin settings.
+ *
+ * Derived classes must implement the method
+ * DolphinSettingsBase::save().
+ *
+ * @author Peter Penz <[email protected]>
+ */
+// TODO: design this base class as Composite pattern,
+// as settings might contain other settings
+class DolphinSettingsBase
+{
+public:
+ DolphinSettingsBase();
+
+ virtual ~DolphinSettingsBase();
+
+ virtual void save() = 0;
+};
+
+#endif
diff --git a/src/dolphinsettingsdialog.cpp b/src/dolphinsettingsdialog.cpp
new file mode 100644
index 0000000..4bed70b
--- /dev/null
+++ b/src/dolphinsettingsdialog.cpp
@@ -0,0 +1,77 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "dolphinsettingsdialog.h"
+#include <klocale.h>
+#include <kiconloader.h>
+#include "generalsettingspage.h"
+#include "viewsettingspage.h"
+#include "bookmarkssettingspage.h"
+#include "dolphin.h"
+
+DolphinSettingsDialog::DolphinSettingsDialog() :
+ KDialogBase(IconList, i18n("D3lphin Preferences"),
+ Ok|Apply|Cancel, Ok)
+{
+ KIconLoader iconLoader;
+ QFrame* generalSettingsFrame = addPage(i18n("General"), 0,
+ iconLoader.loadIcon("exec",
+ KIcon::NoGroup,
+ KIcon::SizeMedium));
+ m_generalSettingsPage = new GeneralSettingsPage(generalSettingsFrame);
+
+ QFrame* viewSettingsFrame = addPage(i18n("View Modes"), 0,
+ iconLoader.loadIcon("view_choose",
+ KIcon::NoGroup,
+ KIcon::SizeMedium));
+ m_viewSettingsPage = new ViewSettingsPage(viewSettingsFrame);
+
+ QFrame* bookmarksSettingsFrame = addPage(i18n("Bookmarks"), 0,
+ iconLoader.loadIcon("bookmark",
+ KIcon::NoGroup,
+ KIcon::SizeMedium));
+ m_bookmarksSettingsPage = new BookmarksSettingsPage(bookmarksSettingsFrame);
+}
+
+DolphinSettingsDialog::~DolphinSettingsDialog()
+{
+}
+
+void DolphinSettingsDialog::slotOk()
+{
+ applySettings();
+ KDialogBase::slotOk();
+}
+
+void DolphinSettingsDialog::slotApply()
+{
+ applySettings();
+ KDialogBase::slotApply();
+}
+
+void DolphinSettingsDialog::applySettings()
+{
+ m_generalSettingsPage->applySettings();
+ m_viewSettingsPage->applySettings();
+ m_bookmarksSettingsPage->applySettings();
+ Dolphin::mainWin().refreshViews();
+}
+
+#include "dolphinsettingsdialog.moc"
diff --git a/src/dolphinsettingsdialog.h b/src/dolphinsettingsdialog.h
new file mode 100644
index 0000000..7b8023d
--- /dev/null
+++ b/src/dolphinsettingsdialog.h
@@ -0,0 +1,56 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef DOLPHINSETTINGSDIALOG_H
+#define DOLPHINSETTINGSDIALOG_H
+
+#include <kdialogbase.h>
+class GeneralSettingsPage;
+class ViewSettingsPage;
+class BookmarksSettingsPage;
+
+/**
+ * @brief Settings dialog for Dolphin.
+ *
+ * Contains the pages for general settings, view settings and
+ * bookmark settings.
+ *
+ * @author Peter Penz <[email protected]>
+ */
+class DolphinSettingsDialog : public KDialogBase {
+ Q_OBJECT
+
+public:
+ DolphinSettingsDialog();
+ virtual ~DolphinSettingsDialog();
+
+protected slots:
+ virtual void slotOk();
+ virtual void slotApply();
+
+private:
+ GeneralSettingsPage* m_generalSettingsPage;
+ ViewSettingsPage* m_viewSettingsPage;
+ BookmarksSettingsPage* m_bookmarksSettingsPage;
+
+ void applySettings();
+};
+
+#endif
diff --git a/src/dolphinstatusbar.cpp b/src/dolphinstatusbar.cpp
new file mode 100644
index 0000000..cfa5fb4
--- /dev/null
+++ b/src/dolphinstatusbar.cpp
@@ -0,0 +1,166 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "dolphinstatusbar.h"
+#include <kprogress.h>
+#include <qlabel.h>
+#include <qtimer.h>
+#include <kiconloader.h>
+
+#include "dolphinview.h"
+#include "statusbarmessagelabel.h"
+#include "statusbarspaceinfo.h"
+
+DolphinStatusBar::DolphinStatusBar(DolphinView* parent) :
+ QHBox(parent),
+ m_messageLabel(0),
+ m_spaceInfo(0),
+ m_progressBar(0),
+ m_progress(100)
+{
+ m_messageLabel = new StatusBarMessageLabel(this);
+ m_messageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
+
+ m_spaceInfo = new StatusBarSpaceInfo(this);
+ m_spaceInfo->setURL(parent->url());
+
+ m_progressText = new QLabel(this);
+ m_progressText->hide();
+
+ m_progressBar = new KProgress(this);
+ m_progressBar->hide();
+
+ m_progressTimer = new QTimer(this);
+ connect(m_progressTimer, SIGNAL(timeout()),
+ this, SLOT(slotProgressTimer()));
+
+ const QSize size(m_progressBar->sizeHint());
+ m_progressBar->setMaximumWidth(size.width());
+ setMinimumHeight(size.height());
+ m_messageLabel->setMinimumTextHeight(size.height());
+
+ connect(parent, SIGNAL(signalURLChanged(const KURL&)),
+ this, SLOT(slotURLChanged(const KURL&)));
+}
+
+
+DolphinStatusBar::~DolphinStatusBar()
+{
+}
+
+void DolphinStatusBar::setMessage(const QString& msg,
+ Type type)
+{
+ m_messageLabel->setText(msg);
+ if (msg.isEmpty() || (msg == m_defaultText)) {
+ type = Default;
+ }
+ m_messageLabel->setType(type);
+
+ if ((type == Error) && (m_progress < 100)) {
+ // If an error message is shown during a progress is ongoing,
+ // the (never finishing) progress information should be hidden immediately
+ // (invoking 'setProgress(100)' only leads to a delayed hiding).
+ m_progressBar->hide();
+ m_progressText->hide();
+ setProgress(100);
+ }
+}
+
+DolphinStatusBar::Type DolphinStatusBar::type() const
+{
+ return m_messageLabel->type();
+}
+
+QString DolphinStatusBar::message() const
+{
+ return m_messageLabel->text();
+}
+
+void DolphinStatusBar::setProgressText(const QString& text)
+{
+ m_progressText->setText(text);
+}
+
+QString DolphinStatusBar::progressText() const
+{
+ return m_progressText->text();
+}
+
+void DolphinStatusBar::setProgress(int percent)
+{
+ if (percent < 0) {
+ percent = 0;
+ }
+ else if (percent > 100) {
+ percent = 100;
+ }
+
+ m_progress = percent;
+ m_progressBar->setProgress(m_progress);
+ m_progressTimer->start(300, true);
+
+ const QString msg(m_messageLabel->text());
+ if (msg.isEmpty() || (msg == m_defaultText)) {
+ if (percent == 0) {
+ m_messageLabel->setText(QString::null);
+ m_messageLabel->setType(Default);
+ }
+ else if (percent == 100) {
+ m_messageLabel->setText(m_defaultText);
+ }
+ }
+}
+
+void DolphinStatusBar::clear()
+{
+ // TODO: check for timeout, so that it's prevented that
+ // a message is cleared too early.
+ m_messageLabel->setText(m_defaultText);
+ m_messageLabel->setType(Default);
+}
+
+void DolphinStatusBar::setDefaultText(const QString& text)
+{
+ m_defaultText = text;
+}
+
+void DolphinStatusBar::slotProgressTimer()
+{
+ if (m_progress < 100) {
+ // progress should be shown
+ m_progressBar->show();
+ m_progressText->show();
+ m_spaceInfo->hide();
+ }
+ else {
+ // progress should not be shown anymore
+ m_progressBar->hide();
+ m_progressText->hide();
+ m_spaceInfo->show();
+ }
+}
+
+void DolphinStatusBar::slotURLChanged(const KURL& url)
+{
+ m_spaceInfo->setURL(url);
+}
+
+#include "dolphinstatusbar.moc"
diff --git a/src/dolphinstatusbar.h b/src/dolphinstatusbar.h
new file mode 100644
index 0000000..e4e3e8d
--- /dev/null
+++ b/src/dolphinstatusbar.h
@@ -0,0 +1,133 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef DOLPHINSTATUSBAR_H
+#define DOLPHINSTATUSBAR_H
+
+#include <qhbox.h>
+class KProgress;
+class QLabel;
+class QTimer;
+class StatusBarMessageLabel;
+class StatusBarSpaceInfo;
+class DolphinView;
+class KURL;
+
+/**
+ * @brief Represents the statusbar of a Dolphin view.
+ *
+ * The statusbar allows to show messages and progress
+ * information.
+ *
+ * @author Peter Penz
+ */
+class DolphinStatusBar : public QHBox {
+ Q_OBJECT
+
+public:
+ /**
+ * Describes the type of the message text. Dependent
+ * from the type a corresponding icon and color is
+ * used for the message text.
+ */
+ enum Type {
+ Default,
+ OperationCompleted,
+ Information,
+ Error
+ };
+
+ DolphinStatusBar(DolphinView* parent = 0);
+ virtual ~DolphinStatusBar();
+
+ /**
+ * Sets the message text to \a msg. Dependant
+ * from the given type \a type an icon is shown and
+ * the color of the text is adjusted. The height of
+ * the statusbar is automatically adjusted in a way,
+ * that the full text fits into the available width.
+ *
+ * If a progress is ongoing and a message
+ * with the type Type::Error is set, the progress
+ * is cleared automatically.
+ */
+ void setMessage(const QString& msg, Type type);
+
+ QString message() const;
+ Type type() const;
+
+ /**
+ * Sets the text for the progress information.
+ * The text is shown with a delay of 300 milliseconds:
+ * if the progress set by DolphinStatusBar::setProgress()
+ * does reach 100 % within 300 milliseconds,
+ * the progress text is not shown at all. This assures that
+ * no flickering occurs for showing a progress of fast
+ * operations.
+ */
+ void setProgressText(const QString& text);
+ QString progressText() const;
+
+ /**
+ * Sets the progress in percent (0 - 100). The
+ * progress is shown with a delay of 300 milliseconds:
+ * if the progress does reach 100 % within 300 milliseconds,
+ * the progress is not shown at all. This assures that
+ * no flickering occurs for showing a progress of fast
+ * operations.
+ */
+ void setProgress(int percent);
+ int progress() const { return m_progress; }
+
+ /**
+ * Clears the message text of the status bar by replacing
+ * the message with the default text, which can be set
+ * by DolphinStatusBar::setDefaultText(). The progress
+ * information is not cleared.
+ */
+ void clear();
+
+ /**
+ * Sets the default text, which is shown if the status bar
+ * is cleared by DolphinStatusBar::clear().
+ */
+ void setDefaultText(const QString& text);
+ const QString& defaultText() const { return m_defaultText; }
+
+private slots:
+ void slotProgressTimer();
+
+ /**
+ * Is invoked, when the URL of the DolphinView, where the
+ * statusbar belongs too, has been changed.
+ */
+ void slotURLChanged(const KURL& url);
+
+private:
+ StatusBarMessageLabel* m_messageLabel;
+ StatusBarSpaceInfo* m_spaceInfo;
+ QLabel* m_progressText;
+ KProgress* m_progressBar;
+ QTimer* m_progressTimer;
+ int m_progress;
+ QString m_defaultText;
+};
+
+#endif
diff --git a/src/dolphinview.cpp b/src/dolphinview.cpp
new file mode 100644
index 0000000..7bf57f0
--- /dev/null
+++ b/src/dolphinview.cpp
@@ -0,0 +1,1065 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz <[email protected]> *
+ * Copyright (C) 2006 by Gregor Kališnik <[email protected]> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "dolphinview.h"
+
+#include <qlayout.h>
+#include <kurl.h>
+#include <klocale.h>
+#include <kio/netaccess.h>
+#include <kio/renamedlg.h>
+#include <assert.h>
+
+#include "urlnavigator.h"
+#include "dolphinstatusbar.h"
+#include "dolphin.h"
+#include "dolphindirlister.h"
+#include "viewproperties.h"
+#include "dolphindetailsview.h"
+#include "dolphiniconsview.h"
+#include "dolphincontextmenu.h"
+#include "undomanager.h"
+#include "renamedialog.h"
+#include "progressindicator.h"
+
+#include "filterbar.h"
+
+DolphinView::DolphinView(QWidget *parent,
+ const KURL& url,
+ Mode mode,
+ bool showHiddenFiles) :
+ QWidget(parent),
+ m_refreshing(false),
+ m_showProgress(false),
+ m_mode(mode),
+ m_iconsView(0),
+ m_detailsView(0),
+ m_statusBar(0),
+ m_iconSize(0),
+ m_folderCount(0),
+ m_fileCount(0),
+ m_filterBar(0)
+{
+ setFocusPolicy(QWidget::StrongFocus);
+ m_topLayout = new QVBoxLayout(this);
+
+ Dolphin& dolphin = Dolphin::mainWin();
+
+ connect(this, SIGNAL(signalModeChanged()),
+ &dolphin, SLOT(slotViewModeChanged()));
+ connect(this, SIGNAL(signalShowHiddenFilesChanged()),
+ &dolphin, SLOT(slotShowHiddenFilesChanged()));
+ connect(this, SIGNAL(signalSortingChanged(DolphinView::Sorting)),
+ &dolphin, SLOT(slotSortingChanged(DolphinView::Sorting)));
+ connect(this, SIGNAL(signalSortOrderChanged(Qt::SortOrder)),
+ &dolphin, SLOT(slotSortOrderChanged(Qt::SortOrder)));
+
+ m_urlNavigator = new URLNavigator(url, this);
+ connect(m_urlNavigator, SIGNAL(urlChanged(const KURL&)),
+ this, SLOT(slotURLChanged(const KURL&)));
+ connect(m_urlNavigator, SIGNAL(urlChanged(const KURL&)),
+ &dolphin, SLOT(slotURLChanged(const KURL&)));
+ connect(m_urlNavigator, SIGNAL(historyChanged()),
+ &dolphin, SLOT(slotHistoryChanged()));
+
+ m_statusBar = new DolphinStatusBar(this);
+
+ m_dirLister = new DolphinDirLister();
+ m_dirLister->setAutoUpdate(true);
+ m_dirLister->setMainWindow(this);
+ m_dirLister->setShowingDotFiles(showHiddenFiles);
+ connect(m_dirLister, SIGNAL(clear()),
+ this, SLOT(slotClear()));
+ connect(m_dirLister, SIGNAL(percent(int)),
+ this, SLOT(slotPercent(int)));
+ connect(m_dirLister, SIGNAL(deleteItem(KFileItem*)),
+ this, SLOT(slotDeleteItem(KFileItem*)));
+ connect(m_dirLister, SIGNAL(completed()),
+ this, SLOT(slotCompleted()));
+ connect(m_dirLister, SIGNAL(infoMessage(const QString&)),
+ this, SLOT(slotInfoMessage(const QString&)));
+ connect(m_dirLister, SIGNAL(errorMessage(const QString&)),
+ this, SLOT(slotErrorMessage(const QString&)));
+ connect(m_dirLister, SIGNAL(refreshItems (const KFileItemList&)),
+ this, SLOT(slotRefreshItems(const KFileItemList&)));
+ connect(m_dirLister, SIGNAL(newItems(const KFileItemList&)),
+ this, SLOT(slotAddItems(const KFileItemList&)));
+
+ m_iconSize = KIcon::SizeMedium;
+
+ m_topLayout->addWidget(m_urlNavigator);
+ createView();
+
+ m_filterBar = new FilterBar(this);
+ m_filterBar->hide();
+ m_topLayout->addWidget(m_filterBar);
+ connect(m_filterBar, SIGNAL(signalFilterChanged(const QString&)),
+ this, SLOT(slotChangeNameFilter(const QString&)));
+
+ m_topLayout->addWidget(m_statusBar);
+}
+
+DolphinView::~DolphinView()
+{
+ delete m_dirLister;
+ m_dirLister = 0;
+}
+
+void DolphinView::setURL(const KURL& url)
+{
+ m_urlNavigator->setURL(url);
+}
+
+const KURL& DolphinView::url() const
+{
+ return m_urlNavigator->url();
+}
+
+void DolphinView::requestActivation()
+{
+ Dolphin::mainWin().setActiveView(this);
+}
+
+bool DolphinView::isActive() const
+{
+ return (Dolphin::mainWin().activeView() == this);
+}
+
+void DolphinView::setMode(Mode mode)
+{
+ if (mode == m_mode) {
+ return; // the wished mode is already set
+ }
+
+ QWidget* view = (m_iconsView != 0) ? static_cast<QWidget*>(m_iconsView) :
+ static_cast<QWidget*>(m_detailsView);
+ if (view != 0) {
+ m_topLayout->remove(view);
+ view->close();
+ view->deleteLater();
+ m_iconsView = 0;
+ m_detailsView = 0;
+ }
+
+ m_mode = mode;
+
+ createView();
+
+ ViewProperties props(m_urlNavigator->url());
+ props.setViewMode(m_mode);
+
+ emit signalModeChanged();
+}
+
+DolphinView::Mode DolphinView::mode() const
+{
+ return m_mode;
+}
+
+void DolphinView::setShowHiddenFilesEnabled(bool show)
+{
+ if (m_dirLister->showingDotFiles() == show) {
+ return;
+ }
+
+ ViewProperties props(m_urlNavigator->url());
+ props.setShowHiddenFilesEnabled(show);
+ props.save();
+
+ m_dirLister->setShowingDotFiles(show);
+
+ emit signalShowHiddenFilesChanged();
+
+ reload();
+}
+
+bool DolphinView::isShowHiddenFilesEnabled() const
+{
+ return m_dirLister->showingDotFiles();
+}
+
+void DolphinView::setViewProperties(const ViewProperties& props)
+{
+ setMode(props.viewMode());
+ setSorting(props.sorting());
+ setSortOrder(props.sortOrder());
+ setShowHiddenFilesEnabled(props.isShowHiddenFilesEnabled());
+}
+
+void DolphinView::renameSelectedItems()
+{
+ const KURL::List urls = selectedURLs();
+ if (urls.count() > 1) {
+ // More than one item has been selected for renaming. Open
+ // a rename dialog and rename all items afterwards.
+ RenameDialog dialog(urls);
+ if (dialog.exec() == QDialog::Rejected) {
+ return;
+ }
+
+ DolphinView* view = Dolphin::mainWin().activeView();
+ const QString& newName = dialog.newName();
+ if (newName.isEmpty()) {
+ view->statusBar()->setMessage(i18n("The new item name is invalid."),
+ DolphinStatusBar::Error);
+ }
+ else {
+ UndoManager& undoMan = UndoManager::instance();
+ undoMan.beginMacro();
+
+ assert(newName.contains('#'));
+
+ const int urlsCount = urls.count();
+ ProgressIndicator* progressIndicator =
+ new ProgressIndicator(i18n("Renaming items..."),
+ i18n("Renaming finished."),
+ urlsCount);
+
+ // iterate through all selected items and rename them...
+ const int replaceIndex = newName.find('#');
+ assert(replaceIndex >= 0);
+ for (int i = 0; i < urlsCount; ++i) {
+ const KURL& source = urls[i];
+ QString name(newName);
+ name.replace(replaceIndex, 1, renameIndexPresentation(i + 1, urlsCount));
+
+ if (source.fileName() != name) {
+ KURL dest(source.upURL());
+ dest.addPath(name);
+
+ const bool destExists = KIO::NetAccess::exists(dest, false, view);
+ if (destExists) {
+ delete progressIndicator;
+ progressIndicator = 0;
+ view->statusBar()->setMessage(i18n("Renaming failed (item '%1' already exists).").arg(name),
+ DolphinStatusBar::Error);
+ break;
+ }
+ else if (KIO::NetAccess::file_move(source, dest)) {
+ // TODO: From the users point of view he executed one 'rename n files' operation,
+ // but internally we store it as n 'rename 1 file' operations for the undo mechanism.
+ DolphinCommand command(DolphinCommand::Rename, source, dest);
+ undoMan.addCommand(command);
+ }
+ }
+
+ progressIndicator->execOperation();
+ }
+ delete progressIndicator;
+ progressIndicator = 0;
+
+ undoMan.endMacro();
+ }
+ }
+ else {
+ // Only one item has been selected for renaming. Use the custom
+ // renaming mechanism from the views.
+ assert(urls.count() == 1);
+ if (m_mode == DetailsView) {
+ QListViewItem* item = m_detailsView->firstChild();
+ while (item != 0) {
+ if (item->isSelected()) {
+ m_detailsView->rename(item, DolphinDetailsView::NameColumn);
+ break;
+ }
+ item = item->nextSibling();
+ }
+ }
+ else {
+ KFileIconViewItem* item = static_cast<KFileIconViewItem*>(m_iconsView->firstItem());
+ while (item != 0) {
+ if (item->isSelected()) {
+ item->rename();
+ break;
+ }
+ item = static_cast<KFileIconViewItem*>(item->nextItem());
+ }
+ }
+ }
+}
+
+void DolphinView::selectAll()
+{
+ fileView()->selectAll();
+}
+
+void DolphinView::invertSelection()
+{
+ fileView()->invertSelection();
+}
+
+DolphinStatusBar* DolphinView::statusBar() const
+{
+ return m_statusBar;
+}
+
+int DolphinView::contentsX() const
+{
+ return scrollView()->contentsX();
+}
+
+int DolphinView::contentsY() const
+{
+ return scrollView()->contentsY();
+}
+
+void DolphinView::refreshSettings()
+{
+ if (m_iconsView != 0) {
+ m_iconsView->refreshSettings();
+ }
+
+ if (m_detailsView != 0) {
+ // TODO: There is no usable interface in QListView/KFileDetailView
+ // to hide/show columns. The easiest approach is to delete
+ // the current instance and recreate a new one, which automatically
+ // refreshs the settings. If a proper interface is available in Qt4
+ // m_detailsView->refreshSettings() would be enough.
+ m_topLayout->remove(m_detailsView);
+ m_detailsView->close();
+ m_detailsView->deleteLater();
+ m_detailsView = 0;
+
+ createView();
+ }
+}
+
+void DolphinView::updateStatusBar()
+{
+ // As the item count information is less important
+ // in comparison with other messages, it should only
+ // be shown if:
+ // - the status bar is empty or
+ // - shows already the item count information or
+ // - shows only a not very important information
+ // - if any progress is given don't show the item count info at all
+ const QString msg(m_statusBar->message());
+ const bool updateStatusBarMsg = (msg.isEmpty() ||
+ (msg == m_statusBar->defaultText()) ||
+ (m_statusBar->type() == DolphinStatusBar::Information)) &&
+ (m_statusBar->progress() == 100);
+
+ const QString text(hasSelection() ? selectionStatusBarText() : defaultStatusBarText());
+ m_statusBar->setDefaultText(text);
+
+ if (updateStatusBarMsg) {
+ m_statusBar->setMessage(text, DolphinStatusBar::Default);
+ }
+}
+
+void DolphinView::requestItemInfo(const KURL& url)
+{
+ emit signalRequestItemInfo(url);
+}
+
+bool DolphinView::isURLEditable() const
+{
+ return m_urlNavigator->isURLEditable();
+}
+
+void DolphinView::zoomIn()
+{
+ itemEffectsManager()->zoomIn();
+}
+
+void DolphinView::zoomOut()
+{
+ itemEffectsManager()->zoomOut();
+}
+
+bool DolphinView::isZoomInPossible() const
+{
+ return itemEffectsManager()->isZoomInPossible();
+}
+
+bool DolphinView::isZoomOutPossible() const
+{
+ return itemEffectsManager()->isZoomOutPossible();
+}
+
+void DolphinView::setSorting(Sorting sorting)
+{
+ if (sorting != this->sorting()) {
+ KFileView* view = fileView();
+ int spec = view->sorting() & ~QDir::Name & ~QDir::Size & ~QDir::Time & ~QDir::Unsorted;
+
+ switch (sorting) {
+ case SortByName: spec = spec | QDir::Name; break;
+ case SortBySize: spec = spec | QDir::Size; break;
+ case SortByDate: spec = spec | QDir::Time; break;
+ default: break;
+ }
+
+ ViewProperties props(url());
+ props.setSorting(sorting);
+
+ view->setSorting(static_cast<QDir::SortSpec>(spec));
+
+ emit signalSortingChanged(sorting);
+ }
+}
+
+DolphinView::Sorting DolphinView::sorting() const
+{
+ const QDir::SortSpec spec = fileView()->sorting();
+
+ if (spec & QDir::Time) {
+ return SortByDate;
+ }
+
+ if (spec & QDir::Size) {
+ return SortBySize;
+ }
+
+ return SortByName;
+}
+
+void DolphinView::setSortOrder(Qt::SortOrder order)
+{
+ if (sortOrder() != order) {
+ KFileView* view = fileView();
+ int sorting = view->sorting();
+ sorting = (order == Qt::Ascending) ? (sorting & ~QDir::Reversed) :
+ (sorting | QDir::Reversed);
+
+ ViewProperties props(url());
+ props.setSortOrder(order);
+
+ view->setSorting(static_cast<QDir::SortSpec>(sorting));
+
+ emit signalSortOrderChanged(order);
+ }
+}
+
+Qt::SortOrder DolphinView::sortOrder() const
+{
+ return fileView()->isReversed() ? Qt::Descending : Qt::Ascending;
+}
+
+void DolphinView::goBack()
+{
+ m_urlNavigator->goBack();
+}
+
+void DolphinView::goForward()
+{
+ m_urlNavigator->goForward();
+}
+
+void DolphinView::goUp()
+{
+ m_urlNavigator->goUp();
+}
+
+void DolphinView::goHome()
+{
+ m_urlNavigator->goHome();
+}
+
+void DolphinView::setURLEditable(bool editable)
+{
+ m_urlNavigator->setURLEditable(editable);
+}
+
+void DolphinView::editURL()
+{
+ m_urlNavigator->editURL();
+}
+
+const QValueList<URLNavigator::HistoryElem> DolphinView::urlHistory(int& index) const
+{
+ return m_urlNavigator->history(index);
+}
+
+bool DolphinView::hasSelection() const
+{
+ const KFileItemList* list = selectedItems();
+ return (list != 0) && !list->isEmpty();
+}
+
+const KFileItemList* DolphinView::selectedItems() const
+{
+ return fileView()->selectedItems();
+}
+
+KURL::List DolphinView::selectedURLs() const
+{
+ KURL::List urls;
+
+ const KFileItemList* list = fileView()->selectedItems();
+ if (list != 0) {
+ KFileItemListIterator it(*list);
+ KFileItem* item = 0;
+ while ((item = it.current()) != 0) {
+ urls.append(item->url());
+ ++it;
+ }
+ }
+
+ return urls;
+}
+
+const KFileItem* DolphinView::currentFileItem() const
+{
+ return fileView()->currentFileItem();
+}
+
+void DolphinView::openContextMenu(KFileItem* fileInfo, const QPoint& pos)
+{
+ DolphinContextMenu contextMenu(this, fileInfo, pos);
+ contextMenu.open();
+}
+
+void DolphinView::rename(const KURL& source, const QString& newName)
+{
+ bool ok = false;
+
+ if (newName.isEmpty() || (source.fileName() == newName)) {
+ return;
+ }
+
+ KURL dest(source.upURL());
+ dest.addPath(newName);
+
+ const bool destExists = KIO::NetAccess::exists(dest,
+ false,
+ Dolphin::mainWin().activeView());
+ if (destExists) {
+ // the destination already exists, hence ask the user
+ // how to proceed...
+ KIO::RenameDlg renameDialog(this,
+ i18n("File Already Exists"),
+ source.path(),
+ dest.path(),
+ KIO::M_OVERWRITE);
+ switch (renameDialog.exec()) {
+ case KIO::R_OVERWRITE:
+ // the destination should be overwritten
+ ok = KIO::NetAccess::file_move(source, dest, -1, true);
+ break;
+
+ case KIO::R_RENAME: {
+ // a new name for the destination has been used
+ KURL newDest(renameDialog.newDestURL());
+ ok = KIO::NetAccess::file_move(source, newDest);
+ break;
+ }
+
+ default:
+ // the renaming operation has been canceled
+ reload();
+ return;
+ }
+ }
+ else {
+ // no destination exists, hence just move the file to
+ // do the renaming
+ ok = KIO::NetAccess::file_move(source, dest);
+ }
+
+ if (ok) {
+ m_statusBar->setMessage(i18n("Renamed file '%1' to '%2'.").arg(source.fileName(), dest.fileName()),
+ DolphinStatusBar::OperationCompleted);
+
+ DolphinCommand command(DolphinCommand::Rename, source, dest);
+ UndoManager::instance().addCommand(command);
+ }
+ else {
+ m_statusBar->setMessage(i18n("Renaming of file '%1' to '%2' failed.").arg(source.fileName(), dest.fileName()),
+ DolphinStatusBar::Error);
+ reload();
+ }
+}
+
+void DolphinView::reload()
+{
+ startDirLister(m_urlNavigator->url(), true);
+}
+
+void DolphinView::slotURLListDropped(QDropEvent* /* event */,
+ const KURL::List& urls,
+ const KURL& url)
+{
+ KURL destination(url);
+ if (destination.isEmpty()) {
+ destination = m_urlNavigator->url();
+ }
+ else {
+ // Check whether the destination URL is a directory. If this is not the
+ // case, use the navigator URL as destination (otherwise the destination,
+ // which represents a file, would be replaced by a copy- or move-operation).
+ KFileItem fileItem(KFileItem::Unknown, KFileItem::Unknown, destination);
+ if (!fileItem.isDir()) {
+ destination = m_urlNavigator->url();
+ }
+ }
+
+ Dolphin::mainWin().dropURLs(urls, destination);
+}
+
+void DolphinView::mouseReleaseEvent(QMouseEvent* event)
+{
+ QWidget::mouseReleaseEvent(event);
+ Dolphin::mainWin().setActiveView(this);
+}
+
+void DolphinView::slotURLChanged(const KURL& url)
+{
+ const ViewProperties props(url);
+ setMode(props.viewMode());
+
+ const bool showHiddenFiles = props.isShowHiddenFilesEnabled();
+ setShowHiddenFilesEnabled(showHiddenFiles);
+ m_dirLister->setShowingDotFiles(showHiddenFiles);
+
+ setSorting(props.sorting());
+ setSortOrder(props.sortOrder());
+
+ startDirLister(url);
+
+ // The selectionChanged signal is not emitted when a new view object is
+ // created. The application does not care whether a view is represented by a
+ // different instance, hence inform the application that the selection might have
+ // changed so that it can update it's actions.
+ Dolphin::mainWin().slotSelectionChanged();
+
+ emit signalURLChanged(url);
+}
+
+void DolphinView::triggerIconsViewItem(QIconViewItem* item)
+{
+ const ButtonState keyboardState = KApplication::keyboardMouseState();
+ const bool isSelectionActive = ((keyboardState & ShiftButton) > 0) ||
+ ((keyboardState & ControlButton) > 0);
+ if ((item != 0) && !isSelectionActive) {
+ // Updating the URL must be done outside the scope of this slot,
+ // as iconview items will get deleted.
+ QTimer::singleShot(0, this, SLOT(updateURL()));
+ Dolphin::mainWin().setActiveView(this);
+ }
+}
+
+void DolphinView::triggerDetailsViewItem(QListViewItem* item,
+ const QPoint& pos,
+ int /* column */)
+{
+ if (item == 0) {
+ return;
+ }
+
+ if (m_detailsView->isOnFilename(item, pos)) {
+ // Updating the URL must be done outside the scope of this slot,
+ // as listview items will get deleted.
+ QTimer::singleShot(0, this, SLOT(updateURL()));
+ Dolphin::mainWin().setActiveView(this);
+ }
+ else {
+ m_detailsView->clearSelection();
+ }
+}
+
+void DolphinView::triggerDetailsViewItem(QListViewItem* item)
+{
+ const QPoint pos(0, item->itemPos());
+ triggerDetailsViewItem(item, pos, 0);
+}
+
+void DolphinView::updateURL()
+{
+ KFileView* fileView = (m_iconsView != 0) ? static_cast<KFileView*>(m_iconsView) :
+ static_cast<KFileView*>(m_detailsView);
+
+ KFileItem* fileItem = fileView->currentFileItem();
+ if (fileItem == 0) {
+ return;
+ }
+
+ if (fileItem->isDir()) {
+ // Prefer the local path over the URL. This assures that the
+ // volume space information is correct. Assuming that the URL is media:/sda1,
+ // and the local path is /windows/C: For the URL the space info is related
+ // to the root partition (and hence wrong) and for the local path the space
+ // info is related to the windows partition (-> correct).
+ const QString localPath(fileItem->localPath());
+ if (localPath.isEmpty()) {
+ setURL(fileItem->url());
+ }
+ else {
+ setURL(KURL(localPath));
+ }
+ }
+ else if (fileItem->isFile()) {
+ // allow to browse through ZIP and tar files
+ KMimeType::Ptr mime = fileItem->mimeTypePtr();
+ if (mime->is("application/x-zip")) {
+ KURL url = fileItem->url();
+ url.setProtocol("zip");
+ setURL(url);
+ }
+ else if (mime->is("application/x-tar") ||
+ mime->is("application/x-tarz") ||
+ mime->is("application/x-tbz") ||
+ mime->is("application/x-tgz") ||
+ mime->is("application/x-tzo")) {
+ KURL url = fileItem->url();
+ url.setProtocol("tar");
+ setURL(url);
+ }
+ else {
+ fileItem->run();
+ }
+ }
+ else {
+ fileItem->run();
+ }
+}
+
+void DolphinView::slotPercent(int percent)
+{
+ if (m_showProgress) {
+ m_statusBar->setProgress(percent);
+ }
+}
+
+void DolphinView::slotClear()
+{
+ fileView()->clearView();
+ updateStatusBar();
+}
+
+void DolphinView::slotDeleteItem(KFileItem* item)
+{
+ fileView()->removeItem(item);
+ updateStatusBar();
+}
+
+void DolphinView::slotCompleted()
+{
+ m_refreshing = true;
+
+ KFileView* view = fileView();
+ view->clearView();
+
+ // TODO: in Qt4 the code should get a lot
+ // simpler and nicer due to Interview...
+ if (m_iconsView != 0) {
+ m_iconsView->beginItemUpdates();
+ }
+ if (m_detailsView != 0) {
+ m_detailsView->beginItemUpdates();
+ }
+
+ if (m_showProgress) {
+ m_statusBar->setProgressText(QString::null);
+ m_statusBar->setProgress(100);
+ m_showProgress = false;
+ }
+
+ KFileItemList items(m_dirLister->items());
+ KFileItemListIterator it(items);
+
+ m_fileCount = 0;
+ m_folderCount = 0;
+
+ KFileItem* item = 0;
+ while ((item = it.current()) != 0) {
+ view->insertItem(item);
+ if (item->isDir()) {
+ ++m_folderCount;
+ }
+ else {
+ ++m_fileCount;
+ }
+ ++it;
+ }
+
+ updateStatusBar();
+
+ if (m_iconsView != 0) {
+ // Prevent a flickering of the icon view widget by giving a small
+ // timeslot to swallow asynchronous update events.
+ m_iconsView->setUpdatesEnabled(false);
+ QTimer::singleShot(10, this, SLOT(slotDelayedUpdate()));
+ }
+
+ if (m_detailsView != 0) {
+ m_detailsView->endItemUpdates();
+ m_refreshing = false;
+ }
+}
+
+void DolphinView::slotDelayedUpdate()
+{
+ if (m_iconsView != 0) {
+ m_iconsView->setUpdatesEnabled(true);
+ m_iconsView->endItemUpdates();
+ }
+ m_refreshing = false;
+}
+
+void DolphinView::slotInfoMessage(const QString& msg)
+{
+ m_statusBar->setMessage(msg, DolphinStatusBar::Information);
+}
+
+void DolphinView::slotErrorMessage(const QString& msg)
+{
+ m_statusBar->setMessage(msg, DolphinStatusBar::Error);
+}
+
+void DolphinView::slotRefreshItems(const KFileItemList& /* list */)
+{
+ QTimer::singleShot(0, this, SLOT(reload()));
+}
+
+void DolphinView::slotAddItems(const KFileItemList& list)
+{
+ fileView()->addItemList(list);
+ fileView()->updateView();
+}
+
+void DolphinView::slotGrabActivation()
+{
+ Dolphin::mainWin().setActiveView(this);
+}
+
+void DolphinView::slotContentsMoving(int x, int y)
+{
+ if (!m_refreshing) {
+ // Only emit a 'contents moved' signal if the user
+ // moved the content by adjusting the sliders. Adjustments
+ // resulted by refreshing a directory should not be respected.
+ emit contentsMoved(x, y);
+ }
+}
+
+void DolphinView::createView()
+{
+ assert(m_iconsView == 0);
+ assert(m_detailsView == 0);
+
+ switch (m_mode) {
+ case IconsView:
+ case PreviewsView: {
+ const DolphinIconsView::LayoutMode layoutMode = (m_mode == IconsView) ?
+ DolphinIconsView::Icons :
+ DolphinIconsView::Previews;
+ m_iconsView = new DolphinIconsView(this, layoutMode);
+ m_topLayout->insertWidget(1, m_iconsView);
+ setFocusProxy(m_iconsView);
+
+ connect(m_iconsView, SIGNAL(executed(QIconViewItem*)),
+ this, SLOT(triggerIconsViewItem(QIconViewItem*)));
+ connect(m_iconsView, SIGNAL(returnPressed(QIconViewItem*)),
+ this, SLOT(triggerIconsViewItem(QIconViewItem*)));
+ connect(m_iconsView, SIGNAL(signalRequestActivation()),
+ this, SLOT(slotGrabActivation()));
+
+ m_iconsView->endItemUpdates();
+ m_iconsView->show();
+ m_iconsView->setFocus();
+ break;
+ }
+
+ case DetailsView: {
+ m_detailsView = new DolphinDetailsView(this);
+ m_topLayout->insertWidget(1, m_detailsView);
+ setFocusProxy(m_detailsView);
+
+ connect(m_detailsView, SIGNAL(executed(QListViewItem*, const QPoint&, int)),
+ this, SLOT(triggerDetailsViewItem(QListViewItem*, const QPoint&, int)));
+ connect(m_detailsView, SIGNAL(returnPressed(QListViewItem*)),
+ this, SLOT(triggerDetailsViewItem(QListViewItem*)));
+ connect(m_detailsView, SIGNAL(signalRequestActivation()),
+ this, SLOT(slotGrabActivation()));
+ m_detailsView->show();
+ m_detailsView->setFocus();
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ connect(scrollView(), SIGNAL(contentsMoving(int, int)),
+ this, SLOT(slotContentsMoving(int, int)));
+
+ startDirLister(m_urlNavigator->url());
+}
+
+KFileView* DolphinView::fileView() const
+{
+ return (m_mode == DetailsView) ? static_cast<KFileView*>(m_detailsView) :
+ static_cast<KFileView*>(m_iconsView);
+}
+
+QScrollView* DolphinView::scrollView() const
+{
+ return (m_mode == DetailsView) ? static_cast<QScrollView*>(m_detailsView) :
+ static_cast<QScrollView*>(m_iconsView);
+}
+
+ItemEffectsManager* DolphinView::itemEffectsManager() const
+{
+ return (m_mode == DetailsView) ? static_cast<ItemEffectsManager*>(m_detailsView) :
+ static_cast<ItemEffectsManager*>(m_iconsView);
+}
+
+void DolphinView::startDirLister(const KURL& url, bool reload)
+{
+ if (!url.isValid()) {
+ const QString location(url.prettyURL());
+ if (location.isEmpty()) {
+ m_statusBar->setMessage(i18n("The location is empty."), DolphinStatusBar::Error);
+ }
+ else {
+ m_statusBar->setMessage(i18n("The location '%1' is invalid.").arg(location),
+ DolphinStatusBar::Error);
+ }
+ return;
+ }
+
+ // Only show the directory loading progress if the status bar does
+ // not contain another progress information. This means that
+ // the directory loading progress information has the lowest priority.
+ const QString progressText(m_statusBar->progressText());
+ m_showProgress = progressText.isEmpty() ||
+ (progressText == i18n("Loading directory..."));
+ if (m_showProgress) {
+ m_statusBar->setProgressText(i18n("Loading directory..."));
+ m_statusBar->setProgress(0);
+ }
+
+ m_refreshing = true;
+ m_dirLister->stop();
+ m_dirLister->openURL(url, false, reload);
+}
+
+QString DolphinView::defaultStatusBarText() const
+{
+ const int itemCount = m_folderCount + m_fileCount;
+
+ QString text = i18n( "1 Item", "%n Items", itemCount );
+ text += i18n(" (1 Folder, ", " (%n Folders, ", m_folderCount );
+ text += i18n("1 File)", "%n Files)", m_fileCount);
+
+ return text;
+}
+
+QString DolphinView::selectionStatusBarText() const
+{
+ QString text;
+ const KFileItemList* list = selectedItems();
+ assert((list != 0) && !list->isEmpty());
+
+ int fileCount = 0;
+ int folderCount = 0;
+ KIO::filesize_t byteSize = 0;
+ for (KFileItemListIterator it(*list); it.current() != 0; ++it) {
+ KFileItem* item = it.current();
+ if (item->isDir()) {
+ ++folderCount;
+ }
+ else {
+ ++fileCount;
+ byteSize += item->size();
+ }
+ }
+
+ if (folderCount>0) {
+ text = i18n("1 Folder selected","%n Folders selected", folderCount);
+ }
+
+ if ((fileCount > 0) && (folderCount > 0)) {
+ text += ", ";
+ }
+
+ if (fileCount > 0) {
+ const QString sizeText(KIO::convertSize(byteSize));
+ text += i18n("1 File selected (%1)", "%n Files selected (%1)", fileCount).arg(sizeText);
+ }
+
+ return text;
+}
+
+QString DolphinView::renameIndexPresentation(int index, int itemCount) const
+{
+ // assure that the string reprentation for all indicess have the same
+ // number of characters based on the given number of items
+ QString str(QString::number(index));
+ int chrCount = 1;
+ while (itemCount >= 10) {
+ ++chrCount;
+ itemCount /= 10;
+ }
+ str.reserve(chrCount);
+
+ const int insertCount = chrCount - str.length();
+ for (int i = 0; i < insertCount; ++i) {
+ str.insert(0, '0');
+ }
+ return str;
+}
+
+void DolphinView::slotShowFilterBar(bool show)
+{
+ assert(m_filterBar != 0);
+ if (show) {
+ m_filterBar->show();
+ }
+ else {
+ m_filterBar->hide();
+ }
+}
+
+void DolphinView::slotChangeNameFilter(const QString& nameFilter)
+{
+ // The name filter of KDirLister does a 'hard' filtering, which
+ // means that only the items are shown where the names match
+ // exactly the filter. This is non-transparent for the user, which
+ // just wants to have a 'soft' filtering: does the name contain
+ // the filter string?
+ QString adjustedFilter(nameFilter);
+ adjustedFilter.insert(0, '*');
+ adjustedFilter.append('*');
+
+ m_dirLister->setNameFilter(adjustedFilter);
+ m_dirLister->emitChanges();
+
+ // TODO: this is a workaround for QIconView: the item position
+ // stay as they are by filtering, only an inserting of an item
+ // results to an automatic adjusting of the item position. In Qt4/KDE4
+ // this workaround should get obsolete due to Interview.
+ KFileView* view = fileView();
+ if (view == m_iconsView) {
+ KFileItem* first = view->firstFileItem();
+ if (first != 0) {
+ view->removeItem(first);
+ view->insertItem(first);
+ }
+ }
+}
+
+bool DolphinView::isFilterBarVisible() const
+{
+ return m_filterBar->isVisible();
+}
+
+#include "dolphinview.moc"
diff --git a/src/dolphinview.h b/src/dolphinview.h
new file mode 100644
index 0000000..d0ad891
--- /dev/null
+++ b/src/dolphinview.h
@@ -0,0 +1,452 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz <[email protected]> *
+ * Copyright (C) 2006 by Gregor Kališnik <[email protected]> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+
+#ifndef _DOLPHINVIEW_H_
+#define _DOLPHINVIEW_H_
+
+#include <qwidget.h>
+#include <kparts/part.h>
+#include <kfileitem.h>
+#include <kfileiconview.h>
+#include <kio/job.h>
+#include <urlnavigator.h>
+
+class QPainter;
+class KURL;
+class QLineEdit;
+class URLNavigator;
+class QTimer;
+class QIconViewItem;
+class QListViewItem;
+class QVBoxLayout;
+class KFileView;
+class Dolphin;
+class DolphinDirLister;
+class DolphinStatusBar;
+class DolphinIconsView;
+class DolphinDetailsView;
+class ViewProperties;
+class QScrollView;
+class KProgress;
+class ItemEffectsManager;
+class FilterBar;
+/**
+ * @short Represents a view for the directory content
+ * including the navigation bar and status bar.
+ *
+ * View modes for icons, details and previews are supported. Currently
+ * Dolphin allows to have up to two views inside the main window.
+ *
+ * @see DolphinIconsView
+ * @see DolphinDetailsView
+ * @see URLNavigator
+ * @see DolphinStatusBar
+ *
+ * @author Peter Penz <[email protected]>
+ */
+class DolphinView : public QWidget
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Defines the view mode for a directory. The view mode
+ * can be defined when constructing a DolphinView. The
+ * view mode is automatically updated if the directory itself
+ * defines a view mode (see class ViewProperties for details).
+ */
+ enum Mode
+ {
+ /**
+ * The directory items are shown as icons including an
+ * icon name. */
+ IconsView = 0,
+
+ /**
+ * The icon, the name and at least the size of the directory
+ * items are shown in a table. It is possible to add columns
+ * for date, group and permissions.
+ */
+ DetailsView = 1,
+
+ /**
+ * The directory items are shown as preview if possible. As
+ * fallback the items are shown as icons.
+ */
+ PreviewsView = 2
+ };
+
+ /** Defines the sort order for the items of a directory. */
+ enum Sorting
+ {
+ SortByName = 0,
+ SortBySize = 1,
+ SortByDate = 2
+ };
+
+ DolphinView(QWidget* parent,
+ const KURL& url,
+ Mode mode = IconsView,
+ bool showHiddenFiles = false);
+
+ virtual ~DolphinView();
+
+ /**
+ * Sets the current active URL.
+ * The signals URLNavigator::urlChanged and URLNavigator::historyChanged
+ * are submitted.
+ */
+ void setURL(const KURL& url);
+
+ /** Returns the current active URL. */
+ const KURL& url() const;
+
+ void requestActivation();
+ bool isActive() const;
+
+ void setMode(Mode mode);
+ Mode mode() const;
+ void setShowHiddenFilesEnabled(bool show);
+ bool isShowHiddenFilesEnabled() const;
+
+ void setViewProperties(const ViewProperties& props);
+
+ /**
+ * Triggers the renaming of the currently selected items, where
+ * the user must input a new name for the items.
+ */
+ void renameSelectedItems();
+
+ /**
+ * Selects all items.
+ * @see DolphinView::selectedItems()
+ */
+ void selectAll();
+
+ /**
+ * Inverts the current selection: selected items get unselected,
+ * unselected items get selected.
+ * @see DolphinView::selectedItems()
+ */
+ void invertSelection();
+
+ /**
+ * Goes back one step in the URL history. The signals
+ * URLNavigator::urlChanged and URLNavigator::historyChanged
+ * are submitted.
+ */
+ void goBack();
+
+ /**
+ * Goes forward one step in the URL history. The signals
+ * URLNavigator::urlChanged and URLNavigator::historyChanged
+ * are submitted.
+ */
+ void goForward();
+
+ /**
+ * Goes up one step of the URL path. The signals
+ * URLNavigator::urlChanged and URLNavigator::historyChanged
+ * are submitted.
+ */
+ void goUp();
+
+ /**
+ * Goes to the home URL. The signals URLNavigator::urlChanged
+ * and URLNavigator::historyChanged are submitted.
+ */
+ void goHome();
+
+ /**
+ * Sets the URL of the navigation bar to an editable state
+ * if \a editable is true. If \a editable is false, each part of
+ * the location is presented by a button for a fast navigation.
+ */
+ void setURLEditable(bool editable);
+
+ /**
+ * Allows to edit the URL of the navigation bar and assures that
+ * the focus is assigned to the URL editor.
+ */
+ void editURL();
+
+ /**
+ * Returns the complete URL history. The index 0 indicates the oldest
+ * history element.
+ * @param index Output parameter which indicates the current
+ * index of the location.
+ */
+ const QValueList<URLNavigator::HistoryElem> urlHistory(int& index) const;
+
+ /**
+ * Returns true, if at least one item is selected.
+ */
+ bool hasSelection() const;
+
+ /**
+ * Returns the selected items. 0 is returned, if no item
+ * is selected.
+ * @see DolphinView::selectedURLs()
+ */
+ const KFileItemList* selectedItems() const;
+
+ /**
+ * Returns a list of URLs for all selected items. An empty list
+ * is returned, if no item is selected.
+ * @see DolphinView::selectedItems()
+ */
+ KURL::List selectedURLs() const;
+
+ /**
+ * Returns the current item, where the cursor is. 0 is returned, if there is no
+ * current item (e. g. if the view is empty). Note that the current item must
+ * not be a selected item.
+ * @see DolphinView::selectedItems()
+ */
+ const KFileItem* currentFileItem() const;
+
+ /**
+ * Opens the context menu for the item indicated by \a fileInfo
+ * on the position \a pos. If 0 is passed for the file info, a context
+ * menu for the viewport is opened.
+ */
+ void openContextMenu(KFileItem* fileInfo, const QPoint& pos);
+
+ /**
+ * Renames the filename of the source URL by the new file name.
+ * If the new file name already exists, a dialog is opened which
+ * asks the user to enter a new name.
+ */
+ void rename(const KURL& source, const QString& newName);
+
+ /** Returns the status bar of the view. */
+ DolphinStatusBar* statusBar() const;
+
+ /**
+ * Returns the x-position of the view content.
+ * The content of the view might be larger than the visible area
+ * and hence a scrolling must be done.
+ */
+ int contentsX() const;
+
+ /**
+ * Returns the y-position of the view content.
+ * The content of the view might be larger than the visible area
+ * and hence a scrolling must be done.
+ */
+ int contentsY() const;
+
+ /**
+ * Returns true, if the URL shown by the navigation bar is editable.
+ * @see URLNavigator
+ */
+ bool isURLEditable() const;
+
+ /** Increases the size of the current set view mode. */
+ void zoomIn();
+
+ /** Decreases the size of the current set view mode. */
+ void zoomOut();
+
+ /**
+ * Returns true, if zooming in is possible. If false is returned,
+ * the minimal zoom size is possible.
+ */
+ bool isZoomInPossible() const;
+
+ /**
+ * Returns true, if zooming out is possible. If false is returned,
+ * the maximum zoom size is possible.
+ */
+ bool isZoomOutPossible() const;
+
+ /** Sets the sort order of the items inside a directory (see DolphinView::Sorting). */
+ void setSorting(Sorting sorting);
+
+ /** Returns the sort order of the items inside a directory (see DolphinView::Sorting). */
+ Sorting sorting() const;
+
+ /** Sets the sort order (Qt::Ascending or Qt::Descending) for the items. */
+ void setSortOrder(Qt::SortOrder order);
+
+ /** Returns the current used sort order (Qt::Ascending or Qt::Descending). */
+ Qt::SortOrder sortOrder() const;
+
+ /** Refreshs the view settings by reading out the stored settings. */
+ void refreshSettings();
+
+ /**
+ * Updates the number of items (= number of files + number of
+ * directories) in the statusbar. If files are selected, the number
+ * of selected files and the sum of the filesize is shown.
+ */
+ void updateStatusBar();
+
+ /** Returns the URLNavigator of the view for read access. */
+ const URLNavigator* urlNavigator() const { return m_urlNavigator; }
+
+ /**
+ * Triggers to request user information for the item given
+ * by the URL \a url. The signal signalRequestItemInfo is emitted,
+ * which provides a way for widgets to get an indication to update
+ * the item information.
+ */
+ void requestItemInfo(const KURL& url);
+
+ /**
+ * Checks if the filter bar is visible.
+ *
+ * @return @c true Filter bar is visible.
+ * @return @c false Filter bar is not visible.
+ */
+ bool isFilterBarVisible() const;
+
+public slots:
+ void reload();
+ void slotURLListDropped(QDropEvent* event,
+ const KURL::List& urls,
+ const KURL& url);
+
+ /**
+ * Slot that popups the filter bar like FireFox popups his Search bar.
+ */
+ void slotShowFilterBar(bool show);
+
+signals:
+ /** Is emitted if URL of the view has been changed to \a url. */
+ void signalURLChanged(const KURL& url);
+
+ /**
+ * Is emitted if the view mode (IconsView, DetailsView,
+ * PreviewsView) has been changed.
+ */
+ void signalModeChanged();
+
+ /** Is emitted if the 'show hidden files' property has been changed. */
+ void signalShowHiddenFilesChanged();
+
+ /** Is emitted if the sorting by name, size or date has been changed. */
+ void signalSortingChanged(DolphinView::Sorting sorting);
+
+ /** Is emitted if the sort order (ascending or descending) has been changed. */
+ void signalSortOrderChanged(Qt::SortOrder order);
+
+ /**
+ * Is emitted if information of an item is requested to be shown e. g. in the sidebar.
+ * It the URL is empty, no item information request is pending.
+ */
+ void signalRequestItemInfo(const KURL& url);
+
+ /** Is emitted if the contents has been moved to \a x, \a y. */
+ void contentsMoved(int x, int y);
+
+ /**
+ * Is emitted whenever the selection has been changed. The current selection can
+ * be retrieved by Dolphin::mainWin().activeView()->selectedItems() or by
+ * Dolphin::mainWin().activeView()->selectedURLs().
+ */
+ void signalSelectionChanged();
+
+protected:
+ /** @see QWidget::mouseReleaseEvent */
+ virtual void mouseReleaseEvent(QMouseEvent* event);
+
+private slots:
+ void slotURLChanged(const KURL& kurl);
+ void triggerIconsViewItem(QIconViewItem *item);
+ void triggerDetailsViewItem(QListViewItem* item,
+ const QPoint& pos,
+ int column);
+ void triggerDetailsViewItem(QListViewItem* item);
+ void updateURL();
+
+ void slotPercent(int percent);
+ void slotClear();
+ void slotDeleteItem(KFileItem* item);
+ void slotCompleted();
+ void slotDelayedUpdate();
+ void slotInfoMessage(const QString& msg);
+ void slotErrorMessage(const QString& msg);
+ void slotRefreshItems(const KFileItemList& list);
+ void slotAddItems(const KFileItemList& list);
+
+ void slotGrabActivation();
+
+ /**
+ * Is invoked shortly before the contents of a view implementation
+ * has been moved and emits the signal contentsMoved. Note that no
+ * signal is emitted when the contents moving is only temporary by
+ * e. g. reloading a directory.
+ */
+ void slotContentsMoving(int x, int y);
+
+ /**
+ * Filters the currently shown items by \a nameFilter. All items
+ * which contain the given filter string will be shown.
+ */
+ void slotChangeNameFilter(const QString& nameFilter);
+
+private:
+ void createView();
+ KFileView* fileView() const;
+ QScrollView* scrollView() const;
+ ItemEffectsManager* itemEffectsManager() const;
+ void startDirLister(const KURL& url, bool reload = false);
+
+ /**
+ * Returns the default text of the status bar, if no item is
+ * selected.
+ */
+ QString defaultStatusBarText() const;
+
+ /**
+ * Returns the text for the status bar, if at least one item
+ * is selected.
+ */
+ QString selectionStatusBarText() const;
+
+ /**
+ * Returns the string representation for the index \a index
+ * for renaming \itemCount items.
+ */
+ QString renameIndexPresentation(int index, int itemCount) const;
+
+ bool m_refreshing;
+ bool m_showProgress;
+ Mode m_mode;
+
+ QVBoxLayout* m_topLayout;
+ URLNavigator* m_urlNavigator;
+
+ DolphinIconsView* m_iconsView;
+ DolphinDetailsView* m_detailsView;
+ DolphinStatusBar* m_statusBar;
+
+ int m_iconSize;
+ int m_folderCount;
+ int m_fileCount;
+
+ DolphinDirLister* m_dirLister;
+
+ FilterBar *m_filterBar;
+};
+
+#endif // _DOLPHINVIEW_H_
diff --git a/src/editbookmarkdialog.cpp b/src/editbookmarkdialog.cpp
new file mode 100644
index 0000000..3d25ce3
--- /dev/null
+++ b/src/editbookmarkdialog.cpp
@@ -0,0 +1,120 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "editbookmarkdialog.h"
+#include <qgrid.h>
+#include <klocale.h>
+#include <qlineedit.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <kiconloader.h>
+#include <qpushbutton.h>
+#include <kurl.h>
+#include <kfiledialog.h>
+#include <kicondialog.h>
+#include <qhbox.h>
+
+EditBookmarkDialog::~EditBookmarkDialog()
+{
+}
+
+KBookmark EditBookmarkDialog::getBookmark(const QString& title,
+ const QString& name,
+ const KURL& url,
+ const QString& icon)
+{
+ EditBookmarkDialog dialog(title, name, url, icon);
+ dialog.exec();
+ return dialog.m_bookmark;
+}
+
+void EditBookmarkDialog::slotOk()
+{
+ m_bookmark = KBookmark::standaloneBookmark(m_name->text(),
+ KURL(m_location->text()),
+ m_iconName);
+
+ KDialogBase::slotOk();
+}
+
+EditBookmarkDialog::EditBookmarkDialog(const QString& title,
+ const QString& name,
+ const KURL& url,
+ const QString& icon) :
+ KDialogBase(Plain, title, Ok|Cancel, Ok),
+ m_iconButton(0),
+ m_name(0),
+ m_location(0)
+{
+ QVBoxLayout* topLayout = new QVBoxLayout(plainPage(), 0, spacingHint());
+
+ QGrid* grid = new QGrid(2, Qt::Horizontal, plainPage());
+ grid->setSpacing(spacingHint());
+
+ // create icon widgets
+ new QLabel(i18n("Icon:"), grid);
+ m_iconName = icon;
+ m_iconButton = new QPushButton(SmallIcon(m_iconName), QString::null, grid);
+ m_iconButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ connect(m_iconButton, SIGNAL(clicked()),
+ this, SLOT(selectIcon()));
+
+ // create name widgets
+ new QLabel(i18n("Name:"), grid);
+ m_name = new QLineEdit(name, grid);
+ m_name->selectAll();
+ m_name->setFocus();
+
+ // create location widgets
+ new QLabel(i18n("Location:"), grid);
+
+ QHBox* locationBox = new QHBox(grid);
+ locationBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+ locationBox->setSpacing(spacingHint());
+ m_location = new QLineEdit(url.prettyURL(), locationBox);
+ m_location->setMinimumWidth(320);
+
+ QPushButton* selectLocationButton = new QPushButton(SmallIcon("folder"), QString::null, locationBox);
+ selectLocationButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ connect(selectLocationButton, SIGNAL(clicked()),
+ this, SLOT(selectLocation()));
+
+ topLayout->addWidget(grid);
+}
+
+void EditBookmarkDialog::selectIcon()
+{
+ const QString iconName(KIconDialog::getIcon(KIcon::Small, KIcon::FileSystem));
+ if (!iconName.isEmpty()) {
+ m_iconName = iconName;
+ m_iconButton->setIconSet(SmallIcon(iconName));
+ }
+}
+
+void EditBookmarkDialog::selectLocation()
+{
+ const QString location(m_location->text());
+ KURL url(KFileDialog::getExistingURL(location));
+ if (!url.isEmpty()) {
+ m_location->setText(url.prettyURL());
+ }
+}
+
+#include "editbookmarkdialog.moc"
diff --git a/src/editbookmarkdialog.h b/src/editbookmarkdialog.h
new file mode 100644
index 0000000..2156aae
--- /dev/null
+++ b/src/editbookmarkdialog.h
@@ -0,0 +1,82 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+#ifndef EDITBOOKMARKDIALOG_H
+#define EDITBOOKMARKDIALOG_H
+
+#include <kbookmark.h>
+#include <kdialogbase.h>
+
+class Bookmark;
+class QLineEdit;
+class QPushButton;
+
+/**
+ * @brief Allows to edit the icon, URL and name of a bookmark.
+ *
+ * The default usage is like this:
+ * \code
+ * KBookmark bookmark = EditBookmarkDialog::getBookmark(i18n("Add Bookmark"),
+ * i18n("New bookmark"),
+ * KURL(),
+ * "bookmark");
+ * if (!bookmark.isNull()) {
+ * // ...
+ * }
+ * \endcode
+ */
+class EditBookmarkDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ virtual ~EditBookmarkDialog();
+
+ /**
+ * Opens a dialog where the current icon, URL and name of
+ * an URL are editable. The title of the dialog is set to \a title.
+ * @return A valid bookmark, if the user has pressed OK. Otherwise
+ * a null bookmark is returned (see Bookmark::isNull()).
+ */
+ static KBookmark getBookmark(const QString& title,
+ const QString& name,
+ const KURL& url,
+ const QString& icon);
+
+protected slots:
+ virtual void slotOk();
+
+protected:
+ EditBookmarkDialog(const QString& title,
+ const QString& name,
+ const KURL& url,
+ const QString& icon);
+
+private slots:
+ void selectIcon();
+ void selectLocation();
+
+private:
+ QString m_iconName;
+ QPushButton* m_iconButton;
+ QLineEdit* m_name;
+ QLineEdit* m_location;
+ KBookmark m_bookmark;
+};
+#endif
diff --git a/src/filterbar.cpp b/src/filterbar.cpp
new file mode 100644
index 0000000..83cc784
--- /dev/null
+++ b/src/filterbar.cpp
@@ -0,0 +1,90 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz <[email protected]> *
+ * Copyright (C) 2006 by Gregor Kališnik <[email protected]> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+#include "filterbar.h"
+
+#include <qlabel.h>
+#include <qlayout.h>
+
+#include <kdialog.h>
+#include <klocale.h>
+#include <kpushbutton.h>
+#include <klineedit.h>
+#include <kiconloader.h>
+
+#include "dolphin.h"
+
+FilterBar::FilterBar(QWidget *parent, const char *name) :
+ QWidget(parent, name)
+{
+ const int gap = 3;
+
+ QVBoxLayout* foo = new QVBoxLayout(this);
+ foo->addSpacing(gap);
+
+ QHBoxLayout* layout = new QHBoxLayout(foo);
+ layout->addSpacing(gap);
+
+ m_filter = new QLabel(i18n("Filter:"), this);
+ layout->addWidget(m_filter);
+ layout->addSpacing(KDialog::spacingHint());
+
+ m_filterInput = new KLineEdit(this);
+ layout->addWidget(m_filterInput);
+
+ m_close = new KPushButton(this);
+ m_close->setIconSet(SmallIcon("fileclose"));
+ m_close->setFlat(true);
+ layout->addWidget(m_close);
+ layout->addSpacing(gap);
+
+ connect(m_filterInput, SIGNAL(textChanged(const QString&)),
+ this, SIGNAL(signalFilterChanged(const QString&)));
+ connect(m_close, SIGNAL(clicked()), this, SLOT(hide()));
+ connect(m_close, SIGNAL(clicked()),
+ &Dolphin::mainWin(), SLOT(slotShowFilterBarChanged()));
+}
+
+FilterBar::~FilterBar()
+{
+}
+
+void FilterBar::hide()
+{
+ m_filterInput->clear();
+ m_filterInput->clearFocus();
+ QWidget::hide();
+}
+
+void FilterBar::show()
+{
+ m_filterInput->setFocus();
+ QWidget::show();
+}
+
+void FilterBar::keyReleaseEvent(QKeyEvent* event)
+{
+ QWidget::keyReleaseEvent(event);
+ if ((event->key() == Qt::Key_Escape)) {
+ hide();
+ Dolphin::mainWin().slotShowFilterBarChanged();
+ }
+}
+
+#include "filterbar.moc"
diff --git a/src/filterbar.h b/src/filterbar.h
new file mode 100644
index 0000000..7f9c8b8
--- /dev/null
+++ b/src/filterbar.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz <[email protected]> *
+ * Copyright (C) 2006 by Gregor Kališnik <[email protected]> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+#ifndef FILTERBAR_H
+#define FILTERBAR_H
+
+#include <qwidget.h>
+
+class QLabel;
+class KLineEdit;
+class KPushButton;
+
+/**
+ * @brief Provides an input field for filtering the currently shown items.
+ *
+ * @author Gregor Kališnik <[email protected]>
+ */
+class FilterBar : public QWidget
+{
+ Q_OBJECT
+
+public:
+ FilterBar(QWidget *parent = 0, const char *name = 0);
+ virtual ~FilterBar();
+
+signals:
+ /**
+ * Signal that reports the name filter has been
+ * changed to \a nameFilter.
+ */
+ void signalFilterChanged(const QString& nameFilter);
+
+public slots:
+ /** @see QWidget::hide() */
+ virtual void hide();
+
+ /** @see QWidget::show() */
+ virtual void show();
+
+protected:
+ virtual void keyReleaseEvent(QKeyEvent* event);
+
+private:
+ QLabel* m_filter;
+ KLineEdit* m_filterInput;
+ KPushButton* m_close;
+};
+
+#endif
diff --git a/src/generalsettingspage.cpp b/src/generalsettingspage.cpp
new file mode 100644
index 0000000..0a97574
--- /dev/null
+++ b/src/generalsettingspage.cpp
@@ -0,0 +1,171 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz ([email protected]) and *
+ * and Patrice Tremblay *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "generalsettingspage.h"
+
+#include <qlayout.h>
+#include <kdialog.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qvbox.h>
+#include <qgrid.h>
+#include <qgroupbox.h>
+#include <klocale.h>
+#include <qcheckbox.h>
+#include <qbuttongroup.h>
+#include <qpushbutton.h>
+#include <kfiledialog.h>
+#include <qradiobutton.h>
+
+#include "dolphinsettings.h"
+#include "dolphin.h"
+#include "dolphinview.h"
+
+GeneralSettingsPage::GeneralSettingsPage(QWidget* parent) :
+ SettingsPageBase(parent),
+ m_homeURL(0),
+ m_startSplit(0),
+ m_startEditable(0)
+{
+ QVBoxLayout* topLayout = new QVBoxLayout(parent, 2, KDialog::spacingHint());
+
+ const int spacing = KDialog::spacingHint();
+ const int margin = KDialog::marginHint();
+ const QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+
+ DolphinSettings& settings = DolphinSettings::instance();
+
+ QVBox* vBox = new QVBox(parent);
+ vBox->setSizePolicy(sizePolicy);
+ vBox->setSpacing(spacing);
+ vBox->setMargin(margin);
+ vBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Ignored);
+
+ // create 'Home URL' editor
+ QGroupBox* homeGroup = new QGroupBox(1, Qt::Horizontal, i18n("Home URL"), vBox);
+ homeGroup->setSizePolicy(sizePolicy);
+ homeGroup->setMargin(margin);
+
+ QHBox* homeURLBox = new QHBox(homeGroup);
+ homeURLBox->setSizePolicy(sizePolicy);
+ homeURLBox->setSpacing(spacing);
+
+ new QLabel(i18n("Location:"), homeURLBox);
+ m_homeURL = new QLineEdit(settings.homeURL().prettyURL(), homeURLBox);
+
+ QPushButton* selectHomeURLButton = new QPushButton(SmallIcon("folder"), QString::null, homeURLBox);
+ connect(selectHomeURLButton, SIGNAL(clicked()),
+ this, SLOT(selectHomeURL()));
+
+ QHBox* buttonBox = new QHBox(homeGroup);
+ buttonBox->setSizePolicy(sizePolicy);
+ buttonBox->setSpacing(spacing);
+ QPushButton* useCurrentButton = new QPushButton(i18n("Use current location"), buttonBox);
+ connect(useCurrentButton, SIGNAL(clicked()),
+ this, SLOT(useCurrentLocation()));
+ QPushButton* useDefaultButton = new QPushButton(i18n("Use default location"), buttonBox);
+ connect(useDefaultButton, SIGNAL(clicked()),
+ this, SLOT(useDefaulLocation()));
+
+ // create 'Default View Mode' group
+ QButtonGroup* buttonGroup = new QButtonGroup(3, Qt::Vertical, i18n("Default View Mode"), vBox);
+ buttonGroup->setSizePolicy(sizePolicy);
+ buttonGroup->setMargin(margin);
+
+ m_iconsView = new QRadioButton(i18n("Icons"), buttonGroup);
+ m_detailsView = new QRadioButton(i18n("Details"), buttonGroup);
+ m_previewsView = new QRadioButton(i18n("Previews"), buttonGroup);
+
+ switch (settings.defaultViewMode()) {
+ case DolphinView::IconsView: m_iconsView->setChecked(true); break;
+ case DolphinView::DetailsView: m_detailsView->setChecked(true); break;
+ case DolphinView::PreviewsView: m_previewsView->setChecked(true); break;
+ }
+
+ // create 'Start with split view' checkbox
+ m_startSplit = new QCheckBox(i18n("Start with split view"), vBox);
+ m_startSplit->setChecked(settings.isViewSplit());
+
+ // create 'Start with editable navigation bar' checkbox
+ m_startEditable = new QCheckBox(i18n("Start with editable navigation bar"), vBox);
+ m_startEditable->setChecked(settings.isURLEditable());
+
+ // create 'Save view properties for each folder' checkbox
+ m_saveView = new QCheckBox(i18n("Save view properties for each folder"), vBox);
+ m_saveView->setChecked(settings.isSaveView());
+
+ // Add a dummy widget with no restriction regarding
+ // a vertical resizing. This assures that the dialog layout
+ // is not stretched vertically.
+ new QWidget(vBox);
+
+ topLayout->addWidget(vBox);
+}
+
+
+GeneralSettingsPage::~GeneralSettingsPage()
+{
+}
+
+void GeneralSettingsPage::applySettings()
+{
+ DolphinSettings& settings = DolphinSettings::instance();
+
+ const KURL url(m_homeURL->text());
+ KFileItem fileItem(S_IFDIR, KFileItem::Unknown, url);
+ if (url.isValid() && fileItem.isDir()) {
+ settings.setHomeURL(url);
+ }
+
+ DolphinView::Mode viewMode = DolphinView::IconsView;
+ if (m_detailsView->isChecked()) {
+ viewMode = DolphinView::DetailsView;
+ }
+ else if (m_previewsView->isChecked()) {
+ viewMode = DolphinView::PreviewsView;
+ }
+ settings.setDefaultViewMode(viewMode);
+
+ settings.setViewSplit(m_startSplit->isChecked());
+ settings.setSaveView(m_saveView->isChecked());
+ settings.setURLEditable(m_startEditable->isChecked());
+}
+
+void GeneralSettingsPage::selectHomeURL()
+{
+ const QString homeURL(m_homeURL->text());
+ KURL url(KFileDialog::getExistingURL(homeURL));
+ if (!url.isEmpty()) {
+ m_homeURL->setText(url.prettyURL());
+ }
+}
+
+void GeneralSettingsPage::useCurrentLocation()
+{
+ const DolphinView* view = Dolphin::mainWin().activeView();
+ m_homeURL->setText(view->url().prettyURL());
+}
+
+void GeneralSettingsPage::useDefaulLocation()
+{
+ m_homeURL->setText("file://" + QDir::homeDirPath());
+}
+
+#include "generalsettingspage.moc"
diff --git a/src/generalsettingspage.h b/src/generalsettingspage.h
new file mode 100644
index 0000000..1d68fde
--- /dev/null
+++ b/src/generalsettingspage.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+#ifndef GENERALSETTINGSPAGE_H
+#define GENERALSETTINGSPAGE_H
+
+#include <settingspagebase.h>
+class QLineEdit;
+class QRadioButton;
+class QCheckBox;
+
+/**
+ * @brief Page for the 'General' settings of the Dolphin settings dialog.
+ *
+ * The general settings allow to set the home URL, the default view mode
+ * and the split view mode.
+ *
+ * @author Peter Penz <[email protected]>
+ */
+class GeneralSettingsPage : public SettingsPageBase
+{
+ Q_OBJECT
+
+public:
+ GeneralSettingsPage(QWidget* parent);
+
+ virtual ~GeneralSettingsPage();
+
+ /** @see SettingsPageBase::applySettings */
+ virtual void applySettings();
+
+private slots:
+ void selectHomeURL();
+ void useCurrentLocation();
+ void useDefaulLocation();
+
+private:
+ QLineEdit* m_homeURL;
+ QRadioButton* m_iconsView;
+ QRadioButton* m_detailsView;
+ QRadioButton* m_previewsView;
+ QCheckBox* m_startSplit;
+ QCheckBox* m_startEditable;
+ QCheckBox* m_saveView;
+};
+
+#endif
diff --git a/src/hi128-app-d3lphin.png b/src/hi128-app-d3lphin.png
new file mode 100644
index 0000000..651128a
--- /dev/null
+++ b/src/hi128-app-d3lphin.png
Binary files differ
diff --git a/src/hi16-app-d3lphin.png b/src/hi16-app-d3lphin.png
new file mode 100644
index 0000000..5788fc7
--- /dev/null
+++ b/src/hi16-app-d3lphin.png
Binary files differ
diff --git a/src/hi22-app-d3lphin.png b/src/hi22-app-d3lphin.png
new file mode 100644
index 0000000..335c07d
--- /dev/null
+++ b/src/hi22-app-d3lphin.png
Binary files differ
diff --git a/src/hi32-app-d3lphin.png b/src/hi32-app-d3lphin.png
new file mode 100644
index 0000000..5bd4a2d
--- /dev/null
+++ b/src/hi32-app-d3lphin.png
Binary files differ
diff --git a/src/hi48-app-d3lphin.png b/src/hi48-app-d3lphin.png
new file mode 100644
index 0000000..0c9574f
--- /dev/null
+++ b/src/hi48-app-d3lphin.png
Binary files differ
diff --git a/src/hi64-app-d3lphin.png b/src/hi64-app-d3lphin.png
new file mode 100644
index 0000000..613c612
--- /dev/null
+++ b/src/hi64-app-d3lphin.png
Binary files differ
diff --git a/src/iconsviewsettingspage.cpp b/src/iconsviewsettingspage.cpp
new file mode 100644
index 0000000..f23e185
--- /dev/null
+++ b/src/iconsviewsettingspage.cpp
@@ -0,0 +1,262 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "iconsviewsettingspage.h"
+
+#include <qlabel.h>
+#include <qslider.h>
+#include <qbuttongroup.h>
+#include <qradiobutton.h>
+#include <qspinbox.h>
+#include <kiconloader.h>
+#include <kfontcombo.h>
+#include <kdialog.h>
+#include <klocale.h>
+#include <assert.h>
+
+#include "dolphiniconsviewsettings.h"
+#include "dolphinsettings.h"
+#include "pixmapviewer.h"
+
+#define GRID_SPACING_BASE 8
+#define GRID_SPACING_INC 12
+
+IconsViewSettingsPage::IconsViewSettingsPage(DolphinIconsView::LayoutMode mode,
+ QWidget* parent) :
+ QVBox(parent),
+ m_mode(mode),
+ m_iconSizeSlider(0),
+ m_previewSizeSlider(0),
+ m_textWidthBox(0),
+ m_gridSpacingBox(0),
+ m_fontFamilyBox(0),
+ m_fontSizeBox(0),
+ m_textlinesCountBox(0),
+ m_arrangementBox(0)
+{
+ const int spacing = KDialog::spacingHint();
+ const int margin = KDialog::marginHint();
+ const QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+
+ setSpacing(spacing);
+ setMargin(margin);
+
+ DolphinIconsViewSettings* settings = DolphinSettings::instance().iconsView(m_mode);
+ assert(settings != 0);
+
+ QHBox* sizesLayout = new QHBox(this);
+ sizesLayout->setSpacing(spacing);
+ sizesLayout->setSizePolicy(sizePolicy);
+
+ // create 'Icon Size' group including slider and preview
+ QGroupBox* iconSizeGroup = new QGroupBox(2, Qt::Vertical, i18n("Icon Size"), sizesLayout);
+ iconSizeGroup->setSizePolicy(sizePolicy);
+ iconSizeGroup->setMargin(margin);
+
+ const QColor iconBackgroundColor(KGlobalSettings::baseColor());
+
+ QHBox* iconSizeVBox = new QHBox(iconSizeGroup);
+ iconSizeVBox->setSpacing(spacing);
+ new QLabel(i18n("Small"), iconSizeVBox);
+ m_iconSizeSlider = new QSlider(0, 5, 1, 0, Qt::Horizontal, iconSizeVBox);
+ m_iconSizeSlider->setValue(sliderValue(settings->iconSize()));
+ m_iconSizeSlider->setTickmarks(QSlider::Below);
+ connect(m_iconSizeSlider, SIGNAL(valueChanged(int)),
+ this, SLOT(slotIconSizeChanged(int)));
+ new QLabel(i18n("Large"), iconSizeVBox);
+
+ m_iconSizeViewer = new PixmapViewer(iconSizeGroup);
+ m_iconSizeViewer->setMinimumWidth(KIcon::SizeEnormous);
+ m_iconSizeViewer->setFixedHeight(KIcon::SizeEnormous);
+ m_iconSizeViewer->setEraseColor(iconBackgroundColor);
+ slotIconSizeChanged(m_iconSizeSlider->value());
+
+ if (m_mode == DolphinIconsView::Previews) {
+ // create 'Preview Size' group including slider and preview
+ QGroupBox* previewSizeGroup = new QGroupBox(2, Qt::Vertical, i18n("Preview Size"), sizesLayout);
+ previewSizeGroup->setSizePolicy(sizePolicy);
+ previewSizeGroup->setMargin(margin);
+
+ QHBox* previewSizeVBox = new QHBox(previewSizeGroup);
+ previewSizeVBox->setSpacing(spacing);
+ new QLabel(i18n("Small"), previewSizeVBox);
+ m_previewSizeSlider = new QSlider(0, 5, 1, 0, Qt::Horizontal, previewSizeVBox);
+ m_previewSizeSlider->setValue(sliderValue(settings->previewSize()));
+ m_previewSizeSlider->setTickmarks(QSlider::Below);
+ connect(m_previewSizeSlider, SIGNAL(valueChanged(int)),
+ this, SLOT(slotPreviewSizeChanged(int)));
+ new QLabel(i18n("Large"), previewSizeVBox);
+
+ m_previewSizeViewer = new PixmapViewer(previewSizeGroup);
+ m_previewSizeViewer->setMinimumWidth(KIcon::SizeEnormous);
+ m_previewSizeViewer->setFixedHeight(KIcon::SizeEnormous);
+ m_previewSizeViewer->setEraseColor(iconBackgroundColor);
+
+ slotPreviewSizeChanged(m_previewSizeSlider->value());
+ }
+
+ QGroupBox* textGroup = new QGroupBox(2, Qt::Horizontal, i18n("Text"), this);
+ textGroup->setSizePolicy(sizePolicy);
+ textGroup->setMargin(margin);
+
+ new QLabel(i18n("Font family:"), textGroup);
+ m_fontFamilyBox = new KFontCombo(textGroup);
+ m_fontFamilyBox->setCurrentFont(settings->fontFamily());
+
+ new QLabel(i18n("Font size:"), textGroup);
+ m_fontSizeBox = new QSpinBox(6, 99, 1, textGroup);
+ m_fontSizeBox->setValue(settings->fontSize());
+
+ new QLabel(i18n("Number of lines:"), textGroup);
+ m_textlinesCountBox = new QSpinBox(1, 5, 1, textGroup);
+ m_textlinesCountBox->setValue(settings->textlinesCount());
+
+ new QLabel(i18n("Text width:"), textGroup);
+ m_textWidthBox = new QComboBox(textGroup);
+ m_textWidthBox->insertItem(i18n("Small"));
+ m_textWidthBox->insertItem(i18n("Medium"));
+ m_textWidthBox->insertItem(i18n("Large"));
+
+ QGroupBox* gridGroup = new QGroupBox(2, Qt::Horizontal, i18n("Grid"), this);
+ gridGroup->setSizePolicy(sizePolicy);
+ gridGroup->setMargin(margin);
+
+ const bool leftToRightArrangement = (settings->arrangement() == QIconView::LeftToRight);
+ new QLabel(i18n("Arrangement:"), gridGroup);
+ m_arrangementBox = new QComboBox(gridGroup);
+ m_arrangementBox->insertItem(i18n("Left to right"));
+ m_arrangementBox->insertItem(i18n("Top to bottom"));
+ m_arrangementBox->setCurrentItem(leftToRightArrangement ? 0 : 1);
+
+ new QLabel(i18n("Grid spacing:"), gridGroup);
+ m_gridSpacingBox = new QComboBox(gridGroup);
+ m_gridSpacingBox->insertItem(i18n("Small"));
+ m_gridSpacingBox->insertItem(i18n("Medium"));
+ m_gridSpacingBox->insertItem(i18n("Large"));
+ m_gridSpacingBox->setCurrentItem((settings->gridSpacing() - GRID_SPACING_BASE) / GRID_SPACING_INC);
+
+ // Add a dummy widget with no restriction regarding
+ // a vertical resizing. This assures that the dialog layout
+ // is not stretched vertically.
+ new QWidget(this);
+
+ adjustTextWidthSelection();
+}
+
+IconsViewSettingsPage::~IconsViewSettingsPage()
+{
+}
+
+void IconsViewSettingsPage::applySettings()
+{
+ DolphinIconsViewSettings* settings = DolphinSettings::instance().iconsView(m_mode);
+ assert(settings != 0);
+
+ const int defaultSize = iconSize(m_iconSizeSlider->value());
+ settings->setIconSize(defaultSize);
+
+ int previewSize = (m_mode == DolphinIconsView::Previews) ?
+ iconSize(m_previewSizeSlider->value()) :
+ defaultSize;
+ if (previewSize < defaultSize) {
+ // assure that the preview size is never smaller than the icon size
+ previewSize = defaultSize;
+ }
+ settings->setPreviewSize(previewSize);
+
+ const int fontSize = m_fontSizeBox->value();
+
+ QIconView::Arrangement arrangement = (m_arrangementBox->currentItem() == 0) ?
+ QIconView::LeftToRight :
+ QIconView::TopToBottom;
+ settings->setArrangement(arrangement);
+ settings->calculateGridSize(m_textWidthBox->currentItem());
+
+ settings->setFontFamily(m_fontFamilyBox->currentFont());
+ settings->setFontSize(fontSize);
+ settings->setTextlinesCount(m_textlinesCountBox->value());
+
+ settings->setGridSpacing(GRID_SPACING_BASE +
+ m_gridSpacingBox->currentItem() * GRID_SPACING_INC);
+}
+
+void IconsViewSettingsPage::slotIconSizeChanged(int value)
+{
+ KIconLoader iconLoader;
+ m_iconSizeViewer->setPixmap(iconLoader.loadIcon("folder", KIcon::Desktop, iconSize(value)));
+
+ if (m_previewSizeSlider != 0) {
+ int previewSizeValue = m_previewSizeSlider->value();
+ if (previewSizeValue < value) {
+ // assure that the preview size is never smaller than the icon size
+ previewSizeValue = value;
+ }
+ slotPreviewSizeChanged(previewSizeValue);
+ }
+}
+
+void IconsViewSettingsPage::slotPreviewSizeChanged(int value)
+{
+ KIconLoader iconLoader;
+ const int iconSizeValue = m_iconSizeSlider->value();
+ if (value < iconSizeValue) {
+ // assure that the preview size is never smaller than the icon size
+ value = iconSizeValue;
+ }
+ m_previewSizeViewer->setPixmap(iconLoader.loadIcon("preview", KIcon::Desktop, iconSize(value)));
+}
+
+int IconsViewSettingsPage::iconSize(int sliderValue) const
+{
+ int size = KIcon::SizeMedium;
+ switch (sliderValue) {
+ case 0: size = KIcon::SizeSmall; break;
+ case 1: size = KIcon::SizeSmallMedium; break;
+ case 2: size = KIcon::SizeMedium; break;
+ case 3: size = KIcon::SizeLarge; break;
+ case 4: size = KIcon::SizeHuge; break;
+ case 5: size = KIcon::SizeEnormous; break;
+ }
+ return size;
+}
+
+int IconsViewSettingsPage::sliderValue(int iconSize) const
+{
+ int value = 0;
+ switch (iconSize) {
+ case KIcon::SizeSmall: value = 0; break;
+ case KIcon::SizeSmallMedium: value = 1; break;
+ case KIcon::SizeMedium: value = 2; break;
+ case KIcon::SizeLarge: value = 3; break;
+ case KIcon::SizeHuge: value = 4; break;
+ case KIcon::SizeEnormous: value = 5; break;
+ default: break;
+ }
+ return value;
+}
+
+void IconsViewSettingsPage::adjustTextWidthSelection()
+{
+ DolphinIconsViewSettings* settings = DolphinSettings::instance().iconsView(m_mode);
+ assert(settings != 0);
+ m_textWidthBox->setCurrentItem(settings->textWidthHint());
+}
+
+#include "iconsviewsettingspage.moc"
diff --git a/src/iconsviewsettingspage.h b/src/iconsviewsettingspage.h
new file mode 100644
index 0000000..ce7ce55
--- /dev/null
+++ b/src/iconsviewsettingspage.h
@@ -0,0 +1,99 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef ICONSVIEWSETTINGSPAGE_H
+#define ICONSVIEWSETTINGSPAGE_H
+
+#include <qvbox.h>
+#include <dolphiniconsview.h>
+
+class QSlider;
+class QComboBox;
+class QCheckBox;
+class QPushButton;
+class QSpinBox;
+class KFontCombo;
+class PixmapViewer;
+
+/**
+ * @brief Tab page for the 'Icons Mode' and 'Previews Mode' settings
+ * of the Dolphin settings dialog.
+ *
+ * Allows to set:
+ * - icon size
+ * - preview size
+ * - text width
+ * - grid spacing
+ * - font family
+ * - font size
+ * - number of text lines
+ * - arrangement
+ *
+ * @see DolphinIconsViewSettings
+ * @author Peter Penz <[email protected]>
+ */
+class IconsViewSettingsPage : public QVBox
+{
+ Q_OBJECT
+
+public:
+ IconsViewSettingsPage(DolphinIconsView::LayoutMode mode,
+ QWidget* parent);
+ virtual ~IconsViewSettingsPage();
+
+ /**
+ * Applies the settings for the icons view.
+ * The settings are persisted automatically when
+ * closing Dolphin.
+ */
+ void applySettings();
+
+private slots:
+ void slotIconSizeChanged(int value);
+ void slotPreviewSizeChanged(int value);
+
+private:
+ DolphinIconsView::LayoutMode m_mode;
+
+ QSlider* m_iconSizeSlider;
+ PixmapViewer* m_iconSizeViewer;
+ QSlider* m_previewSizeSlider;
+ PixmapViewer* m_previewSizeViewer;
+ QComboBox* m_textWidthBox;
+ QComboBox* m_gridSpacingBox;
+ KFontCombo* m_fontFamilyBox;
+ QSpinBox* m_fontSizeBox;
+ QSpinBox* m_textlinesCountBox;
+ QComboBox* m_arrangementBox;
+
+ /** Returns the icon size for the given slider value. */
+ int iconSize(int sliderValue) const;
+
+ /** Returns the slider value for the given icon size. */
+ int sliderValue(int iconSize) const;
+
+ /**
+ * Adjusts the selection of the text width combo box dependant
+ * from the grid width and grid height settings.
+ */
+ void adjustTextWidthSelection();
+};
+
+#endif
diff --git a/src/infosidebarpage.cpp b/src/infosidebarpage.cpp
new file mode 100644
index 0000000..7cfe346
--- /dev/null
+++ b/src/infosidebarpage.cpp
@@ -0,0 +1,630 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz <[email protected]> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "infosidebarpage.h"
+#include <assert.h>
+
+#include <qlayout.h>
+#include <qpixmap.h>
+#include <qlabel.h>
+#include <qtimer.h>
+#include <qpushbutton.h>
+#include <qvbox.h>
+#include <qvgroupbox.h>
+#include <qpopupmenu.h>
+#include <qpainter.h>
+#include <qfontmetrics.h>
+#include <qgrid.h>
+#include <qhgroupbox.h>
+
+#include <kbookmarkmanager.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+#include <kio/previewjob.h>
+#include <kfileitem.h>
+#include <kdialog.h>
+#include <kglobalsettings.h>
+#include <kfilemetainfo.h>
+
+#include "dolphin.h"
+#include "pixmapviewer.h"
+#include "dolphinsettings.h"
+
+InfoSidebarPage::InfoSidebarPage(QWidget* parent) :
+ SidebarPage(parent),
+ m_multipleSelection(false),
+ m_pendingPreview(false),
+ m_timer(0),
+ m_preview(0),
+ m_name(0),
+ m_currInfoLineIdx(0),
+ m_infoGrid(0),
+ m_actionBox(0)
+{
+ const int spacing = KDialog::spacingHint();
+
+ m_timer = new QTimer(this);
+ connect(m_timer, SIGNAL(timeout()),
+ this, SLOT(slotTimeout()));
+
+ QVBoxLayout* layout = new QVBoxLayout(this);
+ layout->setSpacing(spacing);
+
+ // preview
+ m_preview = new PixmapViewer(this);
+ m_preview->setMinimumWidth(KIcon::SizeEnormous);
+ m_preview->setFixedHeight(KIcon::SizeEnormous);
+
+ // name
+ m_name = new QLabel(this);
+ m_name->setTextFormat(Qt::RichText);
+ m_name->setAlignment(m_name->alignment() | Qt::AlignHCenter);
+ QFontMetrics fontMetrics(m_name->font());
+ m_name->setMinimumHeight(fontMetrics.height() * 3);
+ m_name->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum);
+
+ QWidget* sep1 = new QHGroupBox(this); // TODO: check whether default widget exist for this?
+ sep1->setFixedHeight(1);
+
+ // general information
+ m_infoGrid = new QGrid(2, this);
+ m_infoGrid->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+
+ QWidget* sep2 = new QHGroupBox(this); // TODO: check whether default widget exist for this?
+ sep2->setFixedHeight(1);
+
+ // actions
+ m_actionBox = new QVBox(this);
+ m_actionBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+
+ // Add a dummy widget with no restriction regarding a vertical resizing.
+ // This assures that information is always top aligned.
+ QWidget* dummy = new QWidget(this);
+
+ layout->addItem(new QSpacerItem(spacing, spacing, QSizePolicy::Preferred, QSizePolicy::Fixed));
+ layout->addWidget(m_preview);
+ layout->addWidget(m_name);
+ layout->addWidget(sep1);
+ layout->addWidget(m_infoGrid);
+ layout->addWidget(sep2);
+ layout->addWidget(m_actionBox);
+ layout->addWidget(dummy);
+
+ connect(&Dolphin::mainWin(), SIGNAL(selectionChanged()),
+ this, SLOT(showItemInfo()));
+
+ connectToActiveView();
+}
+
+InfoSidebarPage::~InfoSidebarPage()
+{
+}
+
+void InfoSidebarPage::activeViewChanged()
+{
+ connectToActiveView();
+}
+
+void InfoSidebarPage::requestDelayedItemInfo(const KURL& url)
+{
+ cancelRequest();
+
+ if (!url.isEmpty() && !m_multipleSelection) {
+ m_urlCandidate = url;
+ m_timer->start(300, true);
+ }
+}
+
+void InfoSidebarPage::requestItemInfo(const KURL& url)
+{
+ cancelRequest();
+
+ if (!url.isEmpty() && !m_multipleSelection) {
+ m_shownURL = url;
+ showItemInfo();
+ }
+}
+
+void InfoSidebarPage::showItemInfo()
+{
+ cancelRequest();
+
+ m_multipleSelection = false;
+
+ // show the preview...
+ DolphinView* view = Dolphin::mainWin().activeView();
+ const KFileItemList* selectedItems = view->selectedItems();
+ if ((selectedItems != 0) && selectedItems->count() > 1) {
+ m_multipleSelection = true;
+ }
+
+ if (m_multipleSelection) {
+ KIconLoader iconLoader;
+ QPixmap icon = iconLoader.loadIcon("exec",
+ KIcon::NoGroup,
+ KIcon::SizeEnormous);
+ m_preview->setPixmap(icon);
+ m_name->setText(i18n("%n items selected", "%n items selected", selectedItems->count()));
+ }
+ else if (!applyBookmark()) {
+ // try to get a preview pixmap from the item...
+ KURL::List list;
+ list.append(m_shownURL);
+
+ m_pendingPreview = true;
+ m_preview->setPixmap(QPixmap());
+
+ KIO::PreviewJob* job = KIO::filePreview(list,
+ m_preview->width(),
+ KIcon::SizeEnormous);
+ connect(job, SIGNAL(gotPreview(const KFileItem*, const QPixmap&)),
+ this, SLOT(gotPreview(const KFileItem*, const QPixmap&)));
+ connect(job, SIGNAL(failed(const KFileItem*)),
+ this, SLOT(slotPreviewFailed(const KFileItem*)));
+
+ QString text("<b>");
+ text.append(m_shownURL.fileName());
+ text.append("</b>");
+ m_name->setText(text);
+ }
+
+ createMetaInfo();
+ insertActions();
+}
+
+void InfoSidebarPage::slotTimeout()
+{
+ m_shownURL = m_urlCandidate;
+ showItemInfo();
+}
+
+void InfoSidebarPage::slotPreviewFailed(const KFileItem* item)
+{
+ m_pendingPreview = false;
+ if (!applyBookmark()) {
+ m_preview->setPixmap(item->pixmap(KIcon::SizeEnormous));
+ }
+}
+
+void InfoSidebarPage::gotPreview(const KFileItem* /* item */,
+ const QPixmap& pixmap)
+{
+ if (m_pendingPreview) {
+ m_preview->setPixmap(pixmap);
+ m_pendingPreview = false;
+ }
+}
+
+void InfoSidebarPage::startService(int index)
+{
+ DolphinView* view = Dolphin::mainWin().activeView();
+ if (view->hasSelection()) {
+ KURL::List selectedURLs = view->selectedURLs();
+ KDEDesktopMimeType::executeService(selectedURLs, m_actionsVector[index]);
+ }
+ else {
+ KDEDesktopMimeType::executeService(m_shownURL, m_actionsVector[index]);
+ }
+}
+
+void InfoSidebarPage::connectToActiveView()
+{
+ cancelRequest();
+
+ DolphinView* view = Dolphin::mainWin().activeView();
+ connect(view, SIGNAL(signalRequestItemInfo(const KURL&)),
+ this, SLOT(requestDelayedItemInfo(const KURL&)));
+ connect(view, SIGNAL(signalURLChanged(const KURL&)),
+ this, SLOT(requestItemInfo(const KURL&)));
+
+ m_shownURL = view->url();
+ showItemInfo();
+}
+
+bool InfoSidebarPage::applyBookmark()
+{
+ KBookmarkGroup root = DolphinSettings::instance().bookmarkManager()->root();
+ KBookmark bookmark = root.first();
+ while (!bookmark.isNull()) {
+ if (m_shownURL.equals(bookmark.url(), true)) {
+ QString text("<b>");
+ text.append(bookmark.text());
+ text.append("</b>");
+ m_name->setText(text);
+
+ KIconLoader iconLoader;
+ QPixmap icon = iconLoader.loadIcon(bookmark.icon(),
+ KIcon::NoGroup,
+ KIcon::SizeEnormous);
+ m_preview->setPixmap(icon);
+ return true;
+ }
+ bookmark = root.next(bookmark);
+ }
+
+ return false;
+}
+
+void InfoSidebarPage::cancelRequest()
+{
+ m_timer->stop();
+ m_pendingPreview = false;
+}
+
+void InfoSidebarPage::createMetaInfo()
+{
+ // To prevent a flickering it's important to reuse available
+ // labels instead of deleting them and recreate them afterwards.
+ // The methods beginInfoLines(), addInfoLine() and endInfoLines()
+ // take care of this.
+ beginInfoLines();
+ DolphinView* view = Dolphin::mainWin().activeView();
+ if (!view->hasSelection()) {
+ KFileItem fileItem(S_IFDIR, KFileItem::Unknown, m_shownURL);
+ fileItem.refresh();
+
+ if (fileItem.isDir()) {
+ addInfoLine(i18n("Type:"), i18n("Directory"));
+ }
+ else {
+ addInfoLine(i18n("Type:"), fileItem.mimeComment());
+
+ QString sizeText(KIO::convertSize(fileItem.size()));
+ addInfoLine(i18n("Size:"), sizeText);
+ addInfoLine(i18n("Modified:"), fileItem.timeString());
+
+ const KFileMetaInfo& metaInfo = fileItem.metaInfo();
+ if (metaInfo.isValid()) {
+ QStringList keys = metaInfo.supportedKeys();
+ for (QStringList::Iterator it = keys.begin(); it != keys.end(); ++it) {
+ if (showMetaInfo(*it)) {
+ KFileMetaInfoItem metaInfoItem = metaInfo.item(*it);
+ addInfoLine(*it, metaInfoItem.string());
+ }
+ }
+ }
+ }
+ }
+ endInfoLines();
+}
+
+void InfoSidebarPage::beginInfoLines()
+{
+ m_currInfoLineIdx = 0;
+}
+
+void InfoSidebarPage::endInfoLines()
+{
+ if (m_currInfoLineIdx <= 0) {
+ return;
+ }
+
+ // remove labels which have not been used
+ if (m_currInfoLineIdx < static_cast<int>(m_infoWidgets.count())) {
+ QPtrListIterator<QLabel> deleteIter(m_infoWidgets);
+ deleteIter += m_currInfoLineIdx;
+
+ QWidget* widget = 0;
+ int removeCount = 0;
+ while ((widget = deleteIter.current()) != 0) {
+ widget->close();
+ widget->deleteLater();
+ ++deleteIter;
+ ++removeCount;
+ }
+ for (int i = 0; i < removeCount; ++i) {
+ m_infoWidgets.removeLast();
+ }
+ }
+}
+
+bool InfoSidebarPage::showMetaInfo(const QString& key) const
+{
+ // sorted list of keys, where it's data should be shown
+ static const char* keys[] = {
+ "Album",
+ "Artist",
+ "Author",
+ "Bitrate",
+ "Date",
+ "Dimensions",
+ "Genre",
+ "Length",
+ "Lines",
+ "Pages",
+ "Title",
+ "Words"
+ };
+
+ // do a binary search for the key...
+ int top = 0;
+ int bottom = sizeof(keys) / sizeof(char*) - 1;
+ while (top < bottom) {
+ const int middle = (top + bottom) / 2;
+ const int result = key.compare(keys[middle]);
+ if (result < 0) {
+ bottom = middle - 1;
+ }
+ else if (result > 0) {
+ top = middle + 1;
+ }
+ else {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void InfoSidebarPage::addInfoLine(const QString& labelText, const QString& infoText)
+{
+ QString labelStr("<b>");
+ labelStr.append(labelText);
+ labelStr.append("</b>&nbsp;");
+
+ const int count = m_infoWidgets.count();
+ if (m_currInfoLineIdx < count - 1) {
+ // reuse available labels
+ m_infoWidgets.at(m_currInfoLineIdx++)->setText(labelStr);
+ m_infoWidgets.at(m_currInfoLineIdx++)->setText(infoText);
+ }
+ else {
+ // no labels are available anymore, hence create 2 new ones
+ QLabel* label = new QLabel(labelStr, m_infoGrid);
+ label->setTextFormat(Qt::RichText);
+ label->setAlignment(Qt::AlignRight |
+ Qt::AlignTop);
+ label->show();
+ m_infoWidgets.append(label);
+
+ QLabel* info = new QLabel(infoText, m_infoGrid);
+ info->setTextFormat(Qt::RichText);
+ info->setAlignment(Qt::AlignTop | Qt::WordBreak);
+ info->show();
+ m_infoWidgets.append(info);
+
+ m_currInfoLineIdx += 2;
+ }
+}
+
+void InfoSidebarPage::insertActions()
+{
+ // delete all existing action widgets
+ // TODO: just use children() from QObject...
+ QPtrListIterator<QWidget> deleteIter(m_actionWidgets);
+ QWidget* widget = 0;
+ while ((widget = deleteIter.current()) != 0) {
+ widget->close();
+ widget->deleteLater();
+ ++deleteIter;
+ }
+
+ m_actionWidgets.clear();
+ m_actionsVector.clear();
+
+ int actionsIndex = 0;
+
+ // The algorithm for searching the available actions works on a list
+ // of KFileItems. If no selection is given, a temporary KFileItem
+ // by the given URL 'url' is created and added to the list.
+ KFileItem fileItem(S_IFDIR, KFileItem::Unknown, m_shownURL);
+ KFileItemList localList;
+ const KFileItemList* itemList = Dolphin::mainWin().activeView()->selectedItems();
+ if ((itemList == 0) || itemList->isEmpty()) {
+ fileItem.refresh();
+ localList.append(&fileItem);
+ itemList = &localList;
+ }
+
+ // 'itemList' contains now all KFileItems, where an item information should be shown.
+ // TODO: the following algorithm is quite equal to DolphinContextMenu::insertActionItems().
+ // It's open yet whether they should be merged or whether they have to work slightly different.
+ QStringList dirs = KGlobal::dirs()->findDirs("data", "d3lphin/servicemenus/");
+ for (QStringList::ConstIterator dirIt = dirs.begin(); dirIt != dirs.end(); ++dirIt) {
+ QDir dir(*dirIt);
+ QStringList entries = dir.entryList("*.desktop", QDir::Files);
+
+ for (QStringList::ConstIterator entryIt = entries.begin(); entryIt != entries.end(); ++entryIt) {
+ KSimpleConfig cfg(*dirIt + *entryIt, true);
+ cfg.setDesktopGroup();
+ if ((cfg.hasKey("Actions") || cfg.hasKey("X-KDE-GetActionMenu")) && cfg.hasKey("ServiceTypes")) {
+ const QStringList types = cfg.readListEntry("ServiceTypes");
+ for (QStringList::ConstIterator it = types.begin(); it != types.end(); ++it) {
+ // check whether the mime type is equal or whether the
+ // mimegroup (e. g. image/*) is supported
+
+ bool insert = false;
+ if ((*it) == "all/allfiles") {
+ // The service type is valid for all files, but not for directories.
+ // Check whether the selected items only consist of files...
+ KFileItemListIterator mimeIt(*itemList);
+ KFileItem* item = 0;
+ insert = true;
+ while (insert && ((item = mimeIt.current()) != 0)) {
+ insert = !item->isDir();
+ ++mimeIt;
+ }
+ }
+
+ if (!insert) {
+ // Check whether the MIME types of all selected files match
+ // to the mimetype of the service action. As soon as one MIME
+ // type does not match, no service menu is shown at all.
+ KFileItemListIterator mimeIt(*itemList);
+ KFileItem* item = 0;
+ insert = true;
+ while (insert && ((item = mimeIt.current()) != 0)) {
+ const QString mimeType((*mimeIt)->mimetype());
+ const QString mimeGroup(mimeType.left(mimeType.find('/')));
+
+ insert = (*it == mimeType) ||
+ ((*it).right(1) == "*") &&
+ ((*it).left((*it).find('/')) == mimeGroup);
+ ++mimeIt;
+ }
+ }
+
+ if (insert) {
+ const QString submenuName = cfg.readEntry( "X-KDE-Submenu" );
+ QPopupMenu* popup = 0;
+ if (!submenuName.isEmpty()) {
+ // create a sub menu containing all actions
+ popup = new QPopupMenu();
+ connect(popup, SIGNAL(activated(int)),
+ this, SLOT(startService(int)));
+
+ QPushButton* button = new QPushButton(submenuName, m_actionBox);
+ button->setFlat(true);
+ button->setPopup(popup);
+ button->show();
+ m_actionWidgets.append(button);
+ }
+
+ QValueList<KDEDesktopMimeType::Service> userServices =
+ KDEDesktopMimeType::userDefinedServices(*dirIt + *entryIt, true);
+
+ // iterate through all actions and add them to a widget
+ QValueList<KDEDesktopMimeType::Service>::Iterator serviceIt;
+ for (serviceIt = userServices.begin(); serviceIt != userServices.end(); ++serviceIt) {
+ KDEDesktopMimeType::Service service = (*serviceIt);
+ if (popup == 0) {
+ ServiceButton* button = new ServiceButton(SmallIcon(service.m_strIcon),
+ service.m_strName,
+ m_actionBox,
+ actionsIndex);
+ connect(button, SIGNAL(requestServiceStart(int)),
+ this, SLOT(startService(int)));
+ m_actionWidgets.append(button);
+ button->show();
+ }
+ else {
+ popup->insertItem(SmallIcon(service.m_strIcon), service.m_strName, actionsIndex);
+ }
+
+ m_actionsVector.append(service);
+ ++actionsIndex;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+ServiceButton::ServiceButton(const QIconSet& icon,
+ const QString& text,
+ QWidget* parent,
+ int index) :
+ QPushButton(icon, text, parent),
+ m_hover(false),
+ m_index(index)
+{
+ setEraseColor(colorGroup().background());
+ setFocusPolicy(QWidget::NoFocus);
+ connect(this, SIGNAL(released()),
+ this, SLOT(slotReleased()));
+}
+
+ServiceButton::~ServiceButton()
+{
+}
+
+void ServiceButton::drawButton(QPainter* painter)
+{
+ const int buttonWidth = width();
+ const int buttonHeight = height();
+
+ QColor backgroundColor;
+ QColor foregroundColor;
+ if (m_hover) {
+ backgroundColor = KGlobalSettings::highlightColor();
+ foregroundColor = KGlobalSettings::highlightedTextColor();
+ }
+ else {
+ backgroundColor = colorGroup().background();
+ foregroundColor = KGlobalSettings::buttonTextColor();
+ }
+
+ // draw button background
+ painter->setPen(NoPen);
+ painter->setBrush(backgroundColor);
+ painter->drawRect(0, 0, buttonWidth, buttonHeight);
+
+ const int spacing = KDialog::spacingHint();
+
+ // draw icon
+ int x = spacing;
+ const int y = (buttonHeight - KIcon::SizeSmall) / 2;
+ const QIconSet* set = iconSet();
+ if (set != 0) {
+ painter->drawPixmap(x, y, set->pixmap(QIconSet::Small, QIconSet::Normal));
+ }
+ x += KIcon::SizeSmall + spacing;
+
+ // draw text
+ painter->setPen(foregroundColor);
+
+ const int textWidth = buttonWidth - x;
+ QFontMetrics fontMetrics(font());
+ const bool clipped = fontMetrics.width(text()) >= textWidth;
+ //const int align = clipped ? Qt::AlignVCenter : Qt::AlignCenter;
+ painter->drawText(QRect(x, 0, textWidth, buttonHeight), Qt::AlignVCenter, text());
+
+ if (clipped) {
+ // Blend the right area of the text with the background, as the
+ // text is clipped.
+ // TODO #1: use alpha blending in Qt4 instead of drawing the text that often
+ // TODO #2: same code as in URLNavigatorButton::drawButton() -> provide helper class?
+ const int blendSteps = 16;
+
+ QColor blendColor(backgroundColor);
+ const int redInc = (foregroundColor.red() - backgroundColor.red()) / blendSteps;
+ const int greenInc = (foregroundColor.green() - backgroundColor.green()) / blendSteps;
+ const int blueInc = (foregroundColor.blue() - backgroundColor.blue()) / blendSteps;
+ for (int i = 0; i < blendSteps; ++i) {
+ painter->setClipRect(QRect(x + textWidth - i, 0, 1, buttonHeight));
+ painter->setPen(blendColor);
+ painter->drawText(QRect(x, 0, textWidth, buttonHeight), Qt::AlignVCenter, text());
+
+ blendColor.setRgb(blendColor.red() + redInc,
+ blendColor.green() + greenInc,
+ blendColor.blue() + blueInc);
+ }
+ }
+}
+
+void ServiceButton::enterEvent(QEvent* event)
+{
+ QPushButton::enterEvent(event);
+ m_hover = true;
+ update();
+}
+
+void ServiceButton::leaveEvent(QEvent* event)
+{
+ QPushButton::leaveEvent(event);
+ m_hover = false;
+ update();
+}
+
+void ServiceButton::slotReleased()
+{
+ emit requestServiceStart(m_index);
+}
+
diff --git a/src/infosidebarpage.h b/src/infosidebarpage.h
new file mode 100644
index 0000000..48e3dd4
--- /dev/null
+++ b/src/infosidebarpage.h
@@ -0,0 +1,194 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz <[email protected]>
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef _INFOSIDEBARPAGE_H_
+#define _INFOSIDEBARPAGE_H_
+
+#include <sidebarpage.h>
+
+#include <qvaluevector.h>
+#include <qpushbutton.h>
+
+#include <kurl.h>
+#include <ksortablevaluelist.h>
+#include <kmimetype.h>
+
+namespace KIO {
+ class Job;
+};
+
+class QPixmap;
+class QIconSet;
+class QString;
+class QPainter;
+class KFileItem;
+class QLabel;
+class QVBox;
+class QGrid;
+class PixmapViewer;
+
+/**
+ * @brief Prototype for a information sidebar.
+ *
+ * Will be exchanged in future releases by pluggable sidebar pages...
+ */
+class InfoSidebarPage : public SidebarPage
+{
+ Q_OBJECT
+
+public:
+ InfoSidebarPage(QWidget* parent);
+ virtual ~InfoSidebarPage();
+
+protected:
+ /** @see SidebarPage::activeViewChanged() */
+ virtual void activeViewChanged();
+
+private slots:
+ /**
+ * Does a delayed request of information for the item of the given URL and
+ * provides default actions.
+ *
+ * @see InfoSidebarPage::showItemInfo()
+ */
+ void requestDelayedItemInfo(const KURL& url);
+
+ /**
+ * Does a request of information for the item of the given URL and
+ * provides default actions.
+ *
+ * @see InfoSidebarPage::showItemInfo()
+ */
+ void requestItemInfo(const KURL& url);
+
+ /**
+ * Shows the information for the item of the URL which has been provided by
+ * InfoSidebarPage::requestItemInfo() and provides default actions.
+ */
+ void showItemInfo();
+
+ /**
+ * Triggered if the request for item information has timed out.
+ * @see InfoSidebarPage::requestDelayedItemInfo()
+ */
+ void slotTimeout();
+
+ /**
+ * Is invoked if no preview is available for the item. In this
+ * case the icon will be shown.
+ */
+ void slotPreviewFailed(const KFileItem* item);
+
+ /**
+ * Is invoked if a preview is available for the item. The preview
+ * \a pixmap is shown inside the info page.
+ */
+ void gotPreview(const KFileItem* item, const QPixmap& pixmap);
+
+ /**
+ * Starts the service of m_actionsVector with the index \index on
+ * the shown URL (or the selected items if available).
+ */
+ void startService(int index);
+
+private:
+ /**
+ * Connects to signals from the currently active Dolphin view to get
+ * informed about highlighting changes.
+ */
+ void connectToActiveView();
+
+ /**
+ * Checks whether the current URL is repesented by a bookmark. If yes,
+ * then the bookmark icon and name are shown instead of a preview.
+ * @return True, if the URL represents exactly a bookmark.
+ */
+ bool applyBookmark();
+
+ /** Assures that any pending item information request is cancelled. */
+ void cancelRequest();
+
+ // TODO: the following methods are just a prototypes for meta
+ // info generation...
+ void createMetaInfo();
+ void addInfoLine(const QString& labelText,
+ const QString& infoText);
+ void beginInfoLines();
+ void endInfoLines();
+
+ /**
+ * Returns true, if the string \a key represents a meta information
+ * that should be shown.
+ */
+ bool showMetaInfo(const QString& key) const;
+
+ /**
+ * Inserts the available actions to the info page for the given item.
+ */
+ void insertActions();
+
+ bool m_multipleSelection;
+ bool m_pendingPreview;
+ QTimer* m_timer;
+ KURL m_shownURL;
+ KURL m_urlCandidate;
+
+ PixmapViewer* m_preview;
+ QLabel* m_name;
+
+ int m_currInfoLineIdx;
+ QGrid* m_infoGrid;
+ QPtrList<QLabel> m_infoWidgets; // TODO: use children() from QObject instead
+
+ QVBox* m_actionBox;
+ QPtrList<QWidget> m_actionWidgets; // TODO: use children() from QObject instead
+ QValueVector<KDEDesktopMimeType::Service> m_actionsVector;
+};
+
+// TODO #1: move to SidebarPage?
+// TODO #2: quite same button from the optical point of view as URLNavigatorButton
+// -> provide helper class or common base class
+class ServiceButton : public QPushButton
+{
+ Q_OBJECT
+
+public:
+ ServiceButton(const QIconSet& icon,
+ const QString& text,
+ QWidget* parent,
+ int index);
+ virtual ~ServiceButton();
+
+signals:
+ void requestServiceStart(int index);
+
+protected:
+ virtual void drawButton(QPainter* painter);
+ virtual void enterEvent(QEvent* event);
+ virtual void leaveEvent(QEvent* event);
+
+private slots:
+ void slotReleased();
+
+private:
+ bool m_hover;
+ int m_index;
+};
+
+#endif // _INFOSIDEBARPAGE_H_
diff --git a/src/itemeffectsmanager.cpp b/src/itemeffectsmanager.cpp
new file mode 100644
index 0000000..1d1d199
--- /dev/null
+++ b/src/itemeffectsmanager.cpp
@@ -0,0 +1,189 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "itemeffectsmanager.h"
+#include <kiconeffect.h>
+#include <kapplication.h>
+#include <qobjectlist.h>
+#include <kglobalsettings.h>
+#include <qclipboard.h>
+#include <kurldrag.h>
+#include <klocale.h>
+
+#include "dolphin.h"
+#include "dolphinstatusbar.h"
+
+ItemEffectsManager::ItemEffectsManager()
+{
+ m_pixmapCopy = new QPixmap();
+}
+
+ItemEffectsManager::~ItemEffectsManager()
+{
+ delete m_pixmapCopy;
+ m_pixmapCopy = 0;
+
+ m_highlightedURL = 0;
+}
+
+void ItemEffectsManager::zoomIn()
+{
+ Dolphin::mainWin().refreshViews();
+}
+
+void ItemEffectsManager::zoomOut()
+{
+ Dolphin::mainWin().refreshViews();
+}
+
+void ItemEffectsManager::activateItem(void* context)
+{
+ KFileItem* fileInfo = contextFileInfo(context);
+ const KURL itemURL(fileInfo->url());
+ if (m_highlightedURL == itemURL) {
+ // the item is already highlighted
+ return;
+ }
+
+ resetActivatedItem();
+
+ const QPixmap* itemPixmap = contextPixmap(context);
+ if (itemPixmap != 0) {
+ // remember the pixmap and item to be able to
+ // restore it to the old state later
+ *m_pixmapCopy = *itemPixmap;
+ m_highlightedURL = itemURL;
+
+ // apply an icon effect to the item below the mouse pointer
+ KIconEffect iconEffect;
+ QPixmap pixmap = iconEffect.apply(*itemPixmap,
+ KIcon::Desktop,
+ KIcon::ActiveState);
+ setContextPixmap(context, pixmap);
+ }
+
+ if (!Dolphin::mainWin().activeView()->hasSelection()) {
+ DolphinStatusBar* statusBar = Dolphin::mainWin().activeView()->statusBar();
+ statusBar->setMessage(statusBarText(fileInfo), DolphinStatusBar::Default);
+ }
+}
+
+void ItemEffectsManager::resetActivatedItem()
+{
+ if (m_highlightedURL.isEmpty()) {
+ return;
+ }
+
+ for (void* context = firstContext(); context != 0; context = nextContext(context)) {
+ KURL itemURL(contextFileInfo(context)->url());
+ if (itemURL == m_highlightedURL) {
+ // the highlighted item has been found and is restored to the default state
+ KIconEffect iconEffect;
+ QPixmap pixmap = iconEffect.apply(*m_pixmapCopy,
+ KIcon::Desktop,
+ KIcon::DefaultState);
+
+ // TODO: KFileIconView does not emit any signal when the preview has been finished.
+ // Hence check the size to prevent that a preview is hidden by restoring a
+ // non-preview pixmap.
+ const QPixmap* highlightedPixmap = contextPixmap(context);
+ const bool restore = (pixmap.width() == highlightedPixmap->width()) &&
+ (pixmap.height() == highlightedPixmap->height());
+ if (restore) {
+ setContextPixmap(context, pixmap);
+ }
+ break;
+ }
+ }
+
+ m_highlightedURL = 0;
+
+ DolphinStatusBar* statusBar = Dolphin::mainWin().activeView()->statusBar();
+ statusBar->clear();
+}
+
+void ItemEffectsManager::updateDisabledItems()
+{
+ if (!m_disabledItems.isEmpty()) {
+ // restore all disabled items with their original pixmap
+ for (void* context = firstContext(); context != 0; context = nextContext(context)) {
+ const KFileItem* fileInfo = contextFileInfo(context);
+ const KURL& fileURL = fileInfo->url();
+ QValueListIterator<DisabledItem> it = m_disabledItems.begin();
+ while (it != m_disabledItems.end()) {
+ if (fileURL == (*it).url) {
+ setContextPixmap(context, (*it).pixmap);
+ }
+ ++it;
+ }
+ }
+ m_disabledItems.clear();
+ }
+
+ if (!Dolphin::mainWin().clipboardContainsCutData()) {
+ return;
+ }
+
+ QClipboard* clipboard = QApplication::clipboard();
+ QMimeSource* data = clipboard->data();
+ if (!KURLDrag::canDecode(data)) {
+ return;
+ }
+
+ // The clipboard contains items, which have been cutted. Change the pixmaps of all those
+ // items to the disabled state.
+ KURL::List urls;
+ KURLDrag::decode(data, urls);
+ for (void* context = firstContext(); context != 0; context = nextContext(context)) {
+ const KFileItem* fileInfo = contextFileInfo(context);
+ const KURL& fileURL = fileInfo->url();
+ for(KURL::List::ConstIterator it = urls.begin(); it != urls.end(); ++it) {
+ if (fileURL == (*it)) {
+ const QPixmap* itemPixmap = contextPixmap(context);
+ if (itemPixmap != 0) {
+ // remember old pixmap
+ DisabledItem disabledItem;
+ disabledItem.url = fileURL;
+ disabledItem.pixmap = *itemPixmap;
+ m_disabledItems.append(disabledItem);
+
+ KIconEffect iconEffect;
+ QPixmap disabledPixmap = iconEffect.apply(*itemPixmap,
+ KIcon::Desktop,
+ KIcon::DisabledState);
+ setContextPixmap(context, disabledPixmap);
+ }
+ break;
+ }
+ }
+ }
+}
+
+QString ItemEffectsManager::statusBarText(KFileItem* fileInfo) const
+{
+ if (fileInfo->isDir()) {
+ // KFileItem::getStatusBar() returns "MyDocuments/ Folder" as
+ // status bar text for a folder 'MyDocuments'. This is adjusted
+ // to "MyDocuments (Folder)" in Dolphin.
+ return i18n("%1 (Folder)").arg(fileInfo->name());
+ }
+
+ return fileInfo->getStatusBarInfo();
+}
diff --git a/src/itemeffectsmanager.h b/src/itemeffectsmanager.h
new file mode 100644
index 0000000..eb2921d
--- /dev/null
+++ b/src/itemeffectsmanager.h
@@ -0,0 +1,120 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef ITEMEFFECTSMANAGER_H
+#define ITEMEFFECTSMANAGER_H
+
+#include <qobject.h>
+#include <qpixmap.h>
+#include <kurl.h>
+#include <qvaluelist.h>
+class KFileItem;
+
+/**
+ * @brief Abstract class to implement item effects for a Dolphin view.
+ *
+ * Derived classes must implement the following pure virtual methods:
+ * - ItemEffectsManager::setContextPixmap()
+ * - ItemEffectsManager::contextPixmap()
+ * - ItemEffectsManager::firstContext()
+ * - ItemEffectsManager::nextContext()
+ * - ItemEffectsManager::contextFileInfo()
+ *
+ * The item effects manager highlights currently active items and also
+ * respects cutted items. A 'context' is defined as abstract data type,
+ * which usually is represented by a KFileListViewItem or
+ * a KFileIconViewItem.
+ *
+ * In Qt4 the item effects manager should get integrated as part of Interview
+ * and hence no abstract context handling should be necessary anymore. The main
+ * purpose of the current interface is to prevent code duplication as there is
+ * no common model shared by QListView and QIconView of Qt3.
+ *
+ * @see DolphinIconsView
+ * @see DolphinDetailsView
+ * @author Peter Penz <[email protected]>
+ */
+class ItemEffectsManager
+{
+public:
+ ItemEffectsManager();
+ virtual ~ItemEffectsManager();
+
+ /** Is invoked before the items get updated. */
+ virtual void beginItemUpdates() = 0;
+
+ /** Is invoked after the items have been updated. */
+ virtual void endItemUpdates() = 0;
+
+ /**
+ * Increases the size of the current set view mode and refreshes
+ * all views. Derived implementations must invoke the base implementation
+ * if zooming in had been done.
+ */
+ virtual void zoomIn();
+
+ /**
+ * Decreases the size of the current set view mode and refreshes
+ * all views. Derived implementations must invoke the base implementation
+ * if zooming out had been done.
+ */
+ virtual void zoomOut();
+
+ /**
+ * Returns true, if zooming in is possible. If false is returned,
+ * the minimal zoom size is possible.
+ */
+ virtual bool isZoomInPossible() const = 0;
+
+ /**
+ * Returns true, if zooming in is possible. If false is returned,
+ * the minimal zoom size is possible.
+ */
+ virtual bool isZoomOutPossible() const = 0;
+
+protected:
+ virtual void setContextPixmap(void* context,
+ const QPixmap& pixmap) = 0;
+ virtual const QPixmap* contextPixmap(void* context) = 0;
+ virtual void* firstContext() = 0;
+ virtual void* nextContext(void* context) = 0;
+ virtual KFileItem* contextFileInfo(void* context) = 0;
+
+ void activateItem(void* context);
+ void resetActivatedItem();
+ void updateDisabledItems();
+
+private:
+ struct DisabledItem {
+ KURL url;
+ QPixmap pixmap;
+ };
+
+ QPixmap* m_pixmapCopy;
+ KURL m_highlightedURL;
+
+ // contains all items which have been disabled by a 'cut' operation
+ QValueList<DisabledItem> m_disabledItems;
+
+ /** Returns the text for the statusbar for an activated item. */
+ QString statusBarText(KFileItem* fileInfo) const;
+};
+
+#endif
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..73c5b11
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,82 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Marcel Juhnke <[email protected]> *
+ * Copyright (C) 2006 by Peter Penz <[email protected]> *
+ * Copyright (C) 2006 by Stefan Monov <[email protected]> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "dolphin.h"
+#include <kapplication.h>
+#include <dcopclient.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+#include <krun.h>
+
+static KCmdLineOptions options[] =
+{
+ { "+[URL]", I18N_NOOP( "Document to open" ), 0 },
+ KCmdLineLastOption
+};
+
+int main(int argc, char **argv)
+{
+ KAboutData about("d3lphin",
+ I18N_NOOP("Dolphin"),
+ "0.9.2",
+ I18N_NOOP("File Manager"),
+ KAboutData::License_GPL,
+ "(C) 2007 Marcel Juhnke");
+ about.setHomepage("https://marrat.homelinux.org/D3lphin");
+ about.setBugAddress("[email protected]");
+ about.addAuthor("Marcel Juhnke", I18N_NOOP("Maintainer and developer"), "[email protected]");
+ about.addAuthor("Michael Austin", I18N_NOOP("Documentation"), "[email protected]");
+ about.addAuthor("Orville Bennett", I18N_NOOP("Documentation"), "[email protected]");
+ about.addCredit("Peter Penz", I18N_NOOP("... for the great original Dolphin"));
+ about.addCredit("Cvetoslav Ludmiloff, Stefan Monov", I18N_NOOP("... for their development on the original Dolphin"));
+ about.addCredit("Aaron J. Seigo", I18N_NOOP("... for the great support and the amazing patches for the orignal Dolphin"));
+ about.addCredit("Patrice Tremblay, Gregor Kalisnik, Filip Brcic, Igor Stepin and Jan Mette", I18N_NOOP("... for their patches"));
+ about.addCredit("Ain, Itai, Ivan, Jannick, Stephane, Patrice, Piotr, Stefano and Power On",
+ I18N_NOOP("... for their translations"));
+
+ KCmdLineArgs::init(argc, argv, &about);
+ KCmdLineArgs::addCmdLineOptions(options);
+
+ KApplication app;
+ Dolphin& mainWin = Dolphin::mainWin();
+ mainWin.show();
+
+ if (app.isRestored()) {
+ int n = 1;
+ while (KMainWindow::canBeRestored(n)){
+ Dolphin::mainWin().restore(n);
+ ++n;
+ }
+ } else {
+ KCmdLineArgs* args = KCmdLineArgs::parsedArgs();
+ if (args->count() > 0) {
+ mainWin.activeView()->setURL(args->url(0));
+
+ for (int i = 1; i < args->count(); ++i) {
+ KRun::run("d3lphin", args->url(i));
+ }
+ }
+ args->clear();
+ }
+
+ return app.exec();
+}
diff --git a/src/pics/128x128/Makefile.am b/src/pics/128x128/Makefile.am
new file mode 100644
index 0000000..5c6f8a9
--- /dev/null
+++ b/src/pics/128x128/Makefile.am
@@ -0,0 +1,3 @@
+iconsdir = $(kde_datadir)/d3lphin/icons/hicolor/128x128/actions
+icons_DATA = preview.png
+
diff --git a/src/pics/128x128/preview.png b/src/pics/128x128/preview.png
new file mode 100644
index 0000000..f55dbfd
--- /dev/null
+++ b/src/pics/128x128/preview.png
Binary files differ
diff --git a/src/pics/16x16/Makefile.am b/src/pics/16x16/Makefile.am
new file mode 100644
index 0000000..1fa272b
--- /dev/null
+++ b/src/pics/16x16/Makefile.am
@@ -0,0 +1,3 @@
+iconsdir = $(kde_datadir)/d3lphin/icons/hicolor/16x16/actions
+icons_DATA = preview.png editurl.png
+
diff --git a/src/pics/16x16/editurl.png b/src/pics/16x16/editurl.png
new file mode 100644
index 0000000..1c4d2a6
--- /dev/null
+++ b/src/pics/16x16/editurl.png
Binary files differ
diff --git a/src/pics/16x16/preview.png b/src/pics/16x16/preview.png
new file mode 100644
index 0000000..d9010c8
--- /dev/null
+++ b/src/pics/16x16/preview.png
Binary files differ
diff --git a/src/pics/22x22/Makefile.am b/src/pics/22x22/Makefile.am
new file mode 100644
index 0000000..245df4b
--- /dev/null
+++ b/src/pics/22x22/Makefile.am
@@ -0,0 +1,3 @@
+iconsdir = $(kde_datadir)/d3lphin/icons/hicolor/22x22/actions
+icons_DATA = preview.png
+
diff --git a/src/pics/22x22/preview.png b/src/pics/22x22/preview.png
new file mode 100644
index 0000000..b42a438
--- /dev/null
+++ b/src/pics/22x22/preview.png
Binary files differ
diff --git a/src/pics/32x32/Makefile.am b/src/pics/32x32/Makefile.am
new file mode 100644
index 0000000..0d7f9f3
--- /dev/null
+++ b/src/pics/32x32/Makefile.am
@@ -0,0 +1,3 @@
+iconsdir = $(kde_datadir)/d3lphin/icons/hicolor/32x32/actions
+icons_DATA = preview.png
+
diff --git a/src/pics/32x32/preview.png b/src/pics/32x32/preview.png
new file mode 100644
index 0000000..f84bb90
--- /dev/null
+++ b/src/pics/32x32/preview.png
Binary files differ
diff --git a/src/pics/48x48/Makefile.am b/src/pics/48x48/Makefile.am
new file mode 100644
index 0000000..103382b
--- /dev/null
+++ b/src/pics/48x48/Makefile.am
@@ -0,0 +1,3 @@
+iconsdir = $(kde_datadir)/d3lphin/icons/hicolor/48x48/actions
+icons_DATA = preview.png
+
diff --git a/src/pics/48x48/preview.png b/src/pics/48x48/preview.png
new file mode 100644
index 0000000..7ab3b53
--- /dev/null
+++ b/src/pics/48x48/preview.png
Binary files differ
diff --git a/src/pics/64x64/Makefile.am b/src/pics/64x64/Makefile.am
new file mode 100644
index 0000000..c705496
--- /dev/null
+++ b/src/pics/64x64/Makefile.am
@@ -0,0 +1,3 @@
+iconsdir = $(kde_datadir)/d3lphin/icons/hicolor/64x64/actions
+icons_DATA = preview.png
+
diff --git a/src/pics/64x64/preview.png b/src/pics/64x64/preview.png
new file mode 100644
index 0000000..96e53fe
--- /dev/null
+++ b/src/pics/64x64/preview.png
Binary files differ
diff --git a/src/pics/Makefile.am b/src/pics/Makefile.am
new file mode 100644
index 0000000..c26c4f5
--- /dev/null
+++ b/src/pics/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = 128x128 64x64 48x48 32x32 22x22 16x16
diff --git a/src/pixmapviewer.cpp b/src/pixmapviewer.cpp
new file mode 100644
index 0000000..565b16c
--- /dev/null
+++ b/src/pixmapviewer.cpp
@@ -0,0 +1,56 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "pixmapviewer.h"
+
+#include <kglobalsettings.h>
+#include <kiconloader.h>
+#include <qpainter.h>
+
+PixmapViewer::PixmapViewer(QWidget* parent) :
+ QWidget(parent)
+{
+ setMinimumWidth(KIcon::SizeEnormous);
+ setMinimumWidth(KIcon::SizeEnormous);
+}
+
+PixmapViewer::~PixmapViewer()
+{
+}
+
+void PixmapViewer::setPixmap(const QPixmap& pixmap)
+{
+ m_pixmap = pixmap;
+ update();
+}
+
+void PixmapViewer::paintEvent(QPaintEvent* event)
+{
+ QWidget::paintEvent(event);
+
+ QPainter painter;
+ painter.begin(this);
+ const int x = (width() - m_pixmap.width()) / 2;
+ const int y = (height() - m_pixmap.height()) / 2;
+ painter.drawPixmap(x, y, m_pixmap);
+ painter.end();
+}
+
+#include "pixmapviewer.moc"
diff --git a/src/pixmapviewer.h b/src/pixmapviewer.h
new file mode 100644
index 0000000..6c24974
--- /dev/null
+++ b/src/pixmapviewer.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef PIXMAPVIEWER_H
+#define PIXMAPVIEWER_H
+
+#include <qwidget.h>
+#include <qpixmap.h>
+
+/**
+ * @brief Widget which shows a pixmap centered inside the boundaries.
+ *
+ * @see IconsViewSettingsPage
+ * @author Peter Penz <[email protected]>
+ */
+class PixmapViewer : public QWidget
+{
+ Q_OBJECT
+public:
+ PixmapViewer(QWidget* parent);
+ virtual ~PixmapViewer();
+ void setPixmap(const QPixmap& pixmap);
+ const QPixmap& pixmap() const { return m_pixmap; }
+
+protected:
+ virtual void paintEvent(QPaintEvent* event);
+
+private:
+ QPixmap m_pixmap;
+};
+
+
+#endif
diff --git a/src/progressindicator.cpp b/src/progressindicator.cpp
new file mode 100644
index 0000000..6509150
--- /dev/null
+++ b/src/progressindicator.cpp
@@ -0,0 +1,80 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "progressindicator.h"
+#include "dolphin.h"
+#include "dolphinstatusbar.h"
+
+ProgressIndicator::ProgressIndicator(const QString& progressText,
+ const QString& finishedText,
+ int operationsCount)
+ : m_showProgress(false),
+ m_operationsCount(operationsCount),
+ m_operationsIndex(0),
+ m_startTime(QTime::currentTime()),
+ m_finishedText(finishedText)
+{
+ DolphinStatusBar* statusBar = Dolphin::mainWin().activeView()->statusBar();
+ statusBar->clear();
+ statusBar->setProgressText(progressText);
+ statusBar->setProgress(0);
+}
+
+
+ProgressIndicator::~ProgressIndicator()
+{
+ DolphinStatusBar* statusBar = Dolphin::mainWin().activeView()->statusBar();
+ statusBar->setProgressText(QString::null);
+ statusBar->setProgress(100);
+ statusBar->setMessage(m_finishedText, DolphinStatusBar::OperationCompleted);
+
+ if (m_showProgress) {
+ Dolphin::mainWin().setEnabled(true);
+ }
+}
+
+void ProgressIndicator::execOperation()
+{
+ ++m_operationsIndex;
+
+ if (!m_showProgress) {
+ const int elapsed = m_startTime.msecsTo(QTime::currentTime());
+ if (elapsed > 500) {
+ // the operations took already more than 500 milliseconds,
+ // therefore show a progress indication
+ Dolphin::mainWin().setEnabled(false);
+ m_showProgress = true;
+ }
+ }
+
+ if (m_showProgress) {
+ const QTime currentTime = QTime::currentTime();
+ if (m_startTime.msecsTo(currentTime) > 100) {
+ m_startTime = currentTime;
+
+ DolphinStatusBar* statusBar = Dolphin::mainWin().activeView()->statusBar();
+ statusBar->setProgress((m_operationsIndex * 100) / m_operationsCount);
+ kapp->processEvents();
+ statusBar->repaint();
+ }
+ }
+}
+
+
diff --git a/src/progressindicator.h b/src/progressindicator.h
new file mode 100644
index 0000000..7889607
--- /dev/null
+++ b/src/progressindicator.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+#ifndef PROGRESSINDICATOR_H
+#define PROGRESSINDICATOR_H
+
+#include <qdatetime.h>
+
+/**
+ * Allows to show a progress of synchronous operations. Sample code:
+ * \code
+ * const int operationsCount = 100;
+ * ProgressIndicator progressIndicator(i18n("Loading..."),
+ * i18n("Loading finished."),
+ * operationsCount);
+ * for (int i = 0; i < operationsCount; ++i) {
+ * progressIndicator.execOperation();
+ * // do synchronous operation...
+ * }
+ * \endcode
+ * The progress indicator takes care to show the progress bar only after
+ * a delay of around 500 milliseconds. This means if all operations are
+ * executing within 500 milliseconds, no progress bar is shown at all.
+ * As soon as the progress bar is shown, the application still may process
+ * events, but the the Dolphin main widget is disabled.
+ *
+ * @author Peter Penz <[email protected]>
+ */
+class ProgressIndicator
+{
+public:
+ /**
+ * @param progressText Text for the progress bar (e. g. "Loading...").
+ * @param finishedText Text which is displayed after the operations have been finished
+ * (e. g. "Loading finished.").
+ * @param operationsCount Number of operations.
+ */
+ ProgressIndicator(const QString& progressText,
+ const QString& finishedText,
+ int operationsCount);
+
+ /**
+ * Sets the progress to 100 % and displays the 'finishedText' property
+ * in the status bar.
+ */
+ ~ProgressIndicator();
+
+ /**
+ * Increases the progress and should be invoked
+ * before each operation.
+ */
+ void execOperation();
+
+private:
+ bool m_showProgress;
+ int m_operationsCount;
+ int m_operationsIndex;
+ QTime m_startTime;
+ QString m_finishedText;
+};
+
+#endif
diff --git a/src/renamedialog.cpp b/src/renamedialog.cpp
new file mode 100644
index 0000000..7ec8681
--- /dev/null
+++ b/src/renamedialog.cpp
@@ -0,0 +1,89 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "renamedialog.h"
+#include <klocale.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qvbox.h>
+#include <assert.h>
+#include <klineedit.h>
+
+RenameDialog::RenameDialog(const KURL::List& items) :
+ KDialogBase(Plain, i18n("Rename Items"),
+ Ok|Cancel, Ok)
+{
+ setButtonOK(KGuiItem(i18n("Rename"), "apply"));
+
+ QVBoxLayout* topLayout = new QVBoxLayout(plainPage(), 0, spacingHint());
+ topLayout->setMargin(KDialog::marginHint());
+
+ const int itemCount = items.count();
+ QLabel* editLabel = new QLabel(i18n("Rename the %n selected items to:", "Rename the %n selected items to:", itemCount),
+ plainPage());
+
+ m_lineEdit = new KLineEdit(plainPage());
+ m_newName = i18n("New name #");
+ assert(itemCount > 1);
+ QString postfix(items[0].prettyURL().section('.',1));
+ if (postfix.length() > 0) {
+ // The first item seems to have a postfix (e. g. 'jpg' or 'txt'). Now
+ // check whether all other items have the same postfix. If this is the
+ // case, add this postfix to the name suggestion.
+ postfix.insert(0, '.');
+ for (int i = 1; i < itemCount; ++i) {
+ if (!items[i].prettyURL().contains(postfix)) {
+ // at least one item does not have the same postfix
+ postfix.truncate(0);
+ break;
+ }
+ }
+ }
+
+ const int selectionLength = m_newName.length();
+ if (postfix.length() > 0) {
+ m_newName.append(postfix);
+ }
+ m_lineEdit->setText(m_newName);
+ m_lineEdit->setSelection(0, selectionLength - 1);
+ m_lineEdit->setFocus();
+
+ QLabel* infoLabel = new QLabel(i18n("(# will be replaced by ascending numbers)"), plainPage());
+
+ topLayout->addWidget(editLabel);
+ topLayout->addWidget(m_lineEdit);
+ topLayout->addWidget(infoLabel);
+}
+
+RenameDialog::~RenameDialog()
+{
+}
+
+void RenameDialog::slotOk()
+{
+ m_newName = m_lineEdit->text();
+ if (m_newName.contains('#') != 1) {
+ m_newName.truncate(0);
+ }
+
+ KDialogBase::slotOk();
+}
+
+#include "renamedialog.moc"
diff --git a/src/renamedialog.h b/src/renamedialog.h
new file mode 100644
index 0000000..fb743db
--- /dev/null
+++ b/src/renamedialog.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+#ifndef RENAMEDIALOG_H
+#define RENAMEDIALOG_H
+
+#include <kdialogbase.h>
+#include <kurl.h>
+#include <qstring.h>
+
+class KLineEdit;
+
+/**
+ * @brief Dialog for renaming a variable number of files.
+ *
+ * The renaming is not done by the dialog, the invoker
+ * must do this itself:
+ * \code
+ * RenameDialog dialog(...);
+ * if (dialog.exec() == QDialog::Accepted) {
+ * const QString& newName = dialog.newName();
+ * // ... rename items corresponding to the new name
+ * }
+ * \endcode
+ * @author Peter Penz
+ */
+class RenameDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ RenameDialog(const KURL::List& items);
+ virtual ~RenameDialog();
+
+ /**
+ * Returns the new name of the items. If the returned string is not empty,
+ * then it is assured that the string contains exactly one character #,
+ * which should be replaced by ascending numbers. An empty string indicates
+ * that the user has removed the # character.
+ */
+ const QString& newName() const { return m_newName; }
+
+protected slots:
+ virtual void slotOk();
+
+private:
+ KLineEdit* m_lineEdit;
+ QString m_newName;
+};
+
+#endif
diff --git a/src/servicemenus/Makefile.am b/src/servicemenus/Makefile.am
new file mode 100644
index 0000000..45d121f
--- /dev/null
+++ b/src/servicemenus/Makefile.am
@@ -0,0 +1,18 @@
+servicemenusdir = $(kde_datadir)/d3lphin/servicemenus
+servicemenus_DATA = compress.desktop amarok_addaspodcast.desktop amarok_append.desktop \
+ amarok_play_audiocd.desktop ark_compress.desktop ark_extract.desktop ark_extract_subdir.desktop \
+ d3lphin_su.desktop edit_as_root.desktop encryptfile.desktop encryptfolder.desktop \
+ floppy_format.desktop imageconverter.desktop installfont.desktop jpegorient.desktop \
+ k3b_audiocd_rip.desktop k3b_cd_copy.desktop k3b_create_audio_cd.desktop \
+ k3b_create_video_cd.desktop k3b_dvd_copy.desktop k3b_handle_empty_cd.desktop \
+ k3b_handle_empty_dvd.desktop k3b_videodvd_rip.desktop k3b_write_bin_image.desktop \
+ k3b_write_iso_image.desktop kdesktopSetAsBackground.desktop konqgwenview.desktop \
+ konsolehere.desktop mail_as_attachment.desktop media_eject.desktop media_mount.desktop \
+ media_realfolder.desktop media_safelyremove.desktop media_unmount.desktop \
+ open_in_digikam.desktop run_as_root.desktop smb2rdc.desktop text-ada-print.desktop \
+ text-c++-print.desktop text-c++h-print.desktop text-ch-print.desktop text-css-print.desktop \
+ text-diff-print.desktop text-html-print.desktop text-java-print.desktop text-log-print.desktop \
+ text-makefile-print.desktop text-pas-print.desktop text-perl-print.desktop text-print.desktop \
+ text-python-print.desktop text-tcl-print.desktop text-tex-print.desktop text-xml-print.desktop \
+ text-xslt-print.desktop
+
diff --git a/src/servicemenus/Makefile.am.new b/src/servicemenus/Makefile.am.new
new file mode 100644
index 0000000..45d121f
--- /dev/null
+++ b/src/servicemenus/Makefile.am.new
@@ -0,0 +1,18 @@
+servicemenusdir = $(kde_datadir)/d3lphin/servicemenus
+servicemenus_DATA = compress.desktop amarok_addaspodcast.desktop amarok_append.desktop \
+ amarok_play_audiocd.desktop ark_compress.desktop ark_extract.desktop ark_extract_subdir.desktop \
+ d3lphin_su.desktop edit_as_root.desktop encryptfile.desktop encryptfolder.desktop \
+ floppy_format.desktop imageconverter.desktop installfont.desktop jpegorient.desktop \
+ k3b_audiocd_rip.desktop k3b_cd_copy.desktop k3b_create_audio_cd.desktop \
+ k3b_create_video_cd.desktop k3b_dvd_copy.desktop k3b_handle_empty_cd.desktop \
+ k3b_handle_empty_dvd.desktop k3b_videodvd_rip.desktop k3b_write_bin_image.desktop \
+ k3b_write_iso_image.desktop kdesktopSetAsBackground.desktop konqgwenview.desktop \
+ konsolehere.desktop mail_as_attachment.desktop media_eject.desktop media_mount.desktop \
+ media_realfolder.desktop media_safelyremove.desktop media_unmount.desktop \
+ open_in_digikam.desktop run_as_root.desktop smb2rdc.desktop text-ada-print.desktop \
+ text-c++-print.desktop text-c++h-print.desktop text-ch-print.desktop text-css-print.desktop \
+ text-diff-print.desktop text-html-print.desktop text-java-print.desktop text-log-print.desktop \
+ text-makefile-print.desktop text-pas-print.desktop text-perl-print.desktop text-print.desktop \
+ text-python-print.desktop text-tcl-print.desktop text-tex-print.desktop text-xml-print.desktop \
+ text-xslt-print.desktop
+
diff --git a/src/servicemenus/amarok_addaspodcast.desktop b/src/servicemenus/amarok_addaspodcast.desktop
new file mode 100644
index 0000000..7c61588
--- /dev/null
+++ b/src/servicemenus/amarok_addaspodcast.desktop
@@ -0,0 +1,8 @@
+[Desktop Entry]
+ServiceTypes=text/html,text/xml,application/xml,text/rss
+Actions=addAsPodcast
+[Desktop Action addAsPodcast]
+Name=Add as podcast to amaroK
+Name[de]=Als Podcast zu amaroK hinzufügen
+Icon=amarok
+Exec=dcop amarok playlistbrowser addPodcast %u
diff --git a/src/servicemenus/amarok_append.desktop b/src/servicemenus/amarok_append.desktop
new file mode 100644
index 0000000..acf3cb0
--- /dev/null
+++ b/src/servicemenus/amarok_append.desktop
@@ -0,0 +1,96 @@
+[Desktop Entry]
+ServiceTypes=application/asx,audio/*
+Actions=appendToPlaylist;appendAndPlay;queueTrack;
+X-KDE-Submenu=Amarok
+X-KDE-Submenu[bn]=আমারক
+X-KDE-Submenu[pa]=ਅਮਰੋਕ
+X-KDE-Submenu[xx]=xxAmarokxx
+
+[Desktop Action appendToPlaylist]
+Name=Append to Playlist
+Name[bg]=Добавяне към списъка с песни
+Name[bn]=সঙ্গীত-তালিকাতে সংযোজন করো
+Name[br]=Ouzhpennañ d'ar roll tonioù
+Name[cs]=Přidat do seznamu skladeb
+Name[da]=Tilføj til spilleliste
+Name[de]=An Amarok-Wiedergabeliste anhängen
+Name[el]=Προσθήκη στη λίστα αναπαραγωγής
+Name[et]=Lisa lugude nimekirja
+Name[fi]=Lisää soittolistaan
+Name[fr]=Ajouter à la liste de lecture
+Name[ga]=Iarcheangail le Seinmliosta
+Name[it]=Aggiungi alla playlist
+Name[ja]=プレイリストに追加
+Name[km]=បន្ថែម​ទៅ​ខាង​ចុង​បញ្ជីចាក់
+Name[nl]=Toevoegen aanafspeellijst
+Name[pa]=ਸੰਗੀਤ-ਸੂਚੀ 'ਚ ਸ਼ਾਮਲ
+Name[pl]=Dołącz do listy odtwarzania
+Name[pt]=Adicionar à Lista do Amarok
+Name[pt_BR]=Anexar à Lista de Músicas
+Name[ru]=Добавить в список
+Name[sv]=Lägg till i spellistan
+Name[uk]=Додати до списку композицій
+Name[uz]=Қўшиқ рўйхатига қўшиш
+Name[xx]=xxAppend to Playlistxx
+Name[zh_CN]=追加到播放列表
+Icon=amarok
+Exec=amarok -e %U
+
+[Desktop Action appendAndPlay]
+Name=Append & Play
+Name[bg]=Добавяне и възпроизвеждане
+Name[bn]=সংযোজন করো এবং বাজাও
+Name[br]=Ouzhpennañ ha seniñ
+Name[cs]=Připojit a hrát
+Name[da]=Tilføj og spil
+Name[de]=Anhängen und abspielen
+Name[el]=Προσθήκη & αναπαραγωγή
+Name[et]=Lisa ja esita
+Name[fi]=Lisää soittolistaan ja toista
+Name[fr]=Ajouter & Écouter
+Name[ga]=Iarcheangail & Seinn
+Name[it]=Aggiungi & Riproduci
+Name[ja]=追加して再生
+Name[km]=បន្ថែម​ខាង​ចុង & ចាក់
+Name[nl]=Toevoegen en afspelen
+Name[pa]=ਜੋੜੋ ਅਤੇ ਚਲਾਓ
+Name[pl]=Dołącz i odtwórz
+Name[pt]=Adicionar & Reproduzir
+Name[pt_BR]=Anexar & Reproduzir
+Name[ru]=Добавить и запустить
+Name[sv]=Lägg till och spela
+Name[uk]=Додати і програти
+Name[uz]=Қўшиш ва ўйнаш
+Name[xx]=xxAppend & Playxx
+Name[zh_CN]=追加并播放
+Icon=amarok
+Exec=dcop amarok playlist playMedia %U
+
+[Desktop Action queueTrack]
+Name=Queue Track
+Name[bg]=Добавяне и възпроизвеждане
+Name[bn]=গান সারিবদ্ধ করো
+Name[cs]=Zařadit skladbu
+Name[da]=Sæt spor i kø
+Name[de]=Stück in Warteschlange einstellen
+Name[el]=Εισαγωγή του κομματιού στην ουρά
+Name[et]=Sea pala järjekorda
+Name[fi]=Lisää jonoon
+Name[fr]=Ajouter à la file d'attente
+Name[ga]=Ciúáil Amhrán
+Name[it]=Accoda traccia
+Name[ja]=トラックをキュー
+Name[km]=ដាក់​បទ​ក្នុង​ជួរ
+Name[nl]=Track in wachtrij plaatsen
+Name[pa]=ਟਰੈਕ ਕਤਾਰ 'ਚ
+Name[pl]=Wstaw utwór do kolejki
+Name[pt]=Pôr a Faixa na Fila
+Name[pt_BR]=Faixa para Fila
+Name[ru]=Добавить после текущей
+Name[sv]=Köa spår
+Name[uk]=Додати доріжку в чергу
+Name[uz]=Навбатга қўйиш
+Name[xx]=xxQueue Trackxx
+Name[zh_CN]=音轨排队
+Icon=amarok
+Exec=amarok --queue %U
diff --git a/src/servicemenus/amarok_play_audiocd.desktop b/src/servicemenus/amarok_play_audiocd.desktop
new file mode 100644
index 0000000..4bfa828
--- /dev/null
+++ b/src/servicemenus/amarok_play_audiocd.desktop
@@ -0,0 +1,49 @@
+[Desktop Entry]
+ServiceTypes=media/audiocd
+Actions=Play;
+Encoding=UTF-8
+X-KDE-Priority=TopLevel
+
+[Desktop Action Play]
+Name=Play Audio CD with Amarok
+Name[af]=Speel oudio CD met Amarok
+Name[bg]=Изпълнение на компактдиск с Amarok
+Name[bn]=আমারক দিয়ে অডিও সিডি চালাও
+Name[ca]=Reprodueix el CD Àudio amb l'Amarok
+Name[cs]=Přehrát audio CD
+Name[da]=Afspil lyd-cd med Amarok
+Name[de]=Audio-CD mit Amarok wiedergeben
+Name[el]=Αναπαραγωγή CD ήχου με το Amarok
+Name[eo]=Ludi Muzikan KD-n per Amarok
+Name[es]=Reproducir CD con Amarok
+Name[et]=Esita audio CD Amarokis
+Name[fa]=پخش دیسک فشردۀ صوتی با Amarok
+Name[fi]=Soita CD-levy Amarokilla
+Name[fr]=Écouter un CD Audio avec Amarok
+Name[ga]=Seinn Dlúthdhiosca Fuaime le Amarok
+Name[hu]=Hang-CD lejátszása az Amarokkal
+Name[is]=Spila tónlistardisk með Amarok
+Name[it]=Riproduci CD audio con Amarok
+Name[ja]=Amarok でオーディオ CD を再生
+Name[km]=ចាក់​ស៊ីឌី​អូឌីយ៉ូ​ជា​មួយ Amarok
+Name[lt]=Groti audio CD su Amarok
+Name[mk]=Свири аудиоцд со Амарок
+Name[nds]=Audio-CD mit Amarok afspelen
+Name[nl]=Audio-cd met Amarok afspelen
+Name[pa]=ਅਮਰੋਕ ਨਾਲ ਆਡੀਓ CD ਚਲਾਓ
+Name[pl]=Odtwórz Audio CD za pomocą Amarok
+Name[pt]=Tocar o CD de Áudio com o Amarok
+Name[pt_BR]=Reproduzir CD de Áudio com o Amarok
+Name[se]=Čuojat jietna-CD:a Amarokain
+Name[sk]=Zahrať Audio CD pomocou Amarok
+Name[sr]=Пусти аудио CD помоћу Amarok-а
+Name[sr@Latn]=Pusti audio CD pomoću Amarok-a
+Name[sv]=Spela ljud-cd med Amarok
+Name[th]=เล่นซีดีบันทึกเสียงด้วย Amarok
+Name[tr]=Ses CD'sini Amarok ile Çal
+Name[uk]=Грати аудіо-КД в Amarok
+Name[uz]=Аудио-дискни Amarok билан тинглаш
+Name[wa]=Djouwer l' CD d' muzike avou Amarok
+Name[zh_CN]=用 Amarok 播放音频 CD
+Icon=amarok
+Exec=amarok --cdplay %u
diff --git a/src/servicemenus/ark_compress.desktop b/src/servicemenus/ark_compress.desktop
new file mode 100644
index 0000000..308a450
--- /dev/null
+++ b/src/servicemenus/ark_compress.desktop
@@ -0,0 +1,21 @@
+[Desktop Entry]
+ServiceTypes=inode/directory
+Actions=CompressZip;CompressTarGz;CompressTarBz2
+X-KDE-Priority=TopLevel
+X-KDE-Submenu=Compress
+
+[Desktop Action CompressZip]
+Name=Zip Archive
+Icon=ark
+Exec=ark --add-to %u %u.zip
+
+[Desktop Action CompressTarGz]
+Name=Gzipped Tar Archive
+Icon=ark
+Exec=ark --add-to %u %u.tar.gz
+
+[Desktop Action CompressTarBz2]
+Name=Bzip2 Tar Archive
+Icon=ark
+Exec=ark --add-to %u %u.tar.bz2
+
diff --git a/src/servicemenus/ark_extract.desktop b/src/servicemenus/ark_extract.desktop
new file mode 100644
index 0000000..1c54fd6
--- /dev/null
+++ b/src/servicemenus/ark_extract.desktop
@@ -0,0 +1,11 @@
+[Desktop Entry]
+X-SuSE-translate=true
+Encoding=UTF-8
+ServiceTypes=application/x-gzip,application/x-lha,application/x-tar,application/x-tgz,application/x-tbz,application/x-tbz2,application/x-zip,application/x-bzip,application/x-tzo,application/x-lzop,application/x-rar,application/x-rar-compressed,application/x-zoo,application/x-tarz,application/x-archive,application/x-bzip2,application/x-jar,application/x-deb,application/x-ace,application/x-7z,application/x-arc,application/x-arj,application/x-compress,application/x-cpio,application/x-pak
+Actions=extractHere
+
+[Desktop Action extractHere]
+Name=Extract Here
+Name[de]=Hierher entpacken
+Exec=ark --extract-to %d %u
+Icon=ark
diff --git a/src/servicemenus/ark_extract_subdir.desktop b/src/servicemenus/ark_extract_subdir.desktop
new file mode 100644
index 0000000..9d52df1
--- /dev/null
+++ b/src/servicemenus/ark_extract_subdir.desktop
@@ -0,0 +1,11 @@
+[Desktop Entry]
+X-SuSE-translate=true
+Encoding=UTF-8
+ServiceTypes=application/x-gzip,application/x-lha,application/x-tar,application/x-tgz,application/x-tbz,application/x-tbz2,application/x-zip,application/x-bzip,application/x-tzo,application/x-lzop,application/x-rar,application/x-rar-compressed,application/x-zoo,application/x-tarz,application/x-archive,application/x-bzip2,application/x-jar,application/x-deb,application/x-ace,application/x-7z,application/x-arc,application/x-arj,application/x-compress,application/x-cpio,application/x-pak
+Actions=ExtractSubdir
+
+[Desktop Action ExtractSubdir]
+Name=Extract to subdirectory
+Name[de]=In Unterordner entpacken
+Icon=ark
+Exec=ark -caption "%c" %i %m --guess-name --extract-to "%d" "%u"
diff --git a/src/servicemenus/compress.desktop b/src/servicemenus/compress.desktop
new file mode 100644
index 0000000..5d199ba
--- /dev/null
+++ b/src/servicemenus/compress.desktop
@@ -0,0 +1,21 @@
+[Desktop Entry]
+ServiceTypes=all/allfiles
+Actions=CompressZip;CompressTarGz;CompressTarBz2
+X-KDE-Priority=TopLevel
+X-KDE-Submenu=Compress
+
+[Desktop Action CompressZip]
+Name=Zip Archive
+Icon=ark
+Exec=ark --add-to %u %u.zip
+
+[Desktop Action CompressTarGz]
+Name=Gzipped Tar Archive
+Icon=ark
+Exec=ark --add-to %u %u.tar.gz
+
+[Desktop Action CompressTarBz2]
+Name=Bzip2 Tar Archive
+Icon=ark
+Exec=ark --add-to %u %u.tar.bz2
+
diff --git a/src/servicemenus/d3lphin_su.desktop b/src/servicemenus/d3lphin_su.desktop
new file mode 100644
index 0000000..ea6cb55
--- /dev/null
+++ b/src/servicemenus/d3lphin_su.desktop
@@ -0,0 +1,11 @@
+[Desktop Entry]
+ServiceTypes=inode/directory
+Actions=D3lphinSU;
+
+[Desktop Action D3lphinSU]
+ServiceTypes=inode/directory
+Name=Open as Root
+Name[de]=Öffne als Root
+Name[ru]=Открыть под root
+Icon=d3lphin
+Exec=kdesu -c "d3lphin '%U'"
diff --git a/src/servicemenus/edit_as_root.desktop b/src/servicemenus/edit_as_root.desktop
new file mode 100644
index 0000000..049454e
--- /dev/null
+++ b/src/servicemenus/edit_as_root.desktop
@@ -0,0 +1,12 @@
+[Desktop Entry]
+ServiceTypes=text/*,application/x-desktop
+Actions=Editassu
+
+[Desktop Action Editassu]
+Name=Edit as Root
+Name[it]=Edita come Root
+Name[fr]=Editer en tant que Root
+Name[es]=Editar como Root
+Name[de]=Als root bearbeiten
+Icon=kfm
+Exec=kdesu "kwrite" "%U"
diff --git a/src/servicemenus/encryptfile.desktop b/src/servicemenus/encryptfile.desktop
new file mode 100644
index 0000000..797698e
--- /dev/null
+++ b/src/servicemenus/encryptfile.desktop
@@ -0,0 +1,59 @@
+[Desktop Entry]
+ServiceTypes=all/allfiles
+ExcludeServiceTypes=kdedevice/*
+Actions=encrypt
+
+[Desktop Action encrypt]
+Name=Encrypt File
+Name[ar]=تشفير ملف
+Name[bg]=Шифроване на файл
+Name[bs]=Šifriraj datoteku
+Name[ca]=Xifra fitxer
+Name[cs]=Zašifrovat soubor
+Name[cy]=Cêl-ysgrifo Ffeil
+Name[da]=Indkod fil
+Name[de]=Datei verschlüsseln
+Name[el]=Κρυπτογράφηση αρχείου
+Name[es]=Cifrar archivo
+Name[et]=Krüpti fail
+Name[eu]=Fitxategiak Zifratu
+Name[fa]=رمزبندی پرونده
+Name[fi]=Salaa tiedosto
+Name[fr]=Chiffrer le fichier
+Name[ga]=Criptigh Comhad
+Name[he]=הצפן קובץ
+Name[hi]=एनक्रिप्ट फ़ाइल
+Name[hu]=Fájl titkosítása
+Name[is]=Dulrita skrá
+Name[it]=Cifratura file
+Name[ja]=ファイルを暗号化
+Name[kk]=Файлды шифрлау
+Name[km]=អ៊ិនគ្រីប​ឯកសារ
+Name[lt]=Šifruoti bylą
+Name[mk]=Криптирај датотеки
+Name[nb]=Krypter fil
+Name[nds]=Dateiverslöteln
+Name[ne]=फाइल गुप्तीकरण गर्नुहोस्
+Name[nl]=Bestand versleutelen
+Name[nn]=Krypter fil
+Name[pa]=ਇੰਕਰਿਪਟ ਫਾਇਲ
+Name[pl]=Zaszyfruj plik
+Name[pt]=Cifrar Ficheiro
+Name[pt_BR]=Criptografar Arquivo
+Name[ro]=Criptează fişierul
+Name[ru]=Зашифровать файл
+Name[sk]=Šifrovať súbor
+Name[sl]=Šifriraj datoteko
+Name[sr]=Шифруј фајл
+Name[sr@Latn]=Šifruj fajl
+Name[sv]=Kryptera fil
+Name[ta]=சங்கேத கோப்பு
+Name[tg]=Рамзкунонии Файл
+Name[tr]=Dosya Şifrele
+Name[uk]=Зашифрувати файл
+Name[wa]=Ecripter fitchî
+Name[zh_CN]=加密文件
+Name[zh_TW]=加密檔案
+Icon=kgpg
+Exec=kgpg -e %F
+
diff --git a/src/servicemenus/encryptfolder.desktop b/src/servicemenus/encryptfolder.desktop
new file mode 100644
index 0000000..b322b64
--- /dev/null
+++ b/src/servicemenus/encryptfolder.desktop
@@ -0,0 +1,50 @@
+[Desktop Entry]
+ServiceTypes=inode/directory
+Actions=encrypt
+
+[Desktop Action encrypt]
+Name=Archive & Encrypt Folder
+Name[ar]=أرشفة و تشفير مجلّد
+Name[bg]=Архивиране и шифроване на директория
+Name[bs]=Arhiviraj i šifriraj direktorij
+Name[ca]=Arxiva i xifra la carpeta
+Name[cs]=Archivovat a zašifrovat složku
+Name[da]=Arkivér & kryptér mappe
+Name[de]=Ordner packen und verschlüsseln
+Name[el]=Αρχειοθέτηση & κρυπτογράφηση φακέλου
+Name[es]=Archivar y cifrar carpeta
+Name[et]=Arhiveeri ja krüpti kataloog
+Name[eu]=Artxibatu eta enkriptatu karpeta
+Name[fa]=بایگانی و رمزبندی پوشه
+Name[fi]=Pakkaa ja salaa kansio
+Name[fr]=Archiver puis chiffrer le dossier
+Name[ga]=Cuir Fillteán i gCartlann & Criptigh É
+Name[he]=כלי להצפנה וכיווץ תקייה
+Name[hu]=Könyvtár titkosítása és archiválása
+Name[is]=Pakka og dulrita möppu
+Name[it]=Archivia e cifra cartella
+Name[ja]=フォルダをアーカイブ化 & 暗号化
+Name[kk]=Қапшықты архивтеп шифрлау
+Name[km]=ថត​ប័ណ្ណសារ & អ៊ិនគ្រីប
+Name[lt]=Archyvuoti ir šifruoti aplanką
+Name[nb]=Arkiver og krypter mappe
+Name[nds]=Ornern komprimeren un verslöteln
+Name[ne]=फोल्डरलाई सङ्ग्रह र गुप्तीकरण गर्नुहोस्
+Name[nl]=Map archiveren en versleutelen
+Name[nn]=Arkiver og krypter mappe
+Name[pa]=ਆਕੀਵੀ & ਇੰਕਰਿਪਟ ਫੋਲਡਰ
+Name[pl]=Zarchiwizuj i zaszyfruj katalog
+Name[pt]=Arquivar e Cifrar a Pasta
+Name[pt_BR]=Arquivar & Criptografar Pasta
+Name[ru]=Архивировать и зашифровать папку
+Name[sk]=Archivovať a šifrovať priečinok
+Name[sl]=Arhiviranje in ši&friranje imenika
+Name[sr]=Архивирај и шифруј фасциклу
+Name[sr@Latn]=Arhiviraj i šifruj fasciklu
+Name[sv]=Arkivera och kryptera katalog
+Name[tr]=Arşiv ve Klasör Şifrele
+Name[uk]=Зробити архів теки і зашифрувати
+Name[zh_CN]=存档并加密文件夹
+Name[zh_TW]=壓縮並加密資料夾
+Icon=kgpg
+Exec=kgpg -e %F
diff --git a/src/servicemenus/floppy_format.desktop b/src/servicemenus/floppy_format.desktop
new file mode 100644
index 0000000..b175347
--- /dev/null
+++ b/src/servicemenus/floppy_format.desktop
@@ -0,0 +1,36 @@
+[Desktop Action Format]
+Exec=kfloppy %u
+Icon=kfloppy
+Name=Format
+Name[bg]=Форматиране
+Name[br]=Furmadiñ
+Name[ca]=Dona format
+Name[cs]=Formátovat
+Name[cy]=Fformat
+Name[de]=Formatieren
+Name[eo]=Formato
+Name[es]=Formatear
+Name[fr]=Formater
+Name[ga]=Formáid
+Name[it]=Formatta
+Name[ja]=フォーマット
+Name[lt]=Formatas
+Name[nl]=Formatteren
+Name[pa]=ਫਾਰਮਿਟ
+Name[pl]=Formatuj
+Name[pt]=Formatar
+Name[pt_BR]=Formatar
+Name[ru]=Форматирование дискет
+Name[rw]=Imiterere
+Name[sr]=Форматирај
+Name[sr@Latn]=Formatiraj
+Name[sv]=Formatera
+Name[uk]=Форматування
+Name[xx]=xxFormatxx
+Name[zh_CN]=格式化
+
+[Desktop Entry]
+Actions=Format;
+ServiceTypes=media/floppy_unmounted,media/floppy5_unmounted
+X-KDE-Priority=TopLevel
+X-KDE-MediaNotifierHide=true
diff --git a/src/servicemenus/imageconverter.desktop b/src/servicemenus/imageconverter.desktop
new file mode 100644
index 0000000..941a20b
--- /dev/null
+++ b/src/servicemenus/imageconverter.desktop
@@ -0,0 +1,61 @@
+#
+# Servicemenu image converter, by Jens Benecke <[email protected]>.
+# Released under the same license as the KDE core distribution (GPL 2.0).
+#
+[Desktop Entry]
+ServiceTypes=image/*
+Actions=convToJPEG;convToPNG;convToGIF;convToTIF;
+X-KDE-Submenu=Convert To
+X-KDE-Submenu[bg]=Конвертиране в
+X-KDE-Submenu[ca]=Converteix a
+X-KDE-Submenu[cs]=Převést na
+X-KDE-Submenu[da]=Konvertér til
+X-KDE-Submenu[de]=Konvertieren nach
+X-KDE-Submenu[es]=Convertir a
+X-KDE-Submenu[fi]=Muunna
+X-KDE-Submenu[fr]=Convertir en
+X-KDE-Submenu[hu]=Átalakítás
+X-KDE-Submenu[is]=Umbreyta í
+X-KDE-Submenu[it]=Converti in
+X-KDE-Submenu[nb]=Konverter til
+X-KDE-Submenu[nl]=Converteren naar
+X-KDE-Submenu[pl]=Konwertuj do
+X-KDE-Submenu[pt]=Converter Para
+X-KDE-Submenu[pt_BR]=Converter Para
+X-KDE-Submenu[ru]=Сохранить как
+X-KDE-Submenu[sr]=Претвори у
+X-KDE-Submenu[sr@Latn]=Pretvori u
+X-KDE-Submenu[sv]=Konvertera till
+X-KDE-Submenu[uk]=Перетворити в
+X-KDE-Submenu[xx]=xxConvert Toxx
+X-KDE-Submenu[zh_CN]=转换为
+TryExec=convert
+
+[Desktop Action convToJPEG]
+Name=JPEG
+Name[hi]=जेपीईजी
+Name[xx]=xxJPEGxx
+Icon=image
+Exec=convert %f "`echo %f | perl -pe 's/\.[^.]+$//'`.jpg"
+
+[Desktop Action convToPNG]
+Name=PNG
+Name[hi]=पीएनजी
+Name[xx]=xxPNGxx
+Icon=image
+Exec=convert %f "`echo %f | perl -pe 's/\.[^.]+$//'`.png"
+
+[Desktop Action convToTIF]
+Name=TIF
+Name[hi]=टिफ़
+Name[xx]=xxTIFxx
+Icon=image
+Exec=convert %f "`echo %f | perl -pe 's/\.[^.]+$//'`.tif"
+
+[Desktop Action convToGIF]
+Name=GIF
+Name[hi]=जिफ़
+Name[xx]=xxGIFxx
+Icon=image
+Exec=convert %f "`echo %f | perl -pe 's/\.[^.]+$//'`.gif"
+
diff --git a/src/servicemenus/installfont.desktop b/src/servicemenus/installfont.desktop
new file mode 100644
index 0000000..3ca14fa
--- /dev/null
+++ b/src/servicemenus/installfont.desktop
@@ -0,0 +1,143 @@
+[Desktop Entry]
+ServiceTypes=application/x-font-ttf,application/x-font-type1,application/x-font-speedo,application/x-font-bdf,application/x-font-pcf,application/x-font-snf,application/x-font-otf,application/x-font-ttc,application/x-afm
+Actions=installFont;
+
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+[Desktop Action installFont]
+Name=Install
+Name[af]=Installeer
+Name[be]=Усталяваць
+Name[bg]=Инсталиране
+Name[bn]=ইনস্টল
+Name[br]=Staliañ
+Name[bs]=Instaliraj
+Name[ca]=Instal·la
+Name[cs]=Instalovat
+Name[cy]=Gosod
+Name[da]=Installér
+Name[de]=Installieren
+Name[el]=Εγκατάσταση
+Name[eo]=Instalu
+Name[es]=Instalar
+Name[et]=Paigaldamine
+Name[eu]=Instalatu
+Name[fa]=نصب
+Name[fi]=Asenna
+Name[fr]=Installer
+Name[fy]=Ynstallearje
+Name[ga]=Suiteáil
+Name[gl]=Instalar
+Name[he]=התקנה
+Name[hi]=संस्थापित
+#SUSE-Overwrite Name[hr]=Instaliraj
+Name[hu]=Telepítő
+Name[is]=Setja upp
+Name[it]=Installa
+Name[ja]=インストール
+Name[km]=ដំឡើង
+Name[lt]=Įdiegti
+Name[lv]=Instalēt
+Name[mk]=Инсталирај
+Name[ms]=Pasang
+Name[mt]=Installa
+Name[nb]=Installer
+Name[nds]=Installeren
+Name[nl]=Installeren
+Name[nn]=Installer
+Name[pa]=ਇੰਸਟਾਲ
+#SUSE-Overwrite Name[pl]=Instaluj
+Name[pl]=Zainstaluj
+Name[pt]=Instalar
+Name[pt_BR]=Instalar
+Name[ro]=Instalare
+Name[ru]=Установка
+Name[rw]=Kwinjizaporogaramu
+Name[se]=Sajáiduhte
+Name[sk]=Inštalácia
+Name[sl]=Namesti
+Name[sr]=Инсталирај
+Name[sr@Latn]=Instaliraj
+Name[sv]=Installera
+Name[ta]=நிறுவி
+Name[tg]=Гузоштан
+Name[th]=ติดตั้ง
+Name[tr]=Kur
+Name[tt]=Quyu
+Name[uk]=Встановлення
+Name[uz]=Ўрнатиш
+#SUSE-Overwrite Name[vi]=Cài đặt
+Name[zh_CN]=安装
+Name[zh_TW]=安裝
+Icon=fonts
+Exec=kfmclient copy %U fonts:/
+
diff --git a/src/servicemenus/isoservice.desktop b/src/servicemenus/isoservice.desktop
new file mode 100644
index 0000000..4b86111
--- /dev/null
+++ b/src/servicemenus/isoservice.desktop
@@ -0,0 +1,13 @@
+[Desktop Entry]
+Encoding=UTF-8
+Actions=OpenISO
+ServiceTypes=inode/blockdevice,application/x-iso
+
+[Desktop Action OpenISO]
+Comment=ISO9660 View
+Comment[hu]=ISO9660 Nézet
+Comment[fr]=Lecteur ISO9660
+Icon=cd
+Name=ISO9660 View
+Name[hu]=ISO9660 Nézet
+Name[fr]=Lecteur ISO9660
diff --git a/src/servicemenus/jpegorient.desktop b/src/servicemenus/jpegorient.desktop
new file mode 100644
index 0000000..5b25d24
--- /dev/null
+++ b/src/servicemenus/jpegorient.desktop
@@ -0,0 +1,222 @@
+[Desktop Entry]
+ServiceTypes=image/jpeg
+Actions=jpegRot90;jpegRot270;jpegFlipV;jpegFlipH;
+X-KDE-Submenu=Transform Image
+X-KDE-Submenu[bg]=Конвертиране на изображението
+X-KDE-Submenu[ca]=Transforma la imatge
+X-KDE-Submenu[cs]=Převést obrázek
+X-KDE-Submenu[da]=Transformér billede
+X-KDE-Submenu[de]=Bild transformieren
+X-KDE-Submenu[es]=Transformar imagen
+X-KDE-Submenu[fi]=Muuta kuva
+X-KDE-Submenu[fr]=Transformer l'image
+X-KDE-Submenu[hu]=Képátalakítás
+X-KDE-Submenu[is]=Ummynda
+X-KDE-Submenu[it]=Trasforma immagine
+X-KDE-Submenu[nb]=Transformer bilde
+X-KDE-Submenu[nl]=Afbeelding transformeren
+X-KDE-Submenu[pl]=Przekształć obrazek
+X-KDE-Submenu[pt]=Transformar a Imagem
+X-KDE-Submenu[pt_BR]=Transformar Imagem
+X-KDE-Submenu[ru]=Преобразовать
+X-KDE-Submenu[sr]=Трансформиши слику
+X-KDE-Submenu[sr@Latn]=Transformiši sliku
+X-KDE-Submenu[sv]=Ändra bild
+X-KDE-Submenu[uk]=Перетворити зображення
+X-KDE-Submenu[xx]=xxTransform Imagexx
+X-KDE-Submenu[zh_CN]=图像变形
+X-KDE-Require=Write
+
+[Desktop Action jpegRot90]
+Name=Rotate Clockwise
+Name[ar]=تدوير في اتجاه الساعة
+Name[az]=Saat Əqrəbi İstiqamətində Fırlat
+Name[bg]=Завъртане по посока на часов. стрелка
+Name[ca]=Gira 90 graus
+Name[cs]=Rotovat ve směru hod. ručiček
+Name[cy]=Cylchdroi yn Glocwedd
+Name[da]=Rotér med uret
+Name[de]=Im Uhrzeigersinn drehen (nach rechts)
+Name[el]=Περιστροφή δεξιόστροφα
+Name[es]=Girar en el sentido de las agujas del reloj
+Name[et]=Pööra päripäeva
+Name[eu]=Biratu erloju orratzen norabidean
+Name[fi]=Käännä myötäpäivään
+Name[fr]=Tourner en sens horaire
+Name[ga]=Rothlaigh go Deisealach
+Name[he]=סובב עם כיוון השעון
+Name[hi]=घड़ी की दिशा में घुमाएँ
+Name[hu]=Forgatás jobbra
+Name[is]=Snúa réttsælis
+Name[it]=Ruota in senso orario
+Name[ja]=右回りに回転します
+Name[nb]=Roter medurs
+Name[nl]=Klokgewijs draaien
+Name[nn]=Roter med klokka
+Name[pa]=ਸੱਜਾ ਦਾਅ ਘੁੰਮਾਉ
+Name[pl]=Obróć zgodnie z ruchem wskazówek zegara
+Name[pt]=Rodar no Sentido Horário
+Name[pt_BR]=Rodar Relógio Sentido Horário
+Name[ro]=Roteşte la dreapta
+Name[ru]=Повернуть по часовой стрелке
+Name[sk]=Otočiť v smere hodinových ručičiek
+Name[sl]=Zasuči v smeri urinega kazalca
+Name[sr]=Ротирај у смеру казаљке на часовнику
+Name[sr@Latn]=Rotiraj u smeru kazaljke na časovniku
+Name[sv]=Rotera medurs
+Name[ta]=வலதுபுறமாக சுழற்று
+Name[tg]=Чархиш бо ақрабаки соат
+Name[tr]=Saat Yönünde Döndürme
+Name[uk]=Обернути за годинниковою стрілкою
+Name[uz]=Соат кўрсатгичи бўйича айлантириш
+Name[xx]=xxRotate Clockwisexx
+Name[zh_CN]=顺时针旋转
+Icon=rotate_cw
+Exec=jpegorient +90 %F
+
+[Desktop Action jpegRot270]
+Name=Rotate Counter-Clockwise
+Name[ar]=تدوير عكس اتجاه الساعة
+Name[az]=Saat Əqrəbinə Tərs İstiqamətdə Fırlat
+Name[bg]=Завъртане обратно на часов. стрелка
+Name[ca]=Gira 270 graus
+Name[cs]=Rotovat proti směru hod. ručiček
+Name[cy]=Cylchdroi yn Wrthglocwedd
+Name[da]=Rotér mod uret
+Name[de]=Gegen den Uhrzeigersinn drehen (nach links)
+Name[el]=Περιστροφή αριστερόστροφα
+Name[en_GB]=Rotate Anti-Clockwise
+Name[es]=Girar en el sentido contrario a las agujas del reloj
+Name[et]=Pööra vastupäeva
+Name[eu]=Biratu erloju orratzen aurkako norabidean
+Name[fi]=Käännä vastapäivään
+Name[fr]=Tourner en sens anti-horaire
+Name[ga]=Rothlaigh go Tuathalach
+Name[he]=סובב נגד כיוון השעון
+Name[hi]=घड़ी की उलटी दिशा में घुमाएँ
+Name[hu]=Forgatás balra
+Name[is]=Snúa rangsælis
+Name[it]=Ruota in senso anti-orario
+Name[ja]=左回りに回転します
+Name[nb]=Roter moturs
+Name[nl]=Anti-klokgewijs draaien
+Name[nn]=Roter mot klokka
+Name[pa]=ਖੱਬੇ ਦਾਅ ਘੁੰਮਾਓ
+Name[pl]=Obróć przeciwnie do ruchu wskazówek zegara
+Name[pt]=Rodar no Sentido Anti-horário
+Name[pt_BR]=Rodar Contador de Relógio
+Name[ro]=Roteşte la stînga
+Name[ru]=Повернуть против часовой стрелки
+Name[sk]=Otočiť proti smeru hodinových ručičiek
+Name[sl]=Zasuči v nasportni smeri urinega kazalca
+Name[sr]=Ротирај супротно смеру казаљке на часовнику
+Name[sr@Latn]=Rotiraj suprotno smeru kazaljke na časovniku
+Name[sv]=Rotera moturs
+Name[ta]=கடிகார ஓட்டத்திற்கெதிராக சுழற்று
+Name[tg]=Чархиш ба муқобили ақрабаки соат
+Name[tr]=Sayacı Saat Yönünde Döndürme
+Name[uk]=Обернути проти годинникової стрілки
+Name[uz]=Соат кўрсатгичига қарши айлантириш
+Name[xx]=xxRotate Counter-Clockwisexx
+Name[zh_CN]=逆时针旋转
+Icon=rotate_ccw
+Exec=jpegorient +270 %F
+
+#[Desktop Action jpegRot180]
+#Name=Rotate 180
+#Icon=misc
+#Exec=jpegorient +180 %F
+
+[Desktop Action jpegFlipV]
+Name=Flip Vertically
+Name[ar]=تدوير رأسي
+Name[az]=Şaquli Olaraq Çevir
+Name[bg]=Вертикално обръщане
+Name[ca]=Torna vertical
+Name[cs]=Převrátit svisle
+Name[cy]=Troi Drosodd yn Fertigol
+Name[da]=Flip lodret
+Name[de]=Vertikal kippen
+Name[el]=Αναστροφή κατακόρυφα
+Name[es]=Reflejar verticalmente
+Name[et]=Keera ümber vertikaalselt
+Name[eu]=Buruz behera ipini
+Name[fi]=Käännä pystysuorassa
+Name[fr]=Retourner verticalement
+Name[ga]=Smeach go hIngearach
+Name[he]=שקף אנכית
+Name[hi]=खड़ा पलटें
+Name[hu]=Tükrözés függőlegesen
+Name[is]=Snúa við um miðju lóðrétt
+Name[it]=Fletti verticalmente
+Name[ja]=縦のフリップ
+Name[nb]=Speilvend loddrett
+Name[nl]=Verticaal omdraaien
+Name[nn]=Snu loddrett
+Name[pa]=ਲੰਬਕਾਰੀ ਝਟਕੋ
+Name[pl]=Odwróć pionowo
+Name[pt]=Trocar Verticalmente
+Name[pt_BR]=Refletir Verticalmente
+Name[ro]=Întoarce pe verticală
+Name[ru]=Отразить вертикально
+Name[sk]=Preklopiť vertikálne
+Name[sl]=Obrni navpično
+Name[sr]=Преврни усправно
+Name[sr@Latn]=Prevrni uspravno
+Name[sv]=Vänd vertikalt
+Name[ta]=மேல்கீழாக திருப்பு
+Name[tg]=Баргардондан ба амудӣ
+Name[tr]=Dik Olarak Dağıtma
+Name[uk]=Перекинути вертикально
+Name[uz]=Эни бўйича айлантириш
+Name[xx]=xxFlip Verticallyxx
+Name[zh_CN]=上下翻转
+Icon=2uparrow
+Exec=jpegorient v %F
+
+[Desktop Action jpegFlipH]
+Name=Flip Horizontally
+Name[ar]=تدوير أفقي
+Name[az]=Üfüqi Olaraq Çevir
+Name[bg]=Хоризонтално обръщане
+Name[ca]=Torna horitzontal
+Name[cs]=Převrátit vodorovně
+Name[cy]=Troi Drosodd yn Llorweddol
+Name[da]=Flip vandret
+Name[de]=Horizontal kippen
+Name[el]=Αναστροφή οριζόντια
+Name[es]=Reflejar horizontalmente
+Name[et]=Keera ümber horisontaalselt
+Name[eu]=Biratu horizontalki
+Name[fi]=Käännä vaakasuorassa
+Name[fr]=Retourner horizontalement
+Name[ga]=Smeach go Cothrománach
+Name[he]=שקף אופקית
+Name[hi]=आड़ा पलटें
+Name[hu]=Tükrözés vízszintesen
+Name[is]=Snúa við um miðju lárétt
+Name[it]=Fletti orizzontalmente
+Name[ja]=水平にフリップ
+Name[nb]=Speilvend vannrett
+Name[nl]=Horizontaal omdraaien
+Name[nn]=Snu vassrett
+Name[pa]=ਖਿਤਿਜੀ ਝਟਕੋ
+Name[pl]=Odwróć poziomo
+Name[pt]=Trocar Horizontalmente
+Name[pt_BR]=Refletir Horizontalmente
+Name[ro]=Întoarce pe orizontală
+Name[ru]=Отразить горизонтально
+Name[sk]=Preklopiť horizontálne
+Name[sl]=Obrni vodoravno
+Name[sr]=Преврни водоравно
+Name[sr@Latn]=Prevrni vodoravno
+Name[sv]=Vänd horisontellt
+Name[ta]=இடம்வலமாக திருப்புக
+Name[tg]=Баргардондан ба уфуқӣ
+Name[tr]=Yatay Olarak Dağıtma
+Name[uk]=Перекинути горизонтально
+Name[uz]=Бўйи бўйича айлантириш
+Name[xx]=xxFlip Horizontallyxx
+Name[zh_CN]=左右翻转
+Icon=2rightarrow
+Exec=jpegorient h %F
diff --git a/src/servicemenus/k3b_audiocd_rip.desktop b/src/servicemenus/k3b_audiocd_rip.desktop
new file mode 100644
index 0000000..387d44a
--- /dev/null
+++ b/src/servicemenus/k3b_audiocd_rip.desktop
@@ -0,0 +1,46 @@
+[Desktop Entry]
+ServiceTypes=media/audiocd,media/mixedcd
+Actions=K3bRip;
+X-KDE-Priority=TopLevel
+
+[Desktop Action K3bRip]
+Name=Extract Digital Audio with K3b
+Name[af]=Onttrek digitale oudio m.b.v. K3b
+Name[ar]= استعمل K3b لاستخراج الصوتي الرقمي.
+Name[bg]=Извличане на цифров звук с K3b
+Name[br]=Eztennañ klevet niverel gant K3b
+Name[ca]=Extreu àudio digital amb el K3b
+Name[cs]=Extrahovat digitální zvuk pomocí K3b
+Name[da]=Rip digitallyd med K3b
+Name[de]=Digital-Audio mit K3b auslesen
+Name[el]=Εξαγωγή ψηφιακού ήχου με το K3b
+Name[es]=Extraer audio digital con K3b
+Name[et]=Ekstrakti digitaalne audio K3b abil
+Name[fa]=استخراج صوتی رقمی با K3b
+Name[fi]=Pura sisältö digitaalisesti K3b:llä
+Name[fr]=Extraction Audio avec K3b
+Name[gl]=Extrair Áudio Dixital con K3b
+Name[hu]=Digitális hanganyag kimásolása a K3b-vel
+Name[is]=Afrita stafrænt hljóð með K3b
+Name[it]=Estrai audio digitale con K3b
+Name[ja]=K3b でデジタルオーディオを吸い出し
+Name[km]=ស្រង់​ចេញ​អូឌីយ៉ូ​ឌីជីថល​ដោយ​ប្រើ K3b
+Name[lt]=Nurašyti skaitmeninį audio su K3b
+Name[ms]=Ekstrak Audio Digital dengan K3b
+Name[nds]=Digitaal Audiodaten mit K3b ruttrecken
+Name[nl]=Digitale audio rippen met K3b
+Name[pa]=K3b ਨਾਲ ਡਿਜ਼ੀਟਲ ਆਡੀਓ ਖੋਲ੍ਹੋ
+Name[pl]=Zgraj utwory za pomocą K3b
+Name[pt]=Extrair o Áudio Digital com o K3b
+Name[pt_BR]=Extrair Áudio Digital com o K3b
+Name[sk]=Vytiahnuť digitálny zvuk pomocou K3b
+Name[sr]=Издвој дигитални звук помоћу K3b-а
+Name[sr@Latn]=Izdvoj digitalni zvuk pomoću K3b-a
+Name[sv]=Lagra digitalljud med K3b
+Name[tr]=K3b ile Sayısal Ses Aktar
+Name[uk]=Витягування цифрового аудіо за допомогою K3b
+Name[uz]=K3b ёрдамида қўшиқларни аудио-файлга айлантириш
+Name[zh_CN]=用 K3b 提取数字音频
+Name[zh_TW]=使用 K3b 以數位方式提取音樂
+Exec=k3b --cddarip %u
+Icon=k3b
diff --git a/src/servicemenus/k3b_cd_copy.desktop b/src/servicemenus/k3b_cd_copy.desktop
new file mode 100644
index 0000000..fc78f8a
--- /dev/null
+++ b/src/servicemenus/k3b_cd_copy.desktop
@@ -0,0 +1,48 @@
+[Desktop Entry]
+ServiceTypes=media/cdrom_unmounted,media/cdwriter_unmounted,media/audiocd
+Actions=K3bCDCopy;
+X-KDE-Priority=TopLevel
+
+[Desktop Action K3bCDCopy]
+Name=Copy CD with K3b
+Name[af]=Kopiëer CD m.b.v. K3b...
+Name[ar]= انقل القرص المدمج بواسطة K3b .
+Name[bg]=Копиране на CD с K3b
+Name[br]=Eilañ ur CD gant K3b
+Name[ca]=Copia CD amb el K3b
+Name[cs]=Kopírovat CD pomocí K3b
+Name[da]=Kopiér cd med K3b
+Name[de]=CD mit K3b kopieren
+Name[el]=Αντιγραφή CD με το K3b
+Name[es]=Copiar CD con K3b
+Name[et]=Kopeeri CD K3b abil
+Name[fa]=رونوشت دیسک فشرده با K3b
+Name[fi]=Kopioi cd K3b:llä
+Name[fr]=Copier le CD avec K3b
+Name[gl]=Copiar CD con K3b
+Name[hu]=CD-másolás a K3b-vel
+Name[is]=Afrita geisladisk með K3b
+Name[it]=Copia CD con K3b
+Name[ja]=K3b で CD をコピー
+Name[km]=ចម្លង​ស៊ីឌី​ដោយ​ប្រើ K3b
+Name[lt]=Kopijuoti CD su K3b
+Name[mk]=Копирајте CD со K3b
+Name[ms]=Salin CD dengan K3b
+Name[nds]=CD mit K3b koperen
+Name[nl]=CD kopiëren met K3b
+Name[pa]=K3b ਨਾਲ CD ਨਕਲ
+Name[pl]=Skopiuj płytę CD za pomocą K3b
+Name[pt]=Copiar o CD com o K3b
+Name[pt_BR]=Copiar CD com o K3b
+Name[ru]=Записать компакт-диск, используя K3b...
+Name[sk]=Kopírovať CD pomocou K3b
+Name[sr]=Копирај CD помоћу K3b-а
+Name[sr@Latn]=Kopiraj CD pomoću K3b-a
+Name[sv]=Kopiera cd med K3b
+Name[tr]=K3b ile CD Kopyala
+Name[uk]=Копіювати КД за допомогою K3b
+Name[uz]=K3b ёрдамида CD'дан нусха олиш
+Name[zh_CN]=用 K3b 复制 CD
+Name[zh_TW]=使用 K3b 複製 CD
+Exec=k3b --copycd %u
+Icon=k3b
diff --git a/src/servicemenus/k3b_create_audio_cd.desktop b/src/servicemenus/k3b_create_audio_cd.desktop
new file mode 100644
index 0000000..efc1a79
--- /dev/null
+++ b/src/servicemenus/k3b_create_audio_cd.desktop
@@ -0,0 +1,124 @@
+[Desktop Entry]
+Actions=CreateK3bAudioProject;
+Encoding=UTF-8
+ServiceTypes=audio/x-mp3,audio/x-vorbis,application/x-ogg,audio/x-mp2,audio/x-mpegurl,audio/x-wav,media/blankcd
+
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+[Desktop Action CreateK3bAudioProject]
+Exec=k3b --audiocd %U
+Name=Create Audio CD with K3b...
+Name[af]=Skep oudio CD met K3b...
+Name[bg]=Създаване на аудио CD с K3b...
+Name[bn]=কে-থ্রি-বি দিয়ে অডিও সিডি তৈরি করো...
+Name[br]=Krouiñ ur CD klevet gant K3b ...
+Name[bs]=Napravio audio CD koristeći K3b...
+Name[ca]=Crea CD d'àudio amb K3b...
+Name[cs]=Vytvořit zvukové CD...
+#SUSE-Overwrite Name[da]=Lav lyd-cd med K3b...
+Name[da]=Lav lyd-CD med K3b...
+Name[de]=Audio-CD mit K3b erstellen ...
+Name[el]=Δημιουργία μουσικού CD με το K3b...
+Name[es]=Crear CD de audio con K3b...
+Name[et]=Kirjuta audio-CD K3b abil...
+Name[eu]=Sortu audio cdak K3b-rekin...
+Name[fr]=Créer un CD audio avec K3b...
+Name[he]=צור תקליטור שמע בעזרת K3b...
+Name[hi]=के3बी के साथ ऑडियो सीडी बनाए...
+Name[hu]=Hang-CD létrehozása a K3b-vel...
+Name[is]=Búa til hljóðdisk með K3b...
+Name[it]=Crea CD audio con K3b...
+#SUSE-Overwrite Name[ja]=オーディオ CD を K3b で作成...
+Name[ja]=K3bによるオーディオCDの作成...
+Name[lt]=Kurkite audio CD su K3b...
+Name[mk]=Креирајте аудио-CD со K3b...
+#SUSE-Overwrite Name[nb]=Lag lyd-CD med K3b . . .
+Name[nb]=Brenn lyd-CD-er med K3b...
+Name[nl]=Audio-cd aanmaken met K3b...
+Name[pa]=K3b ਨਾਲ ਆਡੀਓ CD ਬਣਾਓ...
+Name[pl]=Stwórz płytę CD Audio za pomocą K3b...
+Name[pt]=Criar um CD de Áudio com o K3b...
+Name[pt_BR]=Criar CD de Áudio com K3b...
+Name[ru]=Записать аудио компакт-диск, используя K3b...
+Name[sl]=Ustvari avdio CD s K3b ...
+Name[sr]=Направи аудио CD помоћу K3b-а...
+Name[sr@Latn]=Napravi audio CD pomoću K3b-a...
+Name[sv]=Skapa ljud-cd med K3b...
+Name[ta]=ஒலிக் குறுந்தகட்டோடு K3bயை உருவாக்குக...
+Name[tr]=K3b ile Ses CD'si oluştur...
+Name[uk]=Створити аудіо-КД за допомогою K3b...
+Name[zh_CN]=用 K3b 创建音频 CD...
+Icon=k3b
+
+Name[fi]=Luo ääni-CD K3b:llä
+Name[km]=បង្កើត​ស៊ីឌី​អូឌីយ៉ូ​ជាមួយ K3b...
+Name[zh_TW]=以 K3b 建立音效 CD...
diff --git a/src/servicemenus/k3b_create_video_cd.desktop b/src/servicemenus/k3b_create_video_cd.desktop
new file mode 100644
index 0000000..45cca6a
--- /dev/null
+++ b/src/servicemenus/k3b_create_video_cd.desktop
@@ -0,0 +1,125 @@
+[Desktop Entry]
+Actions=CreateK3bVcdProject;
+Encoding=UTF-8
+ServiceTypes=video/mpeg
+
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+[Desktop Action CreateK3bVcdProject]
+Exec=k3b --videocd %F
+Name=Create Video CD with K3b...
+Name[af]=Skep video CD met K3b...
+Name[bg]=Създаване на видео CD с K3b...
+Name[bn]=কে-থ্রি-বি দিয়ে ভিডিও সিডি তৈরি করো...
+Name[br]=Krouiñ ur CD video gant K3b ...
+Name[bs]=Napravi video CD koristeći K3b...
+Name[ca]=Crea CD de vídeo amb K3b...
+Name[cs]=Vytvořit video CD...
+#SUSE-Overwrite Name[da]=Lav video-cd med K3b...
+Name[da]=Lav Video CD med K3b...
+Name[de]=Video-CD mit K3b erstellen ...
+Name[el]=Δημιουργία Video CD με το K3b...
+Name[es]=Crear Video CD con K3b...
+Name[et]=Kirjuta video-CD K3b abil...
+Name[eu]=Sortu Bideo CDak K3b-rekin...
+Name[fr]=Créer un CD vidéo avec K3b...
+Name[he]=צור תקליטורי וידאו VCD בעזרת K3b...
+Name[hi]=के3बी के साथ वीडियो सीडी बनाए...
+Name[hu]=Video-CD létrehozása a K3b-vel...
+Name[is]=Búa til vídeódisk með K3b...
+Name[it]=Crea Video CD con K3b...
+#SUSE-Overwrite Name[ja]=Video CD を K3b で作成...
+Name[ja]=K3bによるビデオCDの作成...
+Name[lt]=Kurkite video CD su K3b...
+Name[mk]=Креирајте видео-CD со K3b...
+#SUSE-Overwrite Name[nb]=Lag video-CD med K3b . . .
+Name[nb]=Brenn video-CD-er med K3b...
+Name[nl]=Video-cd aanmaken K3b...
+#SUSE-Overwrite Name[pa]=K3b ਨਾਲ ਵੀਡਿਓ CD ਬਣਾਓ...
+Name[pa]=K3b ਨਾਲ ਵੀਡਿਓ CD ਬਣਾਓ
+Name[pl]=Stwórz płytę Video CD za pomocą K3b...
+Name[pt]=Criar um Video CD com o K3b...
+Name[pt_BR]=Criar CD de Vídeo com K3b...
+Name[ru]=Записать видео компакт-диск, используя K3b...
+Name[sl]=Ustvari video CD s K3b ...
+Name[sr]=Направи видео CD помоћу K3b-а...
+Name[sr@Latn]=Napravi video CD pomoću K3b-a...
+Name[sv]=Skapa video-cd med K3b...
+Name[ta]=ஒளிக் குறுந்தகட்டோடு K3bஐ உருவாக்குக...
+Name[tr]=K3b ile Video CD'si oluştur...
+Name[uk]=Створити відео-КД за допомогою K3b...
+Name[zh_CN]=用 K3b 创建视频 CD...
+Icon=k3b
+
+Name[fi]=Luo video-CD K3b:llä
+Name[km]=បង្កើត​ស៊ីឌី​វីដេអូ​ជាមួយ K3b...
+Name[zh_TW]=以 K3b 建立視訊 CD...
diff --git a/src/servicemenus/k3b_dvd_copy.desktop b/src/servicemenus/k3b_dvd_copy.desktop
new file mode 100644
index 0000000..f85ffcb
--- /dev/null
+++ b/src/servicemenus/k3b_dvd_copy.desktop
@@ -0,0 +1,48 @@
+[Desktop Entry]
+ServiceTypes=media/dvdrom_unmounted,media/dvdwriter_unmounted,media/dvdvideo
+Actions=K3bDVDCopy;
+X-KDE-Priority=TopLevel
+
+[Desktop Action K3bDVDCopy]
+Name=Copy DVD with K3b
+Name[af]=Kopiëer DVD m.b.v. K3b
+Name[ar]= انسخ القرص الرقمي المرئي (DVD) بواسطة K3b .
+Name[bg]=Копиране на DVD с K3b
+Name[br]=Eilañ un DVD gant K3b
+Name[ca]=Copia un DVD amb el K3b
+Name[cs]=Kopírovat DVD pomocí K3b
+Name[da]=Kopiér dvd med K3b
+Name[de]=DVD mit K3b kopieren
+Name[el]=Αντιγραφή DVD με το K3b
+Name[es]=Copiar DVD con K3b
+Name[et]=Kopeeri DVD K3b abil
+Name[fa]=رونوشت دی وی دی با K3b
+Name[fi]=Kopioi dvd K3b:llä
+Name[fr]=Copier le DVD avec K3b
+Name[gl]=Copiar DVD con K3b
+Name[hu]=DVD-másolás a K3b-vel
+Name[is]=Afrita DVD með K3b
+Name[it]=Copia DVD con K3b
+Name[ja]=K3b で DVD をコピー...
+Name[km]=ចម្លង​ឌីវីឌី​ដោយ​ប្រើ K3b
+Name[lt]=Kopijuoti DVD su K3b
+Name[mk]=Копирајте DVD со K3b...
+Name[ms]=Salin DVD dengan K3b
+Name[nds]=DVD mit K3b koperen
+Name[nl]=DVD kopiëren met K3b
+Name[pa]=K3b ਨਾਲ DVD ਨਕਲ
+Name[pl]=Skopiuj DVD za pomocą K3b
+Name[pt]=Copiar o DVD com o K3b
+Name[pt_BR]=Copiar DVD com o K3b
+Name[ru]=Копировать DVD, используя K3b...
+Name[sk]=Vytvoriť DVD pomocou K3b
+Name[sr]=Копирај DVD помоћу K3b-а
+Name[sr@Latn]=Kopiraj DVD pomoću K3b-a
+Name[sv]=Kopiera dvd med K3b
+Name[tr]=K3b ile Veri DVD'si Kopyala
+Name[uk]=Копіювати DVD за допомогою K3b
+Name[uz]=K3b ёрдамида DVD'дан нусха олиш
+Name[zh_CN]=用 K3b 复制 DVD
+Name[zh_TW]=使用 K3b 複製 DVD
+Exec=k3b --copydvd %u
+Icon=k3b
diff --git a/src/servicemenus/k3b_handle_empty_cd.desktop b/src/servicemenus/k3b_handle_empty_cd.desktop
new file mode 100644
index 0000000..63f9283
--- /dev/null
+++ b/src/servicemenus/k3b_handle_empty_cd.desktop
@@ -0,0 +1,114 @@
+[Desktop Entry]
+ServiceTypes=media/blankcd
+Actions=K3bDataProject;K3bAudioCDProject;
+X-KDE-Priority=TopLevel
+
+[Desktop Action K3bDataProject]
+Exec=k3b --device %u --datacd
+Name=Create Data CD with K3b...
+Name[af]=Skep data CD met K3b...
+Name[ar]= انشيء القرص المدمج لحفظ البيانات (Data) بواسطة K3b ...
+Name[bg]=Създаване на CD с данни с K3b...
+Name[bn]=কে-থ্রি-বি দিয়ে ডেটা-সিডি তৈরি করো...
+Name[br]=Krouiñ ur CD roadoù gant K3b ...
+Name[bs]=Napravi podatkovni CD koristeći K3b...
+Name[ca]=Crea un CD de dades amb el K3b...
+Name[cs]=Vytvořit datové CD...
+Name[da]=Lav data-cd med K3b...
+Name[de]=Daten-CD mit K3b erstellen ...
+Name[el]=Δημιουργία CD δεδομένων με το K3b...
+Name[es]=Crear CD de datos con K3b...
+Name[et]=Kirjuta andme-CD K3b abil...
+Name[fa]=ایجاد دیسک فشردۀ داده با K3b...
+Name[fi]=Luo data-cd K3b:llä...
+Name[fr]=Créer un CD de données avec K3b...
+Name[gl]=Criar un CD de Dados con K3b...
+Name[he]=צור תקליטורי מידע CD בעזרת K3b...
+Name[hi]=के3बी के साथ डाटा सीडी बनाए...
+Name[hu]=Adat-CD létrehozása a K3b-vel...
+Name[is]=Búa til gagnadisk með K3b...
+Name[it]=Crea CD dati con K3b...
+Name[ja]=K3b でデータ CD を作成...
+Name[km]=បង្កើត​ស៊ីឌី​ទិន្ន័យ​ជាមួយនឹង K3b...
+Name[lt]=Kurti duomenų CD su K3b...
+Name[mk]=Креирајте податочно CD со K3b...
+Name[ms]= Cipta CD Data dengan K3b...
+Name[nb]=Lag data-CD med K3b . . .
+Name[nds]=Daten-CD mit K3b opstellen...
+Name[ne]=K3b...
+Name[nl]=Gegevens-cd aanmaken met K3b...
+Name[nn]=Lag data-CD med K3b …
+Name[pa]=K2b ਨਾਲ ਡਾਟਾ CD ਬਣਾਓ...
+Name[pl]=Stwórz płytę CD z danymi za pomocą K3b...
+Name[pt]=Criar um CD de Dados com o K3b...
+Name[pt_BR]=Criar CD de Dados com o K3b...
+Name[ru]=Записать компакт-диск с данными, используя K3b...
+Name[sk]=Vytvoriť dátové CD pomocou K3b...
+Name[sl]=Ustvari podatkovni CD s K3b ...
+Name[sr]=Направи CD са подацима помоћу K3b-а...
+Name[sr@Latn]=Napravi CD sa podacima pomoću K3b-a...
+Name[sv]=Skapa data-cd med K3b...
+Name[ta]=தகவல் குறுந்தகட்டோடு K3b ஐ உருவாக்குக...
+Name[tg]=Сабт кардани CD бо маълумотҳо,бо истифодабарии K3b...
+Name[tr]=K3b ile Veri CD'si oluştur...
+Name[uk]=Створити КД з даними за допомогою K3b...
+Name[uz]=K3b ёрдамида маълумот CD яратиш
+Name[xh]=Yenza i CD yolwazi nge K3b...
+Name[zh_CN]=用 K3b 创建数据 CD...
+Name[zh_TW]=使用 K3b 建立資料 CD...
+Icon=k3b
+
+[Desktop Action K3bAudioCDProject]
+Exec=k3b --device %u --audiocd
+Name=Create Audio CD with K3b...
+Name[af]=Skep oudio CD met K3b...
+Name[ar]= انشيء القرص المدمج السمعي بواسطة K3b ...
+Name[bg]=Създаване на аудио CD с K3b...
+Name[bn]=কে-থ্রি-বি দিয়ে অডিও সিডি তৈরি করো...
+Name[br]=Krouiñ ur CD klevet gant K3b ...
+Name[bs]=Napravio audio CD koristeći K3b...
+Name[ca]=Crea un CD d'àudio amb el K3b...
+Name[cs]=Vytvořit zvukové CD...
+Name[da]=Lav lyd-cd med K3b...
+Name[de]=Audio-CD mit K3b erstellen ...
+Name[el]=Δημιουργία CD ήχου με το K3b...
+Name[es]=Crear CD de audio con K3b...
+Name[et]=Kirjuta audio-CD K3b abil...
+Name[fa]=ایجاد دیسک فشردۀ صوتی با K3b...
+Name[fi]=Luo musiikki-cd K3b:llä...
+Name[fr]=Créer un CD audio avec K3b...
+Name[gl]=Criar un CD de Áudio con K3b...
+Name[he]=צור תקליטור שמע בעזרת K3b...
+Name[hi]=के3बी के साथ ऑडियो सीडी बनाए...
+Name[hu]=Hang-CD létrehozása a K3b-vel...
+Name[is]=Búa til hljóðdisk með K3b...
+Name[it]=Crea CD audio con K3b...
+Name[ja]=K3b でオーディオ CD を作成...
+Name[km]=បង្កើត​ស៊ីឌី​អូឌីយ៉ូ​ជាមួយ​នឹង K3b...
+Name[lt]=Kurti audio CD su K3b...
+Name[mk]=Креирајте аудио-CD со K3b...
+Name[ms]= Cipta Audio CD dengan K3b...
+Name[nb]=Lag lyd-CD med K3b . . .
+Name[nds]=Audio-CD mit K3b opstellen...
+Name[ne]=K3b सँग अडियो सीडी सिर्जना गर्नुहोस्...
+Name[nl]=Audio-cd aanmaken met K3b...
+Name[nn]=Lag lyd-CD med K3b …
+Name[pa]=K2b ਨਾਲ ਆਡੀਓ CD ਬਣਾਓ...
+Name[pl]=Stwórz płytę CD Audio za pomocą K3b...
+Name[pt]=Criar um CD de Áudio com o K3b...
+Name[pt_BR]=Criar CD de Áudio com o K3b...
+Name[ru]=Записать аудио компакт-диск, используя K3b...
+Name[sk]=Vytvoriť zvukové CD pomocou K3b...
+Name[sl]=Ustvari avdio CD s K3b ...
+Name[sr]=Направи аудио CD помоћу K3b-а...
+Name[sr@Latn]=Napravi audio CD pomoću K3b-a...
+Name[sv]=Skapa ljud-cd med K3b...
+Name[ta]=ஒலிக் குறுந்தகட்டோடு K3bயை உருவாக்குக...
+Name[tg]=Сабт кардани аудио компакт-диск бо истифодаи K3b...
+Name[tr]=K3b ile Ses CD'si oluştur...
+Name[uk]=Створити аудіо-КД за допомогою K3b...
+Name[uz]=K3b ёрдамида аудио CD яратиш
+Name[xh]=Yenza i CD Yokuvakalayo nge K3b...
+Name[zh_CN]=用 K3b 创建音频 CD...
+Name[zh_TW]=使用 K3b 建立音樂 CD...
+Icon=k3b
diff --git a/src/servicemenus/k3b_handle_empty_dvd.desktop b/src/servicemenus/k3b_handle_empty_dvd.desktop
new file mode 100644
index 0000000..74f8780
--- /dev/null
+++ b/src/servicemenus/k3b_handle_empty_dvd.desktop
@@ -0,0 +1,103 @@
+[Desktop Entry]
+ServiceTypes=media/blankdvd
+Actions=K3bDataProject;
+X-KDE-Priority=TopLevel
+
+[Desktop Action K3bDataProject]
+Exec=k3b --device %u --datadvd
+Name=Create Data CD with K3b...
+Name[af]=Skep data CD met K3b...
+Name[ar]= انشيء القرص المدمج لحفظ البيانات (Data) بواسطة K3b ...
+Name[bg]=Създаване на CD с данни с K3b...
+Name[bn]=কে-থ্রি-বি দিয়ে ডেটা-সিডি তৈরি করো...
+Name[br]=Krouiñ ur CD roadoù gant K3b ...
+Name[bs]=Napravi podatkovni CD koristeći K3b...
+Name[ca]=Crea un CD de dades amb el K3b...
+Name[cs]=Vytvořit datové CD...
+Name[da]=Lav data-cd med K3b...
+Name[de]=Daten-CD mit K3b erstellen ...
+Name[el]=Δημιουργία CD δεδομένων με το K3b...
+Name[es]=Crear CD de datos con K3b...
+Name[et]=Kirjuta andme-CD K3b abil...
+Name[fa]=ایجاد دیسک فشردۀ داده با K3b...
+Name[fi]=Luo data-cd K3b:llä...
+Name[fr]=Créer un CD de données avec K3b...
+Name[gl]=Criar un CD de Dados con K3b...
+Name[he]=צור תקליטורי מידע CD בעזרת K3b...
+Name[hi]=के3बी के साथ डाटा सीडी बनाए...
+Name[hu]=Adat-CD létrehozása a K3b-vel...
+Name[is]=Búa til gagnadisk með K3b...
+Name[it]=Crea CD dati con K3b...
+Name[ja]=K3b でデータ CD を作成...
+Name[km]=បង្កើត​ស៊ីឌី​ទិន្ន័យ​ជាមួយនឹង K3b...
+Name[lt]=Kurti duomenų CD su K3b...
+Name[mk]=Креирајте податочно CD со K3b...
+Name[ms]= Cipta CD Data dengan K3b...
+Name[nb]=Lag data-CD med K3b . . .
+Name[nds]=Daten-CD mit K3b opstellen...
+Name[ne]=K3b...
+Name[nl]=Gegevens-cd aanmaken met K3b...
+Name[nn]=Lag data-CD med K3b …
+Name[pa]=K2b ਨਾਲ ਡਾਟਾ CD ਬਣਾਓ...
+Name[pl]=Stwórz płytę CD z danymi za pomocą K3b...
+Name[pt]=Criar um CD de Dados com o K3b...
+Name[pt_BR]=Criar CD de Dados com o K3b...
+Name[ru]=Записать компакт-диск с данными, используя K3b...
+Name[sk]=Vytvoriť dátové CD pomocou K3b...
+Name[sl]=Ustvari podatkovni CD s K3b ...
+Name[sr]=Направи CD са подацима помоћу K3b-а...
+Name[sr@Latn]=Napravi CD sa podacima pomoću K3b-a...
+Name[sv]=Skapa data-cd med K3b...
+Name[ta]=தகவல் குறுந்தகட்டோடு K3b ஐ உருவாக்குக...
+Name[tg]=Сабт кардани CD бо маълумотҳо,бо истифодабарии K3b...
+Name[tr]=K3b ile Veri CD'si oluştur...
+Name[uk]=Створити КД з даними за допомогою K3b...
+Name[uz]=K3b ёрдамида маълумот CD яратиш
+Name[xh]=Yenza i CD yolwazi nge K3b...
+Name[zh_CN]=用 K3b 创建数据 CD...
+Name[zh_TW]=使用 K3b 建立資料 CD...
+Name=Create Data DVD with K3b...
+Name[af]=Skep 'n Data DVD m.b.v. K3b...
+Name[ar]= انشيء القرص المرئي الرقمي (DVD) لحفظ البيانات (Data) بواسطة K3b ...
+Name[bg]=Създаване на DVD с данни с K3b...
+Name[bn]=কে-থ্রি-বি দিয়ে ডেটা-ডিভিডি তৈরি করো...
+Name[br]=Krouiñ un DVD roadoù gant K3b ...
+Name[ca]=Crea un DVD de dades amb el K3b...
+Name[cs]=Vytvořit datové DVD...
+Name[da]=Lav data-cd med K3b...
+Name[de]=Daten-DVD mit K3b erstellen ...
+Name[el]=Δημιουργία DVD δεδομένων με το K3b...
+Name[es]=Crear DVD de datos con K3b...
+Name[et]=Kirjuta andme-DVD K3b abil...
+Name[fa]=ایجاد دی وی دی داده با K3b...
+Name[fi]=Luo data-dvd K3b:llä...
+Name[fr]=Créer un DVD de données avec K3b...
+Name[gl]=Criar un DVD de Dados con K3b...
+Name[he]=צור תקליטורי מידע DVD בעזרת K3b...
+Name[hu]=Adat-DVD létrehozása a K3b-vel...
+Name[is]=Búa til DVD gagnadisk með K3b...
+Name[it]=Crea DVD dati con K3b...
+Name[ja]=K3b でデータ DVD を作成...
+Name[km]=បង្កើត​ឌីវីឌី​ទិន្នន័យ​ដោយ​ប្រើ K3b...
+Name[lt]=Kurti duomenų DVD su K3b...
+Name[mk]=Креирајте податочно DVD со K3b...
+Name[ms]=Cipta DVD Data dengan K3b...
+Name[nb]=Lag data-DVD med K3b . . .
+Name[nds]=Daten-DVD mit K3b opstellen...
+Name[nl]=Gegevens-dvd aanmaken met K3b...
+Name[pa]=K3b ਨਾਲ ਡਾਟਾ DVD ਬਣਾਓ...
+Name[pl]=Stwórz płytę DVD z danymi za pomocą K3b...
+Name[pt]=Criar um DVD de Dados com o K3b...
+Name[pt_BR]=Criar DVD de Dados com o K3b...
+Name[ru]=Записать DVD с данными, используя K3b...
+Name[sk]=Vytvoriť dátové DVD pomocou K3b...
+Name[sr]=Направи DVD са подацима помоћу K3b-а...
+Name[sr@Latn]=Napravi DVD sa podacima pomoću K3b-a...
+Name[sv]=Skapa data-dvd med K3b...
+Name[tg]=Сабт кардани Маълумотҳои CD бо истифодабарии K3b...
+Name[tr]=K3b ile Veri DVD'si oluştur...
+Name[uk]=Створити DVD з даними у K3b...
+Name[uz]=K3b ёрдамида маълумот DVD яратиш
+Name[zh_CN]=用 K3b 创建数据 DVD...
+Name[zh_TW]=使用 K3b 建立資料 DVD...
+Icon=k3b
diff --git a/src/servicemenus/k3b_videodvd_rip.desktop b/src/servicemenus/k3b_videodvd_rip.desktop
new file mode 100644
index 0000000..a915e67
--- /dev/null
+++ b/src/servicemenus/k3b_videodvd_rip.desktop
@@ -0,0 +1,45 @@
+[Desktop Entry]
+ServiceTypes=media/dvdvideo
+Actions=K3bRip;
+X-KDE-Priority=TopLevel
+
+[Desktop Action K3bRip]
+Name=Rip Video DVD Titles with K3b
+Name[af]=Kopiëer Video DVD titels m.b.v. K3b
+Name[ar]= استخرج عناوين مرئيات من القرص المرئي الرقمي (DVD) بواسطة K3b
+Name[bg]=Извличане на DVD заглавия с K3b
+Name[ca]=Extreure pistes de DVD amb el K3b
+Name[cs]=Ripovat titulky video DVD pomocí K3b
+Name[da]=Rip dvd-titler med K3b
+Name[de]=DVD-Titel mit K3b auslesen
+Name[el]=Εξαγωγή τίτλων DVD με το K3b
+Name[es]=Extraer DVD de vídeo con K3b
+Name[et]=Ripi video-DVD tiitlid K3b abil
+Name[fa]=تبدیل عناوین دی وی دی ویدئویی با K3b
+Name[fi]=Pura dvd K3b:llä
+Name[fr]=Extraire les titres du DVD avec K3b
+Name[gl]=Gravar título de Vídeo DVD con K3b
+Name[hu]=Video DVD-címek beolvasása a K3b-vel
+Name[is]=Afrita DVD titla með K3b
+Name[it]=Estrai titoli DVD video con K3b
+Name[ja]=K3b で DVD タイトルを吸い出し...
+Name[km]=ច្រៀក​ចំណង​ជើង​ឌីវីឌី​វីដេអូ​ដោយ​ប្រើ K3b
+Name[lt]=Nurašyti video DVD su K3b
+Name[ms]=Keluarkan Tajuk Video DVD dengan K3b
+Name[nds]=Video-DVD-Stücken mit K3b utlesen
+Name[nl]=Video-dvd-titels rippen met K3b
+Name[pa]=K3b ਨਾਲ ਵੀਡਿਓ DVD ਟਾਇਟਲ ਰਿਪ
+Name[pl]=Zgraj filmy z płyty DVD Video za pomocą K3b
+Name[pt]=Extrair os Títulos do DVD de Vídeo com o K3b
+Name[pt_BR]=Ripar DVD de Vídeo com o K3b
+Name[sk]=Ripovať titulky video DVD pomocou K3b
+Name[sr]=Исчупај титлове са видео DVD-а помоћу K3b-а
+Name[sr@Latn]=Isčupaj titlove sa video DVD-a pomoću K3b-a
+Name[sv]=Lagra dvd-titlar med K3b
+Name[tr]=K3b ile Görüntü DVD'si Başlıklarını Aktar
+Name[uk]=Видерти заголовки з відео-DVD за допомогою K3b
+Name[uz]=K3b ёрдамида филмларни видео-файлга айлантириш
+Name[zh_CN]=用 K3b 提取视频 DVD
+Name[zh_TW]=使用 K3b 提取視像 DVD Titles
+Exec=k3b --videodvdrip %u
+Icon=k3b
diff --git a/src/servicemenus/k3b_write_bin_image.desktop b/src/servicemenus/k3b_write_bin_image.desktop
new file mode 100644
index 0000000..aaf7967
--- /dev/null
+++ b/src/servicemenus/k3b_write_bin_image.desktop
@@ -0,0 +1,124 @@
+[Desktop Entry]
+Actions=WriteCdImage;
+Encoding=UTF-8
+ServiceTypes=application/x-cue
+
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+[Desktop Action WriteCdImage]
+Exec=k3b --cdimage %F
+Name=Write CD Image with K3b...
+Name[af]=Skryf CD beeld met K3b...
+Name[bg]=Запис на CD образ с K3b...
+Name[bn]=কে-থ্রি-বি দিয়ে সিডি ইমেজ লেখো...
+Name[br]=srivañ ar skeudenn CD gant K3b ...
+Name[bs]=Zapiši CD image koristeći K3b...
+Name[ca]=Escriu imatge per a CD amb K3b...
+Name[cs]=Vypálit obraz CD...
+#SUSE-Overwrite Name[da]=Skriv cd-billede med K3b...
+Name[da]=Skriv CD-billede med K3b...
+Name[de]=CD-Abbild mit K3b brennen ...
+Name[el]=Εγγραφή εικόνας CD με το K3b...
+Name[es]=Escribir imagen de CD con K3b...
+Name[et]=Kirjuta tõmmis K3b abil plaadile...
+Name[eu]=Idatzi CD irudiak K3b-rekin...
+Name[fr]=Graver une image CD avec K3b...
+Name[he]=כתוב תבנית CD בעזרת K3b...
+Name[hi]=के3बी के साथ सीडी इमेज लिखें...
+Name[hu]=CD-képmásfájl írása a K3b-vel...
+Name[is]=Skrifa diskmynd með K3b...
+Name[it]=Scrivi immagine CD con K3b...
+#SUSE-Overwrite Name[ja]=CD イメージを K3b で書き込み...
+Name[ja]=K3bによるCDイメージの書込み...
+Name[lt]=Įrašykite CD atvaizdą su K3b...
+Name[mk]=Запишете CD-слика со K3b...
+#SUSE-Overwrite Name[nb]=Skriv CD-bilde med K3b . . .
+Name[nb]=Brenn diskbilde på CD med K3b...
+Name[nl]=CD-image schrijven met K3b...
+Name[pa]=K3b ਨਾਲ CD ਪ੍ਰਤੀਬਿੰਬ ਲਿਖੋ...
+Name[pl]=Stwórz obraz płyty CD za pomocą K3b...
+Name[pt]=Escrever uma Imagem de CD com o K3b...
+Name[pt_BR]=Gravar Imagem em CD com K3b...
+Name[ru]=Записать образ CD, используя K3b...
+Name[sl]=Zapiši sliko CD-ja s K3b ...
+Name[sr]=Направи одраз CD-а помоћу K3b-а...
+Name[sr@Latn]=Napravi odraz CD-a pomoću K3b-a...
+Name[sv]=Skriv cd-avbild med K3b...
+Name[ta]=குறுந்தகட்டு நிழலுடன் K3bஐ உருவாக்குக...
+Name[tr]=K3b ile CD Kalıbı yazdır...
+Name[uk]=Записати штамп КД за допомогою K3b...
+Name[zh_CN]=用 K3b 刻录 CD 映像...
+Icon=k3b
+
+Name[fi]=Kirjoita CD-levynkuva K3b:llä
+Name[km]=សរសេរ​រូបភាព​ស៊ីឌី​ជាមួយ K3b...
+Name[zh_TW]=以 K3b 燒錄 CD 映像...
diff --git a/src/servicemenus/k3b_write_iso_image.desktop b/src/servicemenus/k3b_write_iso_image.desktop
new file mode 100644
index 0000000..8808f80
--- /dev/null
+++ b/src/servicemenus/k3b_write_iso_image.desktop
@@ -0,0 +1,124 @@
+[Desktop Entry]
+Actions=WriteCdImage;
+Encoding=UTF-8
+ServiceTypes=application/x-iso,inode/ISO-image
+
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+[Desktop Action WriteCdImage]
+Exec=k3b --image %F
+Name=Write CD Image with K3b...
+Name[af]=Skryf CD beeld met K3b...
+Name[bg]=Запис на CD образ с K3b...
+Name[bn]=কে-থ্রি-বি দিয়ে সিডি ইমেজ লেখো...
+Name[br]=srivañ ar skeudenn CD gant K3b ...
+Name[bs]=Zapiši CD image koristeći K3b...
+Name[ca]=Escriu imatge per a CD amb K3b...
+Name[cs]=Vypálit obraz CD...
+#SUSE-Overwrite Name[da]=Skriv cd-billede med K3b...
+Name[da]=Skriv CD-billede med K3b...
+Name[de]=CD-Abbild mit K3b brennen ...
+Name[el]=Εγγραφή εικόνας CD με το K3b...
+Name[es]=Escribir imagen de CD con K3b...
+Name[et]=Kirjuta tõmmis K3b abil plaadile...
+Name[eu]=Idatzi CD irudiak K3b-rekin...
+Name[fr]=Graver une image CD avec K3b...
+Name[he]=כתוב תבנית CD בעזרת K3b...
+Name[hi]=के3बी के साथ सीडी इमेज लिखें...
+Name[hu]=CD-képmásfájl írása a K3b-vel...
+Name[is]=Skrifa diskmynd með K3b...
+Name[it]=Scrivi immagine CD con K3b...
+#SUSE-Overwrite Name[ja]=CD イメージを K3b で書き込み...
+Name[ja]=K3bによるCDイメージの書込み...
+Name[lt]=Įrašykite CD atvaizdą su K3b...
+Name[mk]=Запишете CD-слика со K3b...
+#SUSE-Overwrite Name[nb]=Skriv CD-bilde med K3b . . .
+Name[nb]=Brenn diskbilde på CD med K3b...
+Name[nl]=CD-image schrijven met K3b...
+Name[pa]=K3b ਨਾਲ CD ਪ੍ਰਤੀਬਿੰਬ ਲਿਖੋ...
+Name[pl]=Stwórz obraz płyty CD za pomocą K3b...
+Name[pt]=Escrever uma Imagem de CD com o K3b...
+Name[pt_BR]=Gravar Imagem em CD com K3b...
+Name[ru]=Записать образ CD, используя K3b...
+Name[sl]=Zapiši sliko CD-ja s K3b ...
+Name[sr]=Направи одраз CD-а помоћу K3b-а...
+Name[sr@Latn]=Napravi odraz CD-a pomoću K3b-a...
+Name[sv]=Skriv cd-avbild med K3b...
+Name[ta]=குறுந்தகட்டு நிழலுடன் K3bஐ உருவாக்குக...
+Name[tr]=K3b ile CD Kalıbı yazdır...
+Name[uk]=Записати штамп КД за допомогою K3b...
+Name[zh_CN]=用 K3b 刻录 CD 映像...
+Icon=k3b
+
+Name[fi]=Kirjoita CD-levynkuva K3b:llä
+Name[km]=សរសេរ​រូបភាព​ស៊ីឌី​ជាមួយ K3b...
+Name[zh_TW]=以 K3b 燒錄 CD 映像...
diff --git a/src/servicemenus/kdesktopSetAsBackground.desktop b/src/servicemenus/kdesktopSetAsBackground.desktop
new file mode 100644
index 0000000..5606bb5
--- /dev/null
+++ b/src/servicemenus/kdesktopSetAsBackground.desktop
@@ -0,0 +1,201 @@
+[Desktop Entry]
+ServiceTypes=image/*
+Actions=setAsBackground;tileAsBackground;
+X-KDE-Submenu=Set as Background
+X-KDE-Submenu[af]=Stel as agtergrond
+X-KDE-Submenu[be]=Зрабіць фонавым малюнкам
+X-KDE-Submenu[bg]=Установяване като фон
+X-KDE-Submenu[bn]=পশ্চাদ্‌পট হিসাবে বেছে নাও
+X-KDE-Submenu[bs]=Postavi kao pozadinu
+X-KDE-Submenu[ca]=Estableix com a fons
+X-KDE-Submenu[cs]=Nastavit jako pozadí
+X-KDE-Submenu[csb]=Ùstôwi jakno spòdlé
+X-KDE-Submenu[da]=Sæt som baggrund
+X-KDE-Submenu[de]=Als Hintergrund setzen
+X-KDE-Submenu[el]=Ορισμός ως ταπετσαρία
+X-KDE-Submenu[eo]=Agordu kiel fono
+X-KDE-Submenu[es]=Establecer como fondo
+X-KDE-Submenu[et]=Sea taustapildiks
+X-KDE-Submenu[eu]=Ezarri atzeko plano gisa
+X-KDE-Submenu[fa]=تنظیم به عنوان زمینه
+X-KDE-Submenu[fi]=Aseta taustakuvaksi
+X-KDE-Submenu[fr]=Définir comme arrière-plan
+X-KDE-Submenu[fy]=As eftergrûn brûke
+X-KDE-Submenu[gl]=Pór como Fondo de Escritório
+X-KDE-Submenu[he]=קבע כרקע
+X-KDE-Submenu[hr]=Postavi kao pozadinu
+X-KDE-Submenu[hu]=Beállítás háttérképnek
+X-KDE-Submenu[is]=Setja sem bakgrunn
+X-KDE-Submenu[it]=Imposta come sfondo
+X-KDE-Submenu[ja]=背景としてセット
+X-KDE-Submenu[kk]=Ая ретінде орнату
+X-KDE-Submenu[km]=កំណត់​ជា​ផ្ទៃខាងក្រោយ
+X-KDE-Submenu[lt]=Nustatyti fonu
+X-KDE-Submenu[mk]=Постави како подлога
+X-KDE-Submenu[nb]=Sett som bakgrunn
+X-KDE-Submenu[nds]=As Achtergrund fastleggen
+X-KDE-Submenu[ne]=पृष्ठभूमिको रुपमा सेट गर्छ
+X-KDE-Submenu[nl]=Als achtergrond gebruiken
+X-KDE-Submenu[nn]=Bruk som bakgrunn
+X-KDE-Submenu[pa]=ਪਿੱਠਭੂਮੀ ਬਣਾਓ
+X-KDE-Submenu[pl]=Ustaw jako tło
+X-KDE-Submenu[pt]=Definir como Fundo
+X-KDE-Submenu[pt_BR]=Configurar como Plano de fundo
+X-KDE-Submenu[ro]=Setează ca fundal
+X-KDE-Submenu[ru]=Сделать фоновым рисунком
+X-KDE-Submenu[se]=Geavat duogášgovvan
+X-KDE-Submenu[sk]=Nastaviť ako pozadie
+X-KDE-Submenu[sl]=Nastavi kot ozadje
+X-KDE-Submenu[sr]=Постави као позадину
+X-KDE-Submenu[sr@Latn]=Postavi kao pozadinu
+X-KDE-Submenu[sv]=Använd som bakgrund
+X-KDE-Submenu[th]=ตั้งให้เป็นพื้นหลัง
+X-KDE-Submenu[uk]=Встановити як тло
+X-KDE-Submenu[uz]=Иш столига қўйиш
+X-KDE-Submenu[vi]=Đặt làm Hình nền
+X-KDE-Submenu[zh_CN]=设为背景
+X-KDE-Submenu[zh_TW]=設為背景
+
+[Desktop Action setAsBackground]
+Name=Centered
+Name[af]=Gesentreer
+Name[ar]=مركز
+Name[be]=Пасярэдзіне
+Name[bg]=Центрирано
+Name[bn]=মাঝামাঝি
+Name[br]=Kreizennet
+Name[bs]=Centrirano
+Name[ca]=Centrat
+Name[cs]=Na střed
+Name[csb]=Na westrzódkù
+Name[cy]=Canoledig
+Name[da]=Centreret
+Name[de]=Zentriert
+Name[el]=Κεντράρισμα
+Name[en_GB]=Centred
+Name[eo]=Meza
+Name[es]=Centrado
+Name[et]=Tsentreeritud
+Name[eu]=Erdiratua
+Name[fa]=مرکزی
+Name[fi]=Keskitetty
+Name[fr]=Centré
+Name[fy]=sintraal setten
+Name[ga]=Láraithe
+Name[gl]=Centrado
+Name[he]=ממורכז
+Name[hi]=बीचों-बीच
+Name[hr]=Sredinom
+Name[hu]=Középre igazítva
+Name[is]=Miðjað
+Name[it]=Centrato
+Name[ja]=中央
+Name[kk]=Ортаға
+Name[km]=កណ្ដាល
+Name[lt]=Centruota
+Name[lv]=Centrēts
+Name[mk]=Центриран
+Name[ms]=Tengah
+Name[mt]=Iċċentrat
+Name[nb]=Sentrert
+Name[nds]=In de Merrn
+Name[ne]=केन्द्रित
+Name[nl]=Gecentreerd
+Name[nn]=Sentrert
+Name[pa]=ਕੇਂਦਰੀ
+Name[pl]=Wyśrodkowane
+Name[pt]=Centrado
+Name[pt_BR]=Centralizado
+Name[ro]=Centrat
+Name[ru]=По центру
+Name[rw]=Biri hagati
+Name[se]=Guovdut
+Name[sk]=V strede
+Name[sl]=Usrediščeno
+Name[sr]=Центрирано
+Name[sr@Latn]=Centrirano
+Name[sv]=Centrerad
+Name[ta]=மைய
+Name[te]=మద్యన
+Name[tg]=Марказӣ
+Name[th]=จัดกลาง
+Name[tr]=Ortalanmış
+Name[tt]=Üzäkläşep
+Name[uk]=По центру
+Name[uz]=Марказда
+Name[vi]=Giữa
+Name[zh_CN]=居中
+Name[zh_TW]=置中
+Icon=background
+Exec=dcop kdesktop KBackgroundIface setWallpaper %u 6
+
+[Desktop Action tileAsBackground]
+Name=Tiled
+Name[af]=Geteël
+Name[ar]=مبلّط
+Name[be]=Расцягнутае
+Name[bg]=Каскадно
+Name[bn]=টাইল করা
+Name[br]=Teolet
+Name[bs]=Popločano
+Name[ca]=Repetit
+Name[cs]=Dlaždice
+Name[csb]=Kachelkòwóné
+Name[cy]=Teiledig
+Name[da]=Fliselagt
+Name[de]=Gekachelt
+Name[el]=Σε παράθεση
+Name[eo]=kahela
+Name[es]=Mosaico
+Name[et]=Paanidena
+Name[eu]=Mosaikoa
+Name[fa]=کاشی‌شده
+Name[fi]=Vierekkäin
+Name[fr]=Mosaïque
+Name[fy]=Tegele
+Name[ga]=Tilithe
+Name[gl]=Mosaico
+Name[he]=פרוש
+Name[hi]=चटाई-दार
+Name[hr]=Popločeno
+Name[hu]=Mozaikszerűen
+Name[is]=Flísað
+Name[it]=Ripetuto
+Name[ja]=タイル状
+Name[kk]=Қатарлап
+Name[km]=ក្បឿង
+Name[lt]=Iškloti
+Name[mk]=Поплочен
+Name[ms]=Berjubin
+Name[mt]=Madum
+Name[nb]=Flislagt
+Name[nds]=Kachelt
+Name[ne]=टायल गरिएको
+Name[nl]=Tegels
+Name[nn]=Jamsides
+Name[pa]=ਤਣਿਆ
+Name[pl]=Kafelkowane
+Name[pt]=Mosaico
+Name[pt_BR]=Ladrilhado
+Name[ro]=Mozaic
+Name[ru]=Черепицей
+Name[rw]=Byudukaro
+Name[se]=Bálddalaga
+Name[sk]=Dlaždice
+Name[sl]=Razdeljeno
+Name[sr]=Поређано
+Name[sr@Latn]=Poređano
+Name[sv]=Sida vid sida
+Name[ta]=பிண்ணனி
+Name[te]=పలకలుగా
+Name[tg]=Тахтасангӣ
+Name[th]=ปูทั้งหน้าจอ
+Name[tr]=Uzatılmış
+Name[tt]=Bülengän
+Name[uk]=Плиткою
+Name[uz]=Кафель
+Name[vi]=Xếp ngói
+Name[zh_CN]=平铺
+Name[zh_TW]=拼貼
+Icon=background
+Exec=dcop kdesktop KBackgroundIface setWallpaper %u 2
diff --git a/src/servicemenus/konqgwenview.desktop b/src/servicemenus/konqgwenview.desktop
new file mode 100644
index 0000000..1354948
--- /dev/null
+++ b/src/servicemenus/konqgwenview.desktop
@@ -0,0 +1,53 @@
+[Desktop Entry]
+Encoding=UTF-8
+ServiceTypes=inode/directory
+Actions=gwenview;
+
+[Desktop Action gwenview]
+Name=Browse with Gwenview
+Name[ar]=تصفح بواسطة Gwenview
+Name[bg]=Преглед с Gwenview
+Name[br]=Furchal gant Gwenview
+Name[bs]=Pregledaj sa Gwenview
+Name[ca]=Navega amb el Gwenview
+Name[cs]=Prohlížet pomocí Gwenview
+Name[da]=Gennemse med Gwenview
+Name[de]=Dateien mit Gwenview durchsehen
+Name[el]=Εξερεύνηση με το Gwenview
+Name[es]=Navegación con Gwenview
+Name[et]=Lehitse kasutades Gwenview'd
+Name[fi]=Katsele Gwenviewilla
+Name[fr]=Naviguer avec Gwenview
+Name[ga]=Brabhsáil le Gwenview
+Name[gl]=Examinar con Gwenview
+Name[he]=עיין בעזרת Gwenview
+Name[hi]=ग्वेनव्यू के साथ ब्राउज़ करें
+Name[hr]=Pretraži s Gwenview
+Name[hu]=Böngészés a Gwenview-val
+Name[is]=Skoða með Gwenview
+Name[it]=Sfoglia con Gwenview
+Name[ja]=Gwenview で閲覧
+Name[ka]=დათვალიერება Gwenview-ით
+Name[ms]= Lungsur dengan Gwenview
+Name[nl]=Bladeren met Gwenview
+Name[pa]=Gwenview ਨਾਲ ਵੇਖੋ
+Name[pl]=Przeglądaj za pomocą Gwenview
+Name[pt]=Navegar com o Gwenview
+Name[pt_BR]=Navegar com Gwenview
+Name[ru]=Просмотреть в Gwenview
+Name[sk]=Prehliadať s Gwenview
+Name[sl]=Brskaj z Gwenview
+Name[sr]=Прегледај помоћу Gwenview-а
+Name[sr@Latn]=Pregledaj pomoću Gwenview-a
+Name[sv]=Bläddra med Gwenview
+Name[ta]=GWEN பார்வையை வைத்து தேடு
+Name[tg]=Ҷустан бо НамоишиGwen
+Name[tr]=Gwenview ile gözat
+Name[uk]=Перегляд у Gwenview
+Name[xh]=Khangela nge Gwenview
+Name[xx]=xxBrowse with Gwenviewxx
+Name[zh_CN]=用 Gwenview 浏览
+Name[zh_TW]=以 Gwenview 瀏覽
+Name[zu]=Cinga nge-Gwenview
+Icon=gwenview
+Exec=gwenview %u
diff --git a/src/servicemenus/konsolehere.desktop b/src/servicemenus/konsolehere.desktop
new file mode 100644
index 0000000..a46d1c3
--- /dev/null
+++ b/src/servicemenus/konsolehere.desktop
@@ -0,0 +1,123 @@
+[Desktop Entry]
+ServiceTypes=inode/directory
+Actions=openTerminalHere;
+X-KDE-AuthorizeAction=shell_access
+Encoding=UTF-8
+Type=Application
+
+Name=Konsole
+Name[ar]=طرفية التحكم
+Name[az]=Konsol
+Name[be]=Кансоль
+Name[bg]=Конзола
+Name[bn]=কনসোল
+Name[bs]=Konzola
+Name[ca]=Consola
+Name[csb]=Kònsola
+Name[el]=Κονσόλα
+Name[eo]=Konzolo
+Name[et]=Konsool
+Name[eu]=Kontsola
+Name[he]=מסוף
+Name[hi]=कंसोल
+Name[hr]=Konzola
+Name[is]=Skjáhermir
+Name[ko]=KDE용 콘솔
+Name[lo]=ຄອນໂຊລ - K
+Name[mk]=Конзола
+Name[mn]=Консол
+Name[nb]=Konsoll
+Name[ne]=कन्सोल
+Name[nn]=Konsoll
+Name[pa]=ਕੰਨਸੋਲ
+Name[pl]=Konsola
+Name[ro]=Consolă
+Name[ru]=Консоль
+Name[se]=Konsolla
+Name[sk]=Konzola
+Name[sl]=Konzola
+Name[ta]=கான்சோல்
+Name[te]=కాన్సోల్
+Name[tg]=Консол
+Name[th]=คอนโซล K
+Name[zu]=Ikhonsoli
+
+[Desktop Action openTerminalHere]
+Name=Open Terminal Here
+Name[af]=Maak Terminaal Hier Oop
+Name[ar]=إفتح مطراف سطر الأوامر هنا
+Name[az]=Terminalı Burada Aç
+Name[be]=Адкрыць тэрмінал тут
+Name[bg]=Отваряне на конзола тук
+Name[bn]=এখানে টার্মিনাল খোলো
+Name[br]=Digeriñ un termenell amañ
+Name[bs]=Otvori terminal ovdje
+Name[ca]=Obre un terminal aquí
+Name[cs]=Otevřít terminál zde
+Name[csb]=Òtemknij tuwò terminal
+Name[cy]=Agor Terfynell Yma
+Name[da]=Åbn terminal her
+Name[de]=Terminal öffnen
+Name[el]=Άνοιγμα τερματικού εδώ
+Name[eo]=Lanĉu terminalon ĉi tie
+Name[es]=Abrir terminal aquí
+Name[et]=Ava siin terminal
+Name[eu]=Ireki terminala hemen
+Name[fa]=باز کردن پایانه در اینجا
+Name[fi]=Avaa komentoikkuna tähän
+Name[fr]=Ouvrir un terminal ici
+Name[fy]=Terminal iepenje
+Name[ga]=Oscail Teirminéal Anseo
+Name[gl]=Abrir Terminal Aqui
+Name[he]=פתח מסוף כאן
+Name[hi]=टर्मिनल यहाँ खोलें
+Name[hr]=Ovdje otvori terminal
+Name[hu]=Parancsértelmező megnyitása itt
+Name[is]=Opna skjáhermi hér
+Name[it]=Apri terminale qui
+Name[ja]=ここでターミナルを開く
+Name[kk]=Терминалды ашу
+Name[km]=បើក​ស្ថានីយ​ទីនេះ
+Name[lo]=ເທີມິເນລຂອງ X
+Name[lt]=Atverti čia terminalą
+Name[lv]=Atvērt termināli šeit
+Name[mk]=Отвори терминал тука
+Name[mn]=Терминал нээх
+Name[ms]=Buka Terminal Di Sini
+Name[mt]=Iftaħ terminal hawn
+Name[nb]=Åpne terminal her
+Name[nds]=Terminal hier opmaken
+Name[ne]=यहाँ टर्मिनल खोल्नुहोस्
+Name[nl]=Terminal openen
+Name[nn]=Opna terminal her
+Name[nso]=Bula mafelelo Mo
+Name[pa]=ਟਰਮੀਨਲ ਇੱਥੇ ਖੋਲੋ
+Name[pl]=Otwórz tutaj terminal
+Name[pt]=Abrir um Terminal Aqui
+Name[pt_BR]=Abrir Terminal Aqui
+Name[ro]=Deschide un terminal aici
+Name[ru]=Открыть терминал в этой папке
+Name[rw]= Gufungura Igihera Hano
+Name[se]=Raba terminála dáppe
+Name[sk]=Tu otvoriť terminál
+Name[sl]=Tu odpri terminal
+Name[sr]=Отвори терминал овде
+Name[sr@Latn]=Otvori terminal ovde
+Name[ss]=Vula sikhungo lapha
+Name[sv]=Öppna terminal här
+Name[ta]=முனைய இங்கே திற
+Name[tg]=Терминалро дар инҷо боз кунед
+Name[th]=เปิดเทอร์มินัลที่นี่
+Name[tr]=Terminali Burada Aç
+Name[tt]=Terminalnı Monda Açası
+Name[uk]=Відкрити термінал
+Name[uz]=Терминални шу ерда очиш
+Name[ven]=Vulani theminala hafhano
+Name[vi]=Mở một Thiết bị cuối ở Đây
+Name[wa]=Drovi on terminå chal
+Name[xh]=Vula Isiphelo Sendlela Apha
+Name[zh_CN]=在此打开终端
+Name[zh_TW]=在這裡開啟終端機
+Name[zu]=Vula ithuluzi langaphandle lapha
+Icon=konsole
+Exec=konsole --workdir %f
diff --git a/src/servicemenus/mail_as_attachment.desktop b/src/servicemenus/mail_as_attachment.desktop
new file mode 100644
index 0000000..f8a7c23
--- /dev/null
+++ b/src/servicemenus/mail_as_attachment.desktop
@@ -0,0 +1,10 @@
+[Desktop Entry]
+Encoding=UTF-8
+ServiceTypes=all/allfiles
+Actions=mail_as_attachment
+
+[Desktop Action mail_as_attachment]
+Name=Mail as Attachment...
+Name[de]=Verschicken als Anhang...
+Icon=mail_send
+Exec=kmail --attach %U
diff --git a/src/servicemenus/media_eject.desktop b/src/servicemenus/media_eject.desktop
new file mode 100644
index 0000000..151790f
--- /dev/null
+++ b/src/servicemenus/media_eject.desktop
@@ -0,0 +1,158 @@
+[Desktop Entry]
+ServiceTypes=media/cdrom_mounted,media/cdrom_unmounted,media/cdwriter_mounted,media/cdwriter_unmounted,media/dvd_mounted,media/dvd_unmounted,media/audiocd,media/blankcd,media/blankdvd,media/dvdvideo,media/svcd,media/vcd
+Actions=MediaEject;
+X-KDE-Priority=TopLevel
+X-KDE-MediaNotifierHide=true
+
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+[Desktop Action MediaEject]
+Name=Eject
+Name[af]=Uitskiet
+Name[ar]=اخراج
+Name[az]=Çıxart
+Name[be]=Выняць
+Name[bg]=Изваждане
+Name[bn]=ইজেক্ট
+Name[br]=Stlepel
+Name[bs]=Izbaci
+Name[ca]=Expulsa
+Name[cs]=Vysunout
+Name[cy]=Allfwrw
+Name[da]=Skub ud
+Name[de]=Auswerfen
+Name[el]=Εξαγωγή
+Name[eo]=Eligo
+Name[es]=Expulsar
+Name[et]=Väljastamine
+Name[eu]=Kanporatu
+Name[fa]=اخراج
+Name[fi]=Poista
+Name[fr]=Éjecter
+Name[fy]=Utsmytknop
+Name[ga]=Díchuir
+Name[gl]=Expulsar
+Name[he]=הוצא
+Name[hi]=बाहर
+Name[hr]=Izbaci
+#SUSE-Overwrite Name[hu]=Kidobás
+Name[hu]=Kiadás
+Name[is]=Henda út
+Name[it]=Espelli
+Name[ja]=取り出し
+#SUSE-Overwrite Name[km]=ច្រាន​ចេញ
+Name[km]=ច្រានចេញ
+Name[ko]=꺼내기
+Name[lo]=ເອົາແຜ່ນອອກ
+Name[lt]=Išmesti
+Name[lv]=Izņemt
+Name[mk]=Извади
+Name[mn]=Гаргах
+Name[ms]=Lenting
+Name[mt]=Iftaħ
+Name[nb]=Løs ut
+Name[nds]=Rutsmieten
+Name[nl]=Uitwerpen
+Name[nn]=Løys ut
+Name[nso]=Ntsha
+Name[oc]=Expulsa
+Name[pa]=ਬਾਹਰ ਕੱਢੋ
+Name[pl]=Wysuń
+Name[pt]=Ejectar
+Name[pt_BR]=Ejetar
+Name[ro]=Ejectează
+Name[ru]=Извлечь CD
+Name[rw]=Gusohora
+Name[se]=Bálkes olggos
+Name[sk]=Vysunúť
+Name[sl]=Izvrzi
+Name[sr]=Избаци
+Name[sr@Latn]=Izbaci
+Name[ss]=Khafuna
+Name[sv]=Mata ut
+Name[ta]=வெளித்தள்
+Name[tg]=Ихроҷ
+Name[th]=เอาแผ่นออก
+Name[tr]=Çıkart
+Name[tt]=Çığar
+Name[uk]=Виштовхнути
+Name[uz]=Чиқариш
+Name[ven]=Bvisa
+Name[vi]=Đẩy ra
+Name[wa]=Fé rexhe
+Name[xh]=Khuphela ngaphandle
+Name[zh_CN]=弹出
+Name[zh_TW]=退出
+Name[zu]=Khipha
+Exec=kio_media_mounthelper -e %u
+
+
diff --git a/src/servicemenus/media_mount.desktop b/src/servicemenus/media_mount.desktop
new file mode 100644
index 0000000..12fa545
--- /dev/null
+++ b/src/servicemenus/media_mount.desktop
@@ -0,0 +1,155 @@
+[Desktop Entry]
+ServiceTypes=media/cdrom_unmounted,media/cdwriter_unmounted,media/dvd_unmounted,media/floppy5_unmounted,media/floppy_unmounted,media/hdd_unmounted,media/nfs_unmounted,media/removable_unmounted,media/smb_unmounted,media/zip_unmounted,media/camera_unmounted
+Actions=MediaMount;
+X-KDE-Priority=TopLevel
+X-KDE-MediaNotifierHide=true
+
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+[Desktop Action MediaMount]
+Name=Mount
+Name[af]=Koppel
+Name[ar]=حمّل
+Name[az]=Bağla
+Name[bg]=Монтиране
+Name[bn]=মাউন্ট
+Name[br]=Marc'hañ
+Name[bs]=Montiraj
+Name[ca]=Munta
+Name[cs]=Připojit
+Name[cy]=Gosod
+Name[da]=Montér
+Name[de]=Laufwerk einbinden
+Name[el]=Προσάρτηση
+Name[eo]=Kroĉo
+Name[es]=Montar
+Name[et]=Ühenda
+Name[eu]=Muntatu
+Name[fa]=سوارکردن
+Name[fi]=Liitä
+Name[fr]=Monter
+Name[fy]=Oankeppelje (mount)
+Name[ga]=Feistigh
+Name[gl]=Montar
+Name[he]=חבר
+Name[hi]=माउन्ट
+Name[hr]=Montiraj
+Name[hsb]=montować
+Name[hu]=Csatlakoztatás
+Name[is]=Tengja
+Name[it]=Monta
+Name[ja]=マウント
+#SUSE-Overwrite Name[km]=រៀបចំ
+Name[km]=ម៉ោន
+Name[lo]=ຈໍພາບ
+Name[lt]=Montuoti
+Name[lv]=Piemontēt
+Name[mk]=Монтирај
+Name[mn]=Залгах
+Name[ms]=Lekap
+Name[mt]=Immonta
+Name[nb]=Monter
+Name[nds]=Inhangen
+Name[nl]=Aankoppelen (mount)
+Name[nn]=Monter
+Name[nso]=Nameletsa
+#SUSE-Overwrite Name[pa]=ਮਾਊਟ
+Name[pa]=ਮਾਊਂਟ
+Name[pl]=Zamontuj
+Name[pt]=Montar
+Name[pt_BR]=Montar
+Name[ro]=Montează
+Name[ru]=Монтировать
+Name[rw]=Gushyiramo
+Name[se]=Čana
+Name[sk]=Pripojiť
+Name[sl]=Priklopi
+Name[sr]=Монтирај
+Name[sr@Latn]=Montiraj
+Name[sv]=Montera
+Name[ta]=ஏற்று
+Name[tg]=Васл кунӣ
+Name[th]=เม้าทน์
+Name[tr]=Bağla
+Name[tt]=Bäyläp quy
+Name[uk]=Змонтувати
+Name[uz]=Улаш
+Name[ven]=Gonya
+Name[vi]=Gắn kết
+Name[wa]=Monter
+Name[xh]=Layisha
+Name[zh_CN]=挂载
+Name[zh_TW]=掛載
+Name[zu]=Yenyusa
+Exec=kio_media_mounthelper -m %u
+
+
diff --git a/src/servicemenus/media_realfolder.desktop b/src/servicemenus/media_realfolder.desktop
new file mode 100644
index 0000000..b53f546
--- /dev/null
+++ b/src/servicemenus/media_realfolder.desktop
@@ -0,0 +1,114 @@
+[Desktop Entry]
+ServiceTypes=media/cdrom_mounted,media/cdwriter_mounted,media/dvd_mounted,media/floppy5_mounted,media/floppy_mounted,media/hdd_mounted,media/nfs_mounted,media/smb_mounted,media/removable_mounted,media/zip_mounted
+Actions=MediaRealFolder
+X-KDE-Priority=TopLevel
+X-KDE-MediaNotifierHide=true
+
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+[Desktop Action MediaRealFolder]
+Name=Open Medium System Folder
+Name[ca]=Obre la carpeta de mitjans del sistema
+Name[cs]=Otevřít systémovou složku média
+Name[da]=Åbn medium-system-mappen
+Name[de]=Systemordner des Mediums öffnen
+Name[el]=Άνοιγμα του φακέλου συστήματος του μέσου
+Name[es]=Abrir la carpeta del administrador de medios...
+Name[et]=Ava andmekandja süsteemi kataloog
+Name[eu]=Ireki euskarriaren kudeatzailea
+Name[fi]=Avaa mediajärjestelmän kansio
+Name[fr]=Dossier système d'ouverture de média
+Name[he]=פתח את תיקיית מדיית המערכת
+Name[hu]=A médiaanyagok rendszerkönyvtárának megnyitása
+Name[is]=Opin miðils kerfismappa
+Name[it]=Cartella di sistema per l'apertura di supporti
+Name[lt]=Atverti sisteminį įrenginio aplanką
+Name[nb]=Åpne systemmappe for medie
+Name[nl]=Systeemmap medium openen
+#SUSE-Overwrite Name[pa]=ਮੀਡੀਅਮ ਸਿਸਟਮ ਫੋਲਡਰ ਖੋਲੋ
+Name[pa]=ਮੀਡਿਅਮ ਸਿਸਟਮ ਫੋਲਡਰ ਖੋਲੋ
+Name[pl]=Otwórz folder systemowy mediów
+Name[pt]=Pasta de Sistema Média Aberto
+Name[pt_BR]=Abrir a Pasta de Mídias do Sistema
+Name[ru]=Открыть системную папку
+Name[sr]=Отвори системску фасциклу медијума
+Name[sr@Latn]=Otvori sistemsku fasciklu medijuma
+Name[sv]=Öppna mediumsystemkatalog
+Name[uk]=Відкрити системну теку носія
+Name[zh_CN]=打开介质系统文件夹
+Exec=kio_media_realfolder %u
+
+
+Name[bg]=Системна папка на Open Medium
+Name[ja]=オープン メディアシステムフォルダ
+Name[km]=បើក​ថត​ប្រព័ន្ធ​មេឌៀ
+Name[zh_TW]=開啟媒體系統資料夾
diff --git a/src/servicemenus/media_safelyremove.desktop b/src/servicemenus/media_safelyremove.desktop
new file mode 100644
index 0000000..7d1ccc2
--- /dev/null
+++ b/src/servicemenus/media_safelyremove.desktop
@@ -0,0 +1,132 @@
+[Desktop Entry]
+ServiceTypes=media/removable_mounted,media/removable_unmounted,media/camera_mounted,media/camera_unmounted
+Actions=MediaSafelyRemove;
+X-KDE-Priority=TopLevel
+X-KDE-MediaNotifierHide=true
+
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+[Desktop Action MediaSafelyRemove]
+Name=Safely Remove
+Name[af]=Verwyder veilig
+Name[bg]=Безопасно изваждане
+Name[bn]=নিরাপদভাবে সরাও
+Name[ca]=Extreu amb seguretat
+Name[cs]=Bezpečně odstranit
+Name[da]=Fjern sikkert
+Name[de]=Sicher entfernen
+Name[el]=Ασφαλής αφαίρεση
+Name[es]=Extracción segura
+Name[et]=Eemalda turvaliselt
+Name[eu]=Atera arriskurik gabe
+Name[fi]=Poista turvallisesti
+Name[fr]=Enlever en toute sécurité
+Name[fy]=Feilich ferwiderje
+Name[gl]=Eliminar de Maneira Segura
+Name[he]=שליפה בבטחה
+Name[hu]=Biztonságos leválasztás
+Name[is]=Fjarlægja öruggt
+Name[it]=Rimozione sicura
+Name[ja]=安全に取り除く
+#SUSE-Overwrite Name[km]=យកចេញ​ដោយ​សុវត្ថិភាព
+Name[km]=យក​ចេញ​ដោយ​សុវត្ថិភាព
+Name[lt]=Saugiai pašalinti
+Name[mk]=Отстрани безбедно
+Name[ms]=Buang Dengan Selamat
+Name[nb]=Sikker fjerning
+Name[nds]=Seker rutnehmen
+Name[nl]=Veilig verwijderen
+Name[nn]=Trygg fjerning
+#SUSE-Overwrite Name[pa]=ਸੁਰੱਖਿਅਤ ਹਟਾਓ
+Name[pa]=ਸੁਰੱਖਿਅਤ ਰੂਪ 'ਚ ਹਟਾਓ
+Name[pl]=Usuń w sposób bezpieczny
+Name[pt]=Retirar com Segurança
+Name[pt_BR]=Remover de Modo Seguro
+Name[ro]=Scoate în siguranţă
+Name[ru]=Безопасно извлечь
+Name[rw]=Gukuramo Neza
+Name[se]=Dorvvošlaš eretváldin
+Name[sl]=Varno odstrani
+Name[sr]=Безбедно уклони
+Name[sr@Latn]=Bezbedno ukloni
+Name[sv]=Säker urkoppling
+Name[ta]=பாதுகாப்பாக நீக்கு
+Name[th]=ถอดออกได้อย่างปลอดภัย
+Name[tr]=Güvenli Kaldır
+Name[tt]=İmin Çığaru
+Name[uk]=Безпечно вилучити
+Name[uz]=Эҳтиётлик билан узиш
+Name[zh_CN]=安全删除
+Name[zh_TW]=安全的移除
+Exec=kio_media_mounthelper -s %u
+
+
diff --git a/src/servicemenus/media_unmount.desktop b/src/servicemenus/media_unmount.desktop
new file mode 100644
index 0000000..b70e3a5
--- /dev/null
+++ b/src/servicemenus/media_unmount.desktop
@@ -0,0 +1,155 @@
+[Desktop Entry]
+ServiceTypes=media/cdrom_mounted,media/cdwriter_mounted,media/dvd_mounted,media/floppy5_mounted,media/floppy_mounted,media/hdd_mounted,media/nfs_mounted,media/smb_mounted,media/zip_mounted,media/vcd,media/svcd,media/dvdvideo
+Actions=MediaUnmount;
+X-KDE-Priority=TopLevel
+X-KDE-MediaNotifierHide=true
+
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+X-SuSE-translate=true
+[Desktop Action MediaUnmount]
+Name=Unmount
+Name[af]=Ontkoppel
+Name[ar]=أزل التحميل
+Name[az]=Ayır
+Name[bg]=Демонтиране
+Name[bn]=আনমাউন্ট
+Name[br]=Divarc'hañ
+Name[bs]=Demontiraj
+Name[ca]= Desmunta
+Name[cs]=Odpojit
+Name[cy]=Dadosod
+Name[da]=Afmontér
+Name[de]=Laufwerkeinbindung lösen
+Name[el]=Αποπροσάρτηση
+Name[eo]=Malkroĉo
+Name[es]=Desmontar
+Name[et]=Lahuta
+Name[eu]=Desmuntatu
+Name[fa]=پیاده کردن
+Name[fi]=Irrota
+Name[fr]=Démonter (enlever de l'arborescence Linux)
+Name[fy]=Ofkeppelje (unmount)
+Name[ga]=Dífheistigh
+Name[gl]=Desmontar
+Name[he]=נתק
+Name[hi]=अनमाउन्ट
+Name[hr]=Demontiraj
+Name[hsb]=Wotmontować
+Name[hu]=Leválasztás
+Name[is]=Aftengja
+Name[it]=Smonta
+Name[ja]=マウント解除
+#SUSE-Overwrite Name[km]=មិន​រៀបចំ
+Name[km]=មិន​ម៉ោន
+Name[lo]=ຫັງກາລີ
+Name[lt]=Išmontuoti
+Name[lv]=Nomontēt
+Name[mk]=Демонтирај
+Name[mn]=Салгах
+Name[ms]=Nyahlekap
+Name[mt]=Żmonta
+Name[nb]=Avmonter
+Name[nds]=Afhangen
+Name[nl]=Afkoppelen (unmount)
+Name[nn]=Avmonter
+Name[nso]=Theosa
+#SUSE-Overwrite Name[pa]=ਅਨਮਾਉਟ
+Name[pa]=ਅਣ-ਮਾਊਂਟ
+Name[pl]=Odmontuj
+Name[pt]=Desmontar
+Name[pt_BR]=Desmontar
+Name[ro]=Demontează
+Name[ru]=Отмонтировать
+Name[rw]=Gukuramo
+Name[se]=Gálgga
+Name[sk]=Odpojiť
+Name[sl]=Odklopi
+Name[sr]=Демонтирај
+Name[sr@Latn]=Demontiraj
+Name[sv]=Avmontera
+Name[ta]=வெளியேற்று
+Name[tg]=Ҷудо кунӣ
+Name[th]=ยกเลิกเม้าทน์
+Name[tr]=Ayır
+Name[tt]=Bäyläwne çiş
+Name[uk]=Демонтувати
+Name[uz]=Узиш
+Name[ven]=Usa gonya
+Name[vi]=Gỡ
+Name[wa]=Dismonter
+Name[xh]=Sukuyilayisha
+Name[zh_CN]=卸载
+Name[zh_TW]=未掛載
+Name[zu]=Yehlisa
+Exec=kio_media_mounthelper -u %u
+
+
diff --git a/src/servicemenus/open_in_digikam.desktop b/src/servicemenus/open_in_digikam.desktop
new file mode 100644
index 0000000..658df91
--- /dev/null
+++ b/src/servicemenus/open_in_digikam.desktop
@@ -0,0 +1,29 @@
+[Desktop Action OpenDigikam]
+Exec=digikam --download-from %u
+Icon=digikam
+Name=Open in Digikam
+
+Name[bg]=Отваряне в digiKam
+Name[cs]=Otevřít v digiKamu
+Name[el]=Άνοιξε στο Digikam
+Name[es]=Abrir en digiKam
+Name[fi]=Avaa digiKamissa
+Name[fr]=Ouvert dans Digikam
+Name[hu]=Megnyitás Digikammel
+Name[ja]=Digikamでオープン
+Name[km]=បើក​ក្នុង Digikam
+Name[nb]=Åpne i digiKam
+Name[nl]=Openen in digiKam
+Name[pa]=ਡਿਜ਼ੀਕੈਮ 'ਚ ਖੋਲੋ
+Name[pl]=Otwórz w Digikam
+Name[pt]=Abrir no DigiKam
+Name[pt_BR]=Aberto no Digikam
+Name[sv]=Öppna med Digikam
+Name[uk]=Відкрити в Digikam
+Name[zh_CN]=在 Digikam 中打开
+Name[zh_TW]=在 Digikam 中開啟
+[Desktop Entry]
+Actions=OpenDigikam;
+ServiceTypes=media/gphoto2camera,media/camera_mounted,media/camera_unmounted
+
+X-SuSE-translate=true
diff --git a/src/servicemenus/run_as_root.desktop b/src/servicemenus/run_as_root.desktop
new file mode 100644
index 0000000..6ba05c0
--- /dev/null
+++ b/src/servicemenus/run_as_root.desktop
@@ -0,0 +1,17 @@
+[Desktop Entry]
+ServiceTypes=application/x-executable,application/x-shellscript,application/x-python,application/x-perl
+Actions=runassu
+
+[Desktop Action runassu]
+Name=Run as Root
+Name[de]=Als root ausführen
+Name[cs]=Spustit jako root
+Name[sk]=Spustiť ako root
+Name[hu]=Futtatás rootként
+Name[fr]=Lancer en root
+Name[el]=Εκτέλεση ως Υπερχρήστη�Name[es]=Ejecutar como Root
+Name[pt_br]=Executar como Root
+Name[it]=Esegui come Root
+Name[pl]=Uruchom jako root
+Icon=kfm
+Exec=kdesu -c
diff --git a/src/servicemenus/smb2rdc.desktop b/src/servicemenus/smb2rdc.desktop
new file mode 100644
index 0000000..4b55dea
--- /dev/null
+++ b/src/servicemenus/smb2rdc.desktop
@@ -0,0 +1,55 @@
+# KDE Config File
+[Desktop Entry]
+ServiceTypes=application/x-smb-server
+Actions=smb2rdc
+
+[Desktop Action smb2rdc]
+Name=Open Remote Desktop Connection to This Machine
+Name[be]=Адкрыць аддаленае злучэнне з кампутарам
+Name[bg]=Връзка с отдалечен работно място с избрания компютър
+Name[bn]=এই মেশিনে প্রত্যন্ত ডেস্কটপের সংযোগ খোলো
+Name[bs]=Otvori Remote Desktop vezu na ovaj računar
+Name[ca]=Obre una connexió remota d'escriptori a aquesta màquina
+Name[cs]=Otevřít vzdálené připojení plochy k tomuto počítači
+Name[da]=Åbn ekstern desktopforbindelse til denne maskine
+Name[de]=Verbindung zur Arbeitsfläche dieses Rechners herstellen
+Name[el]=Δημιουργία σύνδεσης σε απομακρυσμένη επιφάνεια εργασίας σε αυτό το μηχάνημα
+Name[es]=Abrir conexión remota de escritorio a este sistema
+Name[et]=Kaugtöölaua ühenduse avamine sellesse arvutisse
+Name[eu]=Open Remote Desktop konexioa makina honetara
+Name[fa]=باز کردن اتصال رومیزی راه دور برای این ماشین
+Name[fi]=Avaa etätyöpöytäyhteys tähän koneeseen
+Name[fr]=Ouvrir une connexion distante au bureau de cette machine
+Name[gl]=Abrir Conexión Remota de Escritorio a Esta Máquina
+Name[he]=פתח חיבור שולחן עבודה מרוחק למכונה זו
+Name[hu]=Távoli munkaasztal nyitása itt
+Name[is]=Opna fjarlæga skjáborðtengingu til þessarar vélar
+Name[it]=Apri connessione a desktop remoto a questa macchina
+Name[ja]=このホストへリモートデスクトップ接続を開く
+Name[kk]=Осы компьютердегі үстелге қашық қосылымды ашу
+Name[km]=បើក​ការ​ត​ភ្ជាប​ផ្ទៃ​តុ​ពី​ចម្ងាយ​ទៅ​ម៉ាស៊ីន​នេះ
+Name[lt]=Užmegzti nutolusio darbastalio prijungimą prie šio kompiuterio
+Name[nb]=Åpne fjerntilkobling til skrivebord til denne maskinen
+Name[nds]=Schriefdisch-Feernverbinnen na dissen Reekner opmaken
+Name[ne]=यो मेशिनमा टाढाको डेस्कटप जडान खोल्नुहोस्
+Name[nl]=Externe bureaubladverbinding met deze computer openen
+Name[nn]=Opna samband til skrivebordet over nettverket til denne maskina
+Name[pa]=ਇਹ ਮਸ਼ੀਨ ਲਈ ਰਿਮੋਟ ਡੈਸਕਟਾਪ ਕੁਨੈਕਸ਼ਨ ਖੋਲ੍ਹੋ
+Name[pl]=Otwórz zdalne połączenie z pulpitem na tej maszynie
+Name[pt]=Abrir Ligação Remota a Ecrã para Este Computador
+Name[pt_BR]=Abre Conexões Remotas para Essa Máquina
+Name[ru]=Открыть соединение Remote Desktop с этой машиной
+Name[sk]=Otvorí spojenie na vzdialenú pracovnú plochu na tomto počítači
+Name[sl]=Odpri povezavo z oddaljenim namizjem na tem računalniku
+Name[sr]=Отвори удаљену везу са радном површином на овој машини
+Name[sr@Latn]=Otvori udaljenu vezu sa radnom površinom na ovoj mašini
+Name[sv]=Öppna fjärrskrivbordsanslutning till den här datorn
+Name[tr]=Bu makinaya Uzak Masaüstü Bağlantısı aç
+Name[uk]=Відкрити з'єднання з віддаленою стільницею до цього комп'ютера
+Name[zh_CN]=打开到此计算机的远程桌面连接
+Name[zh_HK]=開放遠端桌面連線到這電腦
+Name[zh_TW]=在此主機上開啟遠端桌面
+Exec=krdc %u
+Icon=krdc
+
+
diff --git a/src/servicemenus/text-ada-print.desktop b/src/servicemenus/text-ada-print.desktop
new file mode 100644
index 0000000..c0c04c0
--- /dev/null
+++ b/src/servicemenus/text-ada-print.desktop
@@ -0,0 +1,76 @@
+[Desktop Entry]
+Encoding=UTF-8
+ServiceTypes=text/x-adasrc
+Actions=Print;
+
+[Desktop Action Print]
+Name=Print...
+Name[af]=Druk...
+Name[ar]=طباعة...
+Name[az]=Çap et...
+Name[be]=Друкаваць...
+Name[bg]=Печат...
+Name[bn]=ছাপাও...
+Name[br]=Moulañ ...
+Name[bs]=Štampaj...
+Name[ca]=Imprimeix...
+Name[cs]=Tisknout...
+Name[csb]=Drëkùjë...
+Name[cy]=Argraffu...
+Name[da]=Udskriv...
+Name[de]=Drucken ...
+Name[el]=Εκτύπωση...
+Name[eo]=Printi...
+Name[es]=Imprimir...
+Name[et]=Trüki...
+Name[eu]=Inprimatu...
+Name[fa]=چاپ...
+Name[fi]=Tulosta...
+Name[fr]=Imprimer...
+Name[fy]=Printsje...
+Name[ga]=Priontáil...
+Name[gl]=Imprimir...
+Name[he]=הדפס...
+Name[hi]=छापें...
+Name[hr]=Ispiši...
+Name[hu]=Nyomtatás...
+Name[is]=Prenta...
+Name[it]=Stampa...
+Name[ja]=印刷...
+Name[kk]=Басып шығару...
+Name[km]=បោះពុម្ព...
+Name[lv]=Drukāt...
+Name[mk]=Печати...
+Name[ms]=Cetak...
+Name[mt]=Ipprintja...
+Name[nb]=Skriv ut...
+Name[nds]=Drucken...
+Name[ne]=मुद्रण...
+Name[nl]=Afdrukken...
+Name[nn]=Skriv ut ...
+Name[pa]=ਛਪਾਈ...
+Name[pl]=Drukuj...
+Name[pt]=Imprimir...
+Name[pt_BR]=Imprimir...
+Name[ro]=Tipăreşte...
+Name[ru]=Печать...
+Name[rw]=Gucapa...
+Name[se]=Čálit …
+Name[sk]=Tlač...
+Name[sl]=Natisni ...
+Name[sr]=Штампа...
+Name[sr@Latn]=Štampa...
+Name[sv]=Skriv ut...
+Name[ta]=அச்சடி...
+Name[te]=ప్రచురించు...
+Name[tg]=Чоп кардан...
+Name[th]=พิมพ์...
+Name[tr]=Yazdır...
+Name[tt]=Bastıru...
+Name[uk]=Друк...
+Name[uz]=Босиб чиқариш
+Name[vi]=In ấn...
+Name[zh_CN]=打印...
+Name[zh_TW]=列印...
+Exec=kprinter -t %n --caption %n --icon %i --miniicon %m %U
+Icon=filequickprint
diff --git a/src/servicemenus/text-c++-print.desktop b/src/servicemenus/text-c++-print.desktop
new file mode 100644
index 0000000..f34dee4
--- /dev/null
+++ b/src/servicemenus/text-c++-print.desktop
@@ -0,0 +1,76 @@
+[Desktop Entry]
+Encoding=UTF-8
+ServiceTypes=text/x-c++src
+Actions=Print;
+
+[Desktop Action Print]
+Name=Print...
+Name[af]=Druk...
+Name[ar]=طباعة...
+Name[az]=Çap et...
+Name[be]=Друкаваць...
+Name[bg]=Печат...
+Name[bn]=ছাপাও...
+Name[br]=Moulañ ...
+Name[bs]=Štampaj...
+Name[ca]=Imprimeix...
+Name[cs]=Tisknout...
+Name[csb]=Drëkùjë...
+Name[cy]=Argraffu...
+Name[da]=Udskriv...
+Name[de]=Drucken ...
+Name[el]=Εκτύπωση...
+Name[eo]=Printi...
+Name[es]=Imprimir...
+Name[et]=Trüki...
+Name[eu]=Inprimatu...
+Name[fa]=چاپ...
+Name[fi]=Tulosta...
+Name[fr]=Imprimer...
+Name[fy]=Printsje...
+Name[ga]=Priontáil...
+Name[gl]=Imprimir...
+Name[he]=הדפס...
+Name[hi]=छापें...
+Name[hr]=Ispiši...
+Name[hu]=Nyomtatás...
+Name[is]=Prenta...
+Name[it]=Stampa...
+Name[ja]=印刷...
+Name[kk]=Басып шығару...
+Name[km]=បោះពុម្ព...
+Name[lv]=Drukāt...
+Name[mk]=Печати...
+Name[ms]=Cetak...
+Name[mt]=Ipprintja...
+Name[nb]=Skriv ut...
+Name[nds]=Drucken...
+Name[ne]=मुद्रण...
+Name[nl]=Afdrukken...
+Name[nn]=Skriv ut ...
+Name[pa]=ਛਪਾਈ...
+Name[pl]=Drukuj...
+Name[pt]=Imprimir...
+Name[pt_BR]=Imprimir...
+Name[ro]=Tipăreşte...
+Name[ru]=Печать...
+Name[rw]=Gucapa...
+Name[se]=Čálit …
+Name[sk]=Tlač...
+Name[sl]=Natisni ...
+Name[sr]=Штампа...
+Name[sr@Latn]=Štampa...
+Name[sv]=Skriv ut...
+Name[ta]=அச்சடி...
+Name[te]=ప్రచురించు...
+Name[tg]=Чоп кардан...
+Name[th]=พิมพ์...
+Name[tr]=Yazdır...
+Name[tt]=Bastıru...
+Name[uk]=Друк...
+Name[uz]=Босиб чиқариш
+Name[vi]=In ấn...
+Name[zh_CN]=打印...
+Name[zh_TW]=列印...
+Exec=kprinter -t %n --caption %n --icon %i --miniicon %m %U
+Icon=filequickprint
diff --git a/src/servicemenus/text-c++h-print.desktop b/src/servicemenus/text-c++h-print.desktop
new file mode 100644
index 0000000..01a8bfc
--- /dev/null
+++ b/src/servicemenus/text-c++h-print.desktop
@@ -0,0 +1,76 @@
+[Desktop Entry]
+Encoding=UTF-8
+ServiceTypes=text/x-c++hdr
+Actions=Print;
+
+[Desktop Action Print]
+Name=Print...
+Name[af]=Druk...
+Name[ar]=طباعة...
+Name[az]=Çap et...
+Name[be]=Друкаваць...
+Name[bg]=Печат...
+Name[bn]=ছাপাও...
+Name[br]=Moulañ ...
+Name[bs]=Štampaj...
+Name[ca]=Imprimeix...
+Name[cs]=Tisknout...
+Name[csb]=Drëkùjë...
+Name[cy]=Argraffu...
+Name[da]=Udskriv...
+Name[de]=Drucken ...
+Name[el]=Εκτύπωση...
+Name[eo]=Printi...
+Name[es]=Imprimir...
+Name[et]=Trüki...
+Name[eu]=Inprimatu...
+Name[fa]=چاپ...
+Name[fi]=Tulosta...
+Name[fr]=Imprimer...
+Name[fy]=Printsje...
+Name[ga]=Priontáil...
+Name[gl]=Imprimir...
+Name[he]=הדפס...
+Name[hi]=छापें...
+Name[hr]=Ispiši...
+Name[hu]=Nyomtatás...
+Name[is]=Prenta...
+Name[it]=Stampa...
+Name[ja]=印刷...
+Name[kk]=Басып шығару...
+Name[km]=បោះពុម្ព...
+Name[lv]=Drukāt...
+Name[mk]=Печати...
+Name[ms]=Cetak...
+Name[mt]=Ipprintja...
+Name[nb]=Skriv ut...
+Name[nds]=Drucken...
+Name[ne]=मुद्रण...
+Name[nl]=Afdrukken...
+Name[nn]=Skriv ut ...
+Name[pa]=ਛਪਾਈ...
+Name[pl]=Drukuj...
+Name[pt]=Imprimir...
+Name[pt_BR]=Imprimir...
+Name[ro]=Tipăreşte...
+Name[ru]=Печать...
+Name[rw]=Gucapa...
+Name[se]=Čálit …
+Name[sk]=Tlač...
+Name[sl]=Natisni ...
+Name[sr]=Штампа...
+Name[sr@Latn]=Štampa...
+Name[sv]=Skriv ut...
+Name[ta]=அச்சடி...
+Name[te]=ప్రచురించు...
+Name[tg]=Чоп кардан...
+Name[th]=พิมพ์...
+Name[tr]=Yazdır...
+Name[tt]=Bastıru...
+Name[uk]=Друк...
+Name[uz]=Босиб чиқариш
+Name[vi]=In ấn...
+Name[zh_CN]=打印...
+Name[zh_TW]=列印...
+Exec=kprinter -t %n --caption %n --icon %i --miniicon %m %U
+Icon=filequickprint
diff --git a/src/servicemenus/text-ch-print.desktop b/src/servicemenus/text-ch-print.desktop
new file mode 100644
index 0000000..cd3f587
--- /dev/null
+++ b/src/servicemenus/text-ch-print.desktop
@@ -0,0 +1,76 @@
+[Desktop Entry]
+Encoding=UTF-8
+ServiceTypes=text/x-chdr
+Actions=Print;
+
+[Desktop Action Print]
+Name=Print...
+Name[af]=Druk...
+Name[ar]=طباعة...
+Name[az]=Çap et...
+Name[be]=Друкаваць...
+Name[bg]=Печат...
+Name[bn]=ছাপাও...
+Name[br]=Moulañ ...
+Name[bs]=Štampaj...
+Name[ca]=Imprimeix...
+Name[cs]=Tisknout...
+Name[csb]=Drëkùjë...
+Name[cy]=Argraffu...
+Name[da]=Udskriv...
+Name[de]=Drucken ...
+Name[el]=Εκτύπωση...
+Name[eo]=Printi...
+Name[es]=Imprimir...
+Name[et]=Trüki...
+Name[eu]=Inprimatu...
+Name[fa]=چاپ...
+Name[fi]=Tulosta...
+Name[fr]=Imprimer...
+Name[fy]=Printsje...
+Name[ga]=Priontáil...
+Name[gl]=Imprimir...
+Name[he]=הדפס...
+Name[hi]=छापें...
+Name[hr]=Ispiši...
+Name[hu]=Nyomtatás...
+Name[is]=Prenta...
+Name[it]=Stampa...
+Name[ja]=印刷...
+Name[kk]=Басып шығару...
+Name[km]=បោះពុម្ព...
+Name[lv]=Drukāt...
+Name[mk]=Печати...
+Name[ms]=Cetak...
+Name[mt]=Ipprintja...
+Name[nb]=Skriv ut...
+Name[nds]=Drucken...
+Name[ne]=मुद्रण...
+Name[nl]=Afdrukken...
+Name[nn]=Skriv ut ...
+Name[pa]=ਛਪਾਈ...
+Name[pl]=Drukuj...
+Name[pt]=Imprimir...
+Name[pt_BR]=Imprimir...
+Name[ro]=Tipăreşte...
+Name[ru]=Печать...
+Name[rw]=Gucapa...
+Name[se]=Čálit …
+Name[sk]=Tlač...
+Name[sl]=Natisni ...
+Name[sr]=Штампа...
+Name[sr@Latn]=Štampa...
+Name[sv]=Skriv ut...
+Name[ta]=அச்சடி...
+Name[te]=ప్రచురించు...
+Name[tg]=Чоп кардан...
+Name[th]=พิมพ์...
+Name[tr]=Yazdır...
+Name[tt]=Bastıru...
+Name[uk]=Друк...
+Name[uz]=Босиб чиқариш
+Name[vi]=In ấn...
+Name[zh_CN]=打印...
+Name[zh_TW]=列印...
+Exec=kprinter -t %n --caption %n --icon %i --miniicon %m %U
+Icon=filequickprint
diff --git a/src/servicemenus/text-css-print.desktop b/src/servicemenus/text-css-print.desktop
new file mode 100644
index 0000000..3659747
--- /dev/null
+++ b/src/servicemenus/text-css-print.desktop
@@ -0,0 +1,76 @@
+[Desktop Entry]
+Encoding=UTF-8
+ServiceTypes=text/css
+Actions=Print;
+
+[Desktop Action Print]
+Name=Print...
+Name[af]=Druk...
+Name[ar]=طباعة...
+Name[az]=Çap et...
+Name[be]=Друкаваць...
+Name[bg]=Печат...
+Name[bn]=ছাপাও...
+Name[br]=Moulañ ...
+Name[bs]=Štampaj...
+Name[ca]=Imprimeix...
+Name[cs]=Tisknout...
+Name[csb]=Drëkùjë...
+Name[cy]=Argraffu...
+Name[da]=Udskriv...
+Name[de]=Drucken ...
+Name[el]=Εκτύπωση...
+Name[eo]=Printi...
+Name[es]=Imprimir...
+Name[et]=Trüki...
+Name[eu]=Inprimatu...
+Name[fa]=چاپ...
+Name[fi]=Tulosta...
+Name[fr]=Imprimer...
+Name[fy]=Printsje...
+Name[ga]=Priontáil...
+Name[gl]=Imprimir...
+Name[he]=הדפס...
+Name[hi]=छापें...
+Name[hr]=Ispiši...
+Name[hu]=Nyomtatás...
+Name[is]=Prenta...
+Name[it]=Stampa...
+Name[ja]=印刷...
+Name[kk]=Басып шығару...
+Name[km]=បោះពុម្ព...
+Name[lv]=Drukāt...
+Name[mk]=Печати...
+Name[ms]=Cetak...
+Name[mt]=Ipprintja...
+Name[nb]=Skriv ut...
+Name[nds]=Drucken...
+Name[ne]=मुद्रण...
+Name[nl]=Afdrukken...
+Name[nn]=Skriv ut ...
+Name[pa]=ਛਪਾਈ...
+Name[pl]=Drukuj...
+Name[pt]=Imprimir...
+Name[pt_BR]=Imprimir...
+Name[ro]=Tipăreşte...
+Name[ru]=Печать...
+Name[rw]=Gucapa...
+Name[se]=Čálit …
+Name[sk]=Tlač...
+Name[sl]=Natisni ...
+Name[sr]=Штампа...
+Name[sr@Latn]=Štampa...
+Name[sv]=Skriv ut...
+Name[ta]=அச்சடி...
+Name[te]=ప్రచురించు...
+Name[tg]=Чоп кардан...
+Name[th]=พิมพ์...
+Name[tr]=Yazdır...
+Name[tt]=Bastıru...
+Name[uk]=Друк...
+Name[uz]=Босиб чиқариш
+Name[vi]=In ấn...
+Name[zh_CN]=打印...
+Name[zh_TW]=列印...
+Exec=kprinter -t %n --caption %n --icon %i --miniicon %m %U
+Icon=filequickprint
diff --git a/src/servicemenus/text-diff-print.desktop b/src/servicemenus/text-diff-print.desktop
new file mode 100644
index 0000000..a0c39f0
--- /dev/null
+++ b/src/servicemenus/text-diff-print.desktop
@@ -0,0 +1,76 @@
+[Desktop Entry]
+Encoding=UTF-8
+ServiceTypes=text/x-diff
+Actions=Print;
+
+[Desktop Action Print]
+Name=Print...
+Name[af]=Druk...
+Name[ar]=طباعة...
+Name[az]=Çap et...
+Name[be]=Друкаваць...
+Name[bg]=Печат...
+Name[bn]=ছাপাও...
+Name[br]=Moulañ ...
+Name[bs]=Štampaj...
+Name[ca]=Imprimeix...
+Name[cs]=Tisknout...
+Name[csb]=Drëkùjë...
+Name[cy]=Argraffu...
+Name[da]=Udskriv...
+Name[de]=Drucken ...
+Name[el]=Εκτύπωση...
+Name[eo]=Printi...
+Name[es]=Imprimir...
+Name[et]=Trüki...
+Name[eu]=Inprimatu...
+Name[fa]=چاپ...
+Name[fi]=Tulosta...
+Name[fr]=Imprimer...
+Name[fy]=Printsje...
+Name[ga]=Priontáil...
+Name[gl]=Imprimir...
+Name[he]=הדפס...
+Name[hi]=छापें...
+Name[hr]=Ispiši...
+Name[hu]=Nyomtatás...
+Name[is]=Prenta...
+Name[it]=Stampa...
+Name[ja]=印刷...
+Name[kk]=Басып шығару...
+Name[km]=បោះពុម្ព...
+Name[lv]=Drukāt...
+Name[mk]=Печати...
+Name[ms]=Cetak...
+Name[mt]=Ipprintja...
+Name[nb]=Skriv ut...
+Name[nds]=Drucken...
+Name[ne]=मुद्रण...
+Name[nl]=Afdrukken...
+Name[nn]=Skriv ut ...
+Name[pa]=ਛਪਾਈ...
+Name[pl]=Drukuj...
+Name[pt]=Imprimir...
+Name[pt_BR]=Imprimir...
+Name[ro]=Tipăreşte...
+Name[ru]=Печать...
+Name[rw]=Gucapa...
+Name[se]=Čálit …
+Name[sk]=Tlač...
+Name[sl]=Natisni ...
+Name[sr]=Штампа...
+Name[sr@Latn]=Štampa...
+Name[sv]=Skriv ut...
+Name[ta]=அச்சடி...
+Name[te]=ప్రచురించు...
+Name[tg]=Чоп кардан...
+Name[th]=พิมพ์...
+Name[tr]=Yazdır...
+Name[tt]=Bastıru...
+Name[uk]=Друк...
+Name[uz]=Босиб чиқариш
+Name[vi]=In ấn...
+Name[zh_CN]=打印...
+Name[zh_TW]=列印...
+Exec=kprinter -t %n --caption %n --icon %i --miniicon %m %U
+Icon=filequickprint
diff --git a/src/servicemenus/text-html-print.desktop b/src/servicemenus/text-html-print.desktop
new file mode 100644
index 0000000..edf95e6
--- /dev/null
+++ b/src/servicemenus/text-html-print.desktop
@@ -0,0 +1,76 @@
+[Desktop Entry]
+Encoding=UTF-8
+ServiceTypes=text/html
+Actions=Print;
+
+[Desktop Action Print]
+Name=Print...
+Name[af]=Druk...
+Name[ar]=طباعة...
+Name[az]=Çap et...
+Name[be]=Друкаваць...
+Name[bg]=Печат...
+Name[bn]=ছাপাও...
+Name[br]=Moulañ ...
+Name[bs]=Štampaj...
+Name[ca]=Imprimeix...
+Name[cs]=Tisknout...
+Name[csb]=Drëkùjë...
+Name[cy]=Argraffu...
+Name[da]=Udskriv...
+Name[de]=Drucken ...
+Name[el]=Εκτύπωση...
+Name[eo]=Printi...
+Name[es]=Imprimir...
+Name[et]=Trüki...
+Name[eu]=Inprimatu...
+Name[fa]=چاپ...
+Name[fi]=Tulosta...
+Name[fr]=Imprimer...
+Name[fy]=Printsje...
+Name[ga]=Priontáil...
+Name[gl]=Imprimir...
+Name[he]=הדפס...
+Name[hi]=छापें...
+Name[hr]=Ispiši...
+Name[hu]=Nyomtatás...
+Name[is]=Prenta...
+Name[it]=Stampa...
+Name[ja]=印刷...
+Name[kk]=Басып шығару...
+Name[km]=បោះពុម្ព...
+Name[lv]=Drukāt...
+Name[mk]=Печати...
+Name[ms]=Cetak...
+Name[mt]=Ipprintja...
+Name[nb]=Skriv ut...
+Name[nds]=Drucken...
+Name[ne]=मुद्रण...
+Name[nl]=Afdrukken...
+Name[nn]=Skriv ut ...
+Name[pa]=ਛਪਾਈ...
+Name[pl]=Drukuj...
+Name[pt]=Imprimir...
+Name[pt_BR]=Imprimir...
+Name[ro]=Tipăreşte...
+Name[ru]=Печать...
+Name[rw]=Gucapa...
+Name[se]=Čálit …
+Name[sk]=Tlač...
+Name[sl]=Natisni ...
+Name[sr]=Штампа...
+Name[sr@Latn]=Štampa...
+Name[sv]=Skriv ut...
+Name[ta]=அச்சடி...
+Name[te]=ప్రచురించు...
+Name[tg]=Чоп кардан...
+Name[th]=พิมพ์...
+Name[tr]=Yazdır...
+Name[tt]=Bastıru...
+Name[uk]=Друк...
+Name[uz]=Босиб чиқариш
+Name[vi]=In ấn...
+Name[zh_CN]=打印...
+Name[zh_TW]=列印...
+Exec=kprinter -t %n --caption %n --icon %i --miniicon %m %U
+Icon=filequickprint
diff --git a/src/servicemenus/text-java-print.desktop b/src/servicemenus/text-java-print.desktop
new file mode 100644
index 0000000..96dd0d6
--- /dev/null
+++ b/src/servicemenus/text-java-print.desktop
@@ -0,0 +1,76 @@
+[Desktop Entry]
+Encoding=UTF-8
+ServiceTypes=text/x-java
+Actions=Print;
+
+[Desktop Action Print]
+Name=Print...
+Name[af]=Druk...
+Name[ar]=طباعة...
+Name[az]=Çap et...
+Name[be]=Друкаваць...
+Name[bg]=Печат...
+Name[bn]=ছাপাও...
+Name[br]=Moulañ ...
+Name[bs]=Štampaj...
+Name[ca]=Imprimeix...
+Name[cs]=Tisknout...
+Name[csb]=Drëkùjë...
+Name[cy]=Argraffu...
+Name[da]=Udskriv...
+Name[de]=Drucken ...
+Name[el]=Εκτύπωση...
+Name[eo]=Printi...
+Name[es]=Imprimir...
+Name[et]=Trüki...
+Name[eu]=Inprimatu...
+Name[fa]=چاپ...
+Name[fi]=Tulosta...
+Name[fr]=Imprimer...
+Name[fy]=Printsje...
+Name[ga]=Priontáil...
+Name[gl]=Imprimir...
+Name[he]=הדפס...
+Name[hi]=छापें...
+Name[hr]=Ispiši...
+Name[hu]=Nyomtatás...
+Name[is]=Prenta...
+Name[it]=Stampa...
+Name[ja]=印刷...
+Name[kk]=Басып шығару...
+Name[km]=បោះពុម្ព...
+Name[lv]=Drukāt...
+Name[mk]=Печати...
+Name[ms]=Cetak...
+Name[mt]=Ipprintja...
+Name[nb]=Skriv ut...
+Name[nds]=Drucken...
+Name[ne]=मुद्रण...
+Name[nl]=Afdrukken...
+Name[nn]=Skriv ut ...
+Name[pa]=ਛਪਾਈ...
+Name[pl]=Drukuj...
+Name[pt]=Imprimir...
+Name[pt_BR]=Imprimir...
+Name[ro]=Tipăreşte...
+Name[ru]=Печать...
+Name[rw]=Gucapa...
+Name[se]=Čálit …
+Name[sk]=Tlač...
+Name[sl]=Natisni ...
+Name[sr]=Штампа...
+Name[sr@Latn]=Štampa...
+Name[sv]=Skriv ut...
+Name[ta]=அச்சடி...
+Name[te]=ప్రచురించు...
+Name[tg]=Чоп кардан...
+Name[th]=พิมพ์...
+Name[tr]=Yazdır...
+Name[tt]=Bastıru...
+Name[uk]=Друк...
+Name[uz]=Босиб чиқариш
+Name[vi]=In ấn...
+Name[zh_CN]=打印...
+Name[zh_TW]=列印...
+Exec=kprinter -t %n --caption %n --icon %i --miniicon %m %U
+Icon=filequickprint
diff --git a/src/servicemenus/text-log-print.desktop b/src/servicemenus/text-log-print.desktop
new file mode 100644
index 0000000..ad44325
--- /dev/null
+++ b/src/servicemenus/text-log-print.desktop
@@ -0,0 +1,76 @@
+[Desktop Entry]
+Encoding=UTF-8
+ServiceTypes=text/x-log
+Actions=Print;
+
+[Desktop Action Print]
+Name=Print...
+Name[af]=Druk...
+Name[ar]=طباعة...
+Name[az]=Çap et...
+Name[be]=Друкаваць...
+Name[bg]=Печат...
+Name[bn]=ছাপাও...
+Name[br]=Moulañ ...
+Name[bs]=Štampaj...
+Name[ca]=Imprimeix...
+Name[cs]=Tisknout...
+Name[csb]=Drëkùjë...
+Name[cy]=Argraffu...
+Name[da]=Udskriv...
+Name[de]=Drucken ...
+Name[el]=Εκτύπωση...
+Name[eo]=Printi...
+Name[es]=Imprimir...
+Name[et]=Trüki...
+Name[eu]=Inprimatu...
+Name[fa]=چاپ...
+Name[fi]=Tulosta...
+Name[fr]=Imprimer...
+Name[fy]=Printsje...
+Name[ga]=Priontáil...
+Name[gl]=Imprimir...
+Name[he]=הדפס...
+Name[hi]=छापें...
+Name[hr]=Ispiši...
+Name[hu]=Nyomtatás...
+Name[is]=Prenta...
+Name[it]=Stampa...
+Name[ja]=印刷...
+Name[kk]=Басып шығару...
+Name[km]=បោះពុម្ព...
+Name[lv]=Drukāt...
+Name[mk]=Печати...
+Name[ms]=Cetak...
+Name[mt]=Ipprintja...
+Name[nb]=Skriv ut...
+Name[nds]=Drucken...
+Name[ne]=मुद्रण...
+Name[nl]=Afdrukken...
+Name[nn]=Skriv ut ...
+Name[pa]=ਛਪਾਈ...
+Name[pl]=Drukuj...
+Name[pt]=Imprimir...
+Name[pt_BR]=Imprimir...
+Name[ro]=Tipăreşte...
+Name[ru]=Печать...
+Name[rw]=Gucapa...
+Name[se]=Čálit …
+Name[sk]=Tlač...
+Name[sl]=Natisni ...
+Name[sr]=Штампа...
+Name[sr@Latn]=Štampa...
+Name[sv]=Skriv ut...
+Name[ta]=அச்சடி...
+Name[te]=ప్రచురించు...
+Name[tg]=Чоп кардан...
+Name[th]=พิมพ์...
+Name[tr]=Yazdır...
+Name[tt]=Bastıru...
+Name[uk]=Друк...
+Name[uz]=Босиб чиқариш
+Name[vi]=In ấn...
+Name[zh_CN]=打印...
+Name[zh_TW]=列印...
+Exec=kprinter -t %n --caption %n --icon %i --miniicon %m %U
+Icon=filequickprint
diff --git a/src/servicemenus/text-makefile-print.desktop b/src/servicemenus/text-makefile-print.desktop
new file mode 100644
index 0000000..4f2d679
--- /dev/null
+++ b/src/servicemenus/text-makefile-print.desktop
@@ -0,0 +1,76 @@
+[Desktop Entry]
+Encoding=UTF-8
+ServiceTypes=text/x-makefile
+Actions=Print;
+
+[Desktop Action Print]
+Name=Print...
+Name[af]=Druk...
+Name[ar]=طباعة...
+Name[az]=Çap et...
+Name[be]=Друкаваць...
+Name[bg]=Печат...
+Name[bn]=ছাপাও...
+Name[br]=Moulañ ...
+Name[bs]=Štampaj...
+Name[ca]=Imprimeix...
+Name[cs]=Tisknout...
+Name[csb]=Drëkùjë...
+Name[cy]=Argraffu...
+Name[da]=Udskriv...
+Name[de]=Drucken ...
+Name[el]=Εκτύπωση...
+Name[eo]=Printi...
+Name[es]=Imprimir...
+Name[et]=Trüki...
+Name[eu]=Inprimatu...
+Name[fa]=چاپ...
+Name[fi]=Tulosta...
+Name[fr]=Imprimer...
+Name[fy]=Printsje...
+Name[ga]=Priontáil...
+Name[gl]=Imprimir...
+Name[he]=הדפס...
+Name[hi]=छापें...
+Name[hr]=Ispiši...
+Name[hu]=Nyomtatás...
+Name[is]=Prenta...
+Name[it]=Stampa...
+Name[ja]=印刷...
+Name[kk]=Басып шығару...
+Name[km]=បោះពុម្ព...
+Name[lv]=Drukāt...
+Name[mk]=Печати...
+Name[ms]=Cetak...
+Name[mt]=Ipprintja...
+Name[nb]=Skriv ut...
+Name[nds]=Drucken...
+Name[ne]=मुद्रण...
+Name[nl]=Afdrukken...
+Name[nn]=Skriv ut ...
+Name[pa]=ਛਪਾਈ...
+Name[pl]=Drukuj...
+Name[pt]=Imprimir...
+Name[pt_BR]=Imprimir...
+Name[ro]=Tipăreşte...
+Name[ru]=Печать...
+Name[rw]=Gucapa...
+Name[se]=Čálit …
+Name[sk]=Tlač...
+Name[sl]=Natisni ...
+Name[sr]=Штампа...
+Name[sr@Latn]=Štampa...
+Name[sv]=Skriv ut...
+Name[ta]=அச்சடி...
+Name[te]=ప్రచురించు...
+Name[tg]=Чоп кардан...
+Name[th]=พิมพ์...
+Name[tr]=Yazdır...
+Name[tt]=Bastıru...
+Name[uk]=Друк...
+Name[uz]=Босиб чиқариш
+Name[vi]=In ấn...
+Name[zh_CN]=打印...
+Name[zh_TW]=列印...
+Exec=kprinter -t %n --caption %n --icon %i --miniicon %m %U
+Icon=filequickprint
diff --git a/src/servicemenus/text-pas-print.desktop b/src/servicemenus/text-pas-print.desktop
new file mode 100644
index 0000000..e9e303b
--- /dev/null
+++ b/src/servicemenus/text-pas-print.desktop
@@ -0,0 +1,76 @@
+[Desktop Entry]
+Encoding=UTF-8
+ServiceTypes=text/x-pascal
+Actions=Print;
+
+[Desktop Action Print]
+Name=Print...
+Name[af]=Druk...
+Name[ar]=طباعة...
+Name[az]=Çap et...
+Name[be]=Друкаваць...
+Name[bg]=Печат...
+Name[bn]=ছাপাও...
+Name[br]=Moulañ ...
+Name[bs]=Štampaj...
+Name[ca]=Imprimeix...
+Name[cs]=Tisknout...
+Name[csb]=Drëkùjë...
+Name[cy]=Argraffu...
+Name[da]=Udskriv...
+Name[de]=Drucken ...
+Name[el]=Εκτύπωση...
+Name[eo]=Printi...
+Name[es]=Imprimir...
+Name[et]=Trüki...
+Name[eu]=Inprimatu...
+Name[fa]=چاپ...
+Name[fi]=Tulosta...
+Name[fr]=Imprimer...
+Name[fy]=Printsje...
+Name[ga]=Priontáil...
+Name[gl]=Imprimir...
+Name[he]=הדפס...
+Name[hi]=छापें...
+Name[hr]=Ispiši...
+Name[hu]=Nyomtatás...
+Name[is]=Prenta...
+Name[it]=Stampa...
+Name[ja]=印刷...
+Name[kk]=Басып шығару...
+Name[km]=បោះពុម្ព...
+Name[lv]=Drukāt...
+Name[mk]=Печати...
+Name[ms]=Cetak...
+Name[mt]=Ipprintja...
+Name[nb]=Skriv ut...
+Name[nds]=Drucken...
+Name[ne]=मुद्रण...
+Name[nl]=Afdrukken...
+Name[nn]=Skriv ut ...
+Name[pa]=ਛਪਾਈ...
+Name[pl]=Drukuj...
+Name[pt]=Imprimir...
+Name[pt_BR]=Imprimir...
+Name[ro]=Tipăreşte...
+Name[ru]=Печать...
+Name[rw]=Gucapa...
+Name[se]=Čálit …
+Name[sk]=Tlač...
+Name[sl]=Natisni ...
+Name[sr]=Штампа...
+Name[sr@Latn]=Štampa...
+Name[sv]=Skriv ut...
+Name[ta]=அச்சடி...
+Name[te]=ప్రచురించు...
+Name[tg]=Чоп кардан...
+Name[th]=พิมพ์...
+Name[tr]=Yazdır...
+Name[tt]=Bastıru...
+Name[uk]=Друк...
+Name[uz]=Босиб чиқариш
+Name[vi]=In ấn...
+Name[zh_CN]=打印...
+Name[zh_TW]=列印...
+Exec=kprinter -t %n --caption %n --icon %i --miniicon %m %U
+Icon=filequickprint
diff --git a/src/servicemenus/text-perl-print.desktop b/src/servicemenus/text-perl-print.desktop
new file mode 100644
index 0000000..effdc4a
--- /dev/null
+++ b/src/servicemenus/text-perl-print.desktop
@@ -0,0 +1,76 @@
+[Desktop Entry]
+Encoding=UTF-8
+ServiceTypes=text/x-perl
+Actions=Print;
+
+[Desktop Action Print]
+Name=Print...
+Name[af]=Druk...
+Name[ar]=طباعة...
+Name[az]=Çap et...
+Name[be]=Друкаваць...
+Name[bg]=Печат...
+Name[bn]=ছাপাও...
+Name[br]=Moulañ ...
+Name[bs]=Štampaj...
+Name[ca]=Imprimeix...
+Name[cs]=Tisknout...
+Name[csb]=Drëkùjë...
+Name[cy]=Argraffu...
+Name[da]=Udskriv...
+Name[de]=Drucken ...
+Name[el]=Εκτύπωση...
+Name[eo]=Printi...
+Name[es]=Imprimir...
+Name[et]=Trüki...
+Name[eu]=Inprimatu...
+Name[fa]=چاپ...
+Name[fi]=Tulosta...
+Name[fr]=Imprimer...
+Name[fy]=Printsje...
+Name[ga]=Priontáil...
+Name[gl]=Imprimir...
+Name[he]=הדפס...
+Name[hi]=छापें...
+Name[hr]=Ispiši...
+Name[hu]=Nyomtatás...
+Name[is]=Prenta...
+Name[it]=Stampa...
+Name[ja]=印刷...
+Name[kk]=Басып шығару...
+Name[km]=បោះពុម្ព...
+Name[lv]=Drukāt...
+Name[mk]=Печати...
+Name[ms]=Cetak...
+Name[mt]=Ipprintja...
+Name[nb]=Skriv ut...
+Name[nds]=Drucken...
+Name[ne]=मुद्रण...
+Name[nl]=Afdrukken...
+Name[nn]=Skriv ut ...
+Name[pa]=ਛਪਾਈ...
+Name[pl]=Drukuj...
+Name[pt]=Imprimir...
+Name[pt_BR]=Imprimir...
+Name[ro]=Tipăreşte...
+Name[ru]=Печать...
+Name[rw]=Gucapa...
+Name[se]=Čálit …
+Name[sk]=Tlač...
+Name[sl]=Natisni ...
+Name[sr]=Штампа...
+Name[sr@Latn]=Štampa...
+Name[sv]=Skriv ut...
+Name[ta]=அச்சடி...
+Name[te]=ప్రచురించు...
+Name[tg]=Чоп кардан...
+Name[th]=พิมพ์...
+Name[tr]=Yazdır...
+Name[tt]=Bastıru...
+Name[uk]=Друк...
+Name[uz]=Босиб чиқариш
+Name[vi]=In ấn...
+Name[zh_CN]=打印...
+Name[zh_TW]=列印...
+Exec=kprinter -t %n --caption %n --icon %i --miniicon %m %U
+Icon=filequickprint
diff --git a/src/servicemenus/text-print.desktop b/src/servicemenus/text-print.desktop
new file mode 100644
index 0000000..2b72284
--- /dev/null
+++ b/src/servicemenus/text-print.desktop
@@ -0,0 +1,76 @@
+[Desktop Entry]
+Encoding=UTF-8
+ServiceTypes=text/plain
+Actions=Print;
+
+[Desktop Action Print]
+Name=Print...
+Name[af]=Druk...
+Name[ar]=طباعة...
+Name[az]=Çap et...
+Name[be]=Друкаваць...
+Name[bg]=Печат...
+Name[bn]=ছাপাও...
+Name[br]=Moulañ ...
+Name[bs]=Štampaj...
+Name[ca]=Imprimeix...
+Name[cs]=Tisknout...
+Name[csb]=Drëkùjë...
+Name[cy]=Argraffu...
+Name[da]=Udskriv...
+Name[de]=Drucken ...
+Name[el]=Εκτύπωση...
+Name[eo]=Printi...
+Name[es]=Imprimir...
+Name[et]=Trüki...
+Name[eu]=Inprimatu...
+Name[fa]=چاپ...
+Name[fi]=Tulosta...
+Name[fr]=Imprimer...
+Name[fy]=Printsje...
+Name[ga]=Priontáil...
+Name[gl]=Imprimir...
+Name[he]=הדפס...
+Name[hi]=छापें...
+Name[hr]=Ispiši...
+Name[hu]=Nyomtatás...
+Name[is]=Prenta...
+Name[it]=Stampa...
+Name[ja]=印刷...
+Name[kk]=Басып шығару...
+Name[km]=បោះពុម្ព...
+Name[lv]=Drukāt...
+Name[mk]=Печати...
+Name[ms]=Cetak...
+Name[mt]=Ipprintja...
+Name[nb]=Skriv ut...
+Name[nds]=Drucken...
+Name[ne]=मुद्रण...
+Name[nl]=Afdrukken...
+Name[nn]=Skriv ut ...
+Name[pa]=ਛਪਾਈ...
+Name[pl]=Drukuj...
+Name[pt]=Imprimir...
+Name[pt_BR]=Imprimir...
+Name[ro]=Tipăreşte...
+Name[ru]=Печать...
+Name[rw]=Gucapa...
+Name[se]=Čálit …
+Name[sk]=Tlač...
+Name[sl]=Natisni ...
+Name[sr]=Штампа...
+Name[sr@Latn]=Štampa...
+Name[sv]=Skriv ut...
+Name[ta]=அச்சடி...
+Name[te]=ప్రచురించు...
+Name[tg]=Чоп кардан...
+Name[th]=พิมพ์...
+Name[tr]=Yazdır...
+Name[tt]=Bastıru...
+Name[uk]=Друк...
+Name[uz]=Босиб чиқариш
+Name[vi]=In ấn...
+Name[zh_CN]=打印...
+Name[zh_TW]=列印...
+Exec=kprinter -t %n --caption %n --icon %i --miniicon %m %U
+Icon=filequickprint
diff --git a/src/servicemenus/text-python-print.desktop b/src/servicemenus/text-python-print.desktop
new file mode 100644
index 0000000..660f5de
--- /dev/null
+++ b/src/servicemenus/text-python-print.desktop
@@ -0,0 +1,76 @@
+[Desktop Entry]
+Encoding=UTF-8
+ServiceTypes=text/x-python
+Actions=Print;
+
+[Desktop Action Print]
+Name=Print...
+Name[af]=Druk...
+Name[ar]=طباعة...
+Name[az]=Çap et...
+Name[be]=Друкаваць...
+Name[bg]=Печат...
+Name[bn]=ছাপাও...
+Name[br]=Moulañ ...
+Name[bs]=Štampaj...
+Name[ca]=Imprimeix...
+Name[cs]=Tisknout...
+Name[csb]=Drëkùjë...
+Name[cy]=Argraffu...
+Name[da]=Udskriv...
+Name[de]=Drucken ...
+Name[el]=Εκτύπωση...
+Name[eo]=Printi...
+Name[es]=Imprimir...
+Name[et]=Trüki...
+Name[eu]=Inprimatu...
+Name[fa]=چاپ...
+Name[fi]=Tulosta...
+Name[fr]=Imprimer...
+Name[fy]=Printsje...
+Name[ga]=Priontáil...
+Name[gl]=Imprimir...
+Name[he]=הדפס...
+Name[hi]=छापें...
+Name[hr]=Ispiši...
+Name[hu]=Nyomtatás...
+Name[is]=Prenta...
+Name[it]=Stampa...
+Name[ja]=印刷...
+Name[kk]=Басып шығару...
+Name[km]=បោះពុម្ព...
+Name[lv]=Drukāt...
+Name[mk]=Печати...
+Name[ms]=Cetak...
+Name[mt]=Ipprintja...
+Name[nb]=Skriv ut...
+Name[nds]=Drucken...
+Name[ne]=मुद्रण...
+Name[nl]=Afdrukken...
+Name[nn]=Skriv ut ...
+Name[pa]=ਛਪਾਈ...
+Name[pl]=Drukuj...
+Name[pt]=Imprimir...
+Name[pt_BR]=Imprimir...
+Name[ro]=Tipăreşte...
+Name[ru]=Печать...
+Name[rw]=Gucapa...
+Name[se]=Čálit …
+Name[sk]=Tlač...
+Name[sl]=Natisni ...
+Name[sr]=Штампа...
+Name[sr@Latn]=Štampa...
+Name[sv]=Skriv ut...
+Name[ta]=அச்சடி...
+Name[te]=ప్రచురించు...
+Name[tg]=Чоп кардан...
+Name[th]=พิมพ์...
+Name[tr]=Yazdır...
+Name[tt]=Bastıru...
+Name[uk]=Друк...
+Name[uz]=Босиб чиқариш
+Name[vi]=In ấn...
+Name[zh_CN]=打印...
+Name[zh_TW]=列印...
+Exec=kprinter -t %n --caption %n --icon %i --miniicon %m %U
+Icon=filequickprint
diff --git a/src/servicemenus/text-tcl-print.desktop b/src/servicemenus/text-tcl-print.desktop
new file mode 100644
index 0000000..ce786d1
--- /dev/null
+++ b/src/servicemenus/text-tcl-print.desktop
@@ -0,0 +1,76 @@
+[Desktop Entry]
+Encoding=UTF-8
+ServiceTypes=text/x-tcl
+Actions=Print;
+
+[Desktop Action Print]
+Name=Print...
+Name[af]=Druk...
+Name[ar]=طباعة...
+Name[az]=Çap et...
+Name[be]=Друкаваць...
+Name[bg]=Печат...
+Name[bn]=ছাপাও...
+Name[br]=Moulañ ...
+Name[bs]=Štampaj...
+Name[ca]=Imprimeix...
+Name[cs]=Tisknout...
+Name[csb]=Drëkùjë...
+Name[cy]=Argraffu...
+Name[da]=Udskriv...
+Name[de]=Drucken ...
+Name[el]=Εκτύπωση...
+Name[eo]=Printi...
+Name[es]=Imprimir...
+Name[et]=Trüki...
+Name[eu]=Inprimatu...
+Name[fa]=چاپ...
+Name[fi]=Tulosta...
+Name[fr]=Imprimer...
+Name[fy]=Printsje...
+Name[ga]=Priontáil...
+Name[gl]=Imprimir...
+Name[he]=הדפס...
+Name[hi]=छापें...
+Name[hr]=Ispiši...
+Name[hu]=Nyomtatás...
+Name[is]=Prenta...
+Name[it]=Stampa...
+Name[ja]=印刷...
+Name[kk]=Басып шығару...
+Name[km]=បោះពុម្ព...
+Name[lv]=Drukāt...
+Name[mk]=Печати...
+Name[ms]=Cetak...
+Name[mt]=Ipprintja...
+Name[nb]=Skriv ut...
+Name[nds]=Drucken...
+Name[ne]=मुद्रण...
+Name[nl]=Afdrukken...
+Name[nn]=Skriv ut ...
+Name[pa]=ਛਪਾਈ...
+Name[pl]=Drukuj...
+Name[pt]=Imprimir...
+Name[pt_BR]=Imprimir...
+Name[ro]=Tipăreşte...
+Name[ru]=Печать...
+Name[rw]=Gucapa...
+Name[se]=Čálit …
+Name[sk]=Tlač...
+Name[sl]=Natisni ...
+Name[sr]=Штампа...
+Name[sr@Latn]=Štampa...
+Name[sv]=Skriv ut...
+Name[ta]=அச்சடி...
+Name[te]=ప్రచురించు...
+Name[tg]=Чоп кардан...
+Name[th]=พิมพ์...
+Name[tr]=Yazdır...
+Name[tt]=Bastıru...
+Name[uk]=Друк...
+Name[uz]=Босиб чиқариш
+Name[vi]=In ấn...
+Name[zh_CN]=打印...
+Name[zh_TW]=列印...
+Exec=kprinter -t %n --caption %n --icon %i --miniicon %m %U
+Icon=filequickprint
diff --git a/src/servicemenus/text-tex-print.desktop b/src/servicemenus/text-tex-print.desktop
new file mode 100644
index 0000000..32e9c3c
--- /dev/null
+++ b/src/servicemenus/text-tex-print.desktop
@@ -0,0 +1,76 @@
+[Desktop Entry]
+Encoding=UTF-8
+ServiceTypes=text/x-tex
+Actions=Print;
+
+[Desktop Action Print]
+Name=Print...
+Name[af]=Druk...
+Name[ar]=طباعة...
+Name[az]=Çap et...
+Name[be]=Друкаваць...
+Name[bg]=Печат...
+Name[bn]=ছাপাও...
+Name[br]=Moulañ ...
+Name[bs]=Štampaj...
+Name[ca]=Imprimeix...
+Name[cs]=Tisknout...
+Name[csb]=Drëkùjë...
+Name[cy]=Argraffu...
+Name[da]=Udskriv...
+Name[de]=Drucken ...
+Name[el]=Εκτύπωση...
+Name[eo]=Printi...
+Name[es]=Imprimir...
+Name[et]=Trüki...
+Name[eu]=Inprimatu...
+Name[fa]=چاپ...
+Name[fi]=Tulosta...
+Name[fr]=Imprimer...
+Name[fy]=Printsje...
+Name[ga]=Priontáil...
+Name[gl]=Imprimir...
+Name[he]=הדפס...
+Name[hi]=छापें...
+Name[hr]=Ispiši...
+Name[hu]=Nyomtatás...
+Name[is]=Prenta...
+Name[it]=Stampa...
+Name[ja]=印刷...
+Name[kk]=Басып шығару...
+Name[km]=បោះពុម្ព...
+Name[lv]=Drukāt...
+Name[mk]=Печати...
+Name[ms]=Cetak...
+Name[mt]=Ipprintja...
+Name[nb]=Skriv ut...
+Name[nds]=Drucken...
+Name[ne]=मुद्रण...
+Name[nl]=Afdrukken...
+Name[nn]=Skriv ut ...
+Name[pa]=ਛਪਾਈ...
+Name[pl]=Drukuj...
+Name[pt]=Imprimir...
+Name[pt_BR]=Imprimir...
+Name[ro]=Tipăreşte...
+Name[ru]=Печать...
+Name[rw]=Gucapa...
+Name[se]=Čálit …
+Name[sk]=Tlač...
+Name[sl]=Natisni ...
+Name[sr]=Штампа...
+Name[sr@Latn]=Štampa...
+Name[sv]=Skriv ut...
+Name[ta]=அச்சடி...
+Name[te]=ప్రచురించు...
+Name[tg]=Чоп кардан...
+Name[th]=พิมพ์...
+Name[tr]=Yazdır...
+Name[tt]=Bastıru...
+Name[uk]=Друк...
+Name[uz]=Босиб чиқариш
+Name[vi]=In ấn...
+Name[zh_CN]=打印...
+Name[zh_TW]=列印...
+Exec=kprinter -t %n --caption %n --icon %i --miniicon %m %U
+Icon=filequickprint
diff --git a/src/servicemenus/text-xml-print.desktop b/src/servicemenus/text-xml-print.desktop
new file mode 100644
index 0000000..ad4e8ed
--- /dev/null
+++ b/src/servicemenus/text-xml-print.desktop
@@ -0,0 +1,76 @@
+[Desktop Entry]
+Encoding=UTF-8
+ServiceTypes=text/x-xml
+Actions=Print;
+
+[Desktop Action Print]
+Name=Print...
+Name[af]=Druk...
+Name[ar]=طباعة...
+Name[az]=Çap et...
+Name[be]=Друкаваць...
+Name[bg]=Печат...
+Name[bn]=ছাপাও...
+Name[br]=Moulañ ...
+Name[bs]=Štampaj...
+Name[ca]=Imprimeix...
+Name[cs]=Tisknout...
+Name[csb]=Drëkùjë...
+Name[cy]=Argraffu...
+Name[da]=Udskriv...
+Name[de]=Drucken ...
+Name[el]=Εκτύπωση...
+Name[eo]=Printi...
+Name[es]=Imprimir...
+Name[et]=Trüki...
+Name[eu]=Inprimatu...
+Name[fa]=چاپ...
+Name[fi]=Tulosta...
+Name[fr]=Imprimer...
+Name[fy]=Printsje...
+Name[ga]=Priontáil...
+Name[gl]=Imprimir...
+Name[he]=הדפס...
+Name[hi]=छापें...
+Name[hr]=Ispiši...
+Name[hu]=Nyomtatás...
+Name[is]=Prenta...
+Name[it]=Stampa...
+Name[ja]=印刷...
+Name[kk]=Басып шығару...
+Name[km]=បោះពុម្ព...
+Name[lv]=Drukāt...
+Name[mk]=Печати...
+Name[ms]=Cetak...
+Name[mt]=Ipprintja...
+Name[nb]=Skriv ut...
+Name[nds]=Drucken...
+Name[ne]=मुद्रण...
+Name[nl]=Afdrukken...
+Name[nn]=Skriv ut ...
+Name[pa]=ਛਪਾਈ...
+Name[pl]=Drukuj...
+Name[pt]=Imprimir...
+Name[pt_BR]=Imprimir...
+Name[ro]=Tipăreşte...
+Name[ru]=Печать...
+Name[rw]=Gucapa...
+Name[se]=Čálit …
+Name[sk]=Tlač...
+Name[sl]=Natisni ...
+Name[sr]=Штампа...
+Name[sr@Latn]=Štampa...
+Name[sv]=Skriv ut...
+Name[ta]=அச்சடி...
+Name[te]=ప్రచురించు...
+Name[tg]=Чоп кардан...
+Name[th]=พิมพ์...
+Name[tr]=Yazdır...
+Name[tt]=Bastıru...
+Name[uk]=Друк...
+Name[uz]=Босиб чиқариш
+Name[vi]=In ấn...
+Name[zh_CN]=打印...
+Name[zh_TW]=列印...
+Exec=kprinter -t %n --caption %n --icon %i --miniicon %m %U
+Icon=filequickprint
diff --git a/src/servicemenus/text-xslt-print.desktop b/src/servicemenus/text-xslt-print.desktop
new file mode 100644
index 0000000..c482c0a
--- /dev/null
+++ b/src/servicemenus/text-xslt-print.desktop
@@ -0,0 +1,76 @@
+[Desktop Entry]
+Encoding=UTF-8
+ServiceTypes=text/x-xslt
+Actions=Print;
+
+[Desktop Action Print]
+Name=Print...
+Name[af]=Druk...
+Name[ar]=طباعة...
+Name[az]=Çap et...
+Name[be]=Друкаваць...
+Name[bg]=Печат...
+Name[bn]=ছাপাও...
+Name[br]=Moulañ ...
+Name[bs]=Štampaj...
+Name[ca]=Imprimeix...
+Name[cs]=Tisknout...
+Name[csb]=Drëkùjë...
+Name[cy]=Argraffu...
+Name[da]=Udskriv...
+Name[de]=Drucken ...
+Name[el]=Εκτύπωση...
+Name[eo]=Printi...
+Name[es]=Imprimir...
+Name[et]=Trüki...
+Name[eu]=Inprimatu...
+Name[fa]=چاپ...
+Name[fi]=Tulosta...
+Name[fr]=Imprimer...
+Name[fy]=Printsje...
+Name[ga]=Priontáil...
+Name[gl]=Imprimir...
+Name[he]=הדפס...
+Name[hi]=छापें...
+Name[hr]=Ispiši...
+Name[hu]=Nyomtatás...
+Name[is]=Prenta...
+Name[it]=Stampa...
+Name[ja]=印刷...
+Name[kk]=Басып шығару...
+Name[km]=បោះពុម្ព...
+Name[lv]=Drukāt...
+Name[mk]=Печати...
+Name[ms]=Cetak...
+Name[mt]=Ipprintja...
+Name[nb]=Skriv ut...
+Name[nds]=Drucken...
+Name[ne]=मुद्रण...
+Name[nl]=Afdrukken...
+Name[nn]=Skriv ut ...
+Name[pa]=ਛਪਾਈ...
+Name[pl]=Drukuj...
+Name[pt]=Imprimir...
+Name[pt_BR]=Imprimir...
+Name[ro]=Tipăreşte...
+Name[ru]=Печать...
+Name[rw]=Gucapa...
+Name[se]=Čálit …
+Name[sk]=Tlač...
+Name[sl]=Natisni ...
+Name[sr]=Штампа...
+Name[sr@Latn]=Štampa...
+Name[sv]=Skriv ut...
+Name[ta]=அச்சடி...
+Name[te]=ప్రచురించు...
+Name[tg]=Чоп кардан...
+Name[th]=พิมพ์...
+Name[tr]=Yazdır...
+Name[tt]=Bastıru...
+Name[uk]=Друк...
+Name[uz]=Босиб чиқариш
+Name[vi]=In ấn...
+Name[zh_CN]=打印...
+Name[zh_TW]=列印...
+Exec=kprinter -t %n --caption %n --icon %i --miniicon %m %U
+Icon=filequickprint
diff --git a/src/settingspagebase.cpp b/src/settingspagebase.cpp
new file mode 100644
index 0000000..244242c
--- /dev/null
+++ b/src/settingspagebase.cpp
@@ -0,0 +1,33 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "settingspagebase.h"
+
+SettingsPageBase::SettingsPageBase(QWidget* parent) :
+ QWidget(parent)
+{
+}
+
+SettingsPageBase::~SettingsPageBase()
+{
+}
+
+
+#include "settingspagebase.moc"
diff --git a/src/settingspagebase.h b/src/settingspagebase.h
new file mode 100644
index 0000000..0d4ec54
--- /dev/null
+++ b/src/settingspagebase.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef SETTINGSPAGEBASE_H
+#define SETTINGSPAGEBASE_H
+
+#include <qwidget.h>
+
+/**
+ * @brief Base class for the settings pages of the Dolphin settings dialog.
+ *
+ * @author Peter Penz <[email protected]>
+ */
+class SettingsPageBase : public QWidget
+{
+ Q_OBJECT
+
+public:
+ SettingsPageBase(QWidget* parent);
+ virtual ~SettingsPageBase();
+
+ /**
+ * Must be implemented by a derived class to
+ * persistently store the settings.
+ */
+ virtual void applySettings() = 0;
+};
+
+#endif
diff --git a/src/sidebarpage.cpp b/src/sidebarpage.cpp
new file mode 100644
index 0000000..ab057d1
--- /dev/null
+++ b/src/sidebarpage.cpp
@@ -0,0 +1,36 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Cvetoslav Ludmiloff <[email protected]> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "sidebarpage.h"
+#include "dolphin.h"
+
+SidebarPage::SidebarPage(QWidget* parent) :
+ QWidget(parent)
+{
+ connect(&Dolphin::mainWin(), SIGNAL(activeViewChanged()),
+ this, SLOT(activeViewChanged()));
+}
+
+SidebarPage::~SidebarPage()
+{
+}
+
+void SidebarPage::activeViewChanged()
+{
+}
diff --git a/src/sidebarpage.h b/src/sidebarpage.h
new file mode 100644
index 0000000..e136016
--- /dev/null
+++ b/src/sidebarpage.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Cvetoslav Ludmiloff <[email protected]> *
+ * Copyright (C) 2006 by Peter Penz <[email protected]>
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef _SIDEBARPAGE_H_
+#define _SIDEBARPAGE_H_
+
+#include <qwidget.h>
+
+class Sidebar;
+
+/**
+ * @brief Base widget for all pages that can be embedded into the Sidebar.
+ *
+ * TODO
+ */
+class SidebarPage : public QWidget
+{
+ Q_OBJECT
+
+public:
+ SidebarPage(QWidget* parent);
+ virtual ~SidebarPage();
+
+protected slots:
+ /**
+ * Is invoked whenever the active view from Dolphin has been changed.
+ * The active view can be retrieved by Dolphin::mainWin().activeView();
+ */
+ virtual void activeViewChanged();
+};
+
+#endif // _SIDEBARPAGE_H_
diff --git a/src/sidebars.cpp b/src/sidebars.cpp
new file mode 100644
index 0000000..6d401be
--- /dev/null
+++ b/src/sidebars.cpp
@@ -0,0 +1,190 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Marcel Juhnke *
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include <qlayout.h>
+#include <qpixmap.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <qcombobox.h>
+
+#include "dolphinsettings.h"
+#include "sidebarssettings.h"
+#include "bookmarkssidebarpage.h"
+#include "infosidebarpage.h"
+#include "sidebars.h"
+
+#include <assert.h>
+
+/**
+ *
+ * @param parent
+ */
+leftSidebar::leftSidebar(QWidget* parent) :
+ QWidget(parent),
+ m_pagesSelector(0),
+ m_page(0),
+ m_layout(0)
+{
+ m_layout = new QVBoxLayout(this);
+
+ m_pagesSelector = new QComboBox(this);
+ m_pagesSelector->insertItem(i18n("Bookmarks"));
+ m_pagesSelector->insertItem(i18n("Information"));
+
+ // Assure that the combo box has the same height as the URL navigator for
+ // a clean layout.
+ // TODO: the following 2 lines have been copied from the URLNavigator
+ // constructor (-> provide a shared height setting?)
+ //QFontMetrics fontMetrics(font());
+ QFontMetrics fontMetrics(font());
+ m_pagesSelector->setMinimumHeight(fontMetrics.height() + 8);
+
+ leftSidebarSettings* settings = DolphinSettings::instance().leftsidebar();
+ const int selectedIndex = indexForName(settings->selectedPage());
+ m_pagesSelector->setCurrentItem(selectedIndex);
+ m_layout->addWidget(m_pagesSelector);
+
+ createPage(selectedIndex);
+
+ connect(m_pagesSelector, SIGNAL(activated(int)),
+ this, SLOT(createPage(int)));
+}
+
+leftSidebar::~leftSidebar()
+{
+}
+
+QSize leftSidebar::sizeHint() const
+{
+ QSize size(QWidget::sizeHint());
+
+ leftSidebarSettings* settings = DolphinSettings::instance().leftsidebar();
+ size.setWidth(settings->width());
+ return size;
+}
+
+void leftSidebar::createPage(int index)
+{
+ if (m_page != 0) {
+ m_page->deleteLater();
+ m_page = 0;
+ }
+
+ switch (index) {
+ case 0: m_page = new BookmarksSidebarPage(this); break;
+ case 1: m_page = new InfoSidebarPage(this); break;
+ default: break;
+ }
+
+ m_layout->addWidget(m_page);
+ m_page->show();
+
+ leftSidebarSettings* settings = DolphinSettings::instance().leftsidebar();
+ settings->setSelectedPage(m_pagesSelector->text(index));
+}
+
+int leftSidebar::indexForName(const QString& name) const
+{
+ const int count = m_pagesSelector->count();
+ for (int i = 0; i < count; ++i) {
+ if (m_pagesSelector->text(i) == name) {
+ return i;
+ }
+ }
+
+ return 0;
+}
+
+rightSidebar::rightSidebar(QWidget* parent) :
+ QWidget(parent),
+ m_pagesSelector(0),
+ m_page(0),
+ m_layout(0)
+{
+ m_layout = new QVBoxLayout(this);
+
+ m_pagesSelector = new QComboBox(this);
+ m_pagesSelector->insertItem(i18n("Bookmarks"));
+ m_pagesSelector->insertItem(i18n("Information"));
+
+ // Assure that the combo box has the same height as the URL navigator for
+ // a clean layout.
+ // TODO: the following 2 lines have been copied from the URLNavigator
+ // constructor (-> provide a shared height setting?)
+ QFontMetrics fontMetrics(font());
+ m_pagesSelector->setMinimumHeight(fontMetrics.height() + 8);
+
+ rightSidebarSettings* settings = DolphinSettings::instance().rightsidebar();
+ const int selectedIndex = indexForName(settings->selectedPage());
+ m_pagesSelector->setCurrentItem(selectedIndex);
+ m_layout->addWidget(m_pagesSelector);
+
+ createPage(selectedIndex);
+
+ connect(m_pagesSelector, SIGNAL(activated(int)),
+ this, SLOT(createPage(int)));
+}
+
+rightSidebar::~rightSidebar()
+{
+}
+
+QSize rightSidebar::sizeHint() const
+{
+ QSize size(QWidget::sizeHint());
+
+ rightSidebarSettings* settings = DolphinSettings::instance().rightsidebar();
+ size.setWidth(settings->width());
+ return size;
+}
+
+void rightSidebar::createPage(int index)
+{
+ if (m_page != 0) {
+ m_page->deleteLater();
+ m_page = 0;
+ }
+
+ switch (index) {
+ case 0: m_page = new BookmarksSidebarPage(this); break;
+ case 1: m_page = new InfoSidebarPage(this); break;
+ default: break;
+ }
+
+ m_layout->addWidget(m_page);
+ m_page->show();
+
+ rightSidebarSettings* settings = DolphinSettings::instance().rightsidebar();
+ settings->setSelectedPage(m_pagesSelector->text(index));
+}
+
+int rightSidebar::indexForName(const QString& name) const
+{
+ const int count = m_pagesSelector->count();
+ for (int i = 0; i < count; ++i) {
+ if (m_pagesSelector->text(i) == name) {
+ return i;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/sidebars.h b/src/sidebars.h
new file mode 100644
index 0000000..d7eac77
--- /dev/null
+++ b/src/sidebars.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Marcel Juhnke *
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef _SIDEBARS_H_
+#define _SIDEBARS_H_
+
+#include <qwidget.h>
+
+
+class KURL;
+class QComboBox;
+class QVBoxLayout;
+class SidebarPage;
+
+class leftSidebar : public QWidget
+{
+ Q_OBJECT
+
+ public:
+ leftSidebar(QWidget* parent);
+ virtual ~leftSidebar();
+
+ virtual QSize sizeHint() const;
+
+ signals:
+ /**
+ * The user selected an item on sidebar widget and item has
+ * URL property, so inform the parent to go to this URL;
+ */
+ void urlChanged(const KURL& url);
+
+ private slots:
+ void createPage(int index);
+
+ private:
+ int indexForName(const QString& name) const;
+
+ QComboBox* m_pagesSelector;
+ SidebarPage* m_page;
+ QVBoxLayout* m_layout;
+};
+
+class rightSidebar : public QWidget
+{
+ Q_OBJECT
+
+ public:
+ rightSidebar(QWidget* parent);
+ virtual ~rightSidebar();
+
+ virtual QSize sizeHint() const;
+
+ signals:
+ /**
+ * The user selected an item on sidebar widget and item has
+ * URL property, so inform the parent togo to this URL;
+ */
+ void urlChanged(const KURL& url);
+
+ private slots:
+ void createPage(int index);
+
+ private:
+ int indexForName(const QString& name) const;
+
+ QComboBox* m_pagesSelector;
+ SidebarPage* m_page;
+ QVBoxLayout* m_layout;
+};
+
+#endif // _SIDEBARS_H_
diff --git a/src/sidebarssettings.cpp b/src/sidebarssettings.cpp
new file mode 100644
index 0000000..01ca5c6
--- /dev/null
+++ b/src/sidebarssettings.cpp
@@ -0,0 +1,96 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "sidebarssettings.h"
+#include <kapplication.h>
+#include <kconfig.h>
+#include <assert.h>
+
+leftSidebarSettings::leftSidebarSettings() :
+ m_visible(true),
+ m_width(0)
+{
+ KConfig* config = kapp->config();
+ config->setGroup("leftSidebar");
+
+ m_visible = config->readBoolEntry("Visible", true);
+ m_width = config->readNumEntry("Width", 150);
+ m_selectedPage = config->readEntry("Selected Page", "Bookmarks");
+}
+
+leftSidebarSettings::~leftSidebarSettings()
+{
+}
+
+void leftSidebarSettings::setWidth(int width)
+{
+ if (width < 50) {
+ // prevent that a sidebar gets width which makes
+ // it look invisible
+ width = 50;
+ }
+ m_width = width;
+}
+
+void leftSidebarSettings::save()
+{
+ KConfig* config = kapp->config();
+ config->setGroup("leftSidebar");
+
+ config->writeEntry("Visible", m_visible);
+ config->writeEntry("Width", m_width);
+ config->writeEntry("Selected Page", m_selectedPage);
+}
+
+rightSidebarSettings::rightSidebarSettings() :
+ m_visible(true),
+ m_width(0)
+{
+ KConfig* config = kapp->config();
+ config->setGroup("rightSidebar");
+
+ m_visible = config->readBoolEntry("Visible", true);
+ m_width = config->readNumEntry("Width", 150);
+ m_selectedPage = config->readEntry("Selected Page", "Bookmarks");
+}
+
+rightSidebarSettings::~rightSidebarSettings()
+{
+}
+
+void rightSidebarSettings::setWidth(int width)
+{
+ if (width < 50) {
+ // prevent that a sidebar gets width which makes
+ // it look invisible
+ width = 50;
+ }
+ m_width = width;
+}
+
+void rightSidebarSettings::save()
+{
+ KConfig* config = kapp->config();
+ config->setGroup("rightSidebar");
+
+ config->writeEntry("Visible", m_visible);
+ config->writeEntry("Width", m_width);
+ config->writeEntry("Selected Page", m_selectedPage);
+}
diff --git a/src/sidebarssettings.h b/src/sidebarssettings.h
new file mode 100644
index 0000000..7ef678d
--- /dev/null
+++ b/src/sidebarssettings.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef SIDEBARSETTINGS_H
+#define SIDEBARSETTINGS_H
+
+#include <qstring.h>
+#include <dolphinsettingsbase.h>
+
+
+class leftSidebarSettings
+{
+public:
+ leftSidebarSettings();
+ virtual ~leftSidebarSettings();
+ void setVisible(bool visible) { m_visible = visible; }
+ bool isVisible() const { return m_visible; }
+
+ void setWidth(int width);
+ int width() const { return m_width; }
+
+ void setSelectedPage(const QString& pageName) { m_selectedPage = pageName; }
+ const QString& selectedPage() const { return m_selectedPage; }
+
+ virtual void save();
+
+protected:
+ bool m_visible;
+ int m_width;
+ QString m_selectedPage;
+};
+
+class rightSidebarSettings
+{
+public:
+ rightSidebarSettings();
+ virtual ~rightSidebarSettings();
+ void setVisible(bool visible) { m_visible = visible; }
+ bool isVisible() const { return m_visible; }
+
+ void setWidth(int width);
+ int width() const { return m_width; }
+
+ void setSelectedPage(const QString& pageName) { m_selectedPage = pageName; }
+ const QString& selectedPage() const { return m_selectedPage; }
+
+ virtual void save();
+
+protected:
+ bool m_visible;
+ int m_width;
+ QString m_selectedPage;
+};
+
+#endif
diff --git a/src/statusbarmessagelabel.cpp b/src/statusbarmessagelabel.cpp
new file mode 100644
index 0000000..3c49c7a
--- /dev/null
+++ b/src/statusbarmessagelabel.cpp
@@ -0,0 +1,215 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "statusbarmessagelabel.h"
+#include <qpainter.h>
+#include <qtimer.h>
+#include <qfontmetrics.h>
+#include <kiconloader.h>
+#include <kglobalsettings.h>
+
+StatusBarMessageLabel::StatusBarMessageLabel(QWidget* parent) :
+ QWidget(parent),
+ m_type(DolphinStatusBar::Default),
+ m_state(Default),
+ m_illumination(0),
+ m_minTextHeight(-1),
+ m_timer(0)
+{
+ setMinimumHeight(KIcon::SizeSmall);
+
+ m_timer = new QTimer(this);
+ connect(m_timer, SIGNAL(timeout()),
+ this, SLOT(timerDone()));
+}
+
+StatusBarMessageLabel::~StatusBarMessageLabel()
+{
+}
+
+void StatusBarMessageLabel::setType(DolphinStatusBar::Type type)
+{
+ if (type != m_type) {
+ m_type = type;
+
+ m_timer->stop();
+ m_illumination = 0;
+ m_state = Default;
+
+ const char* iconName = 0;
+ QPixmap pixmap;
+ switch (type) {
+ case DolphinStatusBar::OperationCompleted:
+ iconName = "ok";
+ break;
+
+ case DolphinStatusBar::Information:
+ iconName = "info";
+ break;
+
+ case DolphinStatusBar::Error:
+ iconName = "error";
+ m_timer->start(100);
+ m_state = Illuminate;
+ break;
+
+ case DolphinStatusBar::Default:
+ default: break;
+ }
+
+ m_pixmap = (iconName == 0) ? QPixmap() : SmallIcon(iconName);
+ assureVisibleText();
+ update();
+ }
+}
+
+void StatusBarMessageLabel::setText(const QString& text)
+{
+ if (text != m_text) {
+ if (m_type == DolphinStatusBar::Error) {
+ m_timer->start(100);
+ m_illumination = 0;
+ m_state = Illuminate;
+ }
+ m_text = text;
+ assureVisibleText();
+ update();
+ }
+}
+
+void StatusBarMessageLabel::setMinimumTextHeight(int min)
+{
+ if (min != m_minTextHeight) {
+ m_minTextHeight = min;
+ setMinimumHeight(min);
+ }
+}
+
+void StatusBarMessageLabel::paintEvent(QPaintEvent* /* event */)
+{
+ QPixmap buffer(size());
+ QPainter painter(&buffer);
+
+ // draw background
+ QColor backgroundColor(colorGroup().background());
+ QColor foregroundColor(KGlobalSettings::textColor());
+ if (m_illumination > 0) {
+ backgroundColor = mixColors(backgroundColor, QColor(255, 255, 64), m_illumination);
+ foregroundColor = mixColors(foregroundColor, QColor(0, 0, 0), m_illumination);
+ }
+ painter.setBrush(backgroundColor);
+ painter.setPen(backgroundColor);
+ painter.drawRect(QRect(0, 0, width(), height()));
+
+ // draw pixmap
+ int x = pixmapGap();
+ int y = (height() - m_pixmap.height()) / 2;
+
+ if (!m_pixmap.isNull()) {
+ painter.drawPixmap(x, y, m_pixmap);
+ x += m_pixmap.width() + pixmapGap();
+ }
+
+ // draw text
+ painter.setPen(foregroundColor);
+ painter.drawText(QRect(x, 0, width() - x, height()), Qt::AlignVCenter | Qt::WordBreak, m_text);
+ painter.end();
+
+ bitBlt(this, 0, 0, &buffer);
+}
+
+void StatusBarMessageLabel::resizeEvent(QResizeEvent* event)
+{
+ QWidget::resizeEvent(event);
+ QTimer::singleShot(0, this, SLOT(assureVisibleText()));
+}
+
+void StatusBarMessageLabel::timerDone()
+{
+ switch (m_state) {
+ case Illuminate: {
+ // increase the illumination
+ if (m_illumination < 100) {
+ m_illumination += 20;
+ update();
+ }
+ else {
+ m_state = Illuminated;
+ m_timer->start(1000);
+ }
+ break;
+ }
+
+ case Illuminated: {
+ // start desaturation
+ m_state = Desaturate;
+ m_timer->start(100);
+ break;
+ }
+
+ case Desaturate: {
+ // desaturate
+ if (m_illumination > 0) {
+ m_illumination -= 5;
+ update();
+ }
+ else {
+ m_state = Default;
+ m_timer->stop();
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+void StatusBarMessageLabel::assureVisibleText()
+{
+ if (m_text.isEmpty()) {
+ return;
+ }
+
+
+ int availableWidth = width() - m_pixmap.width() - pixmapGap() * 2;
+
+ QFontMetrics fontMetrics(font());
+ QRect bounds(fontMetrics.boundingRect(0, 0, availableWidth, height(),
+ Qt::AlignVCenter | Qt::WordBreak,
+ m_text));
+ int requiredHeight = bounds.height();
+ if (requiredHeight < m_minTextHeight) {
+ requiredHeight = m_minTextHeight;
+ }
+ setMinimumHeight(requiredHeight);
+ updateGeometry();
+}
+
+QColor StatusBarMessageLabel::mixColors(const QColor& c1,
+ const QColor& c2,
+ int percent) const
+{
+ const int recip = 100 - percent;
+ const int red = (c1.red() * recip + c2.red() * percent) / 100;
+ const int green = (c1.green() * recip + c2.green() * percent) / 100;
+ const int blue = (c1.blue() * recip + c2.blue() * percent) / 100;
+ return QColor(red, green, blue);
+}
diff --git a/src/statusbarmessagelabel.h b/src/statusbarmessagelabel.h
new file mode 100644
index 0000000..c743f85
--- /dev/null
+++ b/src/statusbarmessagelabel.h
@@ -0,0 +1,92 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef STATUSBARMESSAGELABEL_H
+#define STATUSBARMESSAGELABEL_H
+
+#include <qwidget.h>
+#include <qpixmap.h>
+#include <qstring.h>
+#include <dolphinstatusbar.h>
+class QTimer;
+
+/**
+ * @brief Represents a message text label as part of the status bar.
+ *
+ * Dependant from the given type automatically a corresponding icon
+ * is shown in front of the text. For message texts having the type
+ * DolphinStatusBar::Error a dynamic color blending is done to get the
+ * attention from the user.
+ *
+ * @author Peter Penz
+ */
+class StatusBarMessageLabel : public QWidget
+{
+ Q_OBJECT
+
+public:
+ StatusBarMessageLabel(QWidget* parent);
+ virtual ~StatusBarMessageLabel();
+
+ void setType(DolphinStatusBar::Type type);
+ DolphinStatusBar::Type type() const { return m_type; }
+
+ void setText(const QString& text);
+ const QString& text() const { return m_text; }
+
+ // TODO: maybe a better approach is possible with the size hint
+ void setMinimumTextHeight(int min);
+ int minimumTextHeight() const { return m_minTextHeight; }
+
+protected:
+ /** @see QWidget::paintEvent */
+ virtual void paintEvent(QPaintEvent* event);
+
+ /** @see QWidget::resizeEvent */
+ virtual void resizeEvent(QResizeEvent* event);
+
+private slots:
+ void timerDone();
+ void assureVisibleText();
+
+private:
+ enum State {
+ Default,
+ Illuminate,
+ Illuminated,
+ Desaturate
+ };
+
+ DolphinStatusBar::Type m_type;
+ State m_state;
+ int m_illumination;
+ int m_minTextHeight;
+ QTimer* m_timer;
+ QString m_text;
+ QPixmap m_pixmap;
+
+ QColor mixColors(const QColor& c1,
+ const QColor& c2,
+ int percent) const;
+
+ int pixmapGap() const { return 3; }
+};
+
+#endif
diff --git a/src/statusbarspaceinfo.cpp b/src/statusbarspaceinfo.cpp
new file mode 100644
index 0000000..221a4f0
--- /dev/null
+++ b/src/statusbarspaceinfo.cpp
@@ -0,0 +1,192 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz ([email protected]) and *
+ * and Patrice Tremblay *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "statusbarspaceinfo.h"
+
+#include <qpainter.h>
+#include <qtimer.h>
+#include <kglobalsettings.h>
+#include <kdiskfreesp.h>
+#include <klocale.h>
+#include <kio/job.h>
+
+StatusBarSpaceInfo::StatusBarSpaceInfo(QWidget* parent) :
+ QWidget(parent),
+ m_gettingSize(false),
+ m_kBSize(0),
+ m_kBAvailable(0)
+{
+ setMinimumWidth(200);
+
+ // Update the space information each 10 seconds. Polling is useful
+ // here, as files can be deleted/added outside the scope of Dolphin.
+ QTimer* timer = new QTimer(this);
+ connect(timer, SIGNAL(timeout()), this, SLOT(refresh()));
+ timer->start(10000);
+}
+
+StatusBarSpaceInfo::~StatusBarSpaceInfo()
+{
+}
+
+void StatusBarSpaceInfo::setURL(const KURL& url)
+{
+ m_url = url;
+ refresh();
+ update();
+}
+
+void StatusBarSpaceInfo::paintEvent(QPaintEvent* /* event */)
+{
+ QPainter painter(this);
+ const int barWidth = width();
+ const int barTop = 2;
+ const int barHeight = height() - 4;
+
+ QString text;
+
+ const int widthDec = 3; // visual decrement for the available width
+
+ const QColor c1 = colorGroup().background();
+ const QColor c2 = KGlobalSettings::buttonTextColor();
+ const QColor frameColor((c1.red() + c2.red()) / 2,
+ (c1.green() + c2.green()) / 2,
+ (c1.blue() + c2.blue()) / 2);
+ painter.setPen(frameColor);
+
+ const QColor backgrColor = KGlobalSettings::baseColor();
+ painter.setBrush(backgrColor);
+
+ painter.drawRect(QRect(0, barTop + 1 , barWidth - widthDec, barHeight));
+
+ if ((m_kBSize > 0) && (m_kBAvailable > 0)) {
+ // draw 'used size' bar
+ painter.setPen(Qt::NoPen);
+ painter.setBrush(progressColor(backgrColor));
+ int usedWidth = barWidth - static_cast<int>((m_kBAvailable *
+ static_cast<float>(barWidth)) / m_kBSize);
+ const int left = 1;
+ int right = usedWidth - (widthDec + 1);
+ if (right < left) {
+ right = left;
+ }
+ painter.drawRect(QRect(left, barTop + 2, right, barHeight - 2));
+
+ text = i18n("%1 free")
+ .arg(KIO::convertSizeFromKB(m_kBAvailable));
+ }
+ else {
+ if (m_gettingSize) {
+ text = i18n("Getting size...");
+ }
+ else {
+ text = "";
+ QTimer::singleShot(0, this, SLOT(hide()));
+ }
+ }
+
+ // draw text (usually 'Y GB free')
+ painter.setPen(KGlobalSettings::textColor());
+ painter.drawText(QRect(1, 1, barWidth - 2, barHeight + 4),
+ Qt::AlignHCenter | Qt::AlignVCenter | Qt::WordBreak,
+ text);
+}
+
+
+void StatusBarSpaceInfo::slotFoundMountPoint(const unsigned long& kBSize,
+ const unsigned long& /* kBUsed */,
+ const unsigned long& kBAvailable,
+ const QString& /* mountPoint */)
+{
+ m_gettingSize = false;
+ m_kBSize = kBSize;
+ m_kBAvailable = kBAvailable;
+
+ // Bypass a the issue (?) of KDiskFreeSp that for protocols like
+ // FTP, SMB the size of root partition is returned.
+ // TODO: check whether KDiskFreeSp is buggy or Dolphin uses it in a wrong way
+ const QString protocol(m_url.protocol());
+ if (!protocol.isEmpty() && (protocol != "file")) {
+ m_kBSize = 0;
+ m_kBAvailable = 0;
+ }
+
+ update();
+}
+
+void StatusBarSpaceInfo::slotDone()
+{
+ m_gettingSize = false;
+ if ((m_kBSize > 0) && (m_kBAvailable > 0)) {
+ show();
+ }
+
+ update();
+}
+
+void StatusBarSpaceInfo::refresh()
+{
+ m_gettingSize = true;
+ m_kBSize = 0;
+ m_kBAvailable = 0;
+
+ const QString mountPoint(KIO::findPathMountPoint(m_url.path()));
+
+ KDiskFreeSp* job = new KDiskFreeSp(this);
+ connect(job, SIGNAL(foundMountPoint(const unsigned long&,
+ const unsigned long&,
+ const unsigned long&,
+ const QString& )),
+ this, SLOT(slotFoundMountPoint(const unsigned long&,
+ const unsigned long&,
+ const unsigned long&,
+ const QString& )));
+ connect(job, SIGNAL(done()),
+ this, SLOT(slotDone()));
+
+ job->readDF(mountPoint);
+}
+
+QColor StatusBarSpaceInfo::progressColor(const QColor& bgColor) const
+{
+ QColor color = KGlobalSettings::buttonBackground();
+
+ // assure that enough contrast is given between the background color
+ // and the progressbar color
+ int bgRed = bgColor.red();
+ int bgGreen = bgColor.green();
+ int bgBlue = bgColor.blue();
+
+ const int backgrBrightness = qGray(bgRed, bgGreen, bgBlue);
+ const int progressBrightness = qGray(color.red(), color.green(), color.blue());
+
+ const int limit = 32;
+ const int diff = backgrBrightness - progressBrightness;
+ bool adjustColor = ((diff >= 0) && (diff < limit)) ||
+ ((diff < 0) && (diff > -limit));
+ if (adjustColor) {
+ const int inc = (backgrBrightness < 2 * limit) ? (2 * limit) : -limit;
+ color = QColor(bgRed + inc, bgGreen + inc, bgBlue + inc);
+ }
+
+ return color;
+}
+
+#include "statusbarspaceinfo.moc"
diff --git a/src/statusbarspaceinfo.h b/src/statusbarspaceinfo.h
new file mode 100644
index 0000000..6409c45
--- /dev/null
+++ b/src/statusbarspaceinfo.h
@@ -0,0 +1,79 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz ([email protected]) and *
+ * and Patrice Tremblay *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+#ifndef STATUSBARSPACEINFO_H
+#define STATUSBARSPACEINFO_H
+
+#include <qwidget.h>
+#include <qstring.h>
+#include <kurl.h>
+#include <qcolor.h>
+
+class KDiskFreeSp;
+
+/**
+ * @short Shows the available space for the current volume as part
+ * of the status bar.
+ */
+class StatusBarSpaceInfo : public QWidget
+{
+ Q_OBJECT
+
+public:
+ StatusBarSpaceInfo(QWidget* parent);
+ virtual ~StatusBarSpaceInfo();
+
+ void setURL(const KURL& url);
+ const KURL& url() const { return m_url; }
+
+protected:
+ /** @see QWidget::paintEvent */
+ virtual void paintEvent(QPaintEvent* event);
+
+private slots:
+ /**
+ * The strange signature of this method is due to a compiler
+ * bug (?). More details are given inside the class KDiskFreeSp (see
+ * KDE Libs documentation).
+ */
+ void slotFoundMountPoint(const unsigned long& kBSize,
+ const unsigned long& kBUsed,
+ const unsigned long& kBAvailable,
+ const QString& mountPoint);
+ void slotDone();
+
+ /** Refreshs the space information for the current set URL. */
+ void refresh();
+
+private:
+ /**
+ * Returns a color for the progress bar by respecting
+ * the given background color \a bgColor. It is assured
+ * that enough contrast is given to have a visual indication.
+ */
+ QColor progressColor(const QColor& bgColor) const;
+
+ KURL m_url;
+ bool m_gettingSize;
+ unsigned long m_kBSize;
+ unsigned long m_kBAvailable;
+
+};
+
+#endif
diff --git a/src/undomanager.cpp b/src/undomanager.cpp
new file mode 100644
index 0000000..5869e4b
--- /dev/null
+++ b/src/undomanager.cpp
@@ -0,0 +1,402 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "undomanager.h"
+#include <klocale.h>
+#include <kio/netaccess.h>
+#include <qtimer.h>
+#include <assert.h>
+
+#include "dolphin.h"
+#include "dolphinstatusbar.h"
+#include "progressindicator.h"
+
+DolphinCommand::DolphinCommand() :
+ m_type(Copy),
+ m_macroIndex(-1)
+{
+ // Implementation note: DolphinCommands are stored in a QValueList, whereas
+ // QValueList requires a default constructor of the added class.
+ // Instead of expressing this implementation detail to the interface by adding a
+ // Type::Undefined just Type::Copy is used to assure that all members have
+ // a defined state.
+}
+
+DolphinCommand::DolphinCommand(Type type,
+ const KURL::List& source,
+ const KURL& dest) :
+ m_type(type),
+ m_macroIndex(-1),
+ m_source(source),
+ m_dest(dest)
+{
+}
+
+DolphinCommand::~DolphinCommand()
+{
+}
+
+DolphinCommand& DolphinCommand::operator = (const DolphinCommand& command)
+{
+ m_type = command.m_type;
+ m_source = command.m_source;
+ m_dest = command.m_dest;
+ return *this;
+}
+
+UndoManager& UndoManager::instance()
+{
+ static UndoManager* instance = 0;
+ if (instance == 0) {
+ instance = new UndoManager();
+ }
+ return *instance;
+}
+
+void UndoManager::addCommand(const DolphinCommand& command)
+{
+ ++m_historyIndex;
+
+ if (m_recordMacro) {
+ DolphinCommand macroCommand = command;
+ macroCommand.m_macroIndex = m_macroCounter;
+ m_history.insert(m_history.at(m_historyIndex), macroCommand);
+ }
+ else {
+ m_history.insert(m_history.at(m_historyIndex), command);
+ }
+
+ emit undoAvailable(true);
+ emit undoTextChanged(i18n("Undo: %1").arg(commandText(command)));
+
+ // prevent an endless growing of the Undo history
+ if (m_historyIndex > 10000) {
+ m_history.erase(m_history.begin());
+ --m_historyIndex;
+ }
+}
+
+void UndoManager::beginMacro()
+{
+ assert(!m_recordMacro);
+ m_recordMacro = true;
+ ++m_macroCounter;
+}
+
+void UndoManager::endMacro()
+{
+ assert(m_recordMacro);
+ m_recordMacro = false;
+}
+
+void UndoManager::undo()
+{
+ if (m_recordMacro) {
+ endMacro();
+ }
+
+ if (m_historyIndex < 0) {
+ return;
+ }
+
+ int progressCount = 0;
+ int macroCount = 1;
+ calcStepsCount(macroCount, progressCount);
+
+ m_progressIndicator = new ProgressIndicator(i18n("Executing undo operation..."),
+ i18n("Executed undo operation."),
+ progressCount);
+
+ for (int i = 0; i < macroCount; ++i) {
+ const DolphinCommand command = m_history[m_historyIndex];
+ --m_historyIndex;
+ if (m_historyIndex < 0) {
+ emit undoAvailable(false);
+ emit undoTextChanged(i18n("Undo"));
+ }
+ else {
+ emit undoTextChanged(i18n("Undo: %1").arg(commandText(m_history[m_historyIndex])));
+ }
+
+ if (m_historyIndex < static_cast<int>(m_history.count()) - 1) {
+ emit redoAvailable(true);
+ emit redoTextChanged(i18n("Redo: %1").arg(commandText(command)));
+ }
+ else {
+ emit redoAvailable(false);
+ emit redoTextChanged(i18n("Redo"));
+ }
+
+ KURL::List sourceURLs = command.source();
+ KURL::List::Iterator it = sourceURLs.begin();
+ const KURL::List::Iterator end = sourceURLs.end();
+ const QString destURL(command.destination().prettyURL(+1));
+
+ KIO::Job* job = 0;
+ switch (command.type()) {
+ case DolphinCommand::Link:
+ case DolphinCommand::Copy: {
+ KURL::List list;
+ while (it != end) {
+ const KURL deleteURL(destURL + (*it).filename());
+ list.append(deleteURL);
+ ++it;
+ }
+ job = KIO::del(list, false, false);
+ break;
+ }
+
+ case DolphinCommand::Move: {
+ KURL::List list;
+ const KURL newDestURL((*it).directory());
+ while (it != end) {
+ const KURL newSourceURL(destURL + (*it).filename());
+ list.append(newSourceURL);
+ ++it;
+ }
+ job = KIO::move(list, newDestURL, false);
+ break;
+ }
+
+ case DolphinCommand::Rename: {
+ assert(sourceURLs.count() == 1);
+ KIO::NetAccess::move(command.destination(), (*it));
+ break;
+ }
+
+ case DolphinCommand::Trash: {
+ while (it != end) {
+ // TODO: use KIO::special for accessing the trash protocol. See
+ // also Dolphin::slotJobResult() for further details.
+ const QString originalFileName((*it).filename().section('-', 1));
+ KURL newDestURL(destURL + originalFileName);
+ KIO::NetAccess::move(*it, newDestURL);
+ ++it;
+
+ m_progressIndicator->execOperation();
+ }
+ break;
+ }
+
+ case DolphinCommand::CreateFolder:
+ case DolphinCommand::CreateFile: {
+ KIO::NetAccess::del(command.destination(), &Dolphin::mainWin());
+ break;
+ }
+ }
+
+ if (job != 0) {
+ // Execute the jobs in a synchronous manner and forward the progress
+ // information to the Dolphin statusbar.
+ connect(job, SIGNAL(percent(KIO::Job*, unsigned long)),
+ this, SLOT(slotPercent(KIO::Job*, unsigned long)));
+ KIO::NetAccess::synchronousRun(job, &Dolphin::mainWin());
+ }
+
+ m_progressIndicator->execOperation();
+ }
+
+ delete m_progressIndicator;
+ m_progressIndicator = 0;
+}
+
+void UndoManager::redo()
+{
+ if (m_recordMacro) {
+ endMacro();
+ }
+
+ const int maxHistoryIndex = m_history.count() - 1;
+ if (m_historyIndex >= maxHistoryIndex) {
+ return;
+ }
+ ++m_historyIndex;
+
+ int progressCount = 0;
+ int macroCount = 1;
+ calcStepsCount(macroCount, progressCount);
+
+ m_progressIndicator = new ProgressIndicator(i18n("Executing redo operation..."),
+ i18n("Executed redo operation."),
+ progressCount);
+
+ for (int i = 0; i < macroCount; ++i) {
+ const DolphinCommand command = m_history[m_historyIndex];
+ if (m_historyIndex >= maxHistoryIndex) {
+ emit redoAvailable(false);
+ emit redoTextChanged(i18n("Redo"));
+ }
+ else {
+ emit redoTextChanged(i18n("Redo: %1").arg(commandText(m_history[m_historyIndex + 1])));
+ }
+
+ emit undoAvailable(true);
+ emit undoTextChanged(i18n("Undo: %1").arg(commandText(command)));
+
+ Dolphin& dolphin = Dolphin::mainWin();
+
+ KURL::List sourceURLs = command.source();
+ KURL::List::Iterator it = sourceURLs.begin();
+ const KURL::List::Iterator end = sourceURLs.end();
+
+ KIO::Job* job = 0;
+ switch (command.type()) {
+ case DolphinCommand::Link: {
+ job = KIO::link(sourceURLs, command.destination(), false);
+ break;
+ }
+
+ case DolphinCommand::Copy: {
+ job = KIO::copy(sourceURLs, command.destination(), false);
+ break;
+ }
+
+ case DolphinCommand::Rename:
+ case DolphinCommand::Move: {
+ job = KIO::move(sourceURLs, command.destination(), false);
+ break;
+ }
+
+ case DolphinCommand::Trash: {
+ const QString destURL(command.destination().prettyURL());
+ while (it != end) {
+ // TODO: use KIO::special for accessing the trash protocol. See
+ // also Dolphin::slotJobResult() for further details.
+ const QString originalFileName((*it).filename().section('-', 1));
+ KURL originalSourceURL(destURL + "/" + originalFileName);
+ KIO::Job* moveToTrashJob = KIO::trash(originalSourceURL);
+ KIO::NetAccess::synchronousRun(moveToTrashJob, &dolphin);
+ ++it;
+
+ m_progressIndicator->execOperation();
+ }
+ break;
+ }
+
+ case DolphinCommand::CreateFolder: {
+ KIO::NetAccess::mkdir(command.destination(), &dolphin);
+ break;
+ }
+
+ case DolphinCommand::CreateFile: {
+ m_progressIndicator->execOperation();
+ KURL::List::Iterator it = sourceURLs.begin();
+ assert(sourceURLs.count() == 1);
+ KIO::CopyJob* copyJob = KIO::copyAs(*it, command.destination(), false);
+ copyJob->setDefaultPermissions(true);
+ job = copyJob;
+ break;
+ }
+ }
+
+ if (job != 0) {
+ // Execute the jobs in a synchronous manner and forward the progress
+ // information to the Dolphin statusbar.
+ connect(job, SIGNAL(percent(KIO::Job*, unsigned long)),
+ this, SLOT(slotPercent(KIO::Job*, unsigned long)));
+ KIO::NetAccess::synchronousRun(job, &dolphin);
+ }
+
+ ++m_historyIndex;
+ m_progressIndicator->execOperation();
+ }
+
+ --m_historyIndex;
+
+ delete m_progressIndicator;
+ m_progressIndicator = 0;
+}
+
+UndoManager::UndoManager() :
+ m_recordMacro(false),
+ m_historyIndex(-1),
+ m_macroCounter(0),
+ m_progressIndicator(0)
+{
+}
+
+UndoManager::~UndoManager()
+{
+ delete m_progressIndicator;
+ m_progressIndicator = 0;
+}
+
+QString UndoManager::commandText(const DolphinCommand& command) const
+{
+ QString text;
+ switch (command.type()) {
+ case DolphinCommand::Copy: text = i18n("Copy"); break;
+ case DolphinCommand::Move: text = i18n("Move"); break;
+ case DolphinCommand::Link: text = i18n("Link"); break;
+ case DolphinCommand::Rename: text = i18n("Rename"); break;
+ case DolphinCommand::Trash: text = i18n("Move to Trash"); break;
+ case DolphinCommand::CreateFolder: text = i18n("Create New Folder"); break;
+ case DolphinCommand::CreateFile: text = i18n("Create New File"); break;
+ default: break;
+ }
+ return text;
+}
+
+void UndoManager::slotPercent(KIO::Job* /* job */, unsigned long /* percent */)
+{
+ // It is not allowed to update the progress indicator in the context
+ // of this slot, hence do an asynchronous triggering.
+ QTimer::singleShot(0, this, SLOT(updateProgress()));
+}
+
+void UndoManager::updateProgress()
+{
+ m_progressIndicator->execOperation();
+}
+
+void UndoManager::calcStepsCount(int& macroCount, int& progressCount)
+{
+ progressCount = 0;
+ macroCount = 0;
+
+ const int macroIndex = m_history[m_historyIndex].m_macroIndex;
+ if (macroIndex < 0) {
+ // default use case: no macro has been recorded
+ macroCount = 1;
+ progressCount = m_history[m_historyIndex].source().count();
+ return;
+ }
+
+ // iterate backward for undo...
+ int i = m_historyIndex;
+ while ((i >= 0) && (m_history[i].m_macroIndex == macroIndex)) {
+ ++macroCount;
+ progressCount += m_history[i].source().count();
+ --i;
+ }
+
+ // iterate forward for redo...
+ const int max = m_history.count() - 1;
+ i = m_historyIndex + 1;
+ while ((i <= max) && (m_history[i].m_macroIndex == macroIndex)) {
+ ++macroCount;
+ progressCount += m_history[i].source().count();
+ ++i;
+ }
+}
+
+#include "undomanager.moc"
+
+
diff --git a/src/undomanager.h b/src/undomanager.h
new file mode 100644
index 0000000..fb6f14e
--- /dev/null
+++ b/src/undomanager.h
@@ -0,0 +1,196 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef UNDOMANAGER_H
+#define UNDOMANAGER_H
+
+#include <qobject.h>
+#include <qvaluelist.h>
+#include <kurl.h>
+#include <kio/jobclasses.h>
+
+class ProgressIndicator;
+
+/**
+ * @short Represents a file manager command which can be undone and redone.
+ *
+ * A command is specified by a type, a list of source URLs and a
+ * destination URL.
+ *
+ * Due to the fixed set of commands a file manager offers this class is
+ * a very simplified version of the classic command pattern.
+ *
+ * @see UndoManager
+ * @author Peter Penz <[email protected]>
+ */
+class DolphinCommand
+{
+public:
+ enum Type {
+ Copy,
+ Move,
+ Link,
+ Rename,
+ Trash,
+ CreateFolder,
+ CreateFile
+ };
+
+ DolphinCommand();
+ DolphinCommand(Type type, const KURL::List& source, const KURL& dest);
+ ~DolphinCommand(); // non-virtual
+
+ DolphinCommand& operator = (const DolphinCommand& command);
+ Type type() const { return m_type; }
+ void setSource(const KURL::List source) { m_source = source; }
+ const KURL::List& source() const { return m_source; }
+ const KURL& destination() const { return m_dest; }
+
+private:
+ Type m_type;
+ int m_macroIndex;
+ KURL::List m_source;
+ KURL m_dest;
+
+ friend class UndoManager; // allow to modify m_macroIndex
+};
+
+/**
+ * @short Stores all file manager commands which can be undone and redone.
+ *
+ * During the undo and redo operations a progress information is
+ * shown in the status bar.
+ *
+ * @author Peter Penz <[email protected]>
+ */
+class UndoManager : public QObject
+{
+ Q_OBJECT
+
+public:
+ static UndoManager& instance();
+
+ /**
+ * Adds the command \a command to the undo list. The command
+ * can be undone by invoking UndoManager::undo().
+ */
+ void addCommand(const DolphinCommand& command);
+
+ /**
+ * Allows to summarize several commands into one macro, which
+ * can be undo in one stop by UndoManager::undo(). Example
+ * \code
+ * UndoManager& undoMan = UndoManager.instance();
+ * undoMan.beginMacro();
+ * undoMan.addCommand(...);
+ * undoMan.addCommand(...);
+ * undoMan.addCommand(...);
+ * undoMan.endMacro();
+ * \endcode
+ * It is not allowed to do nested macro recordings.
+ */
+ void beginMacro();
+
+ /**
+ * Marks the end of a macro command. See UndoManager::beginMacro()
+ * for sample code.
+ */
+ void endMacro();
+
+public slots:
+ /**
+ * Performs an undo operation on the last command which has
+ * been added by UndoManager::addCommand().
+ */
+ void undo();
+
+ /**
+ * Performs a redo operation on the last command where an undo
+ * operation has been applied.
+ */
+ void redo();
+
+signals:
+ /**
+ * Is emitted if whenever the availability state
+ * of the current undo operation changes.
+ */
+ void undoAvailable(bool available);
+
+ /**
+ * Is emitted whenever the text of the current
+ * undo operation changes
+ * (e. g. from 'Undo: Delete' to 'Undo: Copy')
+ */
+ void undoTextChanged(const QString& text);
+
+ /**
+ * Is emitted if whenever the availability state
+ * of the current redo operation changes.
+ */
+ void redoAvailable(bool available);
+
+ /**
+ * Is emitted whenever the text of the current
+ * redo operation changes
+ * (e. g. from 'Redo: Delete' to 'Redo: Copy')
+ */
+ void redoTextChanged(const QString& text);
+
+protected:
+ UndoManager();
+ virtual ~UndoManager();
+ QString commandText(const DolphinCommand& command) const;
+
+private slots:
+ /**
+ * Slot for the percent information of the I/O slaves.
+ * Delegates the updating of the progress information
+ * to UndoManager::updateProgress().
+ */
+ void slotPercent(KIO::Job* job, unsigned long percent);
+
+ /**
+ * Updates the progress information of the statusbar
+ * by accessing the progress indicator information.
+ */
+ void updateProgress();
+
+private:
+ bool m_recordMacro;
+ int m_historyIndex;
+ int m_macroCounter;
+ QValueList<DolphinCommand> m_history;
+ ProgressIndicator* m_progressIndicator;
+
+ /**
+ * Dependent from the current history index \a m_historyIndex
+ * the number of macro commands is written to the output
+ * parameter \a macroCount. The number of steps for all macro
+ * commands is written to the output parameter \a progressCount.
+ *
+ * Per default \a macroCount is 1 and \a progressCount represents
+ * the number of operations for one command.
+ */
+ void calcStepsCount(int& macroCount,
+ int& progressCount);
+};
+
+#endif
diff --git a/src/urlbutton.cpp b/src/urlbutton.cpp
new file mode 100644
index 0000000..27ddc81
--- /dev/null
+++ b/src/urlbutton.cpp
@@ -0,0 +1,96 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz ([email protected]) *
+ * Copyright (C) 2006 by Aaron J. Seigo (<[email protected]>) *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "urlnavigatorbutton.h"
+#include <kurl.h>
+#include <qtooltip.h>
+#include <qcursor.h>
+#include <qfontmetrics.h>
+#include <kurldrag.h>
+#include <kpopupmenu.h>
+#include <kiconloader.h>
+#include <klocale.h>
+
+#include "urlnavigator.h"
+#include "dolphin.h"
+
+
+URLButton::URLButton(URLNavigator* parent)
+: QPushButton(parent),
+ m_displayHint(0),
+ m_urlNavigator(parent)
+{
+ setFocusPolicy(QWidget::NoFocus);
+ setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
+ setMinimumHeight(parent->minimumHeight());
+
+ connect(this, SIGNAL(clicked()), parent, SLOT(slotRequestActivation()));
+ connect(&Dolphin::mainWin(), SIGNAL(activeViewChanged()),
+ this, SLOT(update()));
+}
+
+URLButton::~URLButton()
+{
+}
+
+URLNavigator* URLButton::urlNavigator() const
+{
+ return m_urlNavigator;
+}
+
+void URLButton::setDisplayHintEnabled(DisplayHint hint,
+ bool enable)
+{
+ if (enable) {
+ m_displayHint = m_displayHint | hint;
+ }
+ else {
+ m_displayHint = m_displayHint & ~hint;
+ }
+ update();
+}
+
+bool URLButton::isDisplayHintEnabled(DisplayHint hint) const
+{
+ return (m_displayHint & hint) > 0;
+}
+
+void URLButton::enterEvent(QEvent* event)
+{
+ QPushButton::enterEvent(event);
+ setDisplayHintEnabled(EnteredHint, true);
+ update();
+}
+
+void URLButton::leaveEvent(QEvent* event)
+{
+ QPushButton::leaveEvent(event);
+ setDisplayHintEnabled(EnteredHint, false);
+ update();
+}
+
+QColor URLButton::mixColors(const QColor& c1,
+ const QColor& c2) const
+{
+ const int red = (c1.red() + c2.red()) / 2;
+ const int green = (c1.green() + c2.green()) / 2;
+ const int blue = (c1.blue() + c2.blue()) / 2;
+ return QColor(red, green, blue);
+}
diff --git a/src/urlbutton.h b/src/urlbutton.h
new file mode 100644
index 0000000..3ede7f8
--- /dev/null
+++ b/src/urlbutton.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz ([email protected]) *
+ * Copyright (C) 2006 by Aaron J. Seigo (<[email protected]>) *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef URLBUTTON_H
+#define URLBUTTON_H
+
+#include <qpushbutton.h>
+
+class KURL;
+class URLNavigator;
+class QPainter;
+
+/**
+ * @brief Base class for buttons of the URL navigator.
+ *
+ * Each button of the URL navigator contains an URL, which
+ * is set as soon as the button has been clicked.
+*
+ * @author Peter Penz
+ */
+class URLButton : public QPushButton
+{
+ Q_OBJECT
+
+public:
+ URLButton(URLNavigator* parent);
+ virtual ~URLButton();
+
+ URLNavigator* urlNavigator() const;
+
+protected:
+ enum DisplayHint {
+ ActivatedHint = 1,
+ EnteredHint = 2,
+ DraggedHint = 4,
+ PopupActiveHint = 8
+ };
+
+ void setDisplayHintEnabled(DisplayHint hint, bool enable);
+ bool isDisplayHintEnabled(DisplayHint hint) const;
+
+ virtual void enterEvent(QEvent* event);
+ virtual void leaveEvent(QEvent* event);
+
+ QColor mixColors(const QColor& c1, const QColor& c2) const;
+
+private:
+ int m_displayHint;
+ URLNavigator* m_urlNavigator;
+};
+
+#endif
diff --git a/src/urlnavigator.cpp b/src/urlnavigator.cpp
new file mode 100644
index 0000000..3f0d278
--- /dev/null
+++ b/src/urlnavigator.cpp
@@ -0,0 +1,501 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz ([email protected]) *
+ * Copyright (C) 2006 by Aaron J. Seigo (<[email protected]>) *
+ * Copyright (C) 2006 by Patrice Tremblay *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "urlnavigator.h"
+
+#include <assert.h>
+#include <kurl.h>
+#include <qobjectlist.h>
+#include <qcombobox.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <qpopupmenu.h>
+#include <qlineedit.h>
+#include <qpushbutton.h>
+#include <qsizepolicy.h>
+#include <qtooltip.h>
+#include <qfont.h>
+#include <qlistbox.h>
+
+#include <kio/job.h>
+#include <kurlcombobox.h>
+#include <kurlcompletion.h>
+#include <kbookmarkmanager.h>
+
+#include "dolphin.h"
+#include "dolphinsettings.h"
+#include "bookmarkselector.h"
+#include "dolphinstatusbar.h"
+#include "urlnavigatorbutton.h"
+#include "dolphinview.h"
+
+URLNavigator::HistoryElem::HistoryElem()
+ : m_url(),
+ m_currentFileName(),
+ m_contentsX(0),
+ m_contentsY(0)
+{
+}
+
+URLNavigator::HistoryElem::HistoryElem(const KURL& url)
+ : m_url(url),
+ m_currentFileName(),
+ m_contentsX(0),
+ m_contentsY(0)
+{
+}
+
+URLNavigator::HistoryElem::~HistoryElem()
+{
+}
+
+URLNavigator::URLNavigator(const KURL& url,
+ DolphinView* dolphinView) :
+ QHBox(dolphinView),
+ m_historyIndex(0),
+ m_dolphinView(dolphinView)
+{
+ m_history.prepend(HistoryElem(url));
+
+ QFontMetrics fontMetrics(font());
+ setMinimumHeight(fontMetrics.height() + 8);
+
+ m_toggleButton = new QPushButton(SmallIcon("editurl"), 0, this);
+ m_toggleButton->setFlat(true);
+ m_toggleButton->setToggleButton(true);
+ m_toggleButton->setFocusPolicy(QWidget::NoFocus);
+ m_toggleButton->setMinimumHeight(minimumHeight());
+ connect(m_toggleButton, SIGNAL(clicked()),
+ this, SLOT(slotClicked()));
+ if (DolphinSettings::instance().isURLEditable()) {
+ m_toggleButton->toggle();
+ }
+
+ m_bookmarkSelector = new BookmarkSelector(this);
+ connect(m_bookmarkSelector, SIGNAL(bookmarkActivated(int)),
+ this, SLOT(slotBookmarkActivated(int)));
+
+ m_pathBox = new KURLComboBox(KURLComboBox::Directories, true, this);
+
+ KURLCompletion* kurlCompletion = new KURLCompletion(KURLCompletion::DirCompletion);
+ m_pathBox->setCompletionObject(kurlCompletion);
+ m_pathBox->setAutoDeleteCompletionObject(true);
+
+ connect(m_pathBox, SIGNAL(returnPressed(const QString&)),
+ this, SLOT(slotReturnPressed(const QString&)));
+ connect(m_pathBox, SIGNAL(urlActivated(const KURL&)),
+ this, SLOT(slotURLActivated(const KURL&)));
+
+ connect(dolphinView, SIGNAL(contentsMoved(int, int)),
+ this, SLOT(slotContentsMoved(int, int)));
+ updateContent();
+}
+
+URLNavigator::~URLNavigator()
+{
+}
+
+void URLNavigator::setURL(const KURL& url)
+{
+ QString urlStr(url.prettyURL());
+
+ if (url.protocol() == "zip") {
+ bool stillInside = false;
+ if (KMimeType::findByPath(url.url(-1))
+ ->is("application/x-zip")) {
+ stillInside = true;
+ }
+ else {
+ KURL url1 = url.upURL();
+ while (url1 != url1.upURL()) {
+ if (KMimeType::findByPath(url1.url(-1))
+ ->is("application/x-zip")) {
+ stillInside = true;
+ break;
+ }
+ url1 = url1.upURL();
+ }
+ }
+ if (!stillInside)
+ {
+ // Drop the zip:/ protocol since we are not in the zip anymore
+ urlStr = url.path();
+ }
+ }
+ else if (url.protocol() == "tar")
+ {
+ bool stillInside = false;
+ KMimeType::Ptr kmp =
+ KMimeType::findByPath(url.url(-1));
+ if (kmp->is("application/x-tar") ||
+ kmp->is("application/x-tarz") ||
+ kmp->is("application/x-tbz") ||
+ kmp->is("application/x-tgz") ||
+ kmp->is("application/x-tzo")
+ ) {
+ stillInside = true;
+ }
+ else {
+ KURL url1 = url.upURL();
+ while (url1 != url1.upURL()) {
+ KMimeType::Ptr kmp =
+ KMimeType::findByPath(url1.url(-1));
+ if (kmp->is("application/x-tar") ||
+ kmp->is("application/x-tarz") ||
+ kmp->is("application/x-tbz") ||
+ kmp->is("application/x-tgz") ||
+ kmp->is("application/x-tzo")
+ ) {
+ stillInside = true;
+ break;
+ }
+ url1 = url1.upURL();
+ }
+ }
+ if (!stillInside)
+ {
+ // Drop the tar:/ protocol since we are not in the tar anymore
+ urlStr = url.path();
+ }
+ }
+
+
+ if (urlStr.at(0) == '~') {
+ // replace '~' by the home directory
+ urlStr.remove(0, 1);
+ urlStr.insert(0, QDir::home().path());
+ }
+
+ const KURL transformedURL(urlStr);
+
+ if (m_historyIndex > 0) {
+ // Check whether the previous element of the history has the same URL.
+ // If yes, just go forward instead of inserting a duplicate history
+ // element.
+ const KURL& nextURL = m_history[m_historyIndex - 1].url();
+ if (transformedURL == nextURL) {
+ goForward();
+ return;
+ }
+ }
+
+ const KURL& currURL = m_history[m_historyIndex].url();
+ if (currURL == transformedURL) {
+ // don't insert duplicate history elements
+ return;
+ }
+
+ updateHistoryElem();
+
+ const QValueListIterator<URLNavigator::HistoryElem> it = m_history.at(m_historyIndex);
+ m_history.insert(it, HistoryElem(transformedURL));
+ updateContent();
+ emit urlChanged(transformedURL);
+ emit historyChanged();
+
+ // Prevent an endless growing of the history: remembering
+ // the last 100 URLs should be enough...
+ if (m_historyIndex > 100) {
+ m_history.erase(m_history.begin());
+ --m_historyIndex;
+ }
+}
+
+const KURL& URLNavigator::url() const
+{
+ assert(!m_history.empty());
+ return m_history[m_historyIndex].url();
+}
+
+KURL URLNavigator::url(int index) const
+{
+ assert(index >= 0);
+ QString path(url().prettyURL());
+ path = path.section('/', 0, index);
+
+ if (path.at(path.length()) != '/')
+ {
+ path.append('/');
+ }
+
+ return path;
+}
+
+const QValueList<URLNavigator::HistoryElem>& URLNavigator::history(int& index) const
+{
+ index = m_historyIndex;
+ return m_history;
+}
+
+void URLNavigator::goBack()
+{
+ updateHistoryElem();
+
+ const int count = m_history.count();
+ if (m_historyIndex < count - 1) {
+ ++m_historyIndex;
+ updateContent();
+ emit urlChanged(url());
+ emit historyChanged();
+ }
+}
+
+void URLNavigator::goForward()
+{
+ if (m_historyIndex > 0) {
+ --m_historyIndex;
+ updateContent();
+ emit urlChanged(url());
+ emit historyChanged();
+ }
+}
+
+void URLNavigator::goUp()
+{
+ setURL(url().upURL());
+}
+
+void URLNavigator::goHome()
+{
+ setURL(DolphinSettings::instance().homeURL());
+}
+
+void URLNavigator::setURLEditable(bool editable)
+{
+ if (isURLEditable() != editable) {
+ m_toggleButton->toggle();
+ slotClicked();
+ }
+}
+
+bool URLNavigator::isURLEditable() const
+{
+ return m_toggleButton->state() == QButton::On;
+}
+
+void URLNavigator::editURL()
+{
+ setURLEditable(true);
+ m_pathBox->setFocus();
+}
+
+DolphinView* URLNavigator::dolphinView() const
+{
+ return m_dolphinView;
+}
+
+void URLNavigator::keyReleaseEvent(QKeyEvent* event)
+{
+ QHBox::keyReleaseEvent(event);
+ if (isURLEditable() && (event->key() == Qt::Key_Escape)) {
+ setURLEditable(false);
+ }
+}
+
+void URLNavigator::slotReturnPressed(const QString& text)
+{
+ // Parts of the following code have been taken
+ // from the class KateFileSelector located in
+ // kate/app/katefileselector.hpp of Kate.
+ // Copyright (C) 2001 Christoph Cullmann <[email protected]>
+ // Copyright (C) 2001 Joseph Wenninger <[email protected]>
+ // Copyright (C) 2001 Anders Lund <[email protected]>
+
+ KURL typedURL(text);
+ if (typedURL.hasPass()) {
+ typedURL.setPass(QString::null);
+ }
+
+ QStringList urls = m_pathBox->urls();
+ urls.remove(typedURL.url());
+ urls.prepend(typedURL.url());
+ m_pathBox->setURLs(urls, KURLComboBox::RemoveBottom);
+
+ setURL(typedURL);
+ // The URL might have been adjusted by URLNavigator::setURL(), hence
+ // synchronize the result in the path box.
+ m_pathBox->setURL(url());
+}
+
+void URLNavigator::slotURLActivated(const KURL& url)
+{
+ setURL(url);
+}
+
+void URLNavigator::slotRequestActivation()
+{
+ m_dolphinView->requestActivation();
+}
+
+void URLNavigator::slotBookmarkActivated(int index)
+{
+ m_dolphinView->statusBar()->clear();
+ m_dolphinView->requestActivation();
+
+ KBookmark bookmark = DolphinSettings::instance().bookmark(index);
+ m_dolphinView->setURL(bookmark.url());
+}
+
+void URLNavigator::slotContentsMoved(int x, int y)
+{
+ m_history[m_historyIndex].setContentsX(x);
+ m_history[m_historyIndex].setContentsY(y);
+}
+
+void URLNavigator::slotClicked()
+{
+ updateContent();
+ if (isURLEditable()) {
+ m_pathBox->setFocus();
+ }
+ else {
+ m_dolphinView->setFocus();
+ }
+}
+
+void URLNavigator::updateHistoryElem()
+{
+ assert(m_historyIndex >= 0);
+ const KFileItem* item = m_dolphinView->currentFileItem();
+ if (item != 0) {
+ m_history[m_historyIndex].setCurrentFileName(item->name());
+ }
+ m_history[m_historyIndex].setContentsX(m_dolphinView->contentsX());
+ m_history[m_historyIndex].setContentsY(m_dolphinView->contentsY());
+}
+
+void URLNavigator::updateContent()
+{
+ const QObjectList* list = children();
+ if (list == 0) {
+ return;
+ }
+
+ // set the iterator to the first URL navigator button
+ QObjectListIterator it(*list);
+ QObject* object = 0;
+ while ((object = it.current()) != 0) {
+ if (object->inherits("URLNavigatorButton")) {
+ break;
+ }
+ ++it;
+ }
+
+ // delete all existing URL navigator buttons
+ QPtrList<QWidget> deleteList;
+ while ((object = it.current()) != 0) {
+ if (object->inherits("URLNavigatorButton")) {
+ // Don't close and delete the navigator button immediatly, otherwise
+ // the iterator won't work anymore and an object would get deleted more
+ // than once (-> crash).
+ deleteList.append(static_cast<QWidget*>(object));
+ }
+ ++it;
+ }
+
+ // now close and delete all unused navigator buttons
+ QPtrListIterator<QWidget> deleteIter(deleteList);
+ QWidget* widget = 0;
+ while ((widget = deleteIter.current()) != 0) {
+ widget->close();
+ widget->deleteLater();
+ ++deleteIter;
+ }
+
+ m_bookmarkSelector->updateSelection(url());
+
+ QToolTip::remove(m_toggleButton);
+ QString path(url().prettyURL());
+ if (m_toggleButton->state() == QButton::On) {
+ // TODO: don't hardcode the shortcut as part of the text
+ QToolTip::add(m_toggleButton, i18n("Browse (Ctrl+B, Escape)"));
+
+ setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+ m_pathBox->show();
+ m_pathBox->setURL(url());
+ }
+ else {
+ // TODO: don't hardcode the shortcut as part of the text
+ QToolTip::add(m_toggleButton, i18n("Edit location (Ctrl+L)"));
+
+ setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ m_pathBox->hide();
+ QString dir_name;
+
+ // get the data from the currently selected bookmark
+ KBookmark bookmark = m_bookmarkSelector->selectedBookmark();
+ //int bookmarkIndex = m_bookmarkSelector->selectedIndex();
+
+ QString bookmarkPath;
+ if (bookmark.isNull()) {
+ // No bookmark is a part of the current URL.
+ // The following code tries to guess the bookmark
+ // path. E. g. "fish://[email protected]/var/lib" writes
+ // "fish://[email protected]" to 'bookmarkPath', which leads to the
+ // navigation indication 'Custom Path > var > lib".
+ int idx = path.find(QString("//"));
+ idx = path.find("/", (idx < 0) ? 0 : idx + 2);
+ bookmarkPath = (idx < 0) ? path : path.left(idx);
+ }
+ else {
+ bookmarkPath = bookmark.url().prettyURL();
+ }
+ const uint len = bookmarkPath.length();
+
+ // calculate the start point for the URL navigator buttons by counting
+ // the slashs inside the bookmark URL
+ int slashCount = 0;
+ for (uint i = 0; i < len; ++i) {
+ if (bookmarkPath.at(i) == QChar('/')) {
+ ++slashCount;
+ }
+ }
+ if ((len > 0) && bookmarkPath.at(len - 1) == QChar('/')) {
+ assert(slashCount > 0);
+ --slashCount;
+ }
+
+ // create URL navigator buttons
+ int idx = slashCount;
+ bool hasNext = true;
+ do {
+ dir_name = path.section('/', idx, idx);
+ const bool isFirstButton = (idx == slashCount);
+ hasNext = isFirstButton || !dir_name.isEmpty();
+ if (hasNext) {
+ URLNavigatorButton* button = new URLNavigatorButton(idx, this);
+ if (isFirstButton) {
+ // the first URL navigator button should get the name of the bookmark
+ // instead of the directory name
+ QString text = bookmark.text();
+ if (text.isEmpty()) {
+ text = bookmarkPath;
+ }
+ button->setText(text);
+ }
+ button->show();
+ ++idx;
+ }
+ } while (hasNext);
+ }
+}
+
+#include "urlnavigator.moc"
diff --git a/src/urlnavigator.h b/src/urlnavigator.h
new file mode 100644
index 0000000..706215a
--- /dev/null
+++ b/src/urlnavigator.h
@@ -0,0 +1,210 @@
+/***************************************************************************
+* Copyright (C) 2006 by Peter Penz *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with this program; if not, write to the *
+* Free Software Foundation, Inc., *
+* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+***************************************************************************/
+
+#ifndef URLNAVIGATOR_H
+#define URLNAVIGATOR_H
+
+#include <qhbox.h>
+#include <kurl.h>
+#include <qstring.h>
+
+class DolphinView;
+class QPopupMenu;
+class QPushButton;
+class QComboBox;
+class BookmarkSelector;
+class KURLComboBox;
+class KFileItem;
+
+/**
+ * @brief Navigation bar which contains the current shown URL.
+ *
+ * The URL navigator offers two modes:
+ * - Editable: Represents the 'classic' mode, where the current URL
+ * is editable inside a line editor.
+ * - Non editable: The URL is represented by a number of buttons, where
+ * clicking on a button results in activating the URL
+ * the button represents. This mode also supports drag
+ * and drop of items.
+ *
+ * The mode can be changed by a toggle button located on the left side of
+ * the navigator.
+ *
+ * The URL navigator also remembers the URL history and allows to go
+ * back and forward within this history.
+ *
+ * @author Peter Penz
+*/
+class URLNavigator : public QHBox
+{
+ Q_OBJECT
+
+public:
+ /**
+ * @brief Represents the history element of an URL.
+ *
+ * A history element contains the URL, the name of the current file
+ * (the 'current file' is the file where the cursor is located) and
+ * the x- and y-position of the content.
+ */
+ class HistoryElem {
+ public:
+ HistoryElem();
+ HistoryElem(const KURL& url);
+ ~HistoryElem(); // non virtual
+
+ const KURL& url() const { return m_url; }
+
+ void setCurrentFileName(const QString& name) { m_currentFileName = name; }
+ const QString& currentFileName() const { return m_currentFileName; }
+
+ void setContentsX(int x) { m_contentsX = x; }
+ int contentsX() const { return m_contentsX; }
+
+ void setContentsY(int y) { m_contentsY = y; }
+ int contentsY() const { return m_contentsY; }
+
+ private:
+ KURL m_url;
+ QString m_currentFileName;
+ int m_contentsX;
+ int m_contentsY;
+ };
+
+ URLNavigator(const KURL& url, DolphinView* dolphinView);;
+ virtual ~URLNavigator();
+
+ /**
+ * Sets the current active URL.
+ * The signals URLNavigator::urlChanged and URLNavigator::historyChanged
+ * are submitted.
+ */
+ void setURL(const KURL& url);
+
+ /** Returns the current active URL. */
+ const KURL& url() const;
+
+ /** Returns the portion of the current active URL up to the button at index. */
+ KURL url(int index) const;
+
+ /**
+ * Returns the complete URL history. The index 0 indicates the oldest
+ * history element.
+ * @param index Output parameter which indicates the current
+ * index of the location.
+ */
+ const QValueList<HistoryElem>& history(int& index) const;
+
+ /**
+ * Goes back one step in the URL history. The signals
+ * URLNavigator::urlChanged and URLNavigator::historyChanged
+ * are submitted.
+ */
+ void goBack();
+
+ /**
+ * Goes forward one step in the URL history. The signals
+ * URLNavigator::urlChanged and URLNavigator::historyChanged
+ * are submitted.
+ */
+ void goForward();
+
+ /**
+ * Goes up one step of the URL path. The signals
+ * URLNavigator::urlChanged and URLNavigator::historyChanged
+ * are submitted.
+ */
+ void goUp();
+
+ /**
+ * Goes to the home URL. The signals URLNavigator::urlChanged
+ * and URLNavigator::historyChanged are submitted.
+ */
+ void goHome();
+
+ /**
+ * Allows to edit the URL of the navigation bar if \a editable
+ * is true. If \a editable is false, each part of
+ * the URL is presented by a button for a fast navigation.
+ */
+ void setURLEditable(bool editable);
+
+ /**
+ * @return True, if the URL is editable by the user within a line editor.
+ * If false is returned, each part of the URL is presented by a button
+ * for fast navigation.
+ */
+ bool isURLEditable() const;
+
+ /**
+ * Switches to the edit mode and assures that the keyboard focus
+ * is assigned.
+ */
+ void editURL();
+
+ DolphinView* dolphinView() const;
+
+signals:
+ void urlChanged(const KURL& url);
+ void historyChanged();
+
+protected:
+ /** If the Escape key is pressed, the navigation bar should switch
+ to the browse mode. */
+ virtual void keyReleaseEvent(QKeyEvent* event);
+
+private slots:
+ void slotReturnPressed(const QString& text);
+ void slotURLActivated(const KURL& url);
+
+ void slotRequestActivation();
+ void slotBookmarkActivated(int index);
+
+ /**
+ * Stores the coordinates of the moved content into
+ * the current history element. Is usually triggered
+ * by the signal 'contentsMoved' emitted by DolphinView.
+ */
+ void slotContentsMoved(int x, int y);
+
+ /**
+ * Switches the navigation bar between the editable and noneditable
+ * state (see setURLEditable()) and is connected to the clicked signal
+ * of the navigation bar button.
+ */
+ void slotClicked();
+
+private:
+ int m_historyIndex;
+ DolphinView* m_dolphinView;
+ QValueList<HistoryElem> m_history;
+ QPushButton* m_toggleButton;
+ BookmarkSelector* m_bookmarkSelector;
+ KURLComboBox* m_pathBox;
+
+ /**
+ * Updates the history element with the current file item
+ * and the contents position.
+ */
+ void updateHistoryElem();
+ void updateContent();
+};
+
+#endif
diff --git a/src/urlnavigatorbutton.cpp b/src/urlnavigatorbutton.cpp
new file mode 100644
index 0000000..1cc5bcc
--- /dev/null
+++ b/src/urlnavigatorbutton.cpp
@@ -0,0 +1,393 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz ([email protected]) *
+ * Copyright (C) 2006 by Aaron J. Seigo (<[email protected]>) *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "urlnavigatorbutton.h"
+#include <qcursor.h>
+#include <qfontmetrics.h>
+#include <qpainter.h>
+#include <qtimer.h>
+#include <qtooltip.h>
+
+#include <kglobalsettings.h>
+#include <kiconloader.h>
+#include <kio/jobclasses.h>
+#include <klocale.h>
+#include <kpopupmenu.h>
+#include <kurl.h>
+#include <kurldrag.h>
+#include <assert.h>
+
+#include "urlnavigator.h"
+#include "dolphinview.h"
+#include "dolphin.h"
+
+URLNavigatorButton::URLNavigatorButton(int index, URLNavigator* parent) :
+ URLButton(parent),
+ m_index(-1),
+ m_listJob(0)
+{
+ setAcceptDrops(true);
+ setMinimumWidth(arrowWidth());
+ setIndex(index);
+ connect(this, SIGNAL(clicked()), this, SLOT(updateNavigatorURL()));
+
+ m_popupDelay = new QTimer(this);
+ connect(m_popupDelay, SIGNAL(timeout()), this, SLOT(startListJob()));
+ connect(this, SIGNAL(pressed()), this, SLOT(startPopupDelay()));
+}
+
+URLNavigatorButton::~URLNavigatorButton()
+{
+}
+
+void URLNavigatorButton::setIndex(int index)
+{
+ if (index < 0) {
+ index = 0;
+ }
+
+ m_index = index;
+ QString path(urlNavigator()->url().prettyURL());
+ setText(path.section('/', index, index));
+
+ // Check whether the button indicates the full path of the URL. If
+ // this is the case, the button is marked as 'active'.
+ ++index;
+ QFont adjustedFont(font());
+ if (path.section('/', index, index).isEmpty()) {
+ setDisplayHintEnabled(ActivatedHint, true);
+ adjustedFont.setBold(true);
+ }
+ else {
+ setDisplayHintEnabled(ActivatedHint, false);
+ adjustedFont.setBold(false);
+ }
+
+ setFont(adjustedFont);
+ update();
+}
+
+int URLNavigatorButton::index() const
+{
+ return m_index;
+}
+
+void URLNavigatorButton::drawButton(QPainter* painter)
+{
+ const int buttonWidth = width();
+ const int buttonHeight = height();
+
+ QColor backgroundColor;
+ QColor foregroundColor;
+ const bool isHighlighted = isDisplayHintEnabled(EnteredHint) ||
+ isDisplayHintEnabled(DraggedHint) ||
+ isDisplayHintEnabled(PopupActiveHint);
+ if (isHighlighted) {
+ backgroundColor = KGlobalSettings::highlightColor();
+ foregroundColor = KGlobalSettings::highlightedTextColor();
+ }
+ else {
+ backgroundColor = colorGroup().background();
+ foregroundColor = KGlobalSettings::buttonTextColor();
+ }
+
+ // dimm the colors if the parent view does not have the focus
+ const DolphinView* parentView = urlNavigator()->dolphinView();
+ const Dolphin& dolphin = Dolphin::mainWin();
+
+ const bool isActive = (dolphin.activeView() == parentView);
+ if (!isActive) {
+ QColor dimmColor(colorGroup().background());
+ foregroundColor = mixColors(foregroundColor, dimmColor);
+ if (isHighlighted) {
+ backgroundColor = mixColors(backgroundColor, dimmColor);
+ }
+ }
+
+ // draw button background
+ painter->setPen(NoPen);
+ painter->setBrush(backgroundColor);
+ painter->drawRect(0, 0, buttonWidth, buttonHeight);
+
+ int textWidth = buttonWidth;
+ if (isDisplayHintEnabled(ActivatedHint) && isActive || isHighlighted) {
+ painter->setPen(foregroundColor);
+ }
+ else {
+ // dimm the foreground color by mixing it with the background
+ foregroundColor = mixColors(foregroundColor, backgroundColor);
+ painter->setPen(foregroundColor);
+ }
+
+ if (!isDisplayHintEnabled(ActivatedHint)) {
+ // draw arrow
+ const int border = 2; // horizontal border
+ const int middleY = height() / 2;
+ const int width = arrowWidth();
+ const int startX = (buttonWidth - width) - (2 * border);
+ const int startTopY = middleY - (width - 1);
+ const int startBottomY = middleY + (width - 1);
+ for (int i = 0; i < width; ++i) {
+ painter->drawLine(startX, startTopY + i, startX + i, startTopY + i);
+ painter->drawLine(startX, startBottomY - i, startX + i, startBottomY - i);
+ }
+
+ textWidth = startX - border;
+ }
+
+ const bool clipped = isTextClipped();
+ const int align = clipped ? Qt::AlignVCenter : Qt::AlignCenter;
+ painter->drawText(QRect(0, 0, textWidth, buttonHeight), align, text());
+
+ if (clipped) {
+ // Blend the right area of the text with the background, as the
+ // text is clipped.
+ // TODO: use alpha blending in Qt4 instead of drawing the text that often
+ const int blendSteps = 16;
+
+ QColor blendColor(backgroundColor);
+ const int redInc = (foregroundColor.red() - backgroundColor.red()) / blendSteps;
+ const int greenInc = (foregroundColor.green() - backgroundColor.green()) / blendSteps;
+ const int blueInc = (foregroundColor.blue() - backgroundColor.blue()) / blendSteps;
+ for (int i = 0; i < blendSteps; ++i) {
+ painter->setClipRect(QRect(textWidth - i, 0, 1, buttonHeight));
+ painter->setPen(blendColor);
+ painter->drawText(QRect(0, 0, textWidth, buttonHeight), align, text());
+
+ blendColor.setRgb(blendColor.red() + redInc,
+ blendColor.green() + greenInc,
+ blendColor.blue() + blueInc);
+ }
+ }
+}
+
+void URLNavigatorButton::enterEvent(QEvent* event)
+{
+ URLButton::enterEvent(event);
+
+ // if the text is clipped due to a small window width, the text should
+ // be shown as tooltip
+ if (isTextClipped()) {
+ QToolTip::add(this, text());
+ }
+}
+
+void URLNavigatorButton::leaveEvent(QEvent* event)
+{
+ URLButton::leaveEvent(event);
+ QToolTip::remove(this);
+}
+
+void URLNavigatorButton::dropEvent(QDropEvent* event)
+{
+ KURL::List urls;
+ if (KURLDrag::decode(event, urls) && !urls.isEmpty()) {
+ setDisplayHintEnabled(DraggedHint, true);
+
+ QString path(urlNavigator()->url().prettyURL());
+ path = path.section('/', 0, m_index);
+
+ Dolphin::mainWin().dropURLs(urls, KURL(path));
+
+ setDisplayHintEnabled(DraggedHint, false);
+ update();
+ }
+}
+
+void URLNavigatorButton::dragEnterEvent(QDragEnterEvent* event)
+{
+ event->accept(KURLDrag::canDecode(event));
+
+ setDisplayHintEnabled(DraggedHint, true);
+ update();
+}
+
+void URLNavigatorButton::dragLeaveEvent(QDragLeaveEvent* event)
+{
+ URLButton::dragLeaveEvent(event);
+
+ setDisplayHintEnabled(DraggedHint, false);
+ update();
+}
+
+
+void URLNavigatorButton::updateNavigatorURL()
+{
+ URLNavigator* navigator = urlNavigator();
+ assert(navigator != 0);
+ navigator->setURL(navigator->url(m_index));
+}
+
+void URLNavigatorButton::startPopupDelay()
+{
+ if (m_popupDelay->isActive() || m_listJob) {
+ return;
+ }
+
+ m_popupDelay->start(300, true);
+}
+
+void URLNavigatorButton::stopPopupDelay()
+{
+ m_popupDelay->stop();
+ if (m_listJob) {
+ m_listJob->kill();
+ m_listJob = 0;
+ }
+}
+
+void URLNavigatorButton::startListJob()
+{
+ if (m_listJob) {
+ return;
+ }
+
+ KURL url = urlNavigator()->url(m_index);
+ m_listJob = KIO::listDir(url, false, false);
+ m_subdirs.clear(); // just to be ++safe
+
+ connect(m_listJob, SIGNAL(entries(KIO::Job*, const KIO::UDSEntryList &)),
+ this, SLOT(entriesList(KIO::Job*, const KIO::UDSEntryList&)));
+ connect(m_listJob, SIGNAL(result(KIO::Job*)), this, SLOT(listJobFinished(KIO::Job*)));
+}
+
+void URLNavigatorButton::entriesList(KIO::Job* job, const KIO::UDSEntryList& entries)
+{
+ if (job != m_listJob) {
+ return;
+ }
+
+ KIO::UDSEntryList::const_iterator it = entries.constBegin();
+ KIO::UDSEntryList::const_iterator itEnd = entries.constEnd();
+ while (it != itEnd) {
+ QString name;
+ bool isDir = false;
+ KIO::UDSEntry entry = *it;
+ KIO::UDSEntry::const_iterator atomIt = entry.constBegin();
+ KIO::UDSEntry::const_iterator atomEndIt = entry.constEnd();
+
+ while (atomIt != atomEndIt) {
+ switch ((*atomIt).m_uds) {
+ case KIO::UDS_NAME:
+ name = (*atomIt).m_str;
+ break;
+ case KIO::UDS_FILE_TYPE:
+ isDir = S_ISDIR((*atomIt).m_long);
+ break;
+ default:
+ break;
+ }
+ ++atomIt;
+ }
+
+ if (isDir) {
+ m_subdirs.append(name);
+ }
+
+ ++it;
+ }
+
+ m_subdirs.sort();
+}
+
+void URLNavigatorButton::listJobFinished(KIO::Job* job)
+{
+ if (job != m_listJob) {
+ return;
+ }
+
+ if (job->error() || m_subdirs.isEmpty()) {
+ // clear listing
+ return;
+ }
+
+ setDisplayHintEnabled(PopupActiveHint, true);
+ update(); // ensure the button is drawn highlighted
+ QPopupMenu* dirsMenu = new QPopupMenu(this);
+ //setPopup(dirsMenu);
+ QStringList::const_iterator it = m_subdirs.constBegin();
+ QStringList::const_iterator itEnd = m_subdirs.constEnd();
+ int i = 0;
+ while (it != itEnd) {
+ dirsMenu->insertItem(*it, i);
+ ++i;
+ ++it;
+ }
+
+ int result = dirsMenu->exec(urlNavigator()->mapToGlobal(geometry().bottomLeft()));
+
+ if (result >= 0) {
+ KURL url = urlNavigator()->url(m_index);
+ url.addPath(*m_subdirs.at(result));
+ urlNavigator()->setURL(url);
+ }
+
+ m_listJob = 0;
+ m_subdirs.clear();
+ delete dirsMenu;
+ setDisplayHintEnabled(PopupActiveHint, false);
+}
+
+int URLNavigatorButton::arrowWidth() const
+{
+ int width = (height() / 2) - 7;
+ if (width < 4) {
+ width = 4;
+ }
+ return width;
+}
+
+bool URLNavigatorButton::isTextClipped() const
+{
+ int availableWidth = width();
+ if (!isDisplayHintEnabled(ActivatedHint)) {
+ availableWidth -= arrowWidth() + 1;
+ }
+
+ QFontMetrics fontMetrics(font());
+ return fontMetrics.width(text()) >= availableWidth;
+}
+
+
+void URLNavigatorButton::mousePressEvent(QMouseEvent * event)
+{
+ if (event->button() == LeftButton)
+ dragPos = event->pos();
+ URLButton::mousePressEvent(event);
+}
+
+void URLNavigatorButton::mouseMoveEvent(QMouseEvent * event)
+{
+ if (event->state() & LeftButton) {
+ int distance = (event->pos() - dragPos).manhattanLength();
+ if (distance > QApplication::startDragDistance()*2)//don't start on small move (for submenu usability)
+ startDrag();
+ }
+ URLButton::mouseMoveEvent(event);
+}
+
+void URLNavigatorButton::startDrag()
+{
+ KURL url = urlNavigator()->url(m_index);
+ KURL::List lst;
+ lst.append( url );
+ KURLDrag *drag = new KURLDrag(lst, this);
+ drag->drag();
+}
diff --git a/src/urlnavigatorbutton.h b/src/urlnavigatorbutton.h
new file mode 100644
index 0000000..de71fd6
--- /dev/null
+++ b/src/urlnavigatorbutton.h
@@ -0,0 +1,88 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz ([email protected]) *
+ * Copyright (C) 2006 by Aaron J. Seigo (<[email protected]>) *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+#ifndef URLNAVIGATORBUTTON_H
+#define URLNAVIGATORBUTTON_H
+
+#include <qstringlist.h>
+
+#include <kio/global.h>
+
+#include <urlbutton.h>
+
+class KURL;
+class URLNavigator;
+class QPainter;
+
+namespace KIO
+{
+ class Job;
+}
+
+/**
+ * @brief Button of the URL navigator which contains one part of an URL.
+ *
+ * It is possible to drop a various number of items to an URL button. In this case
+ * a context menu is opened where the user must select whether he wants
+ * to copy, move or link the dropped items to the URL part indicated by
+ * the button.
+ */
+class URLNavigatorButton : public URLButton
+{
+ Q_OBJECT
+
+public:
+ URLNavigatorButton(int index, URLNavigator* parent = 0);
+ virtual ~URLNavigatorButton();
+ void setIndex(int index);
+ int index() const;
+
+protected:
+ virtual void drawButton(QPainter* painter);
+ virtual void enterEvent(QEvent* event);
+ virtual void leaveEvent(QEvent* event);
+ //drag
+ void mousePressEvent( QMouseEvent *event );
+ void mouseMoveEvent( QMouseEvent *event );
+ //drop
+ virtual void dropEvent(QDropEvent* event);
+ virtual void dragEnterEvent(QDragEnterEvent* event);
+ virtual void dragLeaveEvent(QDragLeaveEvent* event);
+
+private slots:
+ void updateNavigatorURL();
+ void startPopupDelay();
+ void stopPopupDelay();
+ void startListJob();
+ void entriesList(KIO::Job* job, const KIO::UDSEntryList& entries);
+ void listJobFinished(KIO::Job* job);
+
+private:
+ int arrowWidth() const;
+ bool isTextClipped() const;
+ void startDrag();
+
+ int m_index;
+ QTimer* m_popupDelay;
+ KIO::Job* m_listJob;
+ QStringList m_subdirs;
+ QPoint dragPos;
+};
+
+#endif
diff --git a/src/viewproperties.cpp b/src/viewproperties.cpp
new file mode 100644
index 0000000..66d5935
--- /dev/null
+++ b/src/viewproperties.cpp
@@ -0,0 +1,362 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include <assert.h>
+
+#include <qdatetime.h>
+#include <qdir.h>
+#include <qfile.h>
+
+#include <klocale.h>
+#include <kstandarddirs.h>
+#include <kurl.h>
+
+#include "viewproperties.h"
+#include "dolphinsettings.h"
+
+#define FILE_NAME "/.d3lphinview"
+
+ViewProperties::ViewProperties(KURL url) :
+ m_changedProps(false),
+ m_autoSave(true),
+ m_subDirValidityHidden(false)
+{
+ url.cleanPath(true);
+ m_filepath = url.path();
+
+ if ((m_filepath.length() < 1) || (m_filepath.at(0) != QChar('/'))) {
+ return;
+ }
+
+ // we try and save it to a file in the directory being viewed
+ // if the directory is not writable by the user or the directory is not local
+ // we store the properties information in a local file
+ DolphinSettings& settings = DolphinSettings::instance();
+ if (settings.isSaveView()) {
+ QString rootDir("/"); // TODO: should this be set to the root of the bookmark, if any?
+ if (url.isLocalFile()) {
+ QFileInfo info(m_filepath);
+
+ if (!info.isWritable()) {
+ QString basePath = KGlobal::instance()->instanceName();
+ basePath.append("/view_properties/local");
+ rootDir = locateLocal("data", basePath);
+ m_filepath = rootDir + m_filepath;
+ }
+ }
+ else {
+ QString basePath = KGlobal::instance()->instanceName();
+ basePath.append("/view_properties/remote/").append(url.host());
+ rootDir = locateLocal("data", basePath);
+ m_filepath = rootDir + m_filepath;
+ }
+
+ QDir dir(m_filepath);
+ QFile file(m_filepath + FILE_NAME);
+
+
+ PropertiesNode node(&file);
+
+ const bool isValidForSubDirs = !node.isEmpty() && node.isValidForSubDirs();
+ while ((dir.path() != rootDir) && dir.cdUp()) {
+ QFile file(dir.path() + FILE_NAME);
+ PropertiesNode parentNode(&file);
+ if (!parentNode.isEmpty()) {
+ const bool inheritProps = parentNode.isValidForSubDirs() &&
+ (parentNode.subDirProperties().m_timeStamp >
+ node.localProperties().m_timeStamp);
+
+ if (inheritProps) {
+ node.setLocalProperties(parentNode.subDirProperties());
+ break;
+ }
+ }
+ }
+
+ m_node = node;
+
+ if (isValidForSubDirs) {
+ m_subDirValidityHidden = true;
+ }
+ m_node.setValidForSubDirs(false);
+ }
+}
+
+ViewProperties::~ViewProperties()
+{
+ if (m_changedProps && m_autoSave) {
+ save();
+ }
+}
+
+void ViewProperties::setViewMode(DolphinView::Mode mode)
+{
+ if (m_node.localProperties().m_viewMode != mode) {
+ m_node.setViewMode(mode);
+ updateTimeStamp();
+ }
+}
+
+DolphinView::Mode ViewProperties::viewMode() const
+{
+ return m_node.localProperties().m_viewMode;
+}
+
+void ViewProperties::setShowHiddenFilesEnabled(bool show)
+{
+ if (m_node.localProperties().m_showHiddenFiles != show) {
+ m_node.setShowHiddenFilesEnabled(show);
+ updateTimeStamp();
+ }
+}
+
+bool ViewProperties::isShowHiddenFilesEnabled() const
+{
+ return m_node.localProperties().m_showHiddenFiles;
+}
+
+void ViewProperties::setSorting(DolphinView::Sorting sorting)
+{
+ if (m_node.localProperties().m_sorting != sorting) {
+ m_node.setSorting(sorting);
+ updateTimeStamp();
+ }
+}
+
+DolphinView::Sorting ViewProperties::sorting() const
+{
+ return m_node.localProperties().m_sorting;
+}
+
+void ViewProperties::setSortOrder(Qt::SortOrder sortOrder)
+{
+ if (m_node.localProperties().m_sortOrder != sortOrder) {
+ m_node.setSortOrder(sortOrder);
+ updateTimeStamp();
+ }
+}
+
+Qt::SortOrder ViewProperties::sortOrder() const
+{
+ return m_node.localProperties().m_sortOrder;
+}
+
+void ViewProperties::setValidForSubDirs(bool valid)
+{
+ if (m_node.isValidForSubDirs() != valid) {
+ m_node.setValidForSubDirs(valid);
+ updateTimeStamp();
+ }
+}
+
+bool ViewProperties::isValidForSubDirs() const
+{
+ return m_node.isValidForSubDirs();
+}
+
+void ViewProperties::setAutoSaveEnabled(bool autoSave)
+{
+ m_autoSave = autoSave;
+}
+
+bool ViewProperties::isAutoSaveEnabled() const
+{
+ return m_autoSave;
+}
+
+void ViewProperties::save()
+{
+ DolphinSettings& settings = DolphinSettings::instance();
+ if (settings.isSaveView()) {
+ QFile file(m_filepath + FILE_NAME);
+ KStandardDirs::makeDir(m_filepath);
+ if (!file.open(IO_WriteOnly)) {
+ return;
+ }
+
+ const Properties& props = m_node.localProperties();
+ char viewMode = static_cast<char>(props.m_viewMode) + '0';
+ char sorting = static_cast<char>(props.m_sorting) + '0';
+ const bool isValidForSubDirs = m_node.isValidForSubDirs() || m_subDirValidityHidden;
+
+ QTextStream stream(&file);
+ stream << "V01"
+ << viewMode
+ << (props.m_showHiddenFiles ? '1' : '0')
+ << props.m_timeStamp.toString("yyyyMMddhhmmss")
+ << sorting
+ << ((props.m_sortOrder == Qt::Ascending) ? 'A' : 'D')
+ << (isValidForSubDirs ? '1' : '0');
+
+ if (m_node.isValidForSubDirs()) {
+ m_node.setSubDirProperties(props);
+ }
+
+ if (isValidForSubDirs) {
+ const Properties& subDirProps = m_node.subDirProperties();
+ viewMode = static_cast<char>(subDirProps.m_viewMode) + '0';
+ sorting = static_cast<char>(subDirProps.m_sorting) + '0';
+ stream << viewMode
+ << (subDirProps.m_showHiddenFiles ? '1' : '0')
+ << subDirProps.m_timeStamp.toString("yyyyMMddhhmmss")
+ << sorting
+ << ((subDirProps.m_sortOrder == Qt::Ascending) ? 'A' : 'D');
+ }
+ file.flush();
+ file.close();
+
+ m_changedProps = false;
+ }
+}
+
+void ViewProperties::updateTimeStamp()
+{
+ m_changedProps = true;
+ m_node.setTimeStamp(QDateTime::currentDateTime());
+}
+
+ViewProperties::Properties::Properties() :
+ m_showHiddenFiles(false),
+ m_viewMode(DolphinView::IconsView),
+ m_sorting(DolphinView::SortByName),
+ m_sortOrder(Qt::Ascending)
+{
+ m_timeStamp.setDate(QDate(1999, 12, 31));
+ m_timeStamp.setTime(QTime(23, 59, 59));
+
+ m_viewMode = DolphinSettings::instance().defaultViewMode();
+}
+
+ViewProperties::Properties::~Properties()
+{
+}
+
+ViewProperties::PropertiesNode::PropertiesNode(QFile* file) :
+ m_empty(true)
+{
+ m_isValidForSubDirs = false;
+
+ if ((file != 0) && file->open(IO_ReadOnly)) {
+ m_empty = false;
+
+ const int max_len = 41;
+ static char buffer[max_len];
+
+ // TODO: use memset
+ for (int i = 0; i < max_len; ++i) {
+ buffer[i] = 0;
+ }
+
+ file->readLine(buffer, max_len);
+
+ // Check version of viewproperties file. The initial format
+ // sadly had no version numbering, which is indicated by a missing 'V'
+ // as first letter. The current scheme uses V + 2 digits.
+ int version = 0;
+ int startInc = 0;
+ if (buffer[0] == 'V') {
+ startInc = 3; // skip version info (e. g. V01)
+ version = 1;
+ // currently no further versions are available:
+ assert(buffer[1] == '0');
+ assert(buffer[2] == '1');
+ }
+
+ int readBytes = readProperties(m_props, &buffer[startInc], version);
+ assert(readBytes >= 0);
+
+ // check whether sub directory properties are available
+ m_isValidForSubDirs = (buffer[startInc + readBytes] != '0');
+ if (m_isValidForSubDirs) {
+ readBytes = readProperties(m_subDirProps,
+ &buffer[startInc + readBytes + 1],
+ version);
+ }
+ file->close();
+
+ m_empty = (readBytes <= 0);
+ }
+}
+
+ViewProperties::PropertiesNode::~PropertiesNode()
+{
+}
+
+ViewProperties::PropertiesNode&
+ ViewProperties::PropertiesNode::operator = (const PropertiesNode& node)
+{
+ if (&node != this) {
+ m_empty = node.m_empty;
+ m_isValidForSubDirs = node.m_isValidForSubDirs;
+ m_props = node.m_props;
+ m_subDirProps = node.m_subDirProps;
+ }
+
+ return *this;
+}
+
+int ViewProperties::PropertiesNode::toInt(const char* buffer, int count) const
+{
+ assert(buffer != 0);
+
+ int value = 0;
+ for (int i = 0; i < count; ++i) {
+ value = value * 10 + static_cast<int>(buffer[i] - '0');
+ }
+
+ return value;
+}
+
+int ViewProperties::PropertiesNode::readProperties(Properties& props,
+ const char* buffer,
+ int version)
+{
+ props.m_viewMode = static_cast<DolphinView::Mode>(buffer[0] - '0');
+ props.m_showHiddenFiles = (buffer[1] != '0');
+
+ // read date
+ QDateTime timeStamp;
+ const int year = toInt(&(buffer[2]), 4);
+ const int month = toInt(&(buffer[6]), 2);
+ const int day = toInt(&(buffer[8]), 2);
+ QDate date(year, month, day);
+ timeStamp.setDate(date);
+
+ // read time
+ const int hour = toInt(&(buffer[10]), 2);
+ const int minute = toInt(&(buffer[12]), 2);
+ const int second = toInt(&(buffer[14]), 2);
+ QTime time(hour, minute, second);
+ timeStamp.setTime(time);
+
+ props.m_timeStamp = timeStamp;
+
+ int readCount = 16;
+ if (version >= 1) {
+ // read sorting type and sorting order
+ props.m_sorting = static_cast<DolphinView::Sorting>(buffer[16] - '0');
+ props.m_sortOrder = (buffer[17] == 'A') ? Qt::Ascending : Qt::Descending;
+ readCount = 18;
+ }
+
+ return (date.isValid() && time.isValid()) ? readCount : -1;
+}
+
+
diff --git a/src/viewproperties.h b/src/viewproperties.h
new file mode 100644
index 0000000..77f0a05
--- /dev/null
+++ b/src/viewproperties.h
@@ -0,0 +1,129 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef VIEWPROPERTIES_H
+#define VIEWPROPERTIES_H
+
+#include <dolphinview.h>
+#include <kurl.h>
+#include <qdatetime.h>
+class QFile;
+
+/**
+ * @short Maintains the view properties like 'view mode' or 'show hidden files' for a directory.
+ *
+ * The view properties are automatically stored inside
+ * the directory as hidden file called '.dolphinview'. To read out the view properties
+ * just construct an instance by passing the URL of the directory:
+ * \code
+ * ViewProperties props(KURL("/home/peter/Documents"));
+ * const DolphinView::Mode mode = props.viewMode();
+ * const bool showHiddenFiles = props.isShowHiddenFilesEnabled();
+ * \endcode
+ * When modifying a view property, the '.dolphinview' file is automatically updated
+ * inside the destructor.
+ *
+ * @author Peter Penz
+ */
+// TODO: provide detailed design description, as mapping the user model to
+// the physical modal is not trivial.
+class ViewProperties
+{
+public:
+ ViewProperties(KURL url);
+ virtual ~ViewProperties();
+
+ void setViewMode(DolphinView::Mode mode);
+ DolphinView::Mode viewMode() const;
+
+ void setShowHiddenFilesEnabled(bool show);
+ bool isShowHiddenFilesEnabled() const;
+
+ void setSorting(DolphinView::Sorting sorting);
+ DolphinView::Sorting sorting() const;
+
+ void setSortOrder(Qt::SortOrder sortOrder);
+ Qt::SortOrder sortOrder() const;
+
+ void setValidForSubDirs(bool valid);
+ bool isValidForSubDirs() const;
+
+ void setAutoSaveEnabled(bool autoSave);
+ bool isAutoSaveEnabled() const;
+
+ void updateTimeStamp();
+ void save();
+
+private:
+ class Properties
+ {
+ public:
+ Properties();
+ ~Properties(); // non virtual
+
+ bool m_showHiddenFiles;
+ DolphinView::Mode m_viewMode;
+ QDateTime m_timeStamp;
+ DolphinView::Sorting m_sorting;
+ Qt::SortOrder m_sortOrder;
+ };
+
+ class PropertiesNode
+ {
+ public:
+ PropertiesNode(QFile* file = 0);
+ ~PropertiesNode();
+ PropertiesNode& operator = (const PropertiesNode& node);
+ bool isEmpty() const { return m_empty; }
+
+ void setValidForSubDirs(bool valid) { m_isValidForSubDirs = valid; }
+ bool isValidForSubDirs() const { return m_isValidForSubDirs; }
+
+ void setLocalProperties(const Properties& props) { m_props = props; }
+ const Properties& localProperties() const { return m_props; }
+
+ void setShowHiddenFilesEnabled(bool show) { m_props.m_showHiddenFiles = show; }
+ void setViewMode(DolphinView::Mode mode) { m_props.m_viewMode = mode; }
+ void setTimeStamp(const QDateTime timeStamp) { m_props.m_timeStamp = timeStamp; }
+ const QDateTime& timeStamp() const { return m_props.m_timeStamp; }
+ void setSorting(DolphinView::Sorting sorting) { m_props.m_sorting = sorting; }
+ void setSortOrder(Qt::SortOrder sortOrder) { m_props.m_sortOrder = sortOrder; }
+
+ void setSubDirProperties(const Properties& props) { m_subDirProps = props; }
+ const Properties& subDirProperties() const { return m_subDirProps; }
+
+ private:
+ int toInt(const char* buffer, int count) const;
+ int readProperties(Properties& props, const char* buffer, int version);
+
+ bool m_empty;
+ bool m_isValidForSubDirs;
+ Properties m_props;
+ Properties m_subDirProps;
+ };
+
+ bool m_changedProps;
+ bool m_autoSave;
+ bool m_subDirValidityHidden;
+ QString m_filepath;
+ PropertiesNode m_node;
+};
+
+#endif
diff --git a/src/viewpropertiesdialog.cpp b/src/viewpropertiesdialog.cpp
new file mode 100644
index 0000000..0739ad8
--- /dev/null
+++ b/src/viewpropertiesdialog.cpp
@@ -0,0 +1,235 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "viewpropertiesdialog.h"
+#include <klocale.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qvbox.h>
+#include <qbuttongroup.h>
+#include <qcheckbox.h>
+#include <qradiobutton.h>
+#include <qpushbutton.h>
+#include <qsizepolicy.h>
+#include <qgroupbox.h>
+#include <qcombobox.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+#include <assert.h>
+
+#include "viewproperties.h"
+#include "dolphinview.h"
+
+ViewPropertiesDialog::ViewPropertiesDialog(DolphinView* dolphinView) :
+ KDialogBase(Plain, i18n("View Properties"),
+ Ok|Apply|Cancel, Ok),
+ m_isDirty(false),
+ m_dolphinView(dolphinView)
+{
+ assert(dolphinView != 0);
+
+ const int margin = KDialog::marginHint();
+ const QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+
+ const KURL& url = dolphinView->url();
+ m_viewProps = new ViewProperties(url);
+ m_viewProps->setAutoSaveEnabled(false);
+
+ QVBoxLayout* topLayout = new QVBoxLayout(plainPage(), 0, spacingHint());
+
+ // create 'Properties' group containing view mode, sorting, sort order and show hidden files
+ QGroupBox* propsGroup = new QGroupBox(2, Qt::Horizontal, i18n("Properties"), plainPage());
+ propsGroup->setSizePolicy(sizePolicy);
+ propsGroup->setMargin(margin);
+
+ new QLabel(i18n("View mode:"), propsGroup);
+ m_viewMode = new QComboBox(propsGroup);
+ m_viewMode->insertItem(SmallIcon("view_icon"), i18n("Icons"));
+ m_viewMode->insertItem(SmallIcon("view_text"), i18n("Details"));
+ m_viewMode->insertItem(SmallIcon("gvdirpart"), i18n("Previews"));
+ const int index = static_cast<int>(m_viewProps->viewMode());
+ m_viewMode->setCurrentItem(index);
+
+ new QLabel(i18n("Sorting:"), propsGroup);
+ m_sorting = new QComboBox(propsGroup);
+ m_sorting->insertItem("By Name");
+ m_sorting->insertItem("By Size");
+ m_sorting->insertItem("By Date");
+ int sortingIdx = 0;
+ switch (m_viewProps->sorting()) {
+ case DolphinView::SortByName: sortingIdx = 0; break;
+ case DolphinView::SortBySize: sortingIdx = 1; break;
+ case DolphinView::SortByDate: sortingIdx = 2; break;
+ default: break;
+ }
+ m_sorting->setCurrentItem(sortingIdx);
+
+ new QLabel(i18n("Sort order:"), propsGroup);
+ m_sortOrder = new QComboBox(propsGroup);
+ m_sortOrder->insertItem(i18n("Ascending"));
+ m_sortOrder->insertItem(i18n("Descending"));
+ const int sortOrderIdx = (m_viewProps->sortOrder() == Qt::Ascending) ? 0 : 1;
+ m_sortOrder->setCurrentItem(sortOrderIdx);
+
+ m_showHiddenFiles = new QCheckBox(i18n("Show hidden files"), propsGroup);
+ m_showHiddenFiles->setChecked(m_viewProps->isShowHiddenFilesEnabled());
+
+ // create 'Apply view properties to:' group
+ QButtonGroup* buttonGroup = new QButtonGroup(3,
+ Qt::Vertical,
+ i18n("Apply view properties to:"),
+ plainPage());
+ buttonGroup->setSizePolicy(sizePolicy);
+ buttonGroup->setMargin(margin);
+
+ m_applyToCurrentFolder = new QRadioButton(i18n("Current folder"), buttonGroup);
+ buttonGroup->insert(m_applyToCurrentFolder);
+
+ m_applyToSubFolders = new QRadioButton(i18n("Current folder including all sub folders"), buttonGroup);
+ buttonGroup->insert(m_applyToSubFolders);
+
+ m_applyToAllFolders = new QRadioButton(i18n("All folders"), buttonGroup);
+ buttonGroup->insert(m_applyToAllFolders);
+
+ if (m_viewProps->isValidForSubDirs()) {
+ m_applyToSubFolders->setChecked(true);
+ }
+ else {
+ m_applyToCurrentFolder->setChecked(true);
+ }
+
+ topLayout->addWidget(propsGroup);
+ topLayout->addWidget(buttonGroup);
+
+ connect(m_viewMode, SIGNAL(activated(int)),
+ this, SLOT(slotViewModeChanged(int)));
+ connect(m_sorting, SIGNAL(activated(int)),
+ this, SLOT(slotSortingChanged(int)));
+ connect(m_sortOrder, SIGNAL(activated(int)),
+ this, SLOT(slotSortOrderChanged(int)));
+ connect(m_showHiddenFiles, SIGNAL(clicked()),
+ this, SLOT(slotShowHiddenFilesChanged()));
+ connect(m_applyToCurrentFolder, SIGNAL(clicked()),
+ this, SLOT(slotApplyToCurrentFolder()));
+ connect(m_applyToSubFolders, SIGNAL(clicked()),
+ this, SLOT(slotApplyToSubFolders()));
+ connect(m_applyToAllFolders, SIGNAL(clicked()),
+ this, SLOT(slotApplyToAllFolders()));
+}
+
+ViewPropertiesDialog::~ViewPropertiesDialog()
+{
+ m_isDirty = false;
+ delete m_viewProps;
+ m_viewProps = 0;
+}
+
+void ViewPropertiesDialog::slotOk()
+{
+ applyViewProperties();
+ KDialogBase::slotOk();
+}
+
+void ViewPropertiesDialog::slotApply()
+{
+ applyViewProperties();
+ KDialogBase::slotApply();
+}
+
+void ViewPropertiesDialog::slotViewModeChanged(int index)
+{
+ assert((index >= 0) && (index <= 2));
+ m_viewProps->setViewMode(static_cast<DolphinView::Mode>(index));
+ m_isDirty = true;
+}
+
+void ViewPropertiesDialog::slotSortingChanged(int index)
+{
+ DolphinView::Sorting sorting = DolphinView::SortByName;
+ switch (index) {
+ case 1: sorting = DolphinView::SortBySize; break;
+ case 2: sorting = DolphinView::SortByDate; break;
+ default: break;
+ }
+ m_viewProps->setSorting(sorting);
+ m_isDirty = true;
+}
+
+void ViewPropertiesDialog::slotSortOrderChanged(int index)
+{
+ Qt::SortOrder sortOrder = (index == 0) ? Qt::Ascending : Qt::Descending;
+ m_viewProps->setSortOrder(sortOrder);
+ m_isDirty = true;
+}
+
+void ViewPropertiesDialog::slotShowHiddenFilesChanged()
+{
+ const bool show = m_showHiddenFiles->isChecked();
+ m_viewProps->setShowHiddenFilesEnabled(show);
+ m_isDirty = true;
+}
+
+void ViewPropertiesDialog::slotApplyToCurrentFolder()
+{
+ m_viewProps->setValidForSubDirs(false);
+ m_isDirty = true;
+}
+
+void ViewPropertiesDialog::slotApplyToSubFolders()
+{
+ m_viewProps->setValidForSubDirs(true);
+ m_isDirty = true;
+}
+
+void ViewPropertiesDialog::slotApplyToAllFolders()
+{
+ m_isDirty = true;
+}
+
+void ViewPropertiesDialog::applyViewProperties()
+{
+ if (m_applyToAllFolders->isChecked()) {
+ if (m_isDirty) {
+ const QString text(i18n("The view properties of all folders will be replaced. Do you want to continue?"));
+ if (KMessageBox::questionYesNo(this, text) == KMessageBox::No) {
+ return;
+ }
+ }
+
+ ViewProperties props(QDir::homeDirPath());
+ props.setViewMode(m_viewProps->viewMode());
+ props.setSorting(m_viewProps->sorting());
+ props.setSortOrder(m_viewProps->sortOrder());
+ props.setShowHiddenFilesEnabled(m_viewProps->isShowHiddenFilesEnabled());
+ props.setValidForSubDirs(true);
+ }
+ else if (m_applyToSubFolders->isChecked() && m_isDirty) {
+ const QString text(i18n("The view properties of all sub folders will be replaced. Do you want to continue?"));
+ if (KMessageBox::questionYesNo(this, text) == KMessageBox::No) {
+ return;
+ }
+ }
+
+ m_viewProps->save();
+ m_dolphinView->setViewProperties(*m_viewProps);
+ m_isDirty = false;
+}
+
+#include "viewpropertiesdialog.moc"
diff --git a/src/viewpropertiesdialog.h b/src/viewpropertiesdialog.h
new file mode 100644
index 0000000..0731a27
--- /dev/null
+++ b/src/viewpropertiesdialog.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+#ifndef VIEWPROPERTIESDIALOG_H
+#define VIEWPROPERTIESDIALOG_H
+
+#include <kdialogbase.h>
+
+class QCheckBox;
+class QButtonGroup;
+class QComboBox;
+class QRadioButton;
+class ViewProperties;
+class DolphinView;
+
+/**
+ * @brief Dialog for changing the current view properties of a directory.
+ *
+ * It is possible to specify the view mode and whether hidden files
+ * should be shown. The properties can be assigned to the current folder,
+ * recursively to all sub folders or to all folders.
+ *
+ * @author Peter Penz
+ */
+class ViewPropertiesDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ ViewPropertiesDialog(DolphinView* dolphinView);
+ virtual ~ViewPropertiesDialog();
+
+protected slots:
+ virtual void slotOk();
+ virtual void slotApply();
+
+private slots:
+ void slotViewModeChanged(int index);
+ void slotSortingChanged(int index);
+ void slotSortOrderChanged(int index);
+ void slotShowHiddenFilesChanged();
+ void slotApplyToCurrentFolder();
+ void slotApplyToSubFolders();
+ void slotApplyToAllFolders();
+
+private:
+ bool m_isDirty;
+ DolphinView* m_dolphinView;
+ ViewProperties* m_viewProps;
+
+ QComboBox* m_viewMode;
+ QComboBox* m_sorting;
+ QComboBox* m_sortOrder;
+ QCheckBox* m_showHiddenFiles;
+ QRadioButton* m_applyToCurrentFolder;
+ QRadioButton* m_applyToSubFolders;
+ QRadioButton* m_applyToAllFolders;
+
+ void applyViewProperties();
+};
+
+#endif
diff --git a/src/viewsettingspage.cpp b/src/viewsettingspage.cpp
new file mode 100644
index 0000000..ccfa80e
--- /dev/null
+++ b/src/viewsettingspage.cpp
@@ -0,0 +1,66 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "viewsettingspage.h"
+#include <qtabwidget.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <kdialogbase.h>
+#include <klocale.h>
+#include "iconsviewsettingspage.h"
+#include "detailsviewsettingspage.h"
+
+ViewSettingsPage::ViewSettingsPage(QWidget *parent) :
+ SettingsPageBase(parent),
+ m_iconsPage(0),
+ m_detailsPage(0),
+ m_previewsPage(0)
+{
+ QVBoxLayout* topLayout = new QVBoxLayout(parent, 0, KDialog::spacingHint());
+
+ QTabWidget* tabWidget = new QTabWidget(parent);
+
+ // initialize 'Icons' tab
+ m_iconsPage = new IconsViewSettingsPage(DolphinIconsView::Icons, tabWidget);
+ tabWidget->addTab(m_iconsPage, SmallIcon("view_icon"), i18n("Icons"));
+
+ // initialize 'Details' tab
+ m_detailsPage = new DetailsViewSettingsPage(tabWidget);
+ tabWidget->addTab(m_detailsPage, SmallIcon("view_text"), i18n("Details"));
+
+ // initialize 'Previews' tab
+ m_previewsPage = new IconsViewSettingsPage(DolphinIconsView::Previews, tabWidget);
+ tabWidget->addTab(m_previewsPage, SmallIcon("gvdirpart"), i18n("Previews"));
+
+ topLayout->addWidget(tabWidget, 0, 0 );
+}
+
+ViewSettingsPage::~ViewSettingsPage()
+{
+}
+
+void ViewSettingsPage::applySettings()
+{
+ m_iconsPage->applySettings();
+ m_detailsPage->applySettings();
+ m_previewsPage->applySettings();
+}
+
+#include "viewsettingspage.moc"
diff --git a/src/viewsettingspage.h b/src/viewsettingspage.h
new file mode 100644
index 0000000..06017dd
--- /dev/null
+++ b/src/viewsettingspage.h
@@ -0,0 +1,55 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+#ifndef VIEWSETTINGSPAGE_H
+#define VIEWSETTINGSPAGE_H
+
+#include <qwidget.h>
+#include <settingspagebase.h>
+
+class IconsViewSettingsPage;
+class DetailsViewSettingsPage;
+
+/**
+ * @brief Page for the 'View' settings of the Dolphin settings dialog.
+ *
+ * The vies settings allow to set the properties for the icons mode,
+ * the details mode and the previews mode.
+ *
+ * @author Peter Penz <[email protected]>
+ */
+class ViewSettingsPage : public SettingsPageBase
+{
+ Q_OBJECT
+
+public:
+ ViewSettingsPage(QWidget* parent);
+
+ virtual ~ViewSettingsPage();
+
+ /** @see SettingsPageBase::applySettings */
+ virtual void applySettings();
+
+private:
+ IconsViewSettingsPage* m_iconsPage;
+ DetailsViewSettingsPage* m_detailsPage;
+ IconsViewSettingsPage* m_previewsPage;
+};
+
+#endif