/*************************************************************************** * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "domutil.h" #include "bookmarks_widget.h" #include "bookmarks_part.h" #include "bookmarks_settings.h" #include "bookmarks_config.h" #include #include #define BOOKMARKSETTINGSPAGE 1 typedef TDevGenericFactory BookmarksFactory; static const TDevPluginInfo data("tdevbookmarks"); K_EXPORT_COMPONENT_FACTORY( libtdevbookmarks, BookmarksFactory( data ) ) BookmarksPart::BookmarksPart(TQObject *parent, const char *name, const TQStringList& ) : TDevPlugin(&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("Bookmarks

" "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( 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( 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( sender() )); if ( KParts::ReadOnlyPart * ro_part = dynamic_cast( senderobj ) ) { if ( partIsSane( ro_part ) ) { setBookmarksForURL( ro_part ); } } } void BookmarksPart::marksEvent() { //kdDebug(0) << "BookmarksPart::marksEvent()" << endl; if ( ! _settingMarks ) { TQObject * senderobj = TQT_TQOBJECT(const_cast( sender() )); KParts::ReadOnlyPart * ro_part = dynamic_cast( 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 it = _dirtyParts.begin(); while ( it != _dirtyParts.end() ) { KParts::ReadOnlyPart * ro_part = *it; if ( partIsSane( ro_part ) ) { if ( dynamic_cast( 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 it( _editorMap ); while ( it.current() ) { TQDomElement bookmark = domDoc.createElement( "bookmark" ); bookmark.setAttribute( "url", it.current()->url.path() ); bookmarksList.appendChild( bookmark ); TQValueListIterator< TQPair > 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 > 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( ro_part ); EditorData * data = _editorMap.find( ro_part->url().path() ); if ( ! ( data && ed ) ) return; TQValueListIterator< TQPair > 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 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(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 > 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(ro_part) ) { _settingMarks = true; TQPtrList marks = mi->marks(); TQPtrListIterator 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( 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 marks = mi->marks(); TQPtrListIterator 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 * partlist = partController()->parts() ) { TQPtrListIterator it( *partlist ); while ( KParts::Part* part = it.current() ) { if ( KParts::ReadOnlyPart * ro_part = dynamic_cast( part ) ) { setBookmarksForURL( ro_part ); } ++it; } } } void BookmarksPart::storeBookmarksForAllURLs() { if( const TQPtrList * partlist = partController()->parts() ) { TQPtrListIterator it( *partlist ); while ( KParts::Part* part = it.current() ) { if ( KParts::ReadOnlyPart * ro_part = dynamic_cast( part ) ) { storeBookmarksForURL( ro_part ); } ++it; } } } // reimplemented from PartController::partForURL to avoid linking KParts::ReadOnlyPart * BookmarksPart::partForURL( KURL const & url ) { TQPtrListIterator it( *partController()->parts() ); while( it.current() ) { KParts::ReadOnlyPart *ro_part = dynamic_cast(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( 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" // kate: space-indent off; indent-width 4; tab-width 4; show-tabs off;