diff options
Diffstat (limited to 'libkonq')
71 files changed, 14445 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 <[email protected]> +David Faure <[email protected]> +Simon Hausmann <[email protected]> +Holger Freyther <[email protected]> +and are all available under the LGPL license. +See the individual files for more. diff --git a/libkonq/CMakeLists.txt b/libkonq/CMakeLists.txt new file mode 100644 index 000000000..532e31d4d --- /dev/null +++ b/libkonq/CMakeLists.txt @@ -0,0 +1,83 @@ +################################################# +# +# (C) 2010-2011 Serghei Amelian +# serghei (DOT) amelian (AT) gmail.com +# +# Improvements and feedback are welcome +# +# This file is released under GPL >= 2 +# +################################################# + +project( libkonq ) + +check_include_file( "sys/statvfs.h" HAVE_STATVFS ) + +add_subdirectory( pics ) +add_subdirectory( favicons ) +add_subdirectory( servicemenus ) + +include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ${TDE_INCLUDE_DIR} + ${TQT_INCLUDE_DIRS} + ${ARTS_INCLUDE_DIRS} + ${TDE_INCLUDE_DIR}/arts/ + ${CMAKE_BINARY_DIR} +) + +link_directories( + ${TQT_LIBRARY_DIRS} + ${ARTS_LIBRARY_DIRS} +) + + +##### headers ################################### + +install( FILES + konq_popupmenu.h knewmenu.h tdefileivi.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 kivfreespaceoverlay.h konq_faviconmgr.h + konq_xmlguiclient.h konqbookmarkmanager.h konq_filetip.h + DESTINATION ${INCLUDE_INSTALL_DIR} ) + + +##### other data ################################ + +install( FILES directory_bookmarkbar.desktop DESTINATION ${DATA_INSTALL_DIR}/kbookmark ) +install( FILES konqpopupmenuplugin.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR} ) + + +##### konq (shared lib) ######################### + +tde_add_library( konq SHARED AUTOMOC + SOURCES + konq_popupmenu.cc knewmenu.cc konq_xmlguiclient.cc tdefileivi.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 kivfreespaceoverlay.cc + konq_faviconmgr.cc konq_faviconmgr.skel konq_filetip.cc + VERSION 4.2.0 + LINK tdeparts-shared + DESTINATION ${LIB_INSTALL_DIR} +) + + +##### konq_sound (module) ####################### + +if( WITH_ARTS ) + tde_add_kpart( konq_sound + SOURCES konq_sound.cc + LINK artskde-shared + DESTINATION ${PLUGIN_INSTALL_DIR} ) +endif( ) + + +##### install import cmake modules ############### + +tde_install_export( ) diff --git a/libkonq/DESIGN b/libkonq/DESIGN new file mode 100644 index 000000000..b925226ba --- /dev/null +++ b/libkonq/DESIGN @@ -0,0 +1,46 @@ +libkonq is the construction kit for a file manager +(together with libtdeio, 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 +tdefileivi.* : 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..131449d7e --- /dev/null +++ b/libkonq/Makefile.am @@ -0,0 +1,74 @@ +# This file is part of the KDE libraries +# Copyright (C) 1997 David Faure <[email protected]> +# +# 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_TDEPARTS) + +libkonq_la_SOURCES = konq_popupmenu.cc knewmenu.cc \ + konq_xmlguiclient.cc\ + tdefileivi.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 \ + kivfreespaceoverlay.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 \ + tdefileivi.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 \ + kivfreespaceoverlay.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 tdecore tdeio/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..12035388c --- /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 ~/.trinity/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-TDE-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/CMakeLists.txt b/libkonq/favicons/CMakeLists.txt new file mode 100644 index 000000000..61afd464b --- /dev/null +++ b/libkonq/favicons/CMakeLists.txt @@ -0,0 +1,37 @@ +################################################# +# +# (C) 2010-2011 Serghei Amelian +# serghei (DOT) amelian (AT) gmail.com +# +# Improvements and feedback are welcome +# +# This file is released under GPL >= 2 +# +################################################# + +include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ${TDE_INCLUDE_DIR} + ${TQT_INCLUDE_DIRS} +) + +link_directories( + ${TDE_LIBRARY_DIRS} + ${TQT_LIBRARY_DIRS} +) + + +##### other data ################################ + +install( FILES favicons.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kded ) +install( FILES favicons.upd DESTINATION ${KCONF_UPDATE_INSTALL_DIR} ) +install( PROGRAMS move_favicons.sh DESTINATION ${KCONF_UPDATE_INSTALL_DIR} ) + + +##### kded_favicons (module) #################### + +tde_add_kpart( kded_favicons AUTOMOC + SOURCES favicons.cpp favicons.skel + LINK tdeinit_kded-shared + DESTINATION ${PLUGIN_INSTALL_DIR} +) diff --git a/libkonq/favicons/Makefile.am b/libkonq/favicons/Makefile.am new file mode 100644 index 000000000..194d9d14c --- /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_TDESYCOCA) + +METASOURCES = AUTO + +servicesdir = $(kde_servicesdir)/kded +services_DATA = favicons.desktop + +update_DATA = favicons.upd +update_SCRIPTS = move_favicons.sh +updatedir = $(kde_datadir)/tdeconf_update diff --git a/libkonq/favicons/favicons.cpp b/libkonq/favicons/favicons.cpp new file mode 100644 index 000000000..234bcf19d --- /dev/null +++ b/libkonq/favicons/favicons.cpp @@ -0,0 +1,275 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Malte Starostik <[email protected]> + + 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 <tqbuffer.h> +#include <tqfile.h> +#include <tqcache.h> +#include <tqimage.h> +#include <tqtimer.h> + +#include <kdatastream.h> // DO NOT REMOVE, otherwise bool marshalling breaks +#include <kicontheme.h> +#include <kimageio.h> +#include <ksimpleconfig.h> +#include <kstandarddirs.h> +#include <tdeio/job.h> + +#include "favicons.moc" + +struct FaviconsModulePrivate +{ + virtual ~FaviconsModulePrivate() { delete config; } + + struct DownloadInfo + { + TQString hostOrURL; + bool isHost; + TQByteArray iconData; + }; + TQMap<TDEIO::Job *, DownloadInfo> downloads; + TQStringList failedDownloads; + KSimpleConfig *config; + TQPtrList<TDEIO::Job> killJobs; + TDEIO::MetaData metaData; + TQString faviconsDir; + TQCache<TQString> faviconsCache; +}; + +FaviconsModule::FaviconsModule(const TQCString &obj) + : KDEDModule(obj) +{ + // create our favicons folder so that TDEIconLoader knows about it + d = new FaviconsModulePrivate; + d->faviconsDir = TDEGlobal::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; +} + +TQString removeSlash(TQString result) +{ + for (unsigned int i = result.length() - 1; i > 0; --i) + if (result[i] != '/') + { + result.truncate(i + 1); + break; + } + + return result; +} + + +TQString FaviconsModule::iconForURL(const KURL &url) +{ + if (url.host().isEmpty()) + return TQString::null; + + TQString icon; + TQString simplifiedURL = simplifyURL(url); + + TQString *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 (TQFile::exists(d->faviconsDir+icon+".png")) + return icon; + + return TQString::null; +} + +TQString FaviconsModule::simplifyURL(const KURL &url) +{ + // splat any = in the URL so it can be safely used as a config key + TQString result = url.host() + url.path(); + for (unsigned int i = 0; i < result.length(); ++i) + if (result[i] == '=') + result[i] = '_'; + return result; +} + +TQString FaviconsModule::iconNameFromURL(const KURL &iconURL) +{ + if (iconURL.path() == "/favicon.ico") + return iconURL.host(); + + TQString 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] = '_'; + + TQString ext = result.right(4); + if (ext == ".ico" || ext == ".png" || ext == ".xpm") + result.remove(result.length() - 4, 4); + + return result; +} + +bool FaviconsModule::isIconOld(const TQString &icon) +{ + struct stat st; + if (stat(TQFile::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) +{ + TQString simplifiedURL = simplifyURL(url); + + d->faviconsCache.insert(removeSlash(simplifiedURL), new TQString(iconURL.url()) ); + + TQString iconName = "favicons/" + iconNameFromURL(iconURL); + TQString iconFile = d->faviconsDir + iconName + ".png"; + + if (!isIconOld(iconFile)) { + emit iconChanged(false, simplifiedURL, iconName); + return; + } + + startDownload(simplifiedURL, false, iconURL); +} + +void FaviconsModule::downloadHostIcon(const KURL &url) +{ + TQString iconFile = d->faviconsDir + "favicons/" + url.host() + ".png"; + if (!isIconOld(iconFile)) + return; + + startDownload(url.host(), true, KURL(url, "/favicon.ico")); +} + +void FaviconsModule::startDownload(const TQString &hostOrURL, bool isHost, const KURL &iconURL) +{ + if (d->failedDownloads.contains(iconURL.url())) + return; + + TDEIO::Job *job = TDEIO::get(iconURL, false, false); + job->addMetaData(d->metaData); + connect(job, TQT_SIGNAL(data(TDEIO::Job *, const TQByteArray &)), TQT_SLOT(slotData(TDEIO::Job *, const TQByteArray &))); + connect(job, TQT_SIGNAL(result(TDEIO::Job *)), TQT_SLOT(slotResult(TDEIO::Job *))); + connect(job, TQT_SIGNAL(infoMessage(TDEIO::Job *, const TQString &)), TQT_SLOT(slotInfoMessage(TDEIO::Job *, const TQString &))); + FaviconsModulePrivate::DownloadInfo download; + download.hostOrURL = hostOrURL; + download.isHost = isHost; + d->downloads.insert(job, download); +} + +void FaviconsModule::slotData(TDEIO::Job *job, const TQByteArray &data) +{ + FaviconsModulePrivate::DownloadInfo &download = d->downloads[job]; + unsigned int oldSize = download.iconData.size(); + if (oldSize > 0x10000) + { + d->killJobs.append(job); + TQTimer::singleShot(0, this, TQT_SLOT(slotKill())); + } + download.iconData.resize(oldSize + data.size()); + memcpy(download.iconData.data() + oldSize, data.data(), data.size()); +} + +void FaviconsModule::slotResult(TDEIO::Job *job) +{ + FaviconsModulePrivate::DownloadInfo download = d->downloads[job]; + d->downloads.remove(job); + KURL iconURL = static_cast<TDEIO::TransferJob *>(job)->url(); + TQString iconName; + if (!job->error()) + { + TQBuffer buffer(download.iconData); + buffer.open(IO_ReadOnly); + TQImageIO io; + io.setIODevice(TQT_TQIODEVICE(&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() != TDEIcon::SizeSmall || io.image().height() != TDEIcon::SizeSmall) + io.setImage(io.image().smoothScale(TDEIcon::SizeSmall, TDEIcon::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 = TQString::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(TDEIO::Job *job, const TQString &msg) +{ + emit infoMessage(static_cast<TDEIO::TransferJob *>( job )->url(), msg); +} + +void FaviconsModule::slotKill() +{ + d->killJobs.clear(); +} + +extern "C" { + KDE_EXPORT KDEDModule *create_favicons(const TQCString &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..a266a74f3 --- /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 KDED +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 KDED +Name[pa]=KDED ਫਾਵੀਕੋਨ ਮੋਡੁਲੀ +Name[pl]=Ikony serwerów +Name[pt]=Módulo Favicon do KDED +Name[pt_BR]=Módulo Favicon do KDED +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]=KDED 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 KDED +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]=Показ настраиваемых значков в KDED +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]=KDED'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]=捷徑圖示支援 +X-TDE-ServiceTypes=KDEDModule +X-TDE-ModuleType=Library +X-TDE-Library=favicons +X-TDE-FactoryName=favicons +X-TDE-Kded-autoload=false +X-TDE-Kded-load-on-demand=true diff --git a/libkonq/favicons/favicons.h b/libkonq/favicons/favicons.h new file mode 100644 index 000000000..e42dace1b --- /dev/null +++ b/libkonq/favicons/favicons.h @@ -0,0 +1,105 @@ +/* This file is part of the KDE Project + Copyright (c) 2001 Malte Starostik <[email protected]> + + 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 TDEIO { 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, TQString, TQString); + * 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 TDEIconLoader 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 <[email protected]> + */ +class FaviconsModule : public KDEDModule +{ + Q_OBJECT + K_DCOP +public: + FaviconsModule(const TQCString &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, TQString::null is returned. + * + * @param url the URL for which the icon is queried + * @return the icon name suitable to pass to @ref TDEIconLoader or + * TQString::null if no icon for this URL was found. + */ + TQString 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, TQString hostOrURL, TQString iconName); + void infoMessage(KURL iconURL, TQString msg); + +private: + void startDownload(const TQString &, bool, const KURL &); + TQString simplifyURL(const KURL &); + TQString iconNameFromURL(const KURL &); + bool isIconOld(const TQString &); + +private slots: + void slotData(TDEIO::Job *, const TQByteArray &); + void slotResult(TDEIO::Job *); + void slotInfoMessage(TDEIO::Job *, const TQString &); + 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..853a87d8f --- /dev/null +++ b/libkonq/favicons/favicons.upd @@ -0,0 +1,3 @@ +# Move favicons from $TDEHOME/share/icons and $TDEHOME/share/cache to $TDEHOME/cache-$HOST +Id=trinity_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..e5b282790 --- /dev/null +++ b/libkonq/favicons/move_favicons.sh @@ -0,0 +1,41 @@ +#!/bin/sh + +prefix=$(tde-config --localprefix) +source1="$prefix/share/icons/favicons" +source2="$prefix/share/cache/favicons" +dest="$(tde-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/kivdirectoryoverlay.cc b/libkonq/kivdirectoryoverlay.cc new file mode 100644 index 000000000..bb1b0d6c2 --- /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 <tqdict.h> +#include <tqpixmap.h> +#include <tqpainter.h> +#include <tqbitmap.h> +#include <tqimage.h> + +#include <tdefileivi.h> +#include <tdefileitem.h> +#include <tdeapplication.h> +#include <kdirlister.h> +#include <kstandarddirs.h> +#include <kiconloader.h> +#include <konq_settings.h> +#include <tdelocale.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, TQT_SIGNAL(completed()), TQT_SLOT(slotCompleted())); + connect(m_lister, TQT_SIGNAL(newItems( const KFileItemList& )), TQT_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 TQDict<int>; + m_popularIcons->setAutoDelete(true); + m_lister->openURL(m_directory->item()->url()); + } else { + emit finished(); + } +} + +void KIVDirectoryOverlay::timerEvent(TQTimerEvent *) +{ + m_lister->stop(); +} + +void KIVDirectoryOverlay::slotCompleted() +{ + if (!m_popularIcons) return; + + // Look through the histogram for the most popular mimetype + TQDictIterator<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 = "application-vnd.tde.tdemultiple"; + } + + 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() ) { + + TQString 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..1734f8108 --- /dev/null +++ b/libkonq/kivdirectoryoverlay.h @@ -0,0 +1,59 @@ +/* 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 <tdefileitem.h> +#include <libkonq_export.h> + +#include <tqdict.h> + +class KDirLister; +class KFileIVI; + +class LIBKONQ_EXPORT KIVDirectoryOverlay : public TQObject +{ + Q_OBJECT + +public: + KIVDirectoryOverlay(KFileIVI* directory); + virtual ~KIVDirectoryOverlay(); + void start(); + +signals: + void finished(); + +protected: + virtual void timerEvent(TQTimerEvent *); + +private slots: + void slotCompleted(); + void slotNewItems( const KFileItemList& items ); + +private: + KDirLister* m_lister; + bool m_foundItems; + bool m_containsFolder; + TQDict<int>* m_popularIcons; + TQString m_bestIcon; + KFileIVI* m_directory; +}; + +#endif diff --git a/libkonq/kivfreespaceoverlay.cc b/libkonq/kivfreespaceoverlay.cc new file mode 100644 index 000000000..29069cf4f --- /dev/null +++ b/libkonq/kivfreespaceoverlay.cc @@ -0,0 +1,118 @@ +/* This file is part of the TDE libraries + Copyright (C) 2013 Timothy Pearson + Based on kivdirectoryoverlay.cc + + 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 "config.h" + +#include <tqdict.h> +#include <tqpixmap.h> +#include <tqpainter.h> +#include <tqbitmap.h> +#include <tqimage.h> +#include <tqfile.h> +#include <tqtimer.h> + +#include <tdefileivi.h> +#include <tdefileitem.h> +#include <tdeapplication.h> +#include <kdirlister.h> +#include <kstandarddirs.h> +#include <kiconloader.h> +#include <konq_settings.h> +#include <tdelocale.h> +#include <kdebug.h> + +#ifdef HAVE_STATVFS +# include <sys/statvfs.h> +#else +# include <sys/mount.h> +# define statvfs statfs +# define f_frsize f_bsize +#endif + +#include "kivfreespaceoverlay.h" + +KIVFreeSpaceOverlay::KIVFreeSpaceOverlay(KFileIVI* freespace) +{ + m_freespace = freespace; +} + +KIVFreeSpaceOverlay::~KIVFreeSpaceOverlay() +{ + // +} + +void KIVFreeSpaceOverlay::start() +{ + if ( !m_freespace->item()->isReadable() ) { + emit finished(); + } + TQTimer::singleShot(0, this, TQT_SLOT(slotDisplay())); +} + +void KIVFreeSpaceOverlay::timerEvent(TQTimerEvent *) +{ + // +} + +void KIVFreeSpaceOverlay::slotDisplay() +{ + KFileItem* item = m_freespace->item(); + if (item) { + if (item->mimetype().contains("_mounted")) { + bool isLocal = false; + KURL localURL = item->mostLocalURL(isLocal); + if (!isLocal) { + m_freespace->setOverlayProgressBar(-1); + } + else { + TQString localPath = localURL.path(); + if (localPath != "") { + TDEIO::filesize_t m_total = 0; + TDEIO::filesize_t m_used = 0; + TDEIO::filesize_t m_free = 0; + + struct statvfs vfs; + memset(&vfs, 0, sizeof(vfs)); + + if ( ::statvfs(TQFile::encodeName(localPath), &vfs) != -1 ) + { + m_total = static_cast<TDEIO::filesize_t>(vfs.f_blocks) * static_cast<TDEIO::filesize_t>(vfs.f_frsize); + m_free = static_cast<TDEIO::filesize_t>(vfs.f_bavail) * static_cast<TDEIO::filesize_t>(vfs.f_frsize); + m_used = m_total - m_free; + m_freespace->setOverlayProgressBar((m_used/(m_total*1.0))*100.0); + } + else { + m_freespace->setOverlayProgressBar(-1); + } + } + else { + m_freespace->setOverlayProgressBar(-1); + } + } + } + } + else { + m_freespace->setOverlayProgressBar(-1); + } + + emit finished(); +} + +#include "kivfreespaceoverlay.moc" diff --git a/libkonq/kivfreespaceoverlay.h b/libkonq/kivfreespaceoverlay.h new file mode 100644 index 000000000..6527ccd29 --- /dev/null +++ b/libkonq/kivfreespaceoverlay.h @@ -0,0 +1,54 @@ +/* This file is part of the TDE libraries + Copyright (C) 2013 Timothy Pearson + Based on kivdirectoryoverlay.h + + 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 _KIVFREESPACEOVERLAY_H_ +#define _KIVFREESPACEOVERLAY_H_ + +#include <tdefileitem.h> +#include <libkonq_export.h> + +#include <tqdict.h> + +class KDirLister; +class KFileIVI; + +class LIBKONQ_EXPORT KIVFreeSpaceOverlay : public TQObject +{ + Q_OBJECT + +public: + KIVFreeSpaceOverlay(KFileIVI* freespace); + virtual ~KIVFreeSpaceOverlay(); + void start(); + +signals: + void finished(); + +protected: + virtual void timerEvent(TQTimerEvent *); + +private slots: + void slotDisplay(); + +private: + KFileIVI* m_freespace; +}; + +#endif diff --git a/libkonq/knewmenu.cc b/libkonq/knewmenu.cc new file mode 100644 index 000000000..621b1f614 --- /dev/null +++ b/libkonq/knewmenu.cc @@ -0,0 +1,621 @@ +/* This file is part of the KDE project + Copyright (C) 1998, 1999 David Faure <[email protected]> + 2003 Sven Leiber <[email protected]> + + 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 <tqdir.h> + +#include <kdebug.h> +#include <kdesktopfile.h> +#include <kdirwatch.h> +#include <kinstance.h> +#include <kinputdialog.h> +#include <tdelocale.h> +#include <tdemessagebox.h> +#include <kstandarddirs.h> +#include <kprotocolinfo.h> +#include <tdepopupmenu.h> +#include <krun.h> + +#include <tdeio/job.h> +#include <tdeio/renamedlg.h> + +#include <kpropertiesdialog.h> +#include "konq_operations.h" +#include "konq_undo.h" +#include "knewmenu.h" +#include <utime.h> + +// For KURLDesktopFileDlg +#include <tqlayout.h> +#include <tqhbox.h> +#include <klineedit.h> +#include <kurlrequester.h> +#include <tqlabel.h> +#include <tqpopupmenu.h> + +TQValueList<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) {} + TDEActionCollection * m_actionCollection; + TQString m_destPath; + TQWidget *m_parentWidget; + TDEActionMenu *m_menuDev; +}; + +KNewMenu::KNewMenu( TDEActionCollection * _collec, const char *name ) : + TDEActionMenu( i18n( "Create New" ), "document-new", _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( TDEActionCollection * _collec, TQWidget *parentWidget, const char *name ) : + TDEActionMenu( i18n( "Create New" ), "document-new", _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 TDEActionMenu( 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 + TQValueList<TDEAction*> actions = d->m_actionCollection->actions( "KNewMenu" ); + for( TQValueListIterator<TDEAction*> 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 TQValueList<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; + TQValueList<Entry>::Iterator templ = s_templatesList->begin(); + for ( /*++templ*/; templ != s_templatesList->end(); ++templ) + { + TQString iconname; + TQString filePath = (*templ).filePath; + if ( !filePath.isEmpty() ) + { + TQString text; + TQString 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"); + TQString 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) + TQString 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(); + + TDEAction *linkURL = 0, *linkApp = 0; // these shall be put at special positions + + int i = 1; // was 2 when there was Folder + TQValueList<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; + + TQValueList<TDEAction*> actions = d->m_actionCollection->actions(); + TQValueListIterator<TDEAction*> 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" ) ) + { + TDEAction * act = new TDEAction( (*templ).text, (*templ).icon, 0, this, TQT_SLOT( slotNewDir() ), + d->m_actionCollection, TQCString().sprintf("newmenu%d", i ) ); + act->setGroup( "KNewMenu" ); + act->plug( popupMenu() ); + + TDEActionSeparator *sep = new TDEActionSeparator(); + sep->plug( popupMenu() ); + } + else + { + TDEAction * act = new TDEAction( (*templ).text, (*templ).icon, 0, this, TQT_SLOT( slotNewFile() ), + d->m_actionCollection, TQCString().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 ); + + TDEActionSeparator * act = new TDEActionSeparator(); + act->plug( popupMenu() ); + } + } + + TDEActionSeparator * act = new TDEActionSeparator(); + 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; + TQStringList dirs = d->m_actionCollection->instance()->dirs()->resourceDirs("templates"); + for ( TQStringList::Iterator it = dirs.begin() ; it != dirs.end() ; ++it ) + { + //kdDebug(1203) << "Templates resource dir: " << *it << endl; + s_pDirWatch->addDir( *it ); + } + connect ( s_pDirWatch, TQT_SIGNAL( dirty( const TQString & ) ), + this, TQT_SLOT ( slotFillTemplates() ) ); + connect ( s_pDirWatch, TQT_SIGNAL( created( const TQString & ) ), + this, TQT_SLOT ( slotFillTemplates() ) ); + connect ( s_pDirWatch, TQT_SIGNAL( deleted( const TQString & ) ), + this, TQT_SLOT ( slotFillTemplates() ) ); + // Ok, this doesn't cope with new dirs in TDEDIRS, but that's another story + } + s_templatesVersion++; + s_filesParsed = false; + + s_templatesList->clear(); + + // Look into "templates" dirs. + TQStringList files = d->m_actionCollection->instance()->dirs()->findAllResources("templates"); + KSortableValueList<Entry,TQString> slist; + for ( TQStringList::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) + TQString 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, TQString>::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 = TQString( TQT_TQOBJECT_CONST(sender())->name() + 7 ).toInt(); // skip "newmenu" + if (id == 0) + { + // run the command for the templates + KRun::runCommand(TQString(TQT_TQOBJECT_CONST(sender())->name())); + return; + } + + emit activated(); // for KDIconView::slotNewMenuActivated() + + Entry entry = *(s_templatesList->at( id - 1 )); + //kdDebug(1203) << TQString("sFile = %1").arg(sFile) << endl; + + if ( !TQFile::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; + TQString 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; + TQString text = entry.text; + text.replace( "...", TQString() ); // the ... is fine for the menu item but not for the default filename + + KURL defaultFile( *it ); + defaultFile.addPath( TDEIO::encodeFileName( text ) ); + if ( defaultFile.isLocalFile() && TQFile::exists( defaultFile.path() ) ) + text = TDEIO::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; + TQString text = entry.text; + text.replace( "...", TQString() ); // the ... is fine for the menu item but not for the default filename + + KURL defaultFile( *(popupFiles.begin()) ); + defaultFile.addPath( TDEIO::encodeFileName( text ) ); + if ( defaultFile.isLocalFile() && TQFile::exists( defaultFile.path() ) ) + text = TDEIO::RenameDlg::suggestName( *(popupFiles.begin()), text); + + name = KInputDialog::getText( TQString::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(); + + TQString src = entry.templatePath; + for ( ; it != popupFiles.end(); ++it ) + { + KURL dest( *it ); + dest.addPath( TDEIO::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 : TDEIO::copyAs( " << uSrc.url() << ", " << dest.url() << ")" << endl; + TDEIO::CopyJob * job = TDEIO::copyAs( uSrc, dest ); + job->setDefaultPermissions( true ); + connect( job, TQT_SIGNAL( result( TDEIO::Job * ) ), + TQT_SLOT( slotResult( TDEIO::Job * ) ) ); + if ( m_isURLDesktopFile ) + connect( job, TQT_SIGNAL( renamed( TDEIO::Job *, const KURL&, const KURL& ) ), + TQT_SLOT( slotRenamed( TDEIO::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( TDEIO::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( TDEIO::Job * job ) +{ + if (job->error()) + job->showErrorDialog(); + else + { + KURL destURL = static_cast<TDEIO::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, tdeio_file copied the mtime. + (void) ::utime( TQFile::encodeName( destURL.path() ), 0 ); + } + } + } +} + +////////// + +KURLDesktopFileDlg::KURLDesktopFileDlg( const TQString& textFileName, const TQString& textUrl ) + : KDialogBase( Plain, TQString::null, Ok|Cancel|User1, Ok, 0L /*parent*/, 0L, true, + true, KStdGuiItem::clear() ) +{ + initDialog( textFileName, TQString::null, textUrl, TQString::null ); +} + +KURLDesktopFileDlg::KURLDesktopFileDlg( const TQString& textFileName, const TQString& textUrl, TQWidget *parent ) + : KDialogBase( Plain, TQString::null, Ok|Cancel|User1, Ok, parent, 0L, true, + true, KStdGuiItem::clear() ) +{ + initDialog( textFileName, TQString::null, textUrl, TQString::null ); +} + +void KURLDesktopFileDlg::initDialog( const TQString& textFileName, const TQString& defaultName, const TQString& textUrl, const TQString& defaultUrl ) +{ + TQVBoxLayout * topLayout = new TQVBoxLayout( plainPage(), 0, spacingHint() ); + + // First line: filename + TQHBox * fileNameBox = new TQHBox( plainPage() ); + topLayout->addWidget( fileNameBox ); + + TQLabel * label = new TQLabel( 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, TQT_SIGNAL(textChanged(const TQString&)), + TQT_SLOT(slotNameTextChanged(const TQString&)) ); + + // Second line: url + TQHBox * urlBox = new TQHBox( plainPage() ); + topLayout->addWidget( urlBox ); + label = new TQLabel( 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(), TQT_SIGNAL(textChanged(const TQString&)), + TQT_SLOT(slotURLTextChanged(const TQString&)) ); + label->setBuddy(m_urlRequester); // please "scheck" style + + m_urlRequester->setFocus(); + enableButtonOK( !defaultName.isEmpty() && !defaultUrl.isEmpty() ); + connect( this, TQT_SIGNAL(user1Clicked()), this, TQT_SLOT(slotClear()) ); + m_fileNameEdited = false; +} + +TQString KURLDesktopFileDlg::url() const +{ + if ( result() == TQDialog::Accepted ) + return m_urlRequester->url(); + else + return TQString::null; +} + +TQString KURLDesktopFileDlg::fileName() const +{ + if ( result() == TQDialog::Accepted ) + return m_leFileName->text(); + else + return TQString::null; +} + +void KURLDesktopFileDlg::slotClear() +{ + m_leFileName->setText( TQString::null ); + m_urlRequester->clear(); + m_fileNameEdited = false; +} + +void KURLDesktopFileDlg::slotNameTextChanged( const TQString& ) +{ + kdDebug() << k_funcinfo << endl; + m_fileNameEdited = true; + enableButtonOK( !m_leFileName->text().isEmpty() && !m_urlRequester->url().isEmpty() ); +} + +void KURLDesktopFileDlg::slotURLTextChanged( const TQString& ) +{ + 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..a0ea38f44 --- /dev/null +++ b/libkonq/knewmenu.h @@ -0,0 +1,224 @@ +/* This file is part of the KDE project + Copyright (C) 1998-2000 David Faure <[email protected]> + 2003 Sven Leiber <[email protected]> + + 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 <tqintdict.h> +#include <tqstringlist.h> + +#include <tdeaction.h> +#include <kdialogbase.h> +#include <kurl.h> +#include <libkonq_export.h> + +namespace TDEIO { class Job; } + +class KDirWatch; +class KLineEdit; +class KURLRequester; +class TQPopupMenu; + +/** + * 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 <[email protected]> + * Ideas and code for the new template handling mechanism ('link' desktop files) + * from Christoph Pickart <[email protected]> + */ +class LIBKONQ_EXPORT KNewMenu : public TDEActionMenu +{ + Q_OBJECT +public: + + /** + * Constructor + */ + KNewMenu( TDEActionCollection * _collec, const char *name=0L ); + KNewMenu( TDEActionCollection * _collec, TQWidget *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( TDEIO::Job * ); + // Special case (filename conflict when creating a link=url file) + void slotRenamed( TDEIO::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 { + TQString text; + TQString filePath; // empty for SEPARATOR + TQString templatePath; // same as filePath for TEMPLATE + TQString icon; + int entryType; + TQString 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 TQValueList<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; + TQString 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 <[email protected]> + */ +class KURLDesktopFileDlg : public KDialogBase +{ + Q_OBJECT +public: + KURLDesktopFileDlg( const TQString& textFileName, const TQString& textUrl ); + KURLDesktopFileDlg( const TQString& textFileName, const TQString& textUrl, TQWidget *parent ); + virtual ~KURLDesktopFileDlg() {} + + /** + * @return the filename the user entered (no path) + */ + TQString fileName() const; + /** + * @return the URL the user entered + */ + TQString url() const; + +protected slots: + void slotClear(); + void slotNameTextChanged( const TQString& ); + void slotURLTextChanged( const TQString& ); +private: + void initDialog( const TQString& textFileName, const TQString& defaultName, const TQString& textUrl, const TQString& 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..60f3aa63d --- /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 <[email protected]> + Copyright (c) 1999 David Faure <[email protected]> + + 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 <tqbuttongroup.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqradiobutton.h> + +#include <kcolorbutton.h> +#include <kcombobox.h> +#include <kdebug.h> +#include <kimagefilepreview.h> +#include <tdelocale.h> +//#include <tderecentdocument.h> +#include <kstandarddirs.h> +#include <kurlrequester.h> + +#include "konq_bgnddlg.h" + + +KonqBgndDialog::KonqBgndDialog( TQWidget* parent, + const TQString& pixmapFile, + const TQColor& theColor, + const TQColor& defaultColor ) + : KDialogBase( parent, "KonqBgndDialog", false, + i18n("Background Settings"), Ok|Cancel, Ok, true ) +{ + TQWidget* page = new TQWidget( this ); + setMainWidget( page ); + TQVBoxLayout* mainLayout = new TQVBoxLayout( page, 0, KDialog::spacingHint() ); + + m_buttonGroup = new TQButtonGroup( i18n("Background"), page ); + m_buttonGroup->setColumnLayout( 0, Qt::Vertical ); + m_buttonGroup->layout()->setMargin( KDialog::marginHint() ); + m_buttonGroup->layout()->setSpacing( KDialog::spacingHint() ); + TQGridLayout* groupLayout = new TQGridLayout( m_buttonGroup->layout() ); + groupLayout->setAlignment( Qt::AlignTop ); + mainLayout->addWidget( m_buttonGroup ); + + connect( m_buttonGroup, TQT_SIGNAL( clicked(int) ), + this, TQT_SLOT( slotBackgroundModeChanged() ) ); + + // color + m_radioColor = new TQRadioButton( i18n("Co&lor:"), m_buttonGroup ); + groupLayout->addWidget( m_radioColor, 0, 0 ); + m_buttonColor = new KColorButton( theColor, defaultColor, m_buttonGroup ); + m_buttonColor->setSizePolicy( TQSizePolicy::Preferred, + TQSizePolicy::Minimum ); + groupLayout->addWidget( m_buttonColor, 0, 1 ); + + connect( m_buttonColor, TQT_SIGNAL( changed( const TQColor& ) ), + this, TQT_SLOT( slotColorChanged() ) ); + + // picture + m_radioPicture = new TQRadioButton( 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(), TQT_SIGNAL( activated( int ) ), + this, TQT_SLOT( slotPictureChanged() ) ); + connect( m_comboPicture, TQT_SIGNAL( urlSelected(const TQString &) ), + this, TQT_SLOT( slotPictureChanged() ) ); + + TQSpacerItem* spacer1 = new TQSpacerItem( 0, 0, TQSizePolicy::Expanding, + TQSizePolicy::Minimum ); + groupLayout->addItem( spacer1, 0, 2 ); + + // preview title + TQHBoxLayout* hlay = new TQHBoxLayout( mainLayout, KDialog::spacingHint() ); + //mainLayout->addLayout( hlay ); + TQLabel* lbl = new TQLabel( i18n("Preview"), page ); + hlay->addWidget( lbl ); + TQFrame* frame = new TQFrame( page ); + frame->setSizePolicy( TQSizePolicy::Expanding, TQSizePolicy::Minimum ); + frame->setFrameShape( TQFrame::HLine ); + frame->setFrameShadow( TQFrame::Sunken ); + hlay->addWidget( frame ); + + // preview frame + m_preview = new TQFrame( page ); + m_preview->setSizePolicy( TQSizePolicy::Expanding, TQSizePolicy::Expanding ); + m_preview->setMinimumSize( 370, 180 ); + m_preview->setFrameShape( TQFrame::Panel ); + m_preview->setFrameShadow( TQFrame::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() +{ +} + +TQColor KonqBgndDialog::color() const +{ + if ( m_radioColor->isChecked() ) + return m_buttonColor->color(); + + return TQColor(); +} + +void KonqBgndDialog::initPictures() +{ + TDEGlobal::dirs()->addResourceType( "tiles", + TDEGlobal::dirs()->kde_default("data") + "konqueror/tiles/"); + kdDebug(1203) << TDEGlobal::dirs()->kde_default("data") + "konqueror/tiles/" << endl; + + TQStringList list = TDEGlobal::dirs()->findAllResources("tiles"); + + if ( list.isEmpty() ) + m_comboPicture->comboBox()->insertItem( i18n("None") ); + else { + TQStringList::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 TQString& 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(); + TQString 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 = TQPixmap(); + 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..a5e179b6f --- /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 <[email protected]> + Copyright (c) 1999 David Faure <[email protected]> + + 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 <tqstring.h> +#include <tqpixmap.h> + +#include <kdialogbase.h> + +class KColorButton; +class KURLRequester; +class TQButtonGroup; +class TQRadioButton; + +/** + * 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( TQWidget* parent, const TQString& pixmapFile, + const TQColor& theColor, const TQColor& defaultColor ); + ~KonqBgndDialog(); + + TQColor color() const; + const TQString& pixmapFile() const { return m_pixmapFile; } + +private slots: + void slotBackgroundModeChanged(); + void slotPictureChanged(); + void slotColorChanged(); + +private: + void initPictures(); + void loadPicture( const TQString& fileName ); + + TQColor m_color; + TQPixmap m_pixmap; + TQString m_pixmapFile; + TQFrame* m_preview; + + TQButtonGroup* m_buttonGroup; + TQRadioButton* m_radioColor; + TQRadioButton* 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..bff2fe8f1 --- /dev/null +++ b/libkonq/konq_defaults.h @@ -0,0 +1,49 @@ +/* This file is part of the KDE project + Copyright (C) 1998, 1999 Torben Weis <[email protected]> + Copyright (C) 1999 - 2002 David Faure <[email protected]> + + 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_SMOOTHSCROLL 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..602496b7c --- /dev/null +++ b/libkonq/konq_dirpart.cc @@ -0,0 +1,756 @@ +/* This file is part of the KDE projects + Copyright (C) 2000 David Faure <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; 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 <tdeio/paste.h> +#include <tdeapplication.h> +#include <tdeaction.h> +#include <kdatastream.h> +#include <kdebug.h> +#include <kdirlister.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <tdemessagebox.h> +#include <konq_drag.h> +#include <tdeparts/browserextension.h> +#include <kurldrag.h> +#include <kuserprofile.h> +#include <kurifilter.h> +#include <tdeglobalsettings.h> + +#include <tqapplication.h> +#include <tqclipboard.h> +#include <tqfile.h> +#include <tqguardedptr.h> +#include <assert.h> +#include <tqvaluevector.h> + +class KonqDirPart::KonqDirPartPrivate +{ +public: + KonqDirPartPrivate() : dirLister( 0 ) {} + TQStringList mimeFilters; + TDEToggleAction *aEnormousIcons; + TDEToggleAction *aSmallMediumIcons; + TQValueVector<int> iconSize; + + KDirLister* dirLister; + bool dirSizeDirty; + + void findAvailableIconSizes(void); + int findNearestIconSize(int size); + int nearestIconSizeError(int size); +}; + +void KonqDirPart::KonqDirPartPrivate::findAvailableIconSizes(void) +{ + TDEIconTheme *root = TDEGlobal::instance()->iconLoader()->theme(); + iconSize.resize(1); + if (root) { + TQValueList<int> avSizes = root->querySizes(TDEIcon::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 + TQValueListConstIterator<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}; + + TQValueListConstIterator<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(TDEIcon::SizeSmall); // 16 + iconSize.append(TDEIcon::SizeMedium); // 32 + iconSize.append(TDEIcon::SizeLarge); // 48 + iconSize.append(TDEIcon::SizeHuge); // 64 + } + kdDebug(1203) << "Using " << iconSize.count() << " icon sizes." << endl; +} + +int KonqDirPart::KonqDirPartPrivate::findNearestIconSize(int preferred) +{ + int s1 = iconSize[1]; + if (preferred == 0) return TDEGlobal::iconLoader()->currentSize(TDEIcon::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( TQObject *parent, const char *name ) + :KParts::ReadOnlyPart( parent, name ), + m_pProps( 0L ), + m_findPart( 0L ) +{ + d = new KonqDirPartPrivate; + resetCount(); + //m_bMultipleItemsSelected = false; + + connect( TQApplication::clipboard(), TQT_SIGNAL(dataChanged()), this, TQT_SLOT(slotClipboardDataChanged()) ); + + actionCollection()->setHighlightingEnabled( true ); + + m_paIncIconSize = new TDEAction( i18n( "Enlarge Icons" ), "zoom-in", 0, this, TQT_SLOT( slotIncIconSize() ), actionCollection(), "incIconSize" ); + m_paDecIconSize = new TDEAction( i18n( "Shrink Icons" ), "zoom-out", 0, this, TQT_SLOT( slotDecIconSize() ), actionCollection(), "decIconSize" ); + + m_paDefaultIcons = new TDERadioAction( i18n( "&Default Size" ), 0, actionCollection(), "modedefault" ); + d->aEnormousIcons = new TDERadioAction( i18n( "&Huge" ), 0, + actionCollection(), "modeenormous" ); + m_paHugeIcons = new TDERadioAction( i18n( "&Very Large" ), 0, actionCollection(), "modehuge" ); + m_paLargeIcons = new TDERadioAction( i18n( "&Large" ), 0, actionCollection(), "modelarge" ); + m_paMediumIcons = new TDERadioAction( i18n( "&Medium" ), 0, actionCollection(), "modemedium" ); + d->aSmallMediumIcons = new TDERadioAction( i18n( "&Small" ), 0, + actionCollection(), "modesmallmedium" ); + m_paSmallIcons = new TDERadioAction( 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, TQT_SIGNAL( toggled( bool ) ), this, TQT_SLOT( slotIconSizeToggled( bool ) ) ); + connect( d->aEnormousIcons, TQT_SIGNAL( toggled( bool ) ), + this, TQT_SLOT( slotIconSizeToggled( bool ) ) ); + connect( m_paHugeIcons, TQT_SIGNAL( toggled( bool ) ), this, TQT_SLOT( slotIconSizeToggled( bool ) ) ); + connect( m_paLargeIcons, TQT_SIGNAL( toggled( bool ) ), this, TQT_SLOT( slotIconSizeToggled( bool ) ) ); + connect( m_paMediumIcons, TQT_SIGNAL( toggled( bool ) ), this, TQT_SLOT( slotIconSizeToggled( bool ) ) ); + connect( d->aSmallMediumIcons, TQT_SIGNAL( toggled( bool ) ), + this, TQT_SLOT( slotIconSizeToggled( bool ) ) ); + connect( m_paSmallIcons, TQT_SIGNAL( toggled( bool ) ), this, TQT_SLOT( slotIconSizeToggled( bool ) ) ); + + connect( kapp, TQT_SIGNAL(iconChanged(int)), TQT_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] = TDEIcon::SizeSmall; // 16 + d->iconSize[2] = TDEIcon::SizeSmallMedium; // 22 + d->iconSize[3] = TDEIcon::SizeMedium; // 32 + d->iconSize[4] = TDEIcon::SizeLarge; // 48 + d->iconSize[5] = TDEIcon::SizeHuge; // 64 + d->iconSize[6] = TDEIcon::SizeEnormous; // 128 + d->iconSize[7] = 192; + d->iconSize[8] = 256; + TDEIconTheme *root = TDEGlobal::instance()->iconLoader()->theme(); + if (root) + { + TQValueList<int> avSizes = root->querySizes(TDEIcon::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. + TQValueList<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] = TDEIcon::SizeSmall; + m_iIconSize[2] = TDEIcon::SizeMedium; + m_iIconSize[3] = TDEIcon::SizeLarge; + m_iIconSize[4] = TDEIcon::SizeHuge; + // ... up to here + + TDEAction *a = new TDEAction( i18n( "Configure Background..." ), "background", 0, this, TQT_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 TQStringList& mime) +{ + TQString u = url().url(); + + if ( u.isEmpty () ) + return; + + if ( mime.isEmpty() ) + d->mimeFilters.clear(); + else + d->mimeFilters = mime; +} + +TQStringList KonqDirPart::mimeFilter() const +{ + return d->mimeFilters; +} + +TQScrollView * KonqDirPart::scrollWidget() +{ + return static_cast<TQScrollView *>(widget()); +} + +void KonqDirPart::slotBackgroundSettings() +{ + TQColor bgndColor = m_pProps->bgColor( widget() ); + TQColor defaultColor = TDEGlobalSettings::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 + TQGuardedPtr<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() ) || TQFile::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( TQDataStream& stream ) +{ + stream << m_nameFilter; +} + +void KonqDirPart::restoreState( TQDataStream& stream ) +{ + stream >> m_nameFilter; +} + +void KonqDirPart::saveFindState( TQDataStream& 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( TQDataStream& 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; + TQMimeSource *data = TQApplication::clipboard()->data(); + if ( data->provides( "application/x-tde-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 +{ + TQString actionText = TDEIO::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; + } + + TQString summary = + TDEIO::itemsSummaryString(m_lFileCount + m_lDirCount, + m_lFileCount, + m_lDirCount, + m_lDirSize, + true); + bool bShowsResult = false; + if (m_findPart) + { + TQVariant 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( TDEIO::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 TQString 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(TDEIcon::SizeEnormous)); + else if ( m_paHugeIcons->isChecked() ) + setIconSize(d->findNearestIconSize(TDEIcon::SizeHuge)); + else if ( m_paLargeIcons->isChecked() ) + setIconSize(d->findNearestIconSize(TDEIcon::SizeLarge)); + else if ( m_paMediumIcons->isChecked() ) + setIconSize(d->findNearestIconSize(TDEIcon::SizeMedium)); + else if ( d->aSmallMediumIcons->isChecked() ) + setIconSize(d->findNearestIconSize(TDEIcon::SizeSmallMedium)); + else if ( m_paSmallIcons->isChecked() ) + setIconSize(d->findNearestIconSize(TDEIcon::SizeSmall)); +} + +void KonqDirPart::slotIncIconSize() +{ + int s = m_pProps->iconSize(); + s = s ? s : TDEGlobal::iconLoader()->currentSize( TDEIcon::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 : TDEGlobal::iconLoader()->currentSize( TDEIcon::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) ? TDEGlobal::iconLoader()->currentSize( TDEIcon::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(TDEIcon::SizeEnormous)); + m_paHugeIcons->setChecked(size == d->findNearestIconSize(TDEIcon::SizeHuge)); + m_paLargeIcons->setChecked(size == d->findNearestIconSize(TDEIcon::SizeLarge)); + m_paMediumIcons->setChecked(size == d->findNearestIconSize(TDEIcon::SizeMedium)); + d->aSmallMediumIcons->setChecked(size == d->findNearestIconSize(TDEIcon::SizeSmallMedium)); + m_paSmallIcons->setChecked(size == d->findNearestIconSize(TDEIcon::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, TQT_SIGNAL( started() ), + this, TQT_SLOT( slotStarted() ) ); + connect( m_findPart, TQT_SIGNAL( started() ), + this, TQT_SLOT( slotStartAnimationSearching() ) ); + connect( m_findPart, TQT_SIGNAL( clear() ), + this, TQT_SLOT( slotClear() ) ); + connect( m_findPart, TQT_SIGNAL( newItems( const KFileItemList & ) ), + this, TQT_SLOT( slotNewItems( const KFileItemList & ) ) ); + connect( m_findPart, TQT_SIGNAL( finished() ), // can't name it completed, it conflicts with a KROP signal + this, TQT_SLOT( slotCompleted() ) ); + connect( m_findPart, TQT_SIGNAL( finished() ), + this, TQT_SLOT( slotStopAnimationSearching() ) ); + connect( m_findPart, TQT_SIGNAL( canceled() ), + this, TQT_SLOT( slotCanceled() ) ); + connect( m_findPart, TQT_SIGNAL( canceled() ), + this, TQT_SLOT( slotStopAnimationSearching() ) ); + + connect( m_findPart, TQT_SIGNAL( findClosed() ), + this, TQT_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 != TDEIcon::Desktop) return; + adjustIconSizes(); +} + +void KonqDirPart::slotStartAnimationSearching() +{ + started(0); +} + +void KonqDirPart::slotStopAnimationSearching() +{ + completed(); +} + +void KonqDirPartBrowserExtension::saveState( TQDataStream &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( TQDataStream &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..6b24bf9c5 --- /dev/null +++ b/libkonq/konq_dirpart.h @@ -0,0 +1,351 @@ +/* This file is part of the KDE projects + Copyright (C) 2000 David Faure <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; 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 <tqstring.h> +#include <tdeparts/part.h> +#include <tdeparts/browserextension.h> +#include <tdefileitem.h> +#include <kdatastream.h> +#include <tdeio/global.h> +#include <libkonq_export.h> + +class KDirLister; +namespace KParts { class BrowserExtension; } +class KonqPropsView; +class TQScrollView; +class TDEAction; +class TDEToggleAction; +class KonqDirPartBrowserExtension; + +class LIBKONQ_EXPORT KonqDirPart: public KParts::ReadOnlyPart +{ + Q_OBJECT + + friend class KonqDirPartBrowserExtension; + +public: + KonqDirPart( TQObject *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? + + TQScrollView * scrollWidget(); + + virtual void saveState( TQDataStream &stream ); + virtual void restoreState( TQDataStream &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 TQString & nameFilter ) { m_nameFilter = nameFilter; } + + TQString nameFilter() const { return m_nameFilter; } + + void setFilesToSelect( const TQStringList & 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 TQStringList& filters); + + /** + * Completely clears the internally stored list of mime filters + * set by call to @ref #setMimeFilter. + */ + TQStringList 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: + + TQString m_nameFilter; + TQStringList m_filesToSelect; + + KonqPropsView * m_pProps; + + TDEAction *m_paIncIconSize; + TDEAction *m_paDecIconSize; + TDEToggleAction *m_paDefaultIcons; + TDEToggleAction *m_paHugeIcons; + TDEToggleAction *m_paLargeIcons; + TDEToggleAction *m_paMediumIcons; + TDEToggleAction *m_paSmallIcons; + + KParts::ReadOnlyPart * m_findPart; + KonqDirPartBrowserExtension * m_extension; + + // Remove all those in KDE4 + int m_iIconSize[5]; + TDEIO::filesize_t m_lDirSize; + uint m_lFileCount; + uint m_lDirCount; + +private: + void saveFindState( TQDataStream& ); + void restoreFindState( TQDataStream& ); + + 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( TQDataStream &stream ); + virtual void restoreState( TQDataStream &stream ); + +private: + KonqDirPart* m_dirPart; +}; + +#endif diff --git a/libkonq/konq_drag.cc b/libkonq/konq_drag.cc new file mode 100644 index 000000000..bb05fc8d8 --- /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 <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; 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( TQWidget * dragSource, const char* name ) + : TQIconDrag( 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-tde-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; +} + +TQByteArray KonqIconDrag::encodedData( const char* mime ) const +{ + TQByteArray a; + TQCString mimetype( mime ); + if ( mimetype == "application/x-qiconlist" ) + a = TQIconDrag::encodedData( mime ); + else if ( mimetype == "text/uri-list" ) { + TQCString 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-tde-cutselection" ) { + TQCString 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()) + { + TQStringList uris; + for (TQStringList::ConstIterator it = urls.begin(); it != urls.end(); ++it) + uris.append(KURLDrag::stringToUrl((*it).latin1()).prettyURL()); + TQCString 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()) + { + TQStringList uris; + + for (TQStringList::ConstIterator it = urls.begin(); it != urls.end(); ++it) + uris.append(KURLDrag::stringToUrl((*it).latin1()).url(0, 4)); // 4 for latin1 + + TQCString 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()) + { + TQStringList uris; + for (TQStringList::ConstIterator it = urls.begin(); it != urls.end(); ++it) + uris.append(KURLDrag::stringToUrl((*it).latin1()).prettyURL()); + TQCString 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 TQMimeSource* e ) +{ + return e->provides( "application/x-qiconlist" ) || + e->provides( "text/uri-list" ) || + e->provides( "application/x-tde-cutselection" ); +} + +void KonqIconDrag::append( const TQIconDragItem &item, const TQRect &pr, + const TQRect &tr, const TQString &url ) +{ + TQIconDrag::append( item, pr, tr ); + urls.append( url ); +} + +KonqIconDrag2::KonqIconDrag2( TQWidget * dragSource ) + : KonqIconDrag( dragSource ) +{ +} + +void KonqIconDrag2::append( const TQIconDragItem &item, const TQRect &pr, + const TQRect &tr, const TQString& url, const KURL &mostLocalURL ) +{ + TQString 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-tde-urilist"; + return KonqIconDrag::format( i ); +} + +TQByteArray KonqIconDrag2::encodedData( const char* mime ) const +{ + TQCString mimetype( mime ); + if ( mimetype == "application/x-tde-urilist" ) + { + TQByteArray a; + int c=0; + for (TQStringList::ConstIterator it = m_kdeURLs.begin(); it != m_kdeURLs.end(); ++it) { + TQCString 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, TQWidget * dragSource, const char* name ) +{ + // See KURLDrag::newDrag + TQStrList 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 TQStrList & urls, bool cut, TQWidget * dragSource, const char* name ) + : TQUriDrag( 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, TQWidget * dragSource ) + : TQUriDrag( dragSource ), + m_bCutSelection( cut ) +{ + TQStrList 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 TQUriDrag. 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-tde-cutselection"; + else if ( i == 2 ) + return "text/plain"; + else if ( i == 3 ) + return "application/x-tde-urilist"; + else return 0; +} + +TQByteArray KonqDrag::encodedData( const char* mime ) const +{ + TQByteArray a; + TQCString mimetype( mime ); + if ( mimetype == "text/uri-list" ) + { + // Code taken from TQUriDrag::setUris + int c=0; + for (TQStrListIterator it(m_urls); *it; ++it) { + int l = tqstrlen(*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-tde-urilist" ) + { + return TQUriDrag::encodedData( "text/uri-list" ); + } + else if ( mimetype == "application/x-tde-cutselection" ) + { + TQCString 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" ) + { + TQStringList uris; + for (TQStrListIterator it(m_urls); *it; ++it) + uris.append(KURLDrag::stringToUrl(*it).prettyURL()); + TQCString 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 TQMimeSource *e ) +{ + TQByteArray a = e->encodedData( "application/x-tde-cutselection" ); + if ( a.isEmpty() ) + return false; + else + { + kdDebug(1203) << "KonqDrag::decodeIsCutSelection : a=" << TQCString(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..c30bbe49b --- /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 <[email protected]> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef __konqdrag_h__ +#define __konqdrag_h__ + +#include <tqdragobject.h> +#include <tqrect.h> +#include <tqstring.h> +#include <tqiconview.h> + +#include <libkonq_export.h> + +#include <kurl.h> + +/***************************************************************************** + * + * Class KonqIconDrag + * + *****************************************************************************/ + +// Clipboard/dnd data for: Icons + URLS + isCut +class LIBKONQ_EXPORT KonqIconDrag : public TQIconDrag +{ + Q_OBJECT + +public: + KonqIconDrag( TQWidget * dragSource, const char* name = 0 ); + virtual ~KonqIconDrag() {} + + const char* format( int i ) const; + TQByteArray encodedData( const char* mime ) const; + + void append( const TQIconDragItem &item, const TQRect &pr, + const TQRect &tr, const TQString &url ); + + void setMoveSelection( bool move ) { m_bCutSelection = move; } + + static bool canDecode( const TQMimeSource* e ); + +protected: // KDE4: private. And d pointer... + TQStringList 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( TQWidget * dragSource ); + virtual ~KonqIconDrag2() {} + + virtual const char* format( int i ) const; + virtual TQByteArray encodedData( const char* mime ) const; + + void append( const TQIconDragItem &item, const TQRect &pr, + const TQRect &tr, const TQString &url, const KURL &mostLocalURL ); + +private: + TQStringList m_kdeURLs; +}; + +// Clipboard/dnd data for: URLS + isCut +class LIBKONQ_EXPORT KonqDrag : public TQUriDrag +{ +public: + // KDE4: remove, use KonqDrag constructor instead + static KonqDrag * newDrag( const KURL::List & urls, + bool move, TQWidget * 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, TQWidget * dragSource = 0 ); + +protected: + // KDE4: remove + KonqDrag( const TQStrList & urls, bool cut, TQWidget * dragSource, const char* name ); + +public: + virtual ~KonqDrag() {} + + virtual const char* format( int i ) const; + virtual TQByteArray 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 TQMimeSource *e ); + +protected: // KDE4: private. And d pointer... + bool m_bCutSelection; + TQStrList 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..17e0f3381 --- /dev/null +++ b/libkonq/konq_events.cc @@ -0,0 +1,8 @@ + +#include <tdefileitem.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..dab0f3fa1 --- /dev/null +++ b/libkonq/konq_events.h @@ -0,0 +1,70 @@ +#ifndef __konq_events_h__ +#define __konq_events_h__ + +#include <tdeparts/event.h> +#include <tqptrlist.h> +#include <libkonq_export.h> + +namespace KParts +{ + class ReadOnlyPart; +} + +class TDEConfig; +class KFileItem; +typedef TQPtrList<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 TQEvent *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 TQEvent *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( TDEConfig *config, const TQString &prefix, bool save ) : KParts::Event( s_configEventName ), m_config( config ), m_prefix( prefix ), m_save( save ) {} + + TDEConfig * config() const { return m_config; } + TQString prefix() const { return m_prefix; } + bool save() const { return m_save; } + + static bool test( const TQEvent *event ) { return KParts::Event::test( event, s_configEventName ); } + +private: + static const char *s_configEventName; + + TDEConfig *m_config; + TQString m_prefix; + bool m_save; +}; + +#endif diff --git a/libkonq/konq_faviconmgr.cc b/libkonq/konq_faviconmgr.cc new file mode 100644 index 000000000..c5c828ec0 --- /dev/null +++ b/libkonq/konq_faviconmgr.cc @@ -0,0 +1,57 @@ +/* This file is part of the KDE project + Copyright (C) 2000 Malte Starostik <[email protected]> + + 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 <tdeapplication.h> +#include <tdeconfig.h> +#include <tdeglobal.h> +#include <kmimetype.h> + +#include "konq_faviconmgr.moc" + +KonqFavIconMgr::KonqFavIconMgr(TQObject *parent, const char *name) + : TQObject(parent, name), + DCOPObject("KonqFavIconMgr") +{ + connectDCOPSignal("kded", "favicons", + "iconChanged(bool, TQString, TQString)", + "notifyChange(bool, TQString, TQString)", false); +} + +TQString KonqFavIconMgr::iconForURL(const TQString &url) +{ + return KMimeType::favIconForURL( KURL(url) ); +} + +void KonqFavIconMgr::setIconForURL(const KURL &url, const KURL &iconURL) +{ + TQByteArray data; + TQDataStream str(data, IO_WriteOnly); + str << url << iconURL; + kapp->dcopClient()->send("kded", "favicons", "setIconForURL(KURL, KURL)", data); +} + +void KonqFavIconMgr::downloadHostIcon(const KURL &url) +{ + TQByteArray data; + TQDataStream 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..48c345bcd --- /dev/null +++ b/libkonq/konq_faviconmgr.h @@ -0,0 +1,70 @@ +/* This file is part of the KDE project + Copyright (C) 1999 Malte Starostik <[email protected]> + + 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 TQObject, public DCOPObject +{ + Q_OBJECT + K_DCOP +public: + /** + * Constructor. + */ + KonqFavIconMgr(TQObject *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 TQString::null otherwise + */ + static TQString iconForURL(const TQString &url); + +k_dcop: + /** + * an icon changed, updates the combo box + */ + virtual ASYNC notifyChange( bool, TQString, TQString ) = 0; + +signals: + void changed(); +}; + +#endif + diff --git a/libkonq/konq_filetip.cc b/libkonq/konq_filetip.cc new file mode 100644 index 000000000..8ad1e0d6f --- /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 <[email protected]> + Copyright (C) 2000, 2001, 2002 David Faure <[email protected]> + Copyright (C) 2004 Martin Koller <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; 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 <tdefileitem.h> +#include <tdeglobalsettings.h> +#include <kstandarddirs.h> +#include <tdeapplication.h> + +#include <tqlabel.h> +#include <tqtooltip.h> +#include <tqlayout.h> +#include <tqpainter.h> +#include <tqscrollview.h> +#include <tqtimer.h> + +#include <fixx11h.h> +//-------------------------------------------------------------------------------- + +KonqFileTip::KonqFileTip( TQScrollView* parent ) + : TQFrame( 0, 0, (WFlags)(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 TQLabel(this); + m_textLabel = new TQLabel(this); + m_textLabel->setAlignment(TQt::AlignAuto | TQt::AlignTop); + + TQGridLayout* layout = new TQGridLayout(this, 1, 2, 8, 0); + layout->addWidget(m_iconLabel, 0, 0); + layout->addWidget(m_textLabel, 0, 1); + layout->setResizeMode(TQLayout::Fixed); + + setPalette( TQToolTip::palette() ); + setMargin( 1 ); + setFrameStyle( TQFrame::Plain | TQFrame::Box ); + + m_timer = new TQTimer(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 TQRect &rect, const TQPixmap *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( TQPixmap() ); + } + + // 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, TQT_SIGNAL(timeout()), this, TQT_SLOT(startDelayed())); + m_timer->start( 300, true ); + } +} + +void KonqFileTip::reposition() +{ + if ( m_rect.isEmpty() || !m_view || !m_view->viewport() ) return; + + TQRect rect = m_rect; + TQPoint off = m_view->viewport()->mapToGlobal( m_view->contentsToViewport( rect.topRight() ) ); + rect.moveTopRight( off ); + + TQPoint 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 ? + TQRect desk = TDEGlobalSettings::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 TQPixmap& pixmap ) +{ + m_previewJob = 0; + if (item != m_item) return; + + m_iconLabel -> setPixmap(pixmap); +} + +void KonqFileTip::gotPreviewResult() +{ + m_previewJob = 0; +} + +void KonqFileTip::drawContents( TQPainter *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 + TQFrame::drawContents( p ); + return; + } + + if ( m_corners[m_corner].isNull()) + m_corners[m_corner].load( locate( "data", TQString::fromLatin1( "konqueror/pics/%1.png" ).arg( names[m_corner] ) ) ); + + TQPixmap &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; + } + + TQFrame::drawContents( p ); +} + +void KonqFileTip::setFilter( bool enable ) +{ + if ( enable == m_filter ) return; + + if ( enable ) { + kapp->installEventFilter( this ); + TQApplication::setGlobalMouseTracking( true ); + } + else { + TQApplication::setGlobalMouseTracking( false ); + kapp->removeEventFilter( this ); + } + m_filter = enable; +} + +void KonqFileTip::showTip() +{ + TQString text = m_item->getToolTipText(m_num); + + if ( text.isEmpty() ) return; + + m_timer->disconnect( this ); + connect(m_timer, TQT_SIGNAL(timeout()), this, TQT_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 = TDEIO::filePreview( oneItem, 256, 256, 64, 70, true, true, 0); + connect( m_previewJob, TQT_SIGNAL( gotPreview( const KFileItem *, const TQPixmap & ) ), + this, TQT_SLOT( gotPreview( const KFileItem *, const TQPixmap & ) ) ); + connect( m_previewJob, TQT_SIGNAL( result( TDEIO::Job * ) ), + this, TQT_SLOT( gotPreviewResult() ) ); + } + + m_timer->disconnect( this ); + connect(m_timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(showTip())); + m_timer->start( 400, true ); +} + +void KonqFileTip::resizeEvent( TQResizeEvent* event ) +{ + TQFrame::resizeEvent(event); + reposition(); +} + +bool KonqFileTip::eventFilter( TQObject *, TQEvent *e ) +{ + switch ( e->type() ) + { + case TQEvent::Leave: + case TQEvent::MouseButtonPress: + case TQEvent::MouseButtonRelease: + case TQEvent::KeyPress: + case TQEvent::KeyRelease: + case TQEvent::FocusIn: + case TQEvent::FocusOut: + case TQEvent::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..4bbc9d0e2 --- /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 <[email protected]> + Copyright (C) 2000, 2001, 2002 David Faure <[email protected]> + Copyright (C) 2004 Martin Koller <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; 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 <tqframe.h> +#include <tqpixmap.h> +#include <tdeio/previewjob.h> + +#include <libkonq_export.h> + +class KFileItem; +class TQLabel; +class TQScrollView; +class TQTimer; + +//-------------------------------------------------------------------------------- + +class LIBKONQ_EXPORT KonqFileTip : public TQFrame +{ + Q_OBJECT + + public: + KonqFileTip( TQScrollView *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 TQRect &rect = TQRect(), + const TQPixmap *pixmap = 0 ); + + virtual bool eventFilter( TQObject *, TQEvent *e ); + + protected: + virtual void drawContents( TQPainter *p ); + virtual void resizeEvent( TQResizeEvent * ); + + private slots: + void gotPreview( const KFileItem*, const TQPixmap& ); + void gotPreviewResult(); + + void startDelayed(); + void showTip(); + void hideTip(); + + private: + void setFilter( bool enable ); + + void reposition(); + + TQLabel* m_iconLabel; + TQLabel* m_textLabel; + bool m_on : 1; + bool m_preview : 1; // shall the preview icon be shown + bool m_filter : 1; + TQPixmap m_corners[4]; + int m_corner; + int m_num; + TQScrollView* m_view; + KFileItem* m_item; + TDEIO::PreviewJob* m_previewJob; + TQRect m_rect; + TQTimer* m_timer; +}; + +#endif diff --git a/libkonq/konq_historycomm.cc b/libkonq/konq_historycomm.cc new file mode 100644 index 000000000..6cfd9b53f --- /dev/null +++ b/libkonq/konq_historycomm.cc @@ -0,0 +1,41 @@ +#include "konq_historycomm.h" + +bool KonqHistoryEntry::marshalURLAsStrings; + +// TQDataStream operators (read and write a KonqHistoryEntry +// from/into a TQDataStream) +TQDataStream& operator<< (TQDataStream& 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; +} + +TQDataStream& operator>> (TQDataStream& s, KonqHistoryEntry& e) { + if (KonqHistoryEntry::marshalURLAsStrings) + { + TQString 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..96c3a375e --- /dev/null +++ b/libkonq/konq_historycomm.h @@ -0,0 +1,77 @@ +/* This file is part of the KDE project + Copyright (C) 2000 Carsten Pfeiffer <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; 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 <tqdatetime.h> +#include <tqstringlist.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; + TQString typedURL; + TQString title; + TQ_UINT32 numberOfTimesVisited; + TQDateTime firstVisited; + TQDateTime lastVisited; +}; + + +// TQDataStream operators (read and write a KonqHistoryEntry +// from/into a QDataStream +TQDataStream& operator<< (TQDataStream& s, const KonqHistoryEntry& e); +TQDataStream& operator>> (TQDataStream& 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( TQCString objId ) : DCOPObject( objId ) {} + +k_dcop: + virtual ASYNC notifyHistoryEntry( KonqHistoryEntry e, TQCString saveId) = 0; + virtual ASYNC notifyMaxCount( TQ_UINT32 count, TQCString saveId ) = 0; + virtual ASYNC notifyMaxAge( TQ_UINT32 days, TQCString saveId ) = 0; + virtual ASYNC notifyClear( TQCString saveId ) = 0; + virtual ASYNC notifyRemove( KURL url, TQCString saveId ) = 0; + virtual ASYNC notifyRemove( KURL::List url, TQCString saveId ) = 0; + virtual TQStringList 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..25cfef345 --- /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 <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; 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 <tdeapplication.h> +#include <kdebug.h> +#include <ksavefile.h> +#include <ksimpleconfig.h> +#include <kstandarddirs.h> + +#include <zlib.h> + +#include "konqbookmarkmanager.h" + +const TQ_UINT32 KonqHistoryManager::s_historyVersion = 3; + +KonqHistoryManager::KonqHistoryManager( TQObject *parent, const char *name ) + : KParts::HistoryProvider( parent, name ), + KonqHistoryComm( "KonqHistoryManager" ) +{ + m_updateTimer = new TQTimer( this ); + + // defaults + TDEConfig *config = TDEGlobal::config(); + TDEConfigGroupSaver cs( config, "HistorySettings" ); + m_maxCount = config->readNumEntry( "Maximum of History entries", 500 ); + m_maxCount = TQMAX( 1, m_maxCount ); + m_maxAgeDays = config->readNumEntry( "Maximum age of History entries", 90); + + m_history.setAutoDelete( true ); + m_filename = locateLocal( "data", + TQString::fromLatin1("konqueror/konq_history" )); + + if ( !kapp->dcopClient()->isAttached() ) + kapp->dcopClient()->attach(); + + + // take care of the completion object + m_pCompletion = new TDECompletion; + m_pCompletion->setOrder( TDECompletion::Weighted ); + + // and load the history + loadHistory(); + + connect( m_updateTimer, TQT_SIGNAL( timeout() ), TQT_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(); + + TQFile 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; + } + + TQDataStream fileStream( &file ); + TQByteArray 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 :) + TQDataStream crcStream( data, IO_ReadOnly ); + + if ( !fileStream.atEnd() ) { + TQ_UINT32 version; + fileStream >> version; + + TQDataStream *stream = &fileStream; + + bool crcChecked = false; + bool crcOk = false; + + if ( version == 2 || version == 3) { + TQ_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] + TQ_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; + TQ_CHECK_PTR( entry ); + *stream >> *entry; + // kdDebug(1203) << "## loaded entry: " << entry->url << ", Title: " << entry->title << endl; + m_history.append( entry ); + TQString urlString2 = entry->url.prettyURL(); + + addToCompletion( urlString2, entry->typedURL, entry->numberOfTimesVisited ); + + // and fill our baseclass. + TQString 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; + } + + TQDataStream *fileStream = file.dataStream(); + *fileStream << s_historyVersion; + + TQByteArray data; + TQDataStream stream( data, IO_WriteOnly ); + + //We use KURL for marshalling URLs in entries in the V3 + //file format + KonqHistoryEntry::marshalURLAsStrings = false; + TQPtrListIterator<KonqHistoryEntry> it( m_history ); + KonqHistoryEntry *entry; + while ( (entry = it.current()) ) { + stream << *entry; + ++it; + } + + //For DCOP, transfer strings instead - wire compat. + KonqHistoryEntry::marshalURLAsStrings = true; + + TQ_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 ); + + TQString 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 TQString& typedURL, + const TQString& title ) +{ + addToHistory( true, url, typedURL, title ); +} + +void KonqHistoryManager::confirmPending( const KURL& url, + const TQString& typedURL, + const TQString& title ) +{ + addToHistory( false, url, typedURL, title ); +} + + +void KonqHistoryManager::addToHistory( bool pending, const KURL& _url, + const TQString& typedURL, + const TQString& 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( TQString::null ); // No password in the history, especially not in the completion! + url.setHost( url.host().lower() ); // All host parts lower case + KonqHistoryEntry entry; + TQString 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 = TQDateTime::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. + TQMapIterator<TQString,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 TQString& 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 = TQDateTime::currentDateTime(); + entry.lastVisited = entry.firstVisited; + emitAddToHistory( entry ); +} + +void KonqHistoryManager::emitAddToHistory( const KonqHistoryEntry& entry ) +{ + TQByteArray data; + TQDataStream 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, TQCString)", + data ); +} + + +void KonqHistoryManager::removePending( const KURL& url ) +{ + // kdDebug(1203) << "## Removing pending... " << url.prettyURL() << endl; + + if ( url.isLocalFile() ) + return; + + TQMapIterator<TQString,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() +{ + TQMapIterator<TQString,KonqHistoryEntry*> it = m_pending.begin(); + while ( it != m_pending.end() ) { + delete it.data(); + ++it; + } + m_pending.clear(); +} + +void KonqHistoryManager::emitRemoveFromHistory( const KURL& url ) +{ + TQByteArray data; + TQDataStream stream( data, IO_WriteOnly ); + stream << url << objId(); + kapp->dcopClient()->send( "konqueror*", "KonqHistoryManager", + "notifyRemove(KURL, TQCString)", data ); +} + +void KonqHistoryManager::emitRemoveFromHistory( const KURL::List& urls ) +{ + TQByteArray data; + TQDataStream stream( data, IO_WriteOnly ); + stream << urls << objId(); + kapp->dcopClient()->send( "konqueror*", "KonqHistoryManager", + "notifyRemove(KURL::List, TQCString)", data ); +} + +void KonqHistoryManager::emitClear() +{ + TQByteArray data; + TQDataStream stream( data, IO_WriteOnly ); + stream << objId(); + kapp->dcopClient()->send( "konqueror*", "KonqHistoryManager", + "notifyClear(TQCString)", data ); +} + +void KonqHistoryManager::emitSetMaxCount( TQ_UINT32 count ) +{ + TQByteArray data; + TQDataStream stream( data, IO_WriteOnly ); + stream << count << objId(); + kapp->dcopClient()->send( "konqueror*", "KonqHistoryManager", + "notifyMaxCount(TQ_UINT32, TQCString)", data ); +} + +void KonqHistoryManager::emitSetMaxAge( TQ_UINT32 days ) +{ + TQByteArray data; + TQDataStream stream( data, IO_WriteOnly ); + stream << days << objId(); + kapp->dcopClient()->send( "konqueror*", "KonqHistoryManager", + "notifyMaxAge(TQ_UINT32, TQCString)", data ); +} + +/////////////////////////////////////////////////////////////////// +// DCOP called methods + +void KonqHistoryManager::notifyHistoryEntry( KonqHistoryEntry e, + TQCString ) +{ + //kdDebug(1203) << "Got new entry from Broadcast: " << e.url.prettyURL() << endl; + + KonqHistoryEntry *entry = findEntry( e.url ); + TQString 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( TQ_UINT32 count, TQCString ) +{ + m_maxCount = count; + clearPending(); + adjustSize(); + + TDEConfig *config = TDEGlobal::config(); + TDEConfigGroupSaver cs( config, "HistorySettings" ); + config->writeEntry( "Maximum of History entries", m_maxCount ); + + if ( isSenderOfBroadcast() ) { + saveHistory(); + config->sync(); + } +} + +void KonqHistoryManager::notifyMaxAge( TQ_UINT32 days, TQCString ) +{ + m_maxAgeDays = days; + clearPending(); + adjustSize(); + + TDEConfig *config = TDEGlobal::config(); + TDEConfigGroupSaver cs( config, "HistorySettings" ); + config->writeEntry( "Maximum age of History entries", m_maxAgeDays ); + + if ( isSenderOfBroadcast() ) { + saveHistory(); + config->sync(); + } +} + +void KonqHistoryManager::notifyClear( TQCString ) +{ + clearPending(); + m_history.clear(); + m_pCompletion->clear(); + + if ( isSenderOfBroadcast() ) + saveHistory(); + + KParts::HistoryProvider::clear(); // also emits the cleared() signal +} + +void KonqHistoryManager::notifyRemove( KURL url, TQCString ) +{ + 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 ); + + TQString 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, TQCString ) +{ + 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 ); + + TQString 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() +{ + TQString file = locateLocal( "config", TQString::fromLatin1("konq_history")); + if ( file.isEmpty() ) + return false; + + KonqHistoryEntry *entry; + KSimpleConfig config( file ); + config.setGroup("History"); + TQStringList items = config.readListEntry( "CompletionItems" ); + TQStringList::Iterator it = items.begin(); + + while ( it != items.end() ) { + entry = createFallbackEntry( *it ); + if ( entry ) { + m_history.append( entry ); + addToCompletion( entry->url.prettyURL(), TQString::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 TDECompletion +KonqHistoryEntry * KonqHistoryManager::createFallbackEntry(const TQString& item) const +{ + // code taken from TDECompletion::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 = TQDateTime::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(); +} + +TQStringList KonqHistoryManager::allURLs() const +{ + TQStringList list; + KonqHistoryIterator it ( m_history ); + for ( ; it.current(); ++it ) + list.append( it.current()->url.url() ); + + return list; +} + +void KonqHistoryManager::addToCompletion( const TQString& url, const TQString& typedURL, + int numberOfTimesVisited ) +{ + m_pCompletion->addItem( url, numberOfTimesVisited ); + // typed urls have a higher priority + m_pCompletion->addItem( typedURL, numberOfTimesVisited +10 ); +} + +void KonqHistoryManager::removeFromCompletion( const TQString& url, const TQString& 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( TQPtrCollection::Item item1, + TQPtrCollection::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..c4cc6a9b1 --- /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 <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; 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 <tqdatastream.h> +#include <tqfile.h> +#include <tqptrlist.h> +#include <tqobject.h> +#include <tqmap.h> +#include <tqtimer.h> + +#include <dcopobject.h> + +#include <kcompletion.h> +#include <kurl.h> +#include <tdeparts/historyprovider.h> + +#include "konq_historycomm.h" + +#include <libkonq_export.h> + +class TDECompletion; + + +typedef TQPtrList<KonqHistoryEntry> KonqBaseHistoryList; +typedef TQPtrListIterator<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( TQPtrCollection::Item, TQPtrCollection::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 TDECompletion object + */ +class LIBKONQ_EXPORT KonqHistoryManager : public KParts::HistoryProvider, + public KonqHistoryComm +{ + Q_OBJECT + +public: + static KonqHistoryManager *kself() { + return static_cast<KonqHistoryManager*>( KParts::HistoryProvider::self() ); + } + + KonqHistoryManager( TQObject *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( TQ_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( TQ_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. + */ + TQ_UINT32 maxCount() const { return m_maxCount; } + + /** + * @returns the current maximum age (in days) of history entries. + */ + TQ_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 TQString& typedURL = TQString::null, + const TQString& title = TQString::null ); + + /** + * Confirms and updates the entry for @p url. + */ + void confirmPending( const KURL& url, + const TQString& typedURL = TQString::null, + const TQString& title = TQString::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 TDECompletion object. + */ + TDECompletion * 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 TQString& ); + virtual void remove( const TQString& ) {} + 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 < + TQDateTime(TQDate::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, TQCString saveId ); + + /** + * Called when the configuration of the maximum count changed. + * Called via DCOP by some config-module + */ + virtual void notifyMaxCount( TQ_UINT32 count, TQCString saveId ); + + /** + * Called when the configuration of the maximum age of history-entries + * changed. Called via DCOP by some config-module + */ + virtual void notifyMaxAge( TQ_UINT32 days, TQCString saveId ); + + /** + * Clears the history completely. Called via DCOP by some config-module + */ + virtual void notifyClear( TQCString 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, TQCString 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, TQCString saveId ); + + /** + * @returns a list of all urls in the history. + */ + virtual TQStringList 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 TQString& typedURL = TQString::null, + const TQString& title = TQString::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 TQString& 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. + */ + TQStringList m_updateURLs; + +private slots: + /** + * Called by the updateTimer to emit the KParts::HistoryProvider::updated() + * signal so that tdehtml 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 TQString& ) const; + + void addToCompletion( const TQString& url, const TQString& typedURL, int numberOfTimesVisited = 1 ); + void removeFromCompletion( const TQString& url, const TQString& typedURL ); + + TQString 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. + */ + TQMap<TQString,KonqHistoryEntry*> m_pending; + + TQ_UINT32 m_maxCount; // maximum of history entries + TQ_UINT32 m_maxAgeDays; // maximum age of a history entry + + TDECompletion *m_pCompletion; // the completion object we sync with + + /** + * A timer that will emit the KParts::HistoryProvider::updated() signal + * thru the slotEmitUpdated slot. + */ + TQTimer *m_updateTimer; + + static const TQ_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..8cb222659 --- /dev/null +++ b/libkonq/konq_iconviewwidget.cc @@ -0,0 +1,1937 @@ +/* This file is part of the KDE projects + Copyright (C) 1998, 1999 Torben Weis <[email protected]> + Copyright (C) 2000 - 2005 David Faure <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; 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 <tqclipboard.h> +#include <tqlayout.h> +#include <tqtimer.h> +#include <tqpainter.h> +#include <tqtooltip.h> +#include <tqlabel.h> +#include <tqmovie.h> +#include <tqregexp.h> +#include <tqcursor.h> + +#include <tdeapplication.h> +#include <kdebug.h> +#include <tdeio/previewjob.h> +#include <tdefileivi.h> +#include <konq_settings.h> +#include <konq_drag.h> +#include <tdeglobalsettings.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 <tdelocale.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; + TQTimer *pSoundTimer; + bool bSoundPreviews; + bool bSoundItemClicked; + bool bAllowSetWallpaper; + bool bCaseInsensitive; + bool bBoostPreview; + + // Animated icons support + bool doAnimations; + TQMovie* m_movie; + int m_movieBlocked; + TQString movieFileName; + + TDEIO::PreviewJob *pPreviewJob; + KonqFileTip* pFileTip; + TQStringList previewSettings; + bool renameItem; + bool firstClick; + bool releaseMouseEvent; + TQPoint mousePos; + int mouseState; + TQTimer *pActivateDoubleClick; + TQStringList* pPreviewMimeTypes; + bool bProgramsURLdrag; +}; + +KonqIconViewWidget::KonqIconViewWidget( TQWidget * parent, const char * name, WFlags f, bool kdesktop ) + : TDEIconView( 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, TQT_SIGNAL( dropped( TQDropEvent *, const TQValueList<TQIconDragItem> & ) ), + this, TQT_SLOT( slotDropped( TQDropEvent*, const TQValueList<TQIconDragItem> & ) ) ); + + connect( this, TQT_SIGNAL( selectionChanged() ), + this, TQT_SLOT( slotSelectionChanged() ) ); + + kapp->addKipcEventMask( KIPC::IconChanged ); + connect( kapp, TQT_SIGNAL(iconChanged(int)), TQT_SLOT(slotIconChanged(int)) ); + connect( this, TQT_SIGNAL(onItem(TQIconViewItem *)), TQT_SLOT(slotOnItem(TQIconViewItem *)) ); + connect( this, TQT_SIGNAL(onViewport()), TQT_SLOT(slotOnViewport()) ); + connect( this, TQT_SIGNAL(itemRenamed(TQIconViewItem *, const TQString &)), TQT_SLOT(slotItemRenamed(TQIconViewItem *, const TQString &)) ); + + m_pSettings = KonqFMSettings::settings(); // already needed in setItemTextPos(), calculateGridX() + d->bBoostPreview = boostPreview(); + + // hardcoded settings + setSelectionMode( TQIconView::Extended ); + setItemTextPos( TQIconView::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 = TQString::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( TQFocusEvent * 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(); + + TDEIconView::focusOutEvent( ev ); +} + +void KonqIconViewWidget::slotItemRenamed(TQIconViewItem *item, const TQString &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, TDEIconView 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) + TDEIO::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 != TDEIcon::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() +{ + TDEConfigGroup cfgGroup( TDEGlobal::config(), "DesktopIcons" ); + d->doAnimations = cfgGroup.readBoolEntry( "Animated", true /*default*/ ); +} + +void KonqIconViewWidget::slotOnItem( TQIconViewItem *_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++; + TQTimer::singleShot(300, this, TQT_SLOT(slotReenableAnimation())); + d->m_movie->restart(); + d->m_movie->unpause(); + } + } + else +#endif + { + TQMovie movie = TDEGlobal::iconLoader()->loadMovie( d->pActiveItem->mouseOverAnimation(), TDEIcon::Desktop, d->pActiveItem->iconSize() ); + if ( !movie.isNull() ) + { + delete d->m_movie; + d->m_movie = new TQMovie( 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 TQPixmap* 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, TQT_SLOT( slotMovieUpdate(const TQRect &) ) ); + d->m_movie->connectStatus( TQT_TQOBJECT(this), TQT_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( TQString::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()) + && TDEGlobalSettings::showFilePreview(item->item()->url()) + && topLevelWidget() == kapp->activeWindow()) + { + d->pSoundItem = item; + d->bSoundItemClicked = false; + if (!d->pSoundTimer) + { + d->pSoundTimer = new TQTimer(this); + connect(d->pSoundTimer, TQT_SIGNAL(timeout()), TQT_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; + TQTimer::singleShot(300, this, TQT_SLOT(slotReenableAnimation())); + } +#endif + d->pActiveItem->refreshIcon( true ); + Q_ASSERT( d->pActiveItem->state() == TDEIcon::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 TQPixmap &pix) +{ + // ### slow. Idea: move KonqKfmIconView's m_itemDict into this class + for (TQIconViewItem *it = firstItem(); it; it = it->nextItem()) + { + KFileIVI* current = static_cast<KFileIVI *>(it); + if (current->item() == item) + { + if (item->overlays() & TDEIcon::HiddenOverlay) { + TQPixmap p(pix); + + TDEIconEffect::semiTransparent(p); + current->setThumbnailPixmap(p); + } else { + current->setThumbnailPixmap(pix); + } + break; + } + } +} + +void KonqIconViewWidget::slotPreviewResult() +{ + d->pPreviewJob = 0; + emit imagePreviewFinished(); +} + +void KonqIconViewWidget::slotToolTipPreview(const KFileItem* , const TQPixmap &) +{ +// unused - remove for KDE4 +} + +void KonqIconViewWidget::slotToolTipPreviewResult() +{ +// unused - remove for KDE4 +} + +void KonqIconViewWidget::slotMovieUpdate( const TQRect& 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 TQPixmap &frame = d->m_movie->framePixmap(); + // This can happen if the icon was scaled to the desired size, so TDEIconLoader + // will happily return a movie with different dimensions than the icon + int iconSize=d->pActiveItem->iconSize(); + if (iconSize==0) iconSize = TDEGlobal::iconLoader()->currentSize( TDEIcon::Desktop ); + if ( frame.width() != iconSize || frame.height() != iconSize ) { + d->pActiveItem->setAnimated( false ); + d->m_movie->pause(); + // No movie available, remember it + d->pActiveItem->setMouseOverAnimation( TQString::null ); + d->pActiveItem->setActive( true ); + return; + } + d->pActiveItem->setPixmapDirect( frame, false, false /*no redraw*/ ); + TQRect 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( TQString::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 + TDEIconView::clear(); + d->pActiveItem = 0L; +} + +void KonqIconViewWidget::takeItem( TQIconViewItem *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() ); + + TDEIconView::takeItem( item ); +} + +// Currently unused - remove in KDE 4.0 +void KonqIconViewWidget::setThumbnailPixmap( KFileIVI * item, const TQPixmap & 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 + TQColor normalTextColor = m_pSettings->normalTextColor(); + setItemColor( normalTextColor ); + + if (m_bDesktop) + { + TQColor itemTextBg = m_pSettings->itemTextBackground(); + if ( itemTextBg.isValid() ) + setItemTextBackground( itemTextBg ); + else + setItemTextBackground( Qt::NoBrush ); + } + + bool on = m_pSettings->showFileTips() && TQToolTip::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 + TQFont font( m_pSettings->standardFont() ); + if (!m_bDesktop) + font.setUnderline( m_pSettings->underlineLink() ); + + if ( font != KonqIconViewWidget::font() ) + { + setFont( font ); + if (!bInit) + { + // TQIconView 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() == TQIconView::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; + + TDEConfigGroup group( TDEGlobal::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 TQStringList& 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 : TDEGlobal::iconLoader()->currentSize( TDEIcon::Desktop ); + // choose spacing depending on font, but min 5 (due to KFileIVI move limit) + setSpacing( ( m_bDesktop || ( realSize > TDEIcon::SizeSmall ) ) ? + TQMAX( 5, TQFontMetrics(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 ( TQIconViewItem *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 TQString& mimeType, const TQStringList& mimeList ) const +{ + // Code duplication from TDEIO::PreviewJob + KMimeType::Ptr mime = KMimeType::mimeType( mimeType ); + for (TQStringList::ConstIterator mt = mimeList.begin(); mt != mimeList.end(); ++mt) + { + if ( mime->is( *mt ) ) + return true; + // Support for *mt == "image/*" + TQString tmp( mimeType ); + if ( (*mt).endsWith("*") && tmp.replace(TQRegExp("/.*"), "/*") == (*mt) ) + return true; + if ( (*mt) == "text/plain" ) + { + TQVariant textProperty = mime->property( "X-TDE-text" ); + if ( textProperty.type() == TQVariant::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 : TDEGlobal::iconLoader()->currentSize( TDEIcon::Desktop ); + + if ( m_bSetGridX ) + if ( pos == TQIconView::Bottom ) + setGridX( TQMAX( sz + 50, previewIconSize( sz ) + 13 ) ); + else + { + setMaxItemWidth( TQMAX( sz, previewIconSize( sz ) ) + m_pSettings->iconTextWidth() ); + setGridX( -1 ); + } + + TDEIconView::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 : TDEGlobal::iconLoader()->currentSize( TDEIcon::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() + TQMAX( TQMAX( iconSize, previewSize ), m_pSettings->iconTextWidth() ); + int textHeight = iconTextHeight() * fontMetrics().height(); + *dy = spacing() + TQMAX( 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() == TQIconView::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 : TDEGlobal::iconLoader()->currentSize( TDEIcon::Desktop ); + int newGridX; + + if ( itemTextPos() == TQIconView::Bottom ) + newGridX = TQMAX( sz + 50, previewIconSize( sz ) + 13 ); + else + newGridX = TQMAX( sz, previewIconSize( sz ) ) + m_pSettings->iconTextWidth(); + + //kdDebug(1203) << "gridXValue: " << newGridX << " sz=" << sz << endl; + return newGridX; +} + +void KonqIconViewWidget::refreshMimeTypes() +{ + updatePreviewMimeTypes(); + for ( TQIconViewItem *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( TDEGlobalSettings::showFilePreview(m_url) ); + + if ( m_url.isLocalFile() ) + m_dotDirectoryPath = m_url.path(1).append( ".directory" ); + else + m_dotDirectoryPath = TQString::null; +} + +void KonqIconViewWidget::startImagePreview( const TQStringList &, bool force ) +{ + stopImagePreview(); // just in case + + // Check config + if ( !TDEGlobalSettings::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(TQT_TQOBJECT(this), 0, "KonqSoundPlayer")); + d->bSoundPreviews = (d->pSoundPlayer != 0L); + } + + KFileItemList items; + for ( TQIconViewItem *it = firstItem(); it; it = it->nextItem() ) + if ( force || !static_cast<KFileIVI *>( it )->hasValidThumbnail() ) + items.append( static_cast<KFileIVI *>( it )->item() ); + + bool onlyAudio = true; + for ( TQStringList::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 : TDEGlobal::iconLoader()->currentSize( TDEIcon::Desktop ); + int size; + + d->bBoostPreview = boostPreview(); + size = previewIconSize( iconSize ); + + if ( !d->bBoostPreview ) + iconSize /= 2; + + d->pPreviewJob = TDEIO::filePreview( items, size, size, iconSize, + m_pSettings->textPreviewIconTransparency(), true /* scale */, + true /* save */, &(d->previewSettings) ); + connect( d->pPreviewJob, TQT_SIGNAL( gotPreview( const KFileItem *, const TQPixmap & ) ), + this, TQT_SLOT( slotPreview( const KFileItem *, const TQPixmap & ) ) ); + connect( d->pPreviewJob, TQT_SIGNAL( result( TDEIO::Job * ) ), + this, TQT_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; + + TQIconViewItem *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( TQDropEvent *ev, const TQValueList<TQIconDragItem> & ) +{ + // 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 TQPoint &, const TQValueList<TDEIO::CopyInfo> &) +{ + // Do nothing :-) +} + +void KonqIconViewWidget::drawBackground( TQPainter *p, const TQRect &r ) +{ + drawBackground(p, r, r.topLeft()); +} + +void KonqIconViewWidget::drawBackground( TQPainter *p, const TQRect &r , const TQPoint &pt) +{ + const TQPixmap *pm = backgroundPixmap(); + bool hasPixmap = pm && !pm->isNull(); + if ( !hasPixmap ) { + pm = viewport()->backgroundPixmap(); + hasPixmap = pm && !pm->isNull(); + } + + TQRect 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, TQPoint(ax, ay)); + } +} + +TQDragObject * KonqIconViewWidget::dragObject() +{ + if ( !currentItem() ) + return 0; + + return konqDragObject( viewport() ); +} + +KonqIconDrag * KonqIconViewWidget::konqDragObject( TQWidget * dragSource ) +{ + //kdDebug(1203) << "KonqIconViewWidget::konqDragObject" << endl; + + KonqIconDrag2 * drag = new KonqIconDrag2( dragSource ); + TQIconViewItem *primaryItem = currentItem(); + // Append all items to the drag object + for ( TQIconViewItem *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); + TQString itemURL = KURLDrag::urlToString(url); + kdDebug(1203) << "itemURL=" << itemURL << endl; + TQIconDragItem id; + id.setData( TQCString(itemURL.latin1()) ); + drag->append( id, + TQRect( it->pixmapRect(false).topLeft() - m_mousePos, + it->pixmapRect().size() ), + TQRect( 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( TQDragEnterEvent *e ) +{ + if ( e->provides( "text/uri-list" ) ) + { + TQByteArray 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; + } + } + + TDEIconView::contentsDragEnterEvent( e ); + emit dragEntered( true /*accepted*/ ); +} + +void KonqIconViewWidget::contentsDragMoveEvent( TQDragMoveEvent *e ) +{ + if ( d->bProgramsURLdrag ) { + emit dragMove( false ); + e->ignore(); + cancelPendingHeldSignal(); + return; + } + + TQIconViewItem *item = findItem( e->pos() ); + if ( e->source() != viewport() && + !item && m_rootItem && !m_rootItem->isWritable() ) { + emit dragMove( false ); + e->ignore(); + cancelPendingHeldSignal(); + return; + } + emit dragMove( true ); + TDEIconView::contentsDragMoveEvent( e ); +} + +void KonqIconViewWidget::contentsDragLeaveEvent( TQDragLeaveEvent *e ) +{ + d->bProgramsURLdrag = false; + TDEIconView::contentsDragLeaveEvent(e); + emit dragLeft(); +} + + +void KonqIconViewWidget::setItemColor( const TQColor &c ) +{ + iColor = c; +} + +TQColor KonqIconViewWidget::itemColor() const +{ + return iColor; +} + +void KonqIconViewWidget::disableIcons( const KURL::List & lst ) +{ + for ( TQIconViewItem *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 ( TQIconViewItem *it = firstItem(); it; it = it->nextItem() ) + { + if ( it->isSelected() ) + { + iCount++; + canCopy++; + + KFileItem *item = ( static_cast<KFileIVI *>( it ) )->item(); + KURL url = item->url(); + TQString local_path = item->localPath(); + + if ( url.directory(false) == TDEGlobalSettings::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; + TQIconViewItem * item = 0L; + TQIconViewItem *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 ); + TQApplication::clipboard()->setData( obj ); +} + +void KonqIconViewWidget::copySelection() +{ + kdDebug(1203) << " -- KonqIconViewWidget::copySelection() -- " << endl; + KonqIconDrag * obj = konqDragObject( /* no parent ! */ ); + TQApplication::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 ( TQIconViewItem *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; +} + +TQRect KonqIconViewWidget::iconArea() const +{ + return m_IconRect; +} + +void KonqIconViewWidget::setIconArea(const TQRect &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( TQMouseEvent *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 ( TQApplication::widgetAt( TQCursor::pos() ) != topLevelWidget() ) + { + if (d->pSoundPlayer) + d->pSoundPlayer->stop(); + d->pSoundItem = 0; + if (d->pSoundTimer && d->pSoundTimer->isActive()) + d->pSoundTimer->stop(); + } + } + d->renameItem= false; + TDEIconView::contentsMouseMoveEvent( e ); +} + +void KonqIconViewWidget::contentsDropEvent( TQDropEvent * ev ) +{ + TQIconViewItem *i = findItem( ev->pos() ); + KURL::List uriList; + + if ( ev->source() != viewport() && + !i && m_rootItem && !m_rootItem->isWritable() ) { + ev->accept( false ); + return; + } + + // Short-circuit TQIconView 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() == TQDropEvent::Copy || ev->action() == TQDropEvent::Link) + && ev->source() && ev->source() == viewport() + && KURLDrag::decode(ev, uriList) && !uriList.isEmpty() + && uriList.first().upURL().url(1) == url().url(1)) + { + // First we need to call TQIconView though, to clear the drag shape + bool bMovable = itemsMovable(); + setItemsMovable(false); // hack ? call it what you want :-) + TDEIconView::contentsDropEvent( ev ); + setItemsMovable(bMovable); + + TQValueList<TQIconDragItem> lst; + slotDropped(ev, lst); + } + else + { + TDEIconView::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 ) + { + TQMouseEvent e( TQEvent::MouseButtonPress,d->mousePos , 1, d->mouseState); + TQIconViewItem* item = findItem( e.pos() ); + KURL url; + if ( item ) + { + url= ( static_cast<KFileIVI *>( item ) )->item()->url(); + bool brenameTrash =false; + if ( url.isLocalFile() && (url.directory(false) == TDEGlobalSettings::trashPath() || url.path(1).startsWith(TDEGlobalSettings::trashPath()))) + brenameTrash = true; + + if ( url.isLocalFile() && !brenameTrash && d->renameItem && m_pSettings->renameIconDirectly() && e.button() == Qt::LeftButton && item->textRect( false ).contains(e.pos())) + { + if( d->pActivateDoubleClick->isActive () ) + d->pActivateDoubleClick->stop(); + item->rename(); + m_bMousePressed = false; + } + } + } + else + { + TQMouseEvent e( TQEvent::MouseMove,d->mousePos , 1, d->mouseState); + TDEIconView::contentsMousePressEvent( &e ); + } + if( d->pActivateDoubleClick->isActive() ) + d->pActivateDoubleClick->stop(); + + d->releaseMouseEvent = false; + d->renameItem= false; +} + +void KonqIconViewWidget::wheelEvent(TQWheelEvent* 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; + } + + TDEIconView::wheelEvent(e); +} + +void KonqIconViewWidget::leaveEvent( TQEvent *e ) +{ + // when leaving the widget, stop possible pending filetip and icon effect + slotOnViewport(); + + TDEIconView::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( TQMouseEvent *e ) +{ + if(d->pActivateDoubleClick && d->pActivateDoubleClick->isActive ()) + d->pActivateDoubleClick->stop(); + TQIconViewItem* 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) == TDEGlobalSettings::trashPath() || url.path(1).startsWith(TDEGlobalSettings::trashPath()))) + brenameTrash = true; + if ( !brenameTrash && !TDEGlobalSettings::singleClick() && m_pSettings->renameIconDirectly() && e->button() == Qt::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 TQTimer(this); + connect(d->pActivateDoubleClick, TQT_SIGNAL(timeout()), this, TQT_SLOT(doubleClickTimeout())); + } + if( d->pActivateDoubleClick->isActive () ) + d->pActivateDoubleClick->stop(); + else + d->pActivateDoubleClick->start(TQApplication::doubleClickInterval()); + d->releaseMouseEvent = false; + return; + } + else + d->renameItem= false; + } + else + d->renameItem= false; + mousePressChangeValue(); + if(d->pActivateDoubleClick && d->pActivateDoubleClick->isActive()) + d->pActivateDoubleClick->stop(); + TDEIconView::contentsMousePressEvent( e ); + +} + +void KonqIconViewWidget::contentsMouseReleaseEvent( TQMouseEvent *e ) +{ + TDEIconView::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 tdebase/kdesktop/kdiconview.cc + // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING + + printf("WARNING: Strongly deprecated method KonqIconViewWidget::slotSaveIconPositions() called!\n"); fflush(stdout); + + if ( m_dotDirectoryPath.isEmpty() ) + return; + if ( !m_bDesktop ) + return; // Currently not available in Konqueror + kdDebug(1214) << "KonqIconViewWidget::slotSaveIconPositions" << endl; + KSimpleConfig dotDirectory( m_dotDirectoryPath ); + TQIconViewItem *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( TQString( m_iconPositionGroupPrefix ).append( item->url().fileName() ) ); + kdDebug(1214) << "KonqIconViewWidget::slotSaveIconPositions " << item->url().fileName() << " " << it->x() << " " << it->y() << endl; + dotDirectory.writeEntry( TQString( "X %1" ).arg( width() ), it->x() ); + dotDirectory.writeEntry( TQString( "Y %1" ).arg( height() ), it->y() ); + dotDirectory.writeEntry( "Exists", true ); + + it = it->nextItem(); + } + + TQStringList groups = dotDirectory.groupList(); + TQStringList::ConstIterator gIt = groups.begin(); + TQStringList::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 tdebase/kdesktop/kdiconview.cc + // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING +} + +// Adapted version of TQIconView::insertInGrid, that works relative to +// m_IconRect, instead of the entire viewport. + +void KonqIconViewWidget::insertInGrid(TQIconViewItem *item) +{ + if (0L == item) + return; + + if (!m_IconRect.isValid()) + { + TDEIconView::insertInGrid(item); + return; + } + + TQRegion r(m_IconRect); + TQIconViewItem *i = firstItem(); + int y = -1; + for (; i; i = i->nextItem() ) + { + r = r.subtract(i->rect()); + y = TQMAX(y, i->y() + i->height()); + } + + TQMemArray<TQRect> rects = r.rects(); + TQMemArray<TQRect>::Iterator it = rects.begin(); + bool foundPlace = FALSE; + for (; it != rects.end(); ++it) + { + TQRect 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 : TDEGlobal::iconLoader()->currentSize( TDEIcon::Desktop ); + + typedef TQValueList<TQIconViewItem*> 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 ( TQIconViewItem* 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 = TQMIN( nx-1, TQMAX( 0, x / dx ) ); + int posY = TQMIN( ny-1, TQMAX( 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 + TQIconViewItem* movedItem; + Bin* items = bins[i][j]; + + int mini = TQMIN( TQMIN( tf, bf ), TQMIN( 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 + TQRegion repaintRegion; + TQValueList<TQIconViewItem*> movedItems; + + for ( i = 0; i < nx; i++ ) { + for ( j = 0; j < ny; j++ ) { + Bin* bin = bins[i][j]; + if ( !bin ) + continue; + if ( !bin->isEmpty() ) { + TQIconViewItem* item = bin->first(); + int newX = x0 + i*dx + spacing() + + TQMAX(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 ) { + TQRect 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... + TQMemArray<TQRect> 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( TQIconView::Arrangement arrangement ) +{ + int x0, y0, dx, dy, nxmax, nymax; + gridValues( &x0, &y0, &dx, &dy, &nxmax, &nymax ); + int textHeight = iconTextHeight() * fontMetrics().height(); + + TQRegion repaintRegion; + TQValueList<TQIconViewItem*> movedItems; + int nx = 0, ny = 0; + + TQIconViewItem* item; + for ( item = firstItem(); item; item = item->nextItem() ) { + int newX = x0 + nx*dx + spacing() + + TQMAX(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 ) { + TQRect oldRect = item->rect(); + movedItems.prepend( item ); + item->move( newX, newY ); + if ( item->rect() != oldRect ) + repaintRegion = repaintRegion.unite( oldRect ); + } + if ( arrangement == TQIconView::LeftToRight ) { + nx++; + if ( nx >= nxmax ) { + ny++; + nx = 0; + } + } + else { + ny++; + if ( ny >= nymax ) { + nx++; + ny = 0; + } + } + } + + // Repaint only repaintRegion... + TQMemArray<TQRect> 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 : TDEGlobal::iconLoader()->currentSize( TDEIcon::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 : TDEGlobal::iconLoader()->currentSize( TDEIcon::Desktop ); + + if (!d->bBoostPreview) + return iconSize; + + return largestPreviewIconSize( iconSize ); +} + +void KonqIconViewWidget::visualActivate(TQIconViewItem * item) +{ + // Rect of the TQIconViewItem. + TQRect irect = item->rect(); + + // Rect of the QIconViewItem's pixmap area. + TQRect 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() ); + + if (TDEGlobalSettings::showKonqIconActivationEffect() == true) { + TDEIconEffect::visualActivate(viewport(), rect, item->pixmap()); + } +} + +void KonqIconViewWidget::backgroundPixmapChange( const TQPixmap & ) +{ + viewport()->update(); +} + +void KonqIconViewWidget::setPreviewSettings( const TQStringList& 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 TQStringList& KonqIconViewWidget::previewSettings() +{ + return d->previewSettings; +} + +void KonqIconViewWidget::setNewURL( const TQString& 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 ( !TDEGlobalSettings::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 TQStringList; + else + d->pPreviewMimeTypes->clear(); + + // Load the list of plugins to determine which mimetypes are supported + TDETrader::OfferList plugins = TDETrader::self()->query("ThumbCreator"); + TDETrader::OfferList::ConstIterator it; + + for ( it = plugins.begin(); it != plugins.end(); ++it ) { + if ( d->previewSettings.contains((*it)->desktopEntryName()) ) { + TQStringList mimeTypes = (*it)->property("MimeTypes").toStringList(); + for (TQStringList::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..d4adf7ed5 --- /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 <[email protected]> + Copyright (C) 2000, 2001, 2002 David Faure <[email protected]> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef __konq_iconviewwidget_h__ +#define __konq_iconviewwidget_h__ + +#include <kiconloader.h> +#include <kiconview.h> +#include <kurl.h> +#include <tqguardedptr.h> +#include <tdefileitem.h> +#include <tdeio/jobclasses.h> +#include <libkonq_export.h> + +class KonqFMSettings; +class KFileIVI; +class KonqIconDrag; +namespace TDEIO { 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 TDEIconView +{ + Q_OBJECT + TQ_PROPERTY( bool sortDirectoriesFirst READ sortDirectoriesFirst WRITE setSortDirectoriesFirst ) + TQ_PROPERTY( TQRect iconArea READ iconArea WRITE setIconArea ) + TQ_PROPERTY( int lineupMode READ lineupMode WRITE setLineupMode ) + TQ_PROPERTY( TQString url READ urlString WRITE setNewURL ) + + friend class KFileIVI; + +public: + + enum LineupMode { LineupHorizontal=1, LineupVertical, LineupBoth }; + + /** + * Constructor + */ + KonqIconViewWidget( TQWidget *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 TQRect &rect ); + + /** + * Reimplemented to make the slotOnItem highlighting work. + */ + virtual void focusOutEvent( TQFocusEvent * /* ev */ ); + + /** + * Returns the icon area. + */ + TQRect 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 (TQIconView::LeftToRight + * for a horizontal arrangement and TQIconView::TopToBottom + * for vertical) + */ + void lineupIcons( TQIconView::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 TQStringList& stopImagePreviewFor = TQStringList() ); + + /** + * 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 TQIconView) + */ + 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 TQStringList &ignored, bool force ); + void stopImagePreview(); + bool isPreviewRunning() const; + // unused + void setThumbnailPixmap( KFileIVI * item, const TQPixmap & pixmap ); + void disableSoundPreviews(); + + void setURL ( const KURL & kurl ); + // ### KDE4: make const + const KURL & url() { return m_url; } + TQString urlString() const { return m_url.url(); } + void setRootItem ( const KFileItem * item ) { m_rootItem = item; } + + /** + * Get list of selected KFileItems + */ + KFileItemList selectedFileItems(); + + void setItemColor( const TQColor &c ); + TQColor 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( TQIconViewItem *item ); + + /** + * Reimplemented from TQIconView to take into account iconArea. + */ + virtual void insertInGrid( TQIconViewItem *item ); + + /** + * Reimplemented from TQIconView to update the gridX + */ + virtual void setItemTextPos( ItemTextPos pos ); + + /** + * Give feedback when item is activated. + */ + virtual void visualActivate(TQIconViewItem *); + + 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 ); + + TQString iconPositionGroupPrefix() const { return m_iconPositionGroupPrefix; } + TQString dotDirectoryPath() const { return m_dotDirectoryPath; } + + void setPreviewSettings(const TQStringList& mimeTypes); + const TQStringList& previewSettings(); + void setNewURL( const TQString& 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 TQPixmap & ); // ### unused - remove for KDE4 + void slotToolTipPreviewResult() ; // ### unused - remove for KDE4 + +signals: + /** + * For cut/copy/paste/move/delete (see tdeparts/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( TQDropEvent *e, const TQValueList<TQIconDragItem> & ); + + void slotItemRenamed(TQIconViewItem *item, const TQString &name); + + void slotIconChanged(int); + void slotOnItem(TQIconViewItem *); + void slotOnViewport(); + void slotStartSoundPreview(); + void slotPreview(const KFileItem *, const TQPixmap &); + void slotPreviewResult(); + + void slotMovieUpdate( const TQRect& rect ); + void slotMovieStatus( int status ); + void slotReenableAnimation(); + + void slotAboutToCreate(const TQPoint &pos, const TQValueList<TDEIO::CopyInfo> &files); + void doubleClickTimeout(); + +protected: + virtual TQDragObject *dragObject(); + KonqIconDrag *konqDragObject( TQWidget * dragSource = 0L ); + bool mimeTypeMatch( const TQString& mimeType, const TQStringList& mimeList ) const; + + virtual void drawBackground( TQPainter *p, const TQRect &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( TQPainter *p, const TQRect &r, + const TQPoint &pt ); + virtual void contentsDragEnterEvent( TQDragEnterEvent *e ); + virtual void contentsDragLeaveEvent( TQDragLeaveEvent *e ); + virtual void contentsDragMoveEvent( TQDragMoveEvent *e ); + virtual void contentsDropEvent( TQDropEvent *e ); + virtual void contentsMousePressEvent( TQMouseEvent *e ); + virtual void contentsMouseReleaseEvent ( TQMouseEvent * e ); + virtual void contentsMouseMoveEvent( TQMouseEvent *e ); + virtual void backgroundPixmapChange( const TQPixmap & ); + virtual void wheelEvent( TQWheelEvent* ); + virtual void leaveEvent( TQEvent *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; + TQPoint m_mousePos; + + TQColor iColor; + + bool m_bSortDirsFirst; + + TQString m_iconPositionGroupPrefix; + TQString m_dotDirectoryPath; + + int m_LineupMode; + TQRect 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..4f754681e --- /dev/null +++ b/libkonq/konq_operations.cc @@ -0,0 +1,825 @@ +/* This file is part of the KDE project + Copyright (C) 2000 David Faure <[email protected]> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include <tqclipboard.h> +#include "konq_operations.h" + +#include <kautomount.h> +#include <kinputdialog.h> +#include <tdelocale.h> +#include <tdemessagebox.h> +#include <knotifyclient.h> +#include <krun.h> +#include <kshell.h> +#include <tdeshortcut.h> + +#include <kdirnotify_stub.h> + +#include <dcopclient.h> +#include "konq_undo.h" +#include "konq_defaults.h" +#include "konqbookmarkmanager.h" + +// For doDrop +#include <tqdir.h>//first +#include <assert.h> +#include <tdeapplication.h> +#include <kipc.h> +#include <kdebug.h> +#include <tdefileitem.h> +#include <kdesktopfile.h> +#include <kurldrag.h> +#include <tdeglobalsettings.h> +#include <kimageio.h> +#include <tdeio/job.h> +#include <tdeio/jobclasses.h> +#include <tdeio/paste.h> +#include <tdeio/netaccess.h> +#include <tdeio/renamedlg.h> +#include <konq_drag.h> +#include <konq_iconviewwidget.h> +#include <kprotocolinfo.h> +#include <kprocess.h> +#include <kstringhandler.h> +#include <tqpopupmenu.h> +#include <unistd.h> +#include <X11/Xlib.h> + +KBookmarkManager * KonqBookmarkManager::s_bookmarkManager; + +KonqOperations::KonqOperations( TQWidget *parent ) + : TQObject( parent, "KonqOperations" ), + m_method( UNKNOWN ), m_info(0L), m_pasteInfo(0L) +{ +} + +KonqOperations::~KonqOperations() +{ + delete m_info; + delete m_pasteInfo; +} + +void KonqOperations::editMimeType( const TQString & mimeType ) +{ + TQString keditfiletype = TQString::fromLatin1("keditfiletype"); + KRun::runCommand( keditfiletype + " " + TDEProcess::quote(mimeType), + keditfiletype, keditfiletype /*unused*/); +} + +void KonqOperations::del( TQWidget * 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( TQWidget *parent, const KURL & url ) +{ + TDEIO::Job * job = TDEIO::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( TQWidget * parent, const KURL & destURL ) +{ + doPaste(parent, destURL, TQPoint()); +} + +void KonqOperations::doPaste( TQWidget * parent, const KURL & destURL, const TQPoint &pos ) +{ + // move or not move ? + bool move = false; + TQMimeSource *data = TQApplication::clipboard()->data(); + if ( data->provides( "application/x-tde-cutselection" ) ) { + move = KonqDrag::decodeIsCutSelection( data ); + kdDebug(1203) << "move (from clipboard data) = " << move << endl; + } + + TDEIO::Job *job = TDEIO::pasteClipboard( destURL, move ); + if ( job ) + { + KonqOperations * op = new KonqOperations( parent ); + TDEIO::CopyJob * copyJob = static_cast<TDEIO::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( TQWidget * 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 ); + TDEIO::Job* job(0); + if (method==LINK) + job= TDEIO::link( selectedURLs, destUrl); + else if (method==MOVE) + job= TDEIO::move( selectedURLs, destUrl); + else + job= TDEIO::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; + TDEIO::Job *job; + m_method = method; + switch( method ) + { + case TRASH: + { + job = TDEIO::trash( selectedURLs ); + (void) new KonqCommandRecorder( KonqCommand::TRASH, selectedURLs, "trash:/", job ); + break; + } + case EMPTYTRASH: + { + // Same as in ktrash --empty + TQByteArray packedArgs; + TQDataStream stream( packedArgs, IO_WriteOnly ); + stream << (int)1; + job = TDEIO::special( "trash:/", packedArgs ); + KNotifyClient::event(0, "Trash: emptied"); + break; + } + case DEL: + job = TDEIO::del( selectedURLs ); + break; + case SHRED: + job = TDEIO::del( selectedURLs, true ); + break; + default: + kdWarning() << "Unknown operation: " << method << endl; + delete this; + return; + } + connect( job, TQT_SIGNAL( result( TDEIO::Job * ) ), + TQT_SLOT( slotResult( TDEIO::Job * ) ) ); + } else + delete this; +} + +void KonqOperations::_restoreTrashedItems( const KURL::List& urls ) +{ + m_method = RESTORE; + KonqMultiRestoreJob* job = new KonqMultiRestoreJob( urls, true ); + connect( job, TQT_SIGNAL( result( TDEIO::Job * ) ), + TQT_SLOT( slotResult( TDEIO::Job * ) ) ); +} + +bool KonqOperations::askDeleteConfirmation( const KURL::List & selectedURLs, int method, ConfirmationType confirmation, TQWidget* widget ) +{ + if ( confirmation == SKIP_CONFIRMATION ) + return true; + TQString keyName; + bool ask = ( confirmation == FORCE_CONFIRMATION ); + if ( !ask ) + { + TDEConfig 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(); + TQStringList prettyList; + for ( ; it != selectedURLs.end(); ++it ) { + if ( (*it).protocol() == "trash" ) { + TQString 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(TQRegExp("^/[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. + TDEConfig *config = kapp->config(); + TDEConfigGroupSaver saver(config, "Notification Messages"); + if (!config->readBoolEntry(keyName, true)) + { + config->writeEntry(keyName, true); + config->sync(); + TDEConfig 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, TQDropEvent * ev, TQWidget * parent ) +{ + kdDebug(1203) << "doDrop: dest : " << dest.url() << endl; + KURL::List lst; + TQMap<TQString, TQString> 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; + TQMap<TQString,TQString>::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( tqt_xdisplay(), tqt_xrootwin(), &root, &child, + &root_x, &root_y, &win_x, &win_y, &keybstate ); + + TQDropEvent::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 = TQDropEvent::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, TQT_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); + TDEIO::CopyJob* job = TDEIO::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") + || (destItem->mimetype() == "media/builtin-mydocuments") + || (destItem->mimetype() == "media/builtin-mycomputer") + || (destItem->mimetype() == "media/builtin-mynetworkplaces") + || (destItem->mimetype() == "media/builtin-printers") + || (destItem->mimetype() == "media/builtin-trash") + || (destItem->mimetype() == "media/builtin-webbrowser") ) + { + // Local .desktop file. What type ? + KDesktopFile desktopFile( m_destURL.path() ); + if ( desktopFile.hasApplicationType() ) + { + TQString error; + TQStringList stringList; + KURL::List lst = m_info->lst; + KURL::List::Iterator it = lst.begin(); + for ( ; it != lst.end() ; it++ ) + { + stringList.append((*it).url()); + } + if ( TDEApplication::startServiceByDesktopPath( m_destURL.path(), stringList, &error ) > 0 ) + KMessageBox::error( 0L, error ); + } + else + { + // Device or Link -> adjust dest + if ( desktopFile.hasDeviceType() && desktopFile.hasKey("MountPoint") ) { + TQString point = desktopFile.readEntry( "MountPoint" ); + m_destURL.setPath( point ); + TQString dev = desktopFile.readDevice(); + TQString mp = TDEIO::findDeviceMountPoint( dev ); + // Is the device already mounted ? + if ( !mp.isNull() ) + doFileCopy(); + else + { + bool ro = desktopFile.readBoolEntry( "ReadOnly", false ); + TQString fstype = desktopFile.readEntry( "FSType" ); + KAutoMount* am = new KAutoMount( ro, fstype, dev, point, m_destURL.path(), false ); + connect( am, TQT_SIGNAL( finished() ), this, TQT_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( TQFile::encodeName(m_destURL.path()), X_OK ) == 0 ); + TDEProcess 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( TDEProcess::DontCare ); + } + delete this; +} + +void KonqOperations::doFileCopy() +{ + assert(m_info); // setDropInfo - and asyncDrop - should have been called before asyncDrop + KURL::List lst = m_info->lst; + TQDropEvent::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 || TQFileInfo((*it).directory()).isWritable() )) + mlst.append(*it); + if ( local && KDesktopFile::isDesktopFile((*it).path())) + isDesktopFile = true; + if ( local && (*it).path().startsWith(TDEGlobalSettings::desktopPath())) + itemIsOnDesktop = true; + if ( local || (*it).protocol() != "trash" ) + allItemsAreFromTrash = false; + } + + bool linkOnly = false; + if (isDesktopFile && !kapp->authorize("run_desktop_files") && + (m_destURL.path(1) == TDEGlobalSettings::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 = TQDropEvent::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 = TQDropEvent::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 = tqt_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; + } + + TQPopupMenu 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("edit-copy"), 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 = TQDropEvent::Copy; break; + case 2 : action = TQDropEvent::Move; break; + case 3 : action = TQDropEvent::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; + } + } + + TDEIO::Job * job = 0; + switch ( action ) { + case TQDropEvent::Move : + job = TDEIO::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 TQDropEvent::Copy : + job = TDEIO::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 TQDropEvent::Link : + kdDebug(1203) << "KonqOperations::asyncDrop lst.count=" << lst.count() << endl; + job = TDEIO::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( TQWidget * 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); + TDEIO::Job * job = TDEIO::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) == TDEGlobalSettings::desktopPath() ) + { + kdDebug(1203) << "That rename was the Desktop path, updating config files" << endl; + TDEConfig *globalConfig = TDEGlobal::config(); + TDEConfigGroupSaver cgs( globalConfig, "Paths" ); + globalConfig->writePathEntry("Desktop" , newurl.path(), true, true ); + globalConfig->sync(); + KIPC::sendMessageAll(KIPC::SettingsChanged, TDEApplication::SETTINGS_PATHS); + } +} + +void KonqOperations::setOperation( TDEIO::Job * job, int method, const KURL::List & /*src*/, const KURL & dest ) +{ + m_method = method; + //m_srcURLs = src; + m_destURL = dest; + if ( job ) + { + connect( job, TQT_SIGNAL( result( TDEIO::Job * ) ), + TQT_SLOT( slotResult( TDEIO::Job * ) ) ); + TDEIO::CopyJob *copyJob = tqt_dynamic_cast<TDEIO::CopyJob*>(job); + KonqIconViewWidget *iconView = tqt_dynamic_cast<KonqIconViewWidget*>(parent()); + if (copyJob && iconView) + { + connect(copyJob, TQT_SIGNAL(aboutToCreate(TDEIO::Job *,const TQValueList<TDEIO::CopyInfo> &)), + this, TQT_SLOT(slotAboutToCreate(TDEIO::Job *,const TQValueList<TDEIO::CopyInfo> &))); + connect(this, TQT_SIGNAL(aboutToCreate(const TQPoint &, const TQValueList<TDEIO::CopyInfo> &)), + iconView, TQT_SLOT(slotAboutToCreate(const TQPoint &, const TQValueList<TDEIO::CopyInfo> &))); + } + } + else // for link + slotResult( 0L ); +} + +void KonqOperations::slotAboutToCreate(TDEIO::Job *, const TQValueList<TDEIO::CopyInfo> &files) +{ + emit aboutToCreate( m_info ? m_info->mousePos : m_pasteInfo ? m_pasteInfo->mousePos : TQPoint(), files); +} + +void KonqOperations::statURL( const KURL & url, const TQObject *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 TQObject *receiver, const char *member ) +{ + connect( this, TQT_SIGNAL( statFinished( const KFileItem * ) ), receiver, member ); + TDEIO::StatJob * job = TDEIO::stat( url /*, false?*/ ); + connect( job, TQT_SIGNAL( result( TDEIO::Job * ) ), + TQT_SLOT( slotStatResult( TDEIO::Job * ) ) ); +} + +void KonqOperations::slotStatResult( TDEIO::Job * job ) +{ + if ( job->error()) + job->showErrorDialog( (TQWidget*)parent() ); + else + { + TDEIO::StatJob * statJob = static_cast<TDEIO::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( TDEIO::Job * job ) +{ + if (job && job->error()) + job->showErrorDialog( (TQWidget*)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( TQWidget * parent, const KURL & oldurl, const TQString & 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( TQWidget * parent, const KURL & baseURL ) +{ + bool ok; + TQString name = i18n( "New Folder" ); + if ( baseURL.isLocalFile() && TQFileInfo( baseURL.path(+1) + name ).exists() ) + name = TDEIO::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 = TDEIO::encodeFileName( name ); + url = baseURL; + url.addPath( name ); + } + KonqOperations::mkdir( 0L, url ); + } +} + +//// + +KonqMultiRestoreJob::KonqMultiRestoreJob( const KURL::List& urls, bool showProgressInfo ) + : TDEIO::Job( showProgressInfo ), + m_urls( urls ), m_urlsIterator( m_urls.begin() ), + m_progress( 0 ) +{ + TQTimer::singleShot(0, this, TQT_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") ) + { + TQString path = new_url.path(); + path.remove(0, 6); + new_url.setProtocol("trash"); + new_url.setPath(path); + } + + Q_ASSERT( new_url.protocol() == "trash" ); + TQByteArray packedArgs; + TQDataStream stream( packedArgs, IO_WriteOnly ); + stream << (int)3 << new_url; + TDEIO::Job* job = TDEIO::special( new_url, packedArgs ); + addSubjob( job ); + } + else // done! + { + KDirNotify_stub allDirNotify("*", "KDirNotify*"); + allDirNotify.FilesRemoved( m_urls ); + emitResult(); + } +} + +void KonqMultiRestoreJob::slotResult( TDEIO::Job *job ) +{ + if ( job->error() ) + { + TDEIO::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(); +} + +TQWidget* KonqOperations::parentWidget() const +{ + return static_cast<TQWidget *>( parent() ); +} + +#include "konq_operations.moc" diff --git a/libkonq/konq_operations.h b/libkonq/konq_operations.h new file mode 100644 index 000000000..c6cef7431 --- /dev/null +++ b/libkonq/konq_operations.h @@ -0,0 +1,215 @@ +/* This file is part of the KDE project + Copyright (C) 2000 David Faure <[email protected]> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef __konq_operations_h__ +#define __konq_operations_h__ + +#include <kurl.h> +#include <libkonq_export.h> + +#include <tqobject.h> +#include <tqevent.h> + +namespace TDEIO { class Job; class CopyInfo; } +class TQWidget; +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 TQObject +{ + Q_OBJECT +protected: + KonqOperations( TQWidget * parent ); + virtual ~KonqOperations(); + +public: + /** + * Pop up properties dialog for mimetype @p mimeType. + */ + static void editMimeType( const TQString & 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( TQWidget * 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( TQWidget * 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, TQDropEvent * ev, TQWidget * parent ); + + /** + * Paste the clipboard contents + */ + static void doPaste( TQWidget * parent, const KURL & destURL, const TQPoint &pos ); + static void doPaste( TQWidget * parent, const KURL & destURL ); + + static void emptyTrash(); + static void restoreTrashedItems( const KURL::List& urls ); + + /** + * Create a directory + */ + static void mkdir( TQWidget *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 TQObject *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( TQWidget * parent, const KURL & oldurl, const TQString & 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( TQWidget * 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( TQWidget * 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, TQWidget* widget ); + +signals: + void statFinished( const KFileItem * item ); + void aboutToCreate(const TQPoint &pos, const TQValueList<TDEIO::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 TQObject *receiver, const char *member ); + + // internal, for COPY/MOVE/LINK/MKDIR + void setOperation( TDEIO::Job * job, int method, const KURL::List & src, const KURL & dest ); + + struct DropInfo + { + DropInfo( uint k, KURL::List & l, const TQMap<TQString,TQString> &m, + int x, int y, TQDropEvent::Action a ) : + keybstate(k), lst(l), metaData(m), mousePos(x,y), action(a) {} + uint keybstate; + KURL::List lst; + TQMap<TQString,TQString> metaData; + TQPoint mousePos; + TQDropEvent::Action action; + }; + // internal, for doDrop + void setDropInfo( DropInfo * info ) { m_info = info; } + + struct KIOPasteInfo // KDE4: remove and use DropInfo instead or a TQPoint member + { + TQByteArray data; // unused + KURL destURL; // unused + TQPoint mousePos; + TQString dialogText; // unused + }; + void setPasteInfo( KIOPasteInfo * info ) { m_pasteInfo = info; } + +private: + TQWidget* parentWidget() const; + +protected slots: + + void slotAboutToCreate(TDEIO::Job *job, const TQValueList<TDEIO::CopyInfo> &files); + void slotResult( TDEIO::Job * job ); + void slotStatResult( TDEIO::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 <tdeio/job.h> + +/// Restore multiple trashed files +class KonqMultiRestoreJob : public TDEIO::Job +{ + Q_OBJECT + +public: + KonqMultiRestoreJob( const KURL::List& urls, bool showProgressInfo ); + +protected slots: + virtual void slotStart(); + virtual void slotResult( TDEIO::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..d5ff0cae1 --- /dev/null +++ b/libkonq/konq_pixmapprovider.cc @@ -0,0 +1,201 @@ +/* This file is part of the KDE project + Copyright (C) 2000 Carsten Pfeiffer <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <tqbitmap.h> + +#include <tdeapplication.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( TQT_TQOBJECT(kapp), "KonqPixmapProvider" ); + + return s_self; +} + +KonqPixmapProvider::KonqPixmapProvider( TQObject *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 +TQString KonqPixmapProvider::iconNameFor( const TQString& url ) +{ + TQMapIterator<TQString,TQString> it = iconMap.find( url ); + TQString 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; +} + +TQPixmap KonqPixmapProvider::pixmapFor( const TQString& url, int size ) +{ + return loadIcon( url, iconNameFor( url ), size ); +} + +void KonqPixmapProvider::load( TDEConfig *kc, const TQString& key ) +{ + iconMap.clear(); + TQStringList list; + list = kc->readPathListEntry( key ); + TQStringList::Iterator it = list.begin(); + TQString 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( TDEConfig *kc, const TQString& key, + const TQStringList& items ) +{ + TQStringList list; + TQStringList::ConstIterator it = items.begin(); + TQMapConstIterator<TQString,TQString> 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, TQString hostOrURL, + TQString iconName ) +{ + for ( TQMapIterator<TQString,TQString> 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. + TQString icon = isHost ? KMimeType::favIconForURL( url ) : iconName; + if ( !icon.isEmpty() ) + *it = icon; + } + } + + emit changed(); +} + +void KonqPixmapProvider::clear() +{ + iconMap.clear(); +} + +TQPixmap KonqPixmapProvider::loadIcon( const TQString& url, const TQString& icon, + int size ) +{ + if ( size <= TDEIcon::SizeSmall ) + return SmallIcon( icon, size ); + + KURL u; + if ( url.at(0) == '/' ) + u.setPath( url ); + else + u = url; + + TQPixmap big; + + // favicon? => blend the favicon in the large + if ( url.startsWith( "http:/" ) && icon.startsWith("favicons/") ) { + TQPixmap small = SmallIcon( icon, size ); + big = TDEGlobal::iconLoader()->loadIcon( KProtocolInfo::icon("http"), + TDEIcon::Panel, size ); + + int x = big.width() - small.width(); + int y = 0; + + if ( big.mask() ) { + TQBitmap mask = *big.mask(); + bitBlt( &mask, x, y, + small.mask() ? TQT_TQPIXMAP(const_cast<TQBitmap *>(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 = TDEGlobal::iconLoader()->loadIcon( icon, TDEIcon::Panel, size ); + + return big; +} diff --git a/libkonq/konq_pixmapprovider.h b/libkonq/konq_pixmapprovider.h new file mode 100644 index 000000000..ca259915f --- /dev/null +++ b/libkonq/konq_pixmapprovider.h @@ -0,0 +1,81 @@ +/* This file is part of the KDE project + Copyright (C) 2000 Carsten Pfeiffer <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; 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 <tqmap.h> + +#include <kpixmapprovider.h> +#include "konq_faviconmgr.h" + +#include <libkonq_export.h> + +class TDEConfig; + +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 TQPixmap pixmapFor( const TQString& url, int size = 0 ); + + /** + * Loads the cache to @p kc from the current TDEConfig-group from key @p key. + */ + void load( TDEConfig * kc, const TQString& key ); + /** + * Saves the cache to @p kc into the current TDEConfig-group as key @p key. + * Only those @p items are saved, otherwise the cache would grow forever. + */ + void save( TDEConfig *, const TQString& key, const TQStringList& 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 + */ + TQString iconNameFor( const TQString& url ); + +protected: + KonqPixmapProvider( TQObject *parent=0, const char *name=0 ); + + /** + * Overridden from KonqFavIconMgr to update the cache + */ + virtual void notifyChange( bool isHost, TQString hostOrURL, TQString iconName ); + + TQPixmap loadIcon( const TQString& url, const TQString& icon, int size ); + +private: + TQMap<TQString,TQString> 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..482c152c5 --- /dev/null +++ b/libkonq/konq_popupmenu.cc @@ -0,0 +1,1259 @@ +/* This file is part of the KDE project + Copyright (C) 1998, 1999 David Faure <[email protected]> + Copyright (C) 2001 Holger Freyther <[email protected]> + + 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 <tqdir.h> +#include <tqeventloop.h> + +#include <tdelocale.h> +#include <tdeapplication.h> +#include <kbookmarkmanager.h> +#include <kdebug.h> +#include <krun.h> +#include <kprotocolinfo.h> +#include <kiconloader.h> +#include <kinputdialog.h> +#include <tdeglobalsettings.h> +#include <kstandarddirs.h> +#include <kxmlguifactory.h> +#include <kxmlguibuilder.h> +#include <tdeparts/componentfactory.h> + +#include <assert.h> + +#include <tdefileshare.h> +#include <kprocess.h> + +#include "kpropertiesdialog.h" +#include "knewmenu.h" +#include "konq_popupmenu.h" +#include "konq_operations.h" +#include "konq_xmlguiclient.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 + tdehtml background + tdehtml link + tdehtml image (www.kde.org RMB on K logo) + tdehtmlimage (same as above, then choose View image, then RMB) + selected text in tdehtml + embedded katepart + kdesktop folder + trash link on desktop + trashed file or directory + application .desktop file + Then the same after uninstalling tdeaddons/konq-plugins (kuick and arkplugin in particular) +*/ + +class KonqPopupMenuGUIBuilder : public KXMLGUIBuilder +{ +public: + KonqPopupMenuGUIBuilder( TQPopupMenu *menu ) + : KXMLGUIBuilder( 0 ) + { + m_menu = menu; + } + virtual ~KonqPopupMenuGUIBuilder() + { + } + + virtual TQWidget *createContainer( TQWidget *parent, int index, + const TQDomElement &element, + int &id ) + { + if ( !parent && element.attribute( "name" ) == "popupmenu" ) + return m_menu; + + return KXMLGUIBuilder::createContainer( parent, index, element, id ); + } + + TQPopupMenu *m_menu; +}; + +class KonqPopupMenu::KonqPopupMenuPrivate +{ +public: + KonqPopupMenuPrivate() : m_parentWidget( 0 ), + m_itemFlags( KParts::BrowserExtension::DefaultPopupItems ) + { + } + TQString m_urlTitle; + TQWidget *m_parentWidget; + KParts::BrowserExtension::PopupFlags m_itemFlags; + + bool localURLSlotFired; + KURL localURLResultURL; + bool localURLResultIsLocal; +}; + +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-TDE-Priority and X-TDE-Submenu. +class PopupServices +{ +public: + ServiceList* selectList( const TQString& priority, const TQString& submenuName ); + + ServiceList builtin; + ServiceList user, userToplevel, userPriority; + TQMap<TQString, ServiceList> userSubmenus, userToplevelSubmenus, userPrioritySubmenus; +}; + +ServiceList* PopupServices::selectList( const TQString& priority, const TQString& 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, + TDEActionCollection & actions, + KNewMenu * newMenu, + bool showProperties ) + : TQPopupMenu( 0L, "konq_popupmenu" ), + m_actions( actions ), m_ownActions( static_cast<TQWidget *>( 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, + TDEActionCollection & actions, + KNewMenu * newMenu, + TQWidget * parentWidget, + bool showProperties ) + : TQPopupMenu( parentWidget, "konq_popupmenu" ), m_actions( actions ), m_ownActions( static_cast<TQWidget *>( 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, + TDEActionCollection & actions, + KNewMenu * newMenu, + TQWidget * parentWidget, + KonqPopupFlags kpf, + KParts::BrowserExtension::PopupFlags flags) + : TQPopupMenu( parentWidget, "konq_popupmenu" ), m_actions( actions ), m_ownActions( static_cast<TQWidget *>( 0 ), "KonqPopupMenu::m_ownActions" ), m_pMenuNew( newMenu ), m_sViewURL(viewURL), m_lstItems(items), m_pManager(mgr) +{ + init(parentWidget, kpf, flags); +} + +void KonqPopupMenu::init (TQWidget * parentWidget, KonqPopupFlags kpf, KParts::BrowserExtension::PopupFlags flags) +{ + d = new KonqPopupMenuPrivate; + d->m_parentWidget = parentWidget; + d->m_itemFlags = flags; + setup(kpf); +} + +int KonqPopupMenu::insertServicesSubmenus(const TQMap<TQString, ServiceList>& submenus, + TQDomElement& menu, + bool isBuiltin) +{ + int count = 0; + TQMap<TQString, ServiceList>::ConstIterator it; + + for (it = submenus.begin(); it != submenus.end(); ++it) + { + if (it.data().isEmpty()) + { + //avoid empty sub-menus + continue; + } + + TQDomElement actionSubmenu = m_doc.createElement( "menu" ); + actionSubmenu.setAttribute( "name", "actions " + it.key() ); + menu.appendChild( actionSubmenu ); + TQDomElement 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, + TQDomElement& 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") + { + TQDomElement separator = m_doc.createElement( "separator" ); + menu.appendChild(separator); + } + continue; + } + + if (isBuiltin || (*it).m_display == true) + { + TQCString name; + name.setNum( id ); + name.prepend( isBuiltin ? "builtinservice_" : "userservice_" ); + TDEAction * act = new TDEAction( TQString((*it).m_strName).replace('&',"&&"), 0, + TQT_TQOBJECT(this), TQT_SLOT( slotRunService() ), + &m_ownActions, name ); + + if ( !(*it).m_strIcon.isEmpty() ) + { + TQPixmap 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(TDEConfig& cfg) +{ + if ( !cfg.hasKey( "X-TDE-AuthorizeAction") ) + { + return true; + } + + TQStringList list = cfg.readListEntry("X-TDE-AuthorizeAction"); + if (kapp && !list.isEmpty()) + { + for(TQStringList::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(); + TQString 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(TDEGlobalSettings::menuFont()); + m_pluginList.setAutoDelete( true ); + m_ownActions.setHighlightingEnabled( true ); + + attrName = TQString::fromLatin1( "name" ); + + prepareXMLGUIStuff(); + m_builder = new KonqPopupMenuGUIBuilder( this ); + m_factory = new KXMLGUIFactory( m_builder ); + + KURL url; + KFileItemListIterator it ( m_lstItems ); + TQStringList 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 = TQString::null; // mimetypes are different => null + + if ( mimeGroup != (*it)->mimetype().left((*it)->mimetype().find('/'))) + mimeGroup = TQString::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; + } + + // If a local path is available, monitor that instead of the given remote URL... + KURL realURL = m_sViewURL; + if (!realURL.isLocalFile()) { + d->localURLSlotFired = false; + TDEIO::LocalURLJob* localURLJob = TDEIO::localURL(m_sViewURL); + if (localURLJob) { + connect(localURLJob, TQT_SIGNAL(localURL(TDEIO::LocalURLJob*, const KURL&, bool)), this, TQT_SLOT(slotLocalURL(TDEIO::LocalURLJob*, const KURL&, bool))); + connect(localURLJob, TQT_SIGNAL(destroyed()), this, TQT_SLOT(slotLocalURLKIODestroyed())); + while (!d->localURLSlotFired) { + kapp->eventLoop()->enterLoop(); + } + if (d->localURLResultIsLocal) { + realURL = d->localURLResultURL; + } + } + } + + url = realURL; + 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 */, true /* ignore_internalReferenceURLS */ ); + if ( isLocal && ((m_sMimeType == "application/x-desktop") + || (m_sMimeType == "media/builtin-mydocuments") + || (m_sMimeType == "media/builtin-mycomputer") + || (m_sMimeType == "media/builtin-mynetworkplaces") + || (m_sMimeType == "media/builtin-printers") + || (m_sMimeType == "media/builtin-trash") + || (m_sMimeType == "media/builtin-webbrowser")) ) { + 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(); + + ////////////////////////////////////////////////////////////////////////// + + TDEAction * act; + + if (!isCurrentTrash) + addMerge( "konqueror" ); + + bool isKDesktop = TQCString( kapp->name() ) == "kdesktop"; + TDEAction *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 ) + { + TQString openStr = isKDesktop ? i18n( "&Open" ) : i18n( "Open in New &Window" ); + actNewWindow = new TDEAction( openStr, "window-new", 0, TQT_TQOBJECT(this), TQT_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) + { + TDEAction *actNewDir = new TDEAction( i18n( "Create &Folder..." ), "folder-new", 0, TQT_TQOBJECT(this), TQT_SLOT( slotPopupNewDir() ), &m_ownActions, "newdir" ); + addAction( actNewDir ); + addSeparator(); + } + } + } else if ( isIntoTrash ) { + // Trashed item, offer restoring + act = new TDEAction( i18n( "&Restore" ), 0, TQT_TQOBJECT(this), TQT_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 (TDEApplication::keyboardMouseState() & TQt::ShiftButton) { + addTrash = false; + addDel = true; + } + else { + TDEConfigGroup configGroup( kapp->config(), "KDE" ); + if ( configGroup.readBoolEntry( "ShowDeleteCommand", false ) ) + addDel = true; + } + } + + if ( addTrash ) + addAction( "trash" ); + if ( addDel ) + addAction( "del" ); + } + } + if ( isCurrentTrash ) + { + act = new TDEAction( i18n( "&Empty Trash Bin" ), "emptytrash", 0, TQT_TQOBJECT(this), TQT_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(); + TQString 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 TDEAction( caption, "bookmark_add", 0, TQT_TQOBJECT(this), TQT_SLOT( slotPopupAddToBookmark() ), &m_ownActions, "bookmark_add" ); + if (m_lstItems.count() > 1) + act->setEnabled(false); + if (kapp->authorizeTDEAction("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") + || (m_sMimeType == "media/builtin-mydocuments") + || (m_sMimeType == "media/builtin-mycomputer") + || (m_sMimeType == "media/builtin-mynetworkplaces") + || (m_sMimeType == "media/builtin-printers") + || (m_sMimeType == "media/builtin-trash") + || (m_sMimeType == "media/builtin-webbrowser")) && isSingleLocal ) // .desktop file + { + // get builtin services, like mount/unmount + s.builtin = KDEDesktopMimeType::builtinServices( urlForServiceMenu ); + const TQString path = urlForServiceMenu.path(); + KSimpleConfig cfg( path, true ); + cfg.setDesktopGroup(); + const TQString priority = cfg.readEntry("X-TDE-Priority"); + const TQString submenuName = cfg.readEntry( "X-TDE-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) + { + TQString dotDirectoryFile = urlForServiceMenu.path(1).append(".directory"); + KSimpleConfig cfg( dotDirectoryFile, true ); + cfg.setDesktopGroup(); + + if (KIOSKAuthorizedAction(cfg)) + { + const TQString priority = cfg.readEntry("X-TDE-Priority"); + const TQString submenuName = cfg.readEntry( "X-TDE-Submenu" ); + ServiceList* list = s.selectList( priority, submenuName ); + (*list) += KDEDesktopMimeType::userDefinedServices( dotDirectoryFile, cfg, true ); + } + } + + // findAllResources() also removes duplicates + const TQStringList entries = TDEGlobal::dirs()->findAllResources("data", + "konqueror/servicemenus/*.desktop", + false /* recursive */, + true /* unique */); + TQStringList::ConstIterator eIt = entries.begin(); + const TQStringList::ConstIterator eEnd = entries.end(); + for (; eIt != eEnd; ++eIt ) + { + KSimpleConfig cfg( *eIt, true ); + cfg.setDesktopGroup(); + + if (!KIOSKAuthorizedAction(cfg)) + { + continue; + } + + if ( cfg.hasKey( "X-TDE-ShowIfRunning" ) ) + { + const TQString app = cfg.readEntry( "X-TDE-ShowIfRunning" ); + if ( !kapp->dcopClient()->isApplicationRegistered( app.utf8() ) ) + continue; + } + if ( cfg.hasKey( "X-TDE-ShowIfDcopCall" ) ) + { + TQString dcopcall = cfg.readEntry( "X-TDE-ShowIfDcopCall" ); + const TQCString app = TQString(dcopcall.section(' ', 0,0)).utf8(); + + //if( !kapp->dcopClient()->isApplicationRegistered( app )) + // continue; //app does not exist so cannot send call + + TQByteArray dataToSend; + TQDataStream dataStream(dataToSend, IO_WriteOnly); + dataStream << m_lstPopupURLs; + + TQCString replyType; + TQByteArray replyData; + TQCString object = TQString(dcopcall.section(' ', 1,-2)).utf8(); + TQString function = TQString(dcopcall.section(' ', -1)); + if(!function.endsWith("(KURL::List)")) { + kdWarning() << "Desktop file " << *eIt << " contains an invalid X-TDE-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-TDE-Protocol" ) ) + { + const TQString protocol = cfg.readEntry( "X-TDE-Protocol" ); + if ( protocol != urlForServiceMenu.protocol() ) + continue; + } + else if ( cfg.hasKey( "X-TDE-Protocols" ) ) + { + TQStringList protocols = TQStringList::split( "," , cfg.readEntry( "X-TDE-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-TDE-Require" ) ) + { + const TQStringList capabilities = cfg.readListEntry( "X-TDE-Require" ); + if ( capabilities.contains( "Write" ) && !sWriting ) + continue; + } + if ( (cfg.hasKey( "Actions" ) || cfg.hasKey( "X-TDE-GetActionMenu") ) && cfg.hasKey( "X-TDE-ServiceTypes" ) ) + { + const TQStringList types = cfg.readListEntry( "X-TDE-ServiceTypes" ); + const TQStringList excludeTypes = cfg.readListEntry( "X-TDE-ExcludeServiceTypes" ); + bool ok = false; + + // check for exact matches or a typeglob'd mimetype if we have a mimetype + for (TQStringList::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 (TQStringList::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 TQString priority = cfg.readEntry("X-TDE-Priority"); + const TQString submenuName = cfg.readEntry( "X-TDE-Submenu" ); + + ServiceList* list = s.selectList( priority, submenuName ); + (*list) += KDEDesktopMimeType::userDefinedServices( *eIt, cfg, url.isLocalFile(), m_lstPopupURLs ); + } + } + } + + TDETrader::OfferList offers; + + if (kapp->authorizeTDEAction("openwith")) + { + TQString constraint = "Type == 'Application' and DesktopEntryName != 'kfmclient' and DesktopEntryName != 'kfmclient_dir' and DesktopEntryName != 'kfmclient_html'"; + TQString subConstraint = " and '%1' in ServiceTypes"; + + TQStringList::ConstIterator it = mimeTypeList.begin(); + TQStringList::ConstIterator end = mimeTypeList.end(); + Q_ASSERT( it != end ); + TQString first = *it; + ++it; + while ( it != end ) { + constraint += subConstraint.arg( *it ); + ++it; + } + + offers = TDETrader::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; + + TQDomElement menu = m_menuElement; + + if ( offers.count() > 1 ) // submenu 'open with' + { + menu = m_doc.createElement( "menu" ); + menu.setAttribute( "name", "openwith submenu" ); + m_menuElement.appendChild( menu ); + TQDomElement text = m_doc.createElement( "text" ); + menu.appendChild( text ); + text.appendChild( m_doc.createTextNode( i18n("&Open With") ) ); + } + + TDETrader::OfferList::ConstIterator it = offers.begin(); + for( ; it != offers.end(); it++ ) + { + KService::Ptr service = (*it); + + // Skip OnlyShowIn=Foo and NotShowIn=TDE 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 TQString onlyShowIn = service->property("OnlyShowIn", TQVariant::String).toString(); + if ( !onlyShowIn.isEmpty() ) { + const TQStringList aList = TQStringList::split(';', onlyShowIn); + if (!aList.contains("TDE")) + continue; + } + const TQString notShowIn = service->property("NotShowIn", TQVariant::String).toString(); + if ( !notShowIn.isEmpty() ) { + const TQStringList aList = TQStringList::split(';', notShowIn); + if (aList.contains("TDE")) + continue; + } + + TQCString nam; + nam.setNum( id ); + + TQString actionName( (*it)->name().replace("&", "&&") ); + if ( menu == m_menuElement ) // no submenu -> prefix single offer + actionName = i18n( "Open with %1" ).arg( actionName ); + + act = new TDEAction( actionName, (*it)->pixmap( TDEIcon::Small ), 0, + TQT_TQOBJECT(this), TQT_SLOT( slotRunService() ), + &m_ownActions, nam.prepend( "appservice_" ) ); + addAction( act, menu ); + + m_mapPopup[ id++ ] = *it; + } + + TQString openWithActionName; + if ( menu != m_menuElement ) // submenu + { + addSeparator( menu ); + openWithActionName = i18n( "&Other..." ); + } + else + { + openWithActionName = i18n( "&Open With..." ); + } + TDEAction *openWithAct = new TDEAction( openWithActionName, 0, TQT_TQOBJECT(this), TQT_SLOT( slotPopupOpenWith() ), &m_ownActions, "openwith" ); + addAction( openWithAct, menu ); + } + else // no app offers -> Open With... + { + act = new TDEAction( i18n( "&Open With..." ), 0, TQT_TQOBJECT(this), TQT_SLOT( slotPopupOpenWith() ), &m_ownActions, "openwith" ); + addAction( act ); + } + + } + addGroup( "preview" ); + } + + // Second block, builtin + user + TQDomElement 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 ); + TQDomElement 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") + { + TQDomElement 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 TDEAction( i18n( "&Properties" ), 0, TQT_TQOBJECT(this), TQT_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 TDEAction( i18n("Share"), 0, TQT_TQOBJECT(this), TQT_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 TQString& 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(); + TQString 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() +{ + TQCString senderName = TQT_TQOBJECT_CONST(sender())->name(); + int id = senderName.mid( senderName.find( '_' ) + 1 ).toInt(); + + // Is it a usual service (application) + TQMap<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 ? + TQMap<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 tdefileitem 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 ); +} + +TDEAction *KonqPopupMenu::action( const TQDomElement &element ) const +{ + TQCString name = element.attribute( attrName ).ascii(); + TDEAction *res = m_ownActions.action( static_cast<const char *>(name) ); + + if ( !res ) + res = m_actions.action( static_cast<const char *>(name) ); + + if ( !res && m_pMenuNew && strcmp( name, m_pMenuNew->name() ) == 0 ) + return m_pMenuNew; + + return res; +} + +TDEActionCollection *KonqPopupMenu::actionCollection() const +{ + return const_cast<TDEActionCollection *>( &m_ownActions ); +} + +TQString 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 + TDETrader::OfferList plugin_offers; + unsigned int pluginCount = 0; + plugin_offers = TDETrader::self()->query( m_sMimeType.isNull() ? TQString::fromLatin1( "all/all" ) : m_sMimeType, "'KonqPopupMenu/Plugin' in ServiceTypes"); + if ( plugin_offers.isEmpty() ) + return; // no plugins installed do not bother about it + + TDETrader::OfferList::ConstIterator iterator = plugin_offers.begin(); + TDETrader::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>( TQFile::encodeName( (*iterator)->library() ), + TQT_TQOBJECT(this), + (*iterator)->name().latin1() ); + if ( !plugin ) + continue; + // This make the kuick plugin insert its stuff above "Properties" + TQString pluginClientName = TQString::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; +} + +void KonqPopupMenu::slotLocalURL(TDEIO::LocalURLJob *job, const KURL& url, bool isLocal) +{ + d->localURLSlotFired = true; + d->localURLResultURL = url; + d->localURLResultIsLocal = isLocal; + kapp->eventLoop()->exitLoop(); +} + +void KonqPopupMenu::slotLocalURLKIODestroyed() +{ + if (!d->localURLSlotFired) { + d->localURLSlotFired = true; + d->localURLResultURL = KURL(); + d->localURLResultIsLocal = false; + kapp->eventLoop()->exitLoop(); + } +} + +/** + Plugin +*/ + +KonqPopupMenuPlugin::KonqPopupMenuPlugin( KonqPopupMenu *parent, const char *name ) + : TQObject( 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..5785d53ab --- /dev/null +++ b/libkonq/konq_popupmenu.h @@ -0,0 +1,227 @@ +/* This file is part of the KDE project + Copyright (C) 1998, 1999 David Faure <[email protected]> + Copyright (C) 2001 Holger Freyther <[email protected]> + + 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 <tqpopupmenu.h> +#include <tqmap.h> +#include <tdeaction.h> + +#include <tqstringlist.h> + +#include <tdefileitem.h> +#include <kmimetype.h> // for KDEDesktopMimeType +#include <libkonq_export.h> + +#include <tdeparts/browserextension.h> +#include <tdeio/jobclasses.h> + +#include "konq_xmlguiclient.h" + +typedef TQValueList<KDEDesktopMimeType::Service> ServiceList; + +class KPropertiesDialog; +class KNewMenu; +class KService; +class KonqPopupMenuPlugin; +class KBookmarkManager; + +// TODO KDE4: change base class to TDEPopupMenu, see TDEAction::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 TQPopupMenu, 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, + TDEActionCollection & 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, + TDEActionCollection & actions, + KNewMenu * newMenu, + TQWidget * 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, + TDEActionCollection & actions, + KNewMenu * newMenu, + TQWidget * 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 TQString& 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 TDEAction *action( const TQDomElement &element ) const; + + + virtual TDEActionCollection *actionCollection() const; + TQString 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: + TDEActionCollection &m_actions; + TDEActionCollection m_ownActions; + +private slots: + void slotLocalURL( TDEIO::LocalURLJob *, const KURL&, bool ); + void slotLocalURLKIODestroyed( ); + +private: + void init (TQWidget * parentWidget, KonqPopupFlags kpf, KParts::BrowserExtension::PopupFlags itemFlags); + void setup(KonqPopupFlags kpf); + void addPlugins( ); + int insertServicesSubmenus(const TQMap<TQString, ServiceList>& list, TQDomElement& menu, bool isBuiltin); + int insertServices(const ServiceList& list, TQDomElement& menu, bool isBuiltin); + bool KIOSKAuthorizedAction(TDEConfig& cfg); + KPropertiesDialog* showPropertiesDialog(); + + class KonqPopupMenuPrivate; + KonqPopupMenuPrivate *d; + KNewMenu *m_pMenuNew; + KURL m_sViewURL; + TQString m_sMimeType; + KFileItemList m_lstItems; + KURL::List m_lstPopupURLs; + TQMap<int,KService::Ptr> m_mapPopup; + TQMap<int,KDEDesktopMimeType::Service> m_mapPopupServices; + bool m_bHandleEditOperations; + KXMLGUIFactory *m_factory; + KXMLGUIBuilder *m_builder; + TQString attrName; + ProtocolInfo m_info; + TQPtrList<KonqPopupMenuPlugin> m_pluginList; + KBookmarkManager* m_pManager; +}; + +class LIBKONQ_EXPORT KonqPopupMenuPlugin : public TQObject, 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 TDEAction and use _popup->addAction(new TDEAction ); + * 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..f9a69b8f6 --- /dev/null +++ b/libkonq/konq_propsview.cc @@ -0,0 +1,604 @@ +/* This file is part of the KDE project + Copyright (C) 1998, 1999 Faure David <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; 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 <tqpixmapcache.h> +#include <tqiconview.h> +#include <unistd.h> +#include <tqfile.h> +#include <iostream> +#include <ktrader.h> +#include <kinstance.h> +#include <assert.h> + +#include <ksimpleconfig.h> + +static TQPixmap wallpaperPixmap( const TQString & _wallpaper ) +{ + TQString key = "wallpapers/"; + key += _wallpaper; + KPixmap pix; + + if ( TQPixmapCache::find( key, pix ) ) + return pix; + + TQString 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 + TQPixmapCache::insert( key, pix ); + return pix; + } else kdWarning(1203) << "Couldn't locate wallpaper " << _wallpaper << endl; + return TQPixmap(); +} + +struct KonqPropsView::Private +{ + TQStringList* previewsToShow; + bool previewsEnabled:1; + bool caseInsensitiveSort:1; + bool dirsfirst:1; + bool descending:1; + TQString sortcriterion; +}; + +KonqPropsView::KonqPropsView( TDEInstance * 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 ) +{ + + TDEConfig *config = instance->config(); + TDEConfigGroupSaver 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", TQIconView::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_bShowFreeSpaceOverlays = config->readBoolEntry( "ShowFreeSpaceOverlays", true ); + + 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 ); + + TQColor tc = KonqFMSettings::settings()->normalTextColor(); + m_textColor = config->readColorEntry( "TextColor", &tc ); + m_bgColor = config->readColorEntry( "BgColor" ); // will be set to TQColor() 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) + { + TDEConfigGroupSaver cgs2(TDEGlobal::config(), "Settings"); + m_textColor = TDEGlobal::config()->readColorEntry( "TextColor", &m_textColor ); + m_bgColor = TDEGlobal::config()->readColorEntry( "BgColor", &m_bgColor ); + m_bgPixmapFile = TDEGlobal::config()->readPathEntry( "BgImage", m_bgPixmapFile ); + //kdDebug(1203) << "KonqPropsView::KonqPropsView from TDEGlobal : BgImage=" << m_bgPixmapFile << endl; + } + + TDEGlobal::dirs()->addResourceType("tiles", + TDEGlobal::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; +} + +TDEConfigBase * 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; +} + +TDEConfigBase * 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 TDEGlobal::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() && TQFile::exists( u.path() ); + dotDirectory = u.isLocalFile() ? u.path() : TQString::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 ); + m_bShowFreeSpaceOverlays = config->readBoolEntry( "ShowFreeSpaceOverlays", m_bShowFreeSpaceOverlays ); + 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()) + { + TDEConfigGroupSaver 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()) + { + TDEConfigGroupSaver cgs(currentConfig(), currentGroup()); + currentConfig()->writeEntry( "ItemTextPos", m_iItemTextPos ); + currentConfig()->sync(); + } +} + +void KonqPropsView::setSortCriterion( const TQString &criterion ) +{ + d->sortcriterion = criterion; + if ( m_defaultProps && !m_bSaveViewPropertiesLocally ) + m_defaultProps->setSortCriterion( criterion ); + else if (currentConfig()) + { + TDEConfigGroupSaver 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()) + { + TDEConfigGroupSaver 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()) + { + TDEConfigGroupSaver 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; + TDEConfigGroupSaver 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; + TDEConfigGroupSaver 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; + TDEConfigGroupSaver cgs(currentConfig(), currentGroup()); + currentConfig()->writeEntry( "ShowDirectoryOverlays", m_bShowDirectoryOverlays ); + currentConfig()->sync(); + } +} + +void KonqPropsView::setShowingFreeSpaceOverlays( bool show ) +{ + kdDebug(1203) << "KonqPropsView::setShowingFreeSpaceOverlays " << show << endl; + m_bShowFreeSpaceOverlays = show; + if ( m_defaultProps && !m_bSaveViewPropertiesLocally ) + { + kdDebug(1203) << "Saving in default properties" << endl; + m_defaultProps->setShowingFreeSpaceOverlays( show ); + } + else if (currentConfig()) + { + kdDebug(1203) << "Saving in current config" << endl; + TDEConfigGroupSaver cgs(currentConfig(), currentGroup()); + currentConfig()->writeEntry( "ShowFreeSpaceOverlays", m_bShowFreeSpaceOverlays ); + currentConfig()->sync(); + } +} + +void KonqPropsView::setShowingPreview( const TQString &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()) + { + TDEConfigGroupSaver 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; + TDEConfigGroupSaver 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 TQColor & color ) +{ + m_bgColor = color; + if ( m_defaultProps && !m_bSaveViewPropertiesLocally ) + { + m_defaultProps->setBgColor( color ); + } + else + { + TDEConfigBase * colorConfig = currentColorConfig(); + if (colorConfig) // 0L when saving locally but remote URL + { + TDEConfigGroupSaver cgs(colorConfig, currentGroup()); + colorConfig->writeEntry( "BgColor", m_bgColor ); + colorConfig->sync(); + } + } +} + +const TQColor & KonqPropsView::bgColor( TQWidget * widget ) const +{ + if ( !m_bgColor.isValid() ) + return widget->colorGroup().base(); + else + return m_bgColor; +} + +void KonqPropsView::setTextColor( const TQColor & color ) +{ + m_textColor = color; + if ( m_defaultProps && !m_bSaveViewPropertiesLocally ) + { + m_defaultProps->setTextColor( color ); + } + else + { + TDEConfigBase * colorConfig = currentColorConfig(); + if (colorConfig) // 0L when saving locally but remote URL + { + TDEConfigGroupSaver cgs(colorConfig, currentGroup()); + colorConfig->writeEntry( "TextColor", m_textColor ); + colorConfig->sync(); + } + } +} + +const TQColor & KonqPropsView::textColor( TQWidget * widget ) const +{ + if ( !m_textColor.isValid() ) + return widget->colorGroup().text(); + else + return m_textColor; +} + +void KonqPropsView::setBgPixmapFile( const TQString & file ) +{ + m_bgPixmapFile = file; + + if ( m_defaultProps && !m_bSaveViewPropertiesLocally ) + { + m_defaultProps->setBgPixmapFile( file ); + } + else + { + TDEConfigBase * colorConfig = currentColorConfig(); + if (colorConfig) // 0L when saving locally but remote URL + { + TDEConfigGroupSaver cgs(colorConfig, currentGroup()); + colorConfig->writePathEntry( "BgImage", file ); + colorConfig->sync(); + } + } +} + +TQPixmap KonqPropsView::loadPixmap() const +{ + //kdDebug(1203) << "KonqPropsView::loadPixmap " << m_bgPixmapFile << endl; + TQPixmap bgPixmap; + if ( !m_bgPixmapFile.isEmpty() ) + bgPixmap = wallpaperPixmap( m_bgPixmapFile ); + return bgPixmap; +} + +void KonqPropsView::applyColors(TQWidget * widget) const +{ + if ( m_bgPixmapFile.isEmpty() ) + widget->setPaletteBackgroundColor( bgColor( widget ) ); + else + { + TQPixmap 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 TQStringList& KonqPropsView::previewSettings() +{ + if ( ! d->previewsToShow ) + { + d->previewsToShow = new TQStringList; + + if (d->previewsEnabled) { + TDETrader::OfferList plugins = TDETrader::self()->query( "ThumbCreator" ); + for ( TDETrader::OfferList::ConstIterator it = plugins.begin(); it != plugins.end(); ++it ) + { + TQString 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 TQString& KonqPropsView::sortCriterion() const { + return d->sortcriterion; +} + diff --git a/libkonq/konq_propsview.h b/libkonq/konq_propsview.h new file mode 100644 index 000000000..c2759693f --- /dev/null +++ b/libkonq/konq_propsview.h @@ -0,0 +1,189 @@ +/* This file is part of the KDE project + Copyright (C) 1997 David Faure <[email protected]> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +#ifndef __konq_viewprops_h__ +#define __konq_viewprops_h__ + +#include <tqpixmap.h> +#include <tqstringlist.h> + +#include <kurl.h> +#include <libkonq_export.h> + +class TDEInstance; +class TDEConfigBase; +class TDEConfig; + +/** + * 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( TDEInstance * 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 ); // TQIconView::Bottom or TQIconView::Right, currently + int itemTextPos() const { return m_iItemTextPos; } + + void setSortCriterion( const TQString &criterion ); + const TQString& 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 setShowingFreeSpaceOverlays( bool show ); + bool isShowingFreeSpaceOverlays() const { return m_bShowFreeSpaceOverlays; } + + void setShowingPreview( const TQString &preview, bool show ); + void setShowingPreview( bool show ); + bool isShowingPreview( const TQString &preview ) const { return ! m_dontPreview.contains(preview); } + bool isShowingPreview(); + const TQStringList &previewSettings(); + + void setBgColor( const TQColor & color ); + const TQColor& bgColor(TQWidget * widget) const; + void setTextColor( const TQColor & color ); + const TQColor& textColor(TQWidget * widget) const; + void setBgPixmapFile( const TQString & file ); + const TQString& bgPixmapFile() const { return m_bgPixmapFile; } + + // Applies bgcolor, textcolor, pixmap to the @p widget + void applyColors( TQWidget * widget ) const; + +protected: + + TQPixmap loadPixmap() const; + + // Current config object for _saving_ + TDEConfigBase * currentConfig(); + + // Current config object for _saving_ settings related to colors + TDEConfigBase * currentColorConfig(); + + TQString currentGroup() const { + return isDefaultProperties() ? + TQString::fromLatin1("Settings") : TQString::fromLatin1("URL properties"); + } + +private: + // The actual properties + + int m_iIconSize; + int m_iItemTextPos; + bool m_bShowDot; + bool m_bShowDirectoryOverlays; + bool m_bShowFreeSpaceOverlays; + TQStringList m_dontPreview; + TQColor m_textColor; + TQColor m_bgColor; + TQString m_bgPixmapFile; + + // Path to .directory file, whether it exists or not + TQString 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 TDEConfig or a KSimpleConfig + TDEConfigBase * 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..41460e8ae --- /dev/null +++ b/libkonq/konq_settings.cc @@ -0,0 +1,184 @@ +/* This file is part of the KDE project + Copyright (C) 1999 David Faure <[email protected]> + + 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 "tdeglobalsettings.h" +#include <tdeglobal.h> +#include <kservicetype.h> +#include <kdesktopfile.h> +#include <kdebug.h> +#include <assert.h> +#include <tqfontmetrics.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) + { + TDEConfig *config = TDEGlobal::config(); + TDEConfigGroupSaver cgs(config, "FMSettings"); + s_pSettings = new KonqFMSettings(config); + } + return s_pSettings; +} + +//static +void KonqFMSettings::reparseConfiguration() +{ + if (s_pSettings) + { + TDEConfig *config = TDEGlobal::config(); + TDEConfigGroupSaver cgs(config, "FMSettings"); + s_pSettings->init( config ); + } +} + +KonqFMSettings::KonqFMSettings( TDEConfig * config ) +{ + d = new KonqFMSettingsPrivate; + init( config ); +} + +KonqFMSettings::~KonqFMSettings() +{ + delete d; +} + +void KonqFMSettings::init( TDEConfig * config ) +{ + // Fonts and colors + m_standardFont = config->readFontEntry( "StandardFont" ); + + m_normalTextColor = TDEGlobalSettings::textColor(); + m_normalTextColor = config->readColorEntry( "NormalTextColor", &m_normalTextColor ); + m_highlightedTextColor = TDEGlobalSettings::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 = TQFontMetrics(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 TQString::localeAwareCompare is case sensitive (it usually isn't, when LC_COLLATE is set) + d->localeAwareCompareIsCaseSensitive = TQString( "a" ).localeAwareCompare( "B" ) > 0; // see #40131 +} + +bool KonqFMSettings::shouldEmbed( const TQString & 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-TDE-LocalProtocol" ).toString().isEmpty(); + TQVariant autoEmbedProp = serviceTypePtr->property( "X-TDE-AutoEmbed" ); + if ( autoEmbedProp.isValid() ) + { + bool autoEmbed = autoEmbedProp.toBool(); + kdDebug(1203) << "X-TDE-AutoEmbed set to " << (autoEmbed ? "true" : "false") << endl; + return autoEmbed; + } else + kdDebug(1203) << "No X-TDE-AutoEmbed, looking for group" << endl; + } + // 2 - in the configuration for the group if nothing was found in the mimetype + TQString 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/* + TQMap<TQString, TQString>::ConstIterator it = m_embedMap.find( TQString::fromLatin1("embed-")+serviceTypeGroup ); + if ( it != m_embedMap.end() ) { + kdDebug(1203) << "KonqFMSettings::shouldEmbed: " << it.data() << endl; + return it.data() == TQString::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 TQString& a, const TQString& b ) const +{ + if ( d->localeAwareCompareIsCaseSensitive ) { + return a.localeAwareCompare( b ); + } + else // can't use localeAwareCompare, have to fallback to normal TQString 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..daca8babe --- /dev/null +++ b/libkonq/konq_settings.h @@ -0,0 +1,141 @@ +/* This file is part of the KDE project + Copyright (C) 1999 David Faure <[email protected]> + + 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 TDEConfig; +#include <tqcolor.h> +#include <tqstring.h> +#include <tqfont.h> +#include <tqmap.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( TDEConfig * 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 TDEGlobal::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 TQString & 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 TQString & 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 TQFont& standardFont() const { return m_standardFont; } + + // Color settings + const TQColor& normalTextColor() const { return m_normalTextColor; } + const TQColor& highlightedTextColor() const { return m_highlightedTextColor; } + const TQColor& itemTextBackground() const { return m_itemTextBackground; } + + int textPreviewIconTransparency() const { return m_iconTransparency; } + + int caseSensitiveCompare( const TQString& a, const TQString& b ) const; + +private: + + static KonqFMSettings * s_pSettings; + + bool m_underlineLink; + bool m_fileSizeInBytes; + bool m_alwaysNewWin; + bool m_bTreeFollow; + + TQMap<TQString, TQString> m_embedMap; + + TQFont m_standardFont; + + TQColor m_normalTextColor; + TQColor m_highlightedTextColor; + TQColor m_itemTextBackground; + + bool m_bWordWrapText; + int m_iconTextHeight; + + TQString m_homeURL; + bool m_showFileTips; + int m_numFileTips; + + // used for the textpreview + int m_iconTransparency; + + /** Called by constructor and reparseConfiguration */ + void init( TDEConfig * 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..9e1ca66fb --- /dev/null +++ b/libkonq/konq_sound.cc @@ -0,0 +1,137 @@ +/* This file is part of the KDE Project + Copyright (c) 2001 Malte Starostik <[email protected]> + + 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 TQStringList &mimeTypes(); + virtual void play(const TQString &fileName); + virtual void stop(); + virtual bool isPlaying(); + +private: + TQStringList 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 TQStringList &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 TQString &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(TQObject *parent = 0, const char *name = 0) + : KLibFactory(parent, name) {}; + virtual ~KonqSoundFactory() {}; + +protected: + virtual TQObject *createObject(TQObject * = 0, const char * = 0, + const char *className = TQOBJECT_OBJECT_NAME_STRING, const TQStringList &args = TQStringList()); +}; + +TQObject *KonqSoundFactory::createObject(TQObject *, const char *, + const char *className, const TQStringList &) +{ + if (qstrcmp(className, "KonqSoundPlayer") == 0) + return TQT_TQOBJECT(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..c0139e763 --- /dev/null +++ b/libkonq/konq_sound.h @@ -0,0 +1,35 @@ +/* This file is part of the KDE Project + Copyright (c) 2001 Malte Starostik <[email protected]> + + 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 TQObject +{ +public: + virtual const TQStringList &mimeTypes() = 0; + virtual void play(const TQString &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..51d85587d --- /dev/null +++ b/libkonq/konq_undo.cc @@ -0,0 +1,667 @@ +/* This file is part of the KDE project + Copyright (C) 2000 Simon Hausmann <[email protected]> + + 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 <tdeio/uiserver_stub.h> +#include "konq_operations.h" + +#include <assert.h> + +#include <dcopclient.h> +#include <dcopref.h> + +#include <tdeapplication.h> +#include <kdatastream.h> +#include <kdebug.h> +#include <tdelocale.h> +#include <tdeglobalsettings.h> +#include <tdeconfig.h> +#include <kipc.h> + +#include <tdeio/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 TDEIO::Job +{ +public: + KonqUndoJob() : TDEIO::Job( true ) { KonqUndoManager::incRef(); }; + virtual ~KonqUndoJob() { KonqUndoManager::decRef(); } + + virtual void kill( bool q) { KonqUndoManager::self()->stopUndo( true ); TDEIO::Job::kill( q ); } +}; + +class KonqCommandRecorder::KonqCommandRecorderPrivate +{ +public: + KonqCommandRecorderPrivate() + { + } + ~KonqCommandRecorderPrivate() + { + } + + KonqCommand m_cmd; +}; + +KonqCommandRecorder::KonqCommandRecorder( KonqCommand::Type op, const KURL::List &src, const KURL &dst, TDEIO::Job *job ) + : TQObject( 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, TQT_SIGNAL( result( TDEIO::Job * ) ), + this, TQT_SLOT( slotResult( TDEIO::Job * ) ) ); + + if ( op != KonqCommand::MKDIR ) { + connect( job, TQT_SIGNAL( copyingDone( TDEIO::Job *, const KURL &, const KURL &, bool, bool ) ), + this, TQT_SLOT( slotCopyingDone( TDEIO::Job *, const KURL &, const KURL &, bool, bool ) ) ); + connect( job, TQT_SIGNAL( copyingLinkDone( TDEIO::Job *, const KURL &, const TQString &, const KURL & ) ), + this, TQT_SLOT( slotCopyingLinkDone( TDEIO::Job *, const KURL &, const TQString &, const KURL & ) ) ); + } + + KonqUndoManager::incRef(); +} + +KonqCommandRecorder::~KonqCommandRecorder() +{ + KonqUndoManager::decRef(); + delete d; +} + +void KonqCommandRecorder::slotResult( TDEIO::Job *job ) +{ + if ( job->error() ) + return; + + KonqUndoManager::self()->addCommand( d->m_cmd ); +} + +void KonqCommandRecorder::slotCopyingDone( TDEIO::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" ); + TQMap<TQString, TQString> metaData = job->metaData(); + TQMap<TQString, TQString>::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( TDEIO::Job *, const KURL &from, const TQString &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( "tdeio_uiserver", "UIServer" ); + m_undoJob = 0; + } + ~KonqUndoManagerPrivate() + { + delete m_uiserver; + } + + bool m_syncronized; + + KonqCommand::Stack m_commands; + + KonqCommand m_current; + TDEIO::Job *m_currentJob; + UndoState m_undoState; + TQValueStack<KURL> m_dirStack; + TQValueStack<KURL> m_dirCleanupStack; + TQValueStack<KURL> m_fileCleanupStack; + TQValueList<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; +} + +TQString 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 TQString::null; +} + +void KonqUndoManager::undo() +{ + KonqCommand cmd = d->m_commands.top(); + assert( cmd.m_valid ); + + d->m_current = cmd; + + TQValueList<KonqBasicOperation>& opStack = d->m_current.m_opStack; + + // Let's first ask for confirmation if we need to delete any file (#99898) + KURL::List fileCleanupStack; + TQValueList<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(); + TQValueList<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( TDEIO::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, TQT_SIGNAL( result( TDEIO::Job * ) ), + this, TQT_SLOT( slotResult( TDEIO::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 = TDEIO::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 = TDEIO::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 = TDEIO::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 = TDEIO::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 = TDEIO::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 TDEIO 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 = TDEIO::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 = TDEIO::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*" ); + TQValueList<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; +} + +TQDataStream &operator<<( TQDataStream &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; +} +TQDataStream &operator>>( TQDataStream &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; +} + +TQDataStream &operator<<( TQDataStream &stream, const KonqCommand &cmd ) +{ + stream << cmd.m_valid << (TQ_INT8)cmd.m_type << cmd.m_opStack << cmd.m_src << cmd.m_dst; + return stream; +} + +TQDataStream &operator>>( TQDataStream &stream, KonqCommand &cmd ) +{ + TQ_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..fa908de67 --- /dev/null +++ b/libkonq/konq_undo.h @@ -0,0 +1,162 @@ +/* This file is part of the KDE project + Copyright (C) 2000 Simon Hausmann <[email protected]> + + 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 <tqobject.h> +#include <tqstring.h> +#include <tqvaluestack.h> + +#include <dcopobject.h> + +#include <kurl.h> +#include <libkonq_export.h> + +namespace TDEIO +{ + class Job; +} + +class KonqUndoJob; + +struct KonqBasicOperation +{ + typedef TQValueStack<KonqBasicOperation> Stack; + + KonqBasicOperation() + { m_valid = false; } + + bool m_valid; + bool m_directory; + bool m_renamed; + bool m_link; + KURL m_src; + KURL m_dst; + TQString m_target; +}; + +struct KonqCommand +{ + typedef TQValueStack<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 TQObject +{ + Q_OBJECT +public: + KonqCommandRecorder( KonqCommand::Type op, const KURL::List &src, const KURL &dst, TDEIO::Job *job ); + virtual ~KonqCommandRecorder(); + +private slots: + void slotResult( TDEIO::Job *job ); + + void slotCopyingDone( TDEIO::Job *, const KURL &from, const KURL &to, bool directory, bool renamed ); + void slotCopyingLinkDone( TDEIO::Job *, const KURL &from, const TQString &target, const KURL &to ); + +private: + class KonqCommandRecorderPrivate; + KonqCommandRecorderPrivate *d; +}; + +class LIBKONQ_EXPORT KonqUndoManager : public TQObject, 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; + TQString undoText() const; + +public slots: + void undo(); + +signals: + void undoAvailable( bool avail ); + void undoTextChanged( const TQString &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( TDEIO::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; +}; + +TQDataStream &operator<<( TQDataStream &stream, const KonqBasicOperation &op ); +TQDataStream &operator>>( TQDataStream &stream, KonqBasicOperation &op ); + +TQDataStream &operator<<( TQDataStream &stream, const KonqCommand &cmd ); +TQDataStream &operator>>( TQDataStream &stream, KonqCommand &cmd ); + +#endif diff --git a/libkonq/konq_xmlguiclient.cc b/libkonq/konq_xmlguiclient.cc new file mode 100644 index 000000000..c3c7215b9 --- /dev/null +++ b/libkonq/konq_xmlguiclient.cc @@ -0,0 +1,157 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Holger Freyther <[email protected]> + Copyright (c) 1998, 1999 David Faure <[email protected]> + + 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 "tdeapplication.h" + +#include "konq_xmlguiclient.h" +#include <kdebug.h> + +class KonqXMLGUIClient::Private +{ +public: + Private() : attrName( "name" ), separatorPending( false ), hasAction( false ) {} + TQString 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 = TQDomDocument( "kpartgui" ); + + TQDomElement 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 ); */ +} + +TQDomElement KonqXMLGUIClient::DomElement() const +{ + return m_menuElement; +} + +TQDomDocument KonqXMLGUIClient::domDocument() const +{ + return m_doc; +} + +void KonqXMLGUIClient::addAction( TDEAction *act, const TQDomElement &menu ) +{ + addAction( act->name(), menu ); +} + +void KonqXMLGUIClient::addAction( const char *name, const TQDomElement &menu ) +{ + static const TQString& tagAction = TDEGlobal::staticQString( "action" ); + + if (!kapp->authorizeTDEAction(name)) + return; + + handlePendingSeparator(); + TQDomElement parent = menu; + if ( parent.isNull() ) { + parent = m_menuElement; + } + + TQDomElement e = m_doc.createElement( tagAction ); + parent.appendChild( e ); + e.setAttribute( d->attrName, name ); + d->hasAction = true; +} + +void KonqXMLGUIClient::addSeparator( const TQDomElement &menu ) +{ + static const TQString& tagSeparator = TDEGlobal::staticQString( "separator" ); + + TQDomElement parent = menu; + if ( parent.isNull() ) { + parent = m_menuElement; + } + + parent.appendChild( m_doc.createElement( tagSeparator ) ); + + d->separatorPending = false; +} + +//void KonqXMLGUIClient::addWeakSeparator() +//{ +// static const TQString& tagWeakSeparator = TDEGlobal::staticQString( "weakSeparator" ); +// m_menuElement.appendChild( m_doc.createElement( tagWeakSeparator ) ); +//} + +void KonqXMLGUIClient::addMerge( const TQString &name ) +{ + // can't call handlePendingSeparator. Merge could be empty + // (testcase: RMB in embedded katepart) + TQDomElement merge = m_doc.createElement( "merge" ); + m_menuElement.appendChild( merge ); + if ( !name.isEmpty() ) + merge.setAttribute( d->attrName, name ); +} + +void KonqXMLGUIClient::addGroup( const TQString &grp ) +{ + handlePendingSeparator(); + TQDomElement 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..685b58a34 --- /dev/null +++ b/libkonq/konq_xmlguiclient.h @@ -0,0 +1,70 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Holger Freyther <[email protected]> + + 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 <tdeaction.h> +#include <kxmlguiclient.h> +#include <tqstringlist.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 + */ + TQDomDocument domDocument( ) const; + + TQDomElement DomElement( ) const; // KDE4: s/D/d/ + +protected: + void addAction( TDEAction *action, const TQDomElement &menu = TQDomElement() ); + void addAction( const char *name, const TQDomElement &menu = TQDomElement() ); + void addSeparator( const TQDomElement &menu = TQDomElement() ); + /// only add a separator if an action is added afterwards + void addPendingSeparator(); + void addGroup( const TQString &grp ); + void addMerge( const TQString &name ); + + // @return true if addAction was called at least once + bool hasAction() const; + void prepareXMLGUIStuff(); + +// KDE4: make private + TQDomElement m_menuElement; + TQDomDocument 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..88ff45ced --- /dev/null +++ b/libkonq/konqbookmarkmanager.h @@ -0,0 +1,36 @@ +#ifndef KONQBOOKMARKMANAGER_H +#define KONQBOOKMARKMANAGER_H + +#include <kbookmarkmanager.h> +#include <kstandarddirs.h> +#include <kurl.h> +#include <tdeio/job.h> +#include <libkonq_export.h> +#include <tdeapplication.h> + +class LIBKONQ_EXPORT KonqBookmarkManager +{ +public: + static KBookmarkManager * self() + { + if ( !s_bookmarkManager ) + { + TQString globalBookmarkFile = locate( "data", TQString::fromLatin1( "konqueror/bookmarks.xml" ) ); + TQString bookmarksFile = locateLocal( "data", TQString::fromLatin1("konqueror/bookmarks.xml" ), true); + if (globalBookmarkFile != TQString::null && bookmarksFile != TQString::null && + globalBookmarkFile != bookmarksFile) + { + TDEIO::file_copy(KURL::fromPathOrURL(globalBookmarkFile), + KURL::fromPathOrURL(bookmarksFile)); + kapp->processEvents(3000); // Allows up to 3 seconds to copy the file + } + 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..07a2a4865 --- /dev/null +++ b/libkonq/konqpopupmenuplugin.desktop @@ -0,0 +1,76 @@ +[Desktop Entry] +Type=ServiceType +X-TDE-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..4e10a4ec0 --- /dev/null +++ b/libkonq/libkonq_export.h @@ -0,0 +1,39 @@ +/* + This file is part of the KDE project + Copyright (C) 2004 Jaroslaw Staniek <[email protected]> + (C) 2004 Dirk Mueller <[email protected]> + + 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 <tqglobal.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/CMakeLists.txt b/libkonq/pics/CMakeLists.txt new file mode 100644 index 000000000..96126651a --- /dev/null +++ b/libkonq/pics/CMakeLists.txt @@ -0,0 +1,15 @@ +################################################# +# +# (C) 2010-2011 Serghei Amelian +# serghei (DOT) amelian (AT) gmail.com +# +# Improvements and feedback are welcome +# +# This file is released under GPL >= 2 +# +################################################# + +install( FILES + thumbnailfont_7x4.png arrow_topleft.png arrow_topright.png + arrow_bottomleft.png arrow_bottomright.png + DESTINATION ${DATA_INSTALL_DIR}/konqueror/pics ) 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 Binary files differnew file mode 100644 index 000000000..90ef9754c --- /dev/null +++ b/libkonq/pics/arrow_bottomleft.png diff --git a/libkonq/pics/arrow_bottomright.png b/libkonq/pics/arrow_bottomright.png Binary files differnew file mode 100644 index 000000000..92f7c9c58 --- /dev/null +++ b/libkonq/pics/arrow_bottomright.png diff --git a/libkonq/pics/arrow_topleft.png b/libkonq/pics/arrow_topleft.png Binary files differnew file mode 100644 index 000000000..b27b6df5c --- /dev/null +++ b/libkonq/pics/arrow_topleft.png diff --git a/libkonq/pics/arrow_topright.png b/libkonq/pics/arrow_topright.png Binary files differnew file mode 100644 index 000000000..624b2b213 --- /dev/null +++ b/libkonq/pics/arrow_topright.png diff --git a/libkonq/pics/thumbnailfont_7x4.png b/libkonq/pics/thumbnailfont_7x4.png Binary files differnew file mode 100644 index 000000000..a442e3cab --- /dev/null +++ b/libkonq/pics/thumbnailfont_7x4.png diff --git a/libkonq/servicemenus/CMakeLists.txt b/libkonq/servicemenus/CMakeLists.txt new file mode 100644 index 000000000..6d54b0ab0 --- /dev/null +++ b/libkonq/servicemenus/CMakeLists.txt @@ -0,0 +1,14 @@ +################################################# +# +# (C) 2013 Timothy Pearson +# kb9vqf (AT) pearsoncomputing.net +# +# Improvements and feedback are welcome +# +# This file is released under the GPL >= 2 +# +################################################# + +install( FILES + edit-as-root.desktop + DESTINATION ${DATA_INSTALL_DIR}/konqueror/servicemenus ) diff --git a/libkonq/servicemenus/edit-as-root.desktop b/libkonq/servicemenus/edit-as-root.desktop new file mode 100644 index 000000000..f927ac1cd --- /dev/null +++ b/libkonq/servicemenus/edit-as-root.desktop @@ -0,0 +1,12 @@ +[Desktop Entry] +X-TDE-ServiceTypes=text/*,application/x-desktop +Actions=Editassu + +[Desktop Action Editassu] +Name=Edit as Root +Name[it]=Edita come Root +Name[fr]=Editer en tant que Root +Name[es]=Editar como Root +Name[de]=Als root bearbeiten +Icon=kfm +Exec=tdesu "kwrite" "%U" diff --git a/libkonq/tdefileivi.cc b/libkonq/tdefileivi.cc new file mode 100644 index 000000000..08bd240ba --- /dev/null +++ b/libkonq/tdefileivi.cc @@ -0,0 +1,579 @@ +/* This file is part of the KDE project + Copyright (C) 1999, 2000, 2001, 2002 David Faure <[email protected]> + + 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 "tdefileivi.h" +#include "kivdirectoryoverlay.h" +#include "kivfreespaceoverlay.h" +#include "konq_iconviewwidget.h" +#include "konq_operations.h" +#include "konq_settings.h" + +#include <tqpainter.h> + +#include <kurldrag.h> +#include <kiconeffect.h> +#include <tdefileitem.h> +#include <kdebug.h> +#include <krun.h> +#include <kservice.h> + +#undef Bool + +/** + * Private data for KFileIVI + */ +struct KFileIVI::Private +{ + TQIconSet icons; // Icon states (cached to prevent re-applying icon effects + // every time) + TQPixmap thumb; // Raw unprocessed thumbnail + TQString m_animatedIcon; // Name of animation + bool m_animated; // Animation currently running ? + KIVDirectoryOverlay* m_directoryOverlay; + KIVFreeSpaceOverlay* m_freeSpaceOverlay; + TQPixmap m_overlay; + TQString m_overlayName; + int m_progress; +}; + +KFileIVI::KFileIVI( KonqIconViewWidget *iconview, KFileItem* fileitem, int size ) + : TDEIconViewItem( iconview, fileitem->text() ), + m_size( size ), m_state( TDEIcon::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(), TQIconSet::Large ); + d->m_animated = false; + + // iconName() requires the mimetype to be known + if ( fileitem->isMimeTypeKnown() ) + { + TQString icon = fileitem->iconName(); + if ( !icon.isEmpty() ) + setMouseOverAnimation( icon ); + else + setMouseOverAnimation( "unknown" ); + } + d->m_progress = -1; + d->m_directoryOverlay = 0; + d->m_freeSpaceOverlay = 0; +} + +KFileIVI::~KFileIVI() +{ + delete d->m_directoryOverlay; + delete d->m_freeSpaceOverlay; + delete d; +} + +void KFileIVI::invalidateThumb( int state, bool redraw ) +{ + TQIconSet::Mode mode; + switch( state ) + { + case TDEIcon::DisabledState: + mode = TQIconSet::Disabled; + break; + case TDEIcon::ActiveState: + mode = TQIconSet::Active; + break; + case TDEIcon::DefaultState: + default: + mode = TQIconSet::Normal; + break; + } + d->icons = TQIconSet(); + d->icons.setPixmap( TDEGlobal::iconLoader()->iconEffect()-> + apply( d->thumb, TDEIcon::Desktop, state ), + TQIconSet::Large, mode ); + m_state = state; + + TQIconViewItem::setPixmap( d->icons.pixmap( TQIconSet::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 = TDEIcon::DisabledState; + else + m_state = state; + + if ( d->m_overlayName.isNull() ) + d->m_overlay = TQPixmap(); + else { + int halfSize; + if (m_size == 0) { + halfSize = IconSize(TDEIcon::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 TQString& iconName ) +{ + d->m_overlayName = iconName; + + refreshIcon(true); +} + +void KFileIVI::setOverlayProgressBar( const int progress ) +{ + d->m_progress = progress; + + 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(TQString()); + return 0; + } +} + +bool KFileIVI::showDirectoryOverlay( ) +{ + return (bool)d->m_directoryOverlay; +} + +KIVFreeSpaceOverlay* KFileIVI::setShowFreeSpaceOverlay( bool show ) +{ + if ( !m_fileitem->mimetype().startsWith("media/") ) { + return 0; + } + + if (show) { + if (!d->m_freeSpaceOverlay) + d->m_freeSpaceOverlay = new KIVFreeSpaceOverlay(this); + return d->m_freeSpaceOverlay; + } else { + delete d->m_freeSpaceOverlay; + d->m_freeSpaceOverlay = 0; + setOverlayProgressBar(-1); + return 0; + } +} + +bool KFileIVI::showFreeSpaceOverlay( ) +{ + return (bool)d->m_freeSpaceOverlay; +} + +void KFileIVI::setPixmapDirect( const TQPixmap& pixmap, bool recalc, bool redraw ) +{ + TQIconSet::Mode mode; + switch( m_state ) + { + case TDEIcon::DisabledState: + mode = TQIconSet::Disabled; + break; + case TDEIcon::ActiveState: + mode = TQIconSet::Active; + break; + case TDEIcon::DefaultState: + default: + mode = TQIconSet::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 = TQIconSet(); + d->icons.setPixmap( pixmap, TQIconSet::Large, mode ); + + updatePixmapSize(); + TQIconViewItem::setPixmap( d->icons.pixmap( TQIconSet::Large, mode ), + recalc, redraw ); +} + +void KFileIVI::setDisabled( bool disabled ) +{ + if ( m_bDisabled != disabled ) + { + m_bDisabled = disabled; + bool active = ( m_state == TDEIcon::ActiveState ); + setEffect( m_bDisabled ? TDEIcon::DisabledState : + ( active ? TDEIcon::ActiveState : TDEIcon::DefaultState ) ); + } +} + +void KFileIVI::setThumbnailPixmap( const TQPixmap & pixmap ) +{ + m_bThumbnail = true; + d->thumb = pixmap; + // TQIconSet::reset() doesn't seem to clear the other generated pixmaps, + // so we just create a blank TQIconSet here + d->icons = TQIconSet(); + d->icons.setPixmap( TDEGlobal::iconLoader()->iconEffect()-> + apply( pixmap, TDEIcon::Desktop, TDEIcon::DefaultState ), + TQIconSet::Large, TQIconSet::Normal ); + + m_state = TDEIcon::DefaultState; + + // Recalc when setting this pixmap! + updatePixmapSize(); + TQIconViewItem::setPixmap( d->icons.pixmap( TQIconSet::Large, + TQIconSet::Normal ), true ); +} + +void KFileIVI::setActive( bool active ) +{ + if ( active ) + setEffect( TDEIcon::ActiveState ); + else + setEffect( m_bDisabled ? TDEIcon::DisabledState : TDEIcon::DefaultState ); +} + +void KFileIVI::setEffect( int state ) +{ + TQIconSet::Mode mode; + switch( state ) + { + case TDEIcon::DisabledState: + mode = TQIconSet::Disabled; + break; + case TDEIcon::ActiveState: + mode = TQIconSet::Active; + break; + case TDEIcon::DefaultState: + default: + mode = TQIconSet::Normal; + break; + } + // Do not update if the fingerprint is identical (prevents flicker)! + + TDEIconEffect *effect = TDEGlobal::iconLoader()->iconEffect(); + + bool haveEffect = effect->hasEffect( TDEIcon::Desktop, m_state ) != + effect->hasEffect( TDEIcon::Desktop, state ); + + //kdDebug(1203) << "desktop;defaultstate=" << + // effect->fingerprint(TDEIcon::Desktop, TDEIcon::DefaultState) << + // endl; + //kdDebug(1203) << "desktop;activestate=" << + // effect->fingerprint(TDEIcon::Desktop, TDEIcon::ActiveState) << + // endl; + + if( haveEffect && + effect->fingerprint( TDEIcon::Desktop, m_state ) != + effect->fingerprint( TDEIcon::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( TQIconSet::Large, mode ) ) + d->icons.setPixmap( effect->apply( d->thumb, TDEIcon::Desktop, state ), + TQIconSet::Large, mode ); + } + else + { + if( d->icons.isGenerated( TQIconSet::Large, mode ) ) + d->icons.setPixmap( m_fileitem->pixmap( m_size, state ), + TQIconSet::Large, mode ); + } + TQIconViewItem::setPixmap( d->icons.pixmap( TQIconSet::Large, mode ) ); + } + m_state = state; +} + +void KFileIVI::refreshIcon( bool redraw ) +{ + if (!isThumbnail()) { + setIcon( m_size, m_state, true, redraw ); + } +} + +void KFileIVI::invalidateThumbnail() +{ + d->thumb = TQPixmap(); +} + +bool KFileIVI::isThumbnailInvalid() const +{ + return d->thumb.isNull(); +} + +bool KFileIVI::acceptDrop( const TQMimeSource *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 TQIconViewItem::acceptDrop( mime ); +} + +void KFileIVI::setKey( const TQString &key ) +{ + TQString theKey = key; + + TQVariant sortDirProp = iconView()->property( "sortDirectoriesFirst" ); + + bool isdir = ( S_ISDIR( m_fileitem->mode() ) && ( !sortDirProp.isValid() || ( sortDirProp.type() == TQVariant::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( TQChar( sortChar + '0' ) ); + + TQIconViewItem::setKey( theKey ); +} + +void KFileIVI::dropped( TQDropEvent *e, const TQValueList<TQIconDragItem> & ) +{ + KonqOperations::doDrop( item(), item()->url(), e, iconView() ); +} + +void KFileIVI::returnPressed() +{ + if ( static_cast<KonqIconViewWidget*>(iconView())->isDesktop() ) { + KURL url = m_fileitem->url(); + if (url.protocol() == "media") { + // The user reasonably expects to be placed within the media:/ tree + // when opening a media device from the desktop + KService::Ptr service = KService::serviceByDesktopName("konqueror"); + if (service) { + // HACK + // There doesn't seem to be a way to prevent KRun from resolving the URL to its + // local path, so simpy launch Konqueror with the correct arguments instead... + KRun::runCommand("konqueror " + url.url(), "konqueror", service->icon()); + } + else { + (void) new KRun( url, m_fileitem->mode(), m_fileitem->isLocalFile() ); + } + } + else { + // 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( TQPainter *p, const TQColorGroup &c ) +{ + TQColorGroup cg = updateColors(c); + paintFontUpdate( p ); + + //*** TEMPORARY CODE - MUST BE MADE CONFIGURABLE FIRST - Martijn + // SET UNDERLINE ON HOVER ONLY + /*if ( ( ( KonqIconViewWidget* ) iconView() )->m_pActiveItem == this ) + { + TQFont f( p->font() ); + f.setUnderline( TRUE ); + p->setFont( f ); + }*/ + + TDEIconViewItem::paintItem( p, cg ); + paintOverlay(p); + paintOverlayProgressBar(p); + +} + +void KFileIVI::paintOverlay( TQPainter *p ) const +{ + if ( !d->m_overlay.isNull() ) { + TQRect rect = pixmapRect(true); + p->drawPixmap(x() + rect.x() , y() + pixmapRect().height() - d->m_overlay.height(), d->m_overlay); + } +} + +void KFileIVI::paintOverlayProgressBar( TQPainter *p ) const +{ + if (d->m_progress != -1) { +// // Pie chart +// TQRect rect = pixmapRect(true); +// rect.setX(x() + rect.x()); +// rect.setY(y() + rect.y() + ((pixmapRect().height()*3)/4)); +// rect.setWidth(pixmapRect().width()/4); +// rect.setHeight(pixmapRect().height()/4); +// +// p->save(); +// +// p->setPen(TQPen::NoPen); +// p->setBrush(TQt::red); +// p->drawEllipse(rect); +// p->setBrush(TQt::green); +// p->drawPie(rect, 1440, (((100-d->m_progress)*5760)/100)); + +// // Horizontal progress bar +// TQRect rect = pixmapRect(true); +// int verticalOffset = 0; +// int usedBarWidth = ((d->m_progress*pixmapRect().width())/100); +// int endPosition = x() + rect.x() + usedBarWidth; +// +// p->save(); +// +// p->setPen(TQPen::NoPen); +// p->setBrush(TQt::red); +// p->drawRect(TQRect(x() + rect.x(), y() + rect.y() + (pixmapRect().height() - verticalOffset), usedBarWidth, 1)); +// p->setBrush(TQt::green); +// p->drawRect(TQRect(endPosition, y() + rect.y() + (pixmapRect().height() - verticalOffset), pixmapRect().width() - usedBarWidth, 1)); + + // Vertical progress bar + TQRect rect = pixmapRect(true); + int horizontalOffset = 0; + int usedBarHeight = (((100-d->m_progress)*pixmapRect().height())/100); + int endPosition = y() + rect.y() + usedBarHeight; + + p->save(); + + p->setPen(TQPen::NoPen); + p->setBrush(TQt::green); + p->drawRect(TQRect(x() + rect.x() + (pixmapRect().width() - horizontalOffset), y() + rect.y(), 1, usedBarHeight)); + p->setBrush(TQt::red); + p->drawRect(TQRect(x() + rect.x() + (pixmapRect().width() - horizontalOffset), endPosition, 1, pixmapRect().height() - usedBarHeight)); + + p->restore(); + } +} + +void KFileIVI::paintFontUpdate( TQPainter *p ) const +{ + if ( m_fileitem->isLink() ) + { + TQFont f( p->font() ); + f.setItalic( TRUE ); + p->setFont( f ); + } +} + +TQColorGroup KFileIVI::updateColors( const TQColorGroup &c ) const +{ + TQColorGroup cg( c ); + cg.setColor( TQColorGroup::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 TQIconViewItem::move( x, y ); +} + +bool KFileIVI::hasAnimation() const +{ + return !d->m_animatedIcon.isEmpty() && !m_bThumbnail; +} + +void KFileIVI::setMouseOverAnimation( const TQString& movieFileName ) +{ + if ( !movieFileName.isEmpty() ) + { + //kdDebug(1203) << "TDEIconViewItem::setMouseOverAnimation " << movieFileName << endl; + d->m_animatedIcon = movieFileName; + } +} + +TQString 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( TQIconViewItem *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 : + TDEGlobal::iconLoader()->currentSize( TDEIcon::Desktop ); + + KonqIconViewWidget* view = static_cast<KonqIconViewWidget*>( iconView() ); + + TQSize pixSize = TQSize( size, size ); + if ( pixSize != pixmapSize() ) { + setPixmapSize( pixSize ); + } +} + +/* vim: set noet sw=4 ts=8 softtabstop=4: */ diff --git a/libkonq/tdefileivi.h b/libkonq/tdefileivi.h new file mode 100644 index 000000000..243688d43 --- /dev/null +++ b/libkonq/tdefileivi.h @@ -0,0 +1,259 @@ +/* This file is part of the KDE project + Copyright (C) 1999, 2000, 2001, 2002 David Faure <[email protected]> + + 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 __tdefileivi_h__ +#define __tdefileivi_h__ + +#include <kiconview.h> +#include <kiconloader.h> +#include <libkonq_export.h> + +class KFileItem; +class KonqIconViewWidget; +class KIVDirectoryOverlay; +class KIVFreeSpaceOverlay; + +/** + * KFileIVI (short form of "Konq - File - IconViewItem") + * is, as expected, an improved TDEIconViewItem, because + * it represents a file. + * All the information about the file is contained in the KFileItem + * pointer. + */ +class LIBKONQ_EXPORT KFileIVI : public TDEIconViewItem +{ +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 TQIconView::acceptDrop() + */ + virtual bool acceptDrop( const TQMimeSource *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 TDEIcon) + * @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=TDEIcon::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 TQPixmap & 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 TDEIcon) + * @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 + * (TDEIcon::DefaultState, TDEIcon::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 TQPixmap & pixmap ); + + /** + * Set the icon to use the specified TDEIconEffect + * See the docs for TDEIconEffect 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(TQString::null) to remove icon. + */ + void setOverlay( const TQString & iconName); + + /** + * Sets a progress bar to be shown on the right side of the icon. + * Currently used for disk space overlays. + * setOverlayProgressBar(-1) to remove progress bar. + */ + void setOverlayProgressBar( const int progress); + + /** + * Redetermines the icon (useful if KFileItem might return another icon). + * Does nothing with thumbnails + */ + virtual void refreshIcon( bool redraw ); + + virtual void setKey( const TQString &key ); + + /** + * Paints this item. Takes care of using the normal or alpha + * blending methods depending on the configuration. + */ + virtual void paintItem( TQPainter *p, const TQColorGroup &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 TQString& movieFileName ); + TQString 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(TQString::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( ); + + /** + * Sets showing of free space overlays. Does nothing if this does + * not represent a media device. + */ + KIVFreeSpaceOverlay* setShowFreeSpaceOverlay( bool ); + bool showFreeSpaceOverlay( ); + + virtual int compare( TQIconViewItem *i ) const; + +protected: + virtual void dropped( TQDropEvent *e, const TQValueList<TQIconDragItem> & ); + + /** + * Contains the logic and code for painting the overlay pixmap. + */ + void paintOverlay( TQPainter *p ) const; + + /** + * Contains the logic and code for painting the overlay progress bar. + */ + void paintOverlayProgressBar( TQPainter *p ) const; + + /** + * Updates the colorgroup. + */ + TQColorGroup updateColors(const TQColorGroup &c) const; + + /** + * Contains the logic and code for painting links. + */ + void paintFontUpdate( TQPainter *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 TQPixmap & icon ) { TDEIconViewItem::setPixmap( icon ); } + virtual void setPixmap ( const TQPixmap & icon, bool recalc, bool redraw = TRUE ) + { TDEIconViewItem::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 tdefileivi.cc + */ + struct Private; + + Private *d; +}; + +#endif 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..965f1273d --- /dev/null +++ b/libkonq/tests/konqdragtest.cpp @@ -0,0 +1,62 @@ +/* This file is part of the KDE libraries + Copyright (c) 2005 David Faure <[email protected]> + + 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 <tqiconview.h> +#include <tdeapplication.h> +#include <tdecmdlineargs.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 ); + TQIconDragItem item; + iconDrag.append( item, TQRect( 1, 2, 3, 4 ), TQRect( 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[]) +{ + TDEApplication::disableAutoDcopRegistration(); + TDECmdLineArgs::init( argc, argv, "kurltest", 0, 0, 0, 0 ); + TDEApplication app; // GUI needed for QPixmaps + + testKonqIconDrag2(); + return 0; +} |