/* This file is part of the KDE project
Copyright ( C ) 1998 , 1999 David Faure < faure @ kde . org >
Copyright ( C ) 2001 Holger Freyther < freyther @ yahoo . com >
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation ; either
version 2 of the License , or ( at your option ) any later version .
This library is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
Library General Public License for more details .
You should have received a copy of the GNU Library General Public License
along with this library ; see the file COPYING . LIB . If not , write to
the Free Software Foundation , Inc . , 51 Franklin Street , Fifth Floor ,
Boston , MA 02110 - 1301 , USA .
*/
# include <tqdir.h>
# include <klocale.h>
# include <kapplication.h>
# include <kbookmarkmanager.h>
# include <kdebug.h>
# include <krun.h>
# include <kprotocolinfo.h>
# include <kiconloader.h>
# include <kinputdialog.h>
# include <kglobalsettings.h>
# include <kstandarddirs.h>
# include <kxmlguifactory.h>
# include <kxmlguibuilder.h>
# include <kparts/componentfactory.h>
# include <assert.h>
# include <kfileshare.h>
# include <kprocess.h>
# include "kpropertiesdialog.h"
# include "knewmenu.h"
# include "konq_popupmenu.h"
# include "konq_operations.h"
# include <dcopclient.h>
/*
Test cases :
iconview file : background
iconview file : file ( with and without servicemenus )
iconview file : directory
iconview remote protocol ( e . g . ftp : or fish : )
iconview trash : /
sidebar directory tree
sidebar Devices / Hard Disc
khtml background
khtml link
khtml image ( www . kde . org RMB on K logo )
khtmlimage ( same as above , then choose View image , then RMB )
selected text in khtml
embedded katepart
kdesktop folder
trash link on desktop
trashed file or directory
application . desktop file
Then the same after uninstalling kdeaddons / konq - plugins ( kuick and arkplugin in particular )
*/
class KonqPopupMenuGUIBuilder : public KXMLGUIBuilder
{
public :
KonqPopupMenuGUIBuilder ( 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 ;
} ;
KonqPopupMenu : : ProtocolInfo : : ProtocolInfo ( )
{
m_Reading = false ;
m_Writing = false ;
m_Deleting = false ;
m_Moving = false ;
m_TrashIncluded = false ;
}
bool KonqPopupMenu : : ProtocolInfo : : supportsReading ( ) const
{
return m_Reading ;
}
bool KonqPopupMenu : : ProtocolInfo : : supportsWriting ( ) const
{
return m_Writing ;
}
bool KonqPopupMenu : : ProtocolInfo : : supportsDeleting ( ) const
{
return m_Deleting ;
}
bool KonqPopupMenu : : ProtocolInfo : : supportsMoving ( ) const
{
return m_Moving ;
}
bool KonqPopupMenu : : ProtocolInfo : : trashIncluded ( ) const
{
return m_TrashIncluded ;
}
// This helper class stores the .desktop-file actions and the servicemenus
// in order to support X-KDE-Priority and X-KDE-Submenu.
class PopupServices
{
public :
ServiceList * selectList ( const 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 ,
KActionCollection & 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 ,
KActionCollection & 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 ,
KActionCollection & 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_ " ) ;
KAction * act = new KAction ( TQString ( ( * it ) . m_strName ) . replace ( ' & ' , " && " ) , 0 ,
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 ( KConfig & cfg )
{
if ( ! cfg . hasKey ( " X-KDE-AuthorizeAction " ) )
{
return true ;
}
TQStringList list = cfg . readListEntry ( " X-KDE-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 ( KGlobalSettings : : 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 ;
}
url = m_sViewURL ;
url . cleanPath ( ) ;
//check if url is current directory
if ( m_lstItems . count ( ) = = 1 )
{
KURL firstPopupURL ( m_lstItems . first ( ) - > url ( ) ) ;
firstPopupURL . cleanPath ( ) ;
//kdDebug(1203) << "View path is " << url.url() << endl;
//kdDebug(1203) << "First popup path is " << firstPopupURL.url() << endl;
currentDir = firstPopupURL . equals ( url , true /* ignore_trailing */ ) ;
if ( isLocal & & m_sMimeType = = " application/x-desktop " ) {
KSimpleConfig cfg ( firstPopupURL . path ( ) , true ) ;
cfg . setDesktopGroup ( ) ;
isTrashLink = ( cfg . readEntry ( " Type " ) = = " Link " & & cfg . readEntry ( " URL " ) = = " trash:/ " ) ;
}
if ( isTrashLink ) {
sDeleting = false ;
}
}
m_info . m_Reading = sReading ;
m_info . m_Writing = sWriting ;
m_info . m_Deleting = sDeleting ;
m_info . m_Moving = sMoving ;
m_info . m_TrashIncluded = bTrashIncluded ;
// isCurrentTrash: popup on trash:/ itself, or on the trash.desktop link
bool isCurrentTrash = ( m_lstItems . count ( ) = = 1 & & bTrashIncluded ) | | isTrashLink ;
bool isIntoTrash = ( url . protocol ( ) = = " trash " | | url . url ( ) . startsWith ( " system:/trash " ) ) & & ! isCurrentTrash ; // trashed file, not trash:/ itself
//kdDebug() << "isLocal=" << isLocal << " url=" << url << " isCurrentTrash=" << isCurrentTrash << " isIntoTrash=" << isIntoTrash << " bTrashIncluded=" << bTrashIncluded << endl;
bool isSingleMedium = m_lstItems . count ( ) = = 1 & & mediaFiles ;
clear ( ) ;
//////////////////////////////////////////////////////////////////////////
KAction * act ;
if ( ! isCurrentTrash )
addMerge ( " konqueror " ) ;
bool isKDesktop = TQCString ( kapp - > name ( ) ) = = " kdesktop " ;
KAction * actNewWindow = 0 ;
if ( ( kpf & ShowProperties ) & & isKDesktop & &
! kapp - > authorize ( " editable_desktop_icons " ) )
{
kpf & = ~ ShowProperties ; // remove flag
}
// Either 'newview' is in the actions we're given (probably in the tabhandling group)
// or we need to insert it ourselves (e.g. for kdesktop). In the first case, actNewWindow must remain 0.
if ( ( ( kpf & ShowNewWindow ) ! = 0 ) & & sReading )
{
TQString openStr = isKDesktop ? i18n ( " &Open " ) : i18n ( " Open in New &Window " ) ;
actNewWindow = new KAction ( openStr , " window_new " , 0 , 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 )
{
KAction * actNewDir = new KAction ( i18n ( " Create &Folder... " ) , " folder_new " , 0 , this , TQT_SLOT ( slotPopupNewDir ( ) ) , & m_ownActions , " newdir " ) ;
addAction ( actNewDir ) ;
addSeparator ( ) ;
}
}
} else if ( isIntoTrash ) {
// Trashed item, offer restoring
act = new KAction ( i18n ( " &Restore " ) , 0 , 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 ( KApplication : : keyboardMouseState ( ) & Qt : : ShiftButton ) {
addTrash = false ;
addDel = true ;
}
else {
KConfigGroup configGroup ( kapp - > config ( ) , " KDE " ) ;
if ( configGroup . readBoolEntry ( " ShowDeleteCommand " , false ) )
addDel = true ;
}
}
if ( addTrash )
addAction ( " trash " ) ;
if ( addDel )
addAction ( " del " ) ;
}
}
if ( isCurrentTrash )
{
act = new KAction ( i18n ( " &Empty Trash Bin " ) , " emptytrash " , 0 , this , 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 KAction ( caption , " bookmark_add " , 0 , this , TQT_SLOT ( slotPopupAddToBookmark ( ) ) , & m_ownActions , " bookmark_add " ) ;
if ( m_lstItems . count ( ) > 1 )
act - > setEnabled ( false ) ;
if ( kapp - > authorizeKAction ( " bookmarks " ) )
addAction ( act ) ;
if ( bIsLink )
addGroup ( " linkactions " ) ;
}
//////////////////////////////////////////////////////
const bool isSingleLocal = m_lstItems . count ( ) = = 1 & & isLocal ;
PopupServices s ;
KURL urlForServiceMenu ( m_lstItems . first ( ) - > url ( ) ) ;
if ( isLocal & & ! isReallyLocal ) { // media or system
bool dummy ;
urlForServiceMenu = m_lstItems . first ( ) - > mostLocalURL ( dummy ) ;
}
// 1 - Look for builtin and user-defined services
if ( m_sMimeType = = " application/x-desktop " & & isSingleLocal ) // .desktop file
{
// get builtin services, like mount/unmount
s . builtin = KDEDesktopMimeType : : builtinServices ( urlForServiceMenu ) ;
const TQString path = urlForServiceMenu . path ( ) ;
KSimpleConfig cfg ( path , true ) ;
cfg . setDesktopGroup ( ) ;
const TQString priority = cfg . readEntry ( " X-KDE-Priority " ) ;
const TQString submenuName = cfg . readEntry ( " X-KDE-Submenu " ) ;
if ( cfg . readEntry ( " Type " ) = = " Link " ) {
urlForServiceMenu = cfg . readEntry ( " URL " ) ;
// TODO: Do we want to make all the actions apply on the target
// of the .desktop file instead of the .desktop file itself?
}
ServiceList * list = s . selectList ( priority , submenuName ) ;
( * list ) = KDEDesktopMimeType : : userDefinedServices ( path , cfg , urlForServiceMenu . isLocalFile ( ) ) ;
}
if ( sReading )
{
// 2 - Look for "servicesmenus" bindings (konqueror-specific user-defined services)
// first check the .directory if this is a directory
if ( isDirectory & & isSingleLocal )
{
TQString dotDirectoryFile = urlForServiceMenu . path ( 1 ) . append ( " .directory " ) ;
KSimpleConfig cfg ( dotDirectoryFile , true ) ;
cfg . setDesktopGroup ( ) ;
if ( KIOSKAuthorizedAction ( cfg ) )
{
const TQString priority = cfg . readEntry ( " X-KDE-Priority " ) ;
const TQString submenuName = cfg . readEntry ( " X-KDE-Submenu " ) ;
ServiceList * list = s . selectList ( priority , submenuName ) ;
( * list ) + = KDEDesktopMimeType : : userDefinedServices ( dotDirectoryFile , cfg , true ) ;
}
}
// findAllResources() also removes duplicates
const TQStringList entries = KGlobal : : 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-KDE-ShowIfRunning " ) )
{
const TQString app = cfg . readEntry ( " X-KDE-ShowIfRunning " ) ;
if ( ! kapp - > dcopClient ( ) - > isApplicationRegistered ( app . utf8 ( ) ) )
continue ;
}
if ( cfg . hasKey ( " X-KDE-ShowIfDcopCall " ) )
{
TQString dcopcall = cfg . readEntry ( " X-KDE-ShowIfDcopCall " ) ;
const TQCString app = 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 = dcopcall . section ( ' ' , 1 , - 2 ) . utf8 ( ) ;
TQString function = dcopcall . section ( ' ' , - 1 ) ;
if ( ! function . endsWith ( " (KURL::List) " ) ) {
kdWarning ( ) < < " Desktop file " < < * eIt < < " contains an invalid X-KDE-ShowIfDcopCall - the function must take the exact parameter (KURL::List) and must be specified. " < < endl ;
continue ; //Be safe.
}
if ( ! kapp - > dcopClient ( ) - > call ( app , object ,
function . utf8 ( ) ,
dataToSend , replyType , replyData , true , 1000 ) )
continue ;
if ( replyType ! = " bool " | | ! replyData [ 0 ] )
continue ;
}
if ( cfg . hasKey ( " X-KDE-Protocol " ) )
{
const TQString protocol = cfg . readEntry ( " X-KDE-Protocol " ) ;
if ( protocol ! = urlForServiceMenu . protocol ( ) )
continue ;
}
else if ( cfg . hasKey ( " X-KDE-Protocols " ) )
{
TQStringList protocols = TQStringList : : split ( " , " , cfg . readEntry ( " X-KDE-Protocols " ) ) ;
if ( ! protocols . contains ( urlForServiceMenu . protocol ( ) ) )
continue ;
}
else if ( urlForServiceMenu . protocol ( ) = = " trash " | | urlForServiceMenu . url ( ) . startsWith ( " system:/trash " ) )
{
// Require servicemenus for the trash to ask for protocol=trash explicitely.
// Trashed files aren't supposed to be available for actions.
// One might want a servicemenu for trash.desktop itself though.
continue ;
}
if ( cfg . hasKey ( " X-KDE-Require " ) )
{
const TQStringList capabilities = cfg . readListEntry ( " X-KDE-Require " ) ;
if ( capabilities . contains ( " Write " ) & & ! sWriting )
continue ;
}
if ( ( cfg . hasKey ( " Actions " ) | | cfg . hasKey ( " X-KDE-GetActionMenu " ) ) & & cfg . hasKey ( " ServiceTypes " ) )
{
const TQStringList types = cfg . readListEntry ( " ServiceTypes " ) ;
const TQStringList excludeTypes = cfg . readListEntry ( " 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-KDE-Priority " ) ;
const TQString submenuName = cfg . readEntry ( " X-KDE-Submenu " ) ;
ServiceList * list = s . selectList ( priority , submenuName ) ;
( * list ) + = KDEDesktopMimeType : : userDefinedServices ( * eIt , cfg , url . isLocalFile ( ) , m_lstPopupURLs ) ;
}
}
}
KTrader : : OfferList offers ;
if ( kapp - > authorizeKAction ( " openwith " ) )
{
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 = KTrader : : self ( ) - > query ( first , constraint ) ;
}
//// Ok, we have everything, now insert
m_mapPopup . clear ( ) ;
m_mapPopupServices . clear ( ) ;
// "Open With..." for folders is really not very useful, especially for remote folders.
// (media:/something, or trash:/, or ftp://...)
if ( ! isDirectory | | isLocal )
{
if ( hasAction ( ) )
addSeparator ( ) ;
if ( ! offers . isEmpty ( ) )
{
// First block, app and preview offers
id = 1 ;
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 " ) ) ) ;
}
KTrader : : OfferList : : ConstIterator it = offers . begin ( ) ;
for ( ; it ! = offers . end ( ) ; it + + )
{
KService : : Ptr service = ( * it ) ;
// Skip OnlyShowIn=Foo and NotShowIn=KDE entries,
// but still offer NoDisplay=true entries, that's the
// whole point of such desktop files. This is why we don't
// use service->noDisplay() here.
const TQString onlyShowIn = service - > property ( " OnlyShowIn " , TQVariant : : String ) . toString ( ) ;
if ( ! onlyShowIn . isEmpty ( ) ) {
const TQStringList aList = TQStringList : : split ( ' ; ' , onlyShowIn ) ;
if ( ! aList . contains ( " KDE " ) )
continue ;
}
const TQString notShowIn = service - > property ( " NotShowIn " , TQVariant : : String ) . toString ( ) ;
if ( ! notShowIn . isEmpty ( ) ) {
const TQStringList aList = TQStringList : : split ( ' ; ' , notShowIn ) ;
if ( aList . contains ( " KDE " ) )
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 KAction ( actionName , ( * it ) - > pixmap ( KIcon : : Small ) , 0 ,
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... " ) ;
}
KAction * openWithAct = new KAction ( openWithActionName , 0 , this , TQT_SLOT ( slotPopupOpenWith ( ) ) , & m_ownActions , " openwith " ) ;
addAction ( openWithAct , menu ) ;
}
else // no app offers -> Open With...
{
act = new KAction ( i18n ( " &Open With... " ) , 0 , 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 KAction ( i18n ( " &Properties " ) , 0 , 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 KAction ( i18n ( " Share " ) , 0 , 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 = 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 kfileitem was created by hand
// (see KonqKfmIconView::slotMouseButtonPressed)
// In that case, we can get more precise info in the properties
// (like permissions) if we stat the URL.
if ( m_lstItems . count ( ) = = 1 )
{
KFileItem * item = m_lstItems . first ( ) ;
if ( item - > entry ( ) . count ( ) = = 0 ) // this item wasn't listed by a slave
{
// KPropertiesDialog will use stat to get more info on the file
return new KPropertiesDialog ( item - > url ( ) , d - > m_parentWidget ) ;
}
}
return new KPropertiesDialog ( m_lstItems , d - > m_parentWidget ) ;
}
KAction * KonqPopupMenu : : action ( const TQDomElement & element ) const
{
TQCString name = element . attribute ( attrName ) . ascii ( ) ;
KAction * res = m_ownActions . action ( name ) ;
if ( ! res )
res = m_actions . action ( name ) ;
if ( ! res & & m_pMenuNew & & strcmp ( name , m_pMenuNew - > name ( ) ) = = 0 )
return m_pMenuNew ;
return res ;
}
KActionCollection * KonqPopupMenu : : actionCollection ( ) const
{
return const_cast < KActionCollection * > ( & m_ownActions ) ;
}
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
KTrader : : OfferList plugin_offers ;
unsigned int pluginCount = 0 ;
plugin_offers = KTrader : : 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
KTrader : : OfferList : : ConstIterator iterator = plugin_offers . begin ( ) ;
KTrader : : OfferList : : ConstIterator end = plugin_offers . end ( ) ;
addGroup ( " plugins " ) ;
// travers the offerlist
for ( ; iterator ! = end ; + + iterator , + + pluginCount ) {
//kdDebug() << (*iterator)->library() << endl;
KonqPopupMenuPlugin * plugin =
KParts : : ComponentFactory : :
createInstanceFromLibrary < KonqPopupMenuPlugin > ( TQFile : : encodeName ( ( * iterator ) - > library ( ) ) ,
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 ;
}
/**
Plugin
*/
KonqPopupMenuPlugin : : KonqPopupMenuPlugin ( KonqPopupMenu * parent , const char * name )
: TQObject ( parent , name )
{
}
KonqPopupMenuPlugin : : ~ KonqPopupMenuPlugin ( )
{
}
# include "konq_popupmenu.moc"