You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdevelop/parts/bookmarks/bookmarks_part.cpp

567 lines
15 KiB

/***************************************************************************
* Copyright (C) 2003 by Jens Dagerbo *
* jens.dagerbo@swipnet.se *
* *
* 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. *
* *
***************************************************************************/
#include <tqwhatsthis.h>
#include <tqvbox.h>
#include <tqtimer.h>
#include <tqtextstream.h>
#include <tqfile.h>
#include <kdebug.h>
#include <kiconloader.h>
#include <tdelocale.h>
#include <kdevgenericfactory.h>
#include <tdetexteditor/markinterface.h>
#include <tdetexteditor/editinterface.h>
#include <tdetexteditor/document.h>
#include <tdeaction.h>
#include <kdialogbase.h>
#include <kdevpartcontroller.h>
#include <kdevcore.h>
#include <kdevmainwindow.h>
#include "domutil.h"
#include "bookmarks_widget.h"
#include "bookmarks_part.h"
#include "bookmarks_settings.h"
#include "bookmarks_config.h"
#include <configwidgetproxy.h>
#include <kdevplugininfo.h>
#define BOOKMARKSETTINGSPAGE 1
typedef KDevGenericFactory<BookmarksPart> BookmarksFactory;
static const KDevPluginInfo data("kdevbookmarks");
K_EXPORT_COMPONENT_FACTORY( libkdevbookmarks, BookmarksFactory( data ) )
BookmarksPart::BookmarksPart(TQObject *parent, const char *name, const TQStringList& )
: KDevPlugin(&data, parent, name ? name : "BookmarksPart" )
{
setInstance(BookmarksFactory::instance());
_widget = new BookmarksWidget(this);
_widget->setCaption(i18n("Bookmarks"));
_widget->setIcon(SmallIcon( info()->icon() ));
_marksChangeTimer = new TQTimer( this );
TQWhatsThis::add(_widget, i18n("<b>Bookmarks</b><p>"
"The bookmark viewer shows all the source bookmarks in the project."));
mainWindow()->embedSelectView(_widget, i18n("Bookmarks"), i18n("Source bookmarks"));
_editorMap.setAutoDelete( true );
_settingMarks = false;
connect( partController(), TQT_SIGNAL( partAdded( KParts::Part * ) ), this, TQT_SLOT( partAdded( KParts::Part * ) ) );
_configProxy = new ConfigWidgetProxy( core() );
_configProxy->createProjectConfigPage( i18n("Bookmarks"), BOOKMARKSETTINGSPAGE, info()->icon() );
connect( _configProxy, TQT_SIGNAL(insertConfigWidget(const KDialogBase*, TQWidget*, unsigned int )),
this, TQT_SLOT(insertConfigWidget(const KDialogBase*, TQWidget*, unsigned int )) );
connect( _widget, TQT_SIGNAL( removeAllBookmarksForURL( const KURL & ) ),
this, TQT_SLOT( removeAllBookmarksForURL( const KURL & ) ) );
connect( _widget, TQT_SIGNAL( removeBookmarkForURL( const KURL &, int ) ),
this, TQT_SLOT( removeBookmarkForURL( const KURL &, int ) ) );
connect( _marksChangeTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( marksChanged() ) );
_config = new BookmarksConfig;
_config->readConfig();
storeBookmarksForAllURLs();
updateContextStringForAll();
_widget->update( _editorMap );
}
BookmarksPart::~BookmarksPart()
{
if( _widget ) {
mainWindow()->removeView( _widget );
delete _widget;
}
delete _config;
delete _configProxy;
}
void BookmarksPart::partAdded( KParts::Part * part )
{
//kdDebug(0) << "BookmarksPart::partAdded()" << endl;
if ( KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart *>( part ) )
{
if ( setBookmarksForURL( ro_part ) )
{
updateContextStringForURL( ro_part );
if ( EditorData * data = _editorMap.find( ro_part->url().path() ) )
{
_widget->updateURL( data );
}
// connect to this editor
KTextEditor::Document * doc = static_cast<KTextEditor::Document*>( ro_part );
connect( doc, TQT_SIGNAL( marksChanged() ), this, TQT_SLOT( marksEvent() ) );
// workaround for a katepart oddity where it drops all bookmarks on 'reload'
connect( doc, TQT_SIGNAL( completed() ), this, TQT_SLOT( reload() ) );
}
}
}
void BookmarksPart::reload()
{
//kdDebug(0) << "BookmarksPart::reload()" << endl;
TQObject * senderobj = TQT_TQOBJECT(const_cast<TQT_BASE_OBJECT_NAME*>( sender() ));
if ( KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart *>( senderobj ) )
{
if ( partIsSane( ro_part ) )
{
setBookmarksForURL( ro_part );
}
}
}
void BookmarksPart::marksEvent()
{
//kdDebug(0) << "BookmarksPart::marksEvent()" << endl;
if ( ! _settingMarks )
{
TQObject * senderobj = TQT_TQOBJECT(const_cast<TQT_BASE_OBJECT_NAME*>( sender() ));
KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart *>( senderobj );
if ( partIsSane( ro_part ) && !_dirtyParts.contains( ro_part ) )
{
_dirtyParts.push_back( ro_part );
_marksChangeTimer->start( 1000, true );
}
}
}
void BookmarksPart::marksChanged()
{
//kdDebug(0) << "BookmarksPart::marksChanged()" << endl;
TQValueListIterator<KParts::ReadOnlyPart*> it = _dirtyParts.begin();
while ( it != _dirtyParts.end() )
{
KParts::ReadOnlyPart * ro_part = *it;
if ( partIsSane( ro_part ) )
{
if ( dynamic_cast<KTextEditor::MarkInterface*>( ro_part ) )
{
if ( EditorData * data = storeBookmarksForURL( ro_part ) )
{
updateContextStringForURL( ro_part );
_widget->updateURL( data );
}
else
{
_widget->removeURL( ro_part->url() );
}
}
}
++it;
}
_dirtyParts.clear();
}
void BookmarksPart::restorePartialProjectSession( const TQDomElement * el )
{
//kdDebug(0) << "BookmarksPart::restorePartialProjectSession()" << endl;
if ( ! el ) return;
TQDomElement bookmarksList = el->namedItem( "bookmarks" ).toElement();
if ( bookmarksList.isNull() ) return;
TQDomElement bookmark = bookmarksList.firstChild().toElement();
while ( ! bookmark.isNull() )
{
TQString path = bookmark.attribute( "url" );
if ( path != TQString() )
{
EditorData * data = new EditorData;
data->url.setPath( path );
TQDomElement mark = bookmark.firstChild().toElement();
while ( ! mark.isNull() )
{
TQString line = mark.attribute( "line" );
if ( line != TQString() )
{
data->marks.append( tqMakePair( line.toInt(), TQString() ) );
}
mark = mark.nextSibling().toElement();
}
if ( ! data->marks.isEmpty() )
{
_editorMap.insert( data->url.path(), data );
}
else
{
delete data;
}
}
bookmark = bookmark.nextSibling().toElement();
}
setBookmarksForAllURLs();
updateContextStringForAll();
_widget->update( _editorMap );
}
void BookmarksPart::savePartialProjectSession( TQDomElement * el )
{
//kdDebug(0) << "BookmarksPart::savePartialProjectSession()" << endl;
if ( ! el ) return;
TQDomDocument domDoc = el->ownerDocument();
if ( domDoc.isNull() ) return;
TQDomElement bookmarksList = domDoc.createElement( "bookmarks" );
TQDictIterator<EditorData> it( _editorMap );
while ( it.current() )
{
TQDomElement bookmark = domDoc.createElement( "bookmark" );
bookmark.setAttribute( "url", it.current()->url.path() );
bookmarksList.appendChild( bookmark );
TQValueListIterator< TQPair<int,TQString> > it2 = it.current()->marks.begin();
while ( it2 != it.current()->marks.end() )
{
TQDomElement line = domDoc.createElement( "mark" );
line.setAttribute( "line", (*it2).first );
bookmark.appendChild( line );
++it2;
}
++it;
}
if ( ! bookmarksList.isNull() )
{
el->appendChild( bookmarksList );
}
}
void BookmarksPart::removeAllBookmarksForURL( KURL const & url )
{
//kdDebug(0) << "BookmarksPart::removeAllBookmarksForURL()" << endl;
_editorMap.remove( url.path() );
setBookmarksForURL( partForURL( url ) );
_widget->removeURL( url );
}
void BookmarksPart::removeBookmarkForURL( KURL const & url, int line )
{
//kdDebug(0) << "BookmarksPart::removeBookmarkForURL()" << endl;
if ( EditorData * data = _editorMap.find( url.path() ) )
{
TQValueListIterator< TQPair<int,TQString> > it = data->marks.begin();
while ( it != data->marks.end() )
{
if ( (*it).first == line )
{
data->marks.remove( it );
break;
}
++it;
}
if ( data->marks.isEmpty() )
{
removeAllBookmarksForURL( url );
}
else
{
setBookmarksForURL( partForURL( url ) );
_widget->updateURL( data );
}
}
}
void BookmarksPart::updateContextStringForURL( KParts::ReadOnlyPart * ro_part )
{
if ( ! ro_part ) return;
KTextEditor::EditInterface * ed =
dynamic_cast<KTextEditor::EditInterface *>( ro_part );
EditorData * data = _editorMap.find( ro_part->url().path() );
if ( ! ( data && ed ) ) return;
TQValueListIterator< TQPair<int,TQString> > it = data->marks.begin();
while ( it != data->marks.end() )
{
(*it).second = ed->textLine( (*it).first );
++it;
}
}
void BookmarksPart::updateContextStringForURL( KURL const & url )
{
updateContextStringForURL( partForURL( url ) );
}
void BookmarksPart::updateContextStringForAll()
{
TQDictIterator<EditorData> it( _editorMap );
while ( it.current() )
{
if ( ! it.current()->marks.isEmpty() )
{
updateContextStringForURL( it.current()->url );
}
++it;
}
}
bool BookmarksPart::setBookmarksForURL( KParts::ReadOnlyPart * ro_part )
{
if ( KTextEditor::MarkInterface * mi = dynamic_cast<KTextEditor::MarkInterface *>(ro_part) )
{
clearBookmarksForURL( ro_part );
_settingMarks = true;
if ( EditorData * data = _editorMap.find( ro_part->url().path() ) )
{
// we've seen this one before, apply stored bookmarks
TQValueListIterator< TQPair<int,TQString> > it = data->marks.begin();
while ( it != data->marks.end() )
{
mi->addMark( (*it).first, KTextEditor::MarkInterface::markType01 );
++it;
}
}
_settingMarks = false;
// true == this is a MarkInterface
return true;
}
return false;
}
// Note: This method is only a convenience method to clear the bookmark marks,
// the way a hypothetical KTextEditor::MarkInterface::clearMarks( uint markType )
// would work.
bool BookmarksPart::clearBookmarksForURL( KParts::ReadOnlyPart * ro_part )
{
if ( KTextEditor::MarkInterface * mi = dynamic_cast<KTextEditor::MarkInterface *>(ro_part) )
{
_settingMarks = true;
TQPtrList<KTextEditor::Mark> marks = mi->marks();
TQPtrListIterator<KTextEditor::Mark> it( marks );
while ( it.current() )
{
if ( it.current()->type & KTextEditor::MarkInterface::markType01 )
{
mi->removeMark( it.current()->line, KTextEditor::MarkInterface::markType01 );
}
++it;
}
_settingMarks = false;
// true == this is a MarkInterface
return true;
}
return false;
}
EditorData * BookmarksPart::storeBookmarksForURL( KParts::ReadOnlyPart * ro_part )
{
//kdDebug(0) << "BookmarksPart::storeBookmarksForURL()" << endl;
if ( KTextEditor::MarkInterface * mi = dynamic_cast<KTextEditor::MarkInterface *>( ro_part ) )
{
EditorData * data = new EditorData;
data->url = ro_part->url();
// removing previous data for this url, if any
_editorMap.remove( data->url.path() );
TQPtrList<KTextEditor::Mark> marks = mi->marks();
TQPtrListIterator<KTextEditor::Mark> it( marks );
while ( it.current() )
{
if ( it.current()->type & KTextEditor::MarkInterface::markType01 )
{
int line = it.current()->line;
data->marks.append( tqMakePair( line, TQString() ) );
}
++it;
}
if ( ! data->marks.isEmpty() )
{
_editorMap.insert( data->url.path(), data );
}
else
{
delete data;
data = 0;
}
return data;
}
return 0;
}
void BookmarksPart::setBookmarksForAllURLs()
{
if( const TQPtrList<KParts::Part> * partlist = partController()->parts() )
{
TQPtrListIterator<KParts::Part> it( *partlist );
while ( KParts::Part* part = it.current() )
{
if ( KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart *>( part ) )
{
setBookmarksForURL( ro_part );
}
++it;
}
}
}
void BookmarksPart::storeBookmarksForAllURLs()
{
if( const TQPtrList<KParts::Part> * partlist = partController()->parts() )
{
TQPtrListIterator<KParts::Part> it( *partlist );
while ( KParts::Part* part = it.current() )
{
if ( KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart *>( part ) )
{
storeBookmarksForURL( ro_part );
}
++it;
}
}
}
// reimplemented from PartController::partForURL to avoid linking
KParts::ReadOnlyPart * BookmarksPart::partForURL( KURL const & url )
{
TQPtrListIterator<KParts::Part> it( *partController()->parts() );
while( it.current() )
{
KParts::ReadOnlyPart *ro_part = dynamic_cast<KParts::ReadOnlyPart*>(it.current());
if (ro_part && url == ro_part->url())
{
return ro_part;
}
++it;
}
return 0;
}
bool BookmarksPart::partIsSane( KParts::ReadOnlyPart * ro_part )
{
return ( ro_part != 0 ) &&
partController()->parts()->contains( ro_part) &&
!ro_part->url().path().isEmpty();
}
void BookmarksPart::insertConfigWidget( const KDialogBase * dlg, TQWidget * page, unsigned int pagenumber )
{
kdDebug() << k_funcinfo << endl;
if ( pagenumber == BOOKMARKSETTINGSPAGE )
{
BookmarkSettings * w = new BookmarkSettings( this, page );
connect( dlg, TQT_SIGNAL(okClicked()), w, TQT_SLOT(slotAccept()) );
}
}
////////////////////////////////////////////
TQStringList BookmarksPart::getContextFromStream( TQTextStream & istream, unsigned int line, unsigned int context )
{
kdDebug() << k_funcinfo << endl;
int startline = context > line ? 0 : line - context;
int endline = line + context;
int n = 0;
TQStringList list;
while ( !istream.atEnd() )
{
TQString templine = istream.readLine();
if ( (n >= startline) && ( n <= endline ) )
{
list << templine;
}
n++;
}
// maybe pad empty lines to the tail
while( n < endline )
{
list.append( " " );
n++;
}
// maybe pad empty lines to the head
while( list.count() < ( context * 2 + 1) )
{
list.prepend( " " );
}
return list;
}
TQStringList BookmarksPart::getContext( KURL const & url, unsigned int line, unsigned int context )
{
// if the file is open - get the line from the editor buffer
if ( KTextEditor::EditInterface * ei = dynamic_cast<KTextEditor::EditInterface*>( partForURL( url ) ) )
{
kdDebug() << "the file is open - get the line from the editor buffer" << endl;
TQString ibuffer = ei->text();
TQTextStream istream( &ibuffer, IO_ReadOnly );
return getContextFromStream( istream, line, context );
}
else if ( url.isLocalFile() ) // else the file is not open - get the line from the file on disk
{
kdDebug() << "the file is not open - get the line from the file on disk" << endl;
TQFile file( url.path() );
TQString buffer;
if ( file.open( IO_ReadOnly ) )
{
TQTextStream istream( &file );
return getContextFromStream( istream, line, context );
}
}
return TQStringList( i18n("Could not find file") );
}
BookmarksConfig * BookmarksPart::config( )
{
return _config;
}
#include "bookmarks_part.moc"