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.
567 lines
15 KiB
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 pluginData("kdevbookmarks");
|
|
K_EXPORT_COMPONENT_FACTORY( libkdevbookmarks, BookmarksFactory( pluginData ) )
|
|
|
|
BookmarksPart::BookmarksPart(TQObject *parent, const char *name, const TQStringList& )
|
|
: KDevPlugin(&pluginData, 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"
|