summaryrefslogtreecommitdiffstats
path: root/libkonq
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commit4aed2c8219774f5d797760606b8489a92ddc5163 (patch)
tree3f8c130f7d269626bf6a9447407ef6c35954426a /libkonq
downloadtdebase-4aed2c8219774f5d797760606b8489a92ddc5163.tar.gz
tdebase-4aed2c8219774f5d797760606b8489a92ddc5163.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdebase@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'libkonq')
-rw-r--r--libkonq/AUTHORS7
-rw-r--r--libkonq/DESIGN46
-rw-r--r--libkonq/Makefile.am72
-rw-r--r--libkonq/PLUGINS13
-rw-r--r--libkonq/SERVICEMENUS52
-rw-r--r--libkonq/directory_bookmarkbar.desktop83
-rw-r--r--libkonq/favicons/Makefile.am15
-rw-r--r--libkonq/favicons/favicons.cpp275
-rw-r--r--libkonq/favicons/favicons.desktop148
-rw-r--r--libkonq/favicons/favicons.h105
-rw-r--r--libkonq/favicons/favicons.upd3
-rwxr-xr-xlibkonq/favicons/move_favicons.sh41
-rw-r--r--libkonq/kfileivi.cc477
-rw-r--r--libkonq/kfileivi.h239
-rw-r--r--libkonq/kivdirectoryoverlay.cc141
-rw-r--r--libkonq/kivdirectoryoverlay.h58
-rw-r--r--libkonq/knewmenu.cc621
-rw-r--r--libkonq/knewmenu.h224
-rw-r--r--libkonq/konq_bgnddlg.cc211
-rw-r--r--libkonq/konq_bgnddlg.h74
-rw-r--r--libkonq/konq_defaults.h48
-rw-r--r--libkonq/konq_dirpart.cc746
-rw-r--r--libkonq/konq_dirpart.h351
-rw-r--r--libkonq/konq_drag.cc284
-rw-r--r--libkonq/konq_drag.h122
-rw-r--r--libkonq/konq_events.cc8
-rw-r--r--libkonq/konq_events.h70
-rw-r--r--libkonq/konq_faviconmgr.cc57
-rw-r--r--libkonq/konq_faviconmgr.h70
-rw-r--r--libkonq/konq_filetip.cc300
-rw-r--r--libkonq/konq_filetip.h97
-rw-r--r--libkonq/konq_historycomm.cc41
-rw-r--r--libkonq/konq_historycomm.h77
-rw-r--r--libkonq/konq_historymgr.cc733
-rw-r--r--libkonq/konq_historymgr.h385
-rw-r--r--libkonq/konq_iconviewwidget.cc1927
-rw-r--r--libkonq/konq_iconviewwidget.h370
-rw-r--r--libkonq/konq_operations.cc817
-rw-r--r--libkonq/konq_operations.h215
-rw-r--r--libkonq/konq_pixmapprovider.cc201
-rw-r--r--libkonq/konq_pixmapprovider.h81
-rw-r--r--libkonq/konq_popupmenu.cc1205
-rw-r--r--libkonq/konq_popupmenu.h221
-rw-r--r--libkonq/konq_propsview.cc584
-rw-r--r--libkonq/konq_propsview.h185
-rw-r--r--libkonq/konq_settings.cc184
-rw-r--r--libkonq/konq_settings.h141
-rw-r--r--libkonq/konq_sound.cc137
-rw-r--r--libkonq/konq_sound.h35
-rw-r--r--libkonq/konq_undo.cc667
-rw-r--r--libkonq/konq_undo.h162
-rw-r--r--libkonq/konq_xmlguiclient.cc157
-rw-r--r--libkonq/konq_xmlguiclient.h70
-rw-r--r--libkonq/konqbookmarkmanager.h24
-rw-r--r--libkonq/konqpopupmenuplugin.desktop76
-rw-r--r--libkonq/libkonq_export.h39
-rw-r--r--libkonq/pics/Makefile.am2
-rw-r--r--libkonq/pics/arrow_bottomleft.pngbin0 -> 163 bytes
-rw-r--r--libkonq/pics/arrow_bottomright.pngbin0 -> 163 bytes
-rw-r--r--libkonq/pics/arrow_topleft.pngbin0 -> 163 bytes
-rw-r--r--libkonq/pics/arrow_topright.pngbin0 -> 161 bytes
-rw-r--r--libkonq/pics/thumbnailfont_7x4.pngbin0 -> 965 bytes
-rw-r--r--libkonq/tests/Makefile.am6
-rw-r--r--libkonq/tests/konqdragtest.cpp62
64 files changed, 13862 insertions, 0 deletions
diff --git a/libkonq/AUTHORS b/libkonq/AUTHORS
new file mode 100644
index 000000000..e33d1edd6
--- /dev/null
+++ b/libkonq/AUTHORS
@@ -0,0 +1,7 @@
+The classes in this library were written by:
+Torben Weis <weis@kde.org>
+David Faure <faure@kde.org>
+Simon Hausmann <hausmann@kde.org>
+Holger Freyther <freyther@yahoo.com>
+and are all available under the LGPL license.
+See the individual files for more.
diff --git a/libkonq/DESIGN b/libkonq/DESIGN
new file mode 100644
index 000000000..0f9fa893b
--- /dev/null
+++ b/libkonq/DESIGN
@@ -0,0 +1,46 @@
+libkonq is the construction kit for a file manager
+(together with libkio, which is at a lower level)
+
+It is used by konqueror, of course, but also by kdesktop, which is
+another file manager in fact, and by apps that want to use
+the properties dialog boxes (like kpanel and kfind) or the bookmark
+classes.
+
+libkonq contents :
+==================
+
+1) menus
+kbookmark.* : general purpose bookmark class
+kbookmarkmenu.* : bookmark menu
+kbookmarkbar.* : bookmark bar
+konq_popupmenu.*: popupmenu for URLs
+konq_xmlguiclient.* : general purpose xmlgui manipulating class
+knewmenu.* : implements the 'new' menu (file templates)
+
+2) files
+konq_operations.*: common operations to all views, like deleting files, and
+ dropping files.
+konq_undo.* : undo feature for file operations
+
+3) icons
+kfileivi.* : icon representing a file (inherits QListViewItem and
+ uses KFileItem for holding file information)
+konq_iconviewwidget.* : the specialisation of QIconView that knows about files.
+ Basic widget for icon views in konqueror and kdesktop.
+konq_drag.* : the drag object for konqiconviewwidget (adds text/uri-list
+ support to QIconView's drag object).
+
+4) configuration
+konq_propsview.* : view properties (global and per-directory)
+konq_settings.* : settings
+konq_defaults.h : default values, shared with kcmkonq
+
+5) directory views
+konq_dirpart.* : base class for directory views
+konq_bgnddlg.* : background chosing dialog
+
+6) other
+konq_events.* : events sent by konqueror, for use by the views [& metaviews]
+
+7) plugin interface
+konq_popupmenu.h : class KonqPopupMenuPlugin
diff --git a/libkonq/Makefile.am b/libkonq/Makefile.am
new file mode 100644
index 000000000..b93f3395a
--- /dev/null
+++ b/libkonq/Makefile.am
@@ -0,0 +1,72 @@
+# This file is part of the KDE libraries
+# Copyright (C) 1997 David Faure <faure@kde.org>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library 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
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public License
+# along with this library; see the file COPYING.LIB. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301, USA.
+
+INCLUDES = -I$(kde_includes)/arts $(all_includes)
+SUBDIRS = pics favicons
+
+lib_LTLIBRARIES = libkonq.la
+libkonq_la_LDFLAGS = $(all_libraries) -version-info 6:0:2 -no-undefined
+libkonq_la_LIBADD = $(LIB_KPARTS)
+
+libkonq_la_SOURCES = konq_popupmenu.cc knewmenu.cc \
+ konq_xmlguiclient.cc\
+ kfileivi.cc konq_iconviewwidget.cc konq_settings.cc konq_drag.cc \
+ konq_operations.cc \
+ konq_dirpart.cc konq_propsview.cc konq_events.cc konq_bgnddlg.cc \
+ konq_undo.cc konq_undo.skel \
+ konq_historymgr.cc konq_historycomm.cc konq_historycomm.skel \
+ konq_pixmapprovider.cc \
+ kivdirectoryoverlay.cc \
+ konq_faviconmgr.cc konq_faviconmgr.skel konq_filetip.cc
+
+directory_DATA = directory_bookmarkbar.desktop
+directorydir = $(kde_datadir)/kbookmark
+
+servicetype_DATA = konqpopupmenuplugin.desktop
+servicetypedir = $(kde_servicetypesdir)
+
+METASOURCES = AUTO
+
+include_HEADERS = konq_popupmenu.h knewmenu.h \
+ kfileivi.h konq_drag.h konq_iconviewwidget.h \
+ konq_defaults.h konq_settings.h \
+ konq_operations.h libkonq_export.h \
+ konq_dirpart.h konq_propsview.h konq_events.h \
+ konq_undo.h konq_historymgr.h konq_historycomm.h \
+ konq_pixmapprovider.h \
+ kivdirectoryoverlay.h \
+ konq_faviconmgr.h konq_xmlguiclient.h konqbookmarkmanager.h konq_filetip.h
+
+
+if include_ARTS
+ARTS_MODULE = konq_sound.la
+endif
+
+kde_module_LTLIBRARIES = $(ARTS_MODULE)
+konq_sound_la_SOURCES = konq_sound.cc
+konq_sound_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+konq_sound_la_LIBADD = -lsoundserver_idl -lartskde
+
+noinst_HEADERS = konq_sound.h
+
+messages:
+ $(XGETTEXT) *.cc *.h -o $(podir)/libkonq.pot
+
+DOXYGEN_REFERENCES = dcop kdecore kio/bookmarks
+include ../admin/Doxyfile.am
+
diff --git a/libkonq/PLUGINS b/libkonq/PLUGINS
new file mode 100644
index 000000000..4eb535a59
--- /dev/null
+++ b/libkonq/PLUGINS
@@ -0,0 +1,13 @@
+Thus file explains how to add plugins into the konqpopupmenu
+used by konqueror and kdesktop.
+
+Why?
+Why do we need this kind of functionality? We do have SERVICEMENUS.
+A plugin can be much more dynamic. If you want to add features that
+are runtime specific or need some interaction with different things
+a plugin comes in handy
+
+How?
+Please look at ?no_location? to get the latest plugin template
+
+Holger Freyther 30th October 2001 \ No newline at end of file
diff --git a/libkonq/SERVICEMENUS b/libkonq/SERVICEMENUS
new file mode 100644
index 000000000..1419b86e0
--- /dev/null
+++ b/libkonq/SERVICEMENUS
@@ -0,0 +1,52 @@
+This file explains how to add an item in the popupmenu (for both
+konqueror and kdesktop), without using the file associations.
+
+Why
+===
+One reason for doing this is being able to associate
+some action with all files without this action becoming a default handler
+(called on left click).
+Another is that for text-based programs and tools (e.g. gzip) it's faster
+than defining a desktop file for the application, making it hidden, and
+associate it with the relevant file types.
+
+How
+===
+Create a file ~/.kde/share/apps/konqueror/servicemenus/something.desktop
+and write into it something like (without the comments) :
+
+[Desktop Entry]
+ServiceTypes=text/html,text/plain # use all/all for all entries
+ # all/allfiles for files only
+ # and use inode/directory for dirs only
+ # you can also do things like image/* for all
+ # image mimetypes
+Actions=gzip;mail # those are ';' separated, per the standard !
+X-KDE-Submenu=Menuname # this optional entry allows grouping the
+ # entries in this servicemenu file into a
+ # common submenu, in this case "Menuname"
+TryExec=gzip # Find if executable exist, if it doesn't exist
+ # menu entry is not displaying
+ExcludeServiceTypes=application/x-zip # This entry is used to avoid to display menu
+ # when it's a specific servicetype
+ # for exemple when we use all/allfiles and zip
+ # them, we don't want to zip a zip file
+
+
+[Desktop Action gzip] # One "Desktop Action <name>" group per Action
+Name=GZip this file
+Name[fr]=...
+Icon=tgz
+Exec=gzip %f
+
+[Desktop Action mail]
+Name=Mail this file
+Name[fr]=...
+Icon=kmail
+Exec=kmail --there-is-no-such-option-yet %f
+
+
+See also the "desktop entry standard", which defines more formally the same
+concept of actions but for desktop files (e.g. eject on a device desktop file,
+etc.)
+
diff --git a/libkonq/directory_bookmarkbar.desktop b/libkonq/directory_bookmarkbar.desktop
new file mode 100644
index 000000000..93c7e9012
--- /dev/null
+++ b/libkonq/directory_bookmarkbar.desktop
@@ -0,0 +1,83 @@
+[Desktop Entry]
+Icon=bookmark_toolbar
+Name=Bookmark Toolbar
+Name[af]=Boekmerk Nutsbalk
+Name[ar]=شريط أدوات علامات المواقع
+Name[az]=Vasitə Çubuğu Dəftəri
+Name[be]=Панэль закладак
+Name[bg]=Лента с отметки
+Name[bn]=বুকমার্ক টুলবার
+Name[br]=Barrenn ostilhoù sined
+Name[bs]=Traka s zabilješkama
+Name[ca]=Barra d'eines de punts
+Name[cs]=Lišta se záložkami
+Name[csb]=Lëstew załóżków
+Name[cy]=Bar Offer Nodau Tudalen
+Name[da]=Bogmærkeværktøjslinje
+Name[de]=Lesezeichenleiste
+Name[el]=Γραμμή εργαλείων Σελιδοδεικτών
+Name[eo]=Legosigno-ilobreto
+Name[es]=Barra de herramientas de marcadores
+Name[et]=Järjehoidjate tööriistariba
+Name[eu]=Laster-marka barra
+Name[fa]=میله ابزار چوب الف
+Name[fi]=Kirjanmerkkien työkalurivi
+Name[fo]=Bókamerkisamboðsbjálki
+Name[fr]=Barre de signets
+Name[fy]=Blêdwizerbalke
+Name[ga]=Barra Uirlisí Leabharmharcanna
+Name[gl]=Barra de Marcadores
+Name[he]=סרגל הסימניות
+Name[hi]=औज़ार-पट्टी पसंद
+Name[hr]=Traka s oznakama
+Name[hu]=Könyvjelző-eszköztár
+Name[id]=Toolbar Bookmark
+Name[is]=Bókamerkjaslá
+Name[it]=Barra dei segnalibri
+Name[ja]=ブックマークツールバー
+Name[ka]=სანიშნეთა პანელი
+Name[kk]=Бетбелгі панелі
+Name[km]=របារ​ឧបករណ៍​ចំណាំ
+Name[ko]=책갈피 도구 모음
+Name[lo]=ແຖບເຄື່ອງມືທີ່ຄັ້ນປື້ນ
+Name[lt]=Žymelių įrankių juosta
+Name[lv]=Grāmatzīmju Rīkjosla
+Name[mk]=Алатник за обележувачи
+Name[mn]=Хавчуурга-самбар
+Name[ms]=Bar Alatan Penandabuku
+Name[mt]=Toolbar tal-Favoriti
+Name[nb]=Bokmerkeverktøy
+Name[nds]=Leesteken-Warktüüchbalken
+Name[ne]=पुस्तकचिनो उपकरणपट्टी
+Name[nl]=Bladwijzer - werkbalk
+Name[nn]=Bokmerke-verktøylinje
+Name[nso]=Bar ya Sebereka sa Tshwao ya Buka
+Name[oc]=Otilh de puents
+Name[pa]=ਬੁੱਕਮਾਰਕ ਸੰਦਪੱਟੀ
+Name[pl]=Pasek zakładek
+Name[pt]=Barra de Favoritos
+Name[pt_BR]=Barra de Ferramenta de Favoritos
+Name[ro]=Bară semne de carte
+Name[ru]=Панель закладок
+Name[rw]=Umwanyabikoresho w'Akamenyetso
+Name[se]=Girjemearkaholga
+Name[sk]=Panel záložiek
+Name[sl]=Orodna vrstica z zaznamki
+Name[sr]=Трака са маркерима
+Name[sr@Latn]=Traka sa markerima
+Name[sv]=Verktygsrad med bokmärken
+Name[ta]=புத்தகக்குறிக் கருவிப்பட்டை
+Name[tg]=Панели поягузорӣ
+Name[th]=แถบเครื่องมือที่คั่นหน้า
+Name[tr]=Araç Çubuğu Defteri
+Name[tt]=Bitbilge Tiräse
+Name[uk]=Панель закладок
+Name[uz]=Xatchoʻp paneli
+Name[uz@cyrillic]=Хатчўп панели
+Name[ven]=Bara ya tshishumiswa tsha tswayo ya bugu
+Name[vi]=Thanh công cụ Lưu địa chỉ
+Name[wa]=Bår ås usteyes des rmåkes
+Name[xh]=Ibar yesixhobo Senqaku lencwadi
+Name[zh_CN]=书签工具栏
+Name[zh_TW]=書籤工具列
+Name[zu]=Ibha yamathuluzi yomaka bencwadi
diff --git a/libkonq/favicons/Makefile.am b/libkonq/favicons/Makefile.am
new file mode 100644
index 000000000..a53c7faf1
--- /dev/null
+++ b/libkonq/favicons/Makefile.am
@@ -0,0 +1,15 @@
+kde_module_LTLIBRARIES = kded_favicons.la
+
+INCLUDES = $(all_includes)
+kded_favicons_la_SOURCES = favicons.cpp favicons.skel
+kded_favicons_la_LDFLAGS = $(all_libraries) -module -avoid-version
+kded_favicons_la_LIBADD = $(LIB_KSYCOCA)
+
+METASOURCES = AUTO
+
+servicesdir = $(kde_servicesdir)/kded
+services_DATA = favicons.desktop
+
+update_DATA = favicons.upd
+update_SCRIPTS = move_favicons.sh
+updatedir = $(kde_datadir)/kconf_update
diff --git a/libkonq/favicons/favicons.cpp b/libkonq/favicons/favicons.cpp
new file mode 100644
index 000000000..9419b4b03
--- /dev/null
+++ b/libkonq/favicons/favicons.cpp
@@ -0,0 +1,275 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Malte Starostik <malte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <string.h>
+#include <time.h>
+
+#include <qbuffer.h>
+#include <qfile.h>
+#include <qcache.h>
+#include <qimage.h>
+#include <qtimer.h>
+
+#include <kdatastream.h> // DO NOT REMOVE, otherwise bool marshalling breaks
+#include <kicontheme.h>
+#include <kimageio.h>
+#include <ksimpleconfig.h>
+#include <kstandarddirs.h>
+#include <kio/job.h>
+
+#include "favicons.moc"
+
+struct FaviconsModulePrivate
+{
+ virtual ~FaviconsModulePrivate() { delete config; }
+
+ struct DownloadInfo
+ {
+ QString hostOrURL;
+ bool isHost;
+ QByteArray iconData;
+ };
+ QMap<KIO::Job *, DownloadInfo> downloads;
+ QStringList failedDownloads;
+ KSimpleConfig *config;
+ QPtrList<KIO::Job> killJobs;
+ KIO::MetaData metaData;
+ QString faviconsDir;
+ QCache<QString> faviconsCache;
+};
+
+FaviconsModule::FaviconsModule(const QCString &obj)
+ : KDEDModule(obj)
+{
+ // create our favicons folder so that KIconLoader knows about it
+ d = new FaviconsModulePrivate;
+ d->faviconsDir = KGlobal::dirs()->saveLocation( "cache", "favicons/" );
+ d->faviconsDir.truncate(d->faviconsDir.length()-9); // Strip off "favicons/"
+ d->metaData.insert("ssl_no_client_cert", "TRUE");
+ d->metaData.insert("ssl_militant", "TRUE");
+ d->metaData.insert("UseCache", "false");
+ d->metaData.insert("cookies", "none");
+ d->metaData.insert("no-auth", "true");
+ d->config = new KSimpleConfig(locateLocal("data", "konqueror/faviconrc"));
+ d->killJobs.setAutoDelete(true);
+ d->faviconsCache.setAutoDelete(true);
+}
+
+FaviconsModule::~FaviconsModule()
+{
+ delete d;
+}
+
+QString removeSlash(QString result)
+{
+ for (unsigned int i = result.length() - 1; i > 0; --i)
+ if (result[i] != '/')
+ {
+ result.truncate(i + 1);
+ break;
+ }
+
+ return result;
+}
+
+
+QString FaviconsModule::iconForURL(const KURL &url)
+{
+ if (url.host().isEmpty())
+ return QString::null;
+
+ QString icon;
+ QString simplifiedURL = simplifyURL(url);
+
+ QString *iconURL = d->faviconsCache.find( removeSlash(simplifiedURL) );
+ if (iconURL)
+ icon = *iconURL;
+ else
+ icon = d->config->readEntry( removeSlash(simplifiedURL) );
+
+ if (!icon.isEmpty())
+ icon = iconNameFromURL(KURL( icon ));
+ else
+ icon = url.host();
+
+ icon = "favicons/" + icon;
+
+ if (QFile::exists(d->faviconsDir+icon+".png"))
+ return icon;
+
+ return QString::null;
+}
+
+QString FaviconsModule::simplifyURL(const KURL &url)
+{
+ // splat any = in the URL so it can be safely used as a config key
+ QString result = url.host() + url.path();
+ for (unsigned int i = 0; i < result.length(); ++i)
+ if (result[i] == '=')
+ result[i] = '_';
+ return result;
+}
+
+QString FaviconsModule::iconNameFromURL(const KURL &iconURL)
+{
+ if (iconURL.path() == "/favicon.ico")
+ return iconURL.host();
+
+ QString result = simplifyURL(iconURL);
+ // splat / so it can be safely used as a file name
+ for (unsigned int i = 0; i < result.length(); ++i)
+ if (result[i] == '/')
+ result[i] = '_';
+
+ QString ext = result.right(4);
+ if (ext == ".ico" || ext == ".png" || ext == ".xpm")
+ result.remove(result.length() - 4, 4);
+
+ return result;
+}
+
+bool FaviconsModule::isIconOld(const QString &icon)
+{
+ struct stat st;
+ if (stat(QFile::encodeName(icon), &st) != 0)
+ return true; // Trigger a new download on error
+
+ return (time(0) - st.st_mtime) > 604800; // arbitrary value (one week)
+}
+
+void FaviconsModule::setIconForURL(const KURL &url, const KURL &iconURL)
+{
+ QString simplifiedURL = simplifyURL(url);
+
+ d->faviconsCache.insert(removeSlash(simplifiedURL), new QString(iconURL.url()) );
+
+ QString iconName = "favicons/" + iconNameFromURL(iconURL);
+ QString iconFile = d->faviconsDir + iconName + ".png";
+
+ if (!isIconOld(iconFile)) {
+ emit iconChanged(false, simplifiedURL, iconName);
+ return;
+ }
+
+ startDownload(simplifiedURL, false, iconURL);
+}
+
+void FaviconsModule::downloadHostIcon(const KURL &url)
+{
+ QString iconFile = d->faviconsDir + "favicons/" + url.host() + ".png";
+ if (!isIconOld(iconFile))
+ return;
+
+ startDownload(url.host(), true, KURL(url, "/favicon.ico"));
+}
+
+void FaviconsModule::startDownload(const QString &hostOrURL, bool isHost, const KURL &iconURL)
+{
+ if (d->failedDownloads.contains(iconURL.url()))
+ return;
+
+ KIO::Job *job = KIO::get(iconURL, false, false);
+ job->addMetaData(d->metaData);
+ connect(job, SIGNAL(data(KIO::Job *, const QByteArray &)), SLOT(slotData(KIO::Job *, const QByteArray &)));
+ connect(job, SIGNAL(result(KIO::Job *)), SLOT(slotResult(KIO::Job *)));
+ connect(job, SIGNAL(infoMessage(KIO::Job *, const QString &)), SLOT(slotInfoMessage(KIO::Job *, const QString &)));
+ FaviconsModulePrivate::DownloadInfo download;
+ download.hostOrURL = hostOrURL;
+ download.isHost = isHost;
+ d->downloads.insert(job, download);
+}
+
+void FaviconsModule::slotData(KIO::Job *job, const QByteArray &data)
+{
+ FaviconsModulePrivate::DownloadInfo &download = d->downloads[job];
+ unsigned int oldSize = download.iconData.size();
+ if (oldSize > 0x10000)
+ {
+ d->killJobs.append(job);
+ QTimer::singleShot(0, this, SLOT(slotKill()));
+ }
+ download.iconData.resize(oldSize + data.size());
+ memcpy(download.iconData.data() + oldSize, data.data(), data.size());
+}
+
+void FaviconsModule::slotResult(KIO::Job *job)
+{
+ FaviconsModulePrivate::DownloadInfo download = d->downloads[job];
+ d->downloads.remove(job);
+ KURL iconURL = static_cast<KIO::TransferJob *>(job)->url();
+ QString iconName;
+ if (!job->error())
+ {
+ QBuffer buffer(download.iconData);
+ buffer.open(IO_ReadOnly);
+ QImageIO io;
+ io.setIODevice(&buffer);
+ io.setParameters("size=16");
+ // Check here too, the job might have had no error, but the downloaded
+ // file contains just a 404 message sent with a 200 status.
+ // microsoft.com does that... (malte)
+ if (io.read())
+ {
+ // Some sites have nasty 32x32 icons, according to the MS docs
+ // IE ignores them, well, we scale them, otherwise the location
+ // combo / menu will look quite ugly
+ if (io.image().width() != KIcon::SizeSmall || io.image().height() != KIcon::SizeSmall)
+ io.setImage(io.image().smoothScale(KIcon::SizeSmall, KIcon::SizeSmall));
+
+ if (download.isHost)
+ iconName = download.hostOrURL;
+ else
+ iconName = iconNameFromURL(iconURL);
+
+ iconName = "favicons/" + iconName;
+
+ io.setIODevice(0);
+ io.setFileName(d->faviconsDir + iconName + ".png");
+ io.setFormat("PNG");
+ if (!io.write())
+ iconName = QString::null;
+ else if (!download.isHost)
+ d->config->writeEntry( removeSlash(download.hostOrURL), iconURL.url());
+ }
+ }
+ if (iconName.isEmpty())
+ d->failedDownloads.append(iconURL.url());
+
+ emit iconChanged(download.isHost, download.hostOrURL, iconName);
+}
+
+void FaviconsModule::slotInfoMessage(KIO::Job *job, const QString &msg)
+{
+ emit infoMessage(static_cast<KIO::TransferJob *>( job )->url(), msg);
+}
+
+void FaviconsModule::slotKill()
+{
+ d->killJobs.clear();
+}
+
+extern "C" {
+ KDE_EXPORT KDEDModule *create_favicons(const QCString &obj)
+ {
+ KImageIO::registerFormats();
+ return new FaviconsModule(obj);
+ }
+}
+
+// vim: ts=4 sw=4 et
diff --git a/libkonq/favicons/favicons.desktop b/libkonq/favicons/favicons.desktop
new file mode 100644
index 000000000..7a7042057
--- /dev/null
+++ b/libkonq/favicons/favicons.desktop
@@ -0,0 +1,148 @@
+[Desktop Entry]
+Type=Service
+Name=KDED Favicon Module
+Name[af]=Kded Favicon Module
+Name[ar]=وحدة KDED لأيقونة الموقع
+Name[az]=KDED Favikon Modulu
+Name[be]=Модуль любімай значкі KDED
+Name[bn]=KDED ফ্যাভ-আইকন মডিউল
+Name[br]=Mollad Favicon evit KDED
+Name[bs]=KDED Favicon modul
+Name[ca]=Mòdul KDED per a favicon
+Name[cs]=Modul KDEDu Favicon
+Name[csb]=Ikònczi serwerów
+Name[cy]=Modiwl KDED Favicon
+Name[da]=KDED Favicon-modul
+Name[de]=Webseitensymbol-Verwaltung
+Name[el]=KDED άρθρωμα Favicon
+Name[eo]=Modulo por interretaj piktogramoj
+Name[es]=Módulo Favicon de KDED
+Name[et]=KDED favicon moodul
+Name[eu]=KDED Favicon modulua
+Name[fa]=پیمانۀ شمایل پسندان KDED
+Name[fi]=KDED-sivustokuvakemoduuli
+Name[fr]=Icône préférée
+Name[gl]=Módulo de Faviconas de KDED
+Name[he]=מודול סמלים מועדפים של KDED
+Name[hi]=केडीईडी फेविकॉन मॉड्यूल
+Name[hr]=KDED Favicon modul
+Name[hu]=KDED favicon-kezelő
+Name[id]=Modul Favicon KDE
+Name[is]=KDED Favicon íhlutur
+Name[it]=Modulo Favicon di KDED
+Name[ja]=KDED Favicon モジュール
+Name[ka]=KDED Favicon მოდული
+Name[kk]=KDED сайт белгішілер модулі
+Name[km]=ម៉ូឌុល KDED Favicon
+Name[ko]=KDED 파비콘 모듈
+Name[lo]=ໂມດລູໄອຄອນ KDED
+Name[lt]=KDED favicon modulis
+Name[lv]=KDED Favikon Modulis
+Name[mk]=KDED Favicon Модул
+Name[mn]=Favicon-Модул
+Name[ms]=Modul KDED Favicon
+Name[mt]=Modulu "favicon" KDED
+Name[nb]=KDED favicon-modul
+Name[nds]=KDED-Moduul för Nettsiet-Lüttbiller
+Name[ne]=KDED फेभिकन मोड्युल
+Name[nn]=KDED favicon-modul
+Name[nso]=Seripa sa Favicon ya KDE
+Name[pa]=KDED ਫਾਵੀਕੋਨ ਮੋਡੁਲੀ
+Name[pl]=Ikony serwerów
+Name[pt]=Módulo Favicon do KDED
+Name[pt_BR]=Módulo Favicon do KDE
+Name[ro]=Module favicon KDED
+Name[ru]=Служба значков
+Name[rw]=Igice KDED Favicon
+Name[se]=KDED favicon-moduvla
+Name[sk]=Modul KDED Favicon
+Name[sl]=Modul KDED za favicon
+Name[sr]=Favicon модул, KDED
+Name[sr@Latn]=Favicon modul, KDED
+Name[sv]=KDED-favoritikonmodul
+Name[ta]=KDED பெவிகான் பகுதி
+Name[tg]=Бахши пиктограммаи KDED
+Name[th]=โมดูลไอคอนเว็บของ KDED
+Name[tr]=KDE Favicon Modülü
+Name[tt]=KDED İkon Module
+Name[uk]=Модуль KDED Favicon
+Name[uz]=KDED Favicon moduli
+Name[uz@cyrillic]=KDED Favicon модули
+Name[ven]=Modulu wa KDED wa Favikhono
+Name[vi]=Mô đun KDED Favicon
+Name[wa]=Module imådjetes KDED
+Name[xh]=KDED Isichatshulwa se Favicon
+Name[zh_CN]=KDED 收藏图标模块
+Name[zh_TW]=KDED Favicon 測試模組
+Name[zu]=Ingxenye ye-Favicon ye-KDED
+Comment=Shortcut icon support
+Comment[af]=Kortpad ikoon ondersteuning
+Comment[az]=Qısa yol timsal dəstəyi
+Comment[be]=Падтрымка значак скаротаў
+Comment[bg]=Поддръжка на препратки с икони
+Comment[bn]=শর্টকাট আইকন সাপোর্ট
+Comment[bs]=Podrška za ikone sa prečicama
+Comment[ca]=Suport de dreceres d'icona
+Comment[cs]=Podpora ikon zkratek
+Comment[csb]=Òbsłużënk ikònów serwerów
+Comment[da]=Genvejsikonstøtte
+Comment[de]=Unterstützung für Webseitensymbole ("Favicons") in KDE
+Comment[el]=υποστήριξη εικονιδίων Συντόμευσης
+Comment[eo]=Subteno por klavkombinaj piktogramoj
+Comment[es]=Soporte para iconos de acceso directo
+Comment[et]=Kiirkorralduse ikooni toetus
+Comment[eu]=Lasterbide-laukitxoen euskarria
+Comment[fa]=پشتیبانی شمایل میان‌بر
+Comment[fi]=Sivustojen kuvakkeet
+Comment[fr]=Gestion d'icône de raccourci
+Comment[fy]=Stipe foar byldkaikes
+Comment[gl]=Soporte para Icona de Atallo Directo
+Comment[he]=תמיכה בסמלי קיצור דרך
+Comment[hi]=शॉर्टकट प्रतीक आधार
+Comment[hr]=Podrška za ikonske prečace
+Comment[hu]=Website-ikonok támogatása
+Comment[is]=Stuðningur fyrir flýtitáknmyndir
+Comment[it]=Supporto icone scorciatoia
+Comment[ja]=ショートカットアイコンサポート
+Comment[ka]=მალმხმობი ხატულების მხარდაჭერა
+Comment[kk]=Жарлықтарды қолдау
+Comment[km]=ការ​គាំទ្រ​រូបតំណាង​ផ្លូវកាត់
+Comment[ko]=단축 아이콘 지원
+Comment[lt]=Nuorodų ženkliukų palaikymas
+Comment[lv]=Īsinājumikonu atbalsts
+Comment[mk]=Поддршка за икони за кратенки
+Comment[ms]=Sokongan ikon pintasan
+Comment[mt]=Sapport għall-ikoni "shortcut"
+Comment[nb]=Støtte for snarveisikoner
+Comment[nds]=Ünnerstütten för Link-Lüttbiller
+Comment[ne]=सर्टकट प्रतिमा समर्थन
+Comment[nl]=Ondersteuning voor pictogrammen
+Comment[nn]=Støtte for snarvegikon
+Comment[pa]=ਸ਼ਾਰਟਕੱਟ ਆਈਕਾਨ ਸਹਿਯੋਗ
+Comment[pl]=Obsługa ikon serwerów
+Comment[pt]=Suporte de ícone de atalho
+Comment[pt_BR]=Suporte ao ícone de atalho
+Comment[ro]=Suport pentru iconițe accelerator
+Comment[ru]=Показ настраиваемых значков в KDE
+Comment[rw]=Iyemera ry'Ihinanzira ry'Agashushondanga
+Comment[se]=Govašlávkestagaid doarjja
+Comment[sk]=Podpora ikon skratiek
+Comment[sl]=Podpora ikonam za bližnjice
+Comment[sr]=Подршка за икону пречице
+Comment[sr@Latn]=Podrška za ikonu prečice
+Comment[sv]=Stöd för genvägsikon
+Comment[ta]=குறுக்கு வழி சின்ன ஆதரவு
+Comment[th]=สนับสนุนไอคอนทางลัด
+Comment[tr]=Kısayol simge desteği
+Comment[tt]=KDE'da ikon kürsätü
+Comment[uk]=Підтримка скорочень піктограм
+Comment[vi]=Hỗ trợ biểu tượng giúp truy cập nhanh
+Comment[wa]=Sopoirt imådjetes rascourtis
+Comment[zh_CN]=快捷图标支持
+Comment[zh_TW]=捷徑圖示支援
+ServiceTypes=KDEDModule
+X-KDE-ModuleType=Library
+X-KDE-Library=favicons
+X-KDE-FactoryName=favicons
+X-KDE-Kded-autoload=false
+X-KDE-Kded-load-on-demand=true
diff --git a/libkonq/favicons/favicons.h b/libkonq/favicons/favicons.h
new file mode 100644
index 000000000..021ea3b9b
--- /dev/null
+++ b/libkonq/favicons/favicons.h
@@ -0,0 +1,105 @@
+/* This file is part of the KDE Project
+ Copyright (c) 2001 Malte Starostik <malte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _FAVICONS_H_
+#define _FAVICONS_H_
+
+#include <kdedmodule.h>
+#include <kurl.h>
+
+namespace KIO { class Job; }
+
+/**
+ * KDED Module to handle shortcut icons ("favicons")
+ * FaviconsModule implements a KDED Module that handles the association of
+ * URLs and hosts with shortcut icons and the icons' downloads in a central
+ * place.
+ *
+ * After a successful download, the DCOP signal iconChanged() is emitted.
+ * It has the signature void iconChanged(bool, QString, QString);
+ * The first parameter is true if the icon is a "host" icon, that is it is
+ * the default icon for all URLs on the given host. In this case, the
+ * second parameter is a host name, otherwise the second parameter is the
+ * URL which is associated with the icon. The third parameter is the
+ * @ref KIconLoader friendly name of the downloaded icon, the same as
+ * @ref iconForURL will from now on return for any matching URL.
+ *
+ * @short KDED Module for favicons
+ * @author Malte Starostik <malte@kde.org>
+ */
+class FaviconsModule : public KDEDModule
+{
+ Q_OBJECT
+ K_DCOP
+public:
+ FaviconsModule(const QCString &obj);
+ virtual ~FaviconsModule();
+
+k_dcop:
+ /**
+ * Looks up an icon name for a given URL. This function does not
+ * initiate any download. If no icon for the URL or its host has
+ * been downloaded yet, QString::null is returned.
+ *
+ * @param url the URL for which the icon is queried
+ * @return the icon name suitable to pass to @ref KIconLoader or
+ * QString::null if no icon for this URL was found.
+ */
+ QString iconForURL(const KURL &url);
+ /**
+ * Assiciates an icon with the given URL. If the icon was not
+ * downloaded before or the downloaded was too long ago, a
+ * download attempt will be started and the iconChanged() DCOP
+ * signal is emitted after the download finished successfully.
+ *
+ * @param url the URL which will be associated with the icon
+ * @param iconURL the URL of the icon to be downloaded
+ */
+ ASYNC setIconForURL(const KURL &url, const KURL &iconURL);
+ /**
+ * Downloads the icon for a given host if it was not downloaded before
+ * or the download was too long ago. If the download finishes
+ * successfully, the iconChanged() DCOP signal is emitted.
+ *
+ * @param url any URL on the host for which the icon is to be downloaded
+ */
+ ASYNC downloadHostIcon(const KURL &url);
+
+k_dcop_signals:
+ void iconChanged(bool isHost, QString hostOrURL, QString iconName);
+ void infoMessage(KURL iconURL, QString msg);
+
+private:
+ void startDownload(const QString &, bool, const KURL &);
+ QString simplifyURL(const KURL &);
+ QString iconNameFromURL(const KURL &);
+ bool isIconOld(const QString &);
+
+private slots:
+ void slotData(KIO::Job *, const QByteArray &);
+ void slotResult(KIO::Job *);
+ void slotInfoMessage(KIO::Job *, const QString &);
+ void slotKill();
+
+private:
+ struct FaviconsModulePrivate *d;
+};
+
+#endif
+
+// vim: ts=4 sw=4 et
diff --git a/libkonq/favicons/favicons.upd b/libkonq/favicons/favicons.upd
new file mode 100644
index 000000000..b5f693b3b
--- /dev/null
+++ b/libkonq/favicons/favicons.upd
@@ -0,0 +1,3 @@
+# Move favicons from $KDEHOME/share/icons and $KDEHOME/share/cache to $KDEHOME/cache-$HOST
+Id=kde3_2
+Script=move_favicons.sh,sh
diff --git a/libkonq/favicons/move_favicons.sh b/libkonq/favicons/move_favicons.sh
new file mode 100755
index 000000000..a06d7d2bd
--- /dev/null
+++ b/libkonq/favicons/move_favicons.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+prefix=$(kde-config --localprefix)
+source1="$prefix/share/icons/favicons"
+source2="$prefix/share/cache/favicons"
+dest="$(kde-config --path cache)/favicons"
+
+if [ -n "$prefix" -a -d "$source1" ]; then
+ while [ ! -d "$dest" ]; do
+ dir="$dest"
+ while [ ! -d `dirname "$dir"` ]; do
+ dir=`dirname "$dir"`
+ done
+ mkdir "$dir" || exit 1
+ done
+
+ icons=`ls "$source1" 2>/dev/null`
+ if [ -n "$icons" ]; then
+ for i in $icons; do
+ mv -f "$source1/$i" "$dest/$i"
+ done
+ fi
+ rmdir "$source1"
+fi
+if [ -n "$prefix" -a -d "$source2" ]; then
+ while [ ! -d "$dest" ]; do
+ dir="$dest"
+ while [ ! -d `dirname "$dir"` ]; do
+ dir=`dirname "$dir"`
+ done
+ mkdir "$dir" || exit 1
+ done
+
+ icons=`ls "$source2" 2>/dev/null`
+ if [ -n "$icons" ]; then
+ for i in $icons; do
+ mv -f "$source2/$i" "$dest/$i"
+ done
+ fi
+ rmdir "$source2"
+fi
diff --git a/libkonq/kfileivi.cc b/libkonq/kfileivi.cc
new file mode 100644
index 000000000..6775f115a
--- /dev/null
+++ b/libkonq/kfileivi.cc
@@ -0,0 +1,477 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999, 2000, 2001, 2002 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kfileivi.h"
+#include "kivdirectoryoverlay.h"
+#include "konq_iconviewwidget.h"
+#include "konq_operations.h"
+#include "konq_settings.h"
+
+#include <qpainter.h>
+
+#include <kurldrag.h>
+#include <kiconeffect.h>
+#include <kfileitem.h>
+#include <kdebug.h>
+#include <krun.h>
+
+#undef Bool
+
+/**
+ * Private data for KFileIVI
+ */
+struct KFileIVI::Private
+{
+ QIconSet icons; // Icon states (cached to prevent re-applying icon effects
+ // every time)
+ QPixmap thumb; // Raw unprocessed thumbnail
+ QString m_animatedIcon; // Name of animation
+ bool m_animated; // Animation currently running ?
+ KIVDirectoryOverlay* m_directoryOverlay;
+ QPixmap m_overlay;
+ QString m_overlayName;
+};
+
+KFileIVI::KFileIVI( KonqIconViewWidget *iconview, KFileItem* fileitem, int size )
+ : KIconViewItem( iconview, fileitem->text() ),
+ m_size( size ), m_state( KIcon::DefaultState ),
+ m_bDisabled( false ), m_bThumbnail( false ), m_fileitem( fileitem )
+{
+ d = new KFileIVI::Private;
+
+ updatePixmapSize();
+ setPixmap( m_fileitem->pixmap( m_size, m_state ) );
+ setDropEnabled( S_ISDIR( m_fileitem->mode() ) );
+
+ // Cache entry for the icon effects
+ d->icons.reset( *pixmap(), QIconSet::Large );
+ d->m_animated = false;
+
+ // iconName() requires the mimetype to be known
+ if ( fileitem->isMimeTypeKnown() )
+ {
+ QString icon = fileitem->iconName();
+ if ( !icon.isEmpty() )
+ setMouseOverAnimation( icon );
+ else
+ setMouseOverAnimation( "unknown" );
+ }
+ d->m_directoryOverlay = 0;
+}
+
+KFileIVI::~KFileIVI()
+{
+ delete d->m_directoryOverlay;
+ delete d;
+}
+
+void KFileIVI::invalidateThumb( int state, bool redraw )
+{
+ QIconSet::Mode mode;
+ switch( state )
+ {
+ case KIcon::DisabledState:
+ mode = QIconSet::Disabled;
+ break;
+ case KIcon::ActiveState:
+ mode = QIconSet::Active;
+ break;
+ case KIcon::DefaultState:
+ default:
+ mode = QIconSet::Normal;
+ break;
+ }
+ d->icons = QIconSet();
+ d->icons.setPixmap( KGlobal::iconLoader()->iconEffect()->
+ apply( d->thumb, KIcon::Desktop, state ),
+ QIconSet::Large, mode );
+ m_state = state;
+
+ QIconViewItem::setPixmap( d->icons.pixmap( QIconSet::Large, mode ),
+ false, redraw );
+}
+
+void KFileIVI::setIcon( int size, int state, bool recalc, bool redraw )
+{
+ m_size = size;
+ m_bThumbnail = false;
+ if ( m_bDisabled )
+ m_state = KIcon::DisabledState;
+ else
+ m_state = state;
+
+ if ( d->m_overlayName.isNull() )
+ d->m_overlay = QPixmap();
+ else {
+ int halfSize;
+ if (m_size == 0) {
+ halfSize = IconSize(KIcon::Desktop) / 2;
+ } else {
+ halfSize = m_size / 2;
+ }
+ d->m_overlay = DesktopIcon(d->m_overlayName, halfSize);
+ }
+
+ setPixmapDirect(m_fileitem->pixmap( m_size, m_state ) , recalc, redraw );
+}
+
+void KFileIVI::setOverlay( const QString& iconName )
+{
+ d->m_overlayName = iconName;
+
+ refreshIcon(true);
+}
+
+KIVDirectoryOverlay* KFileIVI::setShowDirectoryOverlay( bool show )
+{
+ if ( !m_fileitem->isDir() || m_fileitem->iconName() != "folder" )
+ return 0;
+
+ if (show) {
+ if (!d->m_directoryOverlay)
+ d->m_directoryOverlay = new KIVDirectoryOverlay(this);
+ return d->m_directoryOverlay;
+ } else {
+ delete d->m_directoryOverlay;
+ d->m_directoryOverlay = 0;
+ setOverlay(QString());
+ return 0;
+ }
+}
+
+bool KFileIVI::showDirectoryOverlay( )
+{
+ return (bool)d->m_directoryOverlay;
+}
+
+void KFileIVI::setPixmapDirect( const QPixmap& pixmap, bool recalc, bool redraw )
+{
+ QIconSet::Mode mode;
+ switch( m_state )
+ {
+ case KIcon::DisabledState:
+ mode = QIconSet::Disabled;
+ break;
+ case KIcon::ActiveState:
+ mode = QIconSet::Active;
+ break;
+ case KIcon::DefaultState:
+ default:
+ mode = QIconSet::Normal;
+ break;
+ }
+
+ // We cannot just reset() the iconset here, because setIcon can be
+ // called with any state and not just normal state. So we just
+ // create a dummy empty iconset as base object.
+ d->icons = QIconSet();
+ d->icons.setPixmap( pixmap, QIconSet::Large, mode );
+
+ updatePixmapSize();
+ QIconViewItem::setPixmap( d->icons.pixmap( QIconSet::Large, mode ),
+ recalc, redraw );
+}
+
+void KFileIVI::setDisabled( bool disabled )
+{
+ if ( m_bDisabled != disabled )
+ {
+ m_bDisabled = disabled;
+ bool active = ( m_state == KIcon::ActiveState );
+ setEffect( m_bDisabled ? KIcon::DisabledState :
+ ( active ? KIcon::ActiveState : KIcon::DefaultState ) );
+ }
+}
+
+void KFileIVI::setThumbnailPixmap( const QPixmap & pixmap )
+{
+ m_bThumbnail = true;
+ d->thumb = pixmap;
+ // QIconSet::reset() doesn't seem to clear the other generated pixmaps,
+ // so we just create a blank QIconSet here
+ d->icons = QIconSet();
+ d->icons.setPixmap( KGlobal::iconLoader()->iconEffect()->
+ apply( pixmap, KIcon::Desktop, KIcon::DefaultState ),
+ QIconSet::Large, QIconSet::Normal );
+
+ m_state = KIcon::DefaultState;
+
+ // Recalc when setting this pixmap!
+ updatePixmapSize();
+ QIconViewItem::setPixmap( d->icons.pixmap( QIconSet::Large,
+ QIconSet::Normal ), true );
+}
+
+void KFileIVI::setActive( bool active )
+{
+ if ( active )
+ setEffect( KIcon::ActiveState );
+ else
+ setEffect( m_bDisabled ? KIcon::DisabledState : KIcon::DefaultState );
+}
+
+void KFileIVI::setEffect( int state )
+{
+ QIconSet::Mode mode;
+ switch( state )
+ {
+ case KIcon::DisabledState:
+ mode = QIconSet::Disabled;
+ break;
+ case KIcon::ActiveState:
+ mode = QIconSet::Active;
+ break;
+ case KIcon::DefaultState:
+ default:
+ mode = QIconSet::Normal;
+ break;
+ }
+ // Do not update if the fingerprint is identical (prevents flicker)!
+
+ KIconEffect *effect = KGlobal::iconLoader()->iconEffect();
+
+ bool haveEffect = effect->hasEffect( KIcon::Desktop, m_state ) !=
+ effect->hasEffect( KIcon::Desktop, state );
+
+ //kdDebug(1203) << "desktop;defaultstate=" <<
+ // effect->fingerprint(KIcon::Desktop, KIcon::DefaultState) <<
+ // endl;
+ //kdDebug(1203) << "desktop;activestate=" <<
+ // effect->fingerprint(KIcon::Desktop, KIcon::ActiveState) <<
+ // endl;
+
+ if( haveEffect &&
+ effect->fingerprint( KIcon::Desktop, m_state ) !=
+ effect->fingerprint( KIcon::Desktop, state ) )
+ {
+ // Effects on are not applied until they are first accessed to
+ // save memory. Do this now when needed
+ if( m_bThumbnail )
+ {
+ if( d->icons.isGenerated( QIconSet::Large, mode ) )
+ d->icons.setPixmap( effect->apply( d->thumb, KIcon::Desktop, state ),
+ QIconSet::Large, mode );
+ }
+ else
+ {
+ if( d->icons.isGenerated( QIconSet::Large, mode ) )
+ d->icons.setPixmap( m_fileitem->pixmap( m_size, state ),
+ QIconSet::Large, mode );
+ }
+ QIconViewItem::setPixmap( d->icons.pixmap( QIconSet::Large, mode ) );
+ }
+ m_state = state;
+}
+
+void KFileIVI::refreshIcon( bool redraw )
+{
+ if (!isThumbnail())
+ setIcon( m_size, m_state, true, redraw );
+}
+
+void KFileIVI::invalidateThumbnail()
+{
+ d->thumb = QPixmap();
+}
+
+bool KFileIVI::isThumbnailInvalid() const
+{
+ return d->thumb.isNull();
+}
+
+bool KFileIVI::acceptDrop( const QMimeSource *mime ) const
+{
+ if ( mime->provides( "text/uri-list" ) ) // We're dragging URLs
+ {
+ if ( m_fileitem->acceptsDrops() ) // Directory, executables, ...
+ return true;
+
+ // Use cache
+ KURL::List uris = ( static_cast<KonqIconViewWidget*>(iconView()) )->dragURLs();
+
+ // Check if we want to drop something on itself
+ // (Nothing will happen, but it's a convenient way to move icons)
+ KURL::List::Iterator it = uris.begin();
+ for ( ; it != uris.end() ; it++ )
+ {
+ if ( m_fileitem->url().equals( *it, true /*ignore trailing slashes*/ ) )
+ return true;
+ }
+ }
+ return QIconViewItem::acceptDrop( mime );
+}
+
+void KFileIVI::setKey( const QString &key )
+{
+ QString theKey = key;
+
+ QVariant sortDirProp = iconView()->property( "sortDirectoriesFirst" );
+
+ bool isdir = ( S_ISDIR( m_fileitem->mode() ) && ( !sortDirProp.isValid() || ( sortDirProp.type() == QVariant::Bool && sortDirProp.toBool() ) ) );
+
+ // The order is: .dir (0), dir (1), .file (2), file (3)
+ int sortChar = isdir ? 1 : 3;
+ if ( m_fileitem->text()[0] == '.' )
+ --sortChar;
+
+ if ( !iconView()->sortDirection() ) // reverse sorting
+ sortChar = 3 - sortChar;
+
+ theKey.prepend( QChar( sortChar + '0' ) );
+
+ QIconViewItem::setKey( theKey );
+}
+
+void KFileIVI::dropped( QDropEvent *e, const QValueList<QIconDragItem> & )
+{
+ KonqOperations::doDrop( item(), item()->url(), e, iconView() );
+}
+
+void KFileIVI::returnPressed()
+{
+ if ( static_cast<KonqIconViewWidget*>(iconView())->isDesktop() ) {
+ KURL url = m_fileitem->url();
+ // When clicking on a link to e.g. $HOME from the desktop, we want to open $HOME
+ // Symlink resolution must only happen on the desktop though (#63014)
+ if ( m_fileitem->isLink() && url.isLocalFile() )
+ url = KURL( url, m_fileitem->linkDest() );
+
+ (void) new KRun( url, m_fileitem->mode(), m_fileitem->isLocalFile() );
+ } else {
+ m_fileitem->run();
+ }
+}
+
+
+void KFileIVI::paintItem( QPainter *p, const QColorGroup &c )
+{
+ QColorGroup cg = updateColors(c);
+ paintFontUpdate( p );
+
+ //*** TEMPORARY CODE - MUST BE MADE CONFIGURABLE FIRST - Martijn
+ // SET UNDERLINE ON HOVER ONLY
+ /*if ( ( ( KonqIconViewWidget* ) iconView() )->m_pActiveItem == this )
+ {
+ QFont f( p->font() );
+ f.setUnderline( TRUE );
+ p->setFont( f );
+ }*/
+
+ KIconViewItem::paintItem( p, cg );
+ paintOverlay(p);
+
+}
+
+void KFileIVI::paintOverlay( QPainter *p ) const
+{
+ if ( !d->m_overlay.isNull() ) {
+ QRect rect = pixmapRect(true);
+ p->drawPixmap(x() + rect.x() , y() + pixmapRect().height() - d->m_overlay.height(), d->m_overlay);
+ }
+}
+
+void KFileIVI::paintFontUpdate( QPainter *p ) const
+{
+ if ( m_fileitem->isLink() )
+ {
+ QFont f( p->font() );
+ f.setItalic( TRUE );
+ p->setFont( f );
+ }
+}
+
+QColorGroup KFileIVI::updateColors( const QColorGroup &c ) const
+{
+ QColorGroup cg( c );
+ cg.setColor( QColorGroup::Text, static_cast<KonqIconViewWidget*>(iconView())->itemColor() );
+ return cg;
+}
+
+bool KFileIVI::move( int x, int y )
+{
+ if ( static_cast<KonqIconViewWidget*>(iconView())->isDesktop() ) {
+ if ( x < 5 )
+ x = 5;
+ if ( x > iconView()->viewport()->width() - ( width() + 5 ) )
+ x = iconView()->viewport()->width() - ( width() + 5 );
+ if ( y < 5 )
+ y = 5;
+ if ( y > iconView()->viewport()->height() - ( height() + 5 ) )
+ y = iconView()->viewport()->height() - ( height() + 5 );
+ }
+ return QIconViewItem::move( x, y );
+}
+
+bool KFileIVI::hasAnimation() const
+{
+ return !d->m_animatedIcon.isEmpty() && !m_bThumbnail;
+}
+
+void KFileIVI::setMouseOverAnimation( const QString& movieFileName )
+{
+ if ( !movieFileName.isEmpty() )
+ {
+ //kdDebug(1203) << "KIconViewItem::setMouseOverAnimation " << movieFileName << endl;
+ d->m_animatedIcon = movieFileName;
+ }
+}
+
+QString KFileIVI::mouseOverAnimation() const
+{
+ return d->m_animatedIcon;
+}
+
+bool KFileIVI::isAnimated() const
+{
+ return d->m_animated;
+}
+
+void KFileIVI::setAnimated( bool a )
+{
+ d->m_animated = a;
+}
+
+int KFileIVI::compare( QIconViewItem *i ) const
+{
+ KonqIconViewWidget* view = static_cast<KonqIconViewWidget*>(iconView());
+ if ( view->caseInsensitiveSort() )
+ return key().localeAwareCompare( i->key() );
+ else
+ return view->m_pSettings->caseSensitiveCompare( key(), i->key() );
+}
+
+void KFileIVI::updatePixmapSize()
+{
+ int size = m_size ? m_size :
+ KGlobal::iconLoader()->currentSize( KIcon::Desktop );
+
+ KonqIconViewWidget* view = static_cast<KonqIconViewWidget*>( iconView() );
+
+ if ( view && view->canPreview( item() ) ) {
+ int previewSize = view->previewIconSize( size );
+ setPixmapSize( QSize( previewSize, previewSize ) );
+ }
+ else {
+ QSize pixSize = QSize( size, size );
+ if ( pixSize != pixmapSize() )
+ setPixmapSize( pixSize );
+ }
+}
+
+/* vim: set noet sw=4 ts=8 softtabstop=4: */
diff --git a/libkonq/kfileivi.h b/libkonq/kfileivi.h
new file mode 100644
index 000000000..d1f1d9ab7
--- /dev/null
+++ b/libkonq/kfileivi.h
@@ -0,0 +1,239 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999, 2000, 2001, 2002 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __kfileivi_h__
+#define __kfileivi_h__
+
+#include <kiconview.h>
+#include <kiconloader.h>
+#include <libkonq_export.h>
+
+class KFileItem;
+class KonqIconViewWidget;
+class KIVDirectoryOverlay;
+
+/**
+ * KFileIVI (short form of "Konq - File - IconViewItem")
+ * is, as expected, an improved KIconViewItem, because
+ * it represents a file.
+ * All the information about the file is contained in the KFileItem
+ * pointer.
+ */
+class LIBKONQ_EXPORT KFileIVI : public KIconViewItem
+{
+public:
+ /**
+ * Create an icon, within a qlistview, representing a file
+ * @param iconview the parent widget
+ * @param fileitem the file item created by KDirLister
+ * @param size the icon size
+ */
+ KFileIVI( KonqIconViewWidget *iconview, KFileItem* fileitem, int size );
+ virtual ~KFileIVI();
+
+ /**
+ * Handler for return (or single/double click) on ONE icon.
+ * Runs the file through KRun.
+ */
+ virtual void returnPressed();
+
+ /**
+ * @return the file item held by this instance
+ */
+ KFileItem * item() const { return m_fileitem; }
+
+ /**
+ * @return true if dropping on this file is allowed
+ * Overloads QIconView::acceptDrop()
+ */
+ virtual bool acceptDrop( const QMimeSource *mime ) const;
+
+ /**
+ * Changes the icon for this item.
+ * @param size the icon size (0 for default, otherwise size in pixels)
+ * @param state the state of the icon (enum in KIcon)
+ * @param recalc whether to update the layout of the icon view when setting the icon
+ * @param redraw whether to redraw the item after setting the icon
+ */
+ virtual void setIcon( int size,
+ int state=KIcon::DefaultState,
+ bool recalc=false,
+ bool redraw=false);
+
+ /**
+ * Bypass @ref setIcon. This is for animated icons, you should use setIcon
+ * in all other cases.
+ * @param pixmap the pixmap to set - it SHOULD really have the right icon size!
+ * @param recalc whether to update the layout of the icon view when setting the icon
+ * @param redraw whether to redraw the item after setting the icon
+ */
+ void setPixmapDirect( const QPixmap & pixmap,
+ bool recalc=false,
+ bool redraw=false);
+
+ /**
+ * Notifies that all icon effects on thumbs should be invalidated,
+ * e.g. because the effect settings have been changed. The thumb itself
+ * is assumed to be still valid (use setThumbnailPixmap() instead
+ * otherwise).
+ * @param state the state of the icon (enum in KIcon)
+ * @param redraw whether to redraw the item after setting the icon
+ */
+ void invalidateThumb( int state, bool redraw = false );
+
+ /**
+ * Our current thumbnail is not longer "current".
+ * Called when the file contents have changed.
+ */
+ void invalidateThumbnail();
+ bool isThumbnailInvalid() const;
+
+ bool hasValidThumbnail() const { return isThumbnail() && !isThumbnailInvalid(); }
+
+ /**
+ * Return the current state of the icon
+ * (KIcon::DefaultState, KIcon::ActiveState etc.)
+ */
+ int state() const { return m_state; }
+
+ /**
+ * Return the theorical size of the icon
+ */
+ int iconSize() const { return m_size; }
+
+ /**
+ * Set to true when this icon is 'cut'
+ */
+ void setDisabled( bool disabled );
+
+ /**
+ * Set this when the thumbnail was loaded
+ */
+ void setThumbnailPixmap( const QPixmap & pixmap );
+
+ /**
+ * Set the icon to use the specified KIconEffect
+ * See the docs for KIconEffect for details.
+ */
+ void setEffect( /*int group,*/ int state );
+
+ /**
+ * @return true if this item is a thumbnail
+ */
+ bool isThumbnail() const { return m_bThumbnail; }
+
+ /**
+ * Sets an icon to be shown over the bottom left corner of the icon.
+ * Currently used for directory overlays.
+ * setOverlay(QString::null) to remove icon.
+ */
+ void setOverlay( const QString & iconName);
+
+ /**
+ * Redetermines the icon (useful if KFileItem might return another icon).
+ * Does nothing with thumbnails
+ */
+ virtual void refreshIcon( bool redraw );
+
+ virtual void setKey( const QString &key );
+
+ /**
+ * Paints this item. Takes care of using the normal or alpha
+ * blending methods depending on the configuration.
+ */
+ virtual void paintItem( QPainter *p, const QColorGroup &cg );
+
+ virtual bool move( int x, int y );
+
+ /**
+ * Enable an animation on mouseover, if there is an available mng.
+ * @param movieFileName the base name for the mng, e.g. "folder".
+ * Nothing happens if there is no animation available.
+ */
+ void setMouseOverAnimation( const QString& movieFileName );
+ QString mouseOverAnimation() const;
+
+ /**
+ * Return true if the icon _might_ have an animation available.
+ * This doesn't mean the .mng exists (only determined when hovering on the
+ * icon - and if it doesn't exist setMouseOverAnimation(QString::null) is called),
+ * and it doesn't mean that it's currently running either.
+ */
+ bool hasAnimation() const;
+
+ /** Return true if we are currently animating this icon */
+ bool isAnimated() const;
+ void setAnimated( bool );
+
+ /** Called when the mouse is over the icon */
+ void setActive( bool active );
+
+ /**
+ * Sets showing of directory overlays. Does nothing if this does
+ * not represent a folder.
+ */
+ KIVDirectoryOverlay* setShowDirectoryOverlay( bool );
+ bool showDirectoryOverlay( );
+
+ virtual int compare( QIconViewItem *i ) const;
+
+protected:
+ virtual void dropped( QDropEvent *e, const QValueList<QIconDragItem> & );
+
+ /**
+ * Contains the logic and code for painting the overlay pixmap.
+ */
+ void paintOverlay( QPainter *p ) const;
+
+ /**
+ * Updates the colorgroup.
+ */
+ QColorGroup updateColors(const QColorGroup &c) const;
+
+ /**
+ * Contains the logic and code for painting links.
+ */
+ void paintFontUpdate( QPainter *p ) const;
+
+private:
+ /** You are not supposed to call this on a KFileIVI, from the outside,
+ * it bypasses the icons cache */
+ virtual void setPixmap ( const QPixmap & icon ) { KIconViewItem::setPixmap( icon ); }
+ virtual void setPixmap ( const QPixmap & icon, bool recalc, bool redraw = TRUE )
+ { KIconViewItem::setPixmap( icon, recalc, redraw ); }
+
+ /** Check if a thumbnail will be generated and calc the size of the icon */
+ void updatePixmapSize();
+
+ int m_size, m_state;
+ bool m_bDisabled;
+ bool m_bThumbnail;
+ /** Pointer to the file item in KDirLister's list */
+ KFileItem* m_fileitem;
+
+ /**
+ * Private data for KFileIVI
+ * Implementation in kfileivi.cc
+ */
+ struct Private;
+
+ Private *d;
+};
+
+#endif
diff --git a/libkonq/kivdirectoryoverlay.cc b/libkonq/kivdirectoryoverlay.cc
new file mode 100644
index 000000000..5c9d14783
--- /dev/null
+++ b/libkonq/kivdirectoryoverlay.cc
@@ -0,0 +1,141 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Simon MacMullen
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qdict.h>
+#include <qpixmap.h>
+#include <qpainter.h>
+#include <qbitmap.h>
+#include <qimage.h>
+
+#include <kfileivi.h>
+#include <kfileitem.h>
+#include <kapplication.h>
+#include <kdirlister.h>
+#include <kstandarddirs.h>
+#include <kiconloader.h>
+#include <konq_settings.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "kivdirectoryoverlay.h"
+
+KIVDirectoryOverlay::KIVDirectoryOverlay(KFileIVI* directory)
+: m_lister(0), m_foundItems(false),
+ m_containsFolder(false), m_popularIcons(0)
+{
+ if (!m_lister)
+ {
+ m_lister = new KDirLister;
+ m_lister->setAutoErrorHandlingEnabled(false, 0);
+ connect(m_lister, SIGNAL(completed()), SLOT(slotCompleted()));
+ connect(m_lister, SIGNAL(newItems( const KFileItemList& )), SLOT(slotNewItems( const KFileItemList& )));
+ m_lister->setShowingDotFiles(false);
+ }
+ m_directory = directory;
+}
+
+KIVDirectoryOverlay::~KIVDirectoryOverlay()
+{
+ if (m_lister) m_lister->stop();
+ delete m_lister;
+ delete m_popularIcons;
+}
+
+void KIVDirectoryOverlay::start()
+{
+ if ( m_directory->item()->isReadable() ) {
+ m_popularIcons = new QDict<int>;
+ m_popularIcons->setAutoDelete(true);
+ m_lister->openURL(m_directory->item()->url());
+ } else {
+ emit finished();
+ }
+}
+
+void KIVDirectoryOverlay::timerEvent(QTimerEvent *)
+{
+ m_lister->stop();
+}
+
+void KIVDirectoryOverlay::slotCompleted()
+{
+ if (!m_popularIcons) return;
+
+ // Look through the histogram for the most popular mimetype
+ QDictIterator<int> currentIcon( (*m_popularIcons) );
+ unsigned int best = 0;
+ unsigned int total = 0;
+ for ( ; currentIcon.current(); ++currentIcon ) {
+ unsigned int currentCount = (*currentIcon.current());
+ total += currentCount;
+ if ( best < currentCount ) {
+ best = currentCount;
+ m_bestIcon = currentIcon.currentKey();
+ }
+ }
+
+ // Only show folder if there's no other candidate. Most folders contain
+ // folders. We know this.
+ if ( m_bestIcon.isNull() && m_containsFolder ) {
+ m_bestIcon = "folder";
+ }
+
+ if ( best * 2 < total ) {
+ m_bestIcon = "kmultiple";
+ }
+
+ if (!m_bestIcon.isNull()) {
+ m_directory->setOverlay(m_bestIcon);
+ }
+
+ delete m_popularIcons;
+ m_popularIcons = 0;
+
+ emit finished();
+}
+
+void KIVDirectoryOverlay::slotNewItems( const KFileItemList& items )
+{
+ if ( !m_popularIcons) return;
+
+ KFileItemListIterator files( items );
+
+ KFileItem* file;
+ for ( ; (file = files.current()) != 0; ++files ) {
+ if ( file -> isFile() ) {
+
+ QString iconName = file -> iconName();
+ if (!iconName) continue;
+
+ int* iconCount = m_popularIcons -> find( file -> iconName() );
+ if (!iconCount) {
+ iconCount = new int(0);
+ Q_ASSERT(file);
+ m_popularIcons -> insert(file -> iconName(), iconCount);
+ }
+ (*iconCount)++;
+ } else if ( file -> isDir() ) {
+ m_containsFolder = true;
+ }
+ }
+
+ m_foundItems = true;
+}
+
+#include "kivdirectoryoverlay.moc"
diff --git a/libkonq/kivdirectoryoverlay.h b/libkonq/kivdirectoryoverlay.h
new file mode 100644
index 000000000..5ebd07959
--- /dev/null
+++ b/libkonq/kivdirectoryoverlay.h
@@ -0,0 +1,58 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 Simon MacMullen
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KIVDIRECTORYOVERLAY_H_
+#define _KIVDIRECTORYOVERLAY_H_
+
+#include <kfileitem.h>
+#include <libkonq_export.h>
+
+#include <qdict.h>
+
+class KDirLister;
+class KFileIVI;
+
+class LIBKONQ_EXPORT KIVDirectoryOverlay : public QObject
+{
+ Q_OBJECT
+public:
+ KIVDirectoryOverlay(KFileIVI* directory);
+ virtual ~KIVDirectoryOverlay();
+ void start();
+
+signals:
+ void finished();
+
+protected:
+ virtual void timerEvent(QTimerEvent *);
+
+private slots:
+ void slotCompleted();
+ void slotNewItems( const KFileItemList& items );
+
+private:
+ KDirLister* m_lister;
+ bool m_foundItems;
+ bool m_containsFolder;
+ QDict<int>* m_popularIcons;
+ QString m_bestIcon;
+ KFileIVI* m_directory;
+};
+
+#endif
diff --git a/libkonq/knewmenu.cc b/libkonq/knewmenu.cc
new file mode 100644
index 000000000..168ade6f7
--- /dev/null
+++ b/libkonq/knewmenu.cc
@@ -0,0 +1,621 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 David Faure <faure@kde.org>
+ 2003 Sven Leiber <s.leiber@web.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qdir.h>
+
+#include <kdebug.h>
+#include <kdesktopfile.h>
+#include <kdirwatch.h>
+#include <kinstance.h>
+#include <kinputdialog.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+#include <kprotocolinfo.h>
+#include <kpopupmenu.h>
+#include <krun.h>
+
+#include <kio/job.h>
+#include <kio/renamedlg.h>
+
+#include <kpropertiesdialog.h>
+#include "konq_operations.h"
+#include "konq_undo.h"
+#include "knewmenu.h"
+#include <utime.h>
+
+// For KURLDesktopFileDlg
+#include <qlayout.h>
+#include <qhbox.h>
+#include <klineedit.h>
+#include <kurlrequester.h>
+#include <qlabel.h>
+#include <qpopupmenu.h>
+
+QValueList<KNewMenu::Entry> * KNewMenu::s_templatesList = 0L;
+int KNewMenu::s_templatesVersion = 0;
+bool KNewMenu::s_filesParsed = false;
+KDirWatch * KNewMenu::s_pDirWatch = 0L;
+
+class KNewMenu::KNewMenuPrivate
+{
+public:
+ KNewMenuPrivate() : m_parentWidget(0) {}
+ KActionCollection * m_actionCollection;
+ QString m_destPath;
+ QWidget *m_parentWidget;
+ KActionMenu *m_menuDev;
+};
+
+KNewMenu::KNewMenu( KActionCollection * _collec, const char *name ) :
+ KActionMenu( i18n( "Create New" ), "filenew", _collec, name ),
+ menuItemsVersion( 0 )
+{
+ //kdDebug(1203) << "KNewMenu::KNewMenu " << this << endl;
+ // Don't fill the menu yet
+ // We'll do that in slotCheckUpToDate (should be connected to abouttoshow)
+ d = new KNewMenuPrivate;
+ d->m_actionCollection = _collec;
+ makeMenus();
+}
+
+KNewMenu::KNewMenu( KActionCollection * _collec, QWidget *parentWidget, const char *name ) :
+ KActionMenu( i18n( "Create New" ), "filenew", _collec, name ),
+ menuItemsVersion( 0 )
+{
+ d = new KNewMenuPrivate;
+ d->m_actionCollection = _collec;
+ d->m_parentWidget = parentWidget;
+ makeMenus();
+}
+
+KNewMenu::~KNewMenu()
+{
+ //kdDebug(1203) << "KNewMenu::~KNewMenu " << this << endl;
+ delete d;
+}
+
+void KNewMenu::makeMenus()
+{
+ d->m_menuDev = new KActionMenu( i18n( "Link to Device" ), "kcmdevices", d->m_actionCollection, "devnew" );
+}
+
+void KNewMenu::slotCheckUpToDate( )
+{
+ //kdDebug(1203) << "KNewMenu::slotCheckUpToDate() " << this
+ // << " : menuItemsVersion=" << menuItemsVersion
+ // << " s_templatesVersion=" << s_templatesVersion << endl;
+ if (menuItemsVersion < s_templatesVersion || s_templatesVersion == 0)
+ {
+ //kdDebug(1203) << "KNewMenu::slotCheckUpToDate() : recreating actions" << endl;
+ // We need to clean up the action collection
+ // We look for our actions using the group
+ QValueList<KAction*> actions = d->m_actionCollection->actions( "KNewMenu" );
+ for( QValueListIterator<KAction*> it = actions.begin(); it != actions.end(); ++it )
+ {
+ remove( *it );
+ d->m_actionCollection->remove( *it );
+ }
+
+ if (!s_templatesList) { // No templates list up to now
+ s_templatesList = new QValueList<Entry>();
+ slotFillTemplates();
+ parseFiles();
+ }
+
+ // This might have been already done for other popupmenus,
+ // that's the point in s_filesParsed.
+ if ( !s_filesParsed )
+ parseFiles();
+
+ fillMenu();
+
+ menuItemsVersion = s_templatesVersion;
+ }
+}
+
+void KNewMenu::parseFiles()
+{
+ //kdDebug(1203) << "KNewMenu::parseFiles()" << endl;
+ s_filesParsed = true;
+ QValueList<Entry>::Iterator templ = s_templatesList->begin();
+ for ( /*++templ*/; templ != s_templatesList->end(); ++templ)
+ {
+ QString iconname;
+ QString filePath = (*templ).filePath;
+ if ( !filePath.isEmpty() )
+ {
+ QString text;
+ QString templatePath;
+ // If a desktop file, then read the name from it.
+ // Otherwise (or if no name in it?) use file name
+ if ( KDesktopFile::isDesktopFile( filePath ) ) {
+ KSimpleConfig config( filePath, true );
+ config.setDesktopGroup();
+ text = config.readEntry("Name");
+ (*templ).icon = config.readEntry("Icon");
+ (*templ).comment = config.readEntry("Comment");
+ QString type = config.readEntry( "Type" );
+ if ( type == "Link" )
+ {
+ templatePath = config.readPathEntry("URL");
+ if ( templatePath[0] != '/' )
+ {
+ if ( templatePath.startsWith("file:/") )
+ templatePath = KURL(templatePath).path();
+ else
+ {
+ // A relative path, then (that's the default in the files we ship)
+ QString linkDir = filePath.left( filePath.findRev( '/' ) + 1 /*keep / */ );
+ //kdDebug(1203) << "linkDir=" << linkDir << endl;
+ templatePath = linkDir + templatePath;
+ }
+ }
+ }
+ if ( templatePath.isEmpty() )
+ {
+ // No dest, this is an old-style template
+ (*templ).entryType = TEMPLATE;
+ (*templ).templatePath = (*templ).filePath; // we'll copy the file
+ } else {
+ (*templ).entryType = LINKTOTEMPLATE;
+ (*templ).templatePath = templatePath;
+ }
+
+ }
+ if (text.isEmpty())
+ {
+ text = KURL(filePath).fileName();
+ if ( text.endsWith(".desktop") )
+ text.truncate( text.length() - 8 );
+ else if ( text.endsWith(".kdelnk") )
+ text.truncate( text.length() - 7 );
+ }
+ (*templ).text = text;
+ /*kdDebug(1203) << "Updating entry with text=" << text
+ << " entryType=" << (*templ).entryType
+ << " templatePath=" << (*templ).templatePath << endl;*/
+ }
+ else {
+ (*templ).entryType = SEPARATOR;
+ }
+ }
+}
+
+void KNewMenu::fillMenu()
+{
+ //kdDebug(1203) << "KNewMenu::fillMenu()" << endl;
+ popupMenu()->clear();
+ d->m_menuDev->popupMenu()->clear();
+
+ KAction *linkURL = 0, *linkApp = 0; // these shall be put at special positions
+
+ int i = 1; // was 2 when there was Folder
+ QValueList<Entry>::Iterator templ = s_templatesList->begin();
+ for ( ; templ != s_templatesList->end(); ++templ, ++i)
+ {
+ if ( (*templ).entryType != SEPARATOR )
+ {
+ // There might be a .desktop for that one already, if it's a kdelnk
+ // This assumes we read .desktop files before .kdelnk files ...
+
+ // In fact, we skip any second item that has the same text as another one.
+ // Duplicates in a menu look bad in any case.
+
+ bool bSkip = false;
+
+ QValueList<KAction*> actions = d->m_actionCollection->actions();
+ QValueListIterator<KAction*> it = actions.begin();
+ for( ; it != actions.end() && !bSkip; ++it )
+ {
+ if ( (*it)->text() == (*templ).text )
+ {
+ kdDebug(1203) << "KNewMenu: skipping " << (*templ).filePath << endl;
+ bSkip = true;
+ }
+ }
+
+ if ( !bSkip )
+ {
+ Entry entry = *(s_templatesList->at( i-1 ));
+
+ // The best way to identify the "Create Directory", "Link to Location", "Link to Application" was the template
+ if ( (*templ).templatePath.endsWith( "emptydir" ) )
+ {
+ KAction * act = new KAction( (*templ).text, (*templ).icon, 0, this, SLOT( slotNewDir() ),
+ d->m_actionCollection, QCString().sprintf("newmenu%d", i ) );
+ act->setGroup( "KNewMenu" );
+ act->plug( popupMenu() );
+
+ KActionSeparator *sep = new KActionSeparator();
+ sep->plug( popupMenu() );
+ }
+ else
+ {
+ KAction * act = new KAction( (*templ).text, (*templ).icon, 0, this, SLOT( slotNewFile() ),
+ d->m_actionCollection, QCString().sprintf("newmenu%d", i ) );
+ act->setGroup( "KNewMenu" );
+
+ if ( (*templ).templatePath.endsWith( "URL.desktop" ) )
+ {
+ linkURL = act;
+ }
+ else if ( (*templ).templatePath.endsWith( "Program.desktop" ) )
+ {
+ linkApp = act;
+ }
+ else if ( KDesktopFile::isDesktopFile( entry.templatePath ) )
+ {
+ KDesktopFile df( entry.templatePath );
+ if(df.readType() == "FSDevice")
+ act->plug( d->m_menuDev->popupMenu() );
+ else
+ act->plug( popupMenu() );
+ }
+ else
+ {
+ act->plug( popupMenu() );
+ }
+ }
+ }
+ } else { // Separate system from personal templates
+ Q_ASSERT( (*templ).entryType != 0 );
+
+ KActionSeparator * act = new KActionSeparator();
+ act->plug( popupMenu() );
+ }
+ }
+
+ KActionSeparator * act = new KActionSeparator();
+ act->plug( popupMenu() );
+ if ( linkURL ) linkURL->plug( popupMenu() );
+ if ( linkApp ) linkApp->plug( popupMenu() );
+ d->m_menuDev->plug( popupMenu() );
+}
+
+void KNewMenu::slotFillTemplates()
+{
+ //kdDebug(1203) << "KNewMenu::slotFillTemplates()" << endl;
+ // Ensure any changes in the templates dir will call this
+ if ( ! s_pDirWatch )
+ {
+ s_pDirWatch = new KDirWatch;
+ QStringList dirs = d->m_actionCollection->instance()->dirs()->resourceDirs("templates");
+ for ( QStringList::Iterator it = dirs.begin() ; it != dirs.end() ; ++it )
+ {
+ //kdDebug(1203) << "Templates resource dir: " << *it << endl;
+ s_pDirWatch->addDir( *it );
+ }
+ connect ( s_pDirWatch, SIGNAL( dirty( const QString & ) ),
+ this, SLOT ( slotFillTemplates() ) );
+ connect ( s_pDirWatch, SIGNAL( created( const QString & ) ),
+ this, SLOT ( slotFillTemplates() ) );
+ connect ( s_pDirWatch, SIGNAL( deleted( const QString & ) ),
+ this, SLOT ( slotFillTemplates() ) );
+ // Ok, this doesn't cope with new dirs in KDEDIRS, but that's another story
+ }
+ s_templatesVersion++;
+ s_filesParsed = false;
+
+ s_templatesList->clear();
+
+ // Look into "templates" dirs.
+ QStringList files = d->m_actionCollection->instance()->dirs()->findAllResources("templates");
+ KSortableValueList<Entry,QString> slist;
+ for ( QStringList::Iterator it = files.begin() ; it != files.end() ; ++it )
+ {
+ //kdDebug(1203) << *it << endl;
+ if ( (*it)[0] != '.' )
+ {
+ Entry e;
+ e.filePath = *it;
+ e.entryType = 0; // not parsed yet
+ // put Directory etc. with special order (see fillMenu()) first in the list (a bit hacky)
+ if ( (*it).endsWith( "Directory.desktop" ) ||
+ (*it).endsWith( "linkProgram.desktop" ) ||
+ (*it).endsWith( "linkURL.desktop" ) )
+ s_templatesList->prepend( e );
+ else
+ {
+ 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)
+ QString key = config.readEntry("Name");
+ if ( (*it).endsWith( "TextFile.desktop" ) )
+ key = "1_" + key;
+ else
+ key = "2_" + key;
+
+ slist.insert( key, e );
+ }
+ }
+ }
+ slist.sort();
+ for(KSortableValueList<Entry, QString>::ConstIterator it = slist.begin(); it != slist.end(); ++it)
+ {
+ s_templatesList->append( (*it).value() );
+ }
+
+}
+
+void KNewMenu::slotNewDir()
+{
+ emit activated(); // for KDIconView::slotNewMenuActivated()
+
+ if (popupFiles.isEmpty())
+ return;
+
+ KonqOperations::newDir(d->m_parentWidget, popupFiles.first());
+}
+
+void KNewMenu::slotNewFile()
+{
+ int id = QString( sender()->name() + 7 ).toInt(); // skip "newmenu"
+ if (id == 0)
+ {
+ // run the command for the templates
+ KRun::runCommand(QString(sender()->name()));
+ return;
+ }
+
+ emit activated(); // for KDIconView::slotNewMenuActivated()
+
+ Entry entry = *(s_templatesList->at( id - 1 ));
+ //kdDebug(1203) << QString("sFile = %1").arg(sFile) << endl;
+
+ if ( !QFile::exists( entry.templatePath ) ) {
+ kdWarning(1203) << entry.templatePath << " doesn't exist" << endl;
+ KMessageBox::sorry( 0L, i18n("<qt>The template file <b>%1</b> does not exist.</qt>").arg(entry.templatePath));
+ return;
+ }
+ m_isURLDesktopFile = false;
+ QString name;
+ if ( KDesktopFile::isDesktopFile( entry.templatePath ) )
+ {
+ KDesktopFile df( entry.templatePath );
+ //kdDebug(1203) << df.readType() << endl;
+ if ( df.readType() == "Link" )
+ {
+ m_isURLDesktopFile = true;
+ // entry.comment contains i18n("Enter link to location (URL):"). JFYI :)
+ KURLDesktopFileDlg dlg( i18n("File name:"), entry.comment, d->m_parentWidget );
+ // TODO dlg.setCaption( i18n( ... ) );
+ if ( dlg.exec() )
+ {
+ name = dlg.fileName();
+ m_linkURL = dlg.url();
+ if ( name.isEmpty() || m_linkURL.isEmpty() )
+ return;
+ if ( !name.endsWith( ".desktop" ) )
+ name += ".desktop";
+ }
+ else
+ return;
+ }
+ else // any other desktop file (Device, App, etc.)
+ {
+ KURL::List::Iterator it = popupFiles.begin();
+ for ( ; it != popupFiles.end(); ++it )
+ {
+ //kdDebug(1203) << "first arg=" << entry.templatePath << endl;
+ //kdDebug(1203) << "second arg=" << (*it).url() << endl;
+ //kdDebug(1203) << "third arg=" << entry.text << endl;
+ QString text = entry.text;
+ text.replace( "...", QString::null ); // the ... is fine for the menu item but not for the default filename
+
+ KURL defaultFile( *it );
+ defaultFile.addPath( KIO::encodeFileName( text ) );
+ if ( defaultFile.isLocalFile() && QFile::exists( defaultFile.path() ) )
+ text = KIO::RenameDlg::suggestName( *it, text);
+
+ KURL templateURL;
+ templateURL.setPath( entry.templatePath );
+ (void) new KPropertiesDialog( templateURL, *it, text, d->m_parentWidget );
+ }
+ return; // done, exit.
+ }
+ }
+ else
+ {
+ // The template is not a desktop file
+ // Show the small dialog for getting the destination filename
+ bool ok;
+ QString text = entry.text;
+ text.replace( "...", QString::null ); // the ... is fine for the menu item but not for the default filename
+
+ KURL defaultFile( *(popupFiles.begin()) );
+ defaultFile.addPath( KIO::encodeFileName( text ) );
+ if ( defaultFile.isLocalFile() && QFile::exists( defaultFile.path() ) )
+ text = KIO::RenameDlg::suggestName( *(popupFiles.begin()), text);
+
+ name = KInputDialog::getText( QString::null, entry.comment,
+ text, &ok, d->m_parentWidget );
+ if ( !ok )
+ return;
+ }
+
+ // The template is not a desktop file [or it's a URL one]
+ // Copy it.
+ KURL::List::Iterator it = popupFiles.begin();
+
+ QString src = entry.templatePath;
+ for ( ; it != popupFiles.end(); ++it )
+ {
+ KURL dest( *it );
+ dest.addPath( KIO::encodeFileName(name) ); // Chosen destination file name
+ d->m_destPath = dest.path(); // will only be used if m_isURLDesktopFile and dest is local
+
+ KURL uSrc;
+ uSrc.setPath( src );
+ //kdDebug(1203) << "KNewMenu : KIO::copyAs( " << uSrc.url() << ", " << dest.url() << ")" << endl;
+ KIO::CopyJob * job = KIO::copyAs( uSrc, dest );
+ job->setDefaultPermissions( true );
+ connect( job, SIGNAL( result( KIO::Job * ) ),
+ SLOT( slotResult( KIO::Job * ) ) );
+ if ( m_isURLDesktopFile )
+ connect( job, SIGNAL( renamed( KIO::Job *, const KURL&, const KURL& ) ),
+ SLOT( slotRenamed( KIO::Job *, const KURL&, const KURL& ) ) );
+ KURL::List lst;
+ lst.append( uSrc );
+ (void)new KonqCommandRecorder( KonqCommand::COPY, lst, dest, job );
+ }
+}
+
+// Special case (filename conflict when creating a link=url file)
+// We need to update m_destURL
+void KNewMenu::slotRenamed( KIO::Job *, const KURL& from , const KURL& to )
+{
+ if ( from.isLocalFile() )
+ {
+ kdDebug() << k_funcinfo << from.prettyURL() << " -> " << to.prettyURL() << " ( m_destPath=" << d->m_destPath << ")" << endl;
+ Q_ASSERT( from.path() == d->m_destPath );
+ d->m_destPath = to.path();
+ }
+}
+
+void KNewMenu::slotResult( KIO::Job * job )
+{
+ if (job->error())
+ job->showErrorDialog();
+ else
+ {
+ KURL destURL = static_cast<KIO::CopyJob*>(job)->destURL();
+ if ( destURL.isLocalFile() )
+ {
+ if ( m_isURLDesktopFile )
+ {
+ // destURL is the original destination for the new file.
+ // But in case of a renaming (due to a conflict), the real path is in m_destPath
+ kdDebug(1203) << " destURL=" << destURL.path() << " " << " d->m_destPath=" << d->m_destPath << endl;
+ KDesktopFile df( d->m_destPath );
+ df.writeEntry( "Icon", KProtocolInfo::icon( KURL(m_linkURL).protocol() ) );
+ df.writePathEntry( "URL", m_linkURL );
+ df.sync();
+ }
+ else
+ {
+ // Normal (local) file. Need to "touch" it, kio_file copied the mtime.
+ (void) ::utime( QFile::encodeName( destURL.path() ), 0 );
+ }
+ }
+ }
+}
+
+//////////
+
+KURLDesktopFileDlg::KURLDesktopFileDlg( const QString& textFileName, const QString& textUrl )
+ : KDialogBase( Plain, QString::null, Ok|Cancel|User1, Ok, 0L /*parent*/, 0L, true,
+ true, KStdGuiItem::clear() )
+{
+ initDialog( textFileName, QString::null, textUrl, QString::null );
+}
+
+KURLDesktopFileDlg::KURLDesktopFileDlg( const QString& textFileName, const QString& textUrl, QWidget *parent )
+ : KDialogBase( Plain, QString::null, Ok|Cancel|User1, Ok, parent, 0L, true,
+ true, KStdGuiItem::clear() )
+{
+ initDialog( textFileName, QString::null, textUrl, QString::null );
+}
+
+void KURLDesktopFileDlg::initDialog( const QString& textFileName, const QString& defaultName, const QString& textUrl, const QString& defaultUrl )
+{
+ QVBoxLayout * topLayout = new QVBoxLayout( plainPage(), 0, spacingHint() );
+
+ // First line: filename
+ QHBox * fileNameBox = new QHBox( plainPage() );
+ topLayout->addWidget( fileNameBox );
+
+ QLabel * label = new QLabel( textFileName, fileNameBox );
+ m_leFileName = new KLineEdit( fileNameBox, 0L );
+ m_leFileName->setMinimumWidth(m_leFileName->sizeHint().width() * 3);
+ label->setBuddy(m_leFileName); // please "scheck" style
+ m_leFileName->setText( defaultName );
+ m_leFileName->setSelection(0, m_leFileName->text().length()); // autoselect
+ connect( m_leFileName, SIGNAL(textChanged(const QString&)),
+ SLOT(slotNameTextChanged(const QString&)) );
+
+ // Second line: url
+ QHBox * urlBox = new QHBox( plainPage() );
+ topLayout->addWidget( urlBox );
+ label = new QLabel( textUrl, urlBox );
+ m_urlRequester = new KURLRequester( defaultUrl, urlBox, "urlRequester" );
+ m_urlRequester->setMode( KFile::File | KFile::Directory );
+
+ m_urlRequester->setMinimumWidth( m_urlRequester->sizeHint().width() * 3 );
+ connect( m_urlRequester->lineEdit(), SIGNAL(textChanged(const QString&)),
+ SLOT(slotURLTextChanged(const QString&)) );
+ label->setBuddy(m_urlRequester); // please "scheck" style
+
+ m_urlRequester->setFocus();
+ enableButtonOK( !defaultName.isEmpty() && !defaultUrl.isEmpty() );
+ connect( this, SIGNAL(user1Clicked()), this, SLOT(slotClear()) );
+ m_fileNameEdited = false;
+}
+
+QString KURLDesktopFileDlg::url() const
+{
+ if ( result() == QDialog::Accepted )
+ return m_urlRequester->url();
+ else
+ return QString::null;
+}
+
+QString KURLDesktopFileDlg::fileName() const
+{
+ if ( result() == QDialog::Accepted )
+ return m_leFileName->text();
+ else
+ return QString::null;
+}
+
+void KURLDesktopFileDlg::slotClear()
+{
+ m_leFileName->setText( QString::null );
+ m_urlRequester->clear();
+ m_fileNameEdited = false;
+}
+
+void KURLDesktopFileDlg::slotNameTextChanged( const QString& )
+{
+ kdDebug() << k_funcinfo << endl;
+ m_fileNameEdited = true;
+ enableButtonOK( !m_leFileName->text().isEmpty() && !m_urlRequester->url().isEmpty() );
+}
+
+void KURLDesktopFileDlg::slotURLTextChanged( const QString& )
+{
+ if ( !m_fileNameEdited )
+ {
+ // use URL as default value for the filename
+ // (we copy only its filename if protocol supports listing,
+ // but for HTTP we don't want tons of index.html links)
+ KURL url( m_urlRequester->url() );
+ if ( KProtocolInfo::supportsListing( url ) )
+ m_leFileName->setText( url.fileName() );
+ else
+ m_leFileName->setText( url.url() );
+ m_fileNameEdited = false; // slotNameTextChanged set it to true erroneously
+ }
+ enableButtonOK( !m_leFileName->text().isEmpty() && !m_urlRequester->url().isEmpty() );
+}
+
+
+#include "knewmenu.moc"
diff --git a/libkonq/knewmenu.h b/libkonq/knewmenu.h
new file mode 100644
index 000000000..ecba301e5
--- /dev/null
+++ b/libkonq/knewmenu.h
@@ -0,0 +1,224 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998-2000 David Faure <faure@kde.org>
+ 2003 Sven Leiber <s.leiber@web.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __knewmenu_h
+#define __knewmenu_h
+
+#include <qintdict.h>
+#include <qstringlist.h>
+
+#include <kaction.h>
+#include <kdialogbase.h>
+#include <kurl.h>
+#include <libkonq_export.h>
+
+namespace KIO { class Job; }
+
+class KDirWatch;
+class KLineEdit;
+class KURLRequester;
+class QPopupMenu;
+
+/**
+ * The 'New' submenu, both for the File menu and the RMB popup menu.
+ * (The same instance can be used by both).
+ * Fills it with 'Folder' and one item per Template.
+ * For this you need to connect aboutToShow() of the File menu with slotCheckUpToDate()
+ * and to call slotCheckUpToDate() before showing the RMB popupmenu.
+ *
+ * KNewMenu automatically updates the list of templates if templates are
+ * added/updated/deleted.
+ *
+ * @author David Faure <faure@kde.org>
+ * Ideas and code for the new template handling mechanism ('link' desktop files)
+ * from Christoph Pickart <pickart@iam.uni-bonn.de>
+ */
+class LIBKONQ_EXPORT KNewMenu : public KActionMenu
+{
+ Q_OBJECT
+public:
+
+ /**
+ * Constructor
+ */
+ KNewMenu( KActionCollection * _collec, const char *name=0L );
+ KNewMenu( KActionCollection * _collec, QWidget *parentWidget, const char *name=0L );
+ virtual ~KNewMenu();
+
+ /**
+ * Set the files the popup is shown for
+ * Call this before showing up the menu
+ */
+ void setPopupFiles(KURL::List & _files) {
+ popupFiles = _files;
+ }
+ void setPopupFiles(const KURL & _file) {
+ popupFiles.clear();
+ popupFiles.append( _file );
+ }
+
+public slots:
+ /**
+ * Checks if updating the list is necessary
+ * IMPORTANT : Call this in the slot for aboutToShow.
+ */
+ void slotCheckUpToDate( );
+
+protected slots:
+ /**
+ * Called when New->Directory... is clicked
+ */
+ void slotNewDir();
+
+ /**
+ * Called when New->* is clicked
+ */
+ void slotNewFile();
+
+ /**
+ * Fills the templates list.
+ */
+ void slotFillTemplates();
+
+ void slotResult( KIO::Job * );
+ // Special case (filename conflict when creating a link=url file)
+ void slotRenamed( KIO::Job *, const KURL&, const KURL& );
+
+private:
+
+ /**
+ * Fills the menu from the templates list.
+ */
+ void fillMenu();
+
+ /**
+ * Opens the desktop files and completes the Entry list
+ * Input: the entry list. Output: the entry list ;-)
+ */
+ void parseFiles();
+
+ /**
+ * Make the main menus on the startup.
+ */
+ void makeMenus();
+
+ /**
+ * For entryType
+ * LINKTOTEMPLATE: a desktop file that points to a file or dir to copy
+ * TEMPLATE: a real file to copy as is (the KDE-1.x solution)
+ * SEPARATOR: to put a separator in the menu
+ * 0 means: not parsed, i.e. we don't know
+ */
+ enum { LINKTOTEMPLATE = 1, TEMPLATE, SEPARATOR };
+
+ struct Entry {
+ QString text;
+ QString filePath; // empty for SEPARATOR
+ QString templatePath; // same as filePath for TEMPLATE
+ QString icon;
+ int entryType;
+ QString comment;
+ };
+ // NOTE: only filePath is known before we call parseFiles
+
+ /**
+ * List of all template files. It is important that they are in
+ * the same order as the 'New' menu.
+ */
+ static QValueList<Entry> * s_templatesList;
+
+ class KNewMenuPrivate;
+ KNewMenuPrivate* d;
+
+ /**
+ * Is increased when templatesList has been updated and
+ * menu needs to be re-filled. Menus have their own version and compare it
+ * to templatesVersion before showing up
+ */
+ static int s_templatesVersion;
+
+ /**
+ * Set back to false each time new templates are found,
+ * and to true on the first call to parseFiles
+ */
+ static bool s_filesParsed;
+
+ int menuItemsVersion;
+
+ /**
+ * When the user pressed the right mouse button over an URL a popup menu
+ * is displayed. The URL belonging to this popup menu is stored here.
+ */
+ KURL::List popupFiles;
+
+ /**
+ * True when a desktop file with Type=URL is being copied
+ */
+ bool m_isURLDesktopFile;
+ QString m_linkURL; // the url to put in the file
+
+ static KDirWatch * s_pDirWatch;
+};
+
+/**
+ * @internal
+ * Dialog to ask for a filename and a URL, when creating a link to a URL.
+ * Basically a merge of KLineEditDlg and KURLRequesterDlg ;)
+ * @author David Faure <faure@kde.org>
+ */
+class KURLDesktopFileDlg : public KDialogBase
+{
+ Q_OBJECT
+public:
+ KURLDesktopFileDlg( const QString& textFileName, const QString& textUrl );
+ KURLDesktopFileDlg( const QString& textFileName, const QString& textUrl, QWidget *parent );
+ virtual ~KURLDesktopFileDlg() {}
+
+ /**
+ * @return the filename the user entered (no path)
+ */
+ QString fileName() const;
+ /**
+ * @return the URL the user entered
+ */
+ QString url() const;
+
+protected slots:
+ void slotClear();
+ void slotNameTextChanged( const QString& );
+ void slotURLTextChanged( const QString& );
+private:
+ void initDialog( const QString& textFileName, const QString& defaultName, const QString& textUrl, const QString& defaultUrl );
+
+ /**
+ * The line edit widget for the fileName
+ */
+ KLineEdit *m_leFileName;
+ /**
+ * The URL requester for the URL :)
+ */
+ KURLRequester *m_urlRequester;
+
+ /**
+ * True if the filename was manually edited.
+ */
+ bool m_fileNameEdited;
+};
+
+#endif
diff --git a/libkonq/konq_bgnddlg.cc b/libkonq/konq_bgnddlg.cc
new file mode 100644
index 000000000..bb871d2fc
--- /dev/null
+++ b/libkonq/konq_bgnddlg.cc
@@ -0,0 +1,211 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ Copyright (c) 1999 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qbuttongroup.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qradiobutton.h>
+
+#include <kcolorbutton.h>
+#include <kcombobox.h>
+#include <kdebug.h>
+#include <kimagefilepreview.h>
+#include <klocale.h>
+//#include <krecentdocument.h>
+#include <kstandarddirs.h>
+#include <kurlrequester.h>
+
+#include "konq_bgnddlg.h"
+
+
+KonqBgndDialog::KonqBgndDialog( QWidget* parent,
+ const QString& pixmapFile,
+ const QColor& theColor,
+ const QColor& defaultColor )
+ : KDialogBase( parent, "KonqBgndDialog", false,
+ i18n("Background Settings"), Ok|Cancel, Ok, true )
+{
+ QWidget* page = new QWidget( this );
+ setMainWidget( page );
+ QVBoxLayout* mainLayout = new QVBoxLayout( page, 0, KDialog::spacingHint() );
+
+ m_buttonGroup = new QButtonGroup( i18n("Background"), page );
+ m_buttonGroup->setColumnLayout( 0, Qt::Vertical );
+ m_buttonGroup->layout()->setMargin( KDialog::marginHint() );
+ m_buttonGroup->layout()->setSpacing( KDialog::spacingHint() );
+ QGridLayout* groupLayout = new QGridLayout( m_buttonGroup->layout() );
+ groupLayout->setAlignment( Qt::AlignTop );
+ mainLayout->addWidget( m_buttonGroup );
+
+ connect( m_buttonGroup, SIGNAL( clicked(int) ),
+ this, SLOT( slotBackgroundModeChanged() ) );
+
+ // color
+ m_radioColor = new QRadioButton( i18n("Co&lor:"), m_buttonGroup );
+ groupLayout->addWidget( m_radioColor, 0, 0 );
+ m_buttonColor = new KColorButton( theColor, defaultColor, m_buttonGroup );
+ m_buttonColor->setSizePolicy( QSizePolicy::Preferred,
+ QSizePolicy::Minimum );
+ groupLayout->addWidget( m_buttonColor, 0, 1 );
+
+ connect( m_buttonColor, SIGNAL( changed( const QColor& ) ),
+ this, SLOT( slotColorChanged() ) );
+
+ // picture
+ m_radioPicture = new QRadioButton( i18n("&Picture:"), m_buttonGroup );
+ groupLayout->addWidget( m_radioPicture, 1, 0 );
+ m_comboPicture = new KURLComboRequester( m_buttonGroup );
+ groupLayout->addMultiCellWidget( m_comboPicture, 1, 1, 1, 2 );
+ initPictures();
+
+ connect( m_comboPicture->comboBox(), SIGNAL( activated( int ) ),
+ this, SLOT( slotPictureChanged() ) );
+ connect( m_comboPicture, SIGNAL( urlSelected(const QString &) ),
+ this, SLOT( slotPictureChanged() ) );
+
+ QSpacerItem* spacer1 = new QSpacerItem( 0, 0, QSizePolicy::Expanding,
+ QSizePolicy::Minimum );
+ groupLayout->addItem( spacer1, 0, 2 );
+
+ // preview title
+ QHBoxLayout* hlay = new QHBoxLayout( mainLayout, KDialog::spacingHint() );
+ //mainLayout->addLayout( hlay );
+ QLabel* lbl = new QLabel( i18n("Preview"), page );
+ hlay->addWidget( lbl );
+ QFrame* frame = new QFrame( page );
+ frame->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum );
+ frame->setFrameShape( QFrame::HLine );
+ frame->setFrameShadow( QFrame::Sunken );
+ hlay->addWidget( frame );
+
+ // preview frame
+ m_preview = new QFrame( page );
+ m_preview->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
+ m_preview->setMinimumSize( 370, 180 );
+ m_preview->setFrameShape( QFrame::Panel );
+ m_preview->setFrameShadow( QFrame::Raised );
+ mainLayout->addWidget( m_preview );
+
+ if ( !pixmapFile.isEmpty() ) {
+ loadPicture( pixmapFile );
+ m_buttonColor->setColor( defaultColor );
+ m_radioPicture->setChecked( true );
+ }
+ else {
+ m_buttonColor->setColor( theColor );
+ m_comboPicture->comboBox()->setCurrentItem( 0 );
+ m_radioColor->setChecked( true );
+ }
+ slotBackgroundModeChanged();
+}
+
+KonqBgndDialog::~KonqBgndDialog()
+{
+}
+
+QColor KonqBgndDialog::color() const
+{
+ if ( m_radioColor->isChecked() )
+ return m_buttonColor->color();
+
+ return QColor();
+}
+
+void KonqBgndDialog::initPictures()
+{
+ KGlobal::dirs()->addResourceType( "tiles",
+ KGlobal::dirs()->kde_default("data") + "konqueror/tiles/");
+ kdDebug(1203) << KGlobal::dirs()->kde_default("data") + "konqueror/tiles/" << endl;
+
+ QStringList list = KGlobal::dirs()->findAllResources("tiles");
+
+ if ( list.isEmpty() )
+ m_comboPicture->comboBox()->insertItem( i18n("None") );
+ else {
+ QStringList::ConstIterator it;
+ for ( it = list.begin(); it != list.end(); it++ )
+ m_comboPicture->comboBox()->insertItem(
+ ( (*it).at(0) == '/' ) ? // if absolute path
+ KURL( *it ).fileName() : // then only fileName
+ *it );
+ }
+}
+
+void KonqBgndDialog::loadPicture( const QString& fileName )
+{
+ int i ;
+ for ( i = 0; i < m_comboPicture->comboBox()->count(); i++ ) {
+ if ( fileName == m_comboPicture->comboBox()->text( i ) ) {
+ m_comboPicture->comboBox()->setCurrentItem( i );
+ return;
+ }
+ }
+
+ if ( !fileName.isEmpty() ) {
+ m_comboPicture->comboBox()->insertItem( fileName );
+ m_comboPicture->comboBox()->setCurrentItem( i );
+ }
+ else
+ m_comboPicture->comboBox()->setCurrentItem( 0 );
+}
+
+void KonqBgndDialog::slotPictureChanged()
+{
+ m_pixmapFile = m_comboPicture->comboBox()->currentText();
+ QString file = locate( "tiles", m_pixmapFile );
+ if ( file.isEmpty() )
+ file = locate("wallpaper", m_pixmapFile); // add fallback for compatibility
+ if ( file.isEmpty() ) {
+ kdWarning(1203) << "Couldn't locate wallpaper " << m_pixmapFile << endl;
+ m_preview->unsetPalette();
+ m_pixmap = QPixmap();
+ m_pixmapFile = "";
+ }
+ else {
+ m_pixmap.load( file );
+
+ if ( m_pixmap.isNull() )
+ kdWarning(1203) << "Could not load wallpaper " << file << endl;
+ }
+ m_preview->setPaletteBackgroundPixmap( m_pixmap );
+}
+
+void KonqBgndDialog::slotColorChanged()
+{
+ m_preview->setPaletteBackgroundColor( m_buttonColor->color() );
+}
+
+void KonqBgndDialog::slotBackgroundModeChanged()
+{
+ if ( m_radioColor->isChecked() ) {
+ m_buttonColor->setEnabled( true );
+ m_comboPicture->setEnabled( false );
+ m_pixmapFile = "";
+ slotColorChanged();
+ }
+ else { // m_comboPicture->isChecked() == true
+ m_comboPicture->setEnabled( true );
+ m_buttonColor->setEnabled( false );
+ slotPictureChanged();
+ }
+}
+
+
+#include "konq_bgnddlg.moc"
diff --git a/libkonq/konq_bgnddlg.h b/libkonq/konq_bgnddlg.h
new file mode 100644
index 000000000..3a1e3c67d
--- /dev/null
+++ b/libkonq/konq_bgnddlg.h
@@ -0,0 +1,74 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ Copyright (c) 1999 David Faure <fauren@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __konq_bgnd_h
+#define __konq_bgnd_h
+
+#include <qstring.h>
+#include <qpixmap.h>
+
+#include <kdialogbase.h>
+
+class KColorButton;
+class KURLRequester;
+class QButtonGroup;
+class QRadioButton;
+
+/**
+ * Dialog for configuring the background
+ * Currently it defines and shows the pixmaps under the tiles resource
+ */
+class KonqBgndDialog : public KDialogBase
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructor
+ */
+ KonqBgndDialog( QWidget* parent, const QString& pixmapFile,
+ const QColor& theColor, const QColor& defaultColor );
+ ~KonqBgndDialog();
+
+ QColor color() const;
+ const QString& pixmapFile() const { return m_pixmapFile; }
+
+private slots:
+ void slotBackgroundModeChanged();
+ void slotPictureChanged();
+ void slotColorChanged();
+
+private:
+ void initPictures();
+ void loadPicture( const QString& fileName );
+
+ QColor m_color;
+ QPixmap m_pixmap;
+ QString m_pixmapFile;
+ QFrame* m_preview;
+
+ QButtonGroup* m_buttonGroup;
+ QRadioButton* m_radioColor;
+ QRadioButton* m_radioPicture;
+ KURLRequester* m_comboPicture;
+ KColorButton* m_buttonColor;
+
+};
+
+#endif
diff --git a/libkonq/konq_defaults.h b/libkonq/konq_defaults.h
new file mode 100644
index 000000000..fac4fdb3d
--- /dev/null
+++ b/libkonq/konq_defaults.h
@@ -0,0 +1,48 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ Copyright (C) 1999 - 2002 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// Default values for konqueror/kdesktop settings
+// This file is used by konqueror kdesktop, and kcmkonq,
+// to share the same defaults
+
+// appearance tab
+#define DEFAULT_UNDERLINELINKS false
+#define DEFAULT_WORDWRAPTEXT true // kfm-like, sorry Reggie :-)
+#define DEFAULT_TEXTHEIGHT 2
+#define DEFAULT_TEXTWIDTH 0 // 0 = automatic (font depending)
+#define DEFAULT_TEXTWIDTH_MULTICOLUMN 600 // maxwidth, as the iconview has dynamic column width
+#define DEFAULT_FILESIZEINBYTES false
+
+#define DEFAULT_RENAMEICONDIRECTLY false
+
+// transparency of blended mimetype icons in textpreview
+#define DEFAULT_TEXTPREVIEW_ICONTRANSPARENCY 70
+
+// show hidden files on desktop default
+#define DEFAULT_SHOW_HIDDEN_ROOT_ICONS false
+#define DEFAULT_VERT_ALIGN true
+
+// Default terminal for "Open Terminal" in konqueror
+#define DEFAULT_TERMINAL "konsole"
+
+// Confirmations for deletions
+#define DEFAULT_CONFIRMTRASH true
+#define DEFAULT_CONFIRMDELETE true
+#define DEFAULT_CONFIRMSHRED true
diff --git a/libkonq/konq_dirpart.cc b/libkonq/konq_dirpart.cc
new file mode 100644
index 000000000..0e46ec0c9
--- /dev/null
+++ b/libkonq/konq_dirpart.cc
@@ -0,0 +1,746 @@
+/* This file is part of the KDE projects
+ Copyright (C) 2000 David Faure <faure@kde.org>
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "konq_dirpart.h"
+#include "konq_bgnddlg.h"
+#include "konq_propsview.h"
+#include "konq_settings.h"
+
+#include <kio/paste.h>
+#include <kapplication.h>
+#include <kaction.h>
+#include <kdatastream.h>
+#include <kdebug.h>
+#include <kdirlister.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <konq_drag.h>
+#include <kparts/browserextension.h>
+#include <kurldrag.h>
+#include <kuserprofile.h>
+#include <kurifilter.h>
+#include <kglobalsettings.h>
+
+#include <qapplication.h>
+#include <qclipboard.h>
+#include <qfile.h>
+#include <qguardedptr.h>
+#include <assert.h>
+#include <qvaluevector.h>
+
+class KonqDirPart::KonqDirPartPrivate
+{
+public:
+ KonqDirPartPrivate() : dirLister( 0 ) {}
+ QStringList mimeFilters;
+ KToggleAction *aEnormousIcons;
+ KToggleAction *aSmallMediumIcons;
+ QValueVector<int> iconSize;
+
+ KDirLister* dirLister;
+ bool dirSizeDirty;
+
+ void findAvailableIconSizes(void);
+ int findNearestIconSize(int size);
+ int nearestIconSizeError(int size);
+};
+
+void KonqDirPart::KonqDirPartPrivate::findAvailableIconSizes(void)
+{
+ KIconTheme *root = KGlobal::instance()->iconLoader()->theme();
+ iconSize.resize(1);
+ if (root) {
+ QValueList<int> avSizes = root->querySizes(KIcon::Desktop);
+ kdDebug(1203) << "The icon theme handles the sizes:" << avSizes << endl;
+ qHeapSort(avSizes);
+ int oldSize = -1;
+ if (avSizes.count() < 10) {
+ // Fixed or threshold type icons
+ QValueListConstIterator<int> i;
+ for (i = avSizes.begin(); i != avSizes.end(); i++) {
+ // Skip duplicated values (sanity check)
+ if (*i != oldSize) iconSize.append(*i);
+ oldSize = *i;
+ }
+ } else {
+ // Scalable icons.
+ const int progression[] = {16, 22, 32, 48, 64, 96, 128, 192, 256};
+
+ QValueListConstIterator<int> j = avSizes.begin();
+ for (uint i = 0; i < 9; i++) {
+ while (j++ != avSizes.end()) {
+ if (*j >= progression[i]) {
+ iconSize.append(*j);
+ kdDebug(1203) << "appending " << *j << " size." << endl;
+ break;
+ }
+ }
+ }
+ }
+ } else {
+ iconSize.append(KIcon::SizeSmall); // 16
+ iconSize.append(KIcon::SizeMedium); // 32
+ iconSize.append(KIcon::SizeLarge); // 48
+ iconSize.append(KIcon::SizeHuge); // 64
+ }
+ kdDebug(1203) << "Using " << iconSize.count() << " icon sizes." << endl;
+}
+
+int KonqDirPart::KonqDirPartPrivate::findNearestIconSize(int preferred)
+{
+ int s1 = iconSize[1];
+ if (preferred == 0) return KGlobal::iconLoader()->currentSize(KIcon::Desktop);
+ if (preferred <= s1) return s1;
+ for (uint i = 2; i <= iconSize.count(); i++) {
+ if (preferred <= iconSize[i]) {
+ if (preferred - s1 < iconSize[i] - preferred) return s1;
+ else return iconSize[i];
+ } else {
+ s1 = iconSize[i];
+ }
+ }
+ return s1;
+}
+
+int KonqDirPart::KonqDirPartPrivate::nearestIconSizeError(int size)
+{
+ return QABS(size - findNearestIconSize(size));
+}
+
+KonqDirPart::KonqDirPart( QObject *parent, const char *name )
+ :KParts::ReadOnlyPart( parent, name ),
+ m_pProps( 0L ),
+ m_findPart( 0L )
+{
+ d = new KonqDirPartPrivate;
+ resetCount();
+ //m_bMultipleItemsSelected = false;
+
+ connect( QApplication::clipboard(), SIGNAL(dataChanged()), this, SLOT(slotClipboardDataChanged()) );
+
+ actionCollection()->setHighlightingEnabled( true );
+
+ m_paIncIconSize = new KAction( i18n( "Enlarge Icons" ), "viewmag+", 0, this, SLOT( slotIncIconSize() ), actionCollection(), "incIconSize" );
+ m_paDecIconSize = new KAction( i18n( "Shrink Icons" ), "viewmag-", 0, this, SLOT( slotDecIconSize() ), actionCollection(), "decIconSize" );
+
+ m_paDefaultIcons = new KRadioAction( i18n( "&Default Size" ), 0, actionCollection(), "modedefault" );
+ d->aEnormousIcons = new KRadioAction( i18n( "&Huge" ), 0,
+ actionCollection(), "modeenormous" );
+ m_paHugeIcons = new KRadioAction( i18n( "&Very Large" ), 0, actionCollection(), "modehuge" );
+ m_paLargeIcons = new KRadioAction( i18n( "&Large" ), 0, actionCollection(), "modelarge" );
+ m_paMediumIcons = new KRadioAction( i18n( "&Medium" ), 0, actionCollection(), "modemedium" );
+ d->aSmallMediumIcons = new KRadioAction( i18n( "&Small" ), 0,
+ actionCollection(), "modesmallmedium" );
+ m_paSmallIcons = new KRadioAction( i18n( "&Tiny" ), 0, actionCollection(), "modesmall" );
+
+ m_paDefaultIcons->setExclusiveGroup( "ViewMode" );
+ d->aEnormousIcons->setExclusiveGroup( "ViewMode" );
+ m_paHugeIcons->setExclusiveGroup( "ViewMode" );
+ m_paLargeIcons->setExclusiveGroup( "ViewMode" );
+ m_paMediumIcons->setExclusiveGroup( "ViewMode" );
+ d->aSmallMediumIcons->setExclusiveGroup( "ViewMode" );
+ m_paSmallIcons->setExclusiveGroup( "ViewMode" );
+
+ connect( m_paDefaultIcons, SIGNAL( toggled( bool ) ), this, SLOT( slotIconSizeToggled( bool ) ) );
+ connect( d->aEnormousIcons, SIGNAL( toggled( bool ) ),
+ this, SLOT( slotIconSizeToggled( bool ) ) );
+ connect( m_paHugeIcons, SIGNAL( toggled( bool ) ), this, SLOT( slotIconSizeToggled( bool ) ) );
+ connect( m_paLargeIcons, SIGNAL( toggled( bool ) ), this, SLOT( slotIconSizeToggled( bool ) ) );
+ connect( m_paMediumIcons, SIGNAL( toggled( bool ) ), this, SLOT( slotIconSizeToggled( bool ) ) );
+ connect( d->aSmallMediumIcons, SIGNAL( toggled( bool ) ),
+ this, SLOT( slotIconSizeToggled( bool ) ) );
+ connect( m_paSmallIcons, SIGNAL( toggled( bool ) ), this, SLOT( slotIconSizeToggled( bool ) ) );
+
+ connect( kapp, SIGNAL(iconChanged(int)), SLOT(slotIconChanged(int)) );
+#if 0
+ // Extract 6 icon sizes from the icon theme.
+ // Use 16,22,32,48,64,128 as default.
+ // Use these also if the icon theme is scalable.
+ int i;
+ d->iconSize[0] = 0; // Default value
+ d->iconSize[1] = KIcon::SizeSmall; // 16
+ d->iconSize[2] = KIcon::SizeSmallMedium; // 22
+ d->iconSize[3] = KIcon::SizeMedium; // 32
+ d->iconSize[4] = KIcon::SizeLarge; // 48
+ d->iconSize[5] = KIcon::SizeHuge; // 64
+ d->iconSize[6] = KIcon::SizeEnormous; // 128
+ d->iconSize[7] = 192;
+ d->iconSize[8] = 256;
+ KIconTheme *root = KGlobal::instance()->iconLoader()->theme();
+ if (root)
+ {
+ QValueList<int> avSizes = root->querySizes(KIcon::Desktop);
+ kdDebug(1203) << "the icon theme handles the following sizes:" << avSizes << endl;
+ if (avSizes.count() < 10) {
+ // Use the icon sizes supplied by the theme.
+ // If avSizes contains more than 10 entries, assume a scalable
+ // icon theme.
+ QValueList<int>::Iterator it;
+ for (i=1, it=avSizes.begin(); (it!=avSizes.end()) && (i<7); it++, i++)
+ {
+ d->iconSize[i] = *it;
+ kdDebug(1203) << "m_iIconSize[" << i << "] = " << *it << endl;
+ }
+ // Generate missing sizes
+ for (; i < 7; i++) {
+ d->iconSize[i] = d->iconSize[i - 1] + d->iconSize[i - 1] / 2 ;
+ kdDebug(1203) << "m_iIconSize[" << i << "] = " << d->iconSize[i] << endl;
+ }
+ }
+ }
+#else
+ d->iconSize.reserve(10);
+ d->iconSize.append(0); // Default value
+ adjustIconSizes();
+#endif
+
+ // Remove in KDE4 ...
+ // These are here in the event subclasses access them.
+ m_iIconSize[1] = KIcon::SizeSmall;
+ m_iIconSize[2] = KIcon::SizeMedium;
+ m_iIconSize[3] = KIcon::SizeLarge;
+ m_iIconSize[4] = KIcon::SizeHuge;
+ // ... up to here
+
+ KAction *a = new KAction( i18n( "Configure Background..." ), "background", 0, this, SLOT( slotBackgroundSettings() ),
+ actionCollection(), "bgsettings" );
+
+ a->setToolTip( i18n( "Allows choosing of background settings for this view" ) );
+}
+
+KonqDirPart::~KonqDirPart()
+{
+ // Close the find part with us
+ delete m_findPart;
+ delete d;
+ d = 0;
+}
+
+void KonqDirPart::adjustIconSizes()
+{
+ d->findAvailableIconSizes();
+ m_paSmallIcons->setEnabled(d->findNearestIconSize(16) < 20);
+ d->aSmallMediumIcons->setEnabled(d->nearestIconSizeError(22) < 2);
+ m_paMediumIcons->setEnabled(d->nearestIconSizeError(32) < 6);
+ m_paLargeIcons->setEnabled(d->nearestIconSizeError(48) < 8);
+ m_paHugeIcons->setEnabled(d->nearestIconSizeError(64) < 12);
+ d->aEnormousIcons->setEnabled(d->findNearestIconSize(128) > 110);
+
+ if (m_pProps) {
+ int size = m_pProps->iconSize();
+ int nearSize = d->findNearestIconSize(size);
+
+ if (size != nearSize) {
+ m_pProps->setIconSize(nearSize);
+ }
+ newIconSize(nearSize);
+ }
+}
+
+void KonqDirPart::setMimeFilter (const QStringList& mime)
+{
+ QString u = url().url();
+
+ if ( u.isEmpty () )
+ return;
+
+ if ( mime.isEmpty() )
+ d->mimeFilters.clear();
+ else
+ d->mimeFilters = mime;
+}
+
+QStringList KonqDirPart::mimeFilter() const
+{
+ return d->mimeFilters;
+}
+
+QScrollView * KonqDirPart::scrollWidget()
+{
+ return static_cast<QScrollView *>(widget());
+}
+
+void KonqDirPart::slotBackgroundSettings()
+{
+ QColor bgndColor = m_pProps->bgColor( widget() );
+ QColor defaultColor = KGlobalSettings::baseColor();
+ // dlg must be created on the heap as widget() can get deleted while dlg.exec(),
+ // trying to delete dlg as its child then (#124210) - Frank Osterfeld
+ QGuardedPtr<KonqBgndDialog> dlg = new KonqBgndDialog( widget(),
+ m_pProps->bgPixmapFile(),
+ bgndColor,
+ defaultColor );
+
+ if ( dlg->exec() == KonqBgndDialog::Accepted )
+ {
+ if ( dlg->color().isValid() )
+ {
+ m_pProps->setBgColor( dlg->color() );
+ m_pProps->setBgPixmapFile( "" );
+ }
+ else
+ {
+ m_pProps->setBgColor( defaultColor );
+ m_pProps->setBgPixmapFile( dlg->pixmapFile() );
+ }
+ m_pProps->applyColors( scrollWidget()->viewport() );
+ scrollWidget()->viewport()->repaint();
+ }
+
+ delete dlg;
+}
+
+void KonqDirPart::lmbClicked( KFileItem * fileItem )
+{
+ KURL url = fileItem->url();
+ if ( !fileItem->isReadable() )
+ {
+ // No permissions or local file that doesn't exist - need to find out which
+ if ( ( !fileItem->isLocalFile() ) || QFile::exists( url.path() ) )
+ {
+ KMessageBox::error( widget(), i18n("<p>You do not have enough permissions to read <b>%1</b></p>").arg(url.prettyURL()) );
+ return;
+ }
+ KMessageBox::error( widget(), i18n("<p><b>%1</b> does not seem to exist anymore</p>").arg(url.prettyURL()) );
+ return;
+ }
+
+ KParts::URLArgs args;
+ fileItem->determineMimeType();
+ if ( fileItem->isMimeTypeKnown() )
+ args.serviceType = fileItem->mimetype();
+ args.trustedSource = true;
+
+ if (KonqFMSettings::settings()->alwaysNewWin() && fileItem->isDir()) {
+ //args.frameName = "_blank"; // open new window
+ // We tried the other option, passing the path as framename so that
+ // an existing window for that dir is reused (like MSWindows does when
+ // the similar option is activated and the sidebar is hidden (!)).
+ // But this requires some work, including changing the framename
+ // when navigating, etc. Not very much requested yet, in addition.
+ KParts::WindowArgs wargs;
+ KParts::ReadOnlyPart* dummy;
+ emit m_extension->createNewWindow( url, args, wargs, dummy );
+ }
+ else
+ {
+ kdDebug() << "emit m_extension->openURLRequest( " << url.url() << "," << args.serviceType << ")" << endl;
+ emit m_extension->openURLRequest( url, args );
+ }
+}
+
+void KonqDirPart::mmbClicked( KFileItem * fileItem )
+{
+ if ( fileItem )
+ {
+ // Optimisation to avoid KRun to call kfmclient that then tells us
+ // to open a window :-)
+ KService::Ptr offer = KServiceTypeProfile::preferredService(fileItem->mimetype(), "Application");
+ //if (offer) kdDebug(1203) << "KonqDirPart::mmbClicked: got service " << offer->desktopEntryName() << endl;
+ if ( offer && offer->desktopEntryName().startsWith("kfmclient") )
+ {
+ KParts::URLArgs args;
+ args.serviceType = fileItem->mimetype();
+ emit m_extension->createNewWindow( fileItem->url(), args );
+ }
+ else
+ fileItem->run();
+ }
+ else
+ {
+ m_extension->pasteRequest();
+ }
+}
+
+void KonqDirPart::saveState( QDataStream& stream )
+{
+ stream << m_nameFilter;
+}
+
+void KonqDirPart::restoreState( QDataStream& stream )
+{
+ stream >> m_nameFilter;
+}
+
+void KonqDirPart::saveFindState( QDataStream& stream )
+{
+ // assert only doable in KDE4.
+ //assert( m_findPart ); // test done by caller.
+ if ( !m_findPart )
+ return;
+
+ // When we have a find part, our own URL wasn't saved (see KonqDirPartBrowserExtension)
+ // So let's do it here
+ stream << m_url;
+
+ KParts::BrowserExtension* ext = KParts::BrowserExtension::childObject( m_findPart );
+ if( !ext )
+ return;
+
+ ext->saveState( stream );
+}
+
+void KonqDirPart::restoreFindState( QDataStream& stream )
+{
+ // Restore our own URL
+ stream >> m_url;
+
+ emit findOpen( this );
+
+ KParts::BrowserExtension* ext = KParts::BrowserExtension::childObject( m_findPart );
+ slotClear();
+
+ if( !ext )
+ return;
+
+ ext->restoreState( stream );
+}
+
+void KonqDirPart::slotClipboardDataChanged()
+{
+ // This is very related to KDIconView::slotClipboardDataChanged
+
+ KURL::List lst;
+ QMimeSource *data = QApplication::clipboard()->data();
+ if ( data->provides( "application/x-kde-cutselection" ) && data->provides( "text/uri-list" ) )
+ if ( KonqDrag::decodeIsCutSelection( data ) )
+ (void) KURLDrag::decode( data, lst );
+
+ disableIcons( lst );
+
+ updatePasteAction();
+}
+
+void KonqDirPart::updatePasteAction() // KDE4: merge into method above
+{
+ QString actionText = KIO::pasteActionText();
+ bool paste = !actionText.isEmpty();
+ if ( paste )
+ emit m_extension->setActionText( "paste", actionText );
+ emit m_extension->enableAction( "paste", paste );
+}
+
+void KonqDirPart::newItems( const KFileItemList & entries )
+{
+ d->dirSizeDirty = true;
+ if ( m_findPart )
+ emitTotalCount();
+
+ emit itemsAdded( entries );
+}
+
+void KonqDirPart::deleteItem( KFileItem * fileItem )
+{
+ d->dirSizeDirty = true;
+ emit itemRemoved( fileItem );
+}
+
+void KonqDirPart::emitTotalCount()
+{
+ if ( !d->dirLister || d->dirLister->url().isEmpty() )
+ return;
+ if ( d->dirSizeDirty ) {
+ m_lDirSize = 0;
+ m_lFileCount = 0;
+ m_lDirCount = 0;
+ KFileItemList entries = d->dirLister->items();
+ for (KFileItemListIterator it(entries); it.current(); ++it)
+ {
+ if ( !it.current()->isDir() )
+ {
+ if (!it.current()->isLink()) // symlinks don't contribute to the size
+ m_lDirSize += it.current()->size();
+ m_lFileCount++;
+ }
+ else
+ m_lDirCount++;
+ }
+ d->dirSizeDirty = false;
+ }
+
+ QString summary =
+ KIO::itemsSummaryString(m_lFileCount + m_lDirCount,
+ m_lFileCount,
+ m_lDirCount,
+ m_lDirSize,
+ true);
+ bool bShowsResult = false;
+ if (m_findPart)
+ {
+ QVariant prop = m_findPart->property( "showsResult" );
+ bShowsResult = prop.isValid() && prop.toBool();
+ }
+ //kdDebug(1203) << "KonqDirPart::emitTotalCount bShowsResult=" << bShowsResult << endl;
+ emit setStatusBarText( bShowsResult ? i18n("Search result: %1").arg(summary) : summary );
+}
+
+void KonqDirPart::emitCounts( const KFileItemList & lst )
+{
+ if ( lst.count() == 1 )
+ emit setStatusBarText( ((KFileItemList)lst).first()->getStatusBarInfo() );
+ else
+ {
+ long long fileSizeSum = 0;
+ uint fileCount = 0;
+ uint dirCount = 0;
+
+ for ( KFileItemListIterator it( lst ); it.current(); ++it )
+ {
+ if ( it.current()->isDir() )
+ dirCount++;
+ else
+ {
+ if ( !it.current()->isLink() ) // ignore symlinks
+ fileSizeSum += it.current()->size();
+ fileCount++;
+ }
+ }
+
+ emit setStatusBarText( KIO::itemsSummaryString( fileCount + dirCount,
+ fileCount, dirCount,
+ fileSizeSum, true ) );
+ }
+}
+
+void KonqDirPart::emitCounts( const KFileItemList & lst, bool selectionChanged )
+{
+ if ( lst.count() == 0 )
+ emitTotalCount();
+ else
+ emitCounts( lst );
+
+ // Yes, the caller could do that too :)
+ // But this bool could also be used to cache the QString for the last
+ // selection, as long as selectionChanged is false.
+ // Not sure it's worth it though.
+ // MiB: no, I don't think it's worth it. Especially regarding the
+ // loss of readability of the code. Thus, this will be removed in
+ // KDE 4.0.
+ if ( selectionChanged )
+ emit m_extension->selectionInfo( lst );
+}
+
+void KonqDirPart::emitMouseOver( const KFileItem* item )
+{
+ emit m_extension->mouseOverInfo( item );
+}
+
+void KonqDirPart::slotIconSizeToggled( bool toggleOn )
+{
+ //kdDebug(1203) << "KonqDirPart::slotIconSizeToggled" << endl;
+
+ // This slot is called when an iconsize action is checked or by calling
+ // action->setChecked(false) (previously true). So we must filter out
+ // the 'untoggled' case to prevent odd results here (repaints/loops!)
+ if ( !toggleOn )
+ return;
+
+ if ( m_paDefaultIcons->isChecked() )
+ setIconSize(0);
+ else if ( d->aEnormousIcons->isChecked() )
+ setIconSize(d->findNearestIconSize(KIcon::SizeEnormous));
+ else if ( m_paHugeIcons->isChecked() )
+ setIconSize(d->findNearestIconSize(KIcon::SizeHuge));
+ else if ( m_paLargeIcons->isChecked() )
+ setIconSize(d->findNearestIconSize(KIcon::SizeLarge));
+ else if ( m_paMediumIcons->isChecked() )
+ setIconSize(d->findNearestIconSize(KIcon::SizeMedium));
+ else if ( d->aSmallMediumIcons->isChecked() )
+ setIconSize(d->findNearestIconSize(KIcon::SizeSmallMedium));
+ else if ( m_paSmallIcons->isChecked() )
+ setIconSize(d->findNearestIconSize(KIcon::SizeSmall));
+}
+
+void KonqDirPart::slotIncIconSize()
+{
+ int s = m_pProps->iconSize();
+ s = s ? s : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
+ uint sizeIndex = 0;
+ for ( uint idx = 1; idx < d->iconSize.count() ; ++idx )
+ if (s == d->iconSize[idx]) {
+ sizeIndex = idx;
+ break;
+ }
+ if ( sizeIndex > 0 && sizeIndex < d->iconSize.count() - 1 )
+ {
+ setIconSize( d->iconSize[sizeIndex + 1] );
+ }
+}
+
+void KonqDirPart::slotDecIconSize()
+{
+ int s = m_pProps->iconSize();
+ s = s ? s : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
+ uint sizeIndex = 0;
+ for ( uint idx = 1; idx < d->iconSize.count() ; ++idx )
+ if (s == d->iconSize[idx]) {
+ sizeIndex = idx;
+ break;
+ }
+ if ( sizeIndex > 1 )
+ {
+ setIconSize( d->iconSize[sizeIndex - 1] );
+ }
+}
+
+// Only updates Actions, a GUI update is done in the views by reimplementing this
+void KonqDirPart::newIconSize( int size /*0=default, or 16,32,48....*/ )
+{
+ int realSize = (size==0) ? KGlobal::iconLoader()->currentSize( KIcon::Desktop ) : size;
+ m_paDecIconSize->setEnabled(realSize > d->iconSize[1]);
+ m_paIncIconSize->setEnabled(realSize < d->iconSize.back());
+
+ m_paDefaultIcons->setChecked(size == 0);
+ d->aEnormousIcons->setChecked(size == d->findNearestIconSize(KIcon::SizeEnormous));
+ m_paHugeIcons->setChecked(size == d->findNearestIconSize(KIcon::SizeHuge));
+ m_paLargeIcons->setChecked(size == d->findNearestIconSize(KIcon::SizeLarge));
+ m_paMediumIcons->setChecked(size == d->findNearestIconSize(KIcon::SizeMedium));
+ d->aSmallMediumIcons->setChecked(size == d->findNearestIconSize(KIcon::SizeSmallMedium));
+ m_paSmallIcons->setChecked(size == d->findNearestIconSize(KIcon::SizeSmall));
+}
+
+// Stores the new icon size and updates the GUI
+void KonqDirPart::setIconSize( int size )
+{
+ //kdDebug(1203) << "KonqDirPart::setIconSize " << size << " -> updating props and GUI" << endl;
+ m_pProps->setIconSize( size );
+ newIconSize( size );
+}
+
+bool KonqDirPart::closeURL()
+{
+ // Tell all the childern objects to clean themselves up for dinner :)
+ return doCloseURL();
+}
+
+bool KonqDirPart::openURL(const KURL& url)
+{
+ if ( m_findPart )
+ {
+ kdDebug(1203) << "KonqDirPart::openURL -> emit findClosed " << this << endl;
+ delete m_findPart;
+ m_findPart = 0L;
+ emit findClosed( this );
+ }
+
+ m_url = url;
+ emit aboutToOpenURL ();
+
+ return doOpenURL(url);
+}
+
+void KonqDirPart::setFindPart( KParts::ReadOnlyPart * part )
+{
+ assert(part);
+ m_findPart = part;
+ connect( m_findPart, SIGNAL( started() ),
+ this, SLOT( slotStarted() ) );
+ connect( m_findPart, SIGNAL( started() ),
+ this, SLOT( slotStartAnimationSearching() ) );
+ connect( m_findPart, SIGNAL( clear() ),
+ this, SLOT( slotClear() ) );
+ connect( m_findPart, SIGNAL( newItems( const KFileItemList & ) ),
+ this, SLOT( slotNewItems( const KFileItemList & ) ) );
+ connect( m_findPart, SIGNAL( finished() ), // can't name it completed, it conflicts with a KROP signal
+ this, SLOT( slotCompleted() ) );
+ connect( m_findPart, SIGNAL( finished() ),
+ this, SLOT( slotStopAnimationSearching() ) );
+ connect( m_findPart, SIGNAL( canceled() ),
+ this, SLOT( slotCanceled() ) );
+ connect( m_findPart, SIGNAL( canceled() ),
+ this, SLOT( slotStopAnimationSearching() ) );
+
+ connect( m_findPart, SIGNAL( findClosed() ),
+ this, SLOT( slotFindClosed() ) );
+
+ emit findOpened( this );
+
+ // set the initial URL in the find part
+ m_findPart->openURL( url() );
+}
+
+void KonqDirPart::slotFindClosed()
+{
+ kdDebug(1203) << "KonqDirPart::slotFindClosed -> emit findClosed " << this << endl;
+ delete m_findPart;
+ m_findPart = 0L;
+ emit findClosed( this );
+ // reload where we were before
+ openURL( url() );
+}
+
+void KonqDirPart::slotIconChanged( int group )
+{
+ if (group != KIcon::Desktop) return;
+ adjustIconSizes();
+}
+
+void KonqDirPart::slotStartAnimationSearching()
+{
+ started(0);
+}
+
+void KonqDirPart::slotStopAnimationSearching()
+{
+ completed();
+}
+
+void KonqDirPartBrowserExtension::saveState( QDataStream &stream )
+{
+ m_dirPart->saveState( stream );
+ bool hasFindPart = m_dirPart->findPart();
+ stream << hasFindPart;
+ assert( ! ( hasFindPart && !strcmp(m_dirPart->className(), "KFindPart") ) );
+ if ( !hasFindPart )
+ KParts::BrowserExtension::saveState( stream );
+ else {
+ m_dirPart->saveFindState( stream );
+ }
+}
+
+void KonqDirPartBrowserExtension::restoreState( QDataStream &stream )
+{
+ m_dirPart->restoreState( stream );
+ bool hasFindPart;
+ stream >> hasFindPart;
+ assert( ! ( hasFindPart && !strcmp(m_dirPart->className(), "KFindPart") ) );
+ if ( !hasFindPart )
+ // This calls openURL, that's why we don't want to call it in case of a find part
+ KParts::BrowserExtension::restoreState( stream );
+ else {
+ m_dirPart->restoreFindState( stream );
+ }
+}
+
+
+void KonqDirPart::resetCount()
+{
+ m_lDirSize = 0;
+ m_lFileCount = 0;
+ m_lDirCount = 0;
+ d->dirSizeDirty = true;
+}
+
+void KonqDirPart::setDirLister( KDirLister* lister )
+{
+ d->dirLister = lister;
+}
+
+#include "konq_dirpart.moc"
diff --git a/libkonq/konq_dirpart.h b/libkonq/konq_dirpart.h
new file mode 100644
index 000000000..df76e93bd
--- /dev/null
+++ b/libkonq/konq_dirpart.h
@@ -0,0 +1,351 @@
+/* This file is part of the KDE projects
+ Copyright (C) 2000 David Faure <faure@kde.org>
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __konqdirpart_h
+#define __konqdirpart_h
+
+#include <qstring.h>
+#include <kparts/part.h>
+#include <kparts/browserextension.h>
+#include <kfileitem.h>
+#include <kdatastream.h>
+#include <kio/global.h>
+#include <libkonq_export.h>
+
+class KDirLister;
+namespace KParts { class BrowserExtension; }
+class KonqPropsView;
+class QScrollView;
+class KAction;
+class KToggleAction;
+class KonqDirPartBrowserExtension;
+
+class LIBKONQ_EXPORT KonqDirPart: public KParts::ReadOnlyPart
+{
+ Q_OBJECT
+
+ friend class KonqDirPartBrowserExtension;
+
+public:
+ KonqDirPart( QObject *parent, const char *name );
+
+ virtual ~KonqDirPart();
+
+ /**
+ * The derived part should call this in its constructor
+ */
+ void setBrowserExtension( KonqDirPartBrowserExtension * extension )
+ { m_extension = extension; }
+
+ KonqDirPartBrowserExtension * extension()
+ { return m_extension; }
+
+ /**
+ * The derived part should call this in its constructor
+ */
+ void setDirLister( KDirLister* lister );
+ // TODO KDE4 create the KDirLister here and simplify the parts?
+
+ QScrollView * scrollWidget();
+
+ virtual void saveState( QDataStream &stream );
+ virtual void restoreState( QDataStream &stream );
+
+ /** Called when LMB'ing an item in a directory view.
+ * @param fileItem must be set
+ * @param widget is only set as parent pointer for dialog boxes */
+ void lmbClicked( KFileItem * fileItem );
+
+ /** Called when MMB'ing an item in a directory view.
+ * @param fileItem if 0 it means we MMB'ed the background. */
+ void mmbClicked( KFileItem * fileItem );
+
+ void setNameFilter( const QString & nameFilter ) { m_nameFilter = nameFilter; }
+
+ QString nameFilter() const { return m_nameFilter; }
+
+ void setFilesToSelect( const QStringList & filesToSelect ) { m_filesToSelect = filesToSelect; }
+
+ /**
+ * Sets per directory mime-type based filtering.
+ *
+ * This method causes only the items matching the mime-type given
+ * by @p filters to be displayed. You can supply multiple mime-types
+ * by separating them with a space, eg. "text/plain image/x-png".
+ * To clear all the filters set for the current url simply call this
+ * function with a null or empty argument.
+ *
+ * NOTE: the filter(s) specified here only apply to the current
+ * directory as returned by @ref #url().
+ *
+ * @param filter mime-type(s) to filter directory by.
+ */
+ void setMimeFilter (const QStringList& filters);
+
+ /**
+ * Completely clears the internally stored list of mime filters
+ * set by call to @ref #setMimeFilter.
+ */
+ QStringList mimeFilter() const;
+
+
+ KonqPropsView * props() const { return m_pProps; }
+
+ /**
+ * "Cut" icons : disable those whose URL is in lst, enable the others
+ */
+ virtual void disableIcons( const KURL::List & lst ) = 0;
+
+ /**
+ * This class takes care of the counting of items, size etc. in the
+ * current directory. Call this in slotClear.
+ */
+ void resetCount();
+
+ /**
+ * Update the counts for those new items
+ */
+ void newItems( const KFileItemList & entries );
+
+ /**
+ * Update the counts with this item being deleted
+ */
+ void deleteItem( KFileItem * fileItem );
+
+ /**
+ * Show the counts for the directory in the status bar
+ */
+ void emitTotalCount();
+
+ // ##### TODO KDE 4: remove!
+ /**
+ * Show the counts for the list of items in the status bar.
+ * If none are provided emitTotalCount() is called to display
+ * the counts for the whole directory. However, that does not work
+ * for a treeview.
+ *
+ * @deprecated
+ */
+ void emitCounts( const KFileItemList & lst, bool selectionChanged );
+
+ /**
+ * Show the counts for the list of items in the status bar. The list
+ * can be empty.
+ *
+ * @param lst the list of fileitems for which to display the counts
+ * @since 3.4
+ */
+ void emitCounts( const KFileItemList & lst );
+
+ void emitMouseOver( const KFileItem * item );
+
+ /**
+ * Enables or disables the paste action. This depends both on
+ * the data in the clipboard and the number of files selected
+ * (pasting is only possible if not more than one file is selected).
+ */
+ void updatePasteAction();
+
+ /**
+ * Change the icon size of the view.
+ * The view should call it initially.
+ * The view should also reimplement it, to update the icons.
+ */
+ virtual void newIconSize( int size );
+
+ /**
+ * This is called by the actions that change the icon size.
+ * It stores the new size and calls newIconSize.
+ */
+ void setIconSize( int size );
+
+ /**
+ * This is called by konqueror itself, when the "find" functionality is activated
+ */
+ void setFindPart( KParts::ReadOnlyPart * part );
+
+ KParts::ReadOnlyPart * findPart() const { return m_findPart; }
+
+ virtual const KFileItem * currentItem() = 0; // { return 0L; }
+
+ virtual KFileItemList selectedFileItems() { return KFileItemList(); }
+
+ /**
+ * Re-implemented for internal reasons. API is unaffected. All inheriting
+ * classes should re-implement @ref doCloseURL() instead instead of this one.
+ */
+ bool closeURL ();
+
+signals:
+
+ /**
+ * Emitted whenever the current URL is about to be changed.
+ */
+ void aboutToOpenURL();
+
+ /**
+ * We emit this if we want a find part to be created for us.
+ * This happens when restoring from history
+ */
+ void findOpen( KonqDirPart * );
+
+ /**
+ * We emit this _after_ a find part has been created for us.
+ * This also happens initially.
+ */
+ void findOpened( KonqDirPart * );
+
+ /**
+ * We emit this to ask konq to close the find part
+ */
+ void findClosed( KonqDirPart * );
+
+ /**
+ * Emitted as the part is updated with new items.
+ * Useful for informing plugins of changes in view.
+ */
+ void itemsAdded( const KFileItemList& );
+
+ /**
+ * Emitted as the part is updated with these items.
+ * Useful for informing plugins of changes in view.
+ */
+ void itemRemoved( const KFileItem* );
+
+ /**
+ * Emitted with the list of filtered-out items whenever
+ * a mime-based filter(s) is set.
+ */
+ void itemsFilteredByMime( const KFileItemList& );
+
+public slots:
+
+ /**
+ * Re-implemented for internal reasons. API is unaffected. All inheriting
+ * classes should re-implement @ref doOpenURL() instead instead of this one.
+ */
+ bool openURL (const KURL&);
+
+ /**
+ * This is called either by the part's close button, or by the
+ * dir part itself, if entering a directory. It deletes the find
+ * part.
+ */
+ void slotFindClosed();
+
+ /**
+ * Start the animated "K" during kfindpart's file search
+ */
+ void slotStartAnimationSearching();
+
+ /**
+ * Start the animated "K" during kfindpart's file search
+ */
+ void slotStopAnimationSearching();
+
+ void slotBackgroundSettings();
+
+ /**
+ * Called when the clipboard's data changes, to update the 'cut' icons
+ * Call this when the directory's listing is finished, to draw icons as cut.
+ */
+ void slotClipboardDataChanged();
+
+ void slotIncIconSize();
+ void slotDecIconSize();
+
+ void slotIconSizeToggled( bool );
+
+ // slots connected to the directory lister - or to the kfind interface
+ virtual void slotStarted() = 0;
+ virtual void slotCanceled() = 0;
+ virtual void slotCompleted() = 0;
+ virtual void slotNewItems( const KFileItemList& ) = 0;
+ virtual void slotDeleteItem( KFileItem * ) = 0;
+ virtual void slotRefreshItems( const KFileItemList& ) = 0;
+ virtual void slotClear() = 0;
+ virtual void slotRedirection( const KURL & ) = 0;
+
+private slots:
+ void slotIconChanged(int group);
+protected:
+ /**
+ * Invoked from openURL to enable childern classes to
+ * handle open URL requests.
+ */
+ virtual bool doOpenURL( const KURL& ) = 0;
+ virtual bool doCloseURL () = 0;
+
+protected:
+
+ QString m_nameFilter;
+ QStringList m_filesToSelect;
+
+ KonqPropsView * m_pProps;
+
+ KAction *m_paIncIconSize;
+ KAction *m_paDecIconSize;
+ KToggleAction *m_paDefaultIcons;
+ KToggleAction *m_paHugeIcons;
+ KToggleAction *m_paLargeIcons;
+ KToggleAction *m_paMediumIcons;
+ KToggleAction *m_paSmallIcons;
+
+ KParts::ReadOnlyPart * m_findPart;
+ KonqDirPartBrowserExtension * m_extension;
+
+ // Remove all those in KDE4
+ int m_iIconSize[5];
+ KIO::filesize_t m_lDirSize;
+ uint m_lFileCount;
+ uint m_lDirCount;
+
+private:
+ void saveFindState( QDataStream& );
+ void restoreFindState( QDataStream& );
+
+ void adjustIconSizes();
+
+ class KonqDirPartPrivate;
+ KonqDirPartPrivate* d;
+};
+
+class LIBKONQ_EXPORT KonqDirPartBrowserExtension : public KParts::BrowserExtension
+{
+public:
+ KonqDirPartBrowserExtension( KonqDirPart* dirPart )
+ : KParts::BrowserExtension( dirPart )
+ , m_dirPart( dirPart )
+ {}
+
+ /**
+ * This calls saveState in KonqDirPart, and also takes care of the "find part".
+ *
+ * If your KonqDirPart-derived class needs to save and restore state,
+ * you should probably override KonqDirPart::saveState
+ * and KonqDirPart::restoreState, not the following methods.
+ */
+ virtual void saveState( QDataStream &stream );
+ virtual void restoreState( QDataStream &stream );
+
+private:
+ KonqDirPart* m_dirPart;
+};
+
+#endif
diff --git a/libkonq/konq_drag.cc b/libkonq/konq_drag.cc
new file mode 100644
index 000000000..3333061c2
--- /dev/null
+++ b/libkonq/konq_drag.cc
@@ -0,0 +1,284 @@
+/* This file is part of the KDE projects
+ Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "konq_drag.h"
+#include <kdebug.h>
+#include <kurldrag.h>
+
+KonqIconDrag::KonqIconDrag( QWidget * dragSource, const char* name )
+ : QIconDrag( dragSource, name ),
+ m_bCutSelection( false )
+{
+}
+
+const char* KonqIconDrag::format( int i ) const
+{
+ if ( i == 0 )
+ return "application/x-qiconlist";
+ else if ( i == 1 )
+ return "text/uri-list";
+ else if ( i == 2 )
+ return "application/x-kde-cutselection";
+ else if ( i == 3 )
+ return "text/plain";
+ else if ( i == 4 ) //These two are imporant because they may end up being format 0,
+ //which is what KonqDirPart::updatePasteAction() checks
+ return "text/plain;charset=ISO-8859-1";
+ else if ( i == 5 ) //..as well as potentially for interoperability
+ return "text/plain;charset=UTF-8";
+ // warning, don't add anything here without checking KonqIconDrag2
+
+ else return 0;
+}
+
+QByteArray KonqIconDrag::encodedData( const char* mime ) const
+{
+ QByteArray a;
+ QCString mimetype( mime );
+ if ( mimetype == "application/x-qiconlist" )
+ a = QIconDrag::encodedData( mime );
+ else if ( mimetype == "text/uri-list" ) {
+ QCString s = urls.join( "\r\n" ).latin1();
+ if( urls.count() > 0 )
+ s.append( "\r\n" );
+ a.resize( s.length() + 1 ); // trailing zero
+ memcpy( a.data(), s.data(), s.length() + 1 );
+ }
+ else if ( mimetype == "application/x-kde-cutselection" ) {
+ QCString s ( m_bCutSelection ? "1" : "0" );
+ a.resize( s.length() + 1 ); // trailing zero
+ memcpy( a.data(), s.data(), s.length() + 1 );
+ }
+ else if ( mimetype == "text/plain" ) {
+ if (!urls.isEmpty())
+ {
+ QStringList uris;
+ for (QStringList::ConstIterator it = urls.begin(); it != urls.end(); ++it)
+ uris.append(KURLDrag::stringToUrl((*it).latin1()).prettyURL());
+ QCString s = uris.join( "\n" ).local8Bit();
+ if( uris.count() > 1 )
+ s.append( "\n" );
+ a.resize( s.length()); // no trailing zero in clipboard text
+ memcpy( a.data(), s.data(), s.length());
+ }
+ }
+ else if ( mimetype.lower() == "text/plain;charset=iso-8859-1")
+ {
+ if (!urls.isEmpty())
+ {
+ QStringList uris;
+
+ for (QStringList::ConstIterator it = urls.begin(); it != urls.end(); ++it)
+ uris.append(KURLDrag::stringToUrl((*it).latin1()).url(0, 4)); // 4 for latin1
+
+ QCString s = uris.join( "\n" ).latin1();
+ if( uris.count() > 1 )
+ s.append( "\n" );
+ a.resize( s.length());
+ memcpy( a.data(), s.data(), s.length());
+ }
+ }
+ else if ( mimetype.lower() == "text/plain;charset=utf-8")
+ {
+ if (!urls.isEmpty())
+ {
+ QStringList uris;
+ for (QStringList::ConstIterator it = urls.begin(); it != urls.end(); ++it)
+ uris.append(KURLDrag::stringToUrl((*it).latin1()).prettyURL());
+ QCString s = uris.join( "\n" ).utf8();
+ if( uris.count() > 1 )
+ s.append( "\n" );
+ a.resize( s.length());
+ memcpy( a.data(), s.data(), s.length());
+ }
+ }
+ return a;
+}
+
+bool KonqIconDrag::canDecode( const QMimeSource* e )
+{
+ return e->provides( "application/x-qiconlist" ) ||
+ e->provides( "text/uri-list" ) ||
+ e->provides( "application/x-kde-cutselection" );
+}
+
+void KonqIconDrag::append( const QIconDragItem &item, const QRect &pr,
+ const QRect &tr, const QString &url )
+{
+ QIconDrag::append( item, pr, tr );
+ urls.append( url );
+}
+
+KonqIconDrag2::KonqIconDrag2( QWidget * dragSource )
+ : KonqIconDrag( dragSource )
+{
+}
+
+void KonqIconDrag2::append( const QIconDragItem &item, const QRect &pr,
+ const QRect &tr, const QString& url, const KURL &mostLocalURL )
+{
+ QString mostLocalURLStr = KURLDrag::urlToString(mostLocalURL);
+ m_kdeURLs.append( url );
+ KonqIconDrag::append( item, pr, tr, mostLocalURLStr );
+}
+
+const char* KonqIconDrag2::format( int i ) const
+{
+ if ( i == 6 )
+ return "application/x-kde-urilist";
+ return KonqIconDrag::format( i );
+}
+
+QByteArray KonqIconDrag2::encodedData( const char* mime ) const
+{
+ QCString mimetype( mime );
+ if ( mimetype == "application/x-kde-urilist" )
+ {
+ QByteArray a;
+ int c=0;
+ for (QStringList::ConstIterator it = m_kdeURLs.begin(); it != m_kdeURLs.end(); ++it) {
+ QCString url = (*it).utf8();
+ int l = url.length();
+ a.resize(c+l+2);
+ memcpy(a.data()+c, url.data(), l);
+ memcpy(a.data()+c+l,"\r\n",2);
+ c += l+2;
+ }
+ a.resize(c+1);
+ a[c] = 0;
+ return a;
+ }
+ return KonqIconDrag::encodedData( mime );
+}
+
+//
+
+KonqDrag * KonqDrag::newDrag( const KURL::List & urls, bool cut, QWidget * dragSource, const char* name )
+{
+ // See KURLDrag::newDrag
+ QStrList uris;
+ KURL::List::ConstIterator uit = urls.begin();
+ KURL::List::ConstIterator uEnd = urls.end();
+ // Get each URL encoded in utf8 - and since we get it in escaped
+ // form on top of that, .latin1() is fine.
+ for ( ; uit != uEnd ; ++uit )
+ uris.append( KURLDrag::urlToString( *uit ).latin1() );
+ return new KonqDrag( uris, cut, dragSource, name );
+}
+
+// urls must be already checked to have hostname in file URLs
+KonqDrag::KonqDrag( const QStrList & urls, bool cut, QWidget * dragSource, const char* name )
+ : QUriDrag( urls, dragSource, name ),
+ m_bCutSelection( cut ), m_urls( urls )
+{}
+
+// urls must be already checked to have hostname in file URLs
+KonqDrag::KonqDrag( const KURL::List & urls, const KURL::List& mostLocalUrls,
+ bool cut, QWidget * dragSource )
+ : QUriDrag( dragSource ),
+ m_bCutSelection( cut )
+{
+ QStrList uris;
+ KURL::List::ConstIterator uit = urls.begin();
+ KURL::List::ConstIterator uEnd = urls.end();
+ // Get each URL encoded in utf8 - and since we get it in escaped
+ // form on top of that, .latin1() is fine.
+ for ( ; uit != uEnd ; ++uit )
+ uris.append( KURLDrag::urlToString( *uit ).latin1() );
+ setUris( uris ); // we give the KDE uris to QUriDrag. TODO: do the opposite in KDE4 and add a m_mostLocalUris member.
+
+ uit = mostLocalUrls.begin();
+ uEnd = mostLocalUrls.end();
+ for ( ; uit != uEnd ; ++uit )
+ m_urls.append( KURLDrag::urlToString( *uit ).latin1() );
+ // we keep the most-local-uris in m_urls for exporting those as text/plain (for xmms)
+}
+
+const char* KonqDrag::format( int i ) const
+{
+ if ( i == 0 )
+ return "text/uri-list";
+ else if ( i == 1 )
+ return "application/x-kde-cutselection";
+ else if ( i == 2 )
+ return "text/plain";
+ else if ( i == 3 )
+ return "application/x-kde-urilist";
+ else return 0;
+}
+
+QByteArray KonqDrag::encodedData( const char* mime ) const
+{
+ QByteArray a;
+ QCString mimetype( mime );
+ if ( mimetype == "text/uri-list" )
+ {
+ // Code taken from QUriDrag::setUris
+ int c=0;
+ for (QStrListIterator it(m_urls); *it; ++it) {
+ int l = qstrlen(*it);
+ a.resize(c+l+2);
+ memcpy(a.data()+c,*it,l);
+ memcpy(a.data()+c+l,"\r\n",2);
+ c+=l+2;
+ }
+ a.resize(c+1);
+ a[c] = 0;
+ }
+ else if ( mimetype == "application/x-kde-urilist" )
+ {
+ return QUriDrag::encodedData( "text/uri-list" );
+ }
+ else if ( mimetype == "application/x-kde-cutselection" )
+ {
+ QCString s ( m_bCutSelection ? "1" : "0" );
+ a.resize( s.length() + 1 ); // trailing zero
+ memcpy( a.data(), s.data(), s.length() + 1 );
+ }
+ else if ( mimetype == "text/plain" )
+ {
+ QStringList uris;
+ for (QStrListIterator it(m_urls); *it; ++it)
+ uris.append(KURLDrag::stringToUrl(*it).prettyURL());
+ QCString s = uris.join( "\n" ).local8Bit();
+ if( uris.count() > 1 )
+ s.append( "\n" );
+ a.resize( s.length() + 1 ); // trailing zero
+ memcpy( a.data(), s.data(), s.length() + 1 );
+ }
+ return a;
+}
+
+//
+
+// Used for KonqIconDrag too
+
+bool KonqDrag::decodeIsCutSelection( const QMimeSource *e )
+{
+ QByteArray a = e->encodedData( "application/x-kde-cutselection" );
+ if ( a.isEmpty() )
+ return false;
+ else
+ {
+ kdDebug(1203) << "KonqDrag::decodeIsCutSelection : a=" << QCString(a.data(), a.size() + 1) << endl;
+ return (a.at(0) == '1'); // true if 1
+ }
+}
+
+#include "konq_drag.moc"
diff --git a/libkonq/konq_drag.h b/libkonq/konq_drag.h
new file mode 100644
index 000000000..dca79676f
--- /dev/null
+++ b/libkonq/konq_drag.h
@@ -0,0 +1,122 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+
+ 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 __konqdrag_h__
+#define __konqdrag_h__
+
+#include <qdragobject.h>
+#include <qrect.h>
+#include <qstring.h>
+#include <qiconview.h>
+
+#include <libkonq_export.h>
+
+#include <kurl.h>
+
+/*****************************************************************************
+ *
+ * Class KonqIconDrag
+ *
+ *****************************************************************************/
+
+// Clipboard/dnd data for: Icons + URLS + isCut
+class LIBKONQ_EXPORT KonqIconDrag : public QIconDrag
+{
+ Q_OBJECT
+
+public:
+ KonqIconDrag( QWidget * dragSource, const char* name = 0 );
+ virtual ~KonqIconDrag() {}
+
+ const char* format( int i ) const;
+ QByteArray encodedData( const char* mime ) const;
+
+ void append( const QIconDragItem &item, const QRect &pr,
+ const QRect &tr, const QString &url );
+
+ void setMoveSelection( bool move ) { m_bCutSelection = move; }
+
+ static bool canDecode( const QMimeSource* e );
+
+protected: // KDE4: private. And d pointer...
+ QStringList urls;
+ bool m_bCutSelection;
+};
+
+/**
+ * Clipboard/dnd data for: Icons + URLs + MostLocal URLs + isCut
+ * KDE4: merge with KonqIconDrag
+ * @since 3.5
+ */
+class LIBKONQ_EXPORT KonqIconDrag2 : public KonqIconDrag
+{
+ Q_OBJECT
+
+public:
+ KonqIconDrag2( QWidget * dragSource );
+ virtual ~KonqIconDrag2() {}
+
+ virtual const char* format( int i ) const;
+ virtual QByteArray encodedData( const char* mime ) const;
+
+ void append( const QIconDragItem &item, const QRect &pr,
+ const QRect &tr, const QString &url, const KURL &mostLocalURL );
+
+private:
+ QStringList m_kdeURLs;
+};
+
+// Clipboard/dnd data for: URLS + isCut
+class LIBKONQ_EXPORT KonqDrag : public QUriDrag
+{
+public:
+ // KDE4: remove, use KonqDrag constructor instead
+ static KonqDrag * newDrag( const KURL::List & urls,
+ bool move, QWidget * dragSource = 0, const char* name = 0 );
+
+ /**
+ * Create a KonqDrag object.
+ * @param urls a list of URLs, which can use KDE-specific protocols, like system:/
+ * @param mostLocalUrls a list of URLs, which should be resolved to most-local urls, i.e. file:/
+ * @param cut false for copying, true for "cutting"
+ * @param dragSource parent object
+ * @since 3.5
+ */
+ KonqDrag( const KURL::List & urls, const KURL::List& mostLocalUrls, bool cut, QWidget * dragSource = 0 );
+
+protected:
+ // KDE4: remove
+ KonqDrag( const QStrList & urls, bool cut, QWidget * dragSource, const char* name );
+
+public:
+ virtual ~KonqDrag() {}
+
+ virtual const char* format( int i ) const;
+ virtual QByteArray encodedData( const char* mime ) const;
+
+ void setMoveSelection( bool move ) { m_bCutSelection = move; }
+
+ // Returns true if the data was cut (used for KonqIconDrag too)
+ static bool decodeIsCutSelection( const QMimeSource *e );
+
+protected: // KDE4: private. And d pointer...
+ bool m_bCutSelection;
+ QStrList m_urls; // this is set to the "most local urls". KDE4: KURL::List
+};
+
+#endif
diff --git a/libkonq/konq_events.cc b/libkonq/konq_events.cc
new file mode 100644
index 000000000..f608a8cdc
--- /dev/null
+++ b/libkonq/konq_events.cc
@@ -0,0 +1,8 @@
+
+#include <kfileitem.h>
+
+#include "konq_events.h"
+
+const char *KonqFileSelectionEvent::s_fileItemSelectionEventName = "Konqueror/FileSelection";
+const char *KonqFileMouseOverEvent::s_fileItemMouseOverEventName = "Konqueror/FileMouseOver";
+const char *KonqConfigEvent::s_configEventName = "Konqueror/Config";
diff --git a/libkonq/konq_events.h b/libkonq/konq_events.h
new file mode 100644
index 000000000..b76469717
--- /dev/null
+++ b/libkonq/konq_events.h
@@ -0,0 +1,70 @@
+#ifndef __konq_events_h__
+#define __konq_events_h__
+
+#include <kparts/event.h>
+#include <qptrlist.h>
+#include <libkonq_export.h>
+
+namespace KParts
+{
+ class ReadOnlyPart;
+}
+
+class KConfig;
+class KFileItem;
+typedef QPtrList<KFileItem> KFileItemList;
+
+class LIBKONQ_EXPORT KonqFileSelectionEvent : public KParts::Event
+{
+public:
+ KonqFileSelectionEvent( const KFileItemList &selection, KParts::ReadOnlyPart *part ) : KParts::Event( s_fileItemSelectionEventName ), m_selection( selection ), m_part( part ) {}
+
+ KFileItemList selection() const { return m_selection; }
+ KParts::ReadOnlyPart *part() const { return m_part; }
+
+ static bool test( const QEvent *event ) { return KParts::Event::test( event, s_fileItemSelectionEventName ); }
+
+private:
+ static const char *s_fileItemSelectionEventName;
+
+ KFileItemList m_selection;
+ KParts::ReadOnlyPart *m_part;
+};
+
+class LIBKONQ_EXPORT KonqFileMouseOverEvent : public KParts::Event
+{
+public:
+ KonqFileMouseOverEvent( const KFileItem *item, KParts::ReadOnlyPart *part ) : KParts::Event( s_fileItemMouseOverEventName ), m_item( item ), m_part( part ) {}
+
+ const KFileItem* item() const { return m_item; }
+ KParts::ReadOnlyPart *part() const { return m_part; }
+
+ static bool test( const QEvent *event ) { return KParts::Event::test( event, s_fileItemMouseOverEventName ); }
+
+private:
+ static const char *s_fileItemMouseOverEventName;
+
+ const KFileItem* m_item;
+ KParts::ReadOnlyPart *m_part;
+};
+
+class LIBKONQ_EXPORT KonqConfigEvent : public KParts::Event
+{
+public:
+ KonqConfigEvent( KConfig *config, const QString &prefix, bool save ) : KParts::Event( s_configEventName ), m_config( config ), m_prefix( prefix ), m_save( save ) {}
+
+ KConfig * config() const { return m_config; }
+ QString prefix() const { return m_prefix; }
+ bool save() const { return m_save; }
+
+ static bool test( const QEvent *event ) { return KParts::Event::test( event, s_configEventName ); }
+
+private:
+ static const char *s_configEventName;
+
+ KConfig *m_config;
+ QString m_prefix;
+ bool m_save;
+};
+
+#endif
diff --git a/libkonq/konq_faviconmgr.cc b/libkonq/konq_faviconmgr.cc
new file mode 100644
index 000000000..782beca91
--- /dev/null
+++ b/libkonq/konq_faviconmgr.cc
@@ -0,0 +1,57 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000 Malte Starostik <malte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <dcopclient.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kglobal.h>
+#include <kmimetype.h>
+
+#include "konq_faviconmgr.moc"
+
+KonqFavIconMgr::KonqFavIconMgr(QObject *parent, const char *name)
+ : QObject(parent, name),
+ DCOPObject("KonqFavIconMgr")
+{
+ connectDCOPSignal("kded", "favicons",
+ "iconChanged(bool, QString, QString)",
+ "notifyChange(bool, QString, QString)", false);
+}
+
+QString KonqFavIconMgr::iconForURL(const QString &url)
+{
+ return KMimeType::favIconForURL( KURL(url) );
+}
+
+void KonqFavIconMgr::setIconForURL(const KURL &url, const KURL &iconURL)
+{
+ QByteArray data;
+ QDataStream str(data, IO_WriteOnly);
+ str << url << iconURL;
+ kapp->dcopClient()->send("kded", "favicons", "setIconForURL(KURL, KURL)", data);
+}
+
+void KonqFavIconMgr::downloadHostIcon(const KURL &url)
+{
+ QByteArray data;
+ QDataStream str(data, IO_WriteOnly);
+ str << url;
+ kapp->dcopClient()->send("kded", "favicons", "downloadHostIcon(KURL)", data);
+}
+
diff --git a/libkonq/konq_faviconmgr.h b/libkonq/konq_faviconmgr.h
new file mode 100644
index 000000000..66175f682
--- /dev/null
+++ b/libkonq/konq_faviconmgr.h
@@ -0,0 +1,70 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 Malte Starostik <malte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __konq_faviconmgr_h__
+#define __konq_faviconmgr_h__
+
+#include <dcopobject.h>
+#include <kurl.h>
+#include <libkonq_export.h>
+
+/**
+ * Maintains a list of custom icons per URL. This is only a stub
+ * for the "favicons" KDED Module
+ */
+class LIBKONQ_EXPORT KonqFavIconMgr : public QObject, public DCOPObject
+{
+ Q_OBJECT
+ K_DCOP
+public:
+ /**
+ * Constructor.
+ */
+ KonqFavIconMgr(QObject *parent = 0, const char *name = 0);
+
+ /**
+ * Downloads an icon from @p iconURL and associates @p url with it.
+ */
+ static void setIconForURL(const KURL &url, const KURL &iconURL);
+
+ /**
+ * Downloads /favicon.ico from the host of @p url and associates all
+ * URLs on that host with it
+ * (unless a more specific entry for a URL exists)
+ */
+ static void downloadHostIcon(const KURL &url);
+
+ /**
+ * Looks up an icon for @p url and returns its name if found
+ * or QString::null otherwise
+ */
+ static QString iconForURL(const QString &url);
+
+k_dcop:
+ /**
+ * an icon changed, updates the combo box
+ */
+ virtual ASYNC notifyChange( bool, QString, QString ) = 0;
+
+signals:
+ void changed();
+};
+
+#endif
+
diff --git a/libkonq/konq_filetip.cc b/libkonq/konq_filetip.cc
new file mode 100644
index 000000000..c9c661c57
--- /dev/null
+++ b/libkonq/konq_filetip.cc
@@ -0,0 +1,300 @@
+/* This file is part of the KDE projects
+ Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ Copyright (C) 2000, 2001, 2002 David Faure <david@mandrakesoft.com>
+ Copyright (C) 2004 Martin Koller <m.koller@surfeu.at>
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <konq_filetip.h>
+
+#include <kfileitem.h>
+#include <kglobalsettings.h>
+#include <kstandarddirs.h>
+#include <kapplication.h>
+
+#include <qlabel.h>
+#include <qtooltip.h>
+#include <qlayout.h>
+#include <qpainter.h>
+#include <qscrollview.h>
+#include <qtimer.h>
+
+#include <fixx11h.h>
+//--------------------------------------------------------------------------------
+
+KonqFileTip::KonqFileTip( QScrollView* parent )
+ : QFrame( 0, 0, WStyle_Customize | WStyle_NoBorder | WStyle_Tool | WStyle_StaysOnTop | WX11BypassWM ),
+ m_on( false ),
+ m_preview( false ),
+ m_filter( false ),
+ m_corner( 0 ),
+ m_num( 0 ),
+ m_view( parent ),
+ m_item( 0 ),
+ m_previewJob( 0 )
+{
+ m_iconLabel = new QLabel(this);
+ m_textLabel = new QLabel(this);
+ m_textLabel->setAlignment(Qt::AlignAuto | Qt::AlignTop);
+
+ QGridLayout* layout = new QGridLayout(this, 1, 2, 8, 0);
+ layout->addWidget(m_iconLabel, 0, 0);
+ layout->addWidget(m_textLabel, 0, 1);
+ layout->setResizeMode(QLayout::Fixed);
+
+ setPalette( QToolTip::palette() );
+ setMargin( 1 );
+ setFrameStyle( QFrame::Plain | QFrame::Box );
+
+ m_timer = new QTimer(this);
+
+ hide();
+}
+
+KonqFileTip::~KonqFileTip()
+{
+ if ( m_previewJob ) {
+ m_previewJob->kill();
+ m_previewJob = 0;
+ }
+}
+
+void KonqFileTip::setPreview(bool on)
+{
+ m_preview = on;
+ if(on)
+ m_iconLabel->show();
+ else
+ m_iconLabel->hide();
+}
+
+void KonqFileTip::setOptions( bool on, bool preview, int num )
+{
+ setPreview(preview);
+ m_on = on;
+ m_num = num;
+}
+
+void KonqFileTip::setItem( KFileItem *item, const QRect &rect, const QPixmap *pixmap )
+{
+ hideTip();
+
+ if (!m_on) return;
+
+ if ( m_previewJob ) {
+ m_previewJob->kill();
+ m_previewJob = 0;
+ }
+
+ m_rect = rect;
+ m_item = item;
+
+ if ( m_item ) {
+ if (m_preview) {
+ if ( pixmap )
+ m_iconLabel->setPixmap( *pixmap );
+ else
+ m_iconLabel->setPixmap( QPixmap() );
+ }
+
+ // Don't start immediately, because the user could move the mouse over another item
+ // This avoids a quick sequence of started preview-jobs
+ m_timer->disconnect( this );
+ connect(m_timer, SIGNAL(timeout()), this, SLOT(startDelayed()));
+ m_timer->start( 300, true );
+ }
+}
+
+void KonqFileTip::reposition()
+{
+ if ( m_rect.isEmpty() || !m_view || !m_view->viewport() ) return;
+
+ QRect rect = m_rect;
+ QPoint off = m_view->viewport()->mapToGlobal( m_view->contentsToViewport( rect.topRight() ) );
+ rect.moveTopRight( off );
+
+ QPoint pos = rect.center();
+ // m_corner:
+ // 0: upperleft
+ // 1: upperright
+ // 2: lowerleft
+ // 3: lowerright
+ // 4+: none
+ m_corner = 0;
+ // should the tooltip be shown to the left or to the right of the ivi ?
+ QRect desk = KGlobalSettings::desktopGeometry(rect.center());
+ if (rect.center().x() + width() > desk.right())
+ {
+ // to the left
+ if (pos.x() - width() < 0) {
+ pos.setX(0);
+ m_corner = 4;
+ } else {
+ pos.setX( pos.x() - width() );
+ m_corner = 1;
+ }
+ }
+ // should the tooltip be shown above or below the ivi ?
+ if (rect.bottom() + height() > desk.bottom())
+ {
+ // above
+ pos.setY( rect.top() - height() );
+ m_corner += 2;
+ }
+ else pos.setY( rect.bottom() + 1 );
+
+ move( pos );
+ update();
+}
+
+void KonqFileTip::gotPreview( const KFileItem* item, const QPixmap& pixmap )
+{
+ m_previewJob = 0;
+ if (item != m_item) return;
+
+ m_iconLabel -> setPixmap(pixmap);
+}
+
+void KonqFileTip::gotPreviewResult()
+{
+ m_previewJob = 0;
+}
+
+void KonqFileTip::drawContents( QPainter *p )
+{
+ static const char * const names[] = {
+ "arrow_topleft",
+ "arrow_topright",
+ "arrow_bottomleft",
+ "arrow_bottomright"
+ };
+
+ if (m_corner >= 4) { // 4 is empty, so don't draw anything
+ QFrame::drawContents( p );
+ return;
+ }
+
+ if ( m_corners[m_corner].isNull())
+ m_corners[m_corner].load( locate( "data", QString::fromLatin1( "konqueror/pics/%1.png" ).arg( names[m_corner] ) ) );
+
+ QPixmap &pix = m_corners[m_corner];
+
+ switch ( m_corner )
+ {
+ case 0:
+ p->drawPixmap( 3, 3, pix );
+ break;
+ case 1:
+ p->drawPixmap( width() - pix.width() - 3, 3, pix );
+ break;
+ case 2:
+ p->drawPixmap( 3, height() - pix.height() - 3, pix );
+ break;
+ case 3:
+ p->drawPixmap( width() - pix.width() - 3, height() - pix.height() - 3, pix );
+ break;
+ }
+
+ QFrame::drawContents( p );
+}
+
+void KonqFileTip::setFilter( bool enable )
+{
+ if ( enable == m_filter ) return;
+
+ if ( enable ) {
+ kapp->installEventFilter( this );
+ QApplication::setGlobalMouseTracking( true );
+ }
+ else {
+ QApplication::setGlobalMouseTracking( false );
+ kapp->removeEventFilter( this );
+ }
+ m_filter = enable;
+}
+
+void KonqFileTip::showTip()
+{
+ QString text = m_item->getToolTipText(m_num);
+
+ if ( text.isEmpty() ) return;
+
+ m_timer->disconnect( this );
+ connect(m_timer, SIGNAL(timeout()), this, SLOT(hideTip()));
+ m_timer->start( 15000, true );
+
+ m_textLabel->setText( text );
+
+ setFilter( true );
+
+ reposition();
+ show();
+}
+
+void KonqFileTip::hideTip()
+{
+ m_timer->stop();
+ setFilter( false );
+ if ( isShown() && m_view && m_view->viewport() &&
+ (m_view->horizontalScrollBar()->isShown() || m_view->verticalScrollBar()->isShown()) )
+ m_view->viewport()->update();
+ hide();
+}
+void KonqFileTip::startDelayed()
+{
+ if ( m_preview ) {
+ KFileItemList oneItem;
+ oneItem.append( m_item );
+
+ m_previewJob = KIO::filePreview( oneItem, 256, 256, 64, 70, true, true, 0);
+ connect( m_previewJob, SIGNAL( gotPreview( const KFileItem *, const QPixmap & ) ),
+ this, SLOT( gotPreview( const KFileItem *, const QPixmap & ) ) );
+ connect( m_previewJob, SIGNAL( result( KIO::Job * ) ),
+ this, SLOT( gotPreviewResult() ) );
+ }
+
+ m_timer->disconnect( this );
+ connect(m_timer, SIGNAL(timeout()), this, SLOT(showTip()));
+ m_timer->start( 400, true );
+}
+
+void KonqFileTip::resizeEvent( QResizeEvent* event )
+{
+ QFrame::resizeEvent(event);
+ reposition();
+}
+
+bool KonqFileTip::eventFilter( QObject *, QEvent *e )
+{
+ switch ( e->type() )
+ {
+ case QEvent::Leave:
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease:
+ case QEvent::FocusIn:
+ case QEvent::FocusOut:
+ case QEvent::Wheel:
+ hideTip();
+ default: break;
+ }
+
+ return false;
+}
+
+#include "konq_filetip.moc"
diff --git a/libkonq/konq_filetip.h b/libkonq/konq_filetip.h
new file mode 100644
index 000000000..fc878c074
--- /dev/null
+++ b/libkonq/konq_filetip.h
@@ -0,0 +1,97 @@
+/* This file is part of the KDE projects
+ Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ Copyright (C) 2000, 2001, 2002 David Faure <david@mandrakesoft.com>
+ Copyright (C) 2004 Martin Koller <m.koller@surfeu.at>
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KONQ_FILETIP_H
+#define KONQ_FILETIP_H
+
+#include <qframe.h>
+#include <qpixmap.h>
+#include <kio/previewjob.h>
+
+#include <libkonq_export.h>
+
+class KFileItem;
+class QLabel;
+class QScrollView;
+class QTimer;
+
+//--------------------------------------------------------------------------------
+
+class LIBKONQ_EXPORT KonqFileTip : public QFrame
+{
+ Q_OBJECT
+
+ public:
+ KonqFileTip( QScrollView *parent );
+ ~KonqFileTip();
+
+ void setPreview(bool on);
+
+ /**
+ @param on show tooltip at all
+ @param preview include file preview in tooltip
+ @param num the number of tooltip texts to get from KFileItem
+ */
+ void setOptions( bool on, bool preview, int num );
+
+ /** Set the item from which to get the tip information
+ @param item the item from which to get the tip information
+ @param rect the rectangle around which the tip will be shown
+ @param pixmap the pixmap to be shown. If 0, no pixmap is shown
+ */
+ void setItem( KFileItem *item, const QRect &rect = QRect(),
+ const QPixmap *pixmap = 0 );
+
+ virtual bool eventFilter( QObject *, QEvent *e );
+
+ protected:
+ virtual void drawContents( QPainter *p );
+ virtual void resizeEvent( QResizeEvent * );
+
+ private slots:
+ void gotPreview( const KFileItem*, const QPixmap& );
+ void gotPreviewResult();
+
+ void startDelayed();
+ void showTip();
+ void hideTip();
+
+ private:
+ void setFilter( bool enable );
+
+ void reposition();
+
+ QLabel* m_iconLabel;
+ QLabel* m_textLabel;
+ bool m_on : 1;
+ bool m_preview : 1; // shall the preview icon be shown
+ bool m_filter : 1;
+ QPixmap m_corners[4];
+ int m_corner;
+ int m_num;
+ QScrollView* m_view;
+ KFileItem* m_item;
+ KIO::PreviewJob* m_previewJob;
+ QRect m_rect;
+ QTimer* m_timer;
+};
+
+#endif
diff --git a/libkonq/konq_historycomm.cc b/libkonq/konq_historycomm.cc
new file mode 100644
index 000000000..0875a7945
--- /dev/null
+++ b/libkonq/konq_historycomm.cc
@@ -0,0 +1,41 @@
+#include "konq_historycomm.h"
+
+bool KonqHistoryEntry::marshalURLAsStrings;
+
+// QDataStream operators (read and write a KonqHistoryEntry
+// from/into a QDataStream)
+QDataStream& operator<< (QDataStream& s, const KonqHistoryEntry& e) {
+ if (KonqHistoryEntry::marshalURLAsStrings)
+ s << e.url.url();
+ else
+ s << e.url;
+
+ s << e.typedURL;
+ s << e.title;
+ s << e.numberOfTimesVisited;
+ s << e.firstVisited;
+ s << e.lastVisited;
+
+ return s;
+}
+
+QDataStream& operator>> (QDataStream& s, KonqHistoryEntry& e) {
+ if (KonqHistoryEntry::marshalURLAsStrings)
+ {
+ QString url;
+ s >> url;
+ e.url = url;
+ }
+ else
+ {
+ s>>e.url;
+ }
+
+ s >> e.typedURL;
+ s >> e.title;
+ s >> e.numberOfTimesVisited;
+ s >> e.firstVisited;
+ s >> e.lastVisited;
+
+ return s;
+}
diff --git a/libkonq/konq_historycomm.h b/libkonq/konq_historycomm.h
new file mode 100644
index 000000000..e02e10a61
--- /dev/null
+++ b/libkonq/konq_historycomm.h
@@ -0,0 +1,77 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KONQ_HISTORYCOMM_H
+#define KONQ_HISTORYCOMM_H
+
+#include <qdatetime.h>
+#include <qstringlist.h>
+
+#include <dcopobject.h>
+#include <kurl.h>
+
+class KonqHistoryEntry
+{
+public:
+ //Should URLs be marshaled as strings (for DCOP, V2 history format)?
+ static bool marshalURLAsStrings;
+ KonqHistoryEntry()
+ : numberOfTimesVisited(1) {}
+
+ KURL url;
+ QString typedURL;
+ QString title;
+ Q_UINT32 numberOfTimesVisited;
+ QDateTime firstVisited;
+ QDateTime lastVisited;
+};
+
+
+// QDataStream operators (read and write a KonqHistoryEntry
+// from/into a QDataStream
+QDataStream& operator<< (QDataStream& s, const KonqHistoryEntry& e);
+QDataStream& operator>> (QDataStream& s, KonqHistoryEntry& e);
+
+///////////////////////////////////////////////////////////////////
+
+
+/**
+ * DCOP Methods for KonqHistoryManager. Has to be in a separate file, because
+ * dcopidl2cpp barfs on every second construct ;(
+ * Implementations of the pure virtual methods are in KonqHistoryManager
+ */
+class KonqHistoryComm : public DCOPObject
+{
+ K_DCOP
+
+protected:
+ KonqHistoryComm( QCString objId ) : DCOPObject( objId ) {}
+
+k_dcop:
+ virtual ASYNC notifyHistoryEntry( KonqHistoryEntry e, QCString saveId) = 0;
+ virtual ASYNC notifyMaxCount( Q_UINT32 count, QCString saveId ) = 0;
+ virtual ASYNC notifyMaxAge( Q_UINT32 days, QCString saveId ) = 0;
+ virtual ASYNC notifyClear( QCString saveId ) = 0;
+ virtual ASYNC notifyRemove( KURL url, QCString saveId ) = 0;
+ virtual ASYNC notifyRemove( KURL::List url, QCString saveId ) = 0;
+ virtual QStringList allURLs() const = 0;
+
+};
+
+#endif // KONQ_HISTORYCOMM_H
diff --git a/libkonq/konq_historymgr.cc b/libkonq/konq_historymgr.cc
new file mode 100644
index 000000000..72c6be3de
--- /dev/null
+++ b/libkonq/konq_historymgr.cc
@@ -0,0 +1,733 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000,2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "konq_historymgr.h"
+
+#include <dcopclient.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <ksavefile.h>
+#include <ksimpleconfig.h>
+#include <kstandarddirs.h>
+
+#include <zlib.h>
+
+#include "konqbookmarkmanager.h"
+
+const Q_UINT32 KonqHistoryManager::s_historyVersion = 3;
+
+KonqHistoryManager::KonqHistoryManager( QObject *parent, const char *name )
+ : KParts::HistoryProvider( parent, name ),
+ KonqHistoryComm( "KonqHistoryManager" )
+{
+ m_updateTimer = new QTimer( this );
+
+ // defaults
+ KConfig *config = KGlobal::config();
+ KConfigGroupSaver cs( config, "HistorySettings" );
+ m_maxCount = config->readNumEntry( "Maximum of History entries", 500 );
+ m_maxCount = QMAX( 1, m_maxCount );
+ m_maxAgeDays = config->readNumEntry( "Maximum age of History entries", 90);
+
+ m_history.setAutoDelete( true );
+ m_filename = locateLocal( "data",
+ QString::fromLatin1("konqueror/konq_history" ));
+
+ if ( !kapp->dcopClient()->isAttached() )
+ kapp->dcopClient()->attach();
+
+
+ // take care of the completion object
+ m_pCompletion = new KCompletion;
+ m_pCompletion->setOrder( KCompletion::Weighted );
+
+ // and load the history
+ loadHistory();
+
+ connect( m_updateTimer, SIGNAL( timeout() ), SLOT( slotEmitUpdated() ));
+}
+
+
+KonqHistoryManager::~KonqHistoryManager()
+{
+ delete m_pCompletion;
+ clearPending();
+}
+
+bool KonqHistoryManager::isSenderOfBroadcast()
+{
+ DCOPClient *dc = callingDcopClient();
+ return !dc || (dc->senderId() == dc->appId());
+}
+
+// loads the entire history
+bool KonqHistoryManager::loadHistory()
+{
+ clearPending();
+ m_history.clear();
+ m_pCompletion->clear();
+
+ QFile file( m_filename );
+ if ( !file.open( IO_ReadOnly ) ) {
+ if ( file.exists() )
+ kdWarning() << "Can't open " << file.name() << endl;
+
+ // try to load the old completion history
+ bool ret = loadFallback();
+ emit loadingFinished();
+ return ret;
+ }
+
+ QDataStream fileStream( &file );
+ QByteArray data; // only used for version == 2
+ // we construct the stream object now but fill in the data later.
+ // thanks to QBA's explicit sharing this works :)
+ QDataStream crcStream( data, IO_ReadOnly );
+
+ if ( !fileStream.atEnd() ) {
+ Q_UINT32 version;
+ fileStream >> version;
+
+ QDataStream *stream = &fileStream;
+
+ bool crcChecked = false;
+ bool crcOk = false;
+
+ if ( version == 2 || version == 3) {
+ Q_UINT32 crc;
+ crcChecked = true;
+ fileStream >> crc >> data;
+ crcOk = crc32( 0, reinterpret_cast<unsigned char *>( data.data() ), data.size() ) == crc;
+ stream = &crcStream; // pick up the right stream
+ }
+
+ if ( version == 3 )
+ {
+ //Use KURL marshalling for V3 format.
+ KonqHistoryEntry::marshalURLAsStrings = false;
+ }
+
+ if ( version != 0 && version < 3 ) //Versions 1,2 (but not 0) are also valid
+ {
+ //Turn on backwards compatibility mode..
+ KonqHistoryEntry::marshalURLAsStrings = true;
+ // it doesn't make sense to save to save maxAge and maxCount in the
+ // binary file, this would make backups impossible (they would clear
+ // themselves on startup, because all entries expire).
+ // [But V1 and V2 formats did it, so we do a dummy read]
+ Q_UINT32 dummy;
+ *stream >> dummy;
+ *stream >> dummy;
+
+ //OK.
+ version = 3;
+ }
+
+ if ( s_historyVersion != version || ( crcChecked && !crcOk ) ) {
+ kdWarning() << "The history version doesn't match, aborting loading" << endl;
+ file.close();
+ emit loadingFinished();
+ return false;
+ }
+
+
+ while ( !stream->atEnd() ) {
+ KonqHistoryEntry *entry = new KonqHistoryEntry;
+ Q_CHECK_PTR( entry );
+ *stream >> *entry;
+ // kdDebug(1203) << "## loaded entry: " << entry->url << ", Title: " << entry->title << endl;
+ m_history.append( entry );
+ QString urlString2 = entry->url.prettyURL();
+
+ addToCompletion( urlString2, entry->typedURL, entry->numberOfTimesVisited );
+
+ // and fill our baseclass.
+ QString urlString = entry->url.url();
+ KParts::HistoryProvider::insert( urlString );
+ // DF: also insert the "pretty" version if different
+ // This helps getting 'visited' links on websites which don't use fully-escaped urls.
+
+ if ( urlString != urlString2 )
+ KParts::HistoryProvider::insert( urlString2 );
+ }
+
+ kdDebug(1203) << "## loaded: " << m_history.count() << " entries." << endl;
+
+ m_history.sort();
+ adjustSize();
+ }
+
+
+ //This is important - we need to switch to a consistent marshalling format for
+ //communicating between different konqueror instances. Since during an upgrade
+ //some "old" copies may still running, we use the old format for the DCOP transfers.
+ //This doesn't make that much difference performance-wise for single entries anyway.
+ KonqHistoryEntry::marshalURLAsStrings = true;
+
+
+ // Theoretically, we should emit update() here, but as we only ever
+ // load items on startup up to now, this doesn't make much sense. Same
+ // thing for the above loadFallback().
+ // emit KParts::HistoryProvider::update( some list );
+
+
+
+ file.close();
+ emit loadingFinished();
+
+ return true;
+}
+
+
+// saves the entire history
+bool KonqHistoryManager::saveHistory()
+{
+ KSaveFile file( m_filename );
+ if ( file.status() != 0 ) {
+ kdWarning() << "Can't open " << file.name() << endl;
+ return false;
+ }
+
+ QDataStream *fileStream = file.dataStream();
+ *fileStream << s_historyVersion;
+
+ QByteArray data;
+ QDataStream stream( data, IO_WriteOnly );
+
+ //We use KURL for marshalling URLs in entries in the V3
+ //file format
+ KonqHistoryEntry::marshalURLAsStrings = false;
+ QPtrListIterator<KonqHistoryEntry> it( m_history );
+ KonqHistoryEntry *entry;
+ while ( (entry = it.current()) ) {
+ stream << *entry;
+ ++it;
+ }
+
+ //For DCOP, transfer strings instead - wire compat.
+ KonqHistoryEntry::marshalURLAsStrings = true;
+
+ Q_UINT32 crc = crc32( 0, reinterpret_cast<unsigned char *>( data.data() ), data.size() );
+ *fileStream << crc << data;
+
+ file.close();
+
+ return true;
+}
+
+
+void KonqHistoryManager::adjustSize()
+{
+ KonqHistoryEntry *entry = m_history.getFirst();
+
+ while ( m_history.count() > m_maxCount || isExpired( entry ) ) {
+ removeFromCompletion( entry->url.prettyURL(), entry->typedURL );
+
+ QString urlString = entry->url.url();
+ KParts::HistoryProvider::remove( urlString );
+
+ addToUpdateList( urlString );
+
+ emit entryRemoved( m_history.getFirst() );
+ m_history.removeFirst(); // deletes the entry
+
+ entry = m_history.getFirst();
+ }
+}
+
+
+void KonqHistoryManager::addPending( const KURL& url, const QString& typedURL,
+ const QString& title )
+{
+ addToHistory( true, url, typedURL, title );
+}
+
+void KonqHistoryManager::confirmPending( const KURL& url,
+ const QString& typedURL,
+ const QString& title )
+{
+ addToHistory( false, url, typedURL, title );
+}
+
+
+void KonqHistoryManager::addToHistory( bool pending, const KURL& _url,
+ const QString& typedURL,
+ const QString& title )
+{
+ kdDebug(1203) << "## addToHistory: " << _url.prettyURL() << " Typed URL: " << typedURL << ", Title: " << title << endl;
+
+ if ( filterOut( _url ) ) // we only want remote URLs
+ return;
+
+ // http URLs without a path will get redirected immediately to url + '/'
+ if ( _url.path().isEmpty() && _url.protocol().startsWith("http") )
+ return;
+
+ KURL url( _url );
+ bool hasPass = url.hasPass();
+ url.setPass( QString::null ); // No password in the history, especially not in the completion!
+ url.setHost( url.host().lower() ); // All host parts lower case
+ KonqHistoryEntry entry;
+ QString u = url.prettyURL();
+ entry.url = url;
+ if ( (u != typedURL) && !hasPass )
+ entry.typedURL = typedURL;
+
+ // we only keep the title if we are confirming an entry. Otherwise,
+ // we might get bogus titles from the previous url (actually it's just
+ // konqueror's window caption).
+ if ( !pending && u != title )
+ entry.title = title;
+ entry.firstVisited = QDateTime::currentDateTime();
+ entry.lastVisited = entry.firstVisited;
+
+ // always remove from pending if available, otherwise the else branch leaks
+ // if the map already contains an entry for this key.
+ QMapIterator<QString,KonqHistoryEntry*> it = m_pending.find( u );
+ if ( it != m_pending.end() ) {
+ delete it.data();
+ m_pending.remove( it );
+ }
+
+ if ( !pending ) {
+ if ( it != m_pending.end() ) {
+ // we make a pending entry official, so we just have to update
+ // and not increment the counter. No need to care about
+ // firstVisited, as this is not taken into account on update.
+ entry.numberOfTimesVisited = 0;
+ }
+ }
+
+ else {
+ // We add a copy of the current history entry of the url to the
+ // pending list, so that we can restore it if the user canceled.
+ // If there is no entry for the url yet, we just store the url.
+ KonqHistoryEntry *oldEntry = findEntry( url );
+ m_pending.insert( u, oldEntry ?
+ new KonqHistoryEntry( *oldEntry ) : 0L );
+ }
+
+ // notify all konqueror instances about the entry
+ emitAddToHistory( entry );
+}
+
+// interface of KParts::HistoryManager
+// Usually, we only record the history for non-local URLs (i.e. filterOut()
+// returns false). But when using the HistoryProvider interface, we record
+// exactly those filtered-out urls.
+// Moreover, we don't get any pending/confirming entries, just one insert()
+void KonqHistoryManager::insert( const QString& url )
+{
+ KURL u ( url );
+ if ( !filterOut( u ) || u.protocol() == "about" ) { // remote URL
+ return;
+ }
+ // Local URL -> add to history
+ KonqHistoryEntry entry;
+ entry.url = u;
+ entry.firstVisited = QDateTime::currentDateTime();
+ entry.lastVisited = entry.firstVisited;
+ emitAddToHistory( entry );
+}
+
+void KonqHistoryManager::emitAddToHistory( const KonqHistoryEntry& entry )
+{
+ QByteArray data;
+ QDataStream stream( data, IO_WriteOnly );
+ stream << entry << objId();
+ // Protection against very long urls (like data:)
+ if ( data.size() > 4096 )
+ return;
+ kapp->dcopClient()->send( "konqueror*", "KonqHistoryManager",
+ "notifyHistoryEntry(KonqHistoryEntry, QCString)",
+ data );
+}
+
+
+void KonqHistoryManager::removePending( const KURL& url )
+{
+ // kdDebug(1203) << "## Removing pending... " << url.prettyURL() << endl;
+
+ if ( url.isLocalFile() )
+ return;
+
+ QMapIterator<QString,KonqHistoryEntry*> it = m_pending.find( url.prettyURL() );
+ if ( it != m_pending.end() ) {
+ KonqHistoryEntry *oldEntry = it.data(); // the old entry, may be 0L
+ emitRemoveFromHistory( url ); // remove the current pending entry
+
+ if ( oldEntry ) // we had an entry before, now use that instead
+ emitAddToHistory( *oldEntry );
+
+ delete oldEntry;
+ m_pending.remove( it );
+ }
+}
+
+// clears the pending list and makes sure the entries get deleted.
+void KonqHistoryManager::clearPending()
+{
+ QMapIterator<QString,KonqHistoryEntry*> it = m_pending.begin();
+ while ( it != m_pending.end() ) {
+ delete it.data();
+ ++it;
+ }
+ m_pending.clear();
+}
+
+void KonqHistoryManager::emitRemoveFromHistory( const KURL& url )
+{
+ QByteArray data;
+ QDataStream stream( data, IO_WriteOnly );
+ stream << url << objId();
+ kapp->dcopClient()->send( "konqueror*", "KonqHistoryManager",
+ "notifyRemove(KURL, QCString)", data );
+}
+
+void KonqHistoryManager::emitRemoveFromHistory( const KURL::List& urls )
+{
+ QByteArray data;
+ QDataStream stream( data, IO_WriteOnly );
+ stream << urls << objId();
+ kapp->dcopClient()->send( "konqueror*", "KonqHistoryManager",
+ "notifyRemove(KURL::List, QCString)", data );
+}
+
+void KonqHistoryManager::emitClear()
+{
+ QByteArray data;
+ QDataStream stream( data, IO_WriteOnly );
+ stream << objId();
+ kapp->dcopClient()->send( "konqueror*", "KonqHistoryManager",
+ "notifyClear(QCString)", data );
+}
+
+void KonqHistoryManager::emitSetMaxCount( Q_UINT32 count )
+{
+ QByteArray data;
+ QDataStream stream( data, IO_WriteOnly );
+ stream << count << objId();
+ kapp->dcopClient()->send( "konqueror*", "KonqHistoryManager",
+ "notifyMaxCount(Q_UINT32, QCString)", data );
+}
+
+void KonqHistoryManager::emitSetMaxAge( Q_UINT32 days )
+{
+ QByteArray data;
+ QDataStream stream( data, IO_WriteOnly );
+ stream << days << objId();
+ kapp->dcopClient()->send( "konqueror*", "KonqHistoryManager",
+ "notifyMaxAge(Q_UINT32, QCString)", data );
+}
+
+///////////////////////////////////////////////////////////////////
+// DCOP called methods
+
+void KonqHistoryManager::notifyHistoryEntry( KonqHistoryEntry e,
+ QCString )
+{
+ //kdDebug(1203) << "Got new entry from Broadcast: " << e.url.prettyURL() << endl;
+
+ KonqHistoryEntry *entry = findEntry( e.url );
+ QString urlString = e.url.url();
+
+ if ( !entry ) { // create a new history entry
+ entry = new KonqHistoryEntry;
+ entry->url = e.url;
+ entry->firstVisited = e.firstVisited;
+ entry->numberOfTimesVisited = 0; // will get set to 1 below
+ m_history.append( entry );
+ KParts::HistoryProvider::insert( urlString );
+ }
+
+ if ( !e.typedURL.isEmpty() )
+ entry->typedURL = e.typedURL;
+ if ( !e.title.isEmpty() )
+ entry->title = e.title;
+ entry->numberOfTimesVisited += e.numberOfTimesVisited;
+ entry->lastVisited = e.lastVisited;
+
+ addToCompletion( entry->url.prettyURL(), entry->typedURL );
+
+ // bool pending = (e.numberOfTimesVisited != 0);
+
+ adjustSize();
+
+ // note, no need to do the updateBookmarkMetadata for every
+ // history object, only need to for the broadcast sender as
+ // the history object itself keeps the data consistant.
+ bool updated = KonqBookmarkManager::self()->updateAccessMetadata( urlString );
+
+ if ( isSenderOfBroadcast() ) {
+ // we are the sender of the broadcast, so we save
+ saveHistory();
+ // note, bk save does not notify, and we don't want to!
+ if (updated)
+ KonqBookmarkManager::self()->save();
+ }
+
+ addToUpdateList( urlString );
+ emit entryAdded( entry );
+}
+
+void KonqHistoryManager::notifyMaxCount( Q_UINT32 count, QCString )
+{
+ m_maxCount = count;
+ clearPending();
+ adjustSize();
+
+ KConfig *config = KGlobal::config();
+ KConfigGroupSaver cs( config, "HistorySettings" );
+ config->writeEntry( "Maximum of History entries", m_maxCount );
+
+ if ( isSenderOfBroadcast() ) {
+ saveHistory();
+ config->sync();
+ }
+}
+
+void KonqHistoryManager::notifyMaxAge( Q_UINT32 days, QCString )
+{
+ m_maxAgeDays = days;
+ clearPending();
+ adjustSize();
+
+ KConfig *config = KGlobal::config();
+ KConfigGroupSaver cs( config, "HistorySettings" );
+ config->writeEntry( "Maximum age of History entries", m_maxAgeDays );
+
+ if ( isSenderOfBroadcast() ) {
+ saveHistory();
+ config->sync();
+ }
+}
+
+void KonqHistoryManager::notifyClear( QCString )
+{
+ clearPending();
+ m_history.clear();
+ m_pCompletion->clear();
+
+ if ( isSenderOfBroadcast() )
+ saveHistory();
+
+ KParts::HistoryProvider::clear(); // also emits the cleared() signal
+}
+
+void KonqHistoryManager::notifyRemove( KURL url, QCString )
+{
+ kdDebug(1203) << "#### Broadcast: remove entry:: " << url.prettyURL() << endl;
+
+
+ KonqHistoryEntry *entry = m_history.findEntry( url );
+
+ if ( entry ) { // entry is now the current item
+ removeFromCompletion( entry->url.prettyURL(), entry->typedURL );
+
+ QString urlString = entry->url.url();
+ KParts::HistoryProvider::remove( urlString );
+
+ addToUpdateList( urlString );
+
+ m_history.take(); // does not delete
+ emit entryRemoved( entry );
+ delete entry;
+
+ if ( isSenderOfBroadcast() )
+ saveHistory();
+ }
+}
+
+void KonqHistoryManager::notifyRemove( KURL::List urls, QCString )
+{
+ kdDebug(1203) << "#### Broadcast: removing list!" << endl;
+
+ bool doSave = false;
+ KURL::List::Iterator it = urls.begin();
+ while ( it != urls.end() ) {
+ KonqHistoryEntry *entry = m_history.findEntry( *it );
+
+ if ( entry ) { // entry is now the current item
+ removeFromCompletion( entry->url.prettyURL(), entry->typedURL );
+
+ QString urlString = entry->url.url();
+ KParts::HistoryProvider::remove( urlString );
+
+ addToUpdateList( urlString );
+
+ m_history.take(); // does not delete
+ emit entryRemoved( entry );
+ delete entry;
+ doSave = true;
+ }
+
+ ++it;
+ }
+
+ if (doSave && isSenderOfBroadcast())
+ saveHistory();
+}
+
+
+// compatibility fallback, try to load the old completion history
+bool KonqHistoryManager::loadFallback()
+{
+ QString file = locateLocal( "config", QString::fromLatin1("konq_history"));
+ if ( file.isEmpty() )
+ return false;
+
+ KonqHistoryEntry *entry;
+ KSimpleConfig config( file );
+ config.setGroup("History");
+ QStringList items = config.readListEntry( "CompletionItems" );
+ QStringList::Iterator it = items.begin();
+
+ while ( it != items.end() ) {
+ entry = createFallbackEntry( *it );
+ if ( entry ) {
+ m_history.append( entry );
+ addToCompletion( entry->url.prettyURL(), QString::null, entry->numberOfTimesVisited );
+
+ KParts::HistoryProvider::insert( entry->url.url() );
+ }
+ ++it;
+ }
+
+ m_history.sort();
+ adjustSize();
+ saveHistory();
+
+ return true;
+}
+
+// tries to create a small KonqHistoryEntry out of a string, where the string
+// looks like "http://www.bla.com/bla.html:23"
+// the attached :23 is the weighting from KCompletion
+KonqHistoryEntry * KonqHistoryManager::createFallbackEntry(const QString& item) const
+{
+ // code taken from KCompletion::addItem(), adjusted to use weight = 1
+ uint len = item.length();
+ uint weight = 1;
+
+ // find out the weighting of this item (appended to the string as ":num")
+ int index = item.findRev(':');
+ if ( index > 0 ) {
+ bool ok;
+ weight = item.mid( index + 1 ).toUInt( &ok );
+ if ( !ok )
+ weight = 1;
+
+ len = index; // only insert until the ':'
+ }
+
+
+ KonqHistoryEntry *entry = 0L;
+ KURL u( item.left( len ));
+ if ( u.isValid() ) {
+ entry = new KonqHistoryEntry;
+ // that's the only entries we know about...
+ entry->url = u;
+ entry->numberOfTimesVisited = weight;
+ // to make it not expire immediately...
+ entry->lastVisited = QDateTime::currentDateTime();
+ }
+
+ return entry;
+}
+
+KonqHistoryEntry * KonqHistoryManager::findEntry( const KURL& url )
+{
+ // small optimization (dict lookup) for items _not_ in our history
+ if ( !KParts::HistoryProvider::contains( url.url() ) )
+ return 0L;
+
+ return m_history.findEntry( url );
+}
+
+bool KonqHistoryManager::filterOut( const KURL& url )
+{
+ return ( url.isLocalFile() || url.host().isEmpty() );
+}
+
+void KonqHistoryManager::slotEmitUpdated()
+{
+ emit KParts::HistoryProvider::updated( m_updateURLs );
+ m_updateURLs.clear();
+}
+
+QStringList KonqHistoryManager::allURLs() const
+{
+ QStringList list;
+ KonqHistoryIterator it ( m_history );
+ for ( ; it.current(); ++it )
+ list.append( it.current()->url.url() );
+
+ return list;
+}
+
+void KonqHistoryManager::addToCompletion( const QString& url, const QString& typedURL,
+ int numberOfTimesVisited )
+{
+ m_pCompletion->addItem( url, numberOfTimesVisited );
+ // typed urls have a higher priority
+ m_pCompletion->addItem( typedURL, numberOfTimesVisited +10 );
+}
+
+void KonqHistoryManager::removeFromCompletion( const QString& url, const QString& typedURL )
+{
+ m_pCompletion->removeItem( url );
+ m_pCompletion->removeItem( typedURL );
+}
+
+//////////////////////////////////////////////////////////////////
+
+
+KonqHistoryEntry * KonqHistoryList::findEntry( const KURL& url )
+{
+ // we search backwards, probably faster to find an entry
+ KonqHistoryEntry *entry = last();
+ while ( entry ) {
+ if ( entry->url == url )
+ return entry;
+
+ entry = prev();
+ }
+
+ return 0L;
+}
+
+// sort by lastVisited date (oldest go first)
+int KonqHistoryList::compareItems( QPtrCollection::Item item1,
+ QPtrCollection::Item item2 )
+{
+ KonqHistoryEntry *entry1 = static_cast<KonqHistoryEntry *>( item1 );
+ KonqHistoryEntry *entry2 = static_cast<KonqHistoryEntry *>( item2 );
+
+ if ( entry1->lastVisited > entry2->lastVisited )
+ return 1;
+ else if ( entry1->lastVisited < entry2->lastVisited )
+ return -1;
+ else
+ return 0;
+}
+
+using namespace KParts; // for IRIX
+
+#include "konq_historymgr.moc"
diff --git a/libkonq/konq_historymgr.h b/libkonq/konq_historymgr.h
new file mode 100644
index 000000000..4ddcb5e83
--- /dev/null
+++ b/libkonq/konq_historymgr.h
@@ -0,0 +1,385 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000,2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KONQ_HISTORY_H
+#define KONQ_HISTORY_H
+
+#include <qdatastream.h>
+#include <qfile.h>
+#include <qptrlist.h>
+#include <qobject.h>
+#include <qmap.h>
+#include <qtimer.h>
+
+#include <dcopobject.h>
+
+#include <kcompletion.h>
+#include <kurl.h>
+#include <kparts/historyprovider.h>
+
+#include "konq_historycomm.h"
+
+#include <libkonq_export.h>
+
+class KCompletion;
+
+
+typedef QPtrList<KonqHistoryEntry> KonqBaseHistoryList;
+typedef QPtrListIterator<KonqHistoryEntry> KonqHistoryIterator;
+
+class LIBKONQ_EXPORT KonqHistoryList : public KonqBaseHistoryList
+{
+public:
+ /**
+ * Finds an entry by URL. The found item will also be current().
+ * If no matching entry is found, 0L is returned and current() will be
+ * the first item in the list.
+ */
+ KonqHistoryEntry * findEntry( const KURL& url );
+
+protected:
+ /**
+ * Ensures that the items are sorted by the lastVisited date
+ */
+ virtual int compareItems( QPtrCollection::Item, QPtrCollection::Item );
+};
+
+
+///////////////////////////////////////////////////////////////////
+
+
+/**
+ * This class maintains and manages a history of all URLs visited by one
+ * Konqueror instance. Additionally it synchronizes the history with other
+ * Konqueror instances via DCOP to keep one global and persistant history.
+ *
+ * It keeps the history in sync with one KCompletion object
+ */
+class LIBKONQ_EXPORT KonqHistoryManager : public KParts::HistoryProvider,
+ public KonqHistoryComm
+{
+ Q_OBJECT
+
+public:
+ static KonqHistoryManager *kself() {
+ return static_cast<KonqHistoryManager*>( KParts::HistoryProvider::self() );
+ }
+
+ KonqHistoryManager( QObject *parent, const char *name );
+ ~KonqHistoryManager();
+
+ /**
+ * Sets a new maximum size of history and truncates the current history
+ * if necessary. Notifies all other Konqueror instances via DCOP
+ * to do the same.
+ *
+ * The history is saved after receiving the DCOP call.
+ */
+ void emitSetMaxCount( Q_UINT32 count );
+
+ /**
+ * Sets a new maximum age of history entries and removes all entries that
+ * are older than @p days. Notifies all other Konqueror instances via DCOP
+ * to do the same.
+ *
+ * An age of 0 means no expiry based on the age.
+ *
+ * The history is saved after receiving the DCOP call.
+ */
+ void emitSetMaxAge( Q_UINT32 days );
+
+ /**
+ * Removes the history entry for @p url, if existant. Tells all other
+ * Konqueror instances via DCOP to do the same.
+ *
+ * The history is saved after receiving the DCOP call.
+ */
+ void emitRemoveFromHistory( const KURL& url );
+
+ /**
+ * Removes the history entries for the given list of @p urls. Tells all
+ * other Konqueror instances via DCOP to do the same.
+ *
+ * The history is saved after receiving the DCOP call.
+ */
+ void emitRemoveFromHistory( const KURL::List& urls );
+
+ /**
+ * @returns the current maximum number of history entries.
+ */
+ Q_UINT32 maxCount() const { return m_maxCount; }
+
+ /**
+ * @returns the current maximum age (in days) of history entries.
+ */
+ Q_UINT32 maxAge() const { return m_maxAgeDays; }
+
+ /**
+ * Adds a pending entry to the history. Pending means, that the entry is
+ * not verified yet, i.e. it is not sure @p url does exist at all. You
+ * probably don't know the title of the url in that case either.
+ * Call @ref confirmPending() as soon you know the entry is good and should
+ * be updated.
+ *
+ * If an entry with @p url already exists,
+ * it will be updated (lastVisited date will become the current time
+ * and the number of visits will be incremented).
+ *
+ * @param url The url of the history entry
+ * @param typedURL the string that the user typed, which resulted in url
+ * Doesn't have to be a valid url, e.g. "slashdot.org".
+ * @param title The title of the URL. If you don't know it (yet), you may
+ specify it in @ref confirmPending().
+ */
+ void addPending( const KURL& url, const QString& typedURL = QString::null,
+ const QString& title = QString::null );
+
+ /**
+ * Confirms and updates the entry for @p url.
+ */
+ void confirmPending( const KURL& url,
+ const QString& typedURL = QString::null,
+ const QString& title = QString::null );
+
+ /**
+ * Removes a pending url from the history, e.g. when the url does not
+ * exist, or the user aborted loading.
+ */
+ void removePending( const KURL& url );
+
+ /**
+ * @returns the KCompletion object.
+ */
+ KCompletion * completionObject() const { return m_pCompletion; }
+
+ /**
+ * @returns the list of all history entries, sorted by date
+ * (oldest entries first)
+ */
+ const KonqHistoryList& entries() const { return m_history; }
+
+ // HistoryProvider interfae, let konq handle this
+ /**
+ * Reimplemented in such a way that all URLs that would be filtered
+ * out normally (see @ref filterOut()) will still be added to the history.
+ * By default, file:/ urls will be filtered out, but if they come thru
+ * the HistoryProvider interface, they are added to the history.
+ */
+ virtual void insert( const QString& );
+ virtual void remove( const QString& ) {}
+ virtual void clear() {}
+
+
+public slots:
+ /**
+ * Loads the history and fills the completion object.
+ */
+ bool loadHistory();
+
+ /**
+ * Saves the entire history.
+ */
+ bool saveHistory();
+
+ /**
+ * Clears the history and tells all other Konqueror instances via DCOP
+ * to do the same.
+ * The history is saved afterwards, if necessary.
+ */
+ void emitClear();
+
+
+signals:
+ /**
+ * Emitted after the entire history was loaded from disk.
+ */
+ void loadingFinished();
+
+ /**
+ * Emitted after a new entry was added
+ */
+ void entryAdded( const KonqHistoryEntry *entry );
+
+ /**
+ * Emitted after an entry was removed from the history
+ * Note, that this entry will be deleted immediately after you got
+ * that signal.
+ */
+ void entryRemoved( const KonqHistoryEntry *entry );
+
+protected:
+ /**
+ * Resizes the history list to contain less or equal than m_maxCount
+ * entries. The first (oldest) entries are removed.
+ */
+ void adjustSize();
+
+ /**
+ * @returns true if @p entry is older than the given maximum age,
+ * otherwise false.
+ */
+ inline bool isExpired( KonqHistoryEntry *entry ) {
+ return (entry && m_maxAgeDays > 0 && entry->lastVisited <
+ QDate::currentDate().addDays( -m_maxAgeDays ));
+ }
+
+ /**
+ * Notifes all running instances about a new HistoryEntry via DCOP
+ */
+ void emitAddToHistory( const KonqHistoryEntry& entry );
+
+ /**
+ * Every konqueror instance broadcasts new history entries to the other
+ * konqueror instances. Those add the entry to their list, but don't
+ * save the list, because the sender saves the list.
+ *
+ * @param e the new history entry
+ * @param saveId is the DCOPObject::objId() of the sender so that
+ * only the sender saves the new history.
+ */
+ virtual void notifyHistoryEntry( KonqHistoryEntry e, QCString saveId );
+
+ /**
+ * Called when the configuration of the maximum count changed.
+ * Called via DCOP by some config-module
+ */
+ virtual void notifyMaxCount( Q_UINT32 count, QCString saveId );
+
+ /**
+ * Called when the configuration of the maximum age of history-entries
+ * changed. Called via DCOP by some config-module
+ */
+ virtual void notifyMaxAge( Q_UINT32 days, QCString saveId );
+
+ /**
+ * Clears the history completely. Called via DCOP by some config-module
+ */
+ virtual void notifyClear( QCString saveId );
+
+ /**
+ * Notifes about a url that has to be removed from the history.
+ * The instance where saveId == objId() has to save the history.
+ */
+ virtual void notifyRemove( KURL url, QCString saveId );
+
+ /**
+ * Notifes about a list of urls that has to be removed from the history.
+ * The instance where saveId == objId() has to save the history.
+ */
+ virtual void notifyRemove( KURL::List urls, QCString saveId );
+
+ /**
+ * @returns a list of all urls in the history.
+ */
+ virtual QStringList allURLs() const;
+
+ /**
+ * Does the work for @ref addPending() and @ref confirmPending().
+ *
+ * Adds an entry to the history. If an entry with @p url already exists,
+ * it will be updated (lastVisited date will become the current time
+ * and the number of visits will be incremented).
+ * @p pending means, the entry has not been "verified", it's been added
+ * right after typing the url.
+ * If @p pending is false, @p url will be removed from the pending urls
+ * (if available) and NOT be added again in that case.
+ */
+ void addToHistory( bool pending, const KURL& url,
+ const QString& typedURL = QString::null,
+ const QString& title = QString::null );
+
+
+ /**
+ * @returns true if the given @p url should be filtered out and not be
+ * added to the history. By default, all local urls (url.isLocalFile())
+ * will return true, as well as urls with an empty host.
+ */
+ virtual bool filterOut( const KURL& url );
+
+ void addToUpdateList( const QString& url ) {
+ m_updateURLs.append( url );
+ m_updateTimer->start( 500, true );
+ }
+
+ /**
+ * The list of urls that is going to be emitted in slotEmitUpdated. Add
+ * urls to it whenever you modify the list of history entries and start
+ * m_updateTimer.
+ */
+ QStringList m_updateURLs;
+
+private slots:
+ /**
+ * Called by the updateTimer to emit the KParts::HistoryProvider::updated()
+ * signal so that khtml can repaint the updated links.
+ */
+ void slotEmitUpdated();
+
+private:
+ /**
+ * Returns whether the DCOP call we are handling was a call from us self
+ */
+ bool isSenderOfBroadcast();
+
+ void clearPending();
+ /**
+ * a little optimization for KonqHistoryList::findEntry(),
+ * checking the dict of KParts::HistoryProvider before traversing the list.
+ * Can't be used everywhere, because it always returns 0L for "pending"
+ * entries, as those are not added to the dict, currently.
+ */
+ KonqHistoryEntry * findEntry( const KURL& url );
+
+ /**
+ * Stuff to create a proper history out of KDE 2.0's konq_history for
+ * completion.
+ */
+ bool loadFallback();
+ KonqHistoryEntry * createFallbackEntry( const QString& ) const;
+
+ void addToCompletion( const QString& url, const QString& typedURL, int numberOfTimesVisited = 1 );
+ void removeFromCompletion( const QString& url, const QString& typedURL );
+
+ QString m_filename;
+ KonqHistoryList m_history;
+
+ /**
+ * List of pending entries, which were added to the history, but not yet
+ * confirmed (i.e. not yet added with pending = false).
+ * Note: when removing an entry, you have to delete the KonqHistoryEntry
+ * of the item you remove.
+ */
+ QMap<QString,KonqHistoryEntry*> m_pending;
+
+ Q_UINT32 m_maxCount; // maximum of history entries
+ Q_UINT32 m_maxAgeDays; // maximum age of a history entry
+
+ KCompletion *m_pCompletion; // the completion object we sync with
+
+ /**
+ * A timer that will emit the KParts::HistoryProvider::updated() signal
+ * thru the slotEmitUpdated slot.
+ */
+ QTimer *m_updateTimer;
+
+ static const Q_UINT32 s_historyVersion;
+};
+
+
+#endif // KONQ_HISTORY_H
diff --git a/libkonq/konq_iconviewwidget.cc b/libkonq/konq_iconviewwidget.cc
new file mode 100644
index 000000000..99d92ebde
--- /dev/null
+++ b/libkonq/konq_iconviewwidget.cc
@@ -0,0 +1,1927 @@
+/* This file is part of the KDE projects
+ Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ Copyright (C) 2000 - 2005 David Faure <faure@kde.org>
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#include "konq_iconviewwidget.h"
+#include "konq_operations.h"
+#include "konq_undo.h"
+#include "konq_sound.h"
+#include "konq_filetip.h"
+
+#include <qclipboard.h>
+#include <qlayout.h>
+#include <qtimer.h>
+#include <qpainter.h>
+#include <qtooltip.h>
+#include <qlabel.h>
+#include <qmovie.h>
+#include <qregexp.h>
+#include <qcursor.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kio/previewjob.h>
+#include <kfileivi.h>
+#include <konq_settings.h>
+#include <konq_drag.h>
+#include <kglobalsettings.h>
+#include <kpropertiesdialog.h>
+#include <kipc.h>
+#include <kicontheme.h>
+#include <kiconeffect.h>
+#include <kurldrag.h>
+#include <kstandarddirs.h>
+#include <kprotocolinfo.h>
+#include <ktrader.h>
+
+#include <assert.h>
+#include <unistd.h>
+#include <klocale.h>
+
+
+struct KonqIconViewWidgetPrivate
+{
+ KonqIconViewWidgetPrivate() {
+ pActiveItem = 0;
+ bSoundPreviews = false;
+ pSoundItem = 0;
+ bSoundItemClicked = false;
+ pSoundPlayer = 0;
+ pSoundTimer = 0;
+ pPreviewJob = 0;
+ bAllowSetWallpaper = false;
+
+ doAnimations = true;
+ m_movie = 0L;
+ m_movieBlocked = 0;
+ pFileTip = 0;
+ pActivateDoubleClick = 0L;
+ bCaseInsensitive = true;
+ pPreviewMimeTypes = 0L;
+ bProgramsURLdrag = false;
+ }
+ ~KonqIconViewWidgetPrivate() {
+ delete pSoundPlayer;
+ delete pSoundTimer;
+ delete m_movie;
+ delete pFileTip;
+ delete pActivateDoubleClick;
+ delete pPreviewMimeTypes;
+ //delete pPreviewJob; done by stopImagePreview
+ }
+ KFileIVI *pActiveItem;
+ // Sound preview
+ KFileIVI *pSoundItem;
+ KonqSoundPlayer *pSoundPlayer;
+ QTimer *pSoundTimer;
+ bool bSoundPreviews;
+ bool bSoundItemClicked;
+ bool bAllowSetWallpaper;
+ bool bCaseInsensitive;
+ bool bBoostPreview;
+
+ // Animated icons support
+ bool doAnimations;
+ QMovie* m_movie;
+ int m_movieBlocked;
+ QString movieFileName;
+
+ KIO::PreviewJob *pPreviewJob;
+ KonqFileTip* pFileTip;
+ QStringList previewSettings;
+ bool renameItem;
+ bool firstClick;
+ bool releaseMouseEvent;
+ QPoint mousePos;
+ int mouseState;
+ QTimer *pActivateDoubleClick;
+ QStringList* pPreviewMimeTypes;
+ bool bProgramsURLdrag;
+};
+
+KonqIconViewWidget::KonqIconViewWidget( QWidget * parent, const char * name, WFlags f, bool kdesktop )
+ : KIconView( parent, name, f ),
+ m_rootItem( 0L ), m_size( 0 ) /* default is DesktopIcon size */,
+ m_bDesktop( kdesktop ),
+ m_bSetGridX( !kdesktop ) /* No line breaking on the desktop */
+{
+ d = new KonqIconViewWidgetPrivate;
+ connect( this, SIGNAL( dropped( QDropEvent *, const QValueList<QIconDragItem> & ) ),
+ this, SLOT( slotDropped( QDropEvent*, const QValueList<QIconDragItem> & ) ) );
+
+ connect( this, SIGNAL( selectionChanged() ),
+ this, SLOT( slotSelectionChanged() ) );
+
+ kapp->addKipcEventMask( KIPC::IconChanged );
+ connect( kapp, SIGNAL(iconChanged(int)), SLOT(slotIconChanged(int)) );
+ connect( this, SIGNAL(onItem(QIconViewItem *)), SLOT(slotOnItem(QIconViewItem *)) );
+ connect( this, SIGNAL(onViewport()), SLOT(slotOnViewport()) );
+ connect( this, SIGNAL(itemRenamed(QIconViewItem *, const QString &)), SLOT(slotItemRenamed(QIconViewItem *, const QString &)) );
+
+ m_pSettings = KonqFMSettings::settings(); // already needed in setItemTextPos(), calculateGridX()
+ d->bBoostPreview = boostPreview();
+
+ // hardcoded settings
+ setSelectionMode( QIconView::Extended );
+ setItemTextPos( QIconView::Bottom );
+ d->releaseMouseEvent = false;
+ d->pFileTip = new KonqFileTip(this);
+ d->firstClick = false;
+ calculateGridX();
+ setAutoArrange( true );
+ setSorting( true, sortDirection() );
+ readAnimatedIconsConfig();
+ m_bSortDirsFirst = true;
+ m_bMousePressed = false;
+ m_LineupMode = LineupBoth;
+ // emit our signals
+ slotSelectionChanged();
+ m_iconPositionGroupPrefix = QString::fromLatin1( "IconPosition::" );
+ KonqUndoManager::incRef();
+}
+
+KonqIconViewWidget::~KonqIconViewWidget()
+{
+ stopImagePreview();
+ KonqUndoManager::decRef();
+ delete d;
+}
+
+bool KonqIconViewWidget::maySetWallpaper()
+{
+ return d->bAllowSetWallpaper;
+}
+
+void KonqIconViewWidget::setMaySetWallpaper(bool b)
+{
+ d->bAllowSetWallpaper = b;
+}
+
+void KonqIconViewWidget::focusOutEvent( QFocusEvent * ev )
+{
+ // We can't possibly have the mouse pressed and still lose focus.
+ // Well, we can, but when we regain focus we should assume the mouse is
+ // not down anymore or the slotOnItem code will break with highlighting!
+ m_bMousePressed = false;
+
+ // This will ensure that tooltips don't pop up and the mouseover icon
+ // effect will go away if the mouse goes out of the view without
+ // first moving into an empty portion of the view
+ // Fixes part of #86968, and #85204
+ // Matt Newell 2004-09-24
+ slotOnViewport();
+
+ KIconView::focusOutEvent( ev );
+}
+
+void KonqIconViewWidget::slotItemRenamed(QIconViewItem *item, const QString &name)
+{
+ kdDebug(1203) << "KonqIconViewWidget::slotItemRenamed" << endl;
+ KFileIVI *viewItem = static_cast<KFileIVI *>(item);
+ KFileItem *fileItem = viewItem->item();
+
+ // The correct behavior is to show the old name until the rename has successfully
+ // completed. Unfortunately, KIconView forces us to allow the text to be changed
+ // before we try the rename, so set it back to the pre-rename state.
+ viewItem->setText( fileItem->text() );
+ kdDebug(1203)<<" fileItem->text() ;"<<fileItem->text()<<endl;
+ // Don't do anything if the user renamed to a blank name.
+ if( !name.isEmpty() )
+ {
+ // Actually attempt the rename. If it succeeds, KDirLister will update the name.
+ KURL oldurl( fileItem->url() );
+ KURL newurl( oldurl );
+ newurl.setPath( newurl.directory(false) + KIO::encodeFileName( name ) );
+ kdDebug(1203)<<" newurl :"<<newurl<<endl;
+ // We use url()+name so that it also works if the name is a relative path (#51176)
+ KonqOperations::rename( this, oldurl, newurl );
+ }
+}
+
+void KonqIconViewWidget::slotIconChanged( int group )
+{
+ if (group != KIcon::Desktop)
+ return;
+
+ int size = m_size;
+ if ( m_size == 0 )
+ m_size = -1; // little trick to force grid change in setIcons
+ setIcons( size ); // force re-determining all icons
+ readAnimatedIconsConfig();
+}
+
+void KonqIconViewWidget::readAnimatedIconsConfig()
+{
+ KConfigGroup cfgGroup( KGlobal::config(), "DesktopIcons" );
+ d->doAnimations = cfgGroup.readBoolEntry( "Animated", true /*default*/ );
+}
+
+void KonqIconViewWidget::slotOnItem( QIconViewItem *_item )
+{
+ KFileIVI* item = static_cast<KFileIVI *>( _item );
+ // Reset icon of previous item
+ if( d->pActiveItem != 0L && d->pActiveItem != item )
+ {
+ if ( d->m_movie && d->pActiveItem->isAnimated() )
+ {
+ d->m_movie->pause(); // we'll see below what we do with it
+ d->pActiveItem->setAnimated( false );
+ d->pActiveItem->refreshIcon( true );
+ }
+ else {
+ d->pActiveItem->setActive( false );
+ }
+ d->pActiveItem = 0L;
+ d->pFileTip->setItem( 0L );
+ }
+
+ // Stop sound
+ if (d->pSoundPlayer != 0 && item != d->pSoundItem)
+ {
+ d->pSoundPlayer->stop();
+
+ d->pSoundItem = 0;
+ if (d->pSoundTimer && d->pSoundTimer->isActive())
+ d->pSoundTimer->stop();
+ }
+
+ if ( !m_bMousePressed )
+ {
+ if( item != d->pActiveItem )
+ {
+ d->pActiveItem = item;
+ d->pFileTip->setItem( d->pActiveItem->item(),
+ item->rect(),
+ item->pixmap() );
+
+ if ( d->doAnimations && d->pActiveItem && d->pActiveItem->hasAnimation() )
+ {
+ //kdDebug(1203) << "Playing animation for: " << d->pActiveItem->mouseOverAnimation() << endl;
+ // Check if cached movie can be used
+#if 0 // Qt-mng bug, reusing the movie doesn't work currently.
+ if ( d->m_movie && d->movieFileName == d->pActiveItem->mouseOverAnimation() )
+ {
+ d->pActiveItem->setAnimated( true );
+ if (d->m_movieBlocked) {
+ kdDebug(1203) << "onitem, but blocked" << endl;
+ d->m_movie->pause();
+ }
+ else {
+ kdDebug(1203) << "we go ahead.." << endl;
+ d->m_movieBlocked++;
+ QTimer::singleShot(300, this, SLOT(slotReenableAnimation()));
+ d->m_movie->restart();
+ d->m_movie->unpause();
+ }
+ }
+ else
+#endif
+ {
+ QMovie movie = KGlobal::iconLoader()->loadMovie( d->pActiveItem->mouseOverAnimation(), KIcon::Desktop, d->pActiveItem->iconSize() );
+ if ( !movie.isNull() )
+ {
+ delete d->m_movie;
+ d->m_movie = new QMovie( movie ); // shallow copy, don't worry
+ // Fix alpha-channel - currently only if no background pixmap,
+ // the bg pixmap case requires to uncomment the code at qmovie.cpp:404
+ const QPixmap* pm = backgroundPixmap();
+ bool hasPixmap = pm && !pm->isNull();
+ if ( !hasPixmap ) {
+ pm = viewport()->backgroundPixmap();
+ hasPixmap = pm && !pm->isNull();
+ }
+ if (!hasPixmap && backgroundMode() != NoBackground)
+ d->m_movie->setBackgroundColor( viewport()->backgroundColor() );
+ d->m_movie->connectUpdate( this, SLOT( slotMovieUpdate(const QRect &) ) );
+ d->m_movie->connectStatus( this, SLOT( slotMovieStatus(int) ) );
+ d->movieFileName = d->pActiveItem->mouseOverAnimation();
+ d->pActiveItem->setAnimated( true );
+ }
+ else
+ {
+ d->pActiveItem->setAnimated( false );
+ if (d->m_movie)
+ d->m_movie->pause();
+ // No movie available, remember it
+ d->pActiveItem->setMouseOverAnimation( QString::null );
+ }
+ }
+ } // animations
+ // Only do the normal "mouseover" effect if no animation is in use
+ if (d->pActiveItem && !d->pActiveItem->isAnimated())
+ {
+ d->pActiveItem->setActive( true );
+ }
+ }
+ else // No change in current item
+ {
+ // No effect. If we want to underline on hover, we should
+ // force the IVI to repaint here, though!
+ d->pActiveItem = 0L;
+ d->pFileTip->setItem( 0L );
+ }
+ } // bMousePressed
+ else
+ {
+ // All features disabled during mouse clicking, e.g. rectangular
+ // selection
+ d->pActiveItem = 0L;
+ d->pFileTip->setItem( 0L );
+ }
+
+ // ## shouldn't this be disabled during rectangular selection too ?
+ if (d->bSoundPreviews && d->pSoundPlayer &&
+ d->pSoundPlayer->mimeTypes().contains(
+ item->item()->mimetype())
+ && KGlobalSettings::showFilePreview(item->item()->url())
+ && topLevelWidget() == kapp->activeWindow())
+ {
+ d->pSoundItem = item;
+ d->bSoundItemClicked = false;
+ if (!d->pSoundTimer)
+ {
+ d->pSoundTimer = new QTimer(this);
+ connect(d->pSoundTimer, SIGNAL(timeout()), SLOT(slotStartSoundPreview()));
+ }
+ if (d->pSoundTimer->isActive())
+ d->pSoundTimer->stop();
+ d->pSoundTimer->start(500, true);
+ }
+ else
+ {
+ if (d->pSoundPlayer)
+ d->pSoundPlayer->stop();
+ d->pSoundItem = 0;
+ if (d->pSoundTimer && d->pSoundTimer->isActive())
+ d->pSoundTimer->stop();
+ }
+}
+
+void KonqIconViewWidget::slotOnViewport()
+{
+ d->pFileTip->setItem( 0L );
+
+ if (d->pSoundPlayer)
+ d->pSoundPlayer->stop();
+ d->pSoundItem = 0;
+ if (d->pSoundTimer && d->pSoundTimer->isActive())
+ d->pSoundTimer->stop();
+
+ if (d->pActiveItem == 0L)
+ return;
+
+ if ( d->doAnimations && d->m_movie && d->pActiveItem->isAnimated() )
+ {
+ d->pActiveItem->setAnimated( false );
+#if 0
+ // Aborting before the end of the animation ?
+ if (d->m_movie->running()) {
+ d->m_movie->pause();
+ d->m_movieBlocked++;
+ kdDebug(1203) << "on viewport, blocking" << endl;
+ QTimer::singleShot(300, this, SLOT(slotReenableAnimation()));
+ }
+#endif
+ d->pActiveItem->refreshIcon( true );
+ Q_ASSERT( d->pActiveItem->state() == KIcon::DefaultState );
+ //delete d->m_movie;
+ //d->m_movie = 0L;
+ // TODO a timer to delete the movie after some time if unused?
+ }
+ else
+ {
+ d->pActiveItem->setActive( false );
+ }
+ d->pActiveItem = 0L;
+}
+
+void KonqIconViewWidget::slotStartSoundPreview()
+{
+ if (!d->pSoundItem || d->bSoundItemClicked)
+ return;
+
+ d->pSoundPlayer->play(d->pSoundItem->item()->url().url());
+}
+
+
+void KonqIconViewWidget::slotPreview(const KFileItem *item, const QPixmap &pix)
+{
+ // ### slow. Idea: move KonqKfmIconView's m_itemDict into this class
+ for (QIconViewItem *it = firstItem(); it; it = it->nextItem())
+ {
+ KFileIVI* current = static_cast<KFileIVI *>(it);
+ if (current->item() == item)
+ {
+ if (item->overlays() & KIcon::HiddenOverlay) {
+ QPixmap p(pix);
+
+ KIconEffect::semiTransparent(p);
+ current->setThumbnailPixmap(p);
+ } else {
+ current->setThumbnailPixmap(pix);
+ }
+ break;
+ }
+ }
+}
+
+void KonqIconViewWidget::slotPreviewResult()
+{
+ d->pPreviewJob = 0;
+ emit imagePreviewFinished();
+}
+
+void KonqIconViewWidget::slotToolTipPreview(const KFileItem* , const QPixmap &)
+{
+// unused - remove for KDE4
+}
+
+void KonqIconViewWidget::slotToolTipPreviewResult()
+{
+// unused - remove for KDE4
+}
+
+void KonqIconViewWidget::slotMovieUpdate( const QRect& rect )
+{
+ //kdDebug(1203) << "KonqIconViewWidget::slotMovieUpdate " << rect.x() << "," << rect.y() << " " << rect.width() << "x" << rect.height() << endl;
+ Q_ASSERT( d );
+ Q_ASSERT( d->m_movie );
+ // seems stopAnimation triggers one last update
+ if ( d->pActiveItem && d->m_movie && d->pActiveItem->isAnimated() ) {
+ const QPixmap &frame = d->m_movie->framePixmap();
+ // This can happen if the icon was scaled to the desired size, so KIconLoader
+ // will happily return a movie with different dimensions than the icon
+ int iconSize=d->pActiveItem->iconSize();
+ if (iconSize==0) iconSize = KGlobal::iconLoader()->currentSize( KIcon::Desktop );
+ if ( frame.width() != iconSize || frame.height() != iconSize ) {
+ d->pActiveItem->setAnimated( false );
+ d->m_movie->pause();
+ // No movie available, remember it
+ d->pActiveItem->setMouseOverAnimation( QString::null );
+ d->pActiveItem->setActive( true );
+ return;
+ }
+ d->pActiveItem->setPixmapDirect( frame, false, false /*no redraw*/ );
+ QRect pixRect = d->pActiveItem->pixmapRect(false);
+ repaintContents( pixRect.x() + rect.x(), pixRect.y() + rect.y(), rect.width(), rect.height(), false );
+ }
+}
+
+void KonqIconViewWidget::slotMovieStatus( int status )
+{
+ if ( status < 0 ) {
+ // Error playing the MNG -> forget about it and do normal iconeffect
+ if ( d->pActiveItem && d->pActiveItem->isAnimated() ) {
+ d->pActiveItem->setAnimated( false );
+ d->pActiveItem->setMouseOverAnimation( QString::null );
+ d->pActiveItem->setActive( true );
+ }
+ }
+}
+
+void KonqIconViewWidget::slotReenableAnimation()
+{
+ if (!--d->m_movieBlocked) {
+ if ( d->pActiveItem && d->m_movie && d->m_movie->paused()) {
+ kdDebug(1203) << "reenabled animation" << endl;
+ d->m_movie->restart();
+ d->m_movie->unpause();
+ }
+ }
+}
+
+void KonqIconViewWidget::clear()
+{
+ d->pFileTip->setItem( 0L );
+ stopImagePreview(); // Just in case
+ KIconView::clear();
+ d->pActiveItem = 0L;
+}
+
+void KonqIconViewWidget::takeItem( QIconViewItem *item )
+{
+ if ( d->pActiveItem == static_cast<KFileIVI *>(item) )
+ {
+ d->pFileTip->setItem( 0L );
+ d->pActiveItem = 0L;
+ }
+
+ if ( d->pPreviewJob )
+ d->pPreviewJob->removeItem( static_cast<KFileIVI *>(item)->item() );
+
+ KIconView::takeItem( item );
+}
+
+// Currently unused - remove in KDE 4.0
+void KonqIconViewWidget::setThumbnailPixmap( KFileIVI * item, const QPixmap & pixmap )
+{
+ if ( item )
+ {
+ if ( d->pActiveItem == item )
+ {
+ d->pFileTip->setItem( 0L );
+ d->pActiveItem = 0L;
+ }
+ item->setThumbnailPixmap( pixmap );
+ if ( m_bSetGridX && item->width() > gridX() )
+ {
+ setGridX( item->width() );
+ if (autoArrange())
+ arrangeItemsInGrid();
+ }
+ }
+}
+
+bool KonqIconViewWidget::initConfig( bool bInit )
+{
+ bool fontChanged = false;
+
+ // Color settings
+ QColor normalTextColor = m_pSettings->normalTextColor();
+ setItemColor( normalTextColor );
+
+ if (m_bDesktop)
+ {
+ QColor itemTextBg = m_pSettings->itemTextBackground();
+ if ( itemTextBg.isValid() )
+ setItemTextBackground( itemTextBg );
+ else
+ setItemTextBackground( NoBrush );
+ }
+
+ bool on = m_pSettings->showFileTips() && QToolTip::isGloballyEnabled();
+ d->pFileTip->setOptions(on,
+ m_pSettings->showPreviewsInFileTips(),
+ m_pSettings->numFileTips());
+
+ // if the user wants our own tooltip, don't show the one from Qts ListView
+ setShowToolTips(!on);
+
+ // Font settings
+ QFont font( m_pSettings->standardFont() );
+ if (!m_bDesktop)
+ font.setUnderline( m_pSettings->underlineLink() );
+
+ if ( font != KonqIconViewWidget::font() )
+ {
+ setFont( font );
+ if (!bInit)
+ {
+ // QIconView doesn't do it by default... but if the font is made much
+ // bigger, we really need to give more space between the icons
+ fontChanged = true;
+ }
+ }
+
+ setIconTextHeight( m_pSettings->iconTextHeight() );
+
+ if ( (itemTextPos() == QIconView::Right) && (maxItemWidth() != gridXValue()) )
+ {
+ int size = m_size;
+ m_size = -1; // little trick to force grid change in setIcons
+ setIcons( size ); // force re-determining all icons
+ }
+ else if ( d->bBoostPreview != boostPreview() ) // Update icons if settings for preview icon size have changed
+ setIcons(m_size);
+ else if (!bInit)
+ updateContents();
+ return fontChanged;
+}
+
+bool KonqIconViewWidget::boostPreview() const
+{
+ if ( m_bDesktop ) return false;
+
+ KConfigGroup group( KGlobal::config(), "PreviewSettings" );
+ return group.readBoolEntry( "BoostSize", false );
+}
+
+void KonqIconViewWidget::disableSoundPreviews()
+{
+ d->bSoundPreviews = false;
+
+ if (d->pSoundPlayer)
+ d->pSoundPlayer->stop();
+ d->pSoundItem = 0;
+ if (d->pSoundTimer && d->pSoundTimer->isActive())
+ d->pSoundTimer->stop();
+}
+
+void KonqIconViewWidget::setIcons( int size, const QStringList& stopImagePreviewFor )
+{
+ // size has changed?
+ bool sizeChanged = (m_size != size);
+ int oldGridX = gridX();
+ m_size = size;
+
+ // boost preview option has changed?
+ bool boost = boostPreview();
+ bool previewSizeChanged = ( d->bBoostPreview != boost );
+ d->bBoostPreview = boost;
+
+ if ( sizeChanged || previewSizeChanged )
+ {
+ int realSize = size ? size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
+ // choose spacing depending on font, but min 5 (due to KFileIVI move limit)
+ setSpacing( ( m_bDesktop || ( realSize > KIcon::SizeSmall ) ) ?
+ QMAX( 5, QFontMetrics(font()).width('n') ) : 0 );
+ }
+
+ if ( sizeChanged || previewSizeChanged || !stopImagePreviewFor.isEmpty() )
+ {
+ calculateGridX();
+ }
+ bool stopAll = !stopImagePreviewFor.isEmpty() && stopImagePreviewFor.first() == "*";
+
+ // Disable repaints that can be triggered by ivi->setIcon(). Since icons are
+ // resized in-place, if the icon size is increasing it can happens that the right
+ // or bottom icons exceed the size of the viewport.. here we prevent the repaint
+ // event that will be triggered in that case.
+ bool prevUpdatesState = viewport()->isUpdatesEnabled();
+ viewport()->setUpdatesEnabled( false );
+
+ // Do this even if size didn't change, since this is used by refreshMimeTypes...
+ for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() ) {
+ KFileIVI * ivi = static_cast<KFileIVI *>( it );
+ // Set a normal icon for files that are not thumbnails, and for files
+ // that are thumbnails but for which it should be stopped
+ if ( !ivi->isThumbnail() ||
+ sizeChanged ||
+ previewSizeChanged ||
+ stopAll ||
+ mimeTypeMatch( ivi->item()->mimetype(), stopImagePreviewFor ) )
+ {
+ ivi->setIcon( size, ivi->state(), true, false );
+ }
+ else
+ ivi->invalidateThumb( ivi->state(), true );
+ }
+
+ // Restore viewport update to previous state
+ viewport()->setUpdatesEnabled( prevUpdatesState );
+
+ if ( ( sizeChanged || previewSizeChanged || oldGridX != gridX() ||
+ !stopImagePreviewFor.isEmpty() ) && autoArrange() )
+ arrangeItemsInGrid( true ); // take new grid into account and repaint
+ else
+ viewport()->update(); //Repaint later..
+}
+
+bool KonqIconViewWidget::mimeTypeMatch( const QString& mimeType, const QStringList& mimeList ) const
+{
+ // Code duplication from KIO::PreviewJob
+ KMimeType::Ptr mime = KMimeType::mimeType( mimeType );
+ for (QStringList::ConstIterator mt = mimeList.begin(); mt != mimeList.end(); ++mt)
+ {
+ if ( mime->is( *mt ) )
+ return true;
+ // Support for *mt == "image/*"
+ QString tmp( mimeType );
+ if ( (*mt).endsWith("*") && tmp.replace(QRegExp("/.*"), "/*") == (*mt) )
+ return true;
+ if ( (*mt) == "text/plain" )
+ {
+ QVariant textProperty = mime->property( "X-KDE-text" );
+ if ( textProperty.type() == QVariant::Bool && textProperty.toBool() )
+ return true;
+ }
+ }
+ return false;
+}
+
+void KonqIconViewWidget::setItemTextPos( ItemTextPos pos )
+{
+ // can't call gridXValue() because this already would need the new itemTextPos()
+ int sz = m_size ? m_size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
+
+ if ( m_bSetGridX )
+ if ( pos == QIconView::Bottom )
+ setGridX( QMAX( sz + 50, previewIconSize( sz ) + 13 ) );
+ else
+ {
+ setMaxItemWidth( QMAX( sz, previewIconSize( sz ) ) + m_pSettings->iconTextWidth() );
+ setGridX( -1 );
+ }
+
+ KIconView::setItemTextPos( pos );
+}
+
+void KonqIconViewWidget::gridValues( int* x, int* y, int* dx, int* dy,
+ int* nx, int* ny )
+{
+ int previewSize = previewIconSize( m_size );
+ int iconSize = m_size ? m_size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
+
+ // Grid size
+ // as KFileIVI limits to move an icon to x >= 5, y >= 5, we define a grid cell as:
+ // spacing() must be >= 5 (currently set to 5 in setIcons())
+ // horizontal: left spacing() + <width>
+ // vertical : top spacing(), <height>, bottom spacing()
+ // The doubled space in y-direction gives a better visual separation and makes it clearer
+ // to which item the text belongs
+ *dx = spacing() + QMAX( QMAX( iconSize, previewSize ), m_pSettings->iconTextWidth() );
+ int textHeight = iconTextHeight() * fontMetrics().height();
+ *dy = spacing() + QMAX( iconSize, previewSize ) + 2 + textHeight + spacing();
+
+ // Icon Area
+ int w, h;
+ if ( m_IconRect.isValid() ) { // w and h must be != 0, otherwise we would get a div by zero
+ *x = m_IconRect.left(); w = m_IconRect.width();
+ *y = m_IconRect.top(); h = m_IconRect.height();
+ }
+ else {
+ *x = 0; w = viewport()->width();
+ *y = 0; h = viewport()->height();
+ }
+
+ // bug:110775 avoid div by zero (happens e.g. when iconTextHeight or iconTextWidth are very large)
+ if ( *dx > w )
+ *dx = w;
+
+ if ( *dy > h )
+ *dy = h;
+
+ *nx = w / *dx;
+ *ny = h / *dy;
+ // TODO: Check that items->count() <= nx * ny
+
+ // Let have exactly nx columns and ny rows
+ if(*nx && *ny) {
+ *dx = w / *nx;
+ *dy = h / *ny;
+ }
+ kdDebug(1203) << "x=" << *x << " y=" << *y << " spacing=" << spacing() << " iconSize=" << iconSize
+ << " w=" << w << " h=" << h
+ << " nx=" << *nx << " ny=" << *ny
+ << " dx=" << *dx << " dy=" << *dy << endl;
+}
+
+void KonqIconViewWidget::calculateGridX()
+{
+ if ( m_bSetGridX )
+ if ( itemTextPos() == QIconView::Bottom )
+ setGridX( gridXValue() );
+ else
+ {
+ setMaxItemWidth( gridXValue() );
+ setGridX( -1 );
+ }
+}
+
+int KonqIconViewWidget::gridXValue() const
+{
+ // this method is only used in konqi as filemanager (not desktop)
+ int sz = m_size ? m_size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
+ int newGridX;
+
+ if ( itemTextPos() == QIconView::Bottom )
+ newGridX = QMAX( sz + 50, previewIconSize( sz ) + 13 );
+ else
+ newGridX = QMAX( sz, previewIconSize( sz ) ) + m_pSettings->iconTextWidth();
+
+ //kdDebug(1203) << "gridXValue: " << newGridX << " sz=" << sz << endl;
+ return newGridX;
+}
+
+void KonqIconViewWidget::refreshMimeTypes()
+{
+ updatePreviewMimeTypes();
+ for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() )
+ (static_cast<KFileIVI *>( it ))->item()->refreshMimeType();
+ setIcons( m_size );
+}
+
+void KonqIconViewWidget::setURL( const KURL &kurl )
+{
+ stopImagePreview();
+ m_url = kurl;
+
+ d->pFileTip->setPreview( KGlobalSettings::showFilePreview(m_url) );
+
+ if ( m_url.isLocalFile() )
+ m_dotDirectoryPath = m_url.path(1).append( ".directory" );
+ else
+ m_dotDirectoryPath = QString::null;
+}
+
+void KonqIconViewWidget::startImagePreview( const QStringList &, bool force )
+{
+ stopImagePreview(); // just in case
+
+ // Check config
+ if ( !KGlobalSettings::showFilePreview( url() ) ) {
+ kdDebug(1203) << "Previews disabled for protocol " << url().protocol() << endl;
+ emit imagePreviewFinished();
+ return;
+ }
+
+ if ((d->bSoundPreviews = d->previewSettings.contains( "audio/" )) &&
+ !d->pSoundPlayer)
+ {
+ KLibFactory *factory = KLibLoader::self()->factory("konq_sound");
+ if (factory)
+ d->pSoundPlayer = static_cast<KonqSoundPlayer *>(
+ factory->create(this, 0, "KonqSoundPlayer"));
+ d->bSoundPreviews = (d->pSoundPlayer != 0L);
+ }
+
+ KFileItemList items;
+ for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() )
+ if ( force || !static_cast<KFileIVI *>( it )->hasValidThumbnail() )
+ items.append( static_cast<KFileIVI *>( it )->item() );
+
+ bool onlyAudio = true;
+ for ( QStringList::ConstIterator it = d->previewSettings.begin(); it != d->previewSettings.end(); ++it ) {
+ if ( (*it).startsWith( "audio/" ) )
+ d->bSoundPreviews = true;
+ else
+ onlyAudio = false;
+ }
+
+ if ( items.isEmpty() || onlyAudio ) {
+ emit imagePreviewFinished();
+ return; // don't start the preview job if not really necessary
+ }
+
+ int iconSize = m_size ? m_size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
+ int size;
+
+ d->bBoostPreview = boostPreview();
+ size = previewIconSize( iconSize );
+
+ if ( !d->bBoostPreview )
+ iconSize /= 2;
+
+ d->pPreviewJob = KIO::filePreview( items, size, size, iconSize,
+ m_pSettings->textPreviewIconTransparency(), true /* scale */,
+ true /* save */, &(d->previewSettings) );
+ connect( d->pPreviewJob, SIGNAL( gotPreview( const KFileItem *, const QPixmap & ) ),
+ this, SLOT( slotPreview( const KFileItem *, const QPixmap & ) ) );
+ connect( d->pPreviewJob, SIGNAL( result( KIO::Job * ) ),
+ this, SLOT( slotPreviewResult() ) );
+}
+
+void KonqIconViewWidget::stopImagePreview()
+{
+ if (d->pPreviewJob)
+ {
+ d->pPreviewJob->kill();
+ d->pPreviewJob = 0;
+ // Now that previews are updated in-place, calling
+ // arrangeItemsInGrid() here is not needed anymore
+ }
+}
+
+bool KonqIconViewWidget::isPreviewRunning() const
+{
+ return d->pPreviewJob;
+}
+
+KFileItemList KonqIconViewWidget::selectedFileItems()
+{
+ KFileItemList lstItems;
+
+ QIconViewItem *it = firstItem();
+ for (; it; it = it->nextItem() )
+ if ( it->isSelected() ) {
+ KFileItem *fItem = (static_cast<KFileIVI *>(it))->item();
+ lstItems.append( fItem );
+ }
+ return lstItems;
+}
+
+void KonqIconViewWidget::slotDropped( QDropEvent *ev, const QValueList<QIconDragItem> & )
+{
+ // Drop on background
+ KURL dirURL = url();
+ if ( m_rootItem ) {
+ bool dummy;
+ dirURL = m_rootItem->mostLocalURL(dummy);
+ }
+ KonqOperations::doDrop( m_rootItem /* may be 0L */, dirURL, ev, this );
+}
+
+void KonqIconViewWidget::slotAboutToCreate(const QPoint &, const QValueList<KIO::CopyInfo> &)
+{
+ // Do nothing :-)
+}
+
+void KonqIconViewWidget::drawBackground( QPainter *p, const QRect &r )
+{
+ drawBackground(p, r, r.topLeft());
+}
+
+void KonqIconViewWidget::drawBackground( QPainter *p, const QRect &r , const QPoint &pt)
+{
+ const QPixmap *pm = backgroundPixmap();
+ bool hasPixmap = pm && !pm->isNull();
+ if ( !hasPixmap ) {
+ pm = viewport()->backgroundPixmap();
+ hasPixmap = pm && !pm->isNull();
+ }
+
+ QRect rtgt(r);
+ rtgt.moveTopLeft(pt);
+ if (!hasPixmap && backgroundMode() != NoBackground) {
+ p->fillRect(rtgt, viewport()->backgroundColor());
+ return;
+ }
+
+ if (hasPixmap) {
+ int ax = (r.x() + contentsX() + leftMargin()) % pm->width();
+ int ay = (r.y() + contentsY() + topMargin()) % pm->height();
+ p->drawTiledPixmap(rtgt, *pm, QPoint(ax, ay));
+ }
+}
+
+QDragObject * KonqIconViewWidget::dragObject()
+{
+ if ( !currentItem() )
+ return 0;
+
+ return konqDragObject( viewport() );
+}
+
+KonqIconDrag * KonqIconViewWidget::konqDragObject( QWidget * dragSource )
+{
+ //kdDebug(1203) << "KonqIconViewWidget::konqDragObject" << endl;
+
+ KonqIconDrag2 * drag = new KonqIconDrag2( dragSource );
+ QIconViewItem *primaryItem = currentItem();
+ // Append all items to the drag object
+ for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() ) {
+ if ( it->isSelected() ) {
+ if (!primaryItem)
+ primaryItem = it;
+ KFileItem* fileItem = (static_cast<KFileIVI *>(it))->item();
+ KURL url = fileItem->url();
+ bool dummy;
+ KURL mostLocalURL = fileItem->mostLocalURL(dummy);
+ QString itemURL = KURLDrag::urlToString(url);
+ kdDebug(1203) << "itemURL=" << itemURL << endl;
+ QIconDragItem id;
+ id.setData( QCString(itemURL.latin1()) );
+ drag->append( id,
+ QRect( it->pixmapRect(false).topLeft() - m_mousePos,
+ it->pixmapRect().size() ),
+ QRect( it->textRect(false).topLeft() - m_mousePos,
+ it->textRect().size() ),
+ itemURL, mostLocalURL );
+ }
+ }
+
+ if (primaryItem)
+ drag->setPixmap( *primaryItem->pixmap(), m_mousePos - primaryItem->pixmapRect(false).topLeft() );
+
+ return drag;
+}
+
+void KonqIconViewWidget::contentsDragEnterEvent( QDragEnterEvent *e )
+{
+ if ( e->provides( "text/uri-list" ) )
+ {
+ QByteArray payload = e->encodedData( "text/uri-list" );
+ if ( !payload.size() )
+ kdError() << "Empty data !" << endl;
+ // Cache the URLs, since we need them every time we move over a file
+ // (see KFileIVI)
+ bool ok = KURLDrag::decode( e, m_lstDragURLs );
+ if( !ok )
+ kdError() << "Couldn't decode urls dragged !" << endl;
+ }
+
+ KURL::List uriList;
+ if ( KURLDrag::decode(e, uriList) )
+ {
+ if ( uriList.first().protocol() == "programs" )
+ {
+ e->ignore();
+ emit dragEntered( false );
+ d->bProgramsURLdrag = true;
+ return;
+ }
+ }
+
+ KIconView::contentsDragEnterEvent( e );
+ emit dragEntered( true /*accepted*/ );
+}
+
+void KonqIconViewWidget::contentsDragMoveEvent( QDragMoveEvent *e )
+{
+ if ( d->bProgramsURLdrag ) {
+ emit dragMove( false );
+ e->ignore();
+ cancelPendingHeldSignal();
+ return;
+ }
+
+ QIconViewItem *item = findItem( e->pos() );
+ if ( e->source() != viewport() &&
+ !item && m_rootItem && !m_rootItem->isWritable() ) {
+ emit dragMove( false );
+ e->ignore();
+ cancelPendingHeldSignal();
+ return;
+ }
+ emit dragMove( true );
+ KIconView::contentsDragMoveEvent( e );
+}
+
+void KonqIconViewWidget::contentsDragLeaveEvent( QDragLeaveEvent *e )
+{
+ d->bProgramsURLdrag = false;
+ KIconView::contentsDragLeaveEvent(e);
+ emit dragLeft();
+}
+
+
+void KonqIconViewWidget::setItemColor( const QColor &c )
+{
+ iColor = c;
+}
+
+QColor KonqIconViewWidget::itemColor() const
+{
+ return iColor;
+}
+
+void KonqIconViewWidget::disableIcons( const KURL::List & lst )
+{
+ for ( QIconViewItem *kit = firstItem(); kit; kit = kit->nextItem() )
+ {
+ bool bFound = false;
+ // Wow. This is ugly. Matching two lists together....
+ // Some sorting to optimise this would be a good idea ?
+ for (KURL::List::ConstIterator it = lst.begin(); !bFound && it != lst.end(); ++it)
+ {
+ if ( static_cast<KFileIVI *>( kit )->item()->url() == *it )
+ {
+ bFound = true;
+ // maybe remove "it" from lst here ?
+ }
+ }
+ static_cast<KFileIVI *>( kit )->setDisabled( bFound );
+ }
+}
+
+void KonqIconViewWidget::slotSelectionChanged()
+{
+ // This code is very related to ListViewBrowserExtension::updateActions
+ int canCopy = 0;
+ int canDel = 0;
+ int canTrash = 0;
+ bool bInTrash = false;
+ int iCount = 0;
+
+ for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() )
+ {
+ if ( it->isSelected() )
+ {
+ iCount++;
+ canCopy++;
+
+ KFileItem *item = ( static_cast<KFileIVI *>( it ) )->item();
+ KURL url = item->url();
+ QString local_path = item->localPath();
+
+ if ( url.directory(false) == KGlobalSettings::trashPath() )
+ bInTrash = true;
+ if ( KProtocolInfo::supportsDeleting( url ) )
+ canDel++;
+ if ( !local_path.isEmpty() )
+ canTrash++;
+ }
+ }
+
+ emit enableAction( "cut", canDel > 0 );
+ emit enableAction( "copy", canCopy > 0 );
+ emit enableAction( "trash", canDel > 0 && !bInTrash && canTrash==canDel );
+ emit enableAction( "del", canDel > 0 );
+ emit enableAction( "properties", iCount > 0 && KPropertiesDialog::canDisplay( selectedFileItems() ) );
+ emit enableAction( "editMimeType", ( iCount == 1 ) );
+ emit enableAction( "rename", ( iCount == 1) && !bInTrash );
+}
+
+void KonqIconViewWidget::renameCurrentItem()
+{
+ if ( currentItem() )
+ currentItem()->rename();
+}
+
+void KonqIconViewWidget::renameSelectedItem()
+{
+ kdDebug(1203) << " -- KonqIconViewWidget::renameSelectedItem() -- " << endl;
+ QIconViewItem * item = 0L;
+ QIconViewItem *it = firstItem();
+ for (; it; it = it->nextItem() )
+ if ( it->isSelected() && !item )
+ {
+ item = it;
+ break;
+ }
+ if (!item)
+ {
+ Q_ASSERT(item);
+ return;
+ }
+ item->rename();
+}
+
+void KonqIconViewWidget::cutSelection()
+{
+ kdDebug(1203) << " -- KonqIconViewWidget::cutSelection() -- " << endl;
+ KonqIconDrag * obj = konqDragObject( /* no parent ! */ );
+ obj->setMoveSelection( true );
+ QApplication::clipboard()->setData( obj );
+}
+
+void KonqIconViewWidget::copySelection()
+{
+ kdDebug(1203) << " -- KonqIconViewWidget::copySelection() -- " << endl;
+ KonqIconDrag * obj = konqDragObject( /* no parent ! */ );
+ QApplication::clipboard()->setData( obj );
+}
+
+void KonqIconViewWidget::pasteSelection()
+{
+ paste( url() );
+}
+
+void KonqIconViewWidget::paste( const KURL &url )
+{
+ KonqOperations::doPaste( this, url );
+}
+
+KURL::List KonqIconViewWidget::selectedUrls()
+{
+ return selectedUrls( UserVisibleUrls );
+}
+
+KURL::List KonqIconViewWidget::selectedUrls( UrlFlags flags ) const
+{
+ KURL::List lstURLs;
+ bool dummy;
+ for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() )
+ if ( it->isSelected() ) {
+ KFileItem* item = (static_cast<KFileIVI *>( it ))->item();
+ lstURLs.append( flags == MostLocalUrls ? item->mostLocalURL( dummy ) : item->url() );
+ }
+ return lstURLs;
+}
+
+QRect KonqIconViewWidget::iconArea() const
+{
+ return m_IconRect;
+}
+
+void KonqIconViewWidget::setIconArea(const QRect &rect)
+{
+ m_IconRect = rect;
+}
+
+int KonqIconViewWidget::lineupMode() const
+{
+ return m_LineupMode;
+}
+
+void KonqIconViewWidget::setLineupMode(int mode)
+{
+ m_LineupMode = mode;
+}
+
+bool KonqIconViewWidget::sortDirectoriesFirst() const
+{
+ return m_bSortDirsFirst;
+}
+
+void KonqIconViewWidget::setSortDirectoriesFirst( bool b )
+{
+ m_bSortDirsFirst = b;
+}
+
+void KonqIconViewWidget::contentsMouseMoveEvent( QMouseEvent *e )
+{
+ if ( (d->pSoundPlayer && d->pSoundPlayer->isPlaying()) || (d->pSoundTimer && d->pSoundTimer->isActive()))
+ {
+ // The following call is SO expensive (the ::widgetAt call eats up to 80%
+ // of the mouse move cpucycles!), so it's mandatory to place that function
+ // under strict checks, such as d->pSoundPlayer->isPlaying()
+ if ( QApplication::widgetAt( QCursor::pos() ) != topLevelWidget() )
+ {
+ if (d->pSoundPlayer)
+ d->pSoundPlayer->stop();
+ d->pSoundItem = 0;
+ if (d->pSoundTimer && d->pSoundTimer->isActive())
+ d->pSoundTimer->stop();
+ }
+ }
+ d->renameItem= false;
+ KIconView::contentsMouseMoveEvent( e );
+}
+
+void KonqIconViewWidget::contentsDropEvent( QDropEvent * ev )
+{
+ QIconViewItem *i = findItem( ev->pos() );
+
+ if ( ev->source() != viewport() &&
+ !i && m_rootItem && !m_rootItem->isWritable() ) {
+ ev->accept( false );
+ return;
+ }
+
+ // Short-circuit QIconView if Ctrl is pressed, so that it's possible
+ // to drop a file into its own parent widget to copy it.
+ if ( !i && (ev->action() == QDropEvent::Copy || ev->action() == QDropEvent::Link)
+ && ev->source() && ev->source() == viewport())
+ {
+ // First we need to call QIconView though, to clear the drag shape
+ bool bMovable = itemsMovable();
+ setItemsMovable(false); // hack ? call it what you want :-)
+ KIconView::contentsDropEvent( ev );
+ setItemsMovable(bMovable);
+
+ QValueList<QIconDragItem> lst;
+ slotDropped(ev, lst);
+ }
+ else
+ {
+ KIconView::contentsDropEvent( ev );
+ emit dropped(); // What is this for ? (David) KDE4: remove
+ }
+ // Don't do this here, it's too early !
+ // slotSaveIconPositions();
+ // If we want to save after the new file gets listed, though,
+ // we could reimplement contentsDropEvent in KDIconView and set m_bNeedSave. Bah.
+
+ // This signal is sent last because we need to ensure it is
+ // taken in account when all the slots triggered by the dropped() signal
+ // are executed. This way we know that the Drag and Drop is truely finished
+ emit dragFinished();
+}
+
+void KonqIconViewWidget::doubleClickTimeout()
+{
+ d->renameItem= true;
+ mousePressChangeValue();
+ if ( d->releaseMouseEvent )
+ {
+ QMouseEvent e( QEvent::MouseButtonPress,d->mousePos , 1, d->mouseState);
+ QIconViewItem* item = findItem( e.pos() );
+ KURL url;
+ if ( item )
+ {
+ url= ( static_cast<KFileIVI *>( item ) )->item()->url();
+ bool brenameTrash =false;
+ if ( url.isLocalFile() && (url.directory(false) == KGlobalSettings::trashPath() || url.path(1).startsWith(KGlobalSettings::trashPath())))
+ brenameTrash = true;
+
+ if ( url.isLocalFile() && !brenameTrash && d->renameItem && m_pSettings->renameIconDirectly() && e.button() == LeftButton && item->textRect( false ).contains(e.pos()))
+ {
+ if( d->pActivateDoubleClick->isActive () )
+ d->pActivateDoubleClick->stop();
+ item->rename();
+ m_bMousePressed = false;
+ }
+ }
+ }
+ else
+ {
+ QMouseEvent e( QEvent::MouseMove,d->mousePos , 1, d->mouseState);
+ KIconView::contentsMousePressEvent( &e );
+ }
+ if( d->pActivateDoubleClick->isActive() )
+ d->pActivateDoubleClick->stop();
+
+ d->releaseMouseEvent = false;
+ d->renameItem= false;
+}
+
+void KonqIconViewWidget::wheelEvent(QWheelEvent* e)
+{
+ // when scrolling with mousewheel, stop possible pending filetip
+ d->pFileTip->setItem( 0 );
+
+ if (e->state() == ControlButton)
+ {
+ if (e->delta() >= 0)
+ {
+ emit incIconSize();
+ }
+ else
+ {
+ emit decIconSize();
+ }
+ e->accept();
+ return;
+ }
+
+ KIconView::wheelEvent(e);
+}
+
+void KonqIconViewWidget::leaveEvent( QEvent *e )
+{
+ // when leaving the widget, stop possible pending filetip and icon effect
+ slotOnViewport();
+
+ KIconView::leaveEvent(e);
+}
+
+void KonqIconViewWidget::mousePressChangeValue()
+{
+ //kdDebug(1203) << "KonqIconViewWidget::contentsMousePressEvent" << endl;
+ m_bMousePressed = true;
+ if (d->pSoundPlayer)
+ d->pSoundPlayer->stop();
+ d->bSoundItemClicked = true;
+ d->firstClick = false;
+
+ // Once we click on the item, we don't want a tooltip
+ // Fixes part of #86968
+ d->pFileTip->setItem( 0 );
+}
+
+void KonqIconViewWidget::contentsMousePressEvent( QMouseEvent *e )
+{
+ if(d->pActivateDoubleClick && d->pActivateDoubleClick->isActive ())
+ d->pActivateDoubleClick->stop();
+ QIconViewItem* item = findItem( e->pos() );
+ m_mousePos = e->pos();
+ KURL url;
+ if ( item )
+ {
+ url = ( static_cast<KFileIVI *>( item ) )->item()->url();
+ bool brenameTrash =false;
+ if ( url.isLocalFile() && (url.directory(false) == KGlobalSettings::trashPath() || url.path(1).startsWith(KGlobalSettings::trashPath())))
+ brenameTrash = true;
+ if ( !brenameTrash && !KGlobalSettings::singleClick() && m_pSettings->renameIconDirectly() && e->button() == LeftButton && item->textRect( false ).contains(e->pos())&& !d->firstClick && url.isLocalFile() && (!url.protocol().find("device", 0, false)==0))
+ {
+ d->firstClick = true;
+ d->mousePos = e->pos();
+ d->mouseState = e->state();
+ if (!d->pActivateDoubleClick)
+ {
+ d->pActivateDoubleClick = new QTimer(this);
+ connect(d->pActivateDoubleClick, SIGNAL(timeout()), this, SLOT(doubleClickTimeout()));
+ }
+ if( d->pActivateDoubleClick->isActive () )
+ d->pActivateDoubleClick->stop();
+ else
+ d->pActivateDoubleClick->start(QApplication::doubleClickInterval());
+ d->releaseMouseEvent = false;
+ return;
+ }
+ else
+ d->renameItem= false;
+ }
+ else
+ d->renameItem= false;
+ mousePressChangeValue();
+ if(d->pActivateDoubleClick && d->pActivateDoubleClick->isActive())
+ d->pActivateDoubleClick->stop();
+ KIconView::contentsMousePressEvent( e );
+
+}
+
+void KonqIconViewWidget::contentsMouseReleaseEvent( QMouseEvent *e )
+{
+ KIconView::contentsMouseReleaseEvent( e );
+ if(d->releaseMouseEvent && d->pActivateDoubleClick && d->pActivateDoubleClick->isActive ())
+ d->pActivateDoubleClick->stop();
+ slotSelectionChanged();
+ d->releaseMouseEvent = true;
+ m_bMousePressed = false;
+}
+
+void KonqIconViewWidget::slotSaveIconPositions()
+{
+ // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ // This code is currently not used but left in for compatibility reasons.
+ // It can be removed in KDE 4.0
+ // Saving of desktop icon positions is now done in KDIconView::saveIconPositions()
+ // in kdebase/kdesktop/kdiconview.cc
+ // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+
+ if ( m_dotDirectoryPath.isEmpty() )
+ return;
+ if ( !m_bDesktop )
+ return; // Currently not available in Konqueror
+ kdDebug(1214) << "KonqIconViewWidget::slotSaveIconPositions" << endl;
+ KSimpleConfig dotDirectory( m_dotDirectoryPath );
+ QIconViewItem *it = firstItem();
+ if ( !it )
+ return; // No more icons. Maybe we're closing and they've been removed already
+ while ( it )
+ {
+ KFileIVI *ivi = static_cast<KFileIVI *>( it );
+ KFileItem *item = ivi->item();
+
+ dotDirectory.setGroup( QString( m_iconPositionGroupPrefix ).append( item->url().fileName() ) );
+ kdDebug(1214) << "KonqIconViewWidget::slotSaveIconPositions " << item->url().fileName() << " " << it->x() << " " << it->y() << endl;
+ dotDirectory.writeEntry( QString( "X %1" ).arg( width() ), it->x() );
+ dotDirectory.writeEntry( QString( "Y %1" ).arg( height() ), it->y() );
+ dotDirectory.writeEntry( "Exists", true );
+
+ it = it->nextItem();
+ }
+
+ QStringList groups = dotDirectory.groupList();
+ QStringList::ConstIterator gIt = groups.begin();
+ QStringList::ConstIterator gEnd = groups.end();
+ for (; gIt != gEnd; ++gIt )
+ if ( (*gIt).left( m_iconPositionGroupPrefix.length() ) == m_iconPositionGroupPrefix )
+ {
+ dotDirectory.setGroup( *gIt );
+ if ( dotDirectory.hasKey( "Exists" ) )
+ dotDirectory.deleteEntry( "Exists", false );
+ else
+ {
+ kdDebug(1214) << "KonqIconViewWidget::slotSaveIconPositions deleting group " << *gIt << endl;
+ dotDirectory.deleteGroup( *gIt );
+ }
+ }
+
+ dotDirectory.sync();
+
+ // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ // This code is currently not used but left in for compatibility reasons.
+ // It can be removed in KDE 4.0
+ // Saving of desktop icon positions is now done in KDIconView::saveIconPositions()
+ // in kdebase/kdesktop/kdiconview.cc
+ // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+}
+
+// Adapted version of QIconView::insertInGrid, that works relative to
+// m_IconRect, instead of the entire viewport.
+
+void KonqIconViewWidget::insertInGrid(QIconViewItem *item)
+{
+ if (0L == item)
+ return;
+
+ if (!m_IconRect.isValid())
+ {
+ KIconView::insertInGrid(item);
+ return;
+ }
+
+ QRegion r(m_IconRect);
+ QIconViewItem *i = firstItem();
+ int y = -1;
+ for (; i; i = i->nextItem() )
+ {
+ r = r.subtract(i->rect());
+ y = QMAX(y, i->y() + i->height());
+ }
+
+ QMemArray<QRect> rects = r.rects();
+ QMemArray<QRect>::Iterator it = rects.begin();
+ bool foundPlace = FALSE;
+ for (; it != rects.end(); ++it)
+ {
+ QRect rect = *it;
+ if (rect.width() >= item->width() && rect.height() >= item->height())
+ {
+ int sx = 0, sy = 0;
+ if (rect.width() >= item->width() + spacing())
+ sx = spacing();
+ if (rect.height() >= item->height() + spacing())
+ sy = spacing();
+ item->move(rect.x() + sx, rect.y() + sy);
+ foundPlace = true;
+ break;
+ }
+ }
+
+ if (!foundPlace)
+ item->move(m_IconRect.topLeft());
+
+ //item->dirty = false;
+ return;
+}
+
+
+/*
+ * The algorithm used for lineing up the icons could be called
+ * "beating flat the icon field". Imagine the icon field to be some height
+ * field on a regular grid, with the height being the number of icons in
+ * each grid element. Now imagine slamming on the field with a shovel or
+ * some other flat surface. The high peaks will be flattened and spread out
+ * over their adjacent areas. This is basically what the algorithm tries to
+ * simulate.
+ *
+ * First, the icons are binned to a grid of the desired size. If all bins
+ * are containing at most one icon, we're done, of course. We just have to
+ * move all icons to the center of each grid element.
+ * For each bin which has more than one icon in it, we calculate 4
+ * "friction coefficients", one for each cardinal direction. The friction
+ * coefficient of a direction is the number of icons adjacent in that
+ * direction. The idea is that this number is somewhat a measure in which
+ * direction the icons should flow: icons flow in the direction of lowest
+ * friction coefficient. We move a maximum of one icon per bin and loop over
+ * all bins. This procedure is repeated some maximum number of times or until
+ * no icons are moved anymore.
+ *
+ * I don't know if this algorithm is good or bad, I don't even know if it will
+ * work all the time. It seems a correct thing to do, however, and it seems to
+ * work particularly well. In any case, the number of runs is limited so there
+ * can be no races.
+ */
+
+void KonqIconViewWidget::lineupIcons()
+{
+ // even if there are no items yet, calculate the maxItemWidth to have the correct
+ // item rect when we insert new items
+
+ // Create a grid of (ny x nx) bins.
+ int x0, y0, dx, dy, nx, ny;
+ gridValues( &x0, &y0, &dx, &dy, &nx, &ny );
+
+ int itemWidth = dx - spacing();
+ bool newItemWidth = false;
+ if ( maxItemWidth() != itemWidth ) {
+ newItemWidth = true;
+ setMaxItemWidth( itemWidth );
+ setFont( font() ); // Force calcRect()
+ }
+
+ if ( !firstItem() ) {
+ kdDebug(1203) << "No icons at all ?\n";
+ return;
+ }
+
+ int iconSize = m_size ? m_size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
+
+ typedef QValueList<QIconViewItem*> Bin;
+ Bin*** bins = new Bin**[nx];
+ int i;
+ int j;
+ for ( i = 0; i < nx ; i++ ) {
+ bins[i] = new Bin*[ny];
+ for ( j = 0; j < ny; j++ )
+ bins[i][j] = 0L;
+ }
+
+ // Insert items into grid
+ int textHeight = iconTextHeight() * fontMetrics().height();
+
+ for ( QIconViewItem* item = firstItem(); item; item = item->nextItem() ) {
+ int x = item->x() + item->width() / 2 - x0;
+ int y = item->pixmapRect( false ).bottom() - iconSize / 2
+ - ( dy - ( iconSize + textHeight ) ) / 2 - y0;
+ int posX = QMIN( nx-1, QMAX( 0, x / dx ) );
+ int posY = QMIN( ny-1, QMAX( 0, y / dy ) );
+
+ if ( !bins[posX][posY] )
+ bins[posX][posY] = new Bin;
+ bins[posX][posY]->prepend( item );
+ }
+
+ // The shuffle code
+ int n, k;
+ const int infinity = 10000;
+ int nmoves = 1;
+ for ( n = 0; n < 30 && nmoves > 0; n++ ) {
+ nmoves = 0;
+ for ( i = 0; i < nx; i++ ) {
+ for ( j = 0; j < ny; j++ ) {
+ if ( !bins[i][j] || ( bins[i][j]->count() <= 1 ) )
+ continue;
+
+ // Calculate the 4 "friction coefficients".
+ int tf = 0, bf = 0, lf = 0, rf = 0;
+ for ( k = j-1; k >= 0 && bins[i][k] && bins[i][k]->count(); k-- )
+ tf += bins[i][k]->count();
+ if ( k == -1 )
+ tf += infinity;
+
+ for ( k = j+1; k < ny && bins[i][k] && bins[i][k]->count(); k++ )
+ bf += bins[i][k]->count();
+ if ( k == ny )
+ bf += infinity;
+
+ for ( k = i-1; k >= 0 && bins[k][j] && bins[k][j]->count(); k-- )
+ lf += bins[k][j]->count();
+ if ( k == -1 )
+ lf += infinity;
+
+ for ( k = i+1; k < nx && bins[k][j] && bins[k][j]->count(); k++ )
+ rf += bins[k][j]->count();
+ if ( k == nx )
+ rf += infinity;
+
+ // If we are stuck between walls, continue
+ if ( tf >= infinity && bf >= infinity &&
+ lf >= infinity && rf >= infinity )
+ continue;
+
+ // Is there a preferred lineup direction?
+ if ( m_LineupMode == LineupHorizontal ) {
+ tf += infinity;
+ bf += infinity;
+ }
+ else if ( m_LineupMode == LineupVertical ) {
+ lf += infinity;
+ rf += infinity;
+ }
+
+ // Move one item in the direction of the least friction
+ QIconViewItem* movedItem;
+ Bin* items = bins[i][j];
+
+ int mini = QMIN( QMIN( tf, bf ), QMIN( lf, rf ) );
+ if ( tf == mini ) {
+ // move top item in (i,j) to (i,j-1)
+ Bin::iterator it = items->begin();
+ movedItem = *it;
+ for ( ++it; it != items->end(); ++it ) {
+ if ( (*it)->y() < movedItem->y() )
+ movedItem = *it;
+ }
+ items->remove( movedItem );
+ if ( !bins[i][j-1] )
+ bins[i][j-1] = new Bin;
+ bins[i][j-1]->prepend( movedItem );
+ }
+ else if ( bf ==mini ) {
+ // move bottom item in (i,j) to (i,j+1)
+ Bin::iterator it = items->begin();
+ movedItem = *it;
+ for ( ++it; it != items->end(); ++it ) {
+ if ( (*it)->y() > movedItem->y() )
+ movedItem = *it;
+ }
+ items->remove( movedItem );
+ if ( !bins[i][j+1] )
+ bins[i][j+1] = new Bin;
+ bins[i][j+1]->prepend( movedItem );
+ }
+ else if ( lf == mini )
+ {
+ // move left item in (i,j) to (i-1,j)
+ Bin::iterator it = items->begin();
+ movedItem = *it;
+ for ( ++it; it != items->end(); ++it ) {
+ if ( (*it)->x() < movedItem->x() )
+ movedItem = *it;
+ }
+ items->remove( movedItem );
+ if ( !bins[i-1][j] )
+ bins[i-1][j] = new Bin;
+ bins[i-1][j]->prepend( movedItem );
+ }
+ else {
+ // move right item in (i,j) to (i+1,j)
+ Bin::iterator it = items->begin();
+ movedItem = *it;
+ for ( ++it; it != items->end(); ++it ) {
+ if ( (*it)->x() > movedItem->x() )
+ movedItem = *it;
+ }
+ items->remove( movedItem );
+ if ( !bins[i+1][j] )
+ bins[i+1][j] = new Bin;
+ bins[i+1][j]->prepend( movedItem );
+ }
+ nmoves++;
+ }
+ }
+ }
+
+ // Perform the actual moving
+ QRegion repaintRegion;
+ QValueList<QIconViewItem*> movedItems;
+
+ for ( i = 0; i < nx; i++ ) {
+ for ( j = 0; j < ny; j++ ) {
+ Bin* bin = bins[i][j];
+ if ( !bin )
+ continue;
+ if ( !bin->isEmpty() ) {
+ QIconViewItem* item = bin->first();
+ int newX = x0 + i*dx + spacing() +
+ QMAX(0, ( (dx-spacing()) - item->width() ) / 2); // pixmap can be larger as iconsize
+ // align all icons vertically to their text
+ int newY = y0 + j*dy + dy - spacing() - ( item->pixmapRect().bottom() + 2 + textHeight );
+ if ( item->x() != newX || item->y() != newY ) {
+ QRect oldRect = item->rect();
+ movedItems.prepend( item );
+ item->move( newX, newY );
+ if ( item->rect() != oldRect )
+ repaintRegion = repaintRegion.unite( oldRect );
+ }
+ }
+ delete bin;
+ bins[i][j] = 0L;
+ }
+ }
+
+ // repaint
+ if ( newItemWidth )
+ updateContents();
+ else {
+ // Repaint only repaintRegion...
+ QMemArray<QRect> rects = repaintRegion.rects();
+ for ( uint l = 0; l < rects.count(); l++ ) {
+ kdDebug( 1203 ) << "Repainting (" << rects[l].x() << ","
+ << rects[l].y() << ")\n";
+ repaintContents( rects[l], false );
+ }
+ // Repaint icons that were moved
+ while ( !movedItems.isEmpty() ) {
+ repaintItem( movedItems.first() );
+ movedItems.remove( movedItems.first() );
+ }
+ }
+
+ for ( i = 0; i < nx ; i++ ) {
+ delete [] bins[i];
+ }
+ delete [] bins;
+}
+
+void KonqIconViewWidget::lineupIcons( QIconView::Arrangement arrangement )
+{
+ int x0, y0, dx, dy, nxmax, nymax;
+ gridValues( &x0, &y0, &dx, &dy, &nxmax, &nymax );
+ int textHeight = iconTextHeight() * fontMetrics().height();
+
+ QRegion repaintRegion;
+ QValueList<QIconViewItem*> movedItems;
+ int nx = 0, ny = 0;
+
+ QIconViewItem* item;
+ for ( item = firstItem(); item; item = item->nextItem() ) {
+ int newX = x0 + nx*dx + spacing() +
+ QMAX(0, ( (dx-spacing()) - item->width() ) / 2); // icon can be larger as defined
+ // align all icons vertically to their text
+ int newY = y0 + ny*dy + dy - spacing() - ( item->pixmapRect().bottom() + 2 + textHeight );
+ if ( item->x() != newX || item->y() != newY ) {
+ QRect oldRect = item->rect();
+ movedItems.prepend( item );
+ item->move( newX, newY );
+ if ( item->rect() != oldRect )
+ repaintRegion = repaintRegion.unite( oldRect );
+ }
+ if ( arrangement == QIconView::LeftToRight ) {
+ nx++;
+ if ( nx >= nxmax ) {
+ ny++;
+ nx = 0;
+ }
+ }
+ else {
+ ny++;
+ if ( ny >= nymax ) {
+ nx++;
+ ny = 0;
+ }
+ }
+ }
+
+ // Repaint only repaintRegion...
+ QMemArray<QRect> rects = repaintRegion.rects();
+ for ( uint l = 0; l < rects.count(); l++ ) {
+ kdDebug( 1203 ) << "Repainting (" << rects[l].x() << ","
+ << rects[l].y() << ")\n";
+ repaintContents( rects[l], false );
+ }
+ // Repaint icons that were moved
+ while ( !movedItems.isEmpty() ) {
+ repaintItem( movedItems.first() );
+ movedItems.remove( movedItems.first() );
+ }
+}
+
+int KonqIconViewWidget::largestPreviewIconSize( int size ) const
+{
+ int iconSize = size ? size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
+
+ if (iconSize < 28)
+ return 48;
+ if (iconSize < 40)
+ return 64;
+ if (iconSize < 60)
+ return 96;
+ if (iconSize < 120)
+ return 128;
+
+ return 192;
+}
+
+int KonqIconViewWidget::previewIconSize( int size ) const
+{
+ int iconSize = size ? size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
+
+ if (!d->bBoostPreview)
+ return iconSize;
+
+ return largestPreviewIconSize( iconSize );
+}
+
+void KonqIconViewWidget::visualActivate(QIconViewItem * item)
+{
+ // Rect of the QIconViewItem.
+ QRect irect = item->rect();
+
+ // Rect of the QIconViewItem's pixmap area.
+ QRect rect = item->pixmapRect();
+
+ // Adjust to correct position. If this isn't done, the fact that the
+ // text may be wider than the pixmap puts us off-centre.
+ rect.moveBy(irect.x(), irect.y());
+
+ // Adjust for scrolling (David)
+ rect.moveBy( -contentsX(), -contentsY() );
+
+ KIconEffect::visualActivate(viewport(), rect);
+}
+
+void KonqIconViewWidget::backgroundPixmapChange( const QPixmap & )
+{
+ viewport()->update();
+}
+
+void KonqIconViewWidget::setPreviewSettings( const QStringList& settings )
+{
+ d->previewSettings = settings;
+ updatePreviewMimeTypes();
+
+ int size = m_size;
+ m_size = -1; // little trick to force grid change in setIcons
+ setIcons( size ); // force re-determining all icons
+}
+
+const QStringList& KonqIconViewWidget::previewSettings()
+{
+ return d->previewSettings;
+}
+
+void KonqIconViewWidget::setNewURL( const QString& url )
+{
+ KURL u;
+ if ( url.startsWith( "/" ) )
+ u.setPath( url );
+ else
+ u = url;
+ setURL( u );
+}
+
+void KonqIconViewWidget::setCaseInsensitiveSort( bool b )
+{
+ d->bCaseInsensitive = b;
+}
+
+bool KonqIconViewWidget::caseInsensitiveSort() const
+{
+ return d->bCaseInsensitive;
+}
+
+bool KonqIconViewWidget::canPreview( KFileItem* item )
+{
+ if ( !KGlobalSettings::showFilePreview( url() ) )
+ return false;
+
+ if ( d->pPreviewMimeTypes == 0L )
+ updatePreviewMimeTypes();
+
+ return mimeTypeMatch( item->mimetype(), *( d->pPreviewMimeTypes ) );
+}
+
+void KonqIconViewWidget::updatePreviewMimeTypes()
+{
+ if ( d->pPreviewMimeTypes == 0L )
+ d->pPreviewMimeTypes = new QStringList;
+ else
+ d->pPreviewMimeTypes->clear();
+
+ // Load the list of plugins to determine which mimetypes are supported
+ KTrader::OfferList plugins = KTrader::self()->query("ThumbCreator");
+ KTrader::OfferList::ConstIterator it;
+
+ for ( it = plugins.begin(); it != plugins.end(); ++it ) {
+ if ( d->previewSettings.contains((*it)->desktopEntryName()) ) {
+ QStringList mimeTypes = (*it)->property("MimeTypes").toStringList();
+ for (QStringList::ConstIterator mt = mimeTypes.begin(); mt != mimeTypes.end(); ++mt)
+ d->pPreviewMimeTypes->append(*mt);
+ }
+ }
+}
+
+#include "konq_iconviewwidget.moc"
+
+/* vim: set et sw=4 ts=8 softtabstop=4: */
diff --git a/libkonq/konq_iconviewwidget.h b/libkonq/konq_iconviewwidget.h
new file mode 100644
index 000000000..6f18cc020
--- /dev/null
+++ b/libkonq/konq_iconviewwidget.h
@@ -0,0 +1,370 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ Copyright (C) 2000, 2001, 2002 David Faure <david@mandrakesoft.com>
+
+ 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 __konq_iconviewwidget_h__
+#define __konq_iconviewwidget_h__
+
+#include <kiconloader.h>
+#include <kiconview.h>
+#include <kurl.h>
+#include <qguardedptr.h>
+#include <kfileitem.h>
+#include <kio/jobclasses.h>
+#include <libkonq_export.h>
+
+class KonqFMSettings;
+class KFileIVI;
+class KonqIconDrag;
+namespace KIO { class Job; }
+
+/**
+ * A file-aware icon view, implementing drag'n'drop, KDE icon sizes,
+ * user settings, animated icons...
+ * Used by kdesktop and konq_iconview.
+ *
+ */
+class LIBKONQ_EXPORT KonqIconViewWidget : public KIconView
+{
+ Q_OBJECT
+ Q_PROPERTY( bool sortDirectoriesFirst READ sortDirectoriesFirst WRITE setSortDirectoriesFirst )
+ Q_PROPERTY( QRect iconArea READ iconArea WRITE setIconArea )
+ Q_PROPERTY( int lineupMode READ lineupMode WRITE setLineupMode )
+ Q_PROPERTY( QString url READ urlString WRITE setNewURL )
+
+ friend class KFileIVI;
+
+public:
+
+ enum LineupMode { LineupHorizontal=1, LineupVertical, LineupBoth };
+
+ /**
+ * Constructor
+ */
+ KonqIconViewWidget( QWidget *parent = 0L, const char *name = 0L, WFlags f = 0, bool kdesktop = FALSE );
+ virtual ~KonqIconViewWidget();
+
+ /**
+ * Read the configuration and apply it.
+ * Call this in the inherited constructor with bInit=true,
+ * and in some reparseConfiguration() slot with bInit=false.
+ * Returns true if the font was changed (which means something has to
+ * be done so that the icon's texts don't run into each other).
+ * However Konq and KDesktop handle this differently.
+ */
+ bool initConfig( bool bInit );
+
+ /**
+ * Set the area that will be occupied by icons. It is still possible to
+ * drag icons outside this area; this only applies to automatically placed
+ * icons.
+ */
+ void setIconArea( const QRect &rect );
+
+ /**
+ * Reimplemented to make the slotOnItem highlighting work.
+ */
+ virtual void focusOutEvent( QFocusEvent * /* ev */ );
+
+ /**
+ * Returns the icon area.
+ */
+ QRect iconArea() const;
+
+ /**
+ * Set the lineup mode. This determines in which direction(s) icons are
+ * moved when lineing them up.
+ */
+ void setLineupMode(int mode);
+
+ /**
+ * Returns the lineup mode.
+ */
+ int lineupMode() const;
+
+ /**
+ * Line up the icons to a regular grid. The outline of the grid is
+ * specified by iconArea. The two length parameters are
+ * gridX and gridY.
+ */
+ void lineupIcons();
+
+ /**
+ * Line up the icons to a regular grid horizontally or vertically.
+ *
+ * @param arrangement the arrangement to use (QIconView::LeftToRight
+ * for a horizontal arrangement and QIconView::TopToBottom
+ * for vertical)
+ */
+ void lineupIcons( QIconView::Arrangement arrangement );
+
+ /**
+ * Sets the icons of all items, and stores the @p size
+ * This doesn't touch thumbnails, except if @p stopImagePreviewFor is set.
+ * Takes care of the grid, when changing the size.
+ *
+ * @param size size to use for the icons
+ * @param stopImagePreviewFor set to a list of mimetypes which should be made normal again.
+ * For instance "text/plain,image/wmf".
+ * Can be set to "*" for "all mimetypes" and to "image/"+"*" for "all images".
+ */
+ void setIcons( int size, const QStringList& stopImagePreviewFor = QStringList() );
+
+ /**
+ * Called on databaseChanged
+ */
+ void refreshMimeTypes();
+
+ int iconSize() { return m_size; }
+
+ void calculateGridX();
+ /**
+ * The horizontal distance between two icons
+ * (whether or not a grid has been given to QIconView)
+ */
+ int gridXValue() const;
+
+ /**
+ * Calculate the geometry of the fixed grid that is used to line up the
+ * icons, for example when using the lineupIcons() method.
+ *
+ * @param x
+ * @param y
+ * @param dx Cell width
+ * @param dy Cell height
+ * @param nx Number of columns
+ * @param ny Number of rows
+ */
+ void gridValues( int* x, int* y, int* dx, int* dy, int* nx, int* ny );
+
+ /**
+ * Start generating the previews.
+ * @param ignored this parameter is probably ignored
+ * @param force if true, all files are looked at.
+ * Otherwise, only those which are not a thumbnail already.
+ *
+ * @todo figure out the parameter meanings again
+ */
+ void startImagePreview( const QStringList &ignored, bool force );
+ void stopImagePreview();
+ bool isPreviewRunning() const;
+ // unused
+ void setThumbnailPixmap( KFileIVI * item, const QPixmap & pixmap );
+ void disableSoundPreviews();
+
+ void setURL ( const KURL & kurl );
+ // ### KDE4: make const
+ const KURL & url() { return m_url; }
+ QString urlString() const { return m_url.url(); }
+ void setRootItem ( const KFileItem * item ) { m_rootItem = item; }
+
+ /**
+ * Get list of selected KFileItems
+ */
+ KFileItemList selectedFileItems();
+
+ void setItemColor( const QColor &c );
+ QColor itemColor() const;
+
+ virtual void cutSelection();
+ virtual void copySelection();
+ virtual void pasteSelection();
+ virtual KURL::List selectedUrls(); // KDE4: remove virtual + add const
+ enum UrlFlags { UserVisibleUrls = 0, MostLocalUrls = 1 };
+ KURL::List selectedUrls( UrlFlags flags ) const; // KDE4: merge with above, default is == UserVisibleUrls
+ void paste( const KURL &url );
+
+ bool sortDirectoriesFirst() const;
+ void setSortDirectoriesFirst( bool b );
+
+ void setCaseInsensitiveSort( bool b );
+ bool caseInsensitiveSort() const;
+
+ /**
+ * Cache of the dragged URLs over the icon view, used by KFileIVI
+ */
+ const KURL::List & dragURLs() { return m_lstDragURLs; }
+
+ /**
+ * Reimplemented from QIconView
+ */
+ virtual void clear();
+
+ /**
+ * Reimplemented from QIconView
+ */
+ virtual void takeItem( QIconViewItem *item );
+
+ /**
+ * Reimplemented from QIconView to take into account iconArea.
+ */
+ virtual void insertInGrid( QIconViewItem *item );
+
+ /**
+ * Reimplemented from QIconView to update the gridX
+ */
+ virtual void setItemTextPos( ItemTextPos pos );
+
+ /**
+ * Give feedback when item is activated.
+ */
+ virtual void visualActivate(QIconViewItem *);
+
+ bool isDesktop() const { return m_bDesktop; }
+
+ /**
+ * Provided for KDesktop.
+ */
+ virtual void setWallpaper(const KURL&) { }
+
+ bool maySetWallpaper();
+ void setMaySetWallpaper(bool b);
+
+ void disableIcons( const KURL::List & lst );
+
+ QString iconPositionGroupPrefix() const { return m_iconPositionGroupPrefix; }
+ QString dotDirectoryPath() const { return m_dotDirectoryPath; }
+
+ void setPreviewSettings(const QStringList& mimeTypes);
+ const QStringList& previewSettings();
+ void setNewURL( const QString& url );
+
+public slots:
+ /**
+ * Checks the new selection and emits enableAction() signals
+ */
+ virtual void slotSelectionChanged();
+
+ void slotSaveIconPositions();
+
+ void renameSelectedItem();
+ void renameCurrentItem();
+
+ void slotToolTipPreview( const KFileItem *, const QPixmap & ); // ### unused - remove for KDE4
+ void slotToolTipPreviewResult() ; // ### unused - remove for KDE4
+
+signals:
+ /**
+ * For cut/copy/paste/move/delete (see kparts/browserextension.h)
+ */
+ void enableAction( const char * name, bool enabled );
+
+ void dropped();
+ void imagePreviewFinished();
+
+ void incIconSize();
+ void decIconSize();
+
+ /**
+ * We need to track drag in icon views for the spring loading folders
+ */
+ void dragEntered( bool accepted );
+ void dragLeft();
+
+ void dragMove( bool accepted );
+ /**
+ * Emited after the dropped() event. This way we know when the
+ * drag'n'drop is really finished.
+ */
+ void dragFinished();
+
+protected slots:
+ virtual void slotDropped( QDropEvent *e, const QValueList<QIconDragItem> & );
+
+ void slotItemRenamed(QIconViewItem *item, const QString &name);
+
+ void slotIconChanged(int);
+ void slotOnItem(QIconViewItem *);
+ void slotOnViewport();
+ void slotStartSoundPreview();
+ void slotPreview(const KFileItem *, const QPixmap &);
+ void slotPreviewResult();
+
+ void slotMovieUpdate( const QRect& rect );
+ void slotMovieStatus( int status );
+ void slotReenableAnimation();
+
+ void slotAboutToCreate(const QPoint &pos, const QValueList<KIO::CopyInfo> &files);
+ void doubleClickTimeout();
+
+protected:
+ virtual QDragObject *dragObject();
+ KonqIconDrag *konqDragObject( QWidget * dragSource = 0L );
+ bool mimeTypeMatch( const QString& mimeType, const QStringList& mimeList ) const;
+
+ virtual void drawBackground( QPainter *p, const QRect &r );
+ /**
+ * r is the rectangle which you want to paint from the background.
+ * pt is the upper left point in the painter device where you want to paint
+ * the rectangle r.
+ */
+ virtual void drawBackground( QPainter *p, const QRect &r,
+ const QPoint &pt );
+ virtual void contentsDragEnterEvent( QDragEnterEvent *e );
+ virtual void contentsDragLeaveEvent( QDragLeaveEvent *e );
+ virtual void contentsDragMoveEvent( QDragMoveEvent *e );
+ virtual void contentsDropEvent( QDropEvent *e );
+ virtual void contentsMousePressEvent( QMouseEvent *e );
+ virtual void contentsMouseReleaseEvent ( QMouseEvent * e );
+ virtual void contentsMouseMoveEvent( QMouseEvent *e );
+ virtual void backgroundPixmapChange( const QPixmap & );
+ virtual void wheelEvent( QWheelEvent* );
+ virtual void leaveEvent( QEvent *e );
+
+ void readAnimatedIconsConfig();
+ void mousePressChangeValue();
+
+ bool boostPreview() const;
+ int previewIconSize( int size ) const;
+ int largestPreviewIconSize( int size ) const;
+ bool canPreview( KFileItem* item );
+ void updatePreviewMimeTypes();
+
+private:
+ KURL m_url;
+ const KFileItem * m_rootItem;
+
+ KURL::List m_lstDragURLs;
+
+ int m_size;
+
+ /** Konqueror settings */
+ KonqFMSettings * m_pSettings;
+
+ bool m_bMousePressed;
+ QPoint m_mousePos;
+
+ QColor iColor;
+
+ bool m_bSortDirsFirst;
+
+ QString m_iconPositionGroupPrefix;
+ QString m_dotDirectoryPath;
+
+ int m_LineupMode;
+ QRect m_IconRect;
+
+ bool m_bDesktop;
+ bool m_bSetGridX;
+
+private:
+ struct KonqIconViewWidgetPrivate *d;
+
+};
+
+#endif
diff --git a/libkonq/konq_operations.cc b/libkonq/konq_operations.cc
new file mode 100644
index 000000000..5e9e8269b
--- /dev/null
+++ b/libkonq/konq_operations.cc
@@ -0,0 +1,817 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000 David Faure <faure@kde.org>
+
+ 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 <qclipboard.h>
+#include "konq_operations.h"
+
+#include <kautomount.h>
+#include <kinputdialog.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <knotifyclient.h>
+#include <krun.h>
+#include <kshell.h>
+#include <kshortcut.h>
+
+#include <kdirnotify_stub.h>
+
+#include <dcopclient.h>
+#include "konq_undo.h"
+#include "konq_defaults.h"
+#include "konqbookmarkmanager.h"
+
+// For doDrop
+#include <qdir.h>//first
+#include <assert.h>
+#include <kapplication.h>
+#include <kipc.h>
+#include <kdebug.h>
+#include <kfileitem.h>
+#include <kdesktopfile.h>
+#include <kurldrag.h>
+#include <kglobalsettings.h>
+#include <kimageio.h>
+#include <kio/job.h>
+#include <kio/jobclasses.h>
+#include <kio/paste.h>
+#include <kio/netaccess.h>
+#include <kio/renamedlg.h>
+#include <konq_drag.h>
+#include <konq_iconviewwidget.h>
+#include <kprotocolinfo.h>
+#include <kprocess.h>
+#include <kstringhandler.h>
+#include <qpopupmenu.h>
+#include <unistd.h>
+#include <X11/Xlib.h>
+
+KBookmarkManager * KonqBookmarkManager::s_bookmarkManager;
+
+KonqOperations::KonqOperations( QWidget *parent )
+ : QObject( parent, "KonqOperations" ),
+ m_method( UNKNOWN ), m_info(0L), m_pasteInfo(0L)
+{
+}
+
+KonqOperations::~KonqOperations()
+{
+ delete m_info;
+ delete m_pasteInfo;
+}
+
+void KonqOperations::editMimeType( const QString & mimeType )
+{
+ QString keditfiletype = QString::fromLatin1("keditfiletype");
+ KRun::runCommand( keditfiletype + " " + KProcess::quote(mimeType),
+ keditfiletype, keditfiletype /*unused*/);
+}
+
+void KonqOperations::del( QWidget * parent, int method, const KURL::List & selectedURLs )
+{
+ kdDebug(1203) << "KonqOperations::del " << parent->className() << endl;
+ if ( selectedURLs.isEmpty() )
+ {
+ kdWarning(1203) << "Empty URL list !" << endl;
+ return;
+ }
+
+ KonqOperations * op = new KonqOperations( parent );
+ ConfirmationType confirmation = DEFAULT_CONFIRMATION;
+ op->_del( method, selectedURLs, confirmation );
+}
+
+void KonqOperations::emptyTrash()
+{
+ KonqOperations *op = new KonqOperations( 0L );
+ op->_del( EMPTYTRASH, KURL("trash:/"), SKIP_CONFIRMATION );
+}
+
+void KonqOperations::restoreTrashedItems( const KURL::List& urls )
+{
+ KonqOperations *op = new KonqOperations( 0L );
+ op->_restoreTrashedItems( urls );
+}
+
+void KonqOperations::mkdir( QWidget *parent, const KURL & url )
+{
+ KIO::Job * job = KIO::mkdir( url );
+ KonqOperations * op = new KonqOperations( parent );
+ op->setOperation( job, MKDIR, KURL::List(), url );
+ (void) new KonqCommandRecorder( KonqCommand::MKDIR, KURL(), url, job ); // no support yet, apparently
+}
+
+void KonqOperations::doPaste( QWidget * parent, const KURL & destURL )
+{
+ doPaste(parent, destURL, QPoint());
+}
+
+void KonqOperations::doPaste( QWidget * parent, const KURL & destURL, const QPoint &pos )
+{
+ // move or not move ?
+ bool move = false;
+ QMimeSource *data = QApplication::clipboard()->data();
+ if ( data->provides( "application/x-kde-cutselection" ) ) {
+ move = KonqDrag::decodeIsCutSelection( data );
+ kdDebug(1203) << "move (from clipboard data) = " << move << endl;
+ }
+
+ KIO::Job *job = KIO::pasteClipboard( destURL, move );
+ if ( job )
+ {
+ KonqOperations * op = new KonqOperations( parent );
+ KIO::CopyJob * copyJob = static_cast<KIO::CopyJob *>(job);
+ KIOPasteInfo * pi = new KIOPasteInfo;
+ pi->mousePos = pos;
+ op->setPasteInfo( pi );
+ op->setOperation( job, move ? MOVE : COPY, copyJob->srcURLs(), copyJob->destURL() );
+ (void) new KonqCommandRecorder( move ? KonqCommand::MOVE : KonqCommand::COPY, KURL::List(), destURL, job );
+ }
+}
+
+void KonqOperations::copy( QWidget * parent, int method, const KURL::List & selectedURLs, const KURL& destUrl )
+{
+ kdDebug(1203) << "KonqOperations::copy() " << parent->className() << endl;
+ if ((method!=COPY) && (method!=MOVE) && (method!=LINK))
+ {
+ kdWarning(1203) << "Illegal copy method !" << endl;
+ return;
+ }
+ if ( selectedURLs.isEmpty() )
+ {
+ kdWarning(1203) << "Empty URL list !" << endl;
+ return;
+ }
+
+ KonqOperations * op = new KonqOperations( parent );
+ KIO::Job* job(0);
+ if (method==LINK)
+ job= KIO::link( selectedURLs, destUrl);
+ else if (method==MOVE)
+ job= KIO::move( selectedURLs, destUrl);
+ else
+ job= KIO::copy( selectedURLs, destUrl);
+
+ op->setOperation( job, method, selectedURLs, destUrl );
+
+ if (method==COPY)
+ (void) new KonqCommandRecorder( KonqCommand::COPY, selectedURLs, destUrl, job );
+ else
+ (void) new KonqCommandRecorder( method==MOVE?KonqCommand::MOVE:KonqCommand::LINK, selectedURLs, destUrl, job );
+}
+
+void KonqOperations::_del( int method, const KURL::List & _selectedURLs, ConfirmationType confirmation )
+{
+ KURL::List selectedURLs;
+ for (KURL::List::ConstIterator it = _selectedURLs.begin(); it != _selectedURLs.end(); ++it)
+ if (KProtocolInfo::supportsDeleting(*it))
+ selectedURLs.append(*it);
+ if (selectedURLs.isEmpty()) {
+ delete this;
+ return;
+ }
+
+ if ( askDeleteConfirmation( selectedURLs, method, confirmation, parentWidget() ) )
+ {
+ //m_srcURLs = selectedURLs;
+ KIO::Job *job;
+ m_method = method;
+ switch( method )
+ {
+ case TRASH:
+ {
+ job = KIO::trash( selectedURLs );
+ (void) new KonqCommandRecorder( KonqCommand::TRASH, selectedURLs, "trash:/", job );
+ break;
+ }
+ case EMPTYTRASH:
+ {
+ // Same as in ktrash --empty
+ QByteArray packedArgs;
+ QDataStream stream( packedArgs, IO_WriteOnly );
+ stream << (int)1;
+ job = KIO::special( "trash:/", packedArgs );
+ KNotifyClient::event(0, "Trash: emptied");
+ break;
+ }
+ case DEL:
+ job = KIO::del( selectedURLs );
+ break;
+ case SHRED:
+ job = KIO::del( selectedURLs, true );
+ break;
+ default:
+ kdWarning() << "Unknown operation: " << method << endl;
+ delete this;
+ return;
+ }
+ connect( job, SIGNAL( result( KIO::Job * ) ),
+ SLOT( slotResult( KIO::Job * ) ) );
+ } else
+ delete this;
+}
+
+void KonqOperations::_restoreTrashedItems( const KURL::List& urls )
+{
+ m_method = RESTORE;
+ KonqMultiRestoreJob* job = new KonqMultiRestoreJob( urls, true );
+ connect( job, SIGNAL( result( KIO::Job * ) ),
+ SLOT( slotResult( KIO::Job * ) ) );
+}
+
+bool KonqOperations::askDeleteConfirmation( const KURL::List & selectedURLs, int method, ConfirmationType confirmation, QWidget* widget )
+{
+ if ( confirmation == SKIP_CONFIRMATION )
+ return true;
+ QString keyName;
+ bool ask = ( confirmation == FORCE_CONFIRMATION );
+ if ( !ask )
+ {
+ KConfig config("konquerorrc", true, false);
+ config.setGroup( "Trash" );
+ keyName = ( method == DEL ? "ConfirmDelete" : method == SHRED ? "ConfirmShred" : "ConfirmTrash" );
+ bool defaultValue = ( method == DEL ? DEFAULT_CONFIRMDELETE : method == SHRED ? DEFAULT_CONFIRMSHRED : DEFAULT_CONFIRMTRASH );
+ ask = config.readBoolEntry( keyName, defaultValue );
+ }
+ if ( ask )
+ {
+ KURL::List::ConstIterator it = selectedURLs.begin();
+ QStringList prettyList;
+ for ( ; it != selectedURLs.end(); ++it ) {
+ if ( (*it).protocol() == "trash" ) {
+ QString path = (*it).path();
+ // HACK (#98983): remove "0-foo". Note that it works better than
+ // displaying KFileItem::name(), for files under a subdir.
+ prettyList.append( path.remove(QRegExp("^/[0-9]*-")) );
+ } else
+ prettyList.append( (*it).pathOrURL() );
+ }
+
+ int result;
+ switch(method)
+ {
+ case DEL:
+ result = KMessageBox::warningContinueCancelList( widget,
+ i18n( "Do you really want to delete this item?", "Do you really want to delete these %n items?", prettyList.count()),
+ prettyList,
+ i18n( "Delete Files" ),
+ KStdGuiItem::del(),
+ keyName, KMessageBox::Dangerous);
+ break;
+
+ case SHRED:
+ result = KMessageBox::warningContinueCancelList( widget,
+ i18n( "Do you really want to shred this item?", "Do you really want to shred these %n items?", prettyList.count()),
+ prettyList,
+ i18n( "Shred Files" ),
+ KGuiItem( i18n( "Shred" ), "editshred" ),
+ keyName, KMessageBox::Dangerous);
+ break;
+
+ case MOVE:
+ default:
+ result = KMessageBox::warningContinueCancelList( widget,
+ i18n( "Do you really want to move this item to the trash?", "Do you really want to move these %n items to the trash?", prettyList.count()),
+ prettyList,
+ i18n( "Move to Trash" ),
+ KGuiItem( i18n( "Verb", "&Trash" ), "edittrash"),
+ keyName, KMessageBox::Dangerous);
+ }
+ if (!keyName.isEmpty())
+ {
+ // Check kmessagebox setting... erase & copy to konquerorrc.
+ KConfig *config = kapp->config();
+ KConfigGroupSaver saver(config, "Notification Messages");
+ if (!config->readBoolEntry(keyName, true))
+ {
+ config->writeEntry(keyName, true);
+ config->sync();
+ KConfig konq_config("konquerorrc", false);
+ konq_config.setGroup( "Trash" );
+ konq_config.writeEntry( keyName, false );
+ }
+ }
+ return (result == KMessageBox::Continue);
+ }
+ return true;
+}
+
+void KonqOperations::doDrop( const KFileItem * destItem, const KURL & dest, QDropEvent * ev, QWidget * parent )
+{
+ kdDebug(1203) << "doDrop: dest : " << dest.url() << endl;
+ KURL::List lst;
+ QMap<QString, QString> metaData;
+ if ( KURLDrag::decode( ev, lst, metaData ) ) // Are they urls ?
+ {
+ if( lst.count() == 0 )
+ {
+ kdWarning(1203) << "Oooops, no data ...." << endl;
+ ev->accept(false);
+ return;
+ }
+ kdDebug(1203) << "KonqOperations::doDrop metaData: " << metaData.count() << " entries." << endl;
+ QMap<QString,QString>::ConstIterator mit;
+ for( mit = metaData.begin(); mit != metaData.end(); ++mit )
+ {
+ kdDebug(1203) << "metaData: key=" << mit.key() << " value=" << mit.data() << endl;
+ }
+ // Check if we dropped something on itself
+ KURL::List::Iterator it = lst.begin();
+ for ( ; it != lst.end() ; it++ )
+ {
+ kdDebug(1203) << "URL : " << (*it).url() << endl;
+ if ( dest.equals( *it, true /*ignore trailing slashes*/ ) )
+ {
+ // The event source may be the view or an item (icon)
+ // Note: ev->source() can be 0L! (in case of kdesktop) (Simon)
+ if ( !ev->source() || ev->source() != parent && ev->source()->parent() != parent )
+ KMessageBox::sorry( parent, i18n("You cannot drop a folder on to itself") );
+ kdDebug(1203) << "Dropped on itself" << endl;
+ ev->accept(false);
+ return; // do nothing instead of displaying kfm's annoying error box
+ }
+ }
+
+ // Check the state of the modifiers key at the time of the drop
+ Window root;
+ Window child;
+ int root_x, root_y, win_x, win_y;
+ uint keybstate;
+ XQueryPointer( qt_xdisplay(), qt_xrootwin(), &root, &child,
+ &root_x, &root_y, &win_x, &win_y, &keybstate );
+
+ QDropEvent::Action action = ev->action();
+ // Check for the drop of a bookmark -> we want a Link action
+ if ( ev->provides("application/x-xbel") )
+ {
+ keybstate |= ControlMask | ShiftMask;
+ action = QDropEvent::Link;
+ kdDebug(1203) << "KonqOperations::doDrop Bookmark -> emulating Link" << endl;
+ }
+
+ KonqOperations * op = new KonqOperations(parent);
+ op->setDropInfo( new DropInfo( keybstate, lst, metaData, win_x, win_y, action ) );
+
+ // Ok, now we need destItem.
+ if ( destItem )
+ {
+ op->asyncDrop( destItem ); // we have it already
+ }
+ else
+ {
+ // we need to stat to get it.
+ op->_statURL( dest, op, SLOT( asyncDrop( const KFileItem * ) ) );
+ }
+ // In both cases asyncDrop will delete op when done
+
+ ev->acceptAction();
+ }
+ else
+ {
+ //kdDebug(1203) << "Pasting to " << dest.url() << endl;
+ KonqOperations * op = new KonqOperations(parent);
+ KIO::CopyJob* job = KIO::pasteMimeSource( ev, dest,
+ i18n( "File name for dropped contents:" ),
+ parent );
+ if ( job ) // 0 if canceled by user
+ {
+ op->setOperation( job, COPY, KURL::List(), job->destURL() );
+ (void) new KonqCommandRecorder( KonqCommand::COPY, KURL::List(), dest, job );
+ }
+ ev->acceptAction();
+ }
+}
+
+void KonqOperations::asyncDrop( const KFileItem * destItem )
+{
+ assert(m_info); // setDropInfo should have been called before asyncDrop
+ m_destURL = destItem->url();
+
+ //kdDebug(1203) << "KonqOperations::asyncDrop destItem->mode=" << destItem->mode() << " url=" << m_destURL << endl;
+ // Check what the destination is
+ if ( destItem->isDir() )
+ {
+ doFileCopy();
+ return;
+ }
+ if ( !m_destURL.isLocalFile() )
+ {
+ // We dropped onto a remote URL that is not a directory!
+ // (e.g. an HTTP link in the sidebar).
+ // Can't do that, but we can't prevent it before stating the dest....
+ kdWarning(1203) << "Cannot drop onto " << m_destURL << endl;
+ delete this;
+ return;
+ }
+ if ( destItem->mimetype() == "application/x-desktop")
+ {
+ // Local .desktop file. What type ?
+ KDesktopFile desktopFile( m_destURL.path() );
+ if ( desktopFile.hasApplicationType() )
+ {
+ QString error;
+ QStringList stringList;
+ KURL::List lst = m_info->lst;
+ KURL::List::Iterator it = lst.begin();
+ for ( ; it != lst.end() ; it++ )
+ {
+ stringList.append((*it).url());
+ }
+ if ( KApplication::startServiceByDesktopPath( m_destURL.path(), stringList, &error ) > 0 )
+ KMessageBox::error( 0L, error );
+ }
+ else
+ {
+ // Device or Link -> adjust dest
+ if ( desktopFile.hasDeviceType() && desktopFile.hasKey("MountPoint") ) {
+ QString point = desktopFile.readEntry( "MountPoint" );
+ m_destURL.setPath( point );
+ QString dev = desktopFile.readDevice();
+ QString mp = KIO::findDeviceMountPoint( dev );
+ // Is the device already mounted ?
+ if ( !mp.isNull() )
+ doFileCopy();
+ else
+ {
+ bool ro = desktopFile.readBoolEntry( "ReadOnly", false );
+ QString fstype = desktopFile.readEntry( "FSType" );
+ KAutoMount* am = new KAutoMount( ro, fstype, dev, point, m_destURL.path(), false );
+ connect( am, SIGNAL( finished() ), this, SLOT( doFileCopy() ) );
+ }
+ return;
+ }
+ else if ( desktopFile.hasLinkType() && desktopFile.hasKey("URL") ) {
+ m_destURL = desktopFile.readPathEntry("URL");
+ doFileCopy();
+ return;
+ }
+ // else, well: mimetype, service, servicetype or .directory. Can't really drop anything on those.
+ }
+ }
+ else
+ {
+ // Should be a local executable
+ // (If this fails, there is a bug in KFileItem::acceptsDrops)
+ kdDebug(1203) << "KonqOperations::doDrop " << m_destURL.path() << "should be an executable" << endl;
+ Q_ASSERT ( access( QFile::encodeName(m_destURL.path()), X_OK ) == 0 );
+ KProcess proc;
+ proc << m_destURL.path() ;
+ // Launch executable for each of the files
+ KURL::List lst = m_info->lst;
+ KURL::List::Iterator it = lst.begin();
+ for ( ; it != lst.end() ; it++ )
+ proc << (*it).path(); // assume local files
+ kdDebug(1203) << "starting " << m_destURL.path() << " with " << lst.count() << " arguments" << endl;
+ proc.start( KProcess::DontCare );
+ }
+ delete this;
+}
+
+void KonqOperations::doFileCopy()
+{
+ assert(m_info); // setDropInfo - and asyncDrop - should have been called before asyncDrop
+ KURL::List lst = m_info->lst;
+ QDropEvent::Action action = m_info->action;
+ bool isDesktopFile = false;
+ bool itemIsOnDesktop = false;
+ bool allItemsAreFromTrash = true;
+ KURL::List mlst; // list of items that can be moved
+ for (KURL::List::ConstIterator it = lst.begin(); it != lst.end(); ++it)
+ {
+ bool local = (*it).isLocalFile();
+ if ( KProtocolInfo::supportsDeleting( *it ) && (!local || QFileInfo((*it).directory()).isWritable() ))
+ mlst.append(*it);
+ if ( local && KDesktopFile::isDesktopFile((*it).path()))
+ isDesktopFile = true;
+ if ( local && (*it).path().startsWith(KGlobalSettings::desktopPath()))
+ itemIsOnDesktop = true;
+ if ( local || (*it).protocol() != "trash" )
+ allItemsAreFromTrash = false;
+ }
+
+ bool linkOnly = false;
+ if (isDesktopFile && !kapp->authorize("run_desktop_files") &&
+ (m_destURL.path(1) == KGlobalSettings::desktopPath()) )
+ {
+ linkOnly = true;
+ }
+
+ if ( !mlst.isEmpty() && m_destURL.protocol() == "trash" )
+ {
+ if ( itemIsOnDesktop && !kapp->authorize("editable_desktop_icons") )
+ {
+ delete this;
+ return;
+ }
+
+ m_method = TRASH;
+ if ( askDeleteConfirmation( mlst, TRASH, DEFAULT_CONFIRMATION, parentWidget() ) )
+ action = QDropEvent::Move;
+ else
+ {
+ delete this;
+ return;
+ }
+ }
+ else if ( allItemsAreFromTrash || m_destURL.protocol() == "trash" ) {
+ // No point in asking copy/move/link when using dnd from or to the trash.
+ action = QDropEvent::Move;
+ }
+ else if ( (((m_info->keybstate & ControlMask) == 0) && ((m_info->keybstate & ShiftMask) == 0)) ||
+ linkOnly )
+ {
+ // Neither control nor shift are pressed => show popup menu
+ KonqIconViewWidget *iconView = dynamic_cast<KonqIconViewWidget*>(parent());
+ bool bSetWallpaper = false;
+ if ( iconView && iconView->maySetWallpaper() && lst.count() == 1 )
+ {
+ KURL url = lst.first();
+ KMimeType::Ptr mime = KMimeType::findByURL( url );
+ if ( ( !KImageIO::type(url.path()).isEmpty() ) ||
+ ( KImageIO::isSupported(mime->name(), KImageIO::Reading) ) ||
+ mime->is( "image/svg+xml" ) )
+ {
+ bSetWallpaper = true;
+ }
+ }
+
+ // Check what the source can do
+ KURL url = lst.first(); // we'll assume it's the same for all URLs (hack)
+ bool sReading = KProtocolInfo::supportsReading( url );
+ bool sDeleting = KProtocolInfo::supportsDeleting( url );
+ bool sMoving = KProtocolInfo::supportsMoving( url );
+ // Check what the destination can do
+ bool dWriting = KProtocolInfo::supportsWriting( m_destURL );
+ if ( !dWriting )
+ {
+ delete this;
+ return;
+ }
+
+ QPopupMenu popup;
+ if (!mlst.isEmpty() && (sMoving || (sReading && sDeleting)) && !linkOnly )
+ popup.insertItem(SmallIconSet("goto"), i18n( "&Move Here" ) + "\t" + KKey::modFlagLabel( KKey::SHIFT ), 2 );
+ if ( sReading && !linkOnly)
+ popup.insertItem(SmallIconSet("editcopy"), i18n( "&Copy Here" ) + "\t" + KKey::modFlagLabel( KKey::CTRL ), 1 );
+ popup.insertItem(SmallIconSet("www"), i18n( "&Link Here" ) + "\t" + KKey::modFlagLabel( (KKey::ModFlag)( KKey::CTRL|KKey::SHIFT ) ), 3 );
+ if (bSetWallpaper)
+ popup.insertItem(SmallIconSet("background"), i18n( "Set as &Wallpaper" ), 4 );
+ popup.insertSeparator();
+ popup.insertItem(SmallIconSet("cancel"), i18n( "C&ancel" ) + "\t" + KKey( Qt::Key_Escape ).toString(), 5);
+
+ int result = popup.exec( m_info->mousePos );
+
+ switch (result) {
+ case 1 : action = QDropEvent::Copy; break;
+ case 2 : action = QDropEvent::Move; break;
+ case 3 : action = QDropEvent::Link; break;
+ case 4 :
+ {
+ kdDebug(1203) << "setWallpaper iconView=" << iconView << " url=" << lst.first().url() << endl;
+ if (iconView && iconView->isDesktop() ) iconView->setWallpaper(lst.first());
+ delete this;
+ return;
+ }
+ case 5 :
+ default : delete this; return;
+ }
+ }
+
+ KIO::Job * job = 0;
+ switch ( action ) {
+ case QDropEvent::Move :
+ job = KIO::move( lst, m_destURL );
+ job->setMetaData( m_info->metaData );
+ setOperation( job, m_method == TRASH ? TRASH : MOVE, lst, m_destURL );
+ (void) new KonqCommandRecorder(
+ m_method == TRASH ? KonqCommand::TRASH : KonqCommand::MOVE,
+ lst, m_destURL, job );
+ return; // we still have stuff to do -> don't delete ourselves
+ case QDropEvent::Copy :
+ job = KIO::copy( lst, m_destURL );
+ job->setMetaData( m_info->metaData );
+ setOperation( job, COPY, lst, m_destURL );
+ (void) new KonqCommandRecorder( KonqCommand::COPY, lst, m_destURL, job );
+ return;
+ case QDropEvent::Link :
+ kdDebug(1203) << "KonqOperations::asyncDrop lst.count=" << lst.count() << endl;
+ job = KIO::link( lst, m_destURL );
+ job->setMetaData( m_info->metaData );
+ setOperation( job, LINK, lst, m_destURL );
+ (void) new KonqCommandRecorder( KonqCommand::LINK, lst, m_destURL, job );
+ return;
+ default : kdError(1203) << "Unknown action " << (int)action << endl;
+ }
+ delete this;
+}
+
+void KonqOperations::rename( QWidget * parent, const KURL & oldurl, const KURL& newurl )
+{
+ kdDebug(1203) << "KonqOperations::rename oldurl=" << oldurl << " newurl=" << newurl << endl;
+ if ( oldurl == newurl )
+ return;
+
+ KURL::List lst;
+ lst.append(oldurl);
+ KIO::Job * job = KIO::moveAs( oldurl, newurl, !oldurl.isLocalFile() );
+ KonqOperations * op = new KonqOperations( parent );
+ op->setOperation( job, MOVE, lst, newurl );
+ (void) new KonqCommandRecorder( KonqCommand::MOVE, lst, newurl, job );
+ // if moving the desktop then update config file and emit
+ if ( oldurl.isLocalFile() && oldurl.path(1) == KGlobalSettings::desktopPath() )
+ {
+ kdDebug(1203) << "That rename was the Desktop path, updating config files" << endl;
+ KConfig *globalConfig = KGlobal::config();
+ KConfigGroupSaver cgs( globalConfig, "Paths" );
+ globalConfig->writePathEntry("Desktop" , newurl.path(), true, true );
+ globalConfig->sync();
+ KIPC::sendMessageAll(KIPC::SettingsChanged, KApplication::SETTINGS_PATHS);
+ }
+}
+
+void KonqOperations::setOperation( KIO::Job * job, int method, const KURL::List & /*src*/, const KURL & dest )
+{
+ m_method = method;
+ //m_srcURLs = src;
+ m_destURL = dest;
+ if ( job )
+ {
+ connect( job, SIGNAL( result( KIO::Job * ) ),
+ SLOT( slotResult( KIO::Job * ) ) );
+ KIO::CopyJob *copyJob = dynamic_cast<KIO::CopyJob*>(job);
+ KonqIconViewWidget *iconView = dynamic_cast<KonqIconViewWidget*>(parent());
+ if (copyJob && iconView)
+ {
+ connect(copyJob, SIGNAL(aboutToCreate(KIO::Job *,const QValueList<KIO::CopyInfo> &)),
+ this, SLOT(slotAboutToCreate(KIO::Job *,const QValueList<KIO::CopyInfo> &)));
+ connect(this, SIGNAL(aboutToCreate(const QPoint &, const QValueList<KIO::CopyInfo> &)),
+ iconView, SLOT(slotAboutToCreate(const QPoint &, const QValueList<KIO::CopyInfo> &)));
+ }
+ }
+ else // for link
+ slotResult( 0L );
+}
+
+void KonqOperations::slotAboutToCreate(KIO::Job *, const QValueList<KIO::CopyInfo> &files)
+{
+ emit aboutToCreate( m_info ? m_info->mousePos : m_pasteInfo ? m_pasteInfo->mousePos : QPoint(), files);
+}
+
+void KonqOperations::statURL( const KURL & url, const QObject *receiver, const char *member )
+{
+ KonqOperations * op = new KonqOperations( 0L );
+ op->_statURL( url, receiver, member );
+ op->m_method = STAT;
+}
+
+void KonqOperations::_statURL( const KURL & url, const QObject *receiver, const char *member )
+{
+ connect( this, SIGNAL( statFinished( const KFileItem * ) ), receiver, member );
+ KIO::StatJob * job = KIO::stat( url /*, false?*/ );
+ connect( job, SIGNAL( result( KIO::Job * ) ),
+ SLOT( slotStatResult( KIO::Job * ) ) );
+}
+
+void KonqOperations::slotStatResult( KIO::Job * job )
+{
+ if ( job->error())
+ job->showErrorDialog( (QWidget*)parent() );
+ else
+ {
+ KIO::StatJob * statJob = static_cast<KIO::StatJob*>(job);
+ KFileItem * item = new KFileItem( statJob->statResult(), statJob->url() );
+ emit statFinished( item );
+ delete item;
+ }
+ // If we're only here for a stat, we're done. But not if we used _statURL internally
+ if ( m_method == STAT )
+ delete this;
+}
+
+void KonqOperations::slotResult( KIO::Job * job )
+{
+ if (job && job->error())
+ job->showErrorDialog( (QWidget*)parent() );
+ if ( m_method == EMPTYTRASH ) {
+ // Update konq windows opened on trash:/
+ KDirNotify_stub allDirNotify("*", "KDirNotify*");
+ allDirNotify.FilesAdded( "trash:/" ); // yeah, files were removed, but we don't know which ones...
+ }
+ delete this;
+}
+
+void KonqOperations::rename( QWidget * parent, const KURL & oldurl, const QString & name )
+{
+ KURL newurl( oldurl );
+ newurl.setPath( oldurl.directory(false, true) + name );
+ kdDebug(1203) << "KonqOperations::rename("<<name<<") called. newurl=" << newurl << endl;
+ rename( parent, oldurl, newurl );
+}
+
+void KonqOperations::newDir( QWidget * parent, const KURL & baseURL )
+{
+ bool ok;
+ QString name = i18n( "New Folder" );
+ if ( baseURL.isLocalFile() && QFileInfo( baseURL.path(+1) + name ).exists() )
+ name = KIO::RenameDlg::suggestName( baseURL, i18n( "New Folder" ) );
+
+ name = KInputDialog::getText ( i18n( "New Folder" ),
+ i18n( "Enter folder name:" ), name, &ok, parent );
+ if ( ok && !name.isEmpty() )
+ {
+ KURL url;
+ if ((name[0] == '/') || (name[0] == '~'))
+ {
+ url.setPath(KShell::tildeExpand(name));
+ }
+ else
+ {
+ name = KIO::encodeFileName( name );
+ url = baseURL;
+ url.addPath( name );
+ }
+ KonqOperations::mkdir( 0L, url );
+ }
+}
+
+////
+
+KonqMultiRestoreJob::KonqMultiRestoreJob( const KURL::List& urls, bool showProgressInfo )
+ : KIO::Job( showProgressInfo ),
+ m_urls( urls ), m_urlsIterator( m_urls.begin() ),
+ m_progress( 0 )
+{
+ QTimer::singleShot(0, this, SLOT(slotStart()));
+}
+
+void KonqMultiRestoreJob::slotStart()
+{
+ // Well, it's not a total in bytes, so this would look weird
+ //if ( m_urlsIterator == m_urls.begin() ) // first time: emit total
+ // emit totalSize( m_urls.count() );
+
+ if ( m_urlsIterator != m_urls.end() )
+ {
+ const KURL& url = *m_urlsIterator;
+
+ KURL new_url = url;
+ if ( new_url.protocol()=="system"
+ && new_url.path().startsWith("/trash") )
+ {
+ QString path = new_url.path();
+ path.remove(0, 6);
+ new_url.setProtocol("trash");
+ new_url.setPath(path);
+ }
+
+ Q_ASSERT( new_url.protocol() == "trash" );
+ QByteArray packedArgs;
+ QDataStream stream( packedArgs, IO_WriteOnly );
+ stream << (int)3 << new_url;
+ KIO::Job* job = KIO::special( new_url, packedArgs );
+ addSubjob( job );
+ }
+ else // done!
+ {
+ KDirNotify_stub allDirNotify("*", "KDirNotify*");
+ allDirNotify.FilesRemoved( m_urls );
+ emitResult();
+ }
+}
+
+void KonqMultiRestoreJob::slotResult( KIO::Job *job )
+{
+ if ( job->error() )
+ {
+ KIO::Job::slotResult( job ); // will set the error and emit result(this)
+ return;
+ }
+ subjobs.remove( job );
+ // Move on to next one
+ ++m_urlsIterator;
+ ++m_progress;
+ //emit processedSize( this, m_progress );
+ emitPercent( m_progress, m_urls.count() );
+ slotStart();
+}
+
+QWidget* KonqOperations::parentWidget() const
+{
+ return static_cast<QWidget *>( parent() );
+}
+
+#include "konq_operations.moc"
diff --git a/libkonq/konq_operations.h b/libkonq/konq_operations.h
new file mode 100644
index 000000000..82d021c55
--- /dev/null
+++ b/libkonq/konq_operations.h
@@ -0,0 +1,215 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000 David Faure <faure@kde.org>
+
+ 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 __konq_operations_h__
+#define __konq_operations_h__
+
+#include <kurl.h>
+#include <libkonq_export.h>
+
+#include <qobject.h>
+#include <qevent.h>
+
+namespace KIO { class Job; class CopyInfo; }
+class QWidget;
+class KFileItem;
+class KonqMainWindow;
+
+/**
+ * Implements file operations (move,del,trash,shred,paste,copy,move,link...)
+ * for konqueror and kdesktop whatever the view mode is (icon, tree, ...)
+ */
+class LIBKONQ_EXPORT KonqOperations : public QObject
+{
+ Q_OBJECT
+protected:
+ KonqOperations( QWidget * parent );
+ virtual ~KonqOperations();
+
+public:
+ /**
+ * Pop up properties dialog for mimetype @p mimeType.
+ */
+ static void editMimeType( const QString & mimeType );
+
+ enum { TRASH, DEL, SHRED, COPY, MOVE, LINK, EMPTYTRASH, STAT, MKDIR, RESTORE, UNKNOWN };
+ /**
+ * Delete the @p selectedURLs if possible.
+ *
+ * @param parent parent widget (for error dialog box if any)
+ * @param method should be TRASH, DEL or SHRED
+ * @param selectedURLs the URLs to be deleted
+ */
+ static void del( QWidget * parent, int method, const KURL::List & selectedURLs );
+
+ /**
+ * Copy the @p selectedURLs to the destination @p destURL.
+ *
+ * @param parent parent widget (for error dialog box if any)
+ * @param method should be COPY, MOVE or LINK
+ * @param selectedURLs the URLs to copy
+ * @param destURL destination of the copy
+ *
+ * @todo document restrictions on the kind of destination
+ */
+ static void copy( QWidget * parent, int method, const KURL::List & selectedURLs, const KURL& destURL );
+ /**
+ * Drop
+ * @param destItem destination KFileItem for the drop (background or item)
+ * @param destURL destination URL for the drop.
+ * @param ev the drop event
+ * @param parent parent widget (for error dialog box if any)
+ *
+ * If destItem is 0L, doDrop will stat the URL to determine it.
+ */
+ static void doDrop( const KFileItem * destItem, const KURL & destURL, QDropEvent * ev, QWidget * parent );
+
+ /**
+ * Paste the clipboard contents
+ */
+ static void doPaste( QWidget * parent, const KURL & destURL, const QPoint &pos );
+ static void doPaste( QWidget * parent, const KURL & destURL );
+
+ static void emptyTrash();
+ static void restoreTrashedItems( const KURL::List& urls );
+
+ /**
+ * Create a directory
+ */
+ static void mkdir( QWidget *parent, const KURL & url );
+
+ /**
+ * Get info about a given URL, and when that's done (it's asynchronous!),
+ * call a given slot with the KFileItem * as argument.
+ * The KFileItem will be deleted by statURL after calling the slot. Make a copy
+ * if you need one !
+ */
+ static void statURL( const KURL & url, const QObject *receiver, const char *member );
+
+ /**
+ * Do a renaming.
+ * @param parent the parent widget, passed to KonqOperations ctor
+ * @param oldurl the current url of the file to be renamed
+ * @param name the new name for the file. Shouldn't include '/'.
+ */
+ static void rename( QWidget * parent, const KURL & oldurl, const QString & name );
+
+ /**
+ * Do a renaming.
+ * @param parent the parent widget, passed to KonqOperations ctor
+ * @param oldurl the current url of the file to be renamed
+ * @param newurl the new url for the file
+ * Use this version if the other one wouldn't work :) (e.g. because name could
+ * be a relative path, including a '/').
+ */
+ static void rename( QWidget * parent, const KURL & oldurl, const KURL & newurl );
+
+ /**
+ * Ask for the name of a new directory and create it.
+ * @param parent the parent widget
+ * @param baseURL the directory to create the new directory in
+ */
+ static void newDir( QWidget * parent, const KURL & baseURL );
+
+ enum ConfirmationType { DEFAULT_CONFIRMATION, SKIP_CONFIRMATION, FORCE_CONFIRMATION };
+ /**
+ * Ask for confirmation before deleting/trashing @p selectedURLs.
+ * @param selectedURLs the urls about to be deleted
+ * @param method the type of deletion (DEL for real deletion, anything else for trash)
+ * @param confirmation default (based on config file), skip (no confirmation) or force (always confirm)
+ * @param widget parent widget for message boxes
+ * @return true if confirmed
+ */
+ static bool askDeleteConfirmation( const KURL::List & selectedURLs, int method, ConfirmationType confirmation, QWidget* widget );
+
+signals:
+ void statFinished( const KFileItem * item );
+ void aboutToCreate(const QPoint &pos, const QValueList<KIO::CopyInfo> &files);
+
+protected:
+ void _del( int method, const KURL::List & selectedURLs, ConfirmationType confirmation );
+ void _restoreTrashedItems( const KURL::List& urls );
+ void _statURL( const KURL & url, const QObject *receiver, const char *member );
+
+ // internal, for COPY/MOVE/LINK/MKDIR
+ void setOperation( KIO::Job * job, int method, const KURL::List & src, const KURL & dest );
+
+ struct DropInfo
+ {
+ DropInfo( uint k, KURL::List & l, const QMap<QString,QString> &m,
+ int x, int y, QDropEvent::Action a ) :
+ keybstate(k), lst(l), metaData(m), mousePos(x,y), action(a) {}
+ uint keybstate;
+ KURL::List lst;
+ QMap<QString,QString> metaData;
+ QPoint mousePos;
+ QDropEvent::Action action;
+ };
+ // internal, for doDrop
+ void setDropInfo( DropInfo * info ) { m_info = info; }
+
+ struct KIOPasteInfo // KDE4: remove and use DropInfo instead or a QPoint member
+ {
+ QByteArray data; // unused
+ KURL destURL; // unused
+ QPoint mousePos;
+ QString dialogText; // unused
+ };
+ void setPasteInfo( KIOPasteInfo * info ) { m_pasteInfo = info; }
+
+private:
+ QWidget* parentWidget() const;
+
+protected slots:
+
+ void slotAboutToCreate(KIO::Job *job, const QValueList<KIO::CopyInfo> &files);
+ void slotResult( KIO::Job * job );
+ void slotStatResult( KIO::Job * job );
+ void asyncDrop( const KFileItem * item );
+ void doFileCopy();
+
+private:
+ int m_method;
+ //KURL::List m_srcURLs;
+ KURL m_destURL;
+ // for doDrop
+ DropInfo * m_info;
+ KIOPasteInfo * m_pasteInfo;
+};
+
+#include <kio/job.h>
+
+/// Restore multiple trashed files
+class KonqMultiRestoreJob : public KIO::Job
+{
+ Q_OBJECT
+
+public:
+ KonqMultiRestoreJob( const KURL::List& urls, bool showProgressInfo );
+
+protected slots:
+ virtual void slotStart();
+ virtual void slotResult( KIO::Job *job );
+
+private:
+ const KURL::List m_urls;
+ KURL::List::const_iterator m_urlsIterator;
+ int m_progress;
+};
+
+#endif
diff --git a/libkonq/konq_pixmapprovider.cc b/libkonq/konq_pixmapprovider.cc
new file mode 100644
index 000000000..a666aa6cf
--- /dev/null
+++ b/libkonq/konq_pixmapprovider.cc
@@ -0,0 +1,201 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qbitmap.h>
+
+#include <kapplication.h>
+#include <kiconloader.h>
+#include <kmimetype.h>
+#include <kshell.h>
+#include <kprotocolinfo.h>
+
+#include "konq_pixmapprovider.h"
+
+KonqPixmapProvider * KonqPixmapProvider::s_self = 0L;
+
+KonqPixmapProvider * KonqPixmapProvider::self()
+{
+ if ( !s_self )
+ s_self = new KonqPixmapProvider( kapp, "KonqPixmapProvider" );
+
+ return s_self;
+}
+
+KonqPixmapProvider::KonqPixmapProvider( QObject *parent, const char *name )
+ : KPixmapProvider(),
+ KonqFavIconMgr( parent, name )
+{
+}
+
+KonqPixmapProvider::~KonqPixmapProvider()
+{
+ s_self = 0L;
+}
+
+// at first, tries to find the iconname in the cache
+// if not available, tries to find the pixmap for the mimetype of url
+// if that fails, gets the icon for the protocol
+// finally, inserts the url/icon pair into the cache
+QString KonqPixmapProvider::iconNameFor( const QString& url )
+{
+ QMapIterator<QString,QString> it = iconMap.find( url );
+ QString icon;
+ if ( it != iconMap.end() ) {
+ icon = it.data();
+ if ( !icon.isEmpty() )
+ return icon;
+ }
+
+ if ( url.isEmpty() ) {
+ // Use the folder icon for the empty URL
+ icon = KMimeType::mimeType( "inode/directory" )->KServiceType::icon();
+ Q_ASSERT( !icon.isEmpty() );
+ }
+ else
+ {
+ KURL u;
+ if ( url.at(0) == '~' )
+ u.setPath( KShell::tildeExpand( url ) );
+ else if ( url.at(0) == '/' )
+ u.setPath( url );
+ else
+ u = url;
+
+ icon = KMimeType::iconForURL( u );
+ //Q_ASSERT( !icon.isEmpty() );
+ }
+
+
+ // cache the icon found for url
+ iconMap.insert( url, icon );
+
+ return icon;
+}
+
+QPixmap KonqPixmapProvider::pixmapFor( const QString& url, int size )
+{
+ return loadIcon( url, iconNameFor( url ), size );
+}
+
+void KonqPixmapProvider::load( KConfig *kc, const QString& key )
+{
+ iconMap.clear();
+ QStringList list;
+ list = kc->readPathListEntry( key );
+ QStringList::Iterator it = list.begin();
+ QString url, icon;
+ while ( it != list.end() ) {
+ url = (*it);
+ if ( ++it == list.end() )
+ break;
+ icon = (*it);
+ iconMap.insert( url, icon );
+
+ ++it;
+ }
+}
+
+// only saves the cache for the given list of items to prevent the cache
+// from growing forever.
+void KonqPixmapProvider::save( KConfig *kc, const QString& key,
+ const QStringList& items )
+{
+ QStringList list;
+ QStringList::ConstIterator it = items.begin();
+ QMapConstIterator<QString,QString> mit;
+ while ( it != items.end() ) {
+ mit = iconMap.find( *it );
+ if ( mit != iconMap.end() ) {
+ list.append( mit.key() );
+ list.append( mit.data() );
+ }
+
+ ++it;
+ }
+ kc->writePathEntry( key, list );
+}
+
+void KonqPixmapProvider::notifyChange( bool isHost, QString hostOrURL,
+ QString iconName )
+{
+ for ( QMapIterator<QString,QString> it = iconMap.begin();
+ it != iconMap.end();
+ ++it )
+ {
+ KURL url( it.key() );
+ if ( url.protocol().startsWith("http") &&
+ ( ( isHost && url.host() == hostOrURL ) ||
+ ( url.host() + url.path() == hostOrURL ) ) )
+ {
+ // For host default-icons still query the favicon manager to get
+ // the correct icon for pages that have an own one.
+ QString icon = isHost ? KMimeType::favIconForURL( url ) : iconName;
+ if ( !icon.isEmpty() )
+ *it = icon;
+ }
+ }
+
+ emit changed();
+}
+
+void KonqPixmapProvider::clear()
+{
+ iconMap.clear();
+}
+
+QPixmap KonqPixmapProvider::loadIcon( const QString& url, const QString& icon,
+ int size )
+{
+ if ( size <= KIcon::SizeSmall )
+ return SmallIcon( icon, size );
+
+ KURL u;
+ if ( url.at(0) == '/' )
+ u.setPath( url );
+ else
+ u = url;
+
+ QPixmap big;
+
+ // favicon? => blend the favicon in the large
+ if ( url.startsWith( "http:/" ) && icon.startsWith("favicons/") ) {
+ QPixmap small = SmallIcon( icon, size );
+ big = KGlobal::iconLoader()->loadIcon( KProtocolInfo::icon("http"),
+ KIcon::Panel, size );
+
+ int x = big.width() - small.width();
+ int y = 0;
+
+ if ( big.mask() ) {
+ QBitmap mask = *big.mask();
+ bitBlt( &mask, x, y,
+ small.mask() ? const_cast<QBitmap *>(small.mask()) : &small, 0, 0,
+ small.width(), small.height(),
+ small.mask() ? OrROP : SetROP );
+ big.setMask( mask );
+ }
+
+ bitBlt( &big, x, y, &small );
+ }
+
+ else // not a favicon..
+ big = KGlobal::iconLoader()->loadIcon( icon, KIcon::Panel, size );
+
+ return big;
+}
diff --git a/libkonq/konq_pixmapprovider.h b/libkonq/konq_pixmapprovider.h
new file mode 100644
index 000000000..b313652f3
--- /dev/null
+++ b/libkonq/konq_pixmapprovider.h
@@ -0,0 +1,81 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KONQ_PIXMAPPROVIDER_H
+#define KONQ_PIXMAPPROVIDER_H
+
+#include <qmap.h>
+
+#include <kpixmapprovider.h>
+#include "konq_faviconmgr.h"
+
+#include <libkonq_export.h>
+
+class KConfig;
+
+class LIBKONQ_EXPORT KonqPixmapProvider : public KonqFavIconMgr, virtual public KPixmapProvider
+{
+public:
+ static KonqPixmapProvider * self();
+
+ virtual ~KonqPixmapProvider();
+
+ /**
+ * Looks up a pixmap for @p url. Uses a cache for the iconname of url.
+ */
+ virtual QPixmap pixmapFor( const QString& url, int size = 0 );
+
+ /**
+ * Loads the cache to @p kc from the current KConfig-group from key @p key.
+ */
+ void load( KConfig * kc, const QString& key );
+ /**
+ * Saves the cache to @p kc into the current KConfig-group as key @p key.
+ * Only those @p items are saved, otherwise the cache would grow forever.
+ */
+ void save( KConfig *, const QString& key, const QStringList& items );
+
+ /**
+ * Clears the pixmap cache
+ */
+ void clear();
+
+ /**
+ * Looks up an iconname for @p url. Uses a cache for the iconname of url.
+ * @since 3.4.1
+ */
+ QString iconNameFor( const QString& url );
+
+protected:
+ KonqPixmapProvider( QObject *parent=0, const char *name=0 );
+
+ /**
+ * Overridden from KonqFavIconMgr to update the cache
+ */
+ virtual void notifyChange( bool isHost, QString hostOrURL, QString iconName );
+
+ QPixmap loadIcon( const QString& url, const QString& icon, int size );
+
+private:
+ QMap<QString,QString> iconMap;
+ static KonqPixmapProvider * s_self;
+};
+
+
+#endif // KONQ_PIXMAPPROVIDER_H
diff --git a/libkonq/konq_popupmenu.cc b/libkonq/konq_popupmenu.cc
new file mode 100644
index 000000000..9238122c0
--- /dev/null
+++ b/libkonq/konq_popupmenu.cc
@@ -0,0 +1,1205 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 David Faure <faure@kde.org>
+ Copyright (C) 2001 Holger Freyther <freyther@yahoo.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qdir.h>
+
+#include <klocale.h>
+#include <kapplication.h>
+#include <kbookmarkmanager.h>
+#include <kdebug.h>
+#include <krun.h>
+#include <kprotocolinfo.h>
+#include <kiconloader.h>
+#include <kinputdialog.h>
+#include <kglobalsettings.h>
+#include <kstandarddirs.h>
+#include <kxmlguifactory.h>
+#include <kxmlguibuilder.h>
+#include <kparts/componentfactory.h>
+
+#include <assert.h>
+
+#include <kfileshare.h>
+#include <kprocess.h>
+
+#include "kpropertiesdialog.h"
+#include "knewmenu.h"
+#include "konq_popupmenu.h"
+#include "konq_operations.h"
+#include <dcopclient.h>
+
+/*
+ Test cases:
+ iconview file: background
+ iconview file: file (with and without servicemenus)
+ iconview file: directory
+ iconview remote protocol (e.g. ftp: or fish:)
+ iconview trash:/
+ sidebar directory tree
+ sidebar Devices / Hard Disc
+ khtml background
+ khtml link
+ khtml image (www.kde.org RMB on K logo)
+ khtmlimage (same as above, then choose View image, then RMB)
+ selected text in khtml
+ embedded katepart
+ kdesktop folder
+ trash link on desktop
+ trashed file or directory
+ application .desktop file
+ Then the same after uninstalling kdeaddons/konq-plugins (kuick and arkplugin in particular)
+*/
+
+class KonqPopupMenuGUIBuilder : public KXMLGUIBuilder
+{
+public:
+ KonqPopupMenuGUIBuilder( QPopupMenu *menu )
+ : KXMLGUIBuilder( 0 )
+ {
+ m_menu = menu;
+ }
+ virtual ~KonqPopupMenuGUIBuilder()
+ {
+ }
+
+ virtual QWidget *createContainer( QWidget *parent, int index,
+ const QDomElement &element,
+ int &id )
+ {
+ if ( !parent && element.attribute( "name" ) == "popupmenu" )
+ return m_menu;
+
+ return KXMLGUIBuilder::createContainer( parent, index, element, id );
+ }
+
+ QPopupMenu *m_menu;
+};
+
+class KonqPopupMenu::KonqPopupMenuPrivate
+{
+public:
+ KonqPopupMenuPrivate() : m_parentWidget( 0 ),
+ m_itemFlags( KParts::BrowserExtension::DefaultPopupItems )
+ {
+ }
+ QString m_urlTitle;
+ QWidget *m_parentWidget;
+ KParts::BrowserExtension::PopupFlags m_itemFlags;
+};
+
+KonqPopupMenu::ProtocolInfo::ProtocolInfo()
+{
+ m_Reading = false;
+ m_Writing = false;
+ m_Deleting = false;
+ m_Moving = false;
+ m_TrashIncluded = false;
+}
+
+bool KonqPopupMenu::ProtocolInfo::supportsReading() const
+{
+ return m_Reading;
+}
+
+bool KonqPopupMenu::ProtocolInfo::supportsWriting() const
+{
+ return m_Writing;
+}
+
+bool KonqPopupMenu::ProtocolInfo::supportsDeleting() const
+{
+ return m_Deleting;
+}
+
+bool KonqPopupMenu::ProtocolInfo::supportsMoving() const
+{
+ return m_Moving;
+}
+
+bool KonqPopupMenu::ProtocolInfo::trashIncluded() const
+{
+ return m_TrashIncluded;
+}
+
+// This helper class stores the .desktop-file actions and the servicemenus
+// in order to support X-KDE-Priority and X-KDE-Submenu.
+class PopupServices
+{
+public:
+ ServiceList* selectList( const QString& priority, const QString& submenuName );
+
+ ServiceList builtin;
+ ServiceList user, userToplevel, userPriority;
+ QMap<QString, ServiceList> userSubmenus, userToplevelSubmenus, userPrioritySubmenus;
+};
+
+ServiceList* PopupServices::selectList( const QString& priority, const QString& submenuName )
+{
+ // we use the categories .desktop entry to define submenus
+ // if none is defined, we just pop it in the main menu
+ if (submenuName.isEmpty())
+ {
+ if (priority == "TopLevel")
+ {
+ return &userToplevel;
+ }
+ else if (priority == "Important")
+ {
+ return &userPriority;
+ }
+ }
+ else if (priority == "TopLevel")
+ {
+ return &(userToplevelSubmenus[submenuName]);
+ }
+ else if (priority == "Important")
+ {
+ return &(userPrioritySubmenus[submenuName]);
+ }
+ else
+ {
+ return &(userSubmenus[submenuName]);
+ }
+ return &user;
+}
+
+//////////////////
+
+KonqPopupMenu::KonqPopupMenu( KBookmarkManager *mgr, const KFileItemList &items,
+ KURL viewURL,
+ KActionCollection & actions,
+ KNewMenu * newMenu,
+ bool showProperties )
+ : QPopupMenu( 0L, "konq_popupmenu" ),
+ m_actions( actions ), m_ownActions( static_cast<QWidget *>( 0 ), "KonqPopupMenu::m_ownActions" ),
+ m_pMenuNew( newMenu ), m_sViewURL(viewURL), m_lstItems(items), m_pManager(mgr)
+{
+ KonqPopupFlags kpf = ( showProperties ? ShowProperties : IsLink ) | ShowNewWindow;
+ init(0, kpf, KParts::BrowserExtension::DefaultPopupItems);
+}
+
+KonqPopupMenu::KonqPopupMenu( KBookmarkManager *mgr, const KFileItemList &items,
+ KURL viewURL,
+ KActionCollection & actions,
+ KNewMenu * newMenu,
+ QWidget * parentWidget,
+ bool showProperties )
+ : QPopupMenu( parentWidget, "konq_popupmenu" ), m_actions( actions ), m_ownActions( static_cast<QWidget *>( 0 ), "KonqPopupMenu::m_ownActions" ), m_pMenuNew( newMenu ), m_sViewURL(viewURL), m_lstItems(items), m_pManager(mgr)
+{
+ KonqPopupFlags kpf = ( showProperties ? ShowProperties : IsLink ) | ShowNewWindow;
+ init(parentWidget, kpf, KParts::BrowserExtension::DefaultPopupItems);
+}
+
+KonqPopupMenu::KonqPopupMenu( KBookmarkManager *mgr, const KFileItemList &items,
+ const KURL& viewURL,
+ KActionCollection & actions,
+ KNewMenu * newMenu,
+ QWidget * parentWidget,
+ KonqPopupFlags kpf,
+ KParts::BrowserExtension::PopupFlags flags)
+ : QPopupMenu( parentWidget, "konq_popupmenu" ), m_actions( actions ), m_ownActions( static_cast<QWidget *>( 0 ), "KonqPopupMenu::m_ownActions" ), m_pMenuNew( newMenu ), m_sViewURL(viewURL), m_lstItems(items), m_pManager(mgr)
+{
+ init(parentWidget, kpf, flags);
+}
+
+void KonqPopupMenu::init (QWidget * parentWidget, KonqPopupFlags kpf, KParts::BrowserExtension::PopupFlags flags)
+{
+ d = new KonqPopupMenuPrivate;
+ d->m_parentWidget = parentWidget;
+ d->m_itemFlags = flags;
+ setup(kpf);
+}
+
+int KonqPopupMenu::insertServicesSubmenus(const QMap<QString, ServiceList>& submenus,
+ QDomElement& menu,
+ bool isBuiltin)
+{
+ int count = 0;
+ QMap<QString, ServiceList>::ConstIterator it;
+
+ for (it = submenus.begin(); it != submenus.end(); ++it)
+ {
+ if (it.data().isEmpty())
+ {
+ //avoid empty sub-menus
+ continue;
+ }
+
+ QDomElement actionSubmenu = m_doc.createElement( "menu" );
+ actionSubmenu.setAttribute( "name", "actions " + it.key() );
+ menu.appendChild( actionSubmenu );
+ QDomElement subtext = m_doc.createElement( "text" );
+ actionSubmenu.appendChild( subtext );
+ subtext.appendChild( m_doc.createTextNode( it.key() ) );
+ count += insertServices(it.data(), actionSubmenu, isBuiltin);
+ }
+
+ return count;
+}
+
+int KonqPopupMenu::insertServices(const ServiceList& list,
+ QDomElement& menu,
+ bool isBuiltin)
+{
+ static int id = 1000;
+ int count = 0;
+
+ ServiceList::const_iterator it = list.begin();
+ for( ; it != list.end(); ++it )
+ {
+ if ((*it).isEmpty())
+ {
+ if (!menu.firstChild().isNull() &&
+ menu.lastChild().toElement().tagName().lower() != "separator")
+ {
+ QDomElement separator = m_doc.createElement( "separator" );
+ menu.appendChild(separator);
+ }
+ continue;
+ }
+
+ if (isBuiltin || (*it).m_display == true)
+ {
+ QCString name;
+ name.setNum( id );
+ name.prepend( isBuiltin ? "builtinservice_" : "userservice_" );
+ KAction * act = new KAction( QString((*it).m_strName).replace('&',"&&"), 0,
+ this, SLOT( slotRunService() ),
+ &m_ownActions, name );
+
+ if ( !(*it).m_strIcon.isEmpty() )
+ {
+ QPixmap pix = SmallIcon( (*it).m_strIcon );
+ act->setIconSet( pix );
+ }
+
+ addAction( act, menu ); // Add to toplevel menu
+
+ m_mapPopupServices[ id++ ] = *it;
+ ++count;
+ }
+ }
+
+ return count;
+}
+
+bool KonqPopupMenu::KIOSKAuthorizedAction(KConfig& cfg)
+{
+ if ( !cfg.hasKey( "X-KDE-AuthorizeAction") )
+ {
+ return true;
+ }
+
+ QStringList list = cfg.readListEntry("X-KDE-AuthorizeAction");
+ if (kapp && !list.isEmpty())
+ {
+ for(QStringList::ConstIterator it = list.begin();
+ it != list.end();
+ ++it)
+ {
+ if (!kapp->authorize((*it).stripWhiteSpace()))
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+
+void KonqPopupMenu::setup(KonqPopupFlags kpf)
+{
+ assert( m_lstItems.count() >= 1 );
+
+ m_ownActions.setWidget( this );
+
+ const bool bIsLink = (kpf & IsLink);
+ bool currentDir = false;
+ bool sReading = true;
+ bool sDeleting = ( d->m_itemFlags & KParts::BrowserExtension::NoDeletion ) == 0;
+ bool sMoving = sDeleting;
+ bool sWriting = sDeleting && m_lstItems.first()->isWritable();
+ m_sMimeType = m_lstItems.first()->mimetype();
+ QString mimeGroup = m_sMimeType.left(m_sMimeType.find('/'));
+ mode_t mode = m_lstItems.first()->mode();
+ bool isDirectory = S_ISDIR(mode);
+ bool bTrashIncluded = false;
+ bool mediaFiles = false;
+ bool isReallyLocal = m_lstItems.first()->isLocalFile();
+ bool isLocal = isReallyLocal
+ || m_lstItems.first()->url().protocol()=="media"
+ || m_lstItems.first()->url().protocol()=="system";
+ bool isTrashLink = false;
+ m_lstPopupURLs.clear();
+ int id = 0;
+ setFont(KGlobalSettings::menuFont());
+ m_pluginList.setAutoDelete( true );
+ m_ownActions.setHighlightingEnabled( true );
+
+ attrName = QString::fromLatin1( "name" );
+
+ prepareXMLGUIStuff();
+ m_builder = new KonqPopupMenuGUIBuilder( this );
+ m_factory = new KXMLGUIFactory( m_builder );
+
+ KURL url;
+ KFileItemListIterator it ( m_lstItems );
+ QStringList mimeTypeList;
+ // Check whether all URLs are correct
+ for ( ; it.current(); ++it )
+ {
+ url = (*it)->url();
+
+ // Build the list of URLs
+ m_lstPopupURLs.append( url );
+
+ // Determine if common mode among all URLs
+ if ( mode != (*it)->mode() )
+ mode = 0; // modes are different => reset to 0
+
+ // Determine if common mimetype among all URLs
+ if ( m_sMimeType != (*it)->mimetype() )
+ {
+ m_sMimeType = QString::null; // mimetypes are different => null
+
+ if ( mimeGroup != (*it)->mimetype().left((*it)->mimetype().find('/')))
+ mimeGroup = QString::null; // mimetype groups are different as well!
+ }
+
+ if ( mimeTypeList.findIndex( (*it)->mimetype() ) == -1 )
+ mimeTypeList << (*it)->mimetype();
+
+ if ( isReallyLocal && !url.isLocalFile() )
+ isReallyLocal = false;
+ if ( isLocal && !url.isLocalFile() && url.protocol() != "media" && url.protocol() != "system" )
+ isLocal = false;
+
+ if ( !bTrashIncluded && (
+ ( url.protocol() == "trash" && url.path().length() <= 1 )
+ || url.url() == "system:/trash" || url.url() == "system:/trash/" ) ) {
+ bTrashIncluded = true;
+ isLocal = false;
+ }
+
+ if ( sReading )
+ sReading = KProtocolInfo::supportsReading( url );
+
+ if ( sWriting )
+ sWriting = KProtocolInfo::supportsWriting( url ) && (*it)->isWritable();
+
+ if ( sDeleting )
+ sDeleting = KProtocolInfo::supportsDeleting( url );
+
+ if ( sMoving )
+ sMoving = KProtocolInfo::supportsMoving( url );
+ if ( (*it)->mimetype().startsWith("media/") )
+ mediaFiles = true;
+ }
+ url = m_sViewURL;
+ url.cleanPath();
+
+ //check if url is current directory
+ if ( m_lstItems.count() == 1 )
+ {
+ KURL firstPopupURL( m_lstItems.first()->url() );
+ firstPopupURL.cleanPath();
+ //kdDebug(1203) << "View path is " << url.url() << endl;
+ //kdDebug(1203) << "First popup path is " << firstPopupURL.url() << endl;
+ currentDir = firstPopupURL.equals( url, true /* ignore_trailing */ );
+ if ( isLocal && m_sMimeType == "application/x-desktop" ) {
+ KSimpleConfig cfg( firstPopupURL.path(), true );
+ cfg.setDesktopGroup();
+ isTrashLink = ( cfg.readEntry("Type") == "Link" && cfg.readEntry("URL") == "trash:/" );
+ }
+
+ if ( isTrashLink ) {
+ sDeleting = false;
+ }
+ }
+
+ m_info.m_Reading = sReading;
+ m_info.m_Writing = sWriting;
+ m_info.m_Deleting = sDeleting;
+ m_info.m_Moving = sMoving;
+ m_info.m_TrashIncluded = bTrashIncluded;
+
+ // isCurrentTrash: popup on trash:/ itself, or on the trash.desktop link
+ bool isCurrentTrash = ( m_lstItems.count() == 1 && bTrashIncluded ) || isTrashLink;
+ bool isIntoTrash = ( url.protocol() == "trash" || url.url().startsWith( "system:/trash" ) ) && !isCurrentTrash; // trashed file, not trash:/ itself
+ //kdDebug() << "isLocal=" << isLocal << " url=" << url << " isCurrentTrash=" << isCurrentTrash << " isIntoTrash=" << isIntoTrash << " bTrashIncluded=" << bTrashIncluded << endl;
+ bool isSingleMedium = m_lstItems.count() == 1 && mediaFiles;
+ clear();
+
+ //////////////////////////////////////////////////////////////////////////
+
+ KAction * act;
+
+ if (!isCurrentTrash)
+ addMerge( "konqueror" );
+
+ bool isKDesktop = QCString( kapp->name() ) == "kdesktop";
+ KAction *actNewWindow = 0;
+
+ if (( kpf & ShowProperties ) && isKDesktop &&
+ !kapp->authorize("editable_desktop_icons"))
+ {
+ kpf &= ~ShowProperties; // remove flag
+ }
+
+ // Either 'newview' is in the actions we're given (probably in the tabhandling group)
+ // or we need to insert it ourselves (e.g. for kdesktop). In the first case, actNewWindow must remain 0.
+ if ( ((kpf & ShowNewWindow) != 0) && sReading )
+ {
+ QString openStr = isKDesktop ? i18n( "&Open" ) : i18n( "Open in New &Window" );
+ actNewWindow = new KAction( openStr, "window_new", 0, this, SLOT( slotPopupNewView() ), &m_ownActions, "newview" );
+ }
+
+ if ( actNewWindow && !isKDesktop )
+ {
+ if (isCurrentTrash)
+ actNewWindow->setToolTip( i18n( "Open the trash in a new window" ) );
+ else if (isSingleMedium)
+ actNewWindow->setToolTip( i18n( "Open the medium in a new window") );
+ else
+ actNewWindow->setToolTip( i18n( "Open the document in a new window" ) );
+ }
+
+ if ( S_ISDIR(mode) && sWriting && !isCurrentTrash ) // A dir, and we can create things into it
+ {
+ if ( currentDir && m_pMenuNew ) // Current dir -> add the "new" menu
+ {
+ // As requested by KNewMenu :
+ m_pMenuNew->slotCheckUpToDate();
+ m_pMenuNew->setPopupFiles( m_lstPopupURLs );
+
+ addAction( m_pMenuNew );
+
+ addSeparator();
+ }
+ else
+ {
+ if (d->m_itemFlags & KParts::BrowserExtension::ShowCreateDirectory)
+ {
+ KAction *actNewDir = new KAction( i18n( "Create &Folder..." ), "folder_new", 0, this, SLOT( slotPopupNewDir() ), &m_ownActions, "newdir" );
+ addAction( actNewDir );
+ addSeparator();
+ }
+ }
+ } else if ( isIntoTrash ) {
+ // Trashed item, offer restoring
+ act = new KAction( i18n( "&Restore" ), 0, this, SLOT( slotPopupRestoreTrashedItems() ), &m_ownActions, "restore" );
+ addAction( act );
+ }
+
+ if (d->m_itemFlags & KParts::BrowserExtension::ShowNavigationItems)
+ {
+ if (d->m_itemFlags & KParts::BrowserExtension::ShowUp)
+ addAction( "up" );
+ addAction( "back" );
+ addAction( "forward" );
+ if (d->m_itemFlags & KParts::BrowserExtension::ShowReload)
+ addAction( "reload" );
+ addSeparator();
+ }
+
+ // "open in new window" is either provided by us, or by the tabhandling group
+ if (actNewWindow)
+ {
+ addAction( actNewWindow );
+ addSeparator();
+ }
+ addGroup( "tabhandling" ); // includes a separator
+
+ if ( !bIsLink )
+ {
+ if ( !currentDir && sReading ) {
+ if ( sDeleting ) {
+ addAction( "cut" );
+ }
+ addAction( "copy" );
+ }
+
+ if ( S_ISDIR(mode) && sWriting ) {
+ if ( currentDir )
+ addAction( "paste" );
+ else
+ addAction( "pasteto" );
+ }
+ if ( !currentDir )
+ {
+ if ( m_lstItems.count() == 1 && sMoving )
+ addAction( "rename" );
+
+ bool addTrash = false;
+ bool addDel = false;
+
+ if ( sMoving && !isIntoTrash && !isTrashLink )
+ addTrash = true;
+
+ if ( sDeleting ) {
+ if ( !isLocal )
+ addDel = true;
+ else if (KApplication::keyboardMouseState() & Qt::ShiftButton) {
+ addTrash = false;
+ addDel = true;
+ }
+ else {
+ KConfigGroup configGroup( kapp->config(), "KDE" );
+ if ( configGroup.readBoolEntry( "ShowDeleteCommand", false ) )
+ addDel = true;
+ }
+ }
+
+ if ( addTrash )
+ addAction( "trash" );
+ if ( addDel )
+ addAction( "del" );
+ }
+ }
+ if ( isCurrentTrash )
+ {
+ act = new KAction( i18n( "&Empty Trash Bin" ), "emptytrash", 0, this, SLOT( slotPopupEmptyTrashBin() ), &m_ownActions, "empytrash" );
+ KSimpleConfig trashConfig( "trashrc", true );
+ trashConfig.setGroup( "Status" );
+ act->setEnabled( !trashConfig.readBoolEntry( "Empty", true ) );
+ addAction( act );
+ }
+ addGroup( "editactions" );
+
+ if (d->m_itemFlags & KParts::BrowserExtension::ShowTextSelectionItems) {
+ addMerge( 0 );
+ m_factory->addClient( this );
+ return;
+ }
+
+ if ( !isCurrentTrash && !isIntoTrash && (d->m_itemFlags & KParts::BrowserExtension::ShowBookmark))
+ {
+ addSeparator();
+ QString caption;
+ if (currentDir)
+ {
+ bool httpPage = (m_sViewURL.protocol().find("http", 0, false) == 0);
+ if (httpPage)
+ caption = i18n("&Bookmark This Page");
+ else
+ caption = i18n("&Bookmark This Location");
+ }
+ else if (S_ISDIR(mode))
+ caption = i18n("&Bookmark This Folder");
+ else if (bIsLink)
+ caption = i18n("&Bookmark This Link");
+ else
+ caption = i18n("&Bookmark This File");
+
+ act = new KAction( caption, "bookmark_add", 0, this, SLOT( slotPopupAddToBookmark() ), &m_ownActions, "bookmark_add" );
+ if (m_lstItems.count() > 1)
+ act->setEnabled(false);
+ if (kapp->authorizeKAction("bookmarks"))
+ addAction( act );
+ if (bIsLink)
+ addGroup( "linkactions" );
+ }
+
+ //////////////////////////////////////////////////////
+
+ const bool isSingleLocal = m_lstItems.count() == 1 && isLocal;
+ PopupServices s;
+ KURL urlForServiceMenu( m_lstItems.first()->url() );
+ if (isLocal && !isReallyLocal) { // media or system
+ bool dummy;
+ urlForServiceMenu = m_lstItems.first()->mostLocalURL(dummy);
+ }
+
+ // 1 - Look for builtin and user-defined services
+ if ( m_sMimeType == "application/x-desktop" && isSingleLocal ) // .desktop file
+ {
+ // get builtin services, like mount/unmount
+ s.builtin = KDEDesktopMimeType::builtinServices( urlForServiceMenu );
+ const QString path = urlForServiceMenu.path();
+ KSimpleConfig cfg( path, true );
+ cfg.setDesktopGroup();
+ const QString priority = cfg.readEntry("X-KDE-Priority");
+ const QString submenuName = cfg.readEntry( "X-KDE-Submenu" );
+ if ( cfg.readEntry("Type") == "Link" ) {
+ urlForServiceMenu = cfg.readEntry("URL");
+ // TODO: Do we want to make all the actions apply on the target
+ // of the .desktop file instead of the .desktop file itself?
+ }
+ ServiceList* list = s.selectList( priority, submenuName );
+ (*list) = KDEDesktopMimeType::userDefinedServices( path, cfg, urlForServiceMenu.isLocalFile() );
+ }
+
+ if ( sReading )
+ {
+
+ // 2 - Look for "servicesmenus" bindings (konqueror-specific user-defined services)
+
+ // first check the .directory if this is a directory
+ if (isDirectory && isSingleLocal)
+ {
+ QString dotDirectoryFile = urlForServiceMenu.path(1).append(".directory");
+ KSimpleConfig cfg( dotDirectoryFile, true );
+ cfg.setDesktopGroup();
+
+ if (KIOSKAuthorizedAction(cfg))
+ {
+ const QString priority = cfg.readEntry("X-KDE-Priority");
+ const QString submenuName = cfg.readEntry( "X-KDE-Submenu" );
+ ServiceList* list = s.selectList( priority, submenuName );
+ (*list) += KDEDesktopMimeType::userDefinedServices( dotDirectoryFile, cfg, true );
+ }
+ }
+
+ // findAllResources() also removes duplicates
+ const QStringList entries = KGlobal::dirs()->findAllResources("data",
+ "konqueror/servicemenus/*.desktop",
+ false /* recursive */,
+ true /* unique */);
+ QStringList::ConstIterator eIt = entries.begin();
+ const QStringList::ConstIterator eEnd = entries.end();
+ for (; eIt != eEnd; ++eIt )
+ {
+ KSimpleConfig cfg( *eIt, true );
+ cfg.setDesktopGroup();
+
+ if (!KIOSKAuthorizedAction(cfg))
+ {
+ continue;
+ }
+
+ if ( cfg.hasKey( "X-KDE-ShowIfRunning" ) )
+ {
+ const QString app = cfg.readEntry( "X-KDE-ShowIfRunning" );
+ if ( !kapp->dcopClient()->isApplicationRegistered( app.utf8() ) )
+ continue;
+ }
+ if ( cfg.hasKey( "X-KDE-ShowIfDcopCall" ) )
+ {
+ QString dcopcall = cfg.readEntry( "X-KDE-ShowIfDcopCall" );
+ const QCString app = dcopcall.section(' ', 0,0).utf8();
+
+ //if( !kapp->dcopClient()->isApplicationRegistered( app ))
+ // continue; //app does not exist so cannot send call
+
+ QByteArray dataToSend;
+ QDataStream dataStream(dataToSend, IO_WriteOnly);
+ dataStream << m_lstPopupURLs;
+
+ QCString replyType;
+ QByteArray replyData;
+ QCString object = dcopcall.section(' ', 1,-2).utf8();
+ QString function = dcopcall.section(' ', -1);
+ if(!function.endsWith("(KURL::List)")) {
+ kdWarning() << "Desktop file " << *eIt << " contains an invalid X-KDE-ShowIfDcopCall - the function must take the exact parameter (KURL::List) and must be specified." << endl;
+ continue; //Be safe.
+ }
+
+ if(!kapp->dcopClient()->call( app, object,
+ function.utf8(),
+ dataToSend, replyType, replyData, true, 1000))
+ continue;
+ if(replyType != "bool" || !replyData[0])
+ continue;
+
+ }
+ if ( cfg.hasKey( "X-KDE-Protocol" ) )
+ {
+ const QString protocol = cfg.readEntry( "X-KDE-Protocol" );
+ if ( protocol != urlForServiceMenu.protocol() )
+ continue;
+ }
+ else if ( cfg.hasKey( "X-KDE-Protocols" ) )
+ {
+ QStringList protocols = QStringList::split( "," , cfg.readEntry( "X-KDE-Protocols" ) );
+ if ( !protocols.contains( urlForServiceMenu.protocol() ) )
+ continue;
+ }
+ else if ( urlForServiceMenu.protocol() == "trash" || urlForServiceMenu.url().startsWith( "system:/trash" ) )
+ {
+ // Require servicemenus for the trash to ask for protocol=trash explicitely.
+ // Trashed files aren't supposed to be available for actions.
+ // One might want a servicemenu for trash.desktop itself though.
+ continue;
+ }
+
+ if ( cfg.hasKey( "X-KDE-Require" ) )
+ {
+ const QStringList capabilities = cfg.readListEntry( "X-KDE-Require" );
+ if ( capabilities.contains( "Write" ) && !sWriting )
+ continue;
+ }
+ if ( (cfg.hasKey( "Actions" ) || cfg.hasKey( "X-KDE-GetActionMenu") ) && cfg.hasKey( "ServiceTypes" ) )
+ {
+ const QStringList types = cfg.readListEntry( "ServiceTypes" );
+ const QStringList excludeTypes = cfg.readListEntry( "ExcludeServiceTypes" );
+ bool ok = false;
+
+ // check for exact matches or a typeglob'd mimetype if we have a mimetype
+ for (QStringList::ConstIterator it = types.begin();
+ it != types.end() && !ok;
+ ++it)
+ {
+ // first check if we have an all mimetype
+ bool checkTheMimetypes = false;
+ if (*it == "all/all" ||
+ *it == "allfiles" /*compat with KDE up to 3.0.3*/)
+ {
+ checkTheMimetypes = true;
+ }
+
+ // next, do we match all files?
+ if (!ok &&
+ !isDirectory &&
+ *it == "all/allfiles")
+ {
+ checkTheMimetypes = true;
+ }
+
+ // if we have a mimetype, see if we have an exact or a type globbed match
+ if (!ok &&
+ (!m_sMimeType.isEmpty() &&
+ *it == m_sMimeType) ||
+ (!mimeGroup.isEmpty() &&
+ ((*it).right(1) == "*" &&
+ (*it).left((*it).find('/')) == mimeGroup)))
+ {
+ checkTheMimetypes = true;
+ }
+
+ if (checkTheMimetypes)
+ {
+ ok = true;
+ for (QStringList::ConstIterator itex = excludeTypes.begin(); itex != excludeTypes.end(); ++itex)
+ {
+ if( ((*itex).right(1) == "*" && (*itex).left((*itex).find('/')) == mimeGroup) ||
+ ((*itex) == m_sMimeType) )
+ {
+ ok = false;
+ break;
+ }
+ }
+ }
+ }
+
+ if ( ok )
+ {
+ const QString priority = cfg.readEntry("X-KDE-Priority");
+ const QString submenuName = cfg.readEntry( "X-KDE-Submenu" );
+
+ ServiceList* list = s.selectList( priority, submenuName );
+ (*list) += KDEDesktopMimeType::userDefinedServices( *eIt, cfg, url.isLocalFile(), m_lstPopupURLs );
+ }
+ }
+ }
+
+ KTrader::OfferList offers;
+
+ if (kapp->authorizeKAction("openwith"))
+ {
+ QString constraint = "Type == 'Application' and DesktopEntryName != 'kfmclient' and DesktopEntryName != 'kfmclient_dir' and DesktopEntryName != 'kfmclient_html'";
+ QString subConstraint = " and '%1' in ServiceTypes";
+
+ QStringList::ConstIterator it = mimeTypeList.begin();
+ QStringList::ConstIterator end = mimeTypeList.end();
+ Q_ASSERT( it != end );
+ QString first = *it;
+ ++it;
+ while ( it != end ) {
+ constraint += subConstraint.arg( *it );
+ ++it;
+ }
+
+ offers = KTrader::self()->query( first, constraint );
+ }
+
+ //// Ok, we have everything, now insert
+
+ m_mapPopup.clear();
+ m_mapPopupServices.clear();
+ // "Open With..." for folders is really not very useful, especially for remote folders.
+ // (media:/something, or trash:/, or ftp://...)
+ if ( !isDirectory || isLocal )
+ {
+ if ( hasAction() )
+ addSeparator();
+
+ if ( !offers.isEmpty() )
+ {
+ // First block, app and preview offers
+ id = 1;
+
+ QDomElement menu = m_menuElement;
+
+ if ( offers.count() > 1 ) // submenu 'open with'
+ {
+ menu = m_doc.createElement( "menu" );
+ menu.setAttribute( "name", "openwith submenu" );
+ m_menuElement.appendChild( menu );
+ QDomElement text = m_doc.createElement( "text" );
+ menu.appendChild( text );
+ text.appendChild( m_doc.createTextNode( i18n("&Open With") ) );
+ }
+
+ KTrader::OfferList::ConstIterator it = offers.begin();
+ for( ; it != offers.end(); it++ )
+ {
+ KService::Ptr service = (*it);
+
+ // Skip OnlyShowIn=Foo and NotShowIn=KDE entries,
+ // but still offer NoDisplay=true entries, that's the
+ // whole point of such desktop files. This is why we don't
+ // use service->noDisplay() here.
+ const QString onlyShowIn = service->property("OnlyShowIn", QVariant::String).toString();
+ if ( !onlyShowIn.isEmpty() ) {
+ const QStringList aList = QStringList::split(';', onlyShowIn);
+ if (!aList.contains("KDE"))
+ continue;
+ }
+ const QString notShowIn = service->property("NotShowIn", QVariant::String).toString();
+ if ( !notShowIn.isEmpty() ) {
+ const QStringList aList = QStringList::split(';', notShowIn);
+ if (aList.contains("KDE"))
+ continue;
+ }
+
+ QCString nam;
+ nam.setNum( id );
+
+ QString actionName( (*it)->name().replace("&", "&&") );
+ if ( menu == m_menuElement ) // no submenu -> prefix single offer
+ actionName = i18n( "Open with %1" ).arg( actionName );
+
+ act = new KAction( actionName, (*it)->pixmap( KIcon::Small ), 0,
+ this, SLOT( slotRunService() ),
+ &m_ownActions, nam.prepend( "appservice_" ) );
+ addAction( act, menu );
+
+ m_mapPopup[ id++ ] = *it;
+ }
+
+ QString openWithActionName;
+ if ( menu != m_menuElement ) // submenu
+ {
+ addSeparator( menu );
+ openWithActionName = i18n( "&Other..." );
+ }
+ else
+ {
+ openWithActionName = i18n( "&Open With..." );
+ }
+ KAction *openWithAct = new KAction( openWithActionName, 0, this, SLOT( slotPopupOpenWith() ), &m_ownActions, "openwith" );
+ addAction( openWithAct, menu );
+ }
+ else // no app offers -> Open With...
+ {
+ act = new KAction( i18n( "&Open With..." ), 0, this, SLOT( slotPopupOpenWith() ), &m_ownActions, "openwith" );
+ addAction( act );
+ }
+
+ }
+ addGroup( "preview" );
+ }
+
+ // Second block, builtin + user
+ QDomElement actionMenu = m_menuElement;
+ int userItemCount = 0;
+ if (s.user.count() + s.userSubmenus.count() +
+ s.userPriority.count() + s.userPrioritySubmenus.count() > 1)
+ {
+ // we have more than one item, so let's make a submenu
+ actionMenu = m_doc.createElement( "menu" );
+ actionMenu.setAttribute( "name", "actions submenu" );
+ m_menuElement.appendChild( actionMenu );
+ QDomElement text = m_doc.createElement( "text" );
+ actionMenu.appendChild( text );
+ text.appendChild( m_doc.createTextNode( i18n("Ac&tions") ) );
+ }
+
+ userItemCount += insertServicesSubmenus(s.userPrioritySubmenus, actionMenu, false);
+ userItemCount += insertServices(s.userPriority, actionMenu, false);
+
+ // see if we need to put a separator between our priority items and our regular items
+ if (userItemCount > 0 &&
+ (s.user.count() > 0 ||
+ s.userSubmenus.count() > 0 ||
+ s.builtin.count() > 0) &&
+ actionMenu.lastChild().toElement().tagName().lower() != "separator")
+ {
+ QDomElement separator = m_doc.createElement( "separator" );
+ actionMenu.appendChild(separator);
+ }
+
+ userItemCount += insertServicesSubmenus(s.userSubmenus, actionMenu, false);
+ userItemCount += insertServices(s.user, actionMenu, false);
+ userItemCount += insertServices(s.builtin, m_menuElement, true);
+
+ userItemCount += insertServicesSubmenus(s.userToplevelSubmenus, m_menuElement, false);
+ userItemCount += insertServices(s.userToplevel, m_menuElement, false);
+
+ if ( userItemCount > 0 )
+ {
+ addPendingSeparator();
+ }
+
+ if ( !isCurrentTrash && !isIntoTrash && !mediaFiles && sReading )
+ addPlugins(); // now it's time to add plugins
+
+ if ( KPropertiesDialog::canDisplay( m_lstItems ) && (kpf & ShowProperties) )
+ {
+ act = new KAction( i18n( "&Properties" ), 0, this, SLOT( slotPopupProperties() ),
+ &m_ownActions, "properties" );
+ addAction( act );
+ }
+
+ while ( !m_menuElement.lastChild().isNull() &&
+ m_menuElement.lastChild().toElement().tagName().lower() == "separator" )
+ m_menuElement.removeChild( m_menuElement.lastChild() );
+
+ if ( isDirectory && isLocal )
+ {
+ if ( KFileShare::authorization() == KFileShare::Authorized )
+ {
+ addSeparator();
+ act = new KAction( i18n("Share"), 0, this, SLOT( slotOpenShareFileDialog() ),
+ &m_ownActions, "sharefile" );
+ addAction( act );
+ }
+ }
+
+ addMerge( 0 );
+ //kdDebug() << k_funcinfo << domDocument().toString() << endl;
+
+ m_factory->addClient( this );
+}
+
+void KonqPopupMenu::slotOpenShareFileDialog()
+{
+ KPropertiesDialog* dlg = showPropertiesDialog();
+ dlg->showFileSharingPage();
+}
+
+KonqPopupMenu::~KonqPopupMenu()
+{
+ m_pluginList.clear();
+ delete m_factory;
+ delete m_builder;
+ delete d;
+ //kdDebug(1203) << "~KonqPopupMenu leave" << endl;
+}
+
+void KonqPopupMenu::setURLTitle( const QString& urlTitle )
+{
+ d->m_urlTitle = urlTitle;
+}
+
+void KonqPopupMenu::slotPopupNewView()
+{
+ KURL::List::ConstIterator it = m_lstPopupURLs.begin();
+ for ( ; it != m_lstPopupURLs.end(); it++ )
+ (void) new KRun(*it);
+}
+
+void KonqPopupMenu::slotPopupNewDir()
+{
+ if (m_lstPopupURLs.empty())
+ return;
+
+ KonqOperations::newDir(d->m_parentWidget, m_lstPopupURLs.first());
+}
+
+void KonqPopupMenu::slotPopupEmptyTrashBin()
+{
+ KonqOperations::emptyTrash();
+}
+
+void KonqPopupMenu::slotPopupRestoreTrashedItems()
+{
+ KonqOperations::restoreTrashedItems( m_lstPopupURLs );
+}
+
+void KonqPopupMenu::slotPopupOpenWith()
+{
+ KRun::displayOpenWithDialog( m_lstPopupURLs );
+}
+
+void KonqPopupMenu::slotPopupAddToBookmark()
+{
+ KBookmarkGroup root;
+ if ( m_lstPopupURLs.count() == 1 ) {
+ KURL url = m_lstPopupURLs.first();
+ QString title = d->m_urlTitle.isEmpty() ? url.prettyURL() : d->m_urlTitle;
+ root = m_pManager->addBookmarkDialog( url.prettyURL(), title );
+ }
+ else
+ {
+ root = m_pManager->root();
+ KURL::List::ConstIterator it = m_lstPopupURLs.begin();
+ for ( ; it != m_lstPopupURLs.end(); it++ )
+ root.addBookmark( m_pManager, (*it).prettyURL(), (*it) );
+ }
+ m_pManager->emitChanged( root );
+}
+
+void KonqPopupMenu::slotRunService()
+{
+ QCString senderName = sender()->name();
+ int id = senderName.mid( senderName.find( '_' ) + 1 ).toInt();
+
+ // Is it a usual service (application)
+ QMap<int,KService::Ptr>::Iterator it = m_mapPopup.find( id );
+ if ( it != m_mapPopup.end() )
+ {
+ KRun::run( **it, m_lstPopupURLs );
+ return;
+ }
+
+ // Is it a service specific to desktop entry files ?
+ QMap<int,KDEDesktopMimeType::Service>::Iterator it2 = m_mapPopupServices.find( id );
+ if ( it2 != m_mapPopupServices.end() )
+ {
+ KDEDesktopMimeType::executeService( m_lstPopupURLs, it2.data() );
+ }
+
+ return;
+}
+
+void KonqPopupMenu::slotPopupMimeType()
+{
+ KonqOperations::editMimeType( m_sMimeType );
+}
+
+void KonqPopupMenu::slotPopupProperties()
+{
+ (void)showPropertiesDialog();
+}
+
+KPropertiesDialog* KonqPopupMenu::showPropertiesDialog()
+{
+ // It may be that the kfileitem was created by hand
+ // (see KonqKfmIconView::slotMouseButtonPressed)
+ // In that case, we can get more precise info in the properties
+ // (like permissions) if we stat the URL.
+ if ( m_lstItems.count() == 1 )
+ {
+ KFileItem * item = m_lstItems.first();
+ if (item->entry().count() == 0) // this item wasn't listed by a slave
+ {
+ // KPropertiesDialog will use stat to get more info on the file
+ return new KPropertiesDialog( item->url(), d->m_parentWidget );
+ }
+ }
+ return new KPropertiesDialog( m_lstItems, d->m_parentWidget );
+}
+
+KAction *KonqPopupMenu::action( const QDomElement &element ) const
+{
+ QCString name = element.attribute( attrName ).ascii();
+ KAction *res = m_ownActions.action( name );
+
+ if ( !res )
+ res = m_actions.action( name );
+
+ if ( !res && m_pMenuNew && strcmp( name, m_pMenuNew->name() ) == 0 )
+ return m_pMenuNew;
+
+ return res;
+}
+
+KActionCollection *KonqPopupMenu::actionCollection() const
+{
+ return const_cast<KActionCollection *>( &m_ownActions );
+}
+
+QString KonqPopupMenu::mimeType() const
+{
+ return m_sMimeType;
+}
+
+KonqPopupMenu::ProtocolInfo KonqPopupMenu::protocolInfo() const
+{
+ return m_info;
+}
+
+void KonqPopupMenu::addPlugins()
+{
+ // search for Konq_PopupMenuPlugins inspired by simons kpropsdlg
+ //search for a plugin with the right protocol
+ KTrader::OfferList plugin_offers;
+ unsigned int pluginCount = 0;
+ plugin_offers = KTrader::self()->query( m_sMimeType.isNull() ? QString::fromLatin1( "all/all" ) : m_sMimeType, "'KonqPopupMenu/Plugin' in ServiceTypes");
+ if ( plugin_offers.isEmpty() )
+ return; // no plugins installed do not bother about it
+
+ KTrader::OfferList::ConstIterator iterator = plugin_offers.begin();
+ KTrader::OfferList::ConstIterator end = plugin_offers.end();
+
+ addGroup( "plugins" );
+ // travers the offerlist
+ for(; iterator != end; ++iterator, ++pluginCount ) {
+ //kdDebug() << (*iterator)->library() << endl;
+ KonqPopupMenuPlugin *plugin =
+ KParts::ComponentFactory::
+ createInstanceFromLibrary<KonqPopupMenuPlugin>( QFile::encodeName( (*iterator)->library() ),
+ this,
+ (*iterator)->name().latin1() );
+ if ( !plugin )
+ continue;
+ // This make the kuick plugin insert its stuff above "Properties"
+ QString pluginClientName = QString::fromLatin1( "Plugin%1" ).arg( pluginCount );
+ addMerge( pluginClientName );
+ plugin->domDocument().documentElement().setAttribute( "name", pluginClientName );
+ m_pluginList.append( plugin );
+ insertChildClient( plugin );
+ }
+
+ // ## Where is this used?
+ addMerge( "plugins" );
+}
+
+KURL KonqPopupMenu::url() const // ### should be viewURL()
+{
+ return m_sViewURL;
+}
+
+KFileItemList KonqPopupMenu::fileItemList() const
+{
+ return m_lstItems;
+}
+
+KURL::List KonqPopupMenu::popupURLList() const
+{
+ return m_lstPopupURLs;
+}
+
+/**
+ Plugin
+*/
+
+KonqPopupMenuPlugin::KonqPopupMenuPlugin( KonqPopupMenu *parent, const char *name )
+ : QObject( parent, name )
+{
+}
+
+KonqPopupMenuPlugin::~KonqPopupMenuPlugin()
+{
+}
+
+#include "konq_popupmenu.moc"
diff --git a/libkonq/konq_popupmenu.h b/libkonq/konq_popupmenu.h
new file mode 100644
index 000000000..44021713f
--- /dev/null
+++ b/libkonq/konq_popupmenu.h
@@ -0,0 +1,221 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 David Faure <faure@kde.org>
+ Copyright (C) 2001 Holger Freyther <freyther@yahoo.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __konqpopupmenu_h
+#define __konqpopupmenu_h
+
+#include <sys/types.h>
+
+#include <qpopupmenu.h>
+#include <qmap.h>
+#include <kaction.h>
+
+#include <qstringlist.h>
+
+#include <kfileitem.h>
+#include <kmimetype.h> // for KDEDesktopMimeType
+#include <libkonq_export.h>
+
+#include <kparts/browserextension.h>
+
+#include "konq_xmlguiclient.h"
+
+typedef QValueList<KDEDesktopMimeType::Service> ServiceList;
+
+class KPropertiesDialog;
+class KNewMenu;
+class KService;
+class KonqPopupMenuPlugin;
+class KBookmarkManager;
+
+// TODO KDE4: change base class to KPopupMenu, see KAction::slotPopupActivated()
+/**
+ * This class implements the popup menu for URLs in konqueror and kdesktop
+ * It's usage is very simple : on right click, create the KonqPopupMenu instance
+ * with the correct arguments, then exec() to make it appear, then destroy it.
+ *
+ */
+class LIBKONQ_EXPORT KonqPopupMenu : public QPopupMenu, public KonqXMLGUIClient
+{
+ Q_OBJECT
+public:
+
+ /**
+ * Flags set by the calling application (konqueror/kdesktop), unlike
+ * KParts::BrowserExtension::PopupFlags, which are set by the calling part
+ */
+ typedef uint KonqPopupFlags;
+ enum { NoFlags = 0,
+ ShowProperties = 1, ///< whether to show the "Properties" menu item
+ IsLink = 2, ///< HTML link. If set, we won't have cut/copy/paste, and we'll say "bookmark this link"
+ ShowNewWindow = 4 };
+ // WARNING: bitfield. Next item is 8
+
+ /**
+ * @deprecated lacks parentWidget pointer, and
+ * uses bool instead of KonqPopupFlags enum,
+ * might do strange things with the 'new window' action.
+ */
+ KonqPopupMenu( KBookmarkManager* manager,
+ const KFileItemList &items,
+ KURL viewURL,
+ KActionCollection & actions,
+ KNewMenu * newMenu,
+ bool showPropertiesAndFileType = true ) KDE_DEPRECATED;
+
+ /**
+ * @deprecated uses bool instead of KonqPopupFlags enum,
+ * might do strange things with the 'new window' action.
+ */
+ KonqPopupMenu( KBookmarkManager* manager,
+ const KFileItemList &items,
+ KURL viewURL,
+ KActionCollection & actions,
+ KNewMenu * newMenu,
+ QWidget * parentWidget,
+ bool showPropertiesAndFileType = true ) KDE_DEPRECATED;
+
+ /**
+ * Constructor
+ * @param manager the bookmark manager for this bookmark
+ * @param items the list of file items the popupmenu should be shown for
+ * @param viewURL the URL shown in the view, to test for RMB click on view background
+ * @param actions list of actions the caller wants to see in the menu
+ * @param newMenu "New" menu, shared with the File menu, in konqueror
+ * @param parentWidget the widget we're showing this popup for. Helps destroying
+ * the popup if the widget is destroyed before the popup.
+ * @param kpf flags from the KonqPopupFlags enum, set by the calling application
+ * @param f flags from the BrowserExtension enum, set by the calling part
+ *
+ * The actions to pass in include :
+ * showmenubar, back, forward, up, cut, copy, paste, pasteto, trash, rename, del
+ * The others items are automatically inserted.
+ *
+ * @since 3.2
+ *
+ * @todo that list is probably not be up-to-date
+ */
+ KonqPopupMenu( KBookmarkManager* manager,
+ const KFileItemList &items,
+ const KURL& viewURL,
+ KActionCollection & actions,
+ KNewMenu * newMenu,
+ QWidget * parentWidget,
+ KonqPopupFlags kpf,
+ KParts::BrowserExtension::PopupFlags f /*= KParts::BrowserExtension::DefaultPopupItems*/);
+
+ /**
+ * Don't forget to destroy the object
+ */
+ ~KonqPopupMenu();
+
+ /**
+ * Set the title of the URL, when the popupmenu is opened for a single URL.
+ * This is used if the user chooses to add a bookmark for this URL.
+ */
+ void setURLTitle( const QString& urlTitle );
+
+ class LIBKONQ_EXPORT ProtocolInfo {
+ public:
+ ProtocolInfo();
+ bool supportsReading() const;
+ bool supportsWriting() const;
+ bool supportsDeleting() const;
+ bool supportsMoving() const;
+ bool trashIncluded() const;
+ private:
+ friend class KonqPopupMenu;
+ bool m_Reading:1;
+ bool m_Writing:1;
+ bool m_Deleting:1;
+ bool m_Moving:1;
+ bool m_TrashIncluded:1;
+ };
+ /**
+ * Reimplemented for internal purpose
+ */
+ virtual KAction *action( const QDomElement &element ) const;
+
+
+ virtual KActionCollection *actionCollection() const;
+ QString mimeType( ) const;
+ KURL url( ) const;
+ KFileItemList fileItemList() const;
+ KURL::List popupURLList( ) const;
+ ProtocolInfo protocolInfo() const;
+
+public slots: // KDE4: why public?
+ void slotPopupNewDir();
+ void slotPopupNewView();
+ void slotPopupEmptyTrashBin();
+ void slotPopupRestoreTrashedItems();
+ void slotPopupOpenWith();
+ void slotPopupAddToBookmark();
+ void slotRunService();
+ void slotPopupMimeType();
+ void slotPopupProperties();
+ void slotOpenShareFileDialog();
+protected:
+ KActionCollection &m_actions;
+ KActionCollection m_ownActions;
+
+private:
+ void init (QWidget * parentWidget, KonqPopupFlags kpf, KParts::BrowserExtension::PopupFlags itemFlags);
+ void setup(KonqPopupFlags kpf);
+ void addPlugins( );
+ int insertServicesSubmenus(const QMap<QString, ServiceList>& list, QDomElement& menu, bool isBuiltin);
+ int insertServices(const ServiceList& list, QDomElement& menu, bool isBuiltin);
+ bool KIOSKAuthorizedAction(KConfig& cfg);
+ KPropertiesDialog* showPropertiesDialog();
+
+ class KonqPopupMenuPrivate;
+ KonqPopupMenuPrivate *d;
+ KNewMenu *m_pMenuNew;
+ KURL m_sViewURL;
+ QString m_sMimeType;
+ KFileItemList m_lstItems;
+ KURL::List m_lstPopupURLs;
+ QMap<int,KService::Ptr> m_mapPopup;
+ QMap<int,KDEDesktopMimeType::Service> m_mapPopupServices;
+ bool m_bHandleEditOperations;
+ KXMLGUIFactory *m_factory;
+ KXMLGUIBuilder *m_builder;
+ QString attrName;
+ ProtocolInfo m_info;
+ QPtrList<KonqPopupMenuPlugin> m_pluginList;
+ KBookmarkManager* m_pManager;
+};
+
+class LIBKONQ_EXPORT KonqPopupMenuPlugin : public QObject, public KonqXMLGUIClient {
+ Q_OBJECT
+public:
+ /**
+ * Constructor
+ * If you want to insert a dynamic item or menu to konqpopupmenu
+ * this class is the right choice.
+ * Create a KAction and use _popup->addAction(new KAction );
+ * If you want to create a submenu use _popup->addGroup( );
+ */
+ KonqPopupMenuPlugin( KonqPopupMenu *_popup, const char *name ); // this should also be the parent
+ virtual ~KonqPopupMenuPlugin ( );
+};
+
+#endif
+
diff --git a/libkonq/konq_propsview.cc b/libkonq/konq_propsview.cc
new file mode 100644
index 000000000..c2cc3dd3d
--- /dev/null
+++ b/libkonq/konq_propsview.cc
@@ -0,0 +1,584 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Faure David <faure@kde.org>
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "konq_propsview.h"
+#include "konq_settings.h"
+
+#include <kdebug.h>
+#include <kstandarddirs.h>
+#include <kpixmap.h>
+#include <qpixmapcache.h>
+#include <qiconview.h>
+#include <unistd.h>
+#include <qfile.h>
+#include <iostream>
+#include <ktrader.h>
+#include <kinstance.h>
+#include <assert.h>
+
+#include <ksimpleconfig.h>
+
+static QPixmap wallpaperPixmap( const QString & _wallpaper )
+{
+ QString key = "wallpapers/";
+ key += _wallpaper;
+ KPixmap pix;
+
+ if ( QPixmapCache::find( key, pix ) )
+ return pix;
+
+ QString path = locate("tiles", _wallpaper);
+ if (path.isEmpty())
+ path = locate("wallpaper", _wallpaper);
+ if (!path.isEmpty())
+ {
+ // This looks really ugly, especially on an 8bit display.
+ // I'm not sure what it's good for.
+ // Anyway, if you change it here, keep konq_bgnddlg in sync (David)
+ // pix.load( path, 0, KPixmap::LowColor );
+ pix.load( path );
+ if ( pix.isNull() )
+ kdWarning(1203) << "Could not load wallpaper " << path << endl;
+ else
+ QPixmapCache::insert( key, pix );
+ return pix;
+ } else kdWarning(1203) << "Couldn't locate wallpaper " << _wallpaper << endl;
+ return QPixmap();
+}
+
+struct KonqPropsView::Private
+{
+ QStringList* previewsToShow;
+ bool previewsEnabled:1;
+ bool caseInsensitiveSort:1;
+ bool dirsfirst:1;
+ bool descending:1;
+ QString sortcriterion;
+};
+
+KonqPropsView::KonqPropsView( KInstance * instance, KonqPropsView * defaultProps )
+ : m_bSaveViewPropertiesLocally( false ), // will be overridden by setSave... anyway
+ // if this is the default properties instance, then keep config object for saving
+ m_dotDirExists( true ), // HACK so that enterDir returns true initially
+ m_currentConfig( defaultProps ? 0L : instance->config() ),
+ m_defaultProps( defaultProps )
+{
+
+ KConfig *config = instance->config();
+ KConfigGroupSaver cgs(config, "Settings");
+
+ d = new Private;
+ d->previewsToShow = 0;
+ d->caseInsensitiveSort=config->readBoolEntry( "CaseInsensitiveSort", true );
+
+ m_iIconSize = config->readNumEntry( "IconSize", 0 );
+ m_iItemTextPos = config->readNumEntry( "ItemTextPos", QIconView::Bottom );
+ d->sortcriterion = config->readEntry( "SortingCriterion", "sort_nci" );
+ d->dirsfirst = config->readBoolEntry( "SortDirsFirst", true );
+ d->descending = config->readBoolEntry( "SortDescending", false );
+ m_bShowDot = config->readBoolEntry( "ShowDotFiles", false );
+ m_bShowDirectoryOverlays = config->readBoolEntry( "ShowDirectoryOverlays", false );
+
+ m_dontPreview = config->readListEntry( "DontPreview" );
+ m_dontPreview.remove("audio/"); //Use the separate setting.
+ //We default to this off anyway, so it's no harm to remove this
+
+ //The setting for sound previews is stored separately, so we can force
+ //the default-to-off bias to propagate up.
+ if (!config->readBoolEntry("EnableSoundPreviews", false))
+ {
+ if (!m_dontPreview.contains("audio/"))
+ m_dontPreview.append("audio/");
+ }
+
+ d->previewsEnabled = config->readBoolEntry( "PreviewsEnabled", true );
+
+ QColor tc = KonqFMSettings::settings()->normalTextColor();
+ m_textColor = config->readColorEntry( "TextColor", &tc );
+ m_bgColor = config->readColorEntry( "BgColor" ); // will be set to QColor() if not found
+ m_bgPixmapFile = config->readPathEntry( "BgImage" );
+ //kdDebug(1203) << "KonqPropsView::KonqPropsView from \"config\" : BgImage=" << m_bgPixmapFile << endl;
+
+ // colorsConfig is either the local file (.directory) or the application global file
+ // (we want the same colors for all types of view)
+ // The code above reads from the view's config file, for compatibility only.
+ // So now we read the settings from the app global file, if this is the default props
+ if (!defaultProps)
+ {
+ KConfigGroupSaver cgs2(KGlobal::config(), "Settings");
+ m_textColor = KGlobal::config()->readColorEntry( "TextColor", &m_textColor );
+ m_bgColor = KGlobal::config()->readColorEntry( "BgColor", &m_bgColor );
+ m_bgPixmapFile = KGlobal::config()->readPathEntry( "BgImage", m_bgPixmapFile );
+ //kdDebug(1203) << "KonqPropsView::KonqPropsView from KGlobal : BgImage=" << m_bgPixmapFile << endl;
+ }
+
+ KGlobal::dirs()->addResourceType("tiles",
+ KGlobal::dirs()->kde_default("data") + "konqueror/tiles/");
+}
+
+bool KonqPropsView::isCaseInsensitiveSort() const
+{
+ return d->caseInsensitiveSort;
+}
+
+bool KonqPropsView::isDirsFirst() const
+{
+ return d->dirsfirst;
+}
+
+bool KonqPropsView::isDescending() const
+{
+ return d->descending;
+}
+
+KConfigBase * KonqPropsView::currentConfig()
+{
+ if ( !m_currentConfig )
+ {
+ // 0L ? This has to be a non-default save-locally instance...
+ assert ( m_bSaveViewPropertiesLocally );
+ assert ( !isDefaultProperties() );
+
+ if (!dotDirectory.isEmpty())
+ m_currentConfig = new KSimpleConfig( dotDirectory );
+ // the "else" is when we want to save locally but this is a remote URL -> no save
+ }
+ return m_currentConfig;
+}
+
+KConfigBase * KonqPropsView::currentColorConfig()
+{
+ // Saving locally ?
+ if ( m_bSaveViewPropertiesLocally && !isDefaultProperties() )
+ return currentConfig(); // Will create it if necessary
+ else
+ // Save color settings in app's file, not in view's file
+ return KGlobal::config();
+}
+
+KonqPropsView::~KonqPropsView()
+{
+ delete d->previewsToShow;
+ delete d;
+ d=0;
+}
+
+bool KonqPropsView::enterDir( const KURL & dir )
+{
+ //kdDebug(1203) << "enterDir " << dir.prettyURL() << endl;
+ // Can't do that with default properties
+ assert( !isDefaultProperties() );
+
+ // Check for .directory
+ KURL u ( dir );
+ u.addPath(".directory");
+ bool dotDirExists = u.isLocalFile() && QFile::exists( u.path() );
+ dotDirectory = u.isLocalFile() ? u.path() : QString::null;
+
+ // Revert to default setting first - unless there is no .directory
+ // in the previous dir nor in this one (then we can keep the current settings)
+ if (dotDirExists || m_dotDirExists)
+ {
+ m_iIconSize = m_defaultProps->iconSize();
+ m_iItemTextPos = m_defaultProps->itemTextPos();
+ d->sortcriterion = m_defaultProps->sortCriterion();
+ d->dirsfirst = m_defaultProps->isDirsFirst();
+ d->descending = m_defaultProps->isDescending();
+ m_bShowDot = m_defaultProps->isShowingDotFiles();
+ d->caseInsensitiveSort=m_defaultProps->isCaseInsensitiveSort();
+ m_dontPreview = m_defaultProps->m_dontPreview;
+ m_textColor = m_defaultProps->m_textColor;
+ m_bgColor = m_defaultProps->m_bgColor;
+ m_bgPixmapFile = m_defaultProps->bgPixmapFile();
+ }
+
+ if (dotDirExists)
+ {
+ //kdDebug(1203) << "Found .directory file" << endl;
+ KSimpleConfig * config = new KSimpleConfig( dotDirectory, true );
+ config->setGroup("URL properties");
+
+ m_iIconSize = config->readNumEntry( "IconSize", m_iIconSize );
+ m_iItemTextPos = config->readNumEntry( "ItemTextPos", m_iItemTextPos );
+ d->sortcriterion = config->readEntry( "SortingCriterion" , d->sortcriterion );
+ d->dirsfirst = config->readBoolEntry( "SortDirsFirst", d->dirsfirst );
+ d->descending = config->readBoolEntry( "SortDescending", d->descending );
+ m_bShowDot = config->readBoolEntry( "ShowDotFiles", m_bShowDot );
+ d->caseInsensitiveSort=config->readBoolEntry("CaseInsensitiveSort",d->caseInsensitiveSort);
+ m_bShowDirectoryOverlays = config->readBoolEntry( "ShowDirectoryOverlays", m_bShowDirectoryOverlays );
+ if (config->hasKey( "DontPreview" ))
+ {
+ m_dontPreview = config->readListEntry( "DontPreview" );
+
+ //If the .directory file says something about sound previews,
+ //obey it, otherwise propagate the setting up from the defaults
+ //All this really should be split into a per-thumbnail setting,
+ //but that's too invasive at this point
+ if (config->hasKey("EnableSoundPreviews"))
+ {
+
+ if (!config->readBoolEntry("EnableSoundPreviews", false))
+ if (!m_dontPreview.contains("audio/"))
+ m_dontPreview.append("audio/");
+ }
+ else
+ {
+ if (m_defaultProps->m_dontPreview.contains("audio/"))
+ if (!m_dontPreview.contains("audio/"))
+ m_dontPreview.append("audio/");
+ }
+ }
+
+
+
+ m_textColor = config->readColorEntry( "TextColor", &m_textColor );
+ m_bgColor = config->readColorEntry( "BgColor", &m_bgColor );
+ m_bgPixmapFile = config->readPathEntry( "BgImage", m_bgPixmapFile );
+ //kdDebug(1203) << "KonqPropsView::enterDir m_bgPixmapFile=" << m_bgPixmapFile << endl;
+ d->previewsEnabled = config->readBoolEntry( "PreviewsEnabled", d->previewsEnabled );
+ delete config;
+ }
+ //if there is or was a .directory then the settings probably have changed
+ bool configChanged=(m_dotDirExists|| dotDirExists);
+ m_dotDirExists = dotDirExists;
+ m_currentConfig = 0L; // new dir, not current config for saving yet
+ //kdDebug(1203) << "KonqPropsView::enterDir returning " << configChanged << endl;
+ return configChanged;
+}
+
+void KonqPropsView::setSaveViewPropertiesLocally( bool value )
+{
+ assert( !isDefaultProperties() );
+ //kdDebug(1203) << "KonqPropsView::setSaveViewPropertiesLocally " << value << endl;
+
+ if ( m_bSaveViewPropertiesLocally )
+ delete m_currentConfig; // points to a KSimpleConfig
+
+ m_bSaveViewPropertiesLocally = value;
+ m_currentConfig = 0L; // mark as dirty
+}
+
+void KonqPropsView::setIconSize( int size )
+{
+ m_iIconSize = size;
+ if ( m_defaultProps && !m_bSaveViewPropertiesLocally )
+ m_defaultProps->setIconSize( size );
+ else if (currentConfig())
+ {
+ KConfigGroupSaver cgs(currentConfig(), currentGroup());
+ currentConfig()->writeEntry( "IconSize", m_iIconSize );
+ currentConfig()->sync();
+ }
+}
+
+void KonqPropsView::setItemTextPos( int pos )
+{
+ m_iItemTextPos = pos;
+ if ( m_defaultProps && !m_bSaveViewPropertiesLocally )
+ m_defaultProps->setItemTextPos( pos );
+ else if (currentConfig())
+ {
+ KConfigGroupSaver cgs(currentConfig(), currentGroup());
+ currentConfig()->writeEntry( "ItemTextPos", m_iItemTextPos );
+ currentConfig()->sync();
+ }
+}
+
+void KonqPropsView::setSortCriterion( const QString &criterion )
+{
+ d->sortcriterion = criterion;
+ if ( m_defaultProps && !m_bSaveViewPropertiesLocally )
+ m_defaultProps->setSortCriterion( criterion );
+ else if (currentConfig())
+ {
+ KConfigGroupSaver cgs(currentConfig(), currentGroup());
+ currentConfig()->writeEntry( "SortingCriterion", d->sortcriterion );
+ currentConfig()->sync();
+ }
+}
+
+void KonqPropsView::setDirsFirst( bool first)
+{
+ d->dirsfirst = first;
+ if ( m_defaultProps && !m_bSaveViewPropertiesLocally )
+ m_defaultProps->setDirsFirst( first );
+ else if (currentConfig())
+ {
+ KConfigGroupSaver cgs(currentConfig(), currentGroup());
+ currentConfig()->writeEntry( "SortDirsFirst", d->dirsfirst );
+ currentConfig()->sync();
+ }
+}
+
+void KonqPropsView::setDescending( bool descend)
+{
+ d->descending = descend;
+ if ( m_defaultProps && !m_bSaveViewPropertiesLocally )
+ m_defaultProps->setDescending( descend );
+ else if (currentConfig())
+ {
+ KConfigGroupSaver cgs(currentConfig(), currentGroup());
+ currentConfig()->writeEntry( "SortDescending", d->descending );
+ currentConfig()->sync();
+ }
+}
+
+void KonqPropsView::setShowingDotFiles( bool show )
+{
+ kdDebug(1203) << "KonqPropsView::setShowingDotFiles " << show << endl;
+ m_bShowDot = show;
+ if ( m_defaultProps && !m_bSaveViewPropertiesLocally )
+ {
+ kdDebug(1203) << "Saving in default properties" << endl;
+ m_defaultProps->setShowingDotFiles( show );
+ }
+ else if (currentConfig())
+ {
+ kdDebug(1203) << "Saving in current config" << endl;
+ KConfigGroupSaver cgs(currentConfig(), currentGroup());
+ currentConfig()->writeEntry( "ShowDotFiles", m_bShowDot );
+ currentConfig()->sync();
+ }
+}
+
+void KonqPropsView::setCaseInsensitiveSort( bool on )
+{
+ kdDebug(1203) << "KonqPropsView::setCaseInsensitiveSort " << on << endl;
+ d->caseInsensitiveSort = on;
+ if ( m_defaultProps && !m_bSaveViewPropertiesLocally )
+ {
+ kdDebug(1203) << "Saving in default properties" << endl;
+ m_defaultProps->setCaseInsensitiveSort( on );
+ }
+ else if (currentConfig())
+ {
+ kdDebug(1203) << "Saving in current config" << endl;
+ KConfigGroupSaver cgs(currentConfig(), currentGroup());
+ currentConfig()->writeEntry( "CaseInsensitiveSort", d->caseInsensitiveSort );
+ currentConfig()->sync();
+ }
+}
+
+void KonqPropsView::setShowingDirectoryOverlays( bool show )
+{
+ kdDebug(1203) << "KonqPropsView::setShowingDirectoryOverlays " << show << endl;
+ m_bShowDirectoryOverlays = show;
+ if ( m_defaultProps && !m_bSaveViewPropertiesLocally )
+ {
+ kdDebug(1203) << "Saving in default properties" << endl;
+ m_defaultProps->setShowingDirectoryOverlays( show );
+ }
+ else if (currentConfig())
+ {
+ kdDebug(1203) << "Saving in current config" << endl;
+ KConfigGroupSaver cgs(currentConfig(), currentGroup());
+ currentConfig()->writeEntry( "ShowDirectoryOverlays", m_bShowDirectoryOverlays );
+ currentConfig()->sync();
+ }
+}
+
+void KonqPropsView::setShowingPreview( const QString &preview, bool show )
+{
+ if ( m_dontPreview.contains( preview ) != show )
+ return;
+ else if ( show )
+ m_dontPreview.remove( preview );
+ else
+ m_dontPreview.append( preview );
+ if ( m_defaultProps && !m_bSaveViewPropertiesLocally )
+ m_defaultProps->setShowingPreview( preview, show );
+ else if (currentConfig())
+ {
+ KConfigGroupSaver cgs(currentConfig(), currentGroup());
+
+ //Audio is special-cased, as we use a binary setting
+ //for it to get it to follow the defaults right.
+ bool audioEnabled = !m_dontPreview.contains("audio/");
+
+ //Don't write it out into the DontPreview line
+ if (!audioEnabled)
+ m_dontPreview.remove("audio/");
+ currentConfig()->writeEntry( "DontPreview", m_dontPreview );
+ currentConfig()->writeEntry( "EnableSoundPreviews", audioEnabled );
+ currentConfig()->sync();
+ if (!audioEnabled)
+ m_dontPreview.append("audio/");
+
+ }
+
+ delete d->previewsToShow;
+ d->previewsToShow = 0;
+}
+
+void KonqPropsView::setShowingPreview( bool show )
+{
+ d->previewsEnabled = show;
+
+ if ( m_defaultProps && !m_bSaveViewPropertiesLocally )
+ {
+ kdDebug(1203) << "Saving in default properties" << endl;
+ m_defaultProps-> setShowingPreview( show );
+ }
+ else if (currentConfig())
+ {
+ kdDebug(1203) << "Saving in current config" << endl;
+ KConfigGroupSaver cgs(currentConfig(), currentGroup());
+ currentConfig()->writeEntry( "PreviewsEnabled", d->previewsEnabled );
+ currentConfig()->sync();
+ }
+
+ delete d->previewsToShow;
+ d->previewsToShow = 0;
+}
+
+bool KonqPropsView::isShowingPreview()
+{
+ return d->previewsEnabled;
+}
+
+void KonqPropsView::setBgColor( const QColor & color )
+{
+ m_bgColor = color;
+ if ( m_defaultProps && !m_bSaveViewPropertiesLocally )
+ {
+ m_defaultProps->setBgColor( color );
+ }
+ else
+ {
+ KConfigBase * colorConfig = currentColorConfig();
+ if (colorConfig) // 0L when saving locally but remote URL
+ {
+ KConfigGroupSaver cgs(colorConfig, currentGroup());
+ colorConfig->writeEntry( "BgColor", m_bgColor );
+ colorConfig->sync();
+ }
+ }
+}
+
+const QColor & KonqPropsView::bgColor( QWidget * widget ) const
+{
+ if ( !m_bgColor.isValid() )
+ return widget->colorGroup().base();
+ else
+ return m_bgColor;
+}
+
+void KonqPropsView::setTextColor( const QColor & color )
+{
+ m_textColor = color;
+ if ( m_defaultProps && !m_bSaveViewPropertiesLocally )
+ {
+ m_defaultProps->setTextColor( color );
+ }
+ else
+ {
+ KConfigBase * colorConfig = currentColorConfig();
+ if (colorConfig) // 0L when saving locally but remote URL
+ {
+ KConfigGroupSaver cgs(colorConfig, currentGroup());
+ colorConfig->writeEntry( "TextColor", m_textColor );
+ colorConfig->sync();
+ }
+ }
+}
+
+const QColor & KonqPropsView::textColor( QWidget * widget ) const
+{
+ if ( !m_textColor.isValid() )
+ return widget->colorGroup().text();
+ else
+ return m_textColor;
+}
+
+void KonqPropsView::setBgPixmapFile( const QString & file )
+{
+ m_bgPixmapFile = file;
+
+ if ( m_defaultProps && !m_bSaveViewPropertiesLocally )
+ {
+ m_defaultProps->setBgPixmapFile( file );
+ }
+ else
+ {
+ KConfigBase * colorConfig = currentColorConfig();
+ if (colorConfig) // 0L when saving locally but remote URL
+ {
+ KConfigGroupSaver cgs(colorConfig, currentGroup());
+ colorConfig->writePathEntry( "BgImage", file );
+ colorConfig->sync();
+ }
+ }
+}
+
+QPixmap KonqPropsView::loadPixmap() const
+{
+ //kdDebug(1203) << "KonqPropsView::loadPixmap " << m_bgPixmapFile << endl;
+ QPixmap bgPixmap;
+ if ( !m_bgPixmapFile.isEmpty() )
+ bgPixmap = wallpaperPixmap( m_bgPixmapFile );
+ return bgPixmap;
+}
+
+void KonqPropsView::applyColors(QWidget * widget) const
+{
+ if ( m_bgPixmapFile.isEmpty() )
+ widget->setPaletteBackgroundColor( bgColor( widget ) );
+ else
+ {
+ QPixmap pix = loadPixmap();
+ // don't set an null pixmap, as this leads to
+ // undefined results with regards to the background of widgets
+ // that have the iconview as a parent and on the iconview itself
+ // e.g. the rename textedit widget when renaming a QIconViewItem
+ // Qt-issue: N64698
+ if ( ! pix.isNull() )
+ widget->setBackgroundPixmap( pix );
+ // setPaletteBackgroundPixmap leads to flicker on window activation(!)
+ }
+
+ if ( m_textColor.isValid() )
+ widget->setPaletteForegroundColor( m_textColor );
+}
+
+const QStringList& KonqPropsView::previewSettings()
+{
+ if ( ! d->previewsToShow )
+ {
+ d->previewsToShow = new QStringList;
+
+ if (d->previewsEnabled) {
+ KTrader::OfferList plugins = KTrader::self()->query( "ThumbCreator" );
+ for ( KTrader::OfferList::ConstIterator it = plugins.begin(); it != plugins.end(); ++it )
+ {
+ QString name = (*it)->desktopEntryName();
+ if ( ! m_dontPreview.contains(name) )
+ d->previewsToShow->append( name );
+ }
+ if ( ! m_dontPreview.contains( "audio/" ) )
+ d->previewsToShow->append( "audio/" );
+ }
+ }
+
+ return *(d->previewsToShow);
+}
+
+const QString& KonqPropsView::sortCriterion() const {
+ return d->sortcriterion;
+}
+
diff --git a/libkonq/konq_propsview.h b/libkonq/konq_propsview.h
new file mode 100644
index 000000000..679ce8a0e
--- /dev/null
+++ b/libkonq/konq_propsview.h
@@ -0,0 +1,185 @@
+/* This file is part of the KDE project
+ Copyright (C) 1997 David Faure <faure@kde.org>
+
+ 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 __konq_viewprops_h__
+#define __konq_viewprops_h__
+
+#include <qpixmap.h>
+#include <qstringlist.h>
+
+#include <kurl.h>
+#include <libkonq_export.h>
+
+class KInstance;
+class KConfigBase;
+class KConfig;
+
+/**
+ * The class KonqPropsView holds the properties for a Konqueror View
+ *
+ * Separating them from the view class allows to store the default
+ * values (the one read from \<kinstance\>rc) in one instance of this class
+ * and to have another instance of this class in each view, storing the
+ * current values of the view.
+ *
+ * The local values can be read from a desktop entry, if any (.directory,
+ * bookmark, ...). [ .directory is implemented, bookmark isn't ].
+ */
+class LIBKONQ_EXPORT KonqPropsView
+{
+public:
+
+ /**
+ * Constructs a KonqPropsView instance from an instance config file.
+ * defaultProps is a "parent" object. If non null, then this instance
+ * is the one used by a view, and its value can differ from the default ones.
+ * The instance parameter should be the same for both...
+ */
+ KonqPropsView( KInstance * instance, KonqPropsView * defaultProps /*= 0L*/ );
+
+ /** Destructor */
+ virtual ~KonqPropsView();
+
+ /**
+ * Is this the instance representing default properties ?
+ */
+ bool isDefaultProperties() const {
+ // No parent -> we are the default properties
+ return m_defaultProps == 0L;
+ }
+
+ /**
+ * Called when entering a directory
+ * Checks for a .directory, read it.
+ * Don't do this on the default properties instance
+ * Returns TRUE if the settings for the new directories are
+ * different from the settings in the old directory.
+ */
+ bool enterDir( const KURL & dir );
+
+ /**
+ * Turn on/off saving properties locally
+ * Don't do this on the default properties instance
+ */
+ void setSaveViewPropertiesLocally( bool value );
+
+ ///
+
+ void setIconSize( int size ); // in pixel, 0 for default
+ int iconSize() const { return m_iIconSize; }
+
+ void setItemTextPos( int pos ); // QIconView::Bottom or QIconView::Right, currently
+ int itemTextPos() const { return m_iItemTextPos; }
+
+ void setSortCriterion( const QString &criterion );
+ const QString& sortCriterion() const;
+
+ void setDirsFirst ( bool first );
+ bool isDirsFirst() const;
+
+ void setDescending (bool descending);
+ bool isDescending() const;
+
+ void setShowingDotFiles( bool show );
+ bool isShowingDotFiles() const { return m_bShowDot; }
+
+ void setCaseInsensitiveSort( bool show );
+ bool isCaseInsensitiveSort() const;
+
+ void setShowingDirectoryOverlays( bool show );
+ bool isShowingDirectoryOverlays() const { return m_bShowDirectoryOverlays; }
+
+ void setShowingPreview( const QString &preview, bool show );
+ void setShowingPreview( bool show );
+ bool isShowingPreview( const QString &preview ) const { return ! m_dontPreview.contains(preview); }
+ bool isShowingPreview();
+ const QStringList &previewSettings();
+
+ void setBgColor( const QColor & color );
+ const QColor& bgColor(QWidget * widget) const;
+ void setTextColor( const QColor & color );
+ const QColor& textColor(QWidget * widget) const;
+ void setBgPixmapFile( const QString & file );
+ const QString& bgPixmapFile() const { return m_bgPixmapFile; }
+
+ // Applies bgcolor, textcolor, pixmap to the @p widget
+ void applyColors( QWidget * widget ) const;
+
+protected:
+
+ QPixmap loadPixmap() const;
+
+ // Current config object for _saving_
+ KConfigBase * currentConfig();
+
+ // Current config object for _saving_ settings related to colors
+ KConfigBase * currentColorConfig();
+
+ QString currentGroup() const {
+ return isDefaultProperties() ?
+ QString::fromLatin1("Settings") : QString::fromLatin1("URL properties");
+ }
+
+private:
+ // The actual properties
+
+ int m_iIconSize;
+ int m_iItemTextPos;
+ bool m_bShowDot;
+ bool m_bShowDirectoryOverlays;
+ QStringList m_dontPreview;
+ QColor m_textColor;
+ QColor m_bgColor;
+ QString m_bgPixmapFile;
+
+ // Path to .directory file, whether it exists or not
+ QString dotDirectory;
+
+ bool m_bSaveViewPropertiesLocally;
+
+ // True if we found a .directory file to read
+ bool m_dotDirExists;
+
+ // Points to the current .directory file if we are in
+ // save-view-properties-locally mode, otherwise to the global config
+ // It is set to 0L to mark it as "needs to be constructed".
+ // This is to be used for SAVING only.
+ // Can be a KConfig or a KSimpleConfig
+ KConfigBase * m_currentConfig;
+
+ // If this is not a "default properties" instance (but one used by a view)
+ // then m_defaultProps points to the "default properties" instance
+ // Otherwise it's 0L.
+ KonqPropsView * m_defaultProps;
+
+ /**
+ * Private data for KonqPropsView
+ * Implementation in konq_propsview.cc
+ */
+ struct Private;
+
+ Private *d;
+
+private:
+ KonqPropsView( const KonqPropsView & );
+ KonqPropsView();
+};
+
+
+#endif
diff --git a/libkonq/konq_settings.cc b/libkonq/konq_settings.cc
new file mode 100644
index 000000000..07866b08b
--- /dev/null
+++ b/libkonq/konq_settings.cc
@@ -0,0 +1,184 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "konq_settings.h"
+#include "konq_defaults.h"
+#include "kglobalsettings.h"
+#include <kglobal.h>
+#include <kservicetype.h>
+#include <kdesktopfile.h>
+#include <kdebug.h>
+#include <assert.h>
+#include <qfontmetrics.h>
+
+struct KonqFMSettingsPrivate
+{
+ KonqFMSettingsPrivate() {
+ showPreviewsInFileTips = true;
+ m_renameIconDirectly = false;
+ }
+
+ bool showPreviewsInFileTips;
+ bool m_renameIconDirectly;
+ bool localeAwareCompareIsCaseSensitive;
+ int m_iconTextWidth;
+};
+
+//static
+KonqFMSettings * KonqFMSettings::s_pSettings = 0L;
+
+//static
+KonqFMSettings * KonqFMSettings::settings()
+{
+ if (!s_pSettings)
+ {
+ KConfig *config = KGlobal::config();
+ KConfigGroupSaver cgs(config, "FMSettings");
+ s_pSettings = new KonqFMSettings(config);
+ }
+ return s_pSettings;
+}
+
+//static
+void KonqFMSettings::reparseConfiguration()
+{
+ if (s_pSettings)
+ {
+ KConfig *config = KGlobal::config();
+ KConfigGroupSaver cgs(config, "FMSettings");
+ s_pSettings->init( config );
+ }
+}
+
+KonqFMSettings::KonqFMSettings( KConfig * config )
+{
+ d = new KonqFMSettingsPrivate;
+ init( config );
+}
+
+KonqFMSettings::~KonqFMSettings()
+{
+ delete d;
+}
+
+void KonqFMSettings::init( KConfig * config )
+{
+ // Fonts and colors
+ m_standardFont = config->readFontEntry( "StandardFont" );
+
+ m_normalTextColor = KGlobalSettings::textColor();
+ m_normalTextColor = config->readColorEntry( "NormalTextColor", &m_normalTextColor );
+ m_highlightedTextColor = KGlobalSettings::highlightedTextColor();
+ m_highlightedTextColor = config->readColorEntry( "HighlightedTextColor", &m_highlightedTextColor );
+ m_itemTextBackground = config->readColorEntry( "ItemTextBackground" );
+
+ d->m_iconTextWidth = config->readNumEntry( "TextWidth", DEFAULT_TEXTWIDTH );
+ if ( d->m_iconTextWidth == DEFAULT_TEXTWIDTH )
+ d->m_iconTextWidth = QFontMetrics(m_standardFont).width("0000000000");
+
+ m_iconTextHeight = config->readNumEntry( "TextHeight", 0 );
+ if ( m_iconTextHeight == 0 ) {
+ if ( config->readBoolEntry( "WordWrapText", true ) )
+ m_iconTextHeight = DEFAULT_TEXTHEIGHT;
+ else
+ m_iconTextHeight = 1;
+ }
+ m_bWordWrapText = ( m_iconTextHeight > 1 );
+
+ m_underlineLink = config->readBoolEntry( "UnderlineLinks", DEFAULT_UNDERLINELINKS );
+ d->m_renameIconDirectly = config->readBoolEntry( "RenameIconDirectly", DEFAULT_RENAMEICONDIRECTLY );
+ m_fileSizeInBytes = config->readBoolEntry( "DisplayFileSizeInBytes", DEFAULT_FILESIZEINBYTES );
+ m_iconTransparency = config->readNumEntry( "TextpreviewIconOpacity", DEFAULT_TEXTPREVIEW_ICONTRANSPARENCY );
+ if ( m_iconTransparency < 0 || m_iconTransparency > 255 )
+ m_iconTransparency = DEFAULT_TEXTPREVIEW_ICONTRANSPARENCY;
+
+ // Behaviour
+ m_alwaysNewWin = config->readBoolEntry( "AlwaysNewWin", FALSE );
+
+ m_homeURL = config->readPathEntry("HomeURL", "~");
+
+ m_showFileTips = config->readBoolEntry("ShowFileTips", true);
+ d->showPreviewsInFileTips = config->readBoolEntry("ShowPreviewsInFileTips", true);
+ m_numFileTips = config->readNumEntry("FileTipsItems", 6);
+
+ m_embedMap = config->entryMap( "EmbedSettings" );
+
+ /// true if QString::localeAwareCompare is case sensitive (it usually isn't, when LC_COLLATE is set)
+ d->localeAwareCompareIsCaseSensitive = QString( "a" ).localeAwareCompare( "B" ) > 0; // see #40131
+}
+
+bool KonqFMSettings::shouldEmbed( const QString & serviceType ) const
+{
+ // First check in user's settings whether to embed or not
+ // 1 - in the mimetype file itself
+ KServiceType::Ptr serviceTypePtr = KServiceType::serviceType( serviceType );
+ bool hasLocalProtocolRedirect = false;
+ if ( serviceTypePtr )
+ {
+ hasLocalProtocolRedirect = !serviceTypePtr->property( "X-KDE-LocalProtocol" ).toString().isEmpty();
+ QVariant autoEmbedProp = serviceTypePtr->property( "X-KDE-AutoEmbed" );
+ if ( autoEmbedProp.isValid() )
+ {
+ bool autoEmbed = autoEmbedProp.toBool();
+ kdDebug(1203) << "X-KDE-AutoEmbed set to " << (autoEmbed ? "true" : "false") << endl;
+ return autoEmbed;
+ } else
+ kdDebug(1203) << "No X-KDE-AutoEmbed, looking for group" << endl;
+ }
+ // 2 - in the configuration for the group if nothing was found in the mimetype
+ QString serviceTypeGroup = serviceType.left(serviceType.find("/"));
+ kdDebug(1203) << "KonqFMSettings::shouldEmbed : serviceTypeGroup=" << serviceTypeGroup << endl;
+ if ( serviceTypeGroup == "inode" || serviceTypeGroup == "Browser" || serviceTypeGroup == "Konqueror" )
+ return true; //always embed mimetype inode/*, Browser/* and Konqueror/*
+ QMap<QString, QString>::ConstIterator it = m_embedMap.find( QString::fromLatin1("embed-")+serviceTypeGroup );
+ if ( it != m_embedMap.end() ) {
+ kdDebug(1203) << "KonqFMSettings::shouldEmbed: " << it.data() << endl;
+ return it.data() == QString::fromLatin1("true");
+ }
+ // 3 - if no config found, use default.
+ // Note: if you change those defaults, also change kcontrol/filetypes/typeslistitem.cpp !
+ // Embedding is false by default except for image/* and for zip, tar etc.
+ if ( serviceTypeGroup == "image" || hasLocalProtocolRedirect )
+ return true;
+ return false;
+}
+
+bool KonqFMSettings::showPreviewsInFileTips() const
+{
+ return d->showPreviewsInFileTips;
+}
+
+bool KonqFMSettings::renameIconDirectly() const
+{
+ return d->m_renameIconDirectly;
+}
+
+int KonqFMSettings::caseSensitiveCompare( const QString& a, const QString& b ) const
+{
+ if ( d->localeAwareCompareIsCaseSensitive ) {
+ return a.localeAwareCompare( b );
+ }
+ else // can't use localeAwareCompare, have to fallback to normal QString compare
+ return a.compare( b );
+}
+
+int KonqFMSettings::iconTextWidth() const
+{
+ return d->m_iconTextWidth;
+}
diff --git a/libkonq/konq_settings.h b/libkonq/konq_settings.h
new file mode 100644
index 000000000..8f3d981fc
--- /dev/null
+++ b/libkonq/konq_settings.h
@@ -0,0 +1,141 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __konq_settings_h__
+#define __konq_settings_h__
+
+class KConfig;
+#include <qcolor.h>
+#include <qstring.h>
+#include <qfont.h>
+#include <qmap.h>
+
+#include <libkonq_export.h>
+
+/**
+ * The class KonqFMSettings holds the general settings for the
+ * icon/tree views in konqueror/kdesktop.
+ * There is no 'local' (per-URL) instance of it.
+ * All those settings can only be changed in kcmkonq.
+ *
+ * Using this class from konqueror and from kdesktop return
+ * different settings, since the config file is different.
+ * konquerorrc, group "FMSettings", and kdesktoprc, group "FMSettings"
+ * The kcontrol modules handles both files, depending where
+ * it's called from.
+ */
+
+class LIBKONQ_EXPORT KonqFMSettings
+{
+protected:
+ /**
+ * @internal
+ * Constructs a KonqFMSettings instance from a config file.
+ */
+ KonqFMSettings( KConfig * config );
+
+ /** Destructor. Don't delete any instance by yourself. */
+ virtual ~KonqFMSettings();
+
+public:
+
+ /**
+ * The static instance of KonqFMSettings
+ */
+ static KonqFMSettings * settings();
+
+ /**
+ * Reparse the configuration to update the already-created instances
+ *
+ * Warning : you need to call KGlobal::config()->reparseConfiguration()
+ * first (This is not done here so that the caller can avoid too much
+ * reparsing if having several classes from the same config file)
+ */
+ static void reparseConfiguration();
+
+ // Use settings (and mimetype definition files)
+ // to find whether to embed a certain service type or not
+ // Only makes sense in konqueror.
+ bool shouldEmbed( const QString & serviceType ) const;
+
+ // Behaviour settings
+ bool wordWrapText() const { return m_bWordWrapText; }
+ int iconTextHeight() const { return m_iconTextHeight; }
+ int iconTextWidth() const;
+ bool underlineLink() const { return m_underlineLink; }
+ bool fileSizeInBytes() const { return m_fileSizeInBytes; }
+ bool alwaysNewWin() const { return m_alwaysNewWin; }
+ const QString & homeURL() const { return m_homeURL; }
+
+ bool showFileTips() const {return m_showFileTips; }
+ bool showPreviewsInFileTips() const;
+ int numFileTips() const {return m_numFileTips; }
+ bool renameIconDirectly() const;
+
+ // Font settings
+ const QFont& standardFont() const { return m_standardFont; }
+
+ // Color settings
+ const QColor& normalTextColor() const { return m_normalTextColor; }
+ const QColor& highlightedTextColor() const { return m_highlightedTextColor; }
+ const QColor& itemTextBackground() const { return m_itemTextBackground; }
+
+ int textPreviewIconTransparency() const { return m_iconTransparency; }
+
+ int caseSensitiveCompare( const QString& a, const QString& b ) const;
+
+private:
+
+ static KonqFMSettings * s_pSettings;
+
+ bool m_underlineLink;
+ bool m_fileSizeInBytes;
+ bool m_alwaysNewWin;
+ bool m_bTreeFollow;
+
+ QMap<QString, QString> m_embedMap;
+
+ QFont m_standardFont;
+
+ QColor m_normalTextColor;
+ QColor m_highlightedTextColor;
+ QColor m_itemTextBackground;
+
+ bool m_bWordWrapText;
+ int m_iconTextHeight;
+
+ QString m_homeURL;
+ bool m_showFileTips;
+ int m_numFileTips;
+
+ // used for the textpreview
+ int m_iconTransparency;
+
+ /** Called by constructor and reparseConfiguration */
+ void init( KConfig * config );
+
+ struct KonqFMSettingsPrivate * d;
+
+ // There is no default constructor. Use the provided ones.
+ KonqFMSettings();
+ // No copy constructor either. What for ?
+ KonqFMSettings( const KonqFMSettings &);
+};
+
+#endif
diff --git a/libkonq/konq_sound.cc b/libkonq/konq_sound.cc
new file mode 100644
index 000000000..c609df553
--- /dev/null
+++ b/libkonq/konq_sound.cc
@@ -0,0 +1,137 @@
+/* This file is part of the KDE Project
+ Copyright (c) 2001 Malte Starostik <malte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kartsdispatcher.h>
+#include <kdebug.h>
+#include <kplayobjectfactory.h>
+#include <soundserver.h>
+
+#include "konq_sound.h"
+
+using namespace std;
+
+class KonqSoundPlayerImpl : public KonqSoundPlayer
+{
+public:
+ KonqSoundPlayerImpl();
+ virtual ~KonqSoundPlayerImpl();
+
+ virtual const QStringList &mimeTypes();
+ virtual void play(const QString &fileName);
+ virtual void stop();
+ virtual bool isPlaying();
+
+private:
+ QStringList m_mimeTypes;
+
+ KArtsDispatcher m_dispatcher;
+ Arts::SoundServerV2 m_soundServer;
+ KDE::PlayObjectFactory *m_factory;
+ KDE::PlayObject *m_player;
+};
+
+KonqSoundPlayerImpl::KonqSoundPlayerImpl()
+ : m_player(0)
+{
+ m_soundServer = Arts::Reference("global:Arts_SoundServerV2");
+ m_factory = new KDE::PlayObjectFactory(m_soundServer);
+}
+
+KonqSoundPlayerImpl::~KonqSoundPlayerImpl()
+{
+ delete m_player;
+ delete m_factory;
+}
+
+const QStringList &KonqSoundPlayerImpl::mimeTypes()
+{
+ if (m_mimeTypes.isEmpty())
+ {
+ Arts::TraderQuery query;
+ vector<Arts::TraderOffer> *offers = query.query();
+
+ for (vector<Arts::TraderOffer>::iterator it = offers->begin();
+ it != offers->end(); ++it)
+ {
+ vector<string> *prop = (*it).getProperty("MimeType");
+ for (vector<string>::iterator mt = prop->begin();
+ mt != prop->end(); ++mt)
+ if ((*mt).length()) // && (*mt).find("video/") == string::npos)
+ m_mimeTypes << (*mt).c_str();
+ delete prop;
+ }
+ delete offers;
+ }
+ return m_mimeTypes;
+}
+
+void KonqSoundPlayerImpl::play(const QString &fileName)
+{
+ if (m_soundServer.isNull())
+ return;
+
+ delete m_player;
+ if ((m_player = m_factory->createPlayObject(fileName, true)))
+ {
+ if (m_player->isNull())
+ stop();
+ else
+ m_player->play();
+ }
+}
+
+void KonqSoundPlayerImpl::stop()
+{
+ delete m_player;
+ m_player = 0;
+}
+
+bool KonqSoundPlayerImpl::isPlaying()
+{
+ return m_player ? (m_player->state() == Arts::posPlaying) : false;
+}
+
+class KonqSoundFactory : public KLibFactory
+{
+public:
+ KonqSoundFactory(QObject *parent = 0, const char *name = 0)
+ : KLibFactory(parent, name) {};
+ virtual ~KonqSoundFactory() {};
+
+protected:
+ virtual QObject *createObject(QObject * = 0, const char * = 0,
+ const char *className = "QObject", const QStringList &args = QStringList());
+};
+
+QObject *KonqSoundFactory::createObject(QObject *, const char *,
+ const char *className, const QStringList &)
+{
+ if (qstrcmp(className, "KonqSoundPlayer") == 0)
+ return new KonqSoundPlayerImpl();
+ return 0;
+}
+
+extern "C"
+{
+ KDE_EXPORT KLibFactory *init_konq_sound()
+ {
+ return new KonqSoundFactory();
+ }
+}
+
+// vim: ts=4 sw=4 noet
diff --git a/libkonq/konq_sound.h b/libkonq/konq_sound.h
new file mode 100644
index 000000000..78fcc968b
--- /dev/null
+++ b/libkonq/konq_sound.h
@@ -0,0 +1,35 @@
+/* This file is part of the KDE Project
+ Copyright (c) 2001 Malte Starostik <malte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __konq_sound_h__
+#define __konq_sound_h__
+
+#include <klibloader.h>
+
+class KonqSoundPlayer : public QObject
+{
+public:
+ virtual const QStringList &mimeTypes() = 0;
+ virtual void play(const QString &fileName) = 0;
+ virtual void stop() = 0;
+ virtual bool isPlaying() = 0;
+};
+
+#endif
+
+// vim: ts=4 sw=4 noet
diff --git a/libkonq/konq_undo.cc b/libkonq/konq_undo.cc
new file mode 100644
index 000000000..7f8d1a4c6
--- /dev/null
+++ b/libkonq/konq_undo.cc
@@ -0,0 +1,667 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000 Simon Hausmann <hausmann@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "konq_undo.h"
+
+#undef Always
+
+#include <kio/uiserver_stub.h>
+#include "konq_operations.h"
+
+#include <assert.h>
+
+#include <dcopclient.h>
+#include <dcopref.h>
+
+#include <kapplication.h>
+#include <kdatastream.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kglobalsettings.h>
+#include <kconfig.h>
+#include <kipc.h>
+
+#include <kio/job.h>
+#include <kdirnotify_stub.h>
+
+inline const char *dcopTypeName( const KonqCommand & ) { return "KonqCommand"; }
+inline const char *dcopTypeName( const KonqCommand::Stack & ) { return "KonqCommand::Stack"; }
+
+/**
+ * checklist:
+ * copy dir -> overwrite -> works
+ * move dir -> overwrite -> works
+ * copy dir -> rename -> works
+ * move dir -> rename -> works
+ *
+ * copy dir -> works
+ * move dir -> works
+ *
+ * copy files -> works
+ * move files -> works (TODO: optimize (change FileCopyJob to use the renamed arg for copyingDone)
+ *
+ * copy files -> overwrite -> works
+ * move files -> overwrite -> works
+ *
+ * copy files -> rename -> works
+ * move files -> rename -> works
+ */
+
+class KonqUndoJob : public KIO::Job
+{
+public:
+ KonqUndoJob() : KIO::Job( true ) { KonqUndoManager::incRef(); };
+ virtual ~KonqUndoJob() { KonqUndoManager::decRef(); }
+
+ virtual void kill( bool q) { KonqUndoManager::self()->stopUndo( true ); KIO::Job::kill( q ); }
+};
+
+class KonqCommandRecorder::KonqCommandRecorderPrivate
+{
+public:
+ KonqCommandRecorderPrivate()
+ {
+ }
+ ~KonqCommandRecorderPrivate()
+ {
+ }
+
+ KonqCommand m_cmd;
+};
+
+KonqCommandRecorder::KonqCommandRecorder( KonqCommand::Type op, const KURL::List &src, const KURL &dst, KIO::Job *job )
+ : QObject( job, "konqcmdrecorder" )
+{
+ d = new KonqCommandRecorderPrivate;
+ d->m_cmd.m_type = op;
+ d->m_cmd.m_valid = true;
+ d->m_cmd.m_src = src;
+ d->m_cmd.m_dst = dst;
+ connect( job, SIGNAL( result( KIO::Job * ) ),
+ this, SLOT( slotResult( KIO::Job * ) ) );
+
+ if ( op != KonqCommand::MKDIR ) {
+ connect( job, SIGNAL( copyingDone( KIO::Job *, const KURL &, const KURL &, bool, bool ) ),
+ this, SLOT( slotCopyingDone( KIO::Job *, const KURL &, const KURL &, bool, bool ) ) );
+ connect( job, SIGNAL( copyingLinkDone( KIO::Job *, const KURL &, const QString &, const KURL & ) ),
+ this, SLOT( slotCopyingLinkDone( KIO::Job *, const KURL &, const QString &, const KURL & ) ) );
+ }
+
+ KonqUndoManager::incRef();
+}
+
+KonqCommandRecorder::~KonqCommandRecorder()
+{
+ KonqUndoManager::decRef();
+ delete d;
+}
+
+void KonqCommandRecorder::slotResult( KIO::Job *job )
+{
+ if ( job->error() )
+ return;
+
+ KonqUndoManager::self()->addCommand( d->m_cmd );
+}
+
+void KonqCommandRecorder::slotCopyingDone( KIO::Job *job, const KURL &from, const KURL &to, bool directory, bool renamed )
+{
+ KonqBasicOperation op;
+ op.m_valid = true;
+ op.m_directory = directory;
+ op.m_renamed = renamed;
+ op.m_src = from;
+ op.m_dst = to;
+ op.m_link = false;
+
+ if ( d->m_cmd.m_type == KonqCommand::TRASH )
+ {
+ Q_ASSERT( from.isLocalFile() );
+ Q_ASSERT( to.protocol() == "trash" );
+ QMap<QString, QString> metaData = job->metaData();
+ QMap<QString, QString>::ConstIterator it = metaData.find( "trashURL-" + from.path() );
+ if ( it != metaData.end() ) {
+ // Update URL
+ op.m_dst = it.data();
+ }
+ }
+
+ d->m_cmd.m_opStack.prepend( op );
+}
+
+void KonqCommandRecorder::slotCopyingLinkDone( KIO::Job *, const KURL &from, const QString &target, const KURL &to )
+{
+ KonqBasicOperation op;
+ op.m_valid = true;
+ op.m_directory = false;
+ op.m_renamed = false;
+ op.m_src = from;
+ op.m_target = target;
+ op.m_dst = to;
+ op.m_link = true;
+ d->m_cmd.m_opStack.prepend( op );
+}
+
+KonqUndoManager *KonqUndoManager::s_self = 0;
+unsigned long KonqUndoManager::s_refCnt = 0;
+
+class KonqUndoManager::KonqUndoManagerPrivate
+{
+public:
+ KonqUndoManagerPrivate()
+ {
+ m_uiserver = new UIServer_stub( "kio_uiserver", "UIServer" );
+ m_undoJob = 0;
+ }
+ ~KonqUndoManagerPrivate()
+ {
+ delete m_uiserver;
+ }
+
+ bool m_syncronized;
+
+ KonqCommand::Stack m_commands;
+
+ KonqCommand m_current;
+ KIO::Job *m_currentJob;
+ UndoState m_undoState;
+ QValueStack<KURL> m_dirStack;
+ QValueStack<KURL> m_dirCleanupStack;
+ QValueStack<KURL> m_fileCleanupStack;
+ QValueList<KURL> m_dirsToUpdate;
+
+ bool m_lock;
+
+ UIServer_stub *m_uiserver;
+ int m_uiserverJobId;
+
+ KonqUndoJob *m_undoJob;
+};
+
+KonqUndoManager::KonqUndoManager()
+: DCOPObject( "KonqUndoManager" )
+{
+ if ( !kapp->dcopClient()->isAttached() )
+ kapp->dcopClient()->attach();
+
+ d = new KonqUndoManagerPrivate;
+ d->m_syncronized = initializeFromKDesky();
+ d->m_lock = false;
+ d->m_currentJob = 0;
+}
+
+KonqUndoManager::~KonqUndoManager()
+{
+ delete d;
+}
+
+void KonqUndoManager::incRef()
+{
+ s_refCnt++;
+}
+
+void KonqUndoManager::decRef()
+{
+ s_refCnt--;
+ if ( s_refCnt == 0 && s_self )
+ {
+ delete s_self;
+ s_self = 0;
+ }
+}
+
+KonqUndoManager *KonqUndoManager::self()
+{
+ if ( !s_self )
+ {
+ if ( s_refCnt == 0 )
+ s_refCnt++; // someone forgot to call incRef
+ s_self = new KonqUndoManager;
+ }
+ return s_self;
+}
+
+void KonqUndoManager::addCommand( const KonqCommand &cmd )
+{
+ broadcastPush( cmd );
+}
+
+bool KonqUndoManager::undoAvailable() const
+{
+ return ( d->m_commands.count() > 0 ) && !d->m_lock;
+}
+
+QString KonqUndoManager::undoText() const
+{
+ if ( d->m_commands.count() == 0 )
+ return i18n( "Und&o" );
+
+ KonqCommand::Type t = d->m_commands.top().m_type;
+ if ( t == KonqCommand::COPY )
+ return i18n( "Und&o: Copy" );
+ else if ( t == KonqCommand::LINK )
+ return i18n( "Und&o: Link" );
+ else if ( t == KonqCommand::MOVE )
+ return i18n( "Und&o: Move" );
+ else if ( t == KonqCommand::TRASH )
+ return i18n( "Und&o: Trash" );
+ else if ( t == KonqCommand::MKDIR )
+ return i18n( "Und&o: Create Folder" );
+ else
+ assert( false );
+ /* NOTREACHED */
+ return QString::null;
+}
+
+void KonqUndoManager::undo()
+{
+ KonqCommand cmd = d->m_commands.top();
+ assert( cmd.m_valid );
+
+ d->m_current = cmd;
+
+ QValueList<KonqBasicOperation>& opStack = d->m_current.m_opStack;
+
+ // Let's first ask for confirmation if we need to delete any file (#99898)
+ KURL::List fileCleanupStack;
+ QValueList<KonqBasicOperation>::Iterator it = opStack.begin();
+ for ( ; it != opStack.end() ; ++it ) {
+ if ( !(*it).m_directory && !(*it).m_link && d->m_current.m_type == KonqCommand::COPY ) {
+ fileCleanupStack.append( (*it).m_dst );
+ }
+ }
+ if ( !fileCleanupStack.isEmpty() ) {
+ // Because undo can happen with an accidental Ctrl-Z, we want to always confirm.
+ if ( !KonqOperations::askDeleteConfirmation( fileCleanupStack, KonqOperations::DEL,
+ KonqOperations::FORCE_CONFIRMATION,
+ 0 /* TODO parent */ ) )
+ return;
+ }
+
+ d->m_dirCleanupStack.clear();
+ d->m_dirStack.clear();
+ d->m_dirsToUpdate.clear();
+
+ d->m_undoState = MOVINGFILES;
+
+ broadcastPop();
+ broadcastLock();
+
+ it = opStack.begin();
+ QValueList<KonqBasicOperation>::Iterator end = opStack.end();
+ while ( it != end )
+ {
+ if ( (*it).m_directory && !(*it).m_renamed )
+ {
+ d->m_dirStack.push( (*it).m_src );
+ d->m_dirCleanupStack.prepend( (*it).m_dst );
+ it = d->m_current.m_opStack.remove( it );
+ d->m_undoState = MAKINGDIRS;
+ kdDebug(1203) << "KonqUndoManager::undo MAKINGDIRS" << endl;
+ }
+ else if ( (*it).m_link )
+ {
+ if ( !d->m_fileCleanupStack.contains( (*it).m_dst ) )
+ d->m_fileCleanupStack.prepend( (*it).m_dst );
+
+ if ( d->m_current.m_type != KonqCommand::MOVE )
+ it = d->m_current.m_opStack.remove( it );
+ else
+ ++it;
+ }
+ else
+ ++it;
+ }
+
+ /* this shouldn't be necessary at all:
+ * 1) the source list may contain files, we don't want to
+ * create those as... directories
+ * 2) all directories that need creation should already be in the
+ * directory stack
+ if ( d->m_undoState == MAKINGDIRS )
+ {
+ KURL::List::ConstIterator it = d->m_current.m_src.begin();
+ KURL::List::ConstIterator end = d->m_current.m_src.end();
+ for (; it != end; ++it )
+ if ( !d->m_dirStack.contains( *it) )
+ d->m_dirStack.push( *it );
+ }
+ */
+
+ if ( d->m_current.m_type != KonqCommand::MOVE )
+ d->m_dirStack.clear();
+
+ d->m_undoJob = new KonqUndoJob;
+ d->m_uiserverJobId = d->m_undoJob->progressId();
+ undoStep();
+}
+
+void KonqUndoManager::stopUndo( bool step )
+{
+ d->m_current.m_opStack.clear();
+ d->m_dirCleanupStack.clear();
+ d->m_fileCleanupStack.clear();
+ d->m_undoState = REMOVINGDIRS;
+ d->m_undoJob = 0;
+
+ if ( d->m_currentJob )
+ d->m_currentJob->kill( true );
+
+ d->m_currentJob = 0;
+
+ if ( step )
+ undoStep();
+}
+
+void KonqUndoManager::slotResult( KIO::Job *job )
+{
+ d->m_uiserver->jobFinished( d->m_uiserverJobId );
+ if ( job->error() )
+ {
+ job->showErrorDialog( 0L );
+ d->m_currentJob = 0;
+ stopUndo( false );
+ if ( d->m_undoJob )
+ {
+ delete d->m_undoJob;
+ d->m_undoJob = 0;
+ }
+ }
+
+ undoStep();
+}
+
+
+void KonqUndoManager::addDirToUpdate( const KURL& url )
+{
+ if ( d->m_dirsToUpdate.find( url ) == d->m_dirsToUpdate.end() )
+ d->m_dirsToUpdate.prepend( url );
+}
+
+void KonqUndoManager::undoStep()
+{
+ d->m_currentJob = 0;
+
+ if ( d->m_undoState == MAKINGDIRS )
+ undoMakingDirectories();
+
+ if ( d->m_undoState == MOVINGFILES )
+ undoMovingFiles();
+
+ if ( d->m_undoState == REMOVINGFILES )
+ undoRemovingFiles();
+
+ if ( d->m_undoState == REMOVINGDIRS )
+ undoRemovingDirectories();
+
+ if ( d->m_currentJob )
+ connect( d->m_currentJob, SIGNAL( result( KIO::Job * ) ),
+ this, SLOT( slotResult( KIO::Job * ) ) );
+}
+
+void KonqUndoManager::undoMakingDirectories()
+{
+ if ( !d->m_dirStack.isEmpty() ) {
+ KURL dir = d->m_dirStack.pop();
+ kdDebug(1203) << "KonqUndoManager::undoStep creatingDir " << dir.prettyURL() << endl;
+ d->m_currentJob = KIO::mkdir( dir );
+ d->m_uiserver->creatingDir( d->m_uiserverJobId, dir );
+ }
+ else
+ d->m_undoState = MOVINGFILES;
+}
+
+void KonqUndoManager::undoMovingFiles()
+{
+ if ( !d->m_current.m_opStack.isEmpty() )
+ {
+ KonqBasicOperation op = d->m_current.m_opStack.pop();
+
+ assert( op.m_valid );
+ if ( op.m_directory )
+ {
+ if ( op.m_renamed )
+ {
+ kdDebug(1203) << "KonqUndoManager::undoStep rename " << op.m_dst.prettyURL() << " " << op.m_src.prettyURL() << endl;
+ d->m_currentJob = KIO::rename( op.m_dst, op.m_src, false );
+ d->m_uiserver->moving( d->m_uiserverJobId, op.m_dst, op.m_src );
+ }
+ else
+ assert( 0 ); // this should not happen!
+ }
+ else if ( op.m_link )
+ {
+ kdDebug(1203) << "KonqUndoManager::undoStep symlink " << op.m_target << " " << op.m_src.prettyURL() << endl;
+ d->m_currentJob = KIO::symlink( op.m_target, op.m_src, true, false );
+ }
+ else if ( d->m_current.m_type == KonqCommand::COPY )
+ {
+ kdDebug(1203) << "KonqUndoManager::undoStep file_delete " << op.m_dst.prettyURL() << endl;
+ d->m_currentJob = KIO::file_delete( op.m_dst );
+ d->m_uiserver->deleting( d->m_uiserverJobId, op.m_dst );
+ }
+ else if ( d->m_current.m_type == KonqCommand::MOVE
+ || d->m_current.m_type == KonqCommand::TRASH )
+ {
+ kdDebug(1203) << "KonqUndoManager::undoStep file_move " << op.m_dst.prettyURL() << " " << op.m_src.prettyURL() << endl;
+ d->m_currentJob = KIO::file_move( op.m_dst, op.m_src, -1, true );
+ d->m_uiserver->moving( d->m_uiserverJobId, op.m_dst, op.m_src );
+ }
+
+ // The above KIO jobs are lowlevel, they don't trigger KDirNotify notification
+ // So we need to do it ourselves (but schedule it to the end of the undo, to compress them)
+ KURL url( op.m_dst );
+ url.setPath( url.directory() );
+ addDirToUpdate( url );
+
+ url = op.m_src;
+ url.setPath( url.directory() );
+ addDirToUpdate( url );
+ }
+ else
+ d->m_undoState = REMOVINGFILES;
+}
+
+void KonqUndoManager::undoRemovingFiles()
+{
+ kdDebug(1203) << "KonqUndoManager::undoStep REMOVINGFILES" << endl;
+ if ( !d->m_fileCleanupStack.isEmpty() )
+ {
+ KURL file = d->m_fileCleanupStack.pop();
+ kdDebug(1203) << "KonqUndoManager::undoStep file_delete " << file.prettyURL() << endl;
+ d->m_currentJob = KIO::file_delete( file );
+ d->m_uiserver->deleting( d->m_uiserverJobId, file );
+
+ KURL url( file );
+ url.setPath( url.directory() );
+ addDirToUpdate( url );
+ }
+ else
+ {
+ d->m_undoState = REMOVINGDIRS;
+
+ if ( d->m_dirCleanupStack.isEmpty() && d->m_current.m_type == KonqCommand::MKDIR )
+ d->m_dirCleanupStack << d->m_current.m_dst;
+ }
+}
+
+void KonqUndoManager::undoRemovingDirectories()
+{
+ if ( !d->m_dirCleanupStack.isEmpty() )
+ {
+ KURL dir = d->m_dirCleanupStack.pop();
+ kdDebug(1203) << "KonqUndoManager::undoStep rmdir " << dir.prettyURL() << endl;
+ d->m_currentJob = KIO::rmdir( dir );
+ d->m_uiserver->deleting( d->m_uiserverJobId, dir );
+ addDirToUpdate( dir );
+ }
+ else
+ {
+ d->m_current.m_valid = false;
+ d->m_currentJob = 0;
+ if ( d->m_undoJob )
+ {
+ kdDebug(1203) << "KonqUndoManager::undoStep deleting undojob" << endl;
+ d->m_uiserver->jobFinished( d->m_uiserverJobId );
+ delete d->m_undoJob;
+ d->m_undoJob = 0;
+ }
+ KDirNotify_stub allDirNotify( "*", "KDirNotify*" );
+ QValueList<KURL>::ConstIterator it = d->m_dirsToUpdate.begin();
+ for( ; it != d->m_dirsToUpdate.end(); ++it ) {
+ kdDebug() << "Notifying FilesAdded for " << *it << endl;
+ allDirNotify.FilesAdded( *it );
+ }
+ broadcastUnlock();
+ }
+}
+
+void KonqUndoManager::push( const KonqCommand &cmd )
+{
+ d->m_commands.push( cmd );
+ emit undoAvailable( true );
+ emit undoTextChanged( undoText() );
+}
+
+void KonqUndoManager::pop()
+{
+ d->m_commands.pop();
+ emit undoAvailable( undoAvailable() );
+ emit undoTextChanged( undoText() );
+}
+
+void KonqUndoManager::lock()
+{
+// assert( !d->m_lock );
+ d->m_lock = true;
+ emit undoAvailable( undoAvailable() );
+}
+
+void KonqUndoManager::unlock()
+{
+// assert( d->m_lock );
+ d->m_lock = false;
+ emit undoAvailable( undoAvailable() );
+}
+
+KonqCommand::Stack KonqUndoManager::get() const
+{
+ return d->m_commands;
+}
+
+void KonqUndoManager::broadcastPush( const KonqCommand &cmd )
+{
+ if ( !d->m_syncronized )
+ {
+ push( cmd );
+ return;
+ }
+
+ DCOPRef( "kdesktop", "KonqUndoManager" ).send( "push", cmd );
+ DCOPRef( "konqueror*", "KonqUndoManager" ).send( "push", cmd );
+}
+
+void KonqUndoManager::broadcastPop()
+{
+ if ( !d->m_syncronized )
+ {
+ pop();
+ return;
+ }
+ DCOPRef( "kdesktop", "KonqUndoManager" ).send( "pop" );
+ DCOPRef( "konqueror*", "KonqUndoManager" ).send( "pop" );
+}
+
+void KonqUndoManager::broadcastLock()
+{
+// assert( !d->m_lock );
+
+ if ( !d->m_syncronized )
+ {
+ lock();
+ return;
+ }
+ DCOPRef( "kdesktop", "KonqUndoManager" ).send( "lock" );
+ DCOPRef( "konqueror*", "KonqUndoManager" ).send( "lock" );
+}
+
+void KonqUndoManager::broadcastUnlock()
+{
+// assert( d->m_lock );
+
+ if ( !d->m_syncronized )
+ {
+ unlock();
+ return;
+ }
+ DCOPRef( "kdesktop", "KonqUndoManager" ).send( "unlock" );
+ DCOPRef( "konqueror*", "KonqUndoManager" ).send( "unlock" );
+}
+
+bool KonqUndoManager::initializeFromKDesky()
+{
+ // ### workaround for dcop problem and upcoming 2.1 release:
+ // in case of huge io operations the amount of data sent over
+ // dcop (containing undo information broadcasted for global undo
+ // to all konqueror instances) can easily exceed the 64kb limit
+ // of dcop. In order not to run into trouble we disable global
+ // undo for now! (Simon)
+ // ### FIXME: post 2.1
+ return false;
+
+ DCOPClient *client = kapp->dcopClient();
+
+ if ( client->appId() == "kdesktop" ) // we are master :)
+ return true;
+
+ if ( !client->isApplicationRegistered( "kdesktop" ) )
+ return false;
+
+ d->m_commands = DCOPRef( "kdesktop", "KonqUndoManager" ).call( "get" );
+ return true;
+}
+
+QDataStream &operator<<( QDataStream &stream, const KonqBasicOperation &op )
+{
+ stream << op.m_valid << op.m_directory << op.m_renamed << op.m_link
+ << op.m_src << op.m_dst << op.m_target;
+ return stream;
+}
+QDataStream &operator>>( QDataStream &stream, KonqBasicOperation &op )
+{
+ stream >> op.m_valid >> op.m_directory >> op.m_renamed >> op.m_link
+ >> op.m_src >> op.m_dst >> op.m_target;
+ return stream;
+}
+
+QDataStream &operator<<( QDataStream &stream, const KonqCommand &cmd )
+{
+ stream << cmd.m_valid << (Q_INT8)cmd.m_type << cmd.m_opStack << cmd.m_src << cmd.m_dst;
+ return stream;
+}
+
+QDataStream &operator>>( QDataStream &stream, KonqCommand &cmd )
+{
+ Q_INT8 type;
+ stream >> cmd.m_valid >> type >> cmd.m_opStack >> cmd.m_src >> cmd.m_dst;
+ cmd.m_type = static_cast<KonqCommand::Type>( type );
+ return stream;
+}
+
+#include "konq_undo.moc"
diff --git a/libkonq/konq_undo.h b/libkonq/konq_undo.h
new file mode 100644
index 000000000..fae2b5e61
--- /dev/null
+++ b/libkonq/konq_undo.h
@@ -0,0 +1,162 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000 Simon Hausmann <hausmann@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef __konq_undo_h__
+#define __konq_undo_h__
+
+#include <qobject.h>
+#include <qstring.h>
+#include <qvaluestack.h>
+
+#include <dcopobject.h>
+
+#include <kurl.h>
+#include <libkonq_export.h>
+
+namespace KIO
+{
+ class Job;
+}
+
+class KonqUndoJob;
+
+struct KonqBasicOperation
+{
+ typedef QValueStack<KonqBasicOperation> Stack;
+
+ KonqBasicOperation()
+ { m_valid = false; }
+
+ bool m_valid;
+ bool m_directory;
+ bool m_renamed;
+ bool m_link;
+ KURL m_src;
+ KURL m_dst;
+ QString m_target;
+};
+
+struct KonqCommand
+{
+ typedef QValueStack<KonqCommand> Stack;
+
+ enum Type { COPY, MOVE, LINK, MKDIR, TRASH };
+
+ KonqCommand()
+ { m_valid = false; }
+
+ bool m_valid;
+
+ Type m_type;
+ KonqBasicOperation::Stack m_opStack;
+ KURL::List m_src;
+ KURL m_dst;
+};
+
+class KonqCommandRecorder : public QObject
+{
+ Q_OBJECT
+public:
+ KonqCommandRecorder( KonqCommand::Type op, const KURL::List &src, const KURL &dst, KIO::Job *job );
+ virtual ~KonqCommandRecorder();
+
+private slots:
+ void slotResult( KIO::Job *job );
+
+ void slotCopyingDone( KIO::Job *, const KURL &from, const KURL &to, bool directory, bool renamed );
+ void slotCopyingLinkDone( KIO::Job *, const KURL &from, const QString &target, const KURL &to );
+
+private:
+ class KonqCommandRecorderPrivate;
+ KonqCommandRecorderPrivate *d;
+};
+
+class LIBKONQ_EXPORT KonqUndoManager : public QObject, public DCOPObject
+{
+ Q_OBJECT
+ K_DCOP
+ friend class KonqUndoJob;
+public:
+ enum UndoState { MAKINGDIRS, MOVINGFILES, REMOVINGDIRS, REMOVINGFILES };
+
+ KonqUndoManager();
+ virtual ~KonqUndoManager();
+
+ static void incRef();
+ static void decRef();
+ static KonqUndoManager *self();
+
+ void addCommand( const KonqCommand &cmd );
+
+ bool undoAvailable() const;
+ QString undoText() const;
+
+public slots:
+ void undo();
+
+signals:
+ void undoAvailable( bool avail );
+ void undoTextChanged( const QString &text );
+
+protected:
+ /**
+ * @internal
+ */
+ void stopUndo( bool step );
+
+private:
+k_dcop:
+ virtual ASYNC push( const KonqCommand &cmd );
+ virtual ASYNC pop();
+ virtual ASYNC lock();
+ virtual ASYNC unlock();
+
+ virtual KonqCommand::Stack get() const;
+
+private slots:
+ void slotResult( KIO::Job *job );
+
+private:
+ void undoStep();
+
+ void undoMakingDirectories();
+ void undoMovingFiles();
+ void undoRemovingFiles();
+ void undoRemovingDirectories();
+
+ void broadcastPush( const KonqCommand &cmd );
+ void broadcastPop();
+ void broadcastLock();
+ void broadcastUnlock();
+
+ void addDirToUpdate( const KURL& url );
+ bool initializeFromKDesky();
+
+ class KonqUndoManagerPrivate;
+ KonqUndoManagerPrivate *d;
+ static KonqUndoManager *s_self;
+ static unsigned long s_refCnt;
+};
+
+QDataStream &operator<<( QDataStream &stream, const KonqBasicOperation &op );
+QDataStream &operator>>( QDataStream &stream, KonqBasicOperation &op );
+
+QDataStream &operator<<( QDataStream &stream, const KonqCommand &cmd );
+QDataStream &operator>>( QDataStream &stream, KonqCommand &cmd );
+
+#endif
diff --git a/libkonq/konq_xmlguiclient.cc b/libkonq/konq_xmlguiclient.cc
new file mode 100644
index 000000000..7737acd7c
--- /dev/null
+++ b/libkonq/konq_xmlguiclient.cc
@@ -0,0 +1,157 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Holger Freyther <freyther@yahoo.com>
+ Copyright (c) 1998, 1999 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kapplication.h"
+
+#include "konq_xmlguiclient.h"
+#include <kdebug.h>
+
+class KonqXMLGUIClient::Private
+{
+public:
+ Private() : attrName( "name" ), separatorPending( false ), hasAction( false ) {}
+ QString attrName;
+ bool separatorPending;
+ bool hasAction;
+};
+
+KonqXMLGUIClient::KonqXMLGUIClient( ) : KXMLGUIClient( )
+{
+ d = new Private;
+ prepareXMLGUIStuff( );
+}
+
+KonqXMLGUIClient::KonqXMLGUIClient( KXMLGUIClient *parent ) : KXMLGUIClient(parent )
+{
+ d = new Private;
+ prepareXMLGUIStuff( );
+}
+
+void KonqXMLGUIClient::prepareXMLGUIStuff()
+{
+ m_doc = QDomDocument( "kpartgui" );
+
+ QDomElement root = m_doc.createElement( "kpartgui" );
+ m_doc.appendChild( root );
+ root.setAttribute( d->attrName, "popupmenu" );
+
+ m_menuElement = m_doc.createElement( "Menu" );
+ root.appendChild( m_menuElement );
+ m_menuElement.setAttribute( d->attrName, "popupmenu" );
+
+ /*m_builder = new KonqPopupMenuGUIBuilder( this );
+ m_factory = new KXMLGUIFactory( m_builder ); */
+}
+
+QDomElement KonqXMLGUIClient::DomElement() const
+{
+ return m_menuElement;
+}
+
+QDomDocument KonqXMLGUIClient::domDocument() const
+{
+ return m_doc;
+}
+
+void KonqXMLGUIClient::addAction( KAction *act, const QDomElement &menu )
+{
+ addAction( act->name(), menu );
+}
+
+void KonqXMLGUIClient::addAction( const char *name, const QDomElement &menu )
+{
+ static const QString& tagAction = KGlobal::staticQString( "action" );
+
+ if (!kapp->authorizeKAction(name))
+ return;
+
+ handlePendingSeparator();
+ QDomElement parent = menu;
+ if ( parent.isNull() ) {
+ parent = m_menuElement;
+ }
+
+ QDomElement e = m_doc.createElement( tagAction );
+ parent.appendChild( e );
+ e.setAttribute( d->attrName, name );
+ d->hasAction = true;
+}
+
+void KonqXMLGUIClient::addSeparator( const QDomElement &menu )
+{
+ static const QString& tagSeparator = KGlobal::staticQString( "separator" );
+
+ QDomElement parent = menu;
+ if ( parent.isNull() ) {
+ parent = m_menuElement;
+ }
+
+ parent.appendChild( m_doc.createElement( tagSeparator ) );
+
+ d->separatorPending = false;
+}
+
+//void KonqXMLGUIClient::addWeakSeparator()
+//{
+// static const QString& tagWeakSeparator = KGlobal::staticQString( "weakSeparator" );
+// m_menuElement.appendChild( m_doc.createElement( tagWeakSeparator ) );
+//}
+
+void KonqXMLGUIClient::addMerge( const QString &name )
+{
+ // can't call handlePendingSeparator. Merge could be empty
+ // (testcase: RMB in embedded katepart)
+ QDomElement merge = m_doc.createElement( "merge" );
+ m_menuElement.appendChild( merge );
+ if ( !name.isEmpty() )
+ merge.setAttribute( d->attrName, name );
+}
+
+void KonqXMLGUIClient::addGroup( const QString &grp )
+{
+ handlePendingSeparator();
+ QDomElement group = m_doc.createElement( "definegroup" );
+ m_menuElement.appendChild( group );
+ group.setAttribute( d->attrName, grp );
+}
+
+KonqXMLGUIClient::~KonqXMLGUIClient()
+{
+ delete d;
+}
+
+void KonqXMLGUIClient::handlePendingSeparator()
+{
+ if ( d->separatorPending ) {
+ addSeparator();
+ }
+}
+
+void KonqXMLGUIClient::addPendingSeparator()
+{
+ d->separatorPending = true;
+}
+
+bool KonqXMLGUIClient::hasAction() const
+{
+ return d->hasAction;
+}
+
+
diff --git a/libkonq/konq_xmlguiclient.h b/libkonq/konq_xmlguiclient.h
new file mode 100644
index 000000000..175d991c7
--- /dev/null
+++ b/libkonq/konq_xmlguiclient.h
@@ -0,0 +1,70 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Holger Freyther <freyther@yahoo.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __konqxmlguiclient_h
+#define __konqxmlguiclient_h
+
+#include <sys/types.h>
+
+#include <kaction.h>
+#include <kxmlguiclient.h>
+#include <qstringlist.h>
+#include <libkonq_export.h>
+
+/**
+ * This class implements common methods to manipulate the DOMDocument of KXMLGUIClient
+ *
+ */
+class LIBKONQ_EXPORT KonqXMLGUIClient : public KXMLGUIClient
+{
+public:
+ KonqXMLGUIClient( );
+ KonqXMLGUIClient( KXMLGUIClient *parent );
+ virtual ~KonqXMLGUIClient( );
+ /**
+ * Reimplemented for internal purpose
+ */
+ QDomDocument domDocument( ) const;
+
+ QDomElement DomElement( ) const; // KDE4: s/D/d/
+
+protected:
+ void addAction( KAction *action, const QDomElement &menu = QDomElement() );
+ void addAction( const char *name, const QDomElement &menu = QDomElement() );
+ void addSeparator( const QDomElement &menu = QDomElement() );
+ /// only add a separator if an action is added afterwards
+ void addPendingSeparator();
+ void addGroup( const QString &grp );
+ void addMerge( const QString &name );
+
+ // @return true if addAction was called at least once
+ bool hasAction() const;
+ void prepareXMLGUIStuff();
+
+// KDE4: make private
+ QDomElement m_menuElement;
+ QDomDocument m_doc;
+
+private:
+ void handlePendingSeparator();
+ class Private;
+ Private *d;
+};
+#endif
+
diff --git a/libkonq/konqbookmarkmanager.h b/libkonq/konqbookmarkmanager.h
new file mode 100644
index 000000000..5fb45f3e6
--- /dev/null
+++ b/libkonq/konqbookmarkmanager.h
@@ -0,0 +1,24 @@
+#ifndef KONQBOOKMARKMANAGER_H
+#define KONQBOOKMARKMANAGER_H
+
+#include <kbookmarkmanager.h>
+#include <kstandarddirs.h>
+#include <libkonq_export.h>
+
+class LIBKONQ_EXPORT KonqBookmarkManager
+{
+public:
+ static KBookmarkManager * self() {
+ if ( !s_bookmarkManager )
+ {
+ QString bookmarksFile = locateLocal("data", QString::fromLatin1("konqueror/bookmarks.xml"));
+ s_bookmarkManager = KBookmarkManager::managerForFile( bookmarksFile );
+ }
+ return s_bookmarkManager;
+ }
+
+private:
+ static KBookmarkManager *s_bookmarkManager;
+};
+
+#endif
diff --git a/libkonq/konqpopupmenuplugin.desktop b/libkonq/konqpopupmenuplugin.desktop
new file mode 100644
index 000000000..984fe6949
--- /dev/null
+++ b/libkonq/konqpopupmenuplugin.desktop
@@ -0,0 +1,76 @@
+[Desktop Entry]
+Type=ServiceType
+X-KDE-ServiceType=KonqPopupMenu/Plugin
+Comment=Plugin for the Konqueror Popup Menu
+Comment[af]=Inplak vir die Konqueror Opspring Kieslys
+Comment[az]=Konqueror üçün PopupMenu əlavəsi
+Comment[be]=Утулка для выплыўнага меню Konqueror
+Comment[bg]=Приставка за контекстното меню на браузъра
+Comment[bn]=কনকরার পপ-আপ মেনুর জন্য প্লাগ-ইন
+Comment[bs]=Dodatak za Konqueror pop-up meni
+Comment[ca]=Connector per al menú emergent del Konqueror
+Comment[cs]=Modul pro kontextovou nabídku Konqueroru
+Comment[csb]=Plugins do menu (òtmëkô knąpą mëszë) Konquerora
+Comment[cy]=Ategyn i Naidlen Konqueror
+Comment[da]=Plugin for Konqueror popop-menu
+Comment[de]=Plugin für das Popup-Menü von Konqueror
+Comment[el]=Πρόσθετο για το αναδυόμενο μενού του Konqueror
+Comment[eo]=Kromaĵo por la ŝprucmenuo de Konkeranto
+Comment[es]=Complemento para el menú emergente de Konqueror
+Comment[et]=Konquerori hüpikmenüü plugin
+Comment[eu]=Konquerorren laster-menuetarako plugina
+Comment[fa]=وصله برای گزینگان بالاپر Konqueror
+Comment[fi]=Sovelma Konquerorin ponnahdusvalikolle
+Comment[fr]=Module pour le menu contextuel de Konqueror
+Comment[fy]=Plugin foar Konqueror's fluesmenu
+Comment[gl]=Plugin para o Menu Emerxente de Konqueror
+Comment[he]=תוסף לתפריט המוקפץ של Konqueror
+Comment[hi]=कॉन्करर पॉपअप मेन्यू के लिए प्लगइन
+Comment[hr]=Dodatak za Konqueror pop-up izbornik
+Comment[hu]=Bővítőmodul a Konqueror felbukkanó menühöz
+Comment[is]=Íhlutur fyrir stillingarforritið
+Comment[it]=Plugin per il menu a comparsa di Konqueror
+Comment[ja]=Konqueror ポップアップメニューのプラグイン
+Comment[ka]=Konqueror-ის ჩამოშლადი მენიუს პლაგინი
+Comment[kk]=Konqueror баптау мәзір модулі
+Comment[km]=កម្មវិធី​ជំនួយ សម្រាប់​ម៉ឺនុយ​លេចឡើង Konqueror
+Comment[ko]=Konqueror 팝업 메뉴 플러그인
+Comment[lo]=ປັກອິນສຳລັບເມນປອບອັບ Konqueror
+Comment[lt]=Priedas pasirodančiam Konqueror meniu
+Comment[lv]=Iekarotāja Uzlēcošās Izvēlnes spraudnis
+Comment[mk]=Приклучок за контекстното мени на Konqueror
+Comment[mn]=Конкюрорын тагтан-цэсний Плугин
+Comment[ms]=Plugin untuk Menu Popuo Konqueror
+Comment[mt]=Plagin għall-menu kuntestwali ta' Konqueror
+Comment[nb]=Programtillegg for sprettoppmenyen i Konqueror
+Comment[nds]=Plugin för dat Konqueror-Opdukmenü
+Comment[ne]=कन्क्वेरर पपअप मेनुका लागि प्लगइन
+Comment[nl]=Plugin voor Konqueror's contextmenu
+Comment[nn]=Tillegg til sprettoppmenyen i Konqueror
+Comment[nso]=Plugin ya Menu wa Thlarogo ya Konqueror
+Comment[pa]=ਕੋਨਕਿਉਰੋਰ ਪਾਪਅੱਪ ਮੇਨੂ ਲਈ ਪਲੱਗਇਨ
+Comment[pl]=Wtyczka do menu (otwieranego przyciskiem myszy) Konquerora
+Comment[pt]='Plugin' para o Menu do Konqueror
+Comment[pt_BR]=Plug-in do Konqueror para Menus Flutuantes
+Comment[ro]=Modul pentru meniuri popup Konqueror
+Comment[ru]=Модуль для диалога настроек
+Comment[rw]=Gucomeka bijyanye n'Ibikubiyemo Byirambura bya Konqueror
+Comment[se]=Lassemoduvla Konquerora báhccanfállui
+Comment[sk]=Modul pre kontextové menu Konquerora
+Comment[sl]=Vstavek za Konquerorjev pojavni menu
+Comment[sr]=Прикључак за Konqueror-ов искачући мени
+Comment[sr@Latn]=Priključak za Konqueror-ov iskačući meni
+Comment[sv]=Insticksprogram för Konquerors popupmeny
+Comment[ta]=கான்கொரர் தோன்றும் பட்டிக்கான செருகல்கள்
+Comment[tg]=Мутассалкунандаи меню ҷиҳандаи Konqueror
+Comment[th]=ปลั้กอินสำหรับเมนูป้อบอัพของคอนเควอร์เรอร์
+Comment[tr]=Konqueror Seyyar Menüsü İçin Eklenti
+Comment[tt]=Konqueror'da Yözüçe Saylaq buldıruçı Östämä
+Comment[uk]=Втулок вигулькних меню Konqueror
+Comment[ven]=Plugin ya menu wau sokou bvelela wa Konqueror
+Comment[vi]=Trình bổ sung cho Thực đơn Nhảy ra của Konqueror
+Comment[wa]=Tchôke-divins po l' aspitant menu di Konqueror
+Comment[xh]=Iplagi efakiweyo ye Konqueror ye Popup Menu
+Comment[zh_CN]=Konqueror 弹出菜单插件
+Comment[zh_TW]=Konqueror 對話選單的外掛程式
+Comment[zu]=I-Plugin yemenu egxumayo ye-Konqueror
diff --git a/libkonq/libkonq_export.h b/libkonq/libkonq_export.h
new file mode 100644
index 000000000..88192c0c4
--- /dev/null
+++ b/libkonq/libkonq_export.h
@@ -0,0 +1,39 @@
+/*
+ This file is part of the KDE project
+ Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl>
+ (C) 2004 Dirk Mueller <mueller@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef LIBKONQ_EXPORT_H
+#define LIBKONQ_EXPORT_H
+
+/* needed for KDE_EXPORT macros */
+#include <kdemacros.h>
+
+/* needed, because e.g. Q_OS_UNIX is so frequently used */
+#include <qglobal.h>
+
+#ifdef Q_WS_WIN
+
+#else /* Q_OS_UNIX */
+
+/* export statements for unix */
+#define LIBKONQ_EXPORT KDE_EXPORT
+
+#endif
+
+#endif
diff --git a/libkonq/pics/Makefile.am b/libkonq/pics/Makefile.am
new file mode 100644
index 000000000..8731dcc29
--- /dev/null
+++ b/libkonq/pics/Makefile.am
@@ -0,0 +1,2 @@
+libkonq_pics_datadir = $(kde_datadir)/konqueror/pics
+libkonq_pics_data_DATA = thumbnailfont_7x4.png arrow_topleft.png arrow_topright.png arrow_bottomleft.png arrow_bottomright.png
diff --git a/libkonq/pics/arrow_bottomleft.png b/libkonq/pics/arrow_bottomleft.png
new file mode 100644
index 000000000..90ef9754c
--- /dev/null
+++ b/libkonq/pics/arrow_bottomleft.png
Binary files differ
diff --git a/libkonq/pics/arrow_bottomright.png b/libkonq/pics/arrow_bottomright.png
new file mode 100644
index 000000000..92f7c9c58
--- /dev/null
+++ b/libkonq/pics/arrow_bottomright.png
Binary files differ
diff --git a/libkonq/pics/arrow_topleft.png b/libkonq/pics/arrow_topleft.png
new file mode 100644
index 000000000..b27b6df5c
--- /dev/null
+++ b/libkonq/pics/arrow_topleft.png
Binary files differ
diff --git a/libkonq/pics/arrow_topright.png b/libkonq/pics/arrow_topright.png
new file mode 100644
index 000000000..624b2b213
--- /dev/null
+++ b/libkonq/pics/arrow_topright.png
Binary files differ
diff --git a/libkonq/pics/thumbnailfont_7x4.png b/libkonq/pics/thumbnailfont_7x4.png
new file mode 100644
index 000000000..a442e3cab
--- /dev/null
+++ b/libkonq/pics/thumbnailfont_7x4.png
Binary files differ
diff --git a/libkonq/tests/Makefile.am b/libkonq/tests/Makefile.am
new file mode 100644
index 000000000..eeffe6bda
--- /dev/null
+++ b/libkonq/tests/Makefile.am
@@ -0,0 +1,6 @@
+INCLUDES = -I$(top_srcdir)/libkonq $(all_includes)
+AM_LDFLAGS = $(all_libraries)
+check_PROGRAMS = konqdragtest
+konqdragtest_SOURCES = konqdragtest.cpp
+konqdragtest_LDADD = ../libkonq.la
+TESTS = konqdragtest
diff --git a/libkonq/tests/konqdragtest.cpp b/libkonq/tests/konqdragtest.cpp
new file mode 100644
index 000000000..ad03b21fc
--- /dev/null
+++ b/libkonq/tests/konqdragtest.cpp
@@ -0,0 +1,62 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 2005 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kurl.h>
+#include <kdebug.h>
+#include <kurldrag.h>
+#include <assert.h>
+#include <qiconview.h>
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+
+#include <konq_drag.h>
+
+// for future qttestlib porting :)
+#define VERIFY assert
+#define COMPARE( a, b ) assert( (a) == (b) )
+
+void testKonqIconDrag2()
+{
+ // Those URLs don't have to exist.
+ KURL mediaURL = "media:/hda1/tmp/Mat%C3%A9riel";
+ KURL localURL = "file:///tmp/Mat%C3%A9riel";
+ KonqIconDrag2 iconDrag( 0 );
+ QIconDragItem item;
+ iconDrag.append( item, QRect( 1, 2, 3, 4 ), QRect( 5, 6, 7, 8 ),
+ mediaURL.url(), localURL.url() );
+
+
+ VERIFY( KURLDrag::canDecode( &iconDrag ) );
+ KURL::List lst;
+ KURLDrag::decode( &iconDrag, lst );
+ VERIFY( !lst.isEmpty() );
+ COMPARE( lst.count(), 1 );
+ kdDebug() << "lst[0]=" << lst << endl;
+ kdDebug() << "mediaURL=" << mediaURL << endl;
+ COMPARE( lst[0].url(), mediaURL.url() );
+}
+
+int main(int argc, char *argv[])
+{
+ KApplication::disableAutoDcopRegistration();
+ KCmdLineArgs::init( argc, argv, "kurltest", 0, 0, 0, 0 );
+ KApplication app; // GUI needed for QPixmaps
+
+ testKonqIconDrag2();
+ return 0;
+}