/***************************************************************************
* Copyright ( C ) 2005 by Jens Herden *
* jens @ tdewebdev . org *
* *
* This program is free software ; you can redistribute it and / or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation ; either version 2 of the License , or *
* ( at your option ) any later version . *
* *
* This program is distributed in the hope that it will be useful , *
* but WITHOUT ANY WARRANTY ; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the *
* GNU General Public License for more details . *
* *
* You should have received a copy of the GNU General Public License *
* along with this program ; if not , write to the *
* Free Software Foundation , Inc . , *
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA . *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "projectviewprojectconfig.h"
# include "projectviewconfig.h"
# include "projectviewpart.h"
# include "filelist_widget.h"
# include "toolbarguibuilder.h"
# include <tqtimer.h>
# include <tqpopupmenu.h>
# include <tqwhatsthis.h>
# include <tqvaluelist.h>
# include <tqmap.h>
# include <tqdir.h>
# include <tqdom.h>
# include <tqvbox.h>
# include <tqhbox.h>
# include <tqpoint.h>
# include <tqlayout.h>
# include <kmainwindow.h>
# include <kinputdialog.h>
# include <klocale.h>
# include <kaction.h>
# include <kdialogbase.h>
# include <kiconloader.h>
# include <kmessagebox.h>
# include <ktexteditor/viewcursorinterface.h>
# include <ktexteditor/encodinginterface.h>
# include <kparts/part.h>
# include <kxmlguibuilder.h>
# include <kdebug.h>
# include <kconfig.h>
# include <kapplication.h>
# include <kdevplugininfo.h>
# include <kdevgenericfactory.h>
# include <kdevpartcontroller.h>
# include <kdevproject.h>
# include <kdevcore.h>
# include <kdevmainwindow.h>
# include <configwidgetproxy.h>
typedef KDevGenericFactory < ProjectviewPart > projectviewFactory ;
KDevPluginInfo data ( " kdevfilelist " ) ;
K_EXPORT_COMPONENT_FACTORY ( libkdevfilelist , projectviewFactory ( data ) )
# define GLOBALDOC_OPTIONS 1
# define PROJECTDOC_OPTIONS 2
ProjectviewPart : : ProjectviewPart ( TQObject * parent , const char * name , const TQStringList & /*args*/ )
: KDevPlugin ( & data , parent , name ? name : " FileListPart " )
{
setInstance ( projectviewFactory : : instance ( ) ) ;
setXMLFile ( " kdevfilelist.rc " ) ;
setupActions ( ) ;
m_configProxy = new ConfigWidgetProxy ( core ( ) ) ;
m_configProxy - > createGlobalConfigPage ( i18n ( " File List " ) , GLOBALDOC_OPTIONS , info ( ) - > icon ( ) ) ;
m_configProxy - > createProjectConfigPage ( i18n ( " File List " ) , PROJECTDOC_OPTIONS , info ( ) - > icon ( ) ) ;
connect ( m_configProxy , TQT_SIGNAL ( insertConfigWidget ( const KDialogBase * , TQWidget * , unsigned int ) ) ,
this , TQT_SLOT ( insertConfigWidget ( const KDialogBase * , TQWidget * , unsigned int ) ) ) ;
connect ( core ( ) , TQT_SIGNAL ( contextMenu ( TQPopupMenu * , const Context * ) ) ,
this , TQT_SLOT ( contextMenu ( TQPopupMenu * , const Context * ) ) ) ;
connect ( core ( ) , TQT_SIGNAL ( projectOpened ( ) ) , this , TQT_SLOT ( projectOpened ( ) ) ) ;
connect ( core ( ) , TQT_SIGNAL ( projectClosed ( ) ) , this , TQT_SLOT ( projectClosed ( ) ) ) ;
KConfig * config = kapp - > config ( ) ;
config - > setGroup ( " File List Plugin " ) ;
if ( config - > readBoolEntry ( " ToolbarInToolview " , true ) )
{
m_toolbarWidget = new TQVBox ( 0 , " toolbarContainer " ) ;
m_toolbarWidget - > setHidden ( true ) ;
m_guibuilder = new ToolbarGUIBuilder ( m_toolbarWidget , mainWindow ( ) - > main ( ) ) ;
setClientBuilder ( m_guibuilder ) ;
}
m_restored = false ;
TQTimer : : singleShot ( 0 , this , TQT_SLOT ( init ( ) ) ) ;
}
ProjectviewPart : : ~ ProjectviewPart ( )
{
delete m_configProxy ;
delete m_guibuilder ;
if ( m_widget ) {
mainWindow ( ) - > removeView ( m_widget ) ;
delete m_widget ; // deletes the children as well
}
}
void ProjectviewPart : : restorePartialProjectSession ( const TQDomElement * el )
{
m_projectViews . clear ( ) ; // remove the global views
m_restored = true ;
if ( ! el )
{
return ;
}
// get the base of the project
TQString urlStr = project ( ) - > projectDirectory ( ) ;
if ( KURL : : isRelativeURL ( urlStr ) )
{
m_projectBase . setProtocol ( " file " ) ;
m_projectBase . setPath ( urlStr ) ;
} else
{
m_projectBase = KURL : : fromPathOrURL ( urlStr ) ;
}
m_projectBase . adjustPath ( + 1 ) ; // just in case
// read all the views
TQDomNodeList domList = el - > elementsByTagName ( " projectview " ) ;
uint len = domList . length ( ) ;
for ( uint i = 0 ; i < len ; + + i )
{
const TQDomElement viewEl = domList . item ( i ) . toElement ( ) ;
if ( viewEl . isNull ( ) )
{
continue ;
}
FileInfoList urlList ;
TQDomNodeList fileList = viewEl . elementsByTagName ( " file " ) ;
uint len2 = fileList . length ( ) ;
for ( uint i2 = 0 ; i2 < len2 ; + + i2 )
{
const TQDomElement fileEl = fileList . item ( i2 ) . toElement ( ) ;
if ( ! fileEl . isNull ( ) )
{
bool ok ;
int line = - 1 ;
TQString attr = fileEl . attribute ( " line " ) ;
if ( ! attr . isNull ( ) )
{
line = attr . toInt ( & ok ) ;
if ( ! ok )
line = - 1 ;
}
int col = - 1 ;
attr = fileEl . attribute ( " col " ) ;
if ( ! attr . isNull ( ) )
{
col = attr . toInt ( & ok ) ;
if ( ! ok )
col = - 1 ;
}
TQString encoding = " " ;
attr = fileEl . attribute ( " encoding " ) ;
if ( ! attr . isNull ( ) )
{
encoding = attr ;
}
TQString urlStr = fileEl . attribute ( " url " ) ;
if ( KURL : : isRelativeURL ( urlStr ) )
{
KURL url = m_projectBase ;
url . addPath ( urlStr ) ;
urlList . append ( FileInfo ( url , line , col , encoding ) ) ;
} else
urlList . append ( FileInfo ( KURL : : fromPathOrURL ( urlStr ) , line , col , encoding ) ) ;
}
}
m_projectViews . insert ( viewEl . attribute ( " name " ) , urlList ) ;
}
// read default view
domList = el - > elementsByTagName ( " defaultview " ) ;
if ( domList . length ( ) > 0 )
{
m_defaultProjectView = domList . item ( 0 ) . toElement ( ) . attribute ( " name " ) ;
if ( ! m_defaultProjectView . isEmpty ( ) )
{
slotOpenProjectView ( m_defaultProjectView ) ;
}
} else
{
m_defaultProjectView = " " ;
}
}
void ProjectviewPart : : savePartialProjectSession ( TQDomElement * el )
{
if ( ! el | | m_projectViews . empty ( ) )
{
return ;
}
TQDomDocument domDoc = el - > ownerDocument ( ) ;
if ( domDoc . isNull ( ) )
{
return ;
}
// write all views
ViewMap : : ConstIterator it ;
for ( it = m_projectViews . constBegin ( ) ; it ! = m_projectViews . constEnd ( ) ; + + it )
{
// we create the view even if there is no file inside, might be wanted by the user
TQDomElement viewEl = domDoc . createElement ( " projectview " ) ;
viewEl . setAttribute ( " name " , it . key ( ) ) ;
el - > appendChild ( viewEl ) ;
for ( FileInfoList : : ConstIterator it2 = it . data ( ) . constBegin ( ) ; it2 ! = it . data ( ) . constEnd ( ) ; + + it2 )
{
TQDomElement urlEl = domDoc . createElement ( " file " ) ;
if ( m_projectBase . isParentOf ( ( * it2 ) . url ) )
urlEl . setAttribute ( " url " , KURL : : relativeURL ( m_projectBase , ( * it2 ) . url ) ) ;
else
urlEl . setAttribute ( " url " , ( * it2 ) . url . url ( ) ) ;
urlEl . setAttribute ( " line " , ( * it2 ) . line ) ;
urlEl . setAttribute ( " col " , ( * it2 ) . col ) ;
urlEl . setAttribute ( " encoding " , ( * it2 ) . encoding ) ;
viewEl . appendChild ( urlEl ) ;
}
}
// write the default view
TQDomElement defaultEl = domDoc . createElement ( " defaultview " ) ;
defaultEl . setAttribute ( " name " , m_defaultProjectView ) ;
el - > appendChild ( defaultEl ) ;
}
void ProjectviewPart : : init ( )
{
// delayed initialization stuff goes here
// create the toolview
m_widget = new TQWidget ( 0 , " filelist widget " ) ;
m_widget - > setIcon ( SmallIcon ( info ( ) - > icon ( ) ) ) ;
m_widget - > setCaption ( i18n ( " File List " ) ) ;
TQBoxLayout * l = new TQVBoxLayout ( m_widget ) ;
// create the toolbar if needed
if ( m_guibuilder )
{
m_toolbarWidget - > reparent ( m_widget , TQPoint ( 0 , 0 ) , true ) ;
l - > addWidget ( m_toolbarWidget ) ;
TQWhatsThis : : add ( m_toolbarWidget , i18n ( " <b>View Session Toolbar</b><p>This allows to create and work with view sessions. A view session is a set of open documents.</p> " ) ) ;
}
// create the listview
TQWidget * fileListWidget = new FileListWidget ( this , m_widget ) ;
fileListWidget - > setCaption ( i18n ( " File List " ) ) ;
TQWhatsThis : : add ( fileListWidget , i18n ( " <b>File List</b><p>This is the list of opened files.</p> " ) ) ;
l - > addWidget ( fileListWidget ) ;
m_widget - > setFocusProxy ( fileListWidget ) ;
mainWindow ( ) - > embedSelectView ( m_widget , i18n ( " File List " ) , i18n ( " Open files " ) ) ;
if ( ! project ( ) )
readConfig ( ) ;
}
void ProjectviewPart : : setupActions ( )
{
m_openPrjViewAction = new KSelectAction ( i18n ( " Open Session... " ) , 0 , actionCollection ( ) , " viewsession_open " ) ;
connect ( m_openPrjViewAction , TQT_SIGNAL ( activated ( const TQString & ) ) , this , TQT_SLOT ( slotOpenProjectView ( const TQString & ) ) ) ;
m_openPrjViewAction - > setToolTip ( i18n ( " Open Session " ) ) ;
m_savePrjViewAction = new KAction ( i18n ( " Save Session " ) , " filesave " , 0 , this , TQT_SLOT ( slotSaveProjectView ( ) ) , actionCollection ( ) , " viewsession_save " ) ;
m_newPrjViewAction = new KAction ( i18n ( " New Session... " ) , " filenew " , 0 , this , TQT_SLOT ( slotSaveAsProjectView ( ) ) , actionCollection ( ) , " viewsession_new " ) ;
m_deletePrjViewAction = new KSelectAction ( i18n ( " Delete Session " ) , " editdelete " , 0 , actionCollection ( ) , " viewsession_delete " ) ;
connect ( m_deletePrjViewAction , TQT_SIGNAL ( activated ( const TQString & ) ) , this , TQT_SLOT ( slotDeleteProjectView ( const TQString & ) ) ) ;
m_deletePrjViewAction - > setToolTip ( i18n ( " Delete Session " ) ) ;
m_deleteCurrentPrjViewAction = new KAction ( i18n ( " Delete Session " ) , " editdelete " , 0 , this , TQT_SLOT ( slotDeleteProjectViewCurent ( ) ) , actionCollection ( ) , " viewsession_deletecurrent " ) ;
m_deleteCurrentPrjViewAction - > setToolTip ( i18n ( " Delete Session " ) ) ;
adjustViewActions ( ) ;
}
void ProjectviewPart : : insertConfigWidget ( const KDialogBase * dlg , TQWidget * page , unsigned int pageNo )
{
// create configuraton dialogs here
switch ( pageNo )
{
case PROJECTDOC_OPTIONS :
{
ProjectviewProjectConfig * w = new ProjectviewProjectConfig ( this , page , " project config " ) ;
connect ( dlg , TQT_SIGNAL ( okClicked ( ) ) , w , TQT_SLOT ( accept ( ) ) ) ;
break ;
}
case GLOBALDOC_OPTIONS :
{
ProjectviewConfig * w = new ProjectviewConfig ( page , " global config " ) ;
connect ( dlg , TQT_SIGNAL ( okClicked ( ) ) , w , TQT_SLOT ( accept ( ) ) ) ;
break ;
}
}
}
void ProjectviewPart : : contextMenu ( TQPopupMenu */ * popup */ , const Context */ * context */ )
{
// put actions into the context menu here
// if (context->hasType(Context::EditorContext))
// {
// // editor context menu
// const EditorContext *econtext = static_cast<const EditorContext*>(context);
//
// // use context and plug actions here
// // action->plug(popup);
//
// // or create menu items on the fly
// // int id = -1;
// // id = popup->insertItem(i18n("Do Something Here"),
// // this, TQT_SLOT(doSomething()));
// // popup->setWhatsThis(id, i18n("<b>Do something here</b><p>Describe here what does this action do."
// }
// else if (context->hasType(Context::FileContext))
// {
// // file context menu
// const FileContext *fcontext = static_cast<const FileContext*>(context);
//
// //use context and plug actions here
// }
// else if (context->hasType(Context::ProjectModelItemContext))
// {
// // project tree context menu
// const ProjectModelItemContext *pcontext = static_cast<const ProjectModelItemContext*>(context);
//
// // use context and plug actions here
// }
// else if (context->hasType(Context::CodeModelItemContext))
// {
// // class tree context menu
// const CodeModelItemContext *mcontext = static_cast<const CodeModelItemContext*>(context);
//
// // use context and plug actions here
// }
// else if (context->hasType(Context::DocumentationContext))
// {
// // documentation viewer context menu
// const DocumentationContext *dcontext = static_cast<const DocumentationContext*>(context);
//
// // use context and plug actions here
// }
}
void ProjectviewPart : : projectOpened ( )
{
if ( ! m_restored )
m_projectViews . clear ( ) ; // remove the global views
adjustViewActions ( ) ;
m_restored = false ;
}
void ProjectviewPart : : projectClosed ( )
{
m_projectBase = KURL ( ) ;
m_defaultProjectView = " " ;
readConfig ( ) ; // read the global project views
}
void ProjectviewPart : : slotOpenProjectView ( const TQString & view )
{
KConfig * config = kapp - > config ( ) ;
config - > setGroup ( " File List Plugin " ) ;
bool onlyProject = config - > readBoolEntry ( " OnlyProjectFiles " , false ) ;
bool closeOpenFiles = config - > readBoolEntry ( " CloseOpenFiles " , true ) ;
m_currentProjectView = view ;
if ( m_projectViews . contains ( view ) > 0 )
{
FileInfoList viewUrls = m_projectViews [ view ] ;
if ( closeOpenFiles )
{
// we close everything that is not part of the project view
KURL : : List urlsToClose = partController ( ) - > openURLs ( ) ;
for ( KURL : : List : : Iterator it = urlsToClose . begin ( ) ; it ! = urlsToClose . end ( ) ; + + it )
{
// it is in the list of wanted files and do we want it at all
if ( ( viewUrls . contains ( * it ) > 0 ) & & ( ! onlyProject | | ! project ( ) | | project ( ) - > isProjectFile ( ( * it ) . path ( ) ) ) )
{
viewUrls . remove ( * it ) ; // don't open if it is open already
it = urlsToClose . remove ( it ) ;
- - it ; // do not skip one
}
}
if ( ! urlsToClose . empty ( ) )
{
partController ( ) - > closeFiles ( urlsToClose ) ;
}
}
// we open what still needs to get opened
FileInfoList : : const_iterator viewIt ;
for ( viewIt = viewUrls . begin ( ) ; viewIt ! = viewUrls . end ( ) ; + + viewIt )
{
if ( ! onlyProject | | ! project ( ) | | project ( ) - > isProjectFile ( ( * viewIt ) . url . path ( ) ) )
{
partController ( ) - > setEncoding ( ( * viewIt ) . encoding ) ;
partController ( ) - > editDocument ( ( * viewIt ) . url , ( * viewIt ) . line , ( * viewIt ) . col ) ;
}
}
}
adjustViewActions ( ) ;
}
void ProjectviewPart : : slotSaveProjectView ( )
{
slotSaveAsProjectView ( m_currentProjectView . isEmpty ( ) ) ;
}
void ProjectviewPart : : adjustViewActions ( )
{
TQStringList viewList = getViewList ( ) ;
m_openPrjViewAction - > clear ( ) ;
m_openPrjViewAction - > setItems ( viewList ) ;
int i = viewList . findIndex ( m_currentProjectView ) ;
if ( i > - 1 )
{
m_openPrjViewAction - > setCurrentItem ( i ) ;
}
m_deletePrjViewAction - > clear ( ) ;
m_deletePrjViewAction - > setItems ( viewList ) ;
m_currentProjectView = m_openPrjViewAction - > currentText ( ) ;
if ( m_currentProjectView . isEmpty ( ) & & ! viewList . empty ( ) )
{
m_currentProjectView = viewList . front ( ) ;
}
bool haveView = ! m_currentProjectView . isEmpty ( ) ;
m_savePrjViewAction - > setEnabled ( haveView ) ;
m_deleteCurrentPrjViewAction - > setEnabled ( haveView ) ;
}
void ProjectviewPart : : slotDeleteProjectViewCurent ( )
{
slotDeleteProjectView ( m_currentProjectView ) ;
}
void ProjectviewPart : : slotDeleteProjectView ( const TQString & view )
{
m_projectViews . remove ( view ) ;
if ( m_currentProjectView = = view )
m_currentProjectView = " " ;
if ( m_defaultProjectView = = view )
m_defaultProjectView = " " ;
if ( ! project ( ) )
writeConfig ( ) ;
adjustViewActions ( ) ;
}
void ProjectviewPart : : slotSaveAsProjectView ( bool askForName )
{
if ( askForName )
{
bool ok ;
TQString newProjectView = KInputDialog : : getText ( i18n ( " Save View Session As " ) , i18n ( " Enter the name of the session: " ) , " " , & ok , mainWindow ( ) - > main ( ) ) ;
if ( ! ok )
{
return ;
}
newProjectView = newProjectView . remove ( " = " ) ; // we use this string in config files and = would confuse it
if ( m_projectViews . contains ( newProjectView ) > 0 & &
KMessageBox : : warningContinueCancel ( mainWindow ( ) - > main ( ) , i18n ( " <qt>A view session named <b>%1</b> already exists.<br>Do you want to overwrite it?</qt> " ) . arg ( newProjectView ) , TQString ( ) , i18n ( " Overwrite " ) ) ! = KMessageBox : : Continue )
{
return ;
}
m_currentProjectView = newProjectView ;
}
FileInfoList viewUrls ;
KURL : : List openURLs = partController ( ) - > openURLs ( ) ;
for ( KURL : : List : : Iterator it = openURLs . begin ( ) ; it ! = openURLs . end ( ) ; + + it )
{
// test if we have an editor
// FIXME this can fail if there are two parts with the same URL
KParts : : ReadOnlyPart * ro_part = partController ( ) - > partForURL ( * it ) ;
KTextEditor : : ViewCursorInterface * cursorIf = dynamic_cast < KTextEditor : : ViewCursorInterface * > ( ro_part - > widget ( ) ) ;
if ( cursorIf )
{
TQString encoding ;
if ( KTextEditor : : EncodingInterface * ei = dynamic_cast < KTextEditor : : EncodingInterface * > ( ro_part ) )
{
TQString temp = ei - > encoding ( ) ;
if ( ! temp . isNull ( ) )
{
encoding = temp ;
}
}
unsigned int line , col ;
cursorIf - > cursorPositionReal ( & line , & col ) ;
viewUrls . append ( FileInfo ( * it , line , col , encoding ) ) ;
}
}
// add or overwrite the values
m_projectViews . insert ( m_currentProjectView , viewUrls , true ) ;
if ( ! project ( ) )
writeConfig ( ) ;
adjustViewActions ( ) ;
}
void ProjectviewPart : : writeConfig ( )
{
KConfig * config = kapp - > config ( ) ;
config - > deleteGroup ( " ProjectViews " , true ) ;
config - > setGroup ( " ProjectViews " ) ;
// write all views
ViewMap : : ConstIterator it ;
for ( it = m_projectViews . constBegin ( ) ; it ! = m_projectViews . constEnd ( ) ; + + it )
{
// we create the view even if there is no file inside, might be wanted by the user
TQStringList urls ;
for ( FileInfoList : : ConstIterator it2 = it . data ( ) . constBegin ( ) ; it2 ! = it . data ( ) . constEnd ( ) ; + + it2 )
{
if ( ( * it2 ) . encoding . isEmpty ( ) )
urls . append ( ( * it2 ) . url . url ( ) ) ;
else
urls . append ( ( * it2 ) . url . url ( ) + " ; " + ( * it2 ) . encoding ) ;
}
config - > writeEntry ( it . key ( ) , urls ) ;
}
}
void ProjectviewPart : : readConfig ( )
{
KConfig * config = kapp - > config ( ) ;
TQMap < TQString , TQString > entries = config - > entryMap ( " ProjectViews " ) ;
m_projectViews . clear ( ) ;
TQMap < TQString , TQString > : : ConstIterator it ;
for ( it = entries . constBegin ( ) ; it ! = entries . constEnd ( ) ; + + it )
{
FileInfoList urlList ;
TQStringList urls = TQStringList : : split ( " , " , it . data ( ) ) ;
for ( TQStringList : : Iterator it2 = urls . begin ( ) ; it2 ! = urls . end ( ) ; + + it2 )
{
// search the encoding. The entry can be like: fileURL;encoding
TQStringList file = TQStringList : : split ( " ; " , * it2 ) ;
if ( file . count ( ) = = 1 )
urlList . append ( FileInfo ( KURL : : fromPathOrURL ( * it2 ) ) ) ;
else
urlList . append ( FileInfo ( KURL : : fromPathOrURL ( file . first ( ) ) , - 1 , - 1 , file . last ( ) ) ) ;
}
m_projectViews . insert ( it . key ( ) , urlList ) ;
}
adjustViewActions ( ) ;
}
# include "projectviewpart.moc"