autobookmarker.cpp
00001 /* 00002 This library is free software you can redistribute it and/or 00003 modify it under the terms of the GNU Library General Public 00004 License. 00005 00006 This library is distributed in the hope that it will be useful, 00007 but WITHOUT ANY WARRANTY; without even the implied warranty of 00008 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00009 Library General Public License for more details. 00010 00011 You should have received a copy of the GNU Library General Public License 00012 along with this library; see the file COPYING.LIB. If not, write to 00013 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00014 Boston, MA 02110-1301, USA. 00015 00016 --- 00017 file: autobookmarker.cpp 00018 00019 KTextEditor plugin to add bookmarks to documents. 00020 Copyright Anders Lund <anders.lund@lund.tdcadsl.dk>, 2003 00021 */ 00022 00023 //BEGIN includes 00024 #include "autobookmarker.h" 00025 00026 #include <ktexteditor/markinterfaceextension.h> 00027 #include <ktexteditor/editinterface.h> 00028 #include <ktexteditor/documentinfo.h> 00029 #include <ktexteditor/document.h> 00030 00031 #include <kaction.h> 00032 #include <kapplication.h> 00033 #include <kconfig.h> 00034 #include <kgenericfactory.h> 00035 #include <kiconloader.h> 00036 #include <klistview.h> 00037 #include <klocale.h> 00038 #include <kmimetype.h> 00039 #include <kmimetypechooser.h> 00040 #include <kprocess.h> 00041 #include <krun.h> 00042 #include <kstaticdeleter.h> 00043 #include <kurl.h> 00044 00045 #include <tqcheckbox.h> 00046 #include <tqlabel.h> 00047 #include <tqlayout.h> 00048 #include <tqlineedit.h> 00049 #include <tqlistview.h> 00050 #include <tqpopupmenu.h> 00051 #include <tqpushbutton.h> 00052 #include <tqtoolbutton.h> 00053 #include <tqwhatsthis.h> 00054 #include <tqregexp.h> 00055 00056 //#include <kdebug.h> 00057 //END includes 00058 00059 //BEGIN AutoBookmarker 00060 K_EXPORT_COMPONENT_FACTORY( ktexteditor_autobookmarker, KGenericFactory<AutoBookmarker>( "ktexteditor_autobookmarker" ) ) 00061 00062 AutoBookmarker::AutoBookmarker( TQObject *parent, 00063 const char* name, 00064 const TQStringList& /*args*/ ) 00065 : KTextEditor::Plugin ( (KTextEditor::Document*) parent, name ), 00066 KTextEditor::ConfigInterfaceExtension() 00067 { 00068 if ( parent ) 00069 connect( parent, TQT_SIGNAL( completed() ), this, TQT_SLOT( slotCompleted() ) ); 00070 } 00071 00072 void AutoBookmarker::addView(KTextEditor::View */*view*/) 00073 { 00074 } 00075 00076 void AutoBookmarker::removeView(KTextEditor::View */*view*/) 00077 { 00078 } 00079 00080 KTextEditor::ConfigPage * AutoBookmarker::configPage( uint /*number*/, TQWidget *parent, const char *name ) 00081 { 00082 return new AutoBookmarkerConfigPage( parent, name ); 00083 } 00084 00085 TQString AutoBookmarker::configPageName( uint /*p*/ ) const 00086 { 00087 // switch (p) 00088 // { 00089 // case 0: 00090 return i18n("AutoBookmarks"); 00091 // default: 00092 // return ""; 00093 // } 00094 } 00095 00096 TQString AutoBookmarker::configPageFullName( uint /*p*/ ) const 00097 { 00098 // switch (p) 00099 // { 00100 // case 0: 00101 return i18n("Configure AutoBookmarks"); 00102 // default: 00103 // return ""; 00104 // } 00105 } 00106 00107 TQPixmap AutoBookmarker::configPagePixmap( uint /*p*/, int size ) const 00108 { 00109 return UserIcon("kte_bookmark", size); 00110 } 00111 00112 void AutoBookmarker::slotCompleted() 00113 { 00114 // get the document info 00115 KTextEditor::DocumentInfoInterface *di = 00116 ::tqqt_cast<KTextEditor::DocumentInfoInterface*>(document()); 00117 TQString mt; 00118 if ( di ) // we can still try match the URL otherwise 00119 mt = di->mimeType(); 00120 00121 TQString fileName; 00122 if ( document()->url().isValid() ) 00123 fileName = document()->url().fileName(); 00124 00125 ABEntityList *l = ABGlobal::self()->entities(); 00126 // for each item, if either mask matches 00127 // * apply if onLoad is true 00128 ABEntityListIterator it( *l ); 00129 int n( 0 ); 00130 bool found; 00131 AutoBookmarkEnt *e; 00132 while ( ( e = it.current() ) != 0 ) 00133 { 00134 found = ( !e->mimemask.count() && !e->filemask.count() ); // no preferences 00135 if ( ! found ) 00136 found = ( ! mt.isEmpty() && e->mimemask.contains( mt ) ); 00137 if ( ! found ) 00138 for( TQStringList::Iterator it1 = e->filemask.begin(); it1 != e->filemask.end(); ++it1 ) 00139 { 00140 TQRegExp re(*it1, true, true); 00141 if ( ( found = ( ( re.search( fileName ) > -1 ) && ( re.matchedLength() == (int)fileName.length() ) ) ) ) 00142 break; 00143 } 00144 00145 if ( found ) 00146 applyEntity( e ); 00147 00148 n++; 00149 ++it; 00150 } 00151 00152 } 00153 00154 void AutoBookmarker::applyEntity( AutoBookmarkEnt *e ) 00155 { 00156 KTextEditor::Document *doc = document(); 00157 KTextEditor::EditInterface *ei = KTextEditor::editInterface( doc ); 00158 KTextEditor::MarkInterface *mi = KTextEditor::markInterface( doc ); 00159 00160 if ( ! ( ei && mi ) ) return; 00161 00162 TQRegExp re( e->pattern, e->flags & AutoBookmarkEnt::CaseSensitive ); 00163 re.setMinimal( e->flags & AutoBookmarkEnt::MinimalMatching ); 00164 00165 for ( uint l( 0 ); l < ei->numLines(); l++ ) 00166 if ( re.search( ei->textLine( l ) ) > -1 ) 00167 mi->setMark( l, KTextEditor::MarkInterface::Bookmark ); 00168 } 00169 00170 //END 00171 00172 //BEGIN ABGlobal 00173 ABGlobal *ABGlobal::s_self = 0; 00174 00175 ABGlobal::ABGlobal() 00176 { 00177 m_ents = new ABEntityList; 00178 readConfig(); 00179 } 00180 00181 ABGlobal::~ABGlobal() 00182 { 00183 delete m_ents; 00184 } 00185 00186 static KStaticDeleter<ABGlobal> sdSelf; 00187 00188 ABGlobal *ABGlobal::self() 00189 { 00190 if ( ! s_self ) 00191 sdSelf.setObject(s_self, new ABGlobal()); 00192 00193 return s_self; 00194 } 00195 00196 void ABGlobal::readConfig() 00197 { 00198 if ( ! m_ents ) 00199 m_ents = new ABEntityList; 00200 else 00201 m_ents->clear(); 00202 KConfig *config = new KConfig("ktexteditor_autobookmarkerrc"); 00203 00204 uint n( 0 ); 00205 while ( config->hasGroup( TQString("autobookmark%1").arg( n ) ) ) 00206 { 00207 config->setGroup( TQString("autobookmark%1").arg( n ) ); 00208 TQStringList filemask = config->readListEntry( "filemask", ';' ); 00209 TQStringList mimemask = config->readListEntry( "mimemask", ';' ); 00210 int flags = config->readNumEntry( "flags", 1 ); 00211 AutoBookmarkEnt *e = new AutoBookmarkEnt( 00212 config->readEntry( "pattern", "" ), 00213 filemask, 00214 mimemask, 00215 flags 00216 ); 00217 00218 m_ents->append( e ); 00219 00220 ++n; 00221 } 00222 00223 delete config; 00224 } 00225 00226 void ABGlobal::writeConfig() 00227 { 00228 KConfig *config = new KConfig("ktexteditor_autobookmarkerrc"); 00229 00230 // clean the config object 00231 TQStringList l = config->groupList(); 00232 for ( TQStringList::Iterator it = l.begin(); it != l.end(); ++it ) 00233 config->deleteGroup( *it ); 00234 00235 // fill in the current list 00236 for ( uint i = 0; i < m_ents->count(); i++ ) 00237 { 00238 AutoBookmarkEnt *e = m_ents->at( i ); 00239 config->setGroup( TQString("autobookmark%1").arg( i ) ); 00240 config->writeEntry( "pattern", e->pattern ); 00241 config->writeEntry( "filemask", e->filemask, ';' ); 00242 config->writeEntry( "mimemask", e->mimemask, ';' ); 00243 config->writeEntry( "flags", e->flags ); 00244 } 00245 00246 config->sync(); // explicit -- this is supposedly handled by the d'tor 00247 delete config; 00248 } 00249 //END ABGlobal 00250 00251 //BEGIN AutoBookmarkEntItem 00252 // A QListviewItem which can hold a AutoBookmarkEnt pointer 00253 class AutoBookmarkEntItem : public QListViewItem 00254 { 00255 public: 00256 AutoBookmarkEntItem( KListView *lv, AutoBookmarkEnt *e ) 00257 : TQListViewItem( lv ), 00258 ent( e ) 00259 { 00260 redo(); 00261 }; 00262 ~AutoBookmarkEntItem(){}; 00263 void redo() 00264 { 00265 setText( 0, ent->pattern ); 00266 setText( 1, ent->mimemask.join("; ") ); 00267 setText( 2, ent->filemask.join("; ") ); 00268 } 00269 AutoBookmarkEnt *ent; 00270 }; 00271 //END 00272 00273 //BEGIN AutoBookmarkerEntEditor 00274 // Dialog for editing a single autobookmark entity 00275 // * edit the pattern 00276 // * set the file/mime type masks 00277 AutoBookmarkerEntEditor::AutoBookmarkerEntEditor( TQWidget *parent, AutoBookmarkEnt *e ) 00278 : KDialogBase( parent, "autobookmark_ent_editor", 00279 true, i18n("Edit Entry"), 00280 KDialogBase::Ok|KDialogBase::Cancel ), 00281 e( e ) 00282 { 00283 TQFrame *w = makeMainWidget(); 00284 TQGridLayout * lo = new TQGridLayout( w, 5, 3 ); 00285 lo->setSpacing( KDialogBase::spacingHint() ); 00286 00287 TQLabel *l = new TQLabel( i18n("&Pattern:"), w ); 00288 lePattern = new TQLineEdit( e->pattern, w ); 00289 l->setBuddy( lePattern ); 00290 lo->addWidget( l, 0, 0 ); 00291 lo->addMultiCellWidget( lePattern, 0, 0, 1, 2 ); 00292 TQWhatsThis::add( lePattern, i18n( 00293 "<p>A regular expression. Matching lines will be bookmarked.</p>" ) ); 00294 00295 connect( lePattern, TQT_SIGNAL(textChanged ( const TQString & ) ),this, TQT_SLOT( slotPatternChanged( const TQString& ) ) ); 00296 00297 cbCS = new TQCheckBox( i18n("Case &sensitive"), w ); 00298 lo->addMultiCellWidget( cbCS, 1, 1, 0, 2 ); 00299 cbCS->setChecked( e->flags & AutoBookmarkEnt::CaseSensitive ); 00300 TQWhatsThis::add( cbCS, i18n( 00301 "<p>If enabled, the pattern matching will be case sensitive, otherwise " 00302 "not.</p>") ); 00303 00304 cbMM = new TQCheckBox( i18n("&Minimal matching"), w ); 00305 lo->addMultiCellWidget( cbMM, 2, 2, 0 ,2 ); 00306 cbMM->setChecked( e->flags & AutoBookmarkEnt::MinimalMatching ); 00307 TQWhatsThis::add( cbMM, i18n( 00308 "<p>If enabled, the pattern matching will use minimal matching; if you " 00309 "do not know what that is, please read the appendix on regular expressions " 00310 "in the kate manual.</p>") ); 00311 00312 l = new TQLabel( i18n("&File mask:"), w ); 00313 leFileMask = new TQLineEdit( e->filemask.join( "; " ), w ); 00314 l->setBuddy( leFileMask ); 00315 lo->addWidget( l, 3, 0 ); 00316 lo->addMultiCellWidget( leFileMask, 3, 3, 1, 2 ); 00317 TQWhatsThis::add( leFileMask, i18n( 00318 "<p>A list of filename masks, separated by semicolons. This can be used " 00319 "to limit the usage of this entity to files with matching names.</p>" 00320 "<p>Use the wizard button to the right of the mimetype entry below to " 00321 "easily fill out both lists.</p>" ) ); 00322 00323 l = new TQLabel( i18n("MIME &types:"), w ); 00324 leMimeTypes = new TQLineEdit( e->mimemask.join( "; " ), w ); 00325 l->setBuddy( leMimeTypes ); 00326 lo->addWidget( l, 4, 0 ); 00327 lo->addWidget( leMimeTypes, 4, 1 ); 00328 TQWhatsThis::add( leMimeTypes, i18n( 00329 "<p>A list of mime types, separated by semicolon. This can be used to " 00330 "limit the usage of this entity to files with matching mime types.</p>" 00331 "<p>Use the wizard button on the right to get a list of existing file " 00332 "types to choose from, using it will fill in the file masks as well.</p>" ) ); 00333 00334 TQToolButton *btnMTW = new TQToolButton(w); 00335 lo->addWidget( btnMTW, 4, 2 ); 00336 btnMTW->setIconSet(TQIconSet(SmallIcon("wizard"))); 00337 connect(btnMTW, TQT_SIGNAL(clicked()), this, TQT_SLOT(showMTDlg())); 00338 TQWhatsThis::add( btnMTW, i18n( 00339 "<p>Click this button to display a checkable list of mimetypes available " 00340 "on your system. When used, the file masks entry above will be filled in " 00341 "with the corresponding masks.</p>") ); 00342 slotPatternChanged( lePattern->text() ); 00343 } 00344 00345 void AutoBookmarkerEntEditor::slotPatternChanged( const TQString&_pattern ) 00346 { 00347 enableButtonOK( !_pattern.isEmpty() ); 00348 } 00349 00350 void AutoBookmarkerEntEditor::apply() 00351 { 00352 if ( lePattern->text().isEmpty() ) return; 00353 00354 e->pattern = lePattern->text(); 00355 e->filemask = TQStringList::split( TQRegExp("\\s*;\\s*"), leFileMask->text() ); 00356 e->mimemask = TQStringList::split( TQRegExp("\\s*;\\s*"), leMimeTypes->text() ); 00357 e->flags = 0; 00358 if ( cbCS->isOn() ) e->flags |= AutoBookmarkEnt::CaseSensitive; 00359 if ( cbMM->isOn() ) e->flags |= AutoBookmarkEnt::MinimalMatching; 00360 } 00361 00362 void AutoBookmarkerEntEditor::showMTDlg() 00363 { 00364 TQString text = i18n("Select the MimeTypes for this pattern.\nPlease note that this will automatically edit the associated file extensions as well."); 00365 TQStringList list = TQStringList::split( TQRegExp("\\s*;\\s*"), leMimeTypes->text() ); 00366 KMimeTypeChooserDialog d( i18n("Select Mime Types"), text, list, "text", this ); 00367 if ( d.exec() == KDialogBase::Accepted ) { 00368 // do some checking, warn user if mime types or patterns are removed. 00369 // if the lists are empty, and the fields not, warn. 00370 leFileMask->setText(d.chooser()->patterns().join("; ")); 00371 leMimeTypes->setText(d.chooser()->mimeTypes().join("; ")); 00372 } 00373 } 00374 //END 00375 00376 //BEGIN AutoBookmarkerConfigPage 00377 // TODO allow custom mark types with icons 00378 AutoBookmarkerConfigPage::AutoBookmarkerConfigPage( TQWidget *parent, const char *name ) 00379 : KTextEditor::ConfigPage( parent, name ) 00380 { 00381 TQVBoxLayout *lo = new TQVBoxLayout( this ); 00382 lo->setSpacing( KDialogBase::spacingHint() ); 00383 00384 TQLabel *l = new TQLabel( i18n("&Patterns"), this ); 00385 lo->addWidget( l ); 00386 lvPatterns = new KListView( this ); 00387 lvPatterns->addColumn( i18n("Pattern") ); 00388 lvPatterns->addColumn( i18n("Mime Types") ); 00389 lvPatterns->addColumn( i18n("File Masks") ); 00390 lo->addWidget( lvPatterns ); 00391 l->setBuddy( lvPatterns ); 00392 TQWhatsThis::add( lvPatterns, i18n( 00393 "<p>This list shows your configured autobookmark entities. When a document " 00394 "is opened, each entity is used in the following way: " 00395 "<ol>" 00396 "<li>The entity is dismissed, if a mime and/or filename mask is defined, " 00397 "and neither matches the document.</li>" 00398 "<li>Otherwise each line of the document is tried against the pattern, " 00399 "and a bookmark is set on matching lines.</li></ul>" 00400 "<p>Use the buttons below to manage your collection of entities.</p>") ); 00401 00402 TQHBoxLayout *lo1 = new TQHBoxLayout ( lo ); 00403 lo1->setSpacing( KDialogBase::spacingHint() ); 00404 00405 btnNew = new TQPushButton( i18n("&New..."), this ); 00406 lo1->addWidget( btnNew ); 00407 TQWhatsThis::add( btnNew, i18n( 00408 "Press this button to create a new autobookmark entity.") ); 00409 00410 btnDel = new TQPushButton( i18n("&Delete"), this ); 00411 lo1->addWidget( btnDel ); 00412 TQWhatsThis::add( btnDel, i18n( 00413 "Press this button to delete the currently selected entity.") ); 00414 00415 btnEdit = new TQPushButton( i18n("&Edit..."), this ); 00416 lo1->addWidget( btnEdit ); 00417 TQWhatsThis::add( btnEdit, i18n( 00418 "Press this button to edit the currently selected entity.") ); 00419 00420 lo1->addStretch( 1 ); 00421 00422 connect( btnNew, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotNew()) ); 00423 connect( btnDel, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotDel()) ); 00424 connect( btnEdit, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotEdit()) ); 00425 connect( lvPatterns, TQT_SIGNAL(doubleClicked(TQListViewItem *)), this, TQT_SLOT(slotEdit()) ); 00426 00427 m_ents = new ABEntityList(); 00428 m_ents->setAutoDelete( true ); 00429 reset(); 00430 } 00431 00432 // replace the global list with the new one 00433 void AutoBookmarkerConfigPage::apply() 00434 { 00435 ABGlobal::self()->entities()->clear(); 00436 00437 ABEntityListIterator it ( *m_ents ); 00438 AutoBookmarkEnt *e; 00439 00440 while ( (e = it.current()) != 0 ) 00441 { 00442 ABGlobal::self()->entities()->append( e ); 00443 ++it; 00444 } 00445 00446 ABGlobal::self()->writeConfig(); 00447 00448 // TODO -- how do i refresh all the view menus 00449 } 00450 00451 // renew our copy of the global list 00452 void AutoBookmarkerConfigPage::reset() 00453 { 00454 m_ents->clear(); // unused - no reset button currently 00455 00456 ABEntityListIterator it ( *ABGlobal::self()->entities() ); 00457 AutoBookmarkEnt *e; 00458 while ( (e = it.current()) != 0 ) 00459 { 00460 AutoBookmarkEnt *me = new AutoBookmarkEnt( *e ); 00461 m_ents->append( me ); 00462 new AutoBookmarkEntItem( lvPatterns, me ); 00463 ++it; 00464 } 00465 } 00466 00467 // TODO (so far not used) we have no defaults (except deleting all items??) 00468 void AutoBookmarkerConfigPage::defaults() 00469 { 00470 // if KMessageBox::warningYesNo() 00471 // clear all 00472 } 00473 00474 // open the edit dialog with a new entity, 00475 // and add it if the dialog is accepted 00476 void AutoBookmarkerConfigPage::slotNew() 00477 { 00478 AutoBookmarkEnt *e = new AutoBookmarkEnt(); 00479 AutoBookmarkerEntEditor dlg( this, e ); 00480 if ( dlg.exec() ) 00481 { 00482 dlg.apply(); 00483 new AutoBookmarkEntItem( lvPatterns, e ); 00484 m_ents->append( e ); 00485 } 00486 } 00487 00488 // delete the selected item and remove it from the list view and internal list 00489 void AutoBookmarkerConfigPage::slotDel() 00490 { 00491 AutoBookmarkEntItem *i = (AutoBookmarkEntItem*)lvPatterns->currentItem(); 00492 int idx = m_ents->findRef( i->ent ); 00493 m_ents->remove( idx ); 00494 delete i; 00495 } 00496 00497 // open the edit dialog with the selected item 00498 void AutoBookmarkerConfigPage::slotEdit() 00499 { 00500 AutoBookmarkEnt *e = ((AutoBookmarkEntItem*)lvPatterns->currentItem())->ent; 00501 AutoBookmarkerEntEditor dlg( this, e ); 00502 if ( dlg.exec() ) 00503 { 00504 dlg.apply(); 00505 ((AutoBookmarkEntItem*)lvPatterns->currentItem())->redo(); 00506 } 00507 } 00508 //END AutoBookmarkerConfigPage 00509 00510 //BEGIN AutoBookmarkEnt 00511 AutoBookmarkEnt::AutoBookmarkEnt( const TQString &p, const TQStringList &f, const TQStringList &m, int fl ) 00512 : pattern( p ), 00513 filemask( f ), 00514 mimemask( m ), 00515 flags( fl ) 00516 {; 00517 } 00518 //END 00519 // 00520 #include "autobookmarker.moc"