/* This file is part of the KDE project Copyright (C) 1998, 1999 Torben Weis <weis@kde.org> Copyright (C) 2000, 2001 David Faure <faure@kde.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. 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 "kdiconview.h" #include "krootwm.h" #include "desktop.h" #include "kdesktopsettings.h" #include <kio/paste.h> #include <kaccel.h> #include <kapplication.h> #include <kcolordrag.h> #include <kdebug.h> #include <kdesktopfile.h> #include <kdirlister.h> #include <kglobalsettings.h> #include <kpropertiesdialog.h> #include <klocale.h> #include <konqbookmarkmanager.h> #include <konq_defaults.h> #include <konq_drag.h> #include <konq_operations.h> #include <konq_popupmenu.h> #include <konq_settings.h> #include <konq_undo.h> #include <kprotocolinfo.h> #include <kstdaction.h> #include <kstandarddirs.h> #include <kurldrag.h> #include <twin.h> #include <twinmodule.h> #include <fixx11h.h> #include <tqclipboard.h> #include <tqdir.h> #include <tqevent.h> #include <tqregexp.h> #include <unistd.h> #include "kshadowengine.h" #include "kdesktopshadowsettings.h" #include "kfileividesktop.h" // for multihead extern int kdesktop_screen_number; // ----------------------------------------------------------------------------- TQRect KDIconView::desktopRect() { return ( kdesktop_screen_number == 0 ) ? TQApplication::desktop()->geometry() // simple case, or xinerama : TQApplication::desktop()->screenGeometry( kdesktop_screen_number ); // multi-head } // ----------------------------------------------------------------------------- void KDIconView::saveIconPosition(KSimpleConfig *config, int x, int y) { // save the icon position in absolute coordinates config->writeEntry("Xabs", x); config->writeEntry("Yabs", y); // save also mentioning desktop size TQRect desk = desktopRect(); TQString sizeStr = TQString( "_%1x%2" ).arg(desk.width()).arg(desk.height()); config->writeEntry("Xabs" + sizeStr, x); config->writeEntry("Yabs" + sizeStr, y); } // ----------------------------------------------------------------------------- void KDIconView::readIconPosition(KSimpleConfig *config, int &x, int &y) { // check if we have the position for the current desktop size TQRect desk = desktopRect(); TQString sizeStr = TQString( "_%1x%2" ).arg(desk.width()).arg(desk.height()); x = config->readNumEntry("Xabs" + sizeStr, -99999); if ( x != -99999 ) y = config->readNumEntry("Yabs" + sizeStr); else { // not found; use the resolution independent position x = config->readNumEntry("Xabs", -99999); if ( x != -99999 ) y = config->readNumEntry("Yabs"); else // for compatibility, read the old iconArea-relative-position { // problem here: when reading a position before we know the correct // desktopIconsArea, the relative position do not make sense // workaround: use desktopRect() as the allowed size TQRect desk = desktopRect(); TQString X_w = TQString("X %1").arg(desk.width() ); TQString Y_h = TQString("Y %1").arg(desk.height()); x = config->readNumEntry(X_w, -99999); if ( x != -99999 ) x = config->readNumEntry("X"); if ( x < 0 ) x += desk.width(); y = config->readNumEntry(Y_h, -99999); if ( y != -99999 ) y = config->readNumEntry("Y"); if ( y < 0 ) y += desk.height(); } } } // ----------------------------------------------------------------------------- KDIconView::KDIconView( TQWidget *parent, const char* name ) : KonqIconViewWidget( parent, name, (WFlags)WResizeNoErase, true ), m_actionCollection( this, "KDIconView::m_actionCollection" ), m_accel( 0L ), m_bNeedRepaint( false ), m_bNeedSave( false ), m_autoAlign( false ), m_hasExistingPos( false ), m_bEditableDesktopIcons( kapp->authorize("editable_desktop_icons") ), m_bShowDot( false ), m_bVertAlign( true ), m_dirLister( 0L ), m_mergeDirs(), m_dotDirectory( 0L ), m_lastDeletedIconPos(), m_eSortCriterion( NameCaseInsensitive ), m_bSortDirectoriesFirst( true ), m_itemsAlwaysFirst(), m_gotIconsArea(false), m_needDesktopAlign(true) { setResizeMode( Fixed ); setIconArea( desktopRect() ); // the default is the whole desktop // Initialise the shadow data objects... m_shadowEngine = new KShadowEngine(new KDesktopShadowSettings(KGlobal::config())); // Initialize media handler mMediaListView = new TQListView(); connect( TQApplication::clipboard(), TQT_SIGNAL(dataChanged()), this, TQT_SLOT(slotClipboardDataChanged()) ); setURL( desktopURL() ); // sets m_url m_desktopDirs = KGlobal::dirs()->findDirs( "appdata", "Desktop" ); initDotDirectories(); connect( this, TQT_SIGNAL( executed( TQIconViewItem * ) ), TQT_SLOT( slotExecuted( TQIconViewItem * ) ) ); connect( this, TQT_SIGNAL( returnPressed( TQIconViewItem * ) ), TQT_SLOT( slotReturnPressed( TQIconViewItem * ) ) ); connect( this, TQT_SIGNAL( mouseButtonPressed(int, TQIconViewItem*, const TQPoint&)), TQT_SLOT( slotMouseButtonPressed(int, TQIconViewItem*, const TQPoint&)) ); connect( this, TQT_SIGNAL( mouseButtonClicked(int, TQIconViewItem*, const TQPoint&)), TQT_SLOT( slotMouseButtonClickedKDesktop(int, TQIconViewItem*, const TQPoint&)) ); connect( this, TQT_SIGNAL( contextMenuRequested(TQIconViewItem*, const TQPoint&)), TQT_SLOT( slotContextMenuRequested(TQIconViewItem*, const TQPoint&)) ); connect( this, TQT_SIGNAL( enableAction( const char * , bool ) ), TQT_SLOT( slotEnableAction( const char * , bool ) ) ); // Hack: KonqIconViewWidget::slotItemRenamed is not virtual :-( disconnect( this, TQT_SIGNAL(itemRenamed(TQIconViewItem *, const TQString &)), this, TQT_SLOT(slotItemRenamed(TQIconViewItem *, const TQString &)) ); connect( this, TQT_SIGNAL(itemRenamed(TQIconViewItem *, const TQString &)), this, TQT_SLOT(slotItemRenamed(TQIconViewItem *, const TQString &)) ); if (!m_bEditableDesktopIcons) { setItemsMovable(false); setAcceptDrops(false); viewport()->setAcceptDrops(false); } } KDIconView::~KDIconView() { if (m_dotDirectory && !m_bEditableDesktopIcons) m_dotDirectory->rollback(false); // Don't save positions delete m_dotDirectory; delete m_dirLister; delete m_shadowEngine; } void KDIconView::initDotDirectories() { TQStringList dirs = m_desktopDirs; KURL u = desktopURL(); if (u.isLocalFile()) dirs.prepend(u.path()); TQString prefix = iconPositionGroupPrefix(); TQString dotFileName = locateLocal("appdata", "IconPositions"); if (kdesktop_screen_number != 0) dotFileName += "_Desktop" + TQString::number(kdesktop_screen_number); if (m_dotDirectory && !m_bEditableDesktopIcons) m_dotDirectory->rollback(false); // Don't save positions delete m_dotDirectory; m_dotDirectory = new KSimpleConfig( dotFileName ); // If we don't allow editable desktop icons, empty m_dotDirectory if (!m_bEditableDesktopIcons) { TQStringList groups = m_dotDirectory->groupList(); TQStringList::ConstIterator gIt = groups.begin(); TQStringList::ConstIterator gEnd = groups.end(); for (; gIt != gEnd; ++gIt ) { m_dotDirectory->deleteGroup(*gIt, true); } } TQRect desk = desktopRect(); TQString X_w = TQString( "X %1" ).arg( desk.width() ); TQString Y_h = TQString( "Y %1" ).arg( desk.height() ); for ( TQStringList::ConstIterator it = dirs.begin() ; it != dirs.end() ; ++it ) { kdDebug(1204) << "KDIconView::initDotDirectories found dir " << *it << endl; TQString localDotFileName = *it + "/.directory"; if (TQFile::exists(localDotFileName)) { KSimpleConfig dotDir(localDotFileName, true); // Read only TQStringList groups = dotDir.groupList(); TQStringList::ConstIterator gIt = groups.begin(); TQStringList::ConstIterator gEnd = groups.end(); for (; gIt != gEnd; ++gIt ) { if ( (*gIt).startsWith(prefix) ) { dotDir.setGroup( *gIt ); m_dotDirectory->setGroup( *gIt ); if (!m_dotDirectory->hasKey( X_w )) { int x,y; readIconPosition(&dotDir, x, y); m_dotDirectory->writeEntry( X_w, x ); m_dotDirectory->writeEntry( Y_h, y ); // Not persistant! } } } } } } void KDIconView::initConfig( bool init ) { //kdDebug() << "initConfig " << init << endl; if ( !init ) { KonqFMSettings::reparseConfiguration(); KDesktopSettings::self()->readConfig(); } KConfig * config = KGlobal::config(); if ( !init ) { KDesktopShadowSettings *shadowSettings = static_cast<KDesktopShadowSettings *>(m_shadowEngine->shadowSettings()); shadowSettings->setConfig(config); } setMaySetWallpaper(!config->isImmutable() && !KGlobal::dirs()->isRestrictedResource("wallpaper")); m_bShowDot = KDesktopSettings::showHidden(); m_bVertAlign = KDesktopSettings::vertAlign(); TQStringList oldPreview = previewSettings(); setPreviewSettings( KDesktopSettings::preview() ); // read arrange configuration m_eSortCriterion = (SortCriterion)KDesktopSettings::sortCriterion(); m_bSortDirectoriesFirst = KDesktopSettings::directoriesFirst(); m_itemsAlwaysFirst = KDesktopSettings::alwaysFirstItems(); // Distributor plug-in if (KProtocolInfo::isKnownProtocol(TQString::fromLatin1("media"))) m_enableMedia=KDesktopSettings::mediaEnabled(); else m_enableMedia=false; TQString tmpList=KDesktopSettings::exclude(); kdDebug(1204)<<"m_excludeList"<<tmpList<<endl; m_excludedMedia=TQStringList::split(",",tmpList,false); kdDebug(1204)<<" m_excludeList / item count:" <<m_excludedMedia.count()<<endl; if ( m_dirLister ) // only when called while running - not on first startup { configureMedia(); m_dirLister->setShowingDotFiles( m_bShowDot ); m_dirLister->emitChanges(); } setArrangement(m_bVertAlign ? TopToBottom : LeftToRight); if ( KonqIconViewWidget::initConfig( init ) ) lineupIcons(); // called if the font changed. setAutoArrange( false ); if ( previewSettings().count() ) { for ( TQStringList::ConstIterator it = oldPreview.begin(); it != oldPreview.end(); ++it) if ( !previewSettings().contains( *it ) ){ kdDebug(1204) << "Disabling preview for " << *it << endl; if ( *it == "audio/" ) disableSoundPreviews(); else { KService::Ptr serv = KService::serviceByDesktopName( *it ); Q_ASSERT( serv != 0L ); if ( serv ) { setIcons( iconSize( ), serv->property("MimeTypes").toStringList() /* revert no-longer wanted previews to icons */ ); } } } startImagePreview( TQStringList(), true ); } else { stopImagePreview(); setIcons( iconSize(), "*" /* stopImagePreview */ ); } if ( !init ) updateContents(); } void KDIconView::start() { // We can only start once Q_ASSERT(!m_dirLister); if (m_dirLister) return; kdDebug(1204) << "KDIconView::start" << endl; // Create the directory lister m_dirLister = new KDirLister(); m_bNeedSave = false; connect( m_dirLister, TQT_SIGNAL( clear() ), this, TQT_SLOT( slotClear() ) ); connect( m_dirLister, TQT_SIGNAL( started(const KURL&) ), this, TQT_SLOT( slotStarted(const KURL&) ) ); connect( m_dirLister, TQT_SIGNAL( completed() ), this, TQT_SLOT( slotCompleted() ) ); connect( m_dirLister, TQT_SIGNAL( newItems( const KFileItemList & ) ), this, TQT_SLOT( slotNewItems( const KFileItemList & ) ) ); connect( m_dirLister, TQT_SIGNAL( deleteItem( KFileItem * ) ), this, TQT_SLOT( slotDeleteItem( KFileItem * ) ) ); connect( m_dirLister, TQT_SIGNAL( refreshItems( const KFileItemList & ) ), this, TQT_SLOT( slotRefreshItems( const KFileItemList & ) ) ); // Start the directory lister ! m_dirLister->setShowingDotFiles( m_bShowDot ); kapp->allowURLAction("list", KURL(), url()); startDirLister(); createActions(); } void KDIconView::configureMedia() { kdDebug(1204) << "***********KDIconView::configureMedia() " <<endl; m_dirLister->setMimeExcludeFilter(m_excludedMedia); m_dirLister->emitChanges(); updateContents(); if (m_enableMedia) { for (KURL::List::Iterator it1=m_mergeDirs.begin();it1!=m_mergeDirs.end();++it1) { if ((*it1).url()=="media:/") return; } m_mergeDirs.append(KURL("media:/")); m_dirLister->openURL(KURL("media:/"),true); } else { for (KURL::List::Iterator it2=m_mergeDirs.begin();it2!=m_mergeDirs.end();++it2) { if ((*it2).url()=="media:/") { delete m_dirLister; m_dirLister=0; start(); // m_mergeDirs.remove(it2); // m_dirLister->stop("media"); return; } } return; } } void KDIconView::createActions() { if (m_bEditableDesktopIcons) { KAction *undo = KStdAction::undo( KonqUndoManager::self(), TQT_SLOT( undo() ), &m_actionCollection, "undo" ); connect( KonqUndoManager::self(), TQT_SIGNAL( undoAvailable( bool ) ), undo, TQT_SLOT( setEnabled( bool ) ) ); connect( KonqUndoManager::self(), TQT_SIGNAL( undoTextChanged( const TQString & ) ), undo, TQT_SLOT( setText( const TQString & ) ) ); undo->setEnabled( KonqUndoManager::self()->undoAvailable() ); KAction* paCut = KStdAction::cut( TQT_TQOBJECT(this), TQT_SLOT( slotCut() ), &m_actionCollection, "cut" ); KShortcut cutShortCut = paCut->shortcut(); cutShortCut.remove( KKey( SHIFT + Key_Delete ) ); // used for deleting files paCut->setShortcut( cutShortCut ); KStdAction::copy( TQT_TQOBJECT(this), TQT_SLOT( slotCopy() ), &m_actionCollection, "copy" ); KStdAction::paste( TQT_TQOBJECT(this), TQT_SLOT( slotPaste() ), &m_actionCollection, "paste" ); KAction *pasteTo = KStdAction::paste( TQT_TQOBJECT(this), TQT_SLOT( slotPopupPasteTo() ), &m_actionCollection, "pasteto" ); pasteTo->setEnabled( false ); // only enabled during popupMenu() KShortcut reloadShortcut = KStdAccel::shortcut(KStdAccel::Reload); new KAction( i18n( "&Reload" ), "reload", reloadShortcut, TQT_TQOBJECT(this), TQT_SLOT( refreshIcons() ), &m_actionCollection, "reload" ); (void) new KAction( i18n( "&Rename" ), /*"editrename",*/ Key_F2, TQT_TQOBJECT(this), TQT_SLOT( renameSelectedItem() ), &m_actionCollection, "rename" ); (void) new KAction( i18n( "&Properties" ), ALT+Key_Return, TQT_TQOBJECT(this), TQT_SLOT( slotProperties() ), &m_actionCollection, "properties" ); KAction* trash = new KAction( i18n( "&Move to Trash" ), "edittrash", Key_Delete, &m_actionCollection, "trash" ); connect( trash, TQT_SIGNAL( activated( KAction::ActivationReason, TQt::ButtonState ) ), this, TQT_SLOT( slotTrashActivated( KAction::ActivationReason, TQt::ButtonState ) ) ); KConfig config("kdeglobals", true, false); config.setGroup( "KDE" ); (void) new KAction( i18n( "&Delete" ), "editdelete", SHIFT+Key_Delete, TQT_TQOBJECT(this), TQT_SLOT( slotDelete() ), &m_actionCollection, "del" ); // Initial state of the actions (cut/copy/paste/...) slotSelectionChanged(); //init paste action slotClipboardDataChanged(); } } void KDIconView::rearrangeIcons( SortCriterion sc, bool bSortDirectoriesFirst ) { m_eSortCriterion = sc; m_bSortDirectoriesFirst = bSortDirectoriesFirst; rearrangeIcons(); } void KDIconView::rearrangeIcons() { setupSortKeys(); sort(); // calls arrangeItemsInGrid() which does not honor iconArea() if ( m_autoAlign ) lineupIcons( m_bVertAlign ? TQIconView::TopToBottom : TQIconView::LeftToRight ); // also saves position else { KonqIconViewWidget::lineupIcons(m_bVertAlign ? TQIconView::TopToBottom : TQIconView::LeftToRight); saveIconPositions(); } } void KDIconView::lineupIcons() { if ( !m_gotIconsArea ) return; KonqIconViewWidget::lineupIcons(); saveIconPositions(); } void KDIconView::setAutoAlign( bool b ) { m_autoAlign = b; // Auto line-up icons if ( b ) { if (!KRootWm::self()->startup) lineupIcons(); else KRootWm::self()->startup = false; connect( this, TQT_SIGNAL( iconMoved() ), this, TQT_SLOT( lineupIcons() ) ); } else { // change maxItemWidth, because when grid-align was active, it changed this for the grid int sz = iconSize() ? iconSize() : KGlobal::iconLoader()->currentSize( KIcon::Desktop ); setMaxItemWidth( QMAX( QMAX( sz, previewIconSize( iconSize() ) ), KonqFMSettings::settings()->iconTextWidth() ) ); setFont( font() ); // Force calcRect() disconnect( this, TQT_SIGNAL( iconMoved() ), this, TQT_SLOT( lineupIcons() ) ); } } void KDIconView::startDirLister() { // if desktop is resized before start() is called (XRandr) if (!m_dirLister) return; m_dirLister->openURL( url() ); // Gather the list of directories to merge into the desktop // (the main URL is desktopURL(), no need for it in the m_mergeDirs list) m_mergeDirs.clear(); for ( TQStringList::ConstIterator it = m_desktopDirs.begin() ; it != m_desktopDirs.end() ; ++it ) { kdDebug(1204) << "KDIconView::desktopResized found merge dir " << *it << endl; KURL u; u.setPath( *it ); m_mergeDirs.append( u ); // And start listing this dir right now kapp->allowURLAction("list", KURL(), u); m_dirLister->openURL( u, true ); } configureMedia(); } void KDIconView::lineupIcons(TQIconView::Arrangement align) { m_bVertAlign = ( align == TQIconView::TopToBottom ); setArrangement( m_bVertAlign ? TopToBottom : LeftToRight ); if ( m_autoAlign ) { KonqIconViewWidget::lineupIcons( align ); saveIconPositions(); } else rearrangeIcons(); // also saves the position KDesktopSettings::setVertAlign( m_bVertAlign ); KDesktopSettings::writeConfig(); } // Only used for DCOP TQStringList KDIconView::selectedURLs() { TQStringList seq; TQIconViewItem *it = firstItem(); for (; it; it = it->nextItem() ) if ( it->isSelected() ) { KFileItem *fItem = ((KFileIVI *)it)->item(); seq.append( fItem->url().url() ); // copy the URL } return seq; } void KDIconView::recheckDesktopURL() { // Did someone change the path to the desktop ? kdDebug(1204) << desktopURL().url() << endl; kdDebug(1204) << url().url() << endl; if ( desktopURL() != url() ) { kdDebug(1204) << "Desktop path changed from " << url().url() << " to " << desktopURL().url() << endl; setURL( desktopURL() ); // sets m_url initDotDirectories(); m_dirLister->openURL( url() ); } } KURL KDIconView::desktopURL() { // Support both paths and URLs TQString desktopPath = KGlobalSettings::desktopPath(); if (kdesktop_screen_number != 0) { TQString dn = "Desktop"; dn += TQString::number(kdesktop_screen_number); desktopPath.replace("Desktop", dn); } KURL desktopURL; if (desktopPath[0] == '/') desktopURL.setPath(desktopPath); else desktopURL = desktopPath; Q_ASSERT( desktopURL.isValid() ); if ( !desktopURL.isValid() ) { // should never happen KURL u; u.setPath( TQDir::homeDirPath() + "/" + "Desktop" + "/" ); return u; } return desktopURL; } void KDIconView::contentsMousePressEvent( TQMouseEvent *e ) { if (!m_dirLister) return; //kdDebug(1204) << "KDIconView::contentsMousePressEvent" << endl; // TQIconView, as of Qt 2.2, doesn't emit mouseButtonPressed for LMB on background if ( e->button() == Qt::LeftButton && KRootWm::self()->hasLeftButtonMenu() ) { TQIconViewItem *item = findItem( e->pos() ); if ( !item ) { // Left click menu KRootWm::self()->mousePressed( e->globalPos(), e->button() ); return; } } KonqIconViewWidget::contentsMousePressEvent( e ); } void KDIconView::mousePressEvent( TQMouseEvent *e ) { KRootWm::self()->mousePressed( e->globalPos(), e->button() ); } void KDIconView::wheelEvent( TQWheelEvent* e ) { if (!m_dirLister) return; //kdDebug(1204) << "KDIconView::wheelEvent" << endl; TQIconViewItem *item = findItem( e->pos() ); if ( !item ) { emit wheelRolled( e->delta() ); return; } KonqIconViewWidget::wheelEvent( e ); } void KDIconView::slotProperties() { KFileItemList selectedFiles = selectedFileItems(); if( selectedFiles.isEmpty() ) return; (void) new KPropertiesDialog( selectedFiles ); } void KDIconView::slotContextMenuRequested(TQIconViewItem *_item, const TQPoint& _global) { if (_item) { ((KFileIVI*)_item)->setSelected( true ); popupMenu( _global, selectedFileItems() ); } } void KDIconView::slotMouseButtonPressed(int _button, TQIconViewItem* _item, const TQPoint& _global) { //kdDebug(1204) << "KDIconView::slotMouseButtonPressed" << endl; if (!m_dirLister) return; m_lastDeletedIconPos = TQPoint(); // user action -> not renaming an icon if(!_item) KRootWm::self()->mousePressed( _global, _button ); } void KDIconView::slotMouseButtonClickedKDesktop(int _button, TQIconViewItem* _item, const TQPoint&) { if (!m_dirLister) return; //kdDebug(1204) << "KDIconView::slotMouseButtonClickedKDesktop" << endl; if ( _item && _button == Qt::MidButton ) slotExecuted(_item); } // ----------------------------------------------------------------------------- void KDIconView::slotReturnPressed( TQIconViewItem *item ) { if (item && item->isSelected()) slotExecuted(item); } // ----------------------------------------------------------------------------- void KDIconView::slotExecuted( TQIconViewItem *item ) { kapp->propagateSessionManager(); m_lastDeletedIconPos = TQPoint(); // user action -> not renaming an icon if (item) { visualActivate(item); ((KFileIVI*)item)->returnPressed(); } } // ----------------------------------------------------------------------------- void KDIconView::slotCut() { cutSelection(); } // ----------------------------------------------------------------------------- void KDIconView::slotCopy() { copySelection(); } // ----------------------------------------------------------------------------- void KDIconView::slotPaste() { KonqOperations::doPaste(this, url(), KRootWm::self()->desktopMenuPosition()); } void KDIconView::slotPopupPasteTo() { Q_ASSERT( !m_popupURL.isEmpty() ); if ( !m_popupURL.isEmpty() ) paste( m_popupURL ); } // These two functions and the following class are all lifted from desktopbehavior_impl.cpp to handle the media icons class DesktopBehaviorMediaItem : public TQCheckListItem { public: DesktopBehaviorMediaItem(TQListView *parent, const TQString name, const TQString mimetype, bool on) : TQCheckListItem(parent, name, CheckBox), m_mimeType(mimetype){setOn(on);} const TQString &mimeType() const { return m_mimeType; } private: TQString m_mimeType; }; void KDIconView::fillMediaListView() { g_pConfig = new KConfig("kdesktoprc"); mMediaListView->hide(); mMediaListView->clear(); KMimeType::List mimetypes = KMimeType::allMimeTypes(); TQValueListIterator<KMimeType::Ptr> it2(mimetypes.begin()); g_pConfig->setGroup( "Media" ); TQString excludedMedia=g_pConfig->readEntry("exclude","media/hdd_mounted,media/hdd_unmounted,media/floppy_unmounted,media/cdrom_unmounted,media/floppy5_unmounted"); for (; it2 != mimetypes.end(); ++it2) { if ( ((*it2)->name().startsWith("media/")) ) { bool ok=excludedMedia.contains((*it2)->name())==0; new DesktopBehaviorMediaItem (mMediaListView, (*it2)->comment(), (*it2)->name(),ok); } } delete g_pConfig; } void KDIconView::saveMediaListView() { g_pConfig = new KConfig("kdesktoprc"); g_pConfig->setGroup( "Media" ); TQStringList exclude; for (DesktopBehaviorMediaItem *it=static_cast<DesktopBehaviorMediaItem *>(mMediaListView->firstChild()); it; it=static_cast<DesktopBehaviorMediaItem *>(it->nextSibling())) { if (!it->isOn()) exclude << it->mimeType(); } g_pConfig->writeEntry("exclude",exclude); g_pConfig->sync(); // Reload kdesktop configuration to apply changes TQByteArray data; int konq_screen_number = KApplication::desktop()->primaryScreen(); TQCString appname; if (konq_screen_number == 0) appname = "kdesktop"; else appname.sprintf("kdesktop-screen-%d", konq_screen_number); kapp->dcopClient()->send( appname, "KDesktopIface", "configure()", data ); delete g_pConfig; } void KDIconView::removeBuiltinIcon(TQString iconName) { DesktopBehaviorMediaItem *changeItem; fillMediaListView(); changeItem = static_cast<DesktopBehaviorMediaItem *>(mMediaListView->findItem(iconName, 0)); if (changeItem != 0) { changeItem->setOn(false); } saveMediaListView(); KMessageBox::information(0, i18n("You have chosen to remove a system icon") + TQString(".\n") + i18n("You can restore this icon in the future through the") + TQString(" \"") + ("Device Icons") + TQString("\" ") + i18n("tab in the") + TQString(" \"") + i18n("Behavior") + TQString("\" ") + i18n("pane of the Desktop Settings control module."), "System Icon Removed", "sysiconremovedwarning"); } /** * The files on the desktop come from a variety of sources. * If an attempt is made to delete a .desktop file that does * not originate from the users own Desktop directory then * a .desktop file with "Hidden=true" is written to the users * own Desktop directory to hide the file. * * Returns true if all selected items have been deleted. * Returns false if there are selected items remaining that * still need to be deleted in a regular fashion. */ bool KDIconView::deleteGlobalDesktopFiles() { KURL desktop_URL = desktopURL(); if (!desktop_URL.isLocalFile()) return false; // Dunno how to do this. TQString desktopPath = desktop_URL.path(); bool itemsLeft = false; TQIconViewItem *it = 0; TQIconViewItem *nextIt = firstItem(); for (; (it = nextIt); ) { nextIt = it->nextItem(); if ( !it->isSelected() ) continue; KFileItem *fItem = ((KFileIVI *)it)->item(); if (fItem->url().path().startsWith(desktopPath)) { itemsLeft = true; continue; // File is in users own Desktop directory } if (!isDesktopFile(fItem)) { itemsLeft = true; continue; // Not a .desktop file } // Ignore these special files // Name URL Type OnlyShowIn // My Documents kxdglauncher --xdgname DOCUMENTS Application KDE; // My Computer media:/ Link KDE; // My Network Places remote:/ Link KDE; // Printers [exec] kjobviewer --all --show %i %m Application KDE; // Trash trash:/ Link KDE; // Web Browser kfmclient openBrowser %u Application KDE; if ( isDesktopFile(fItem) ) { KSimpleConfig cfg( fItem->url().path(), true ); cfg.setDesktopGroup(); if ( cfg.readEntry( "X-Trinity-BuiltIn" ) == "true" ) { removeBuiltinIcon(cfg.readEntry( "Name" )); continue; } } KDesktopFile df(desktopPath + fItem->url().fileName()); df.writeEntry("Hidden", true); df.sync(); delete it; } return !itemsLeft; } void KDIconView::slotTrashActivated( KAction::ActivationReason reason, TQt::ButtonState state ) { if (deleteGlobalDesktopFiles()) return; // All items deleted if ( reason == KAction::PopupMenuActivation && ( state & TQt::ShiftButton ) ) KonqOperations::del(this, KonqOperations::DEL, selectedUrls()); else KonqOperations::del(this, KonqOperations::TRASH, selectedUrls()); } void KDIconView::slotDelete() { if (deleteGlobalDesktopFiles()) return; // All items deleted KonqOperations::del(this, KonqOperations::DEL, selectedUrls()); } // ----------------------------------------------------------------------------- // This method is called when right-clicking over one or more items // Not to be confused with the global popup-menu, KRootWm, when doing RMB on the desktop void KDIconView::popupMenu( const TQPoint &_global, const KFileItemList& _items ) { if (!kapp->authorize("action/kdesktop_rmb")) return; if (!m_dirLister) return; if ( _items.count() == 1 ) m_popupURL = _items.getFirst()->url(); KAction* pasteTo = m_actionCollection.action( "pasteto" ); if (pasteTo) pasteTo->setEnabled( m_actionCollection.action( "paste" )->isEnabled() ); bool hasMediaFiles = false; KFileItemListIterator it(_items); for (; it.current() && !hasMediaFiles; ++it) { hasMediaFiles = it.current()->url().protocol() == "media"; } KParts::BrowserExtension::PopupFlags itemFlags = KParts::BrowserExtension::DefaultPopupItems; if ( hasMediaFiles ) itemFlags |= KParts::BrowserExtension::NoDeletion; KonqPopupMenu * popupMenu = new KonqPopupMenu( KonqBookmarkManager::self(), _items, url(), m_actionCollection, KRootWm::self()->newMenu(), this, KonqPopupMenu::ShowProperties | KonqPopupMenu::ShowNewWindow, itemFlags ); popupMenu->exec( _global ); delete popupMenu; m_popupURL = KURL(); if (pasteTo) pasteTo->setEnabled( false ); } void KDIconView::slotNewMenuActivated() { //kdDebug(1204) << "KDIconView::slotNewMenuActivated" << endl; // New / <template> was chosen, a new file is going to appear soon, // make it appear at the position of the popupmenu. m_nextItemPos = KRootWm::self()->desktopMenuPosition(); } // ----------------------------------------------------------------------------- void KDIconView::slotEnableAction( const char * name, bool enabled ) { //kdDebug(1204) << "slotEnableAction " << name << " enabled=" << enabled << endl; TQCString sName( name ); // No such actions here... konqpopupmenu provides them. if ( sName == "properties" || sName == "editMimeType" ) return; KAction * act = m_actionCollection.action( sName.data() ); if (act) act->setEnabled( enabled ); } // ----------------------------------------------------------------------------- // Straight from kpropsdlg :) bool KDIconView::isDesktopFile( KFileItem * _item ) const { // only local files if ( !_item->isLocalFile() ) return false; // only regular files if ( !S_ISREG( _item->mode() ) ) return false; TQString t( _item->url().path() ); // only if readable if ( access( TQFile::encodeName(t), R_OK ) != 0 ) return false; // return true if desktop file return ( (_item->mimetype() == TQString::fromLatin1("application/x-desktop")) || (_item->mimetype() == TQString::fromLatin1("media/builtin-mydocuments")) || (_item->mimetype() == TQString::fromLatin1("media/builtin-mycomputer")) || (_item->mimetype() == TQString::fromLatin1("media/builtin-mynetworkplaces")) || (_item->mimetype() == TQString::fromLatin1("media/builtin-printers")) || (_item->mimetype() == TQString::fromLatin1("media/builtin-trash")) || (_item->mimetype() == TQString::fromLatin1("media/builtin-webbrowser")) ); } TQString KDIconView::stripDesktopExtension( const TQString & text ) { if (text.right(7) == TQString::fromLatin1(".kdelnk")) return text.left(text.length() - 7); else if (text.right(8) == TQString::fromLatin1(".desktop")) return text.left(text.length() - 8); return text; } bool KDIconView::makeFriendlyText( KFileIVI *fileIVI ) { KFileItem *item = fileIVI->item(); TQString desktopFile; if ( item->isDir() && item->isLocalFile() ) { KURL u( item->url() ); u.addPath( ".directory" ); // using KStandardDirs as this one checks for path being // a file instead of a directory if ( KStandardDirs::exists( u.path() ) ) desktopFile = u.path(); } else if ( isDesktopFile( item ) ) { desktopFile = item->url().path(); } if ( !desktopFile.isEmpty() ) { KSimpleConfig cfg( desktopFile, true ); cfg.setDesktopGroup(); if (cfg.readBoolEntry("Hidden")) return false; if (cfg.readBoolEntry( "NoDisplay", false )) return false; TQStringList tmpList; if (cfg.hasKey("OnlyShowIn")) { if (!cfg.readListEntry("OnlyShowIn", ';').contains("KDE")) return false; } if (cfg.hasKey("NotShowIn")) { if (cfg.readListEntry("NotShowIn", ';').contains("KDE")) return false; } if (cfg.hasKey("TryExec")) { if (KStandardDirs::findExe( cfg.readEntry( "TryExec" ) ).isEmpty()) return false; } TQString name = cfg.readEntry("Name"); if ( !name.isEmpty() ) fileIVI->setText( name ); else // For compatibility fileIVI->setText( stripDesktopExtension( fileIVI->text() ) ); } return true; } // ----------------------------------------------------------------------------- void KDIconView::slotClear() { clear(); } // ----------------------------------------------------------------------------- void KDIconView::slotNewItems( const KFileItemList & entries ) { bool firstRun = (count() == 0); // no icons yet, this seems to be the initial loading // delay updates until all new items have been created setUpdatesEnabled( false ); TQRect area = iconArea(); setIconArea( TQRect( 0, 0, -1, -1 ) ); TQString desktopPath; KURL desktop_URL = desktopURL(); if (desktop_URL.isLocalFile()) desktopPath = desktop_URL.path(); // We have new items, so we'll need to repaint in slotCompleted m_bNeedRepaint = true; kdDebug(1214) << "KDIconView::slotNewItems count=" << entries.count() << endl; KFileItemListIterator it(entries); KFileIVI* fileIVI = 0L; // Ensure that the saved positions had a chance to be loaded if (!m_dotDirectory) { initDotDirectories(); } if (m_nextItemPos.isNull() && !m_dotDirectory) { // Not found, we'll need to save the new pos kdDebug(1214)<<"Neither a drop position stored nor m_dotDirectory set"<<endl; m_dotDirectory = new KSimpleConfig( dotDirectoryPath(), true ); // recursion slotNewItems( entries ); delete m_dotDirectory; m_dotDirectory = 0; return; } for (; it.current(); ++it) { KURL url = it.current()->url(); if (!desktopPath.isEmpty() && url.isLocalFile() && !url.path().startsWith(desktopPath)) { TQString fileName = url.fileName(); if (TQFile::exists(desktopPath + fileName)) continue; // Don't duplicate entry TQString mostLocal = locate("appdata", "Desktop/"+fileName); if (!mostLocal.isEmpty() && (mostLocal != url.path())) continue; // Don't duplicate entry } // No delayed mimetype determination on the desktop it.current()->determineMimeType(); fileIVI = new KFileIVIDesktop( this, it.current(), iconSize(), m_shadowEngine ); if (!makeFriendlyText( fileIVI )) { delete fileIVI; continue; } kdDebug(1214) << " slotNewItems: " << url.url() << " text: " << fileIVI->text() << endl; fileIVI->setRenameEnabled( false ); if ( !m_nextItemPos.isNull() ) // position remembered from e.g. RMB-popupmenu position, when doing New/... { kdDebug(1214) << "slotNewItems : using popupmenu position " << m_nextItemPos.x() << "," << m_nextItemPos.y() << endl; fileIVI->move( m_nextItemPos.x(), m_nextItemPos.y() ); m_nextItemPos = TQPoint(); } else { kdDebug(1214) << "slotNewItems : trying to read position from .directory file"<<endl; TQString group = iconPositionGroupPrefix(); TQString filename = url.fileName(); if ( filename.endsWith(".part") && !m_dotDirectory->hasGroup( group + filename ) ) filename = filename.left( filename.length() - 5 ); group.append( filename ); kdDebug(1214) << "slotNewItems : looking for group " << group << endl; if ( m_dotDirectory->hasGroup( group ) ) { m_dotDirectory->setGroup( group ); m_hasExistingPos = true; int x,y; readIconPosition(m_dotDirectory, x, y); kdDebug(1214)<<"slotNewItems() x: "<<x<<" y: "<<y<<endl; TQRect oldPos = fileIVI->rect(); fileIVI->move( x, y ); if ( (!firstRun) && (!isFreePosition( fileIVI )) && (!m_needDesktopAlign) ) // if we can't put it there, then let TQIconView decide { kdDebug(1214)<<"slotNewItems() pos was not free :-("<<endl; fileIVI->move( oldPos.x(), oldPos.y() ); m_dotDirectory->deleteGroup( group ); m_bNeedSave = true; } else { kdDebug(1214)<<"Using saved position"<<endl; } } } } setIconArea( area ); // align on grid if ( m_autoAlign ) lineupIcons(); setUpdatesEnabled( true ); } // ----------------------------------------------------------------------------- // see also KonqKfmIconView::slotRefreshItems void KDIconView::slotRefreshItems( const KFileItemList & entries ) { kdDebug(1204) << "KDIconView::slotRefreshItems" << endl; bool bNeedPreviewJob = false; KFileItemListIterator rit(entries); for (; rit.current(); ++rit) { bool found = false; TQIconViewItem *it = firstItem(); for ( ; it ; it = it->nextItem() ) { KFileIVI * fileIVI = static_cast<KFileIVI *>(it); if ( fileIVI->item() == rit.current() ) // compare the pointers { kdDebug(1204) << "KDIconView::slotRefreshItems refreshing icon " << fileIVI->item()->url().url() << endl; found = true; fileIVI->setText( rit.current()->text() ); if (!makeFriendlyText( fileIVI )) { delete fileIVI; break; } if ( fileIVI->isThumbnail() ) { bNeedPreviewJob = true; fileIVI->invalidateThumbnail(); } else fileIVI->refreshIcon( true ); if ( rit.current()->isMimeTypeKnown() ) fileIVI->setMouseOverAnimation( rit.current()->iconName() ); break; } } if ( !found ) kdDebug(1204) << "Item not found: " << rit.current()->url().url() << endl; } if ( bNeedPreviewJob && previewSettings().count() ) { startImagePreview( TQStringList(), false ); } else { // In case we replace a big icon with a small one, need to repaint. updateContents(); // Can't do that with m_bNeedRepaint since slotCompleted isn't called m_bNeedRepaint = false; } } void KDIconView::refreshIcons() { TQIconViewItem *it = firstItem(); for ( ; it ; it = it->nextItem() ) { KFileIVI * fileIVI = static_cast<KFileIVI *>(it); fileIVI->item()->refresh(); fileIVI->refreshIcon( true ); makeFriendlyText( fileIVI ); } } void KDIconView::FilesAdded( const KURL & directory ) { if ( directory.path().length() <= 1 && directory.protocol() == "trash" ) refreshTrashIcon(); } void KDIconView::FilesRemoved( const KURL::List & fileList ) { if ( !fileList.isEmpty() ) { const KURL url = fileList.first(); if ( url.protocol() == "trash" ) refreshTrashIcon(); } } void KDIconView::refreshTrashIcon() { TQIconViewItem *it = firstItem(); for ( ; it ; it = it->nextItem() ) { KFileIVI * fileIVI = static_cast<KFileIVI *>(it); KFileItem* item = fileIVI->item(); if ( isDesktopFile( item ) ) { KSimpleConfig cfg( item->url().path(), true ); cfg.setDesktopGroup(); if ( cfg.readEntry( "Type" ) == "Link" && cfg.readEntry( "URL" ) == "trash:/" ) { fileIVI->refreshIcon( true ); } } } } // ----------------------------------------------------------------------------- void KDIconView::slotDeleteItem( KFileItem * _fileitem ) { kdDebug(1204) << "KDIconView::slotDeleteItems" << endl; // we need to find out the KFileIVI containing the fileitem TQIconViewItem *it = firstItem(); while ( it ) { KFileIVI * fileIVI = static_cast<KFileIVI *>(it); if ( fileIVI->item() == _fileitem ) { // compare the pointers // Delete this item. //kdDebug(1204) << fileIVI->text() << endl; TQString group = iconPositionGroupPrefix(); group.append( fileIVI->item()->url().fileName() ); if ( m_dotDirectory->hasGroup( group ) ) m_dotDirectory->deleteGroup( group ); m_lastDeletedIconPos = fileIVI->pos(); delete fileIVI; break; } it = it->nextItem(); } m_bNeedRepaint = true; } // ----------------------------------------------------------------------------- void KDIconView::slotStarted( const KURL& _url ) { kdDebug(1204) << "KDIconView::slotStarted url: " << _url.url() << " url().url(): "<<url().url()<<endl; } void KDIconView::slotCompleted() { // Root item ? Store in konqiconviewwidget (used for drops onto the background, for instance) if ( m_dirLister->rootItem() ) setRootItem( m_dirLister->rootItem() ); if ( previewSettings().count() ) startImagePreview( TQStringList(), true ); else { stopImagePreview(); setIcons( iconSize(), "*" /* stopImagePreview */ ); } // during first run need to rearrange all icons so default config settings will be used kdDebug(1204)<<"slotCompleted() m_hasExistingPos: "<<(m_hasExistingPos?(int)1:(int)0)<<endl; if (!m_hasExistingPos) rearrangeIcons(); // kdDebug(1204) << "KDIconView::slotCompleted save:" << m_bNeedSave << " repaint:" << m_bNeedRepaint << endl; if ( m_bNeedSave ) { // Done here because we want to align icons only once initially, and each time new icons appear. // This MUST precede the call to saveIconPositions(). emit iconMoved(); saveIconPositions(); m_hasExistingPos = true; // if we didn't have positions, we have now. m_bNeedSave = false; } if ( m_bNeedRepaint ) { viewport()->repaint(); m_bNeedRepaint = false; } } void KDIconView::slotClipboardDataChanged() { // This is very related to KonqDirPart::slotClipboardDataChanged KURL::List lst; TQMimeSource *data = TQApplication::clipboard()->data(); if ( data->provides( "application/x-kde-cutselection" ) && data->provides( "text/uri-list" ) ) if ( KonqDrag::decodeIsCutSelection( data ) ) (void) KURLDrag::decode( data, lst ); disableIcons( lst ); TQString actionText = KIO::pasteActionText(); bool paste = !actionText.isEmpty(); if ( paste ) { KAction* pasteAction = m_actionCollection.action( "paste" ); if ( pasteAction ) pasteAction->setText( actionText ); } slotEnableAction( "paste", paste ); } void KDIconView::renameDesktopFile(const TQString &path, const TQString &name) { KDesktopFile cfg( path, false ); // if we don't have the desktop entry group, then we assume that // it's not a config file (and we don't nuke it!) if ( !cfg.hasGroup( "Desktop Entry" ) ) return; if ( cfg.readName() == name ) return; cfg.writeEntry( "Name", name, true, false, false ); cfg.writeEntry( "Name", name, true, false, true ); cfg.sync(); } void KDIconView::slotItemRenamed(TQIconViewItem* _item, const TQString &name) { kdDebug(1204) << "KDIconView::slotItemRenamed(item, \"" << name << "\" )" << endl; TQString newName(name); if ( _item) { KFileIVI *fileItem = static_cast< KFileIVI* >( _item ); //save position of item renamed m_lastDeletedIconPos = fileItem->pos(); if ( fileItem->item() && !fileItem->item()->isLink() ) { TQString desktopFile( fileItem->item()->url().path() ); if (!desktopFile.isEmpty()) { // first and foremost, we make sure that this is a .desktop file // before we write anything to it KMimeType::Ptr type = KMimeType::findByURL( fileItem->item()->url() ); bool bDesktopFile = false; if ( (type->name() == "application/x-desktop") || (type->name() == "media/builtin-mydocuments") || (type->name() == "media/builtin-mycomputer") || (type->name() == "media/builtin-mynetworkplaces") || (type->name() == "media/builtin-printers") || (type->name() == "media/builtin-trash") || (type->name() == "media/builtin-webbrowser") ) { bDesktopFile = true; if (!newName.endsWith(".desktop")) newName += ".desktop"; } else if(type->name() == "inode/directory") { desktopFile += "/.directory"; bDesktopFile = true; } if (TQFile(desktopFile).exists() && bDesktopFile) { renameDesktopFile(desktopFile, name); return; } } } } KonqIconViewWidget::slotItemRenamed(_item, newName); } void KDIconView::slotAboutToCreate(const TQPoint &pos, const TQValueList<KIO::CopyInfo> &files) { if (pos.isNull()) return; if (m_dropPos != pos) { m_dropPos = pos; m_lastDropPos = pos; } TQString dir = url().path(-1); // Strip trailing / TQValueList<KIO::CopyInfo>::ConstIterator it = files.begin(); int gridX = gridXValue(); int gridY = 120; // 120 pixels should be enough for everyone (tm) for ( ; it!= files.end() ; ++it ) { kdDebug(1214) << "KDIconView::saveFuturePosition x=" << m_lastDropPos.x() << " y=" << m_lastDropPos.y() << " filename=" << (*it).uDest.prettyURL() << endl; if ((*it).uDest.isLocalFile() && ((*it).uDest.directory() == dir)) { m_dotDirectory->setGroup( iconPositionGroupPrefix() + (*it).uDest.fileName() ); saveIconPosition(m_dotDirectory, m_lastDropPos.x(), m_lastDropPos.y()); int dX = m_lastDropPos.x() - m_dropPos.x(); int dY = m_lastDropPos.y() - m_dropPos.y(); if ((QABS(dX) > QABS(dY)) || (m_lastDropPos.x() + 2*gridX > width())) m_lastDropPos = TQPoint(m_dropPos.x(), m_lastDropPos.y() + gridY); else m_lastDropPos = TQPoint(m_lastDropPos.x() + gridX, m_lastDropPos.y()); } } m_dotDirectory->sync(); } // ----------------------------------------------------------------------------- void KDIconView::showEvent( TQShowEvent *e ) { //HACK to avoid TQIconView calling arrangeItemsInGrid (Simon) //EVEN MORE HACK: unfortunately, TQScrollView has no concept of //TopToBottom, therefore, it always adds LeftToRight. So, if any of //the icons have a setting, we'll use TQScrollView.. but otherwise, //we use the iconview //kdDebug(1204)<<"showEvent() m_hasExistingPos: "<<(m_hasExistingPos?(int)1:(int)0)<<endl; if (m_hasExistingPos) TQScrollView::showEvent( e ); else KIconView::showEvent( e ); } void KDIconView::contentsDropEvent( TQDropEvent * e ) { kdDebug(1204)<<"void KDIconView::contentsDropEvent( TQDropEvent * e )\n"; // mind: if it's a filedrag which itself is an image, libkonq is called. There's a popup for drops as well // that contains the same line "Set as Wallpaper" in void KonqOperations::asyncDrop bool isColorDrag = KColorDrag::canDecode(e); bool isImageDrag = TQImageDrag::canDecode(e); bool isUrlDrag = KURLDrag::canDecode(e); bool isImmutable = KGlobal::config()->isImmutable(); if ( (isColorDrag || isImageDrag) && !isUrlDrag ) { // Hack to clear the drag shape bool bMovable = itemsMovable(); bool bSignals = signalsBlocked(); setItemsMovable(false); blockSignals(true); KIconView::contentsDropEvent( e ); blockSignals(bSignals); setItemsMovable(bMovable); // End hack if ( !isImmutable ) // just ignore event in kiosk-mode { if ( isColorDrag) emit colorDropEvent( e ); else if (isImageDrag) emit imageDropEvent( e ); } } else { setLastIconPosition( e->pos() ); KonqIconViewWidget::contentsDropEvent( e ); } // Check if any items have been moved outside the desktop area. // If we find any, move them right back in there. (#40418) TQRect desk = desktopRect(); bool adjustedAnyItems = false; for( TQIconViewItem *item = firstItem(); item; item = item->nextItem() ) { if( !desk.contains( item->rect(), true )) { TQRect r = item->rect(); if( r.top() < 0 ) r.moveTop( 0 ); if( r.bottom() > rect().bottom() ) r.moveBottom( rect().bottom() ); if( r.left() < 0 ) r.moveLeft( 0 ); if( r.right() > rect().right() ) r.moveRight( rect().right() ); item->move( r.x(), r.y() ); adjustedAnyItems = true; } } if( adjustedAnyItems ) { // Make sure the viewport isn't unnecessarily resized by now, // then schedule a repaint to remove any garbage pixels. resizeContents( width(), height() ); viewport()->update(); } if (TQIconDrag::canDecode(e)) { emit iconMoved(); if ( !m_autoAlign ) // if autoAlign, positions were saved in lineupIcons saveIconPositions(); } } // don't scroll when someone uses his nifty mouse wheel void KDIconView::viewportWheelEvent( TQWheelEvent * e ) { e->accept(); } void KDIconView::updateWorkArea( const TQRect &wr ) { m_gotIconsArea = true; // now we have it! if (( iconArea() == wr ) && (m_needDesktopAlign == false)) return; // nothing changed; avoid repaint/saveIconPosition ... TQRect oldArea = iconArea(); setIconArea( wr ); kdDebug(1204) << "KDIconView::updateWorkArea wr: " << wr.x() << "," << wr.y() << " " << wr.width() << "x" << wr.height() << endl; kdDebug(1204) << " oldArea: " << oldArea.x() << "," << oldArea.y() << " " << oldArea.width() << "x" << oldArea.height() << endl; if ( m_autoAlign ) int dummy = 0; //lineupIcons(); else { bool needRepaint = false; TQIconViewItem* item; int dx, dy; dx = wr.left() - oldArea.left(); dy = wr.top() - oldArea.top(); if ( dx != 0 || dy != 0 ) { if ( (dx > 0) || (dy > 0) ) // the iconArea was shifted right/down; less space now for ( item = firstItem(); item; item = item->nextItem() ) { // check if there is any item inside the now unavailable area // If so, we have to move _all_ items // If not, we don't have to move any item (avoids bug:117868) if ( (item->x() < wr.x()) || (item->y() < wr.y()) ) { needRepaint = true; break; } } else // the iconArea was shifted left/up; more space now - use it needRepaint = true; if ( needRepaint ) for ( item = firstItem(); item; item = item->nextItem() ) item->moveBy( dx, dy ); } for ( item = firstItem(); item; item = item->nextItem() ) { TQRect r( item->rect() ); int dx = 0, dy = 0; if ( r.bottom() > wr.bottom() ) dy = wr.bottom() - r.bottom() - 1; if ( r.right() > wr.right() ) dx = wr.right() - r.right() - 1; if ( dx != 0 || dy != 0 ) { needRepaint = true; item->moveBy( dx, dy ); } } if ( needRepaint ) { viewport()->repaint( FALSE ); repaint( FALSE ); saveIconPositions(); } } m_needDesktopAlign = false; lineupIcons(); } void KDIconView::setupSortKeys() { // can't use sorting in KFileIVI::setKey() setProperty("sortDirectoriesFirst", TQVariant(false, 0)); for (TQIconViewItem *it = firstItem(); it; it = it->nextItem()) { TQString strKey; if (!m_itemsAlwaysFirst.isEmpty()) { TQString strFileName = static_cast<KFileIVI *>( it )->item()->url().fileName(); int nFind = m_itemsAlwaysFirst.findIndex(strFileName); if (nFind >= 0) strKey = "0" + TQString::number(nFind); } if (strKey.isEmpty()) { switch (m_eSortCriterion) { case NameCaseSensitive: strKey = it->text(); break; case NameCaseInsensitive: strKey = it->text().lower(); break; case Size: strKey = KIO::number(static_cast<KFileIVI *>( it )->item()->size()).rightJustify(20, '0'); break; case Type: // Sort by Type + Name (#17014) strKey = static_cast<KFileIVI *>( it )->item()->mimetype() + '~' + it->text().lower(); break; case Date: TQDateTime dayt; dayt.setTime_t( static_cast<KFileIVI *>( it )-> item()->time( KIO::UDS_MODIFICATION_TIME ) ); strKey = dayt.toString( "yyyyMMddhhmmss" ); break; } if (m_bSortDirectoriesFirst) { if (S_ISDIR(static_cast<KFileIVI *>( it )->item()->mode())) strKey.prepend(sortDirection() ? '1' : '2'); else strKey.prepend(sortDirection() ? '2' : '1' ); } else strKey.prepend('1'); } it->setKey(strKey); } } bool KDIconView::isFreePosition( const TQIconViewItem *item ) const { TQRect r = item->rect(); TQIconViewItem *it = firstItem(); for (; it; it = it->nextItem() ) { if ( !it->rect().isValid() || it == item ) continue; if ( it->intersects( r ) ) return false; } return true; } bool KDIconView::isFreePosition( const TQIconViewItem *item ,const TQRect& rect) const { TQIconViewItem *it = firstItem(); for (; it; it = it->nextItem() ) { if ( !rect.isValid() || it == item ) continue; if ( it->intersects( rect ) ) return false; } return true; } void KDIconView::setLastIconPosition( const TQPoint &_pos ) { m_lastDeletedIconPos = _pos; } void KDIconView::moveToFreePosition(TQIconViewItem *item ) { bool success; // It may be that a file has been renamed. In this case, // m_lastDeletedIconPos is the position to use for this "apparently new" item. // (We rely on deleteItem being now emitted before newItems). if ( !m_lastDeletedIconPos.isNull() ) // Problem is: I'd like to compare those two file's attributes // (size, creation time, modification time... etc.) but since renaming // is done by kpropsdlg, all of those can have changed (and creation time // is different since the new file is a copy!) { kdDebug(1214) << "Moving " << item->text() << " to position of last deleted icon." << endl; item->move( m_lastDeletedIconPos ); m_lastDeletedIconPos = TQPoint(); return; } //try to find a free place to put the item, honouring the m_bVertAlign property TQRect rect=item->rect(); if (m_bVertAlign) { kdDebug(1214)<<"moveToFreePosition for vertical alignment"<<endl; rect.moveTopLeft(TQPoint(spacing(),spacing())); do { success=false; while (rect.bottom()<height()) { if (!isFreePosition(item,rect)) { rect.moveBy(0,rect.height()+spacing()); } else { success=true; break; } } if (!success) { rect.moveTopLeft(TQPoint(rect.right()+spacing(),spacing())); } else break; } while (item->rect().right()<width()); if (success) item->move(rect.x(),rect.y()); else item->move(width()-spacing()-item->rect().width(),height()-spacing()-item->rect().height()); } } TQPoint KDIconView::findPlaceForIconCol( int column, int dx, int dy) { if (column < 0) return TQPoint(); TQRect rect; rect.moveTopLeft( TQPoint(column * dx, 0) ); rect.setWidth(dx); rect.setHeight(dy); if (rect.right() > viewport()->width()) return TQPoint(); while ( rect.bottom() < viewport()->height() - spacing() ) { if ( !isFreePosition(0,rect) ) rect.moveBy(0, rect.height()); else return rect.topLeft(); } return TQPoint(); } TQPoint KDIconView::findPlaceForIconRow( int row, int dx, int dy ) { if (row < 0) return TQPoint(); TQRect rect; rect.moveTopLeft(TQPoint(0, row * dy)); rect.setWidth(dx); rect.setHeight(dy); if (rect.bottom() > viewport()->height()) return TQPoint(); while (rect.right() < viewport()->width() - spacing()) { if (!isFreePosition(0,rect)) rect.moveBy(rect.width()+spacing(), 0); else return rect.topLeft(); } return TQPoint(); } TQPoint KDIconView::findPlaceForIcon( int column, int row) { int dx = gridXValue(), dy = 0; TQIconViewItem *item = firstItem(); for ( ; item; item = item->nextItem() ) { dx = QMAX( dx, item->width() ); dy = QMAX( dy, item->height() ); } dx += spacing(); dy += spacing(); if (row == -1) { int max_cols = viewport()->width() / dx; int delta = 0; TQPoint res; do { delta++; res = findPlaceForIconCol(column + (delta / 2) * (-2 * (delta % 2) + 1), dx, dy); if (delta / 2 > QMAX(max_cols - column, column)) return res; } while (res.isNull()); return res; } if (column == -1) { int max_rows = viewport()->height() / dy; int delta = 0; TQPoint res; do { delta++; res = findPlaceForIconRow(row + (delta / 2) * (-2 * (delta % 2) + 1), dx, dy); if (delta / 2 > QMAX(max_rows - row, row)) return res; } while (res.isNull()); return res; } // very unlikely - if I may add that return TQPoint(0, 0); } void KDIconView::saveIconPositions() { kdDebug(1214) << "KDIconView::saveIconPositions" << endl; if (!m_bEditableDesktopIcons) return; // Don't save position TQString prefix = iconPositionGroupPrefix(); 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(); m_dotDirectory->setGroup( prefix + item->url().fileName() ); kdDebug(1214) << "KDIconView::saveIconPositions " << item->url().fileName() << " " << it->x() << " " << it->y() << endl; saveIconPosition(m_dotDirectory, it->x(), it->y()); it = it->nextItem(); } m_dotDirectory->sync(); } void KDIconView::update( const TQString &_url ) { if (m_dirLister) m_dirLister->updateDirectory( _url ); } #include "kdiconview.moc"