kate Library API Documentation

ISearchPlugin.cpp

00001 /* This file is part of the KDE libraries 00002 Copyright (C) 2002 by John Firebaugh <jfirebaugh@kde.org> 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License version 2 as published by the Free Software Foundation. 00007 00008 This library is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00011 Library General Public License for more details. 00012 00013 You should have received a copy of the GNU Library General Public License 00014 along with this library; see the file COPYING.LIB. If not, write to 00015 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00016 Boston, MA 02111-1307, USA. 00017 */ 00018 00019 #include <qlabel.h> 00020 #include <qregexp.h> 00021 #include <qstyle.h> 00022 #include <qpopupmenu.h> 00023 #include <kgenericfactory.h> 00024 #include <klocale.h> 00025 #include <kaction.h> 00026 #include <kcombobox.h> 00027 #include <kconfig.h> 00028 #include <kdebug.h> 00029 00030 #include "ISearchPlugin.h" 00031 #include "ISearchPlugin.moc" 00032 00033 K_EXPORT_COMPONENT_FACTORY( ktexteditor_isearch, KGenericFactory<ISearchPlugin>( "ktexteditor_isearch" ) ) 00034 00035 ISearchPluginView::ISearchPluginView( KTextEditor::View *view ) 00036 : QObject ( view ), KXMLGUIClient (view) 00037 , m_view( 0L ) 00038 , m_doc( 0L ) 00039 , m_searchIF( 0L ) 00040 , m_cursorIF( 0L ) 00041 , m_selectIF( 0L ) 00042 // , m_toolBarAction( 0L ) 00043 , m_searchForwardAction( 0L ) 00044 , m_searchBackwardAction( 0L ) 00045 , m_label( 0L ) 00046 , m_combo( 0L ) 00047 , m_lastString( "" ) 00048 , m_searchBackward( false ) 00049 , m_caseSensitive( false ) 00050 , m_fromBeginning( false ) 00051 , m_regExp( false ) 00052 , m_autoWrap( false ) 00053 , m_wrapped( false ) 00054 , m_startLine( 0 ) 00055 , m_startCol( 0 ) 00056 , m_searchLine( 0 ) 00057 , m_searchCol( 0 ) 00058 , m_foundLine( 0 ) 00059 , m_foundCol( 0 ) 00060 , m_matchLen( 0 ) 00061 , m_toolBarWasHidden( false ) 00062 { 00063 view->insertChildClient (this); 00064 00065 setInstance( KGenericFactory<ISearchPlugin>::instance() ); 00066 00067 m_searchForwardAction = new KAction( 00068 i18n("Search Incrementally"), CTRL+ALT+Key_F, 00069 this, SLOT(slotSearchForwardAction()), 00070 actionCollection(), "edit_isearch" ); 00071 m_searchBackwardAction = new KAction( 00072 i18n("Search Incrementally Backwards"), CTRL+ALT+SHIFT+Key_F, 00073 this, SLOT(slotSearchBackwardAction()), 00074 actionCollection(), "edit_isearch_reverse" ); 00075 00076 m_label = new QLabel( i18n("I-Search:"), 0L, "kde toolbar widget" ); 00077 KWidgetAction* labelAction = new KWidgetAction( 00078 m_label, 00079 i18n("I-Search:"), 0, 0, 0, 00080 actionCollection(), "isearch_label" ); 00081 labelAction->setShortcutConfigurable( false ); 00082 00083 m_combo = new KHistoryCombo(); 00084 m_combo->setDuplicatesEnabled( false ); 00085 m_combo->setMaximumWidth( 300 ); 00086 m_combo->lineEdit()->installEventFilter( this ); 00087 connect( m_combo, SIGNAL(textChanged(const QString&)), 00088 this, SLOT(slotTextChanged(const QString&)) ); 00089 connect( m_combo, SIGNAL(returnPressed(const QString&)), 00090 this, SLOT(slotReturnPressed(const QString&)) ); 00091 connect( m_combo, SIGNAL(aboutToShowContextMenu(QPopupMenu*)), 00092 this, SLOT(slotAddContextMenuItems(QPopupMenu*)) ); 00093 m_comboAction = new KWidgetAction( 00094 m_combo, 00095 i18n("Search"), 0, 0, 0, 00096 actionCollection(), "isearch_combo" ); 00097 m_comboAction->setAutoSized( true ); 00098 m_comboAction->setShortcutConfigurable( false ); 00099 00100 KActionMenu* optionMenu = new KActionMenu( 00101 i18n("Search Options"), "configure", 00102 actionCollection(), "isearch_options" ); 00103 optionMenu->setDelayed( false ); 00104 00105 KToggleAction* action = new KToggleAction( 00106 i18n("Case Sensitive"), KShortcut(), 00107 actionCollection(), "isearch_case_sensitive" ); 00108 action->setShortcutConfigurable( false ); 00109 connect( action, SIGNAL(toggled(bool)), 00110 this, SLOT(setCaseSensitive(bool)) ); 00111 action->setChecked( m_caseSensitive ); 00112 optionMenu->insert( action ); 00113 00114 action = new KToggleAction( 00115 i18n("From Beginning"), KShortcut(), 00116 actionCollection(), "isearch_from_beginning" ); 00117 action->setShortcutConfigurable( false ); 00118 connect( action, SIGNAL(toggled(bool)), 00119 this, SLOT(setFromBeginning(bool)) ); 00120 action->setChecked( m_fromBeginning ); 00121 optionMenu->insert( action ); 00122 00123 action = new KToggleAction( 00124 i18n("Regular Expression"), KShortcut(), 00125 actionCollection(), "isearch_reg_exp" ); 00126 action->setShortcutConfigurable( false ); 00127 connect( action, SIGNAL(toggled(bool)), 00128 this, SLOT(setRegExp(bool)) ); 00129 action->setChecked( m_regExp ); 00130 optionMenu->insert( action ); 00131 00132 // optionMenu->insert( new KActionSeparator() ); 00133 // 00134 // action = new KToggleAction( 00135 // i18n("Auto-Wrap Search"), KShortcut(), 00136 // actionCollection(), "isearch_auto_wrap" ); 00137 // connect( action, SIGNAL(toggled(bool)), 00138 // this, SLOT(setAutoWrap(bool)) ); 00139 // action->setChecked( m_autoWrap ); 00140 // optionMenu->insert( action ); 00141 00142 setXMLFile( "ktexteditor_isearchui.rc" ); 00143 } 00144 00145 ISearchPluginView::~ISearchPluginView() 00146 { 00147 writeConfig(); 00148 m_combo->lineEdit()->removeEventFilter( this ); 00149 delete m_combo; 00150 delete m_label; 00151 } 00152 00153 void ISearchPluginView::setView( KTextEditor::View* view ) 00154 { 00155 m_view = view; 00156 m_doc = m_view->document(); 00157 m_searchIF = KTextEditor::searchInterface ( m_doc ); 00158 m_cursorIF = KTextEditor::viewCursorInterface ( m_view ); 00159 m_selectIF = KTextEditor::selectionInterface ( m_doc ); 00160 if( !m_doc || !m_cursorIF || !m_selectIF ) { 00161 m_view = 0L; 00162 m_doc = 0L; 00163 m_searchIF = 0L; 00164 m_cursorIF = 0L; 00165 m_selectIF = 0L; 00166 } 00167 00168 readConfig(); 00169 } 00170 00171 void ISearchPluginView::readConfig() 00172 { 00173 // KConfig* config = instance()->config(); 00174 } 00175 00176 void ISearchPluginView::writeConfig() 00177 { 00178 // KConfig* config = instance()->config(); 00179 } 00180 00181 void ISearchPluginView::setCaseSensitive( bool caseSensitive ) 00182 { 00183 m_caseSensitive = caseSensitive; 00184 } 00185 00186 void ISearchPluginView::setFromBeginning( bool fromBeginning ) 00187 { 00188 m_fromBeginning = fromBeginning; 00189 00190 if( m_fromBeginning ) { 00191 m_searchLine = m_searchCol = 0; 00192 } 00193 } 00194 00195 void ISearchPluginView::setRegExp( bool regExp ) 00196 { 00197 m_regExp = regExp; 00198 } 00199 00200 void ISearchPluginView::setAutoWrap( bool autoWrap ) 00201 { 00202 m_autoWrap = autoWrap; 00203 } 00204 00205 bool ISearchPluginView::eventFilter( QObject* o, QEvent* e ) 00206 { 00207 if( o != m_combo->lineEdit() ) 00208 return false; 00209 00210 if( e->type() == QEvent::FocusIn ) { 00211 QFocusEvent* focusEvent = (QFocusEvent*)e; 00212 if( focusEvent->reason() == QFocusEvent::ActiveWindow || 00213 focusEvent->reason() == QFocusEvent::Popup ) 00214 return false; 00215 startSearch(); 00216 } 00217 00218 if( e->type() == QEvent::FocusOut ) { 00219 QFocusEvent* focusEvent = (QFocusEvent*)e; 00220 if( focusEvent->reason() == QFocusEvent::ActiveWindow || 00221 focusEvent->reason() == QFocusEvent::Popup ) 00222 return false; 00223 endSearch(); 00224 } 00225 00226 if( e->type() == QEvent::KeyPress ) { 00227 QKeyEvent *keyEvent = (QKeyEvent*)e; 00228 if( keyEvent->key() == Qt::Key_Escape ) 00229 quitToView( QString::null ); 00230 } 00231 00232 return false; 00233 } 00234 00235 // Sigh... i18n hell. 00236 void ISearchPluginView::updateLabelText( 00237 bool failing /* = false */, bool reverse /* = false */, 00238 bool wrapped /* = false */, bool overwrapped /* = false */ ) 00239 { 00240 QString text; 00241 // Reverse binary: 00242 // 0000 00243 if( !failing && !reverse && !wrapped && !overwrapped ) { 00244 text = i18n("Incremental Search", "I-Search:"); 00245 // 1000 00246 } else if ( failing && !reverse && !wrapped && !overwrapped ) { 00247 text = i18n("Incremental Search found no match", "Failing I-Search:"); 00248 // 0100 00249 } else if ( !failing && reverse && !wrapped && !overwrapped ) { 00250 text = i18n("Incremental Search in the reverse direction", "I-Search Backward:"); 00251 // 1100 00252 } else if ( failing && reverse && !wrapped && !overwrapped ) { 00253 text = i18n("Failing I-Search Backward:"); 00254 // 0010 00255 } else if ( !failing && !reverse && wrapped && !overwrapped ) { 00256 text = i18n("Incremental Search has passed the end of the document", "Wrapped I-Search:"); 00257 // 1010 00258 } else if ( failing && !reverse && wrapped && !overwrapped ) { 00259 text = i18n("Failing Wrapped I-Search:"); 00260 // 0110 00261 } else if ( !failing && reverse && wrapped && !overwrapped ) { 00262 text = i18n("Wrapped I-Search Backward:"); 00263 // 1110 00264 } else if ( failing && reverse && wrapped && !overwrapped ) { 00265 text = i18n("Failing Wrapped I-Search Backward:"); 00266 // 0011 00267 } else if ( !failing && !reverse && overwrapped ) { 00268 text = i18n("Incremental Search has passed both the end of the document " 00269 "and the original starting position", "Overwrapped I-Search:"); 00270 // 1011 00271 } else if ( failing && !reverse && overwrapped ) { 00272 text = i18n("Failing Overwrapped I-Search:"); 00273 // 0111 00274 } else if ( !failing && reverse && overwrapped ) { 00275 text = i18n("Overwrapped I-Search Backwards:"); 00276 // 1111 00277 } else if ( failing && reverse && overwrapped ) { 00278 text = i18n("Failing Overwrapped I-Search Backward:"); 00279 } else { 00280 text = i18n("Error: unknown i-search state!"); 00281 } 00282 m_label->setText( text ); 00283 } 00284 00285 void ISearchPluginView::slotSearchForwardAction() 00286 { 00287 slotSearchAction( false ); 00288 } 00289 00290 void ISearchPluginView::slotSearchBackwardAction() 00291 { 00292 slotSearchAction( true ); 00293 } 00294 00295 void ISearchPluginView::slotSearchAction( bool reverse ) 00296 { 00297 if( !m_combo->hasFocus() ) { 00298 if( m_comboAction->container(0) && m_comboAction->container(0)->isHidden() ) { 00299 m_toolBarWasHidden = true; 00300 m_comboAction->container(0)->setHidden( false ); 00301 } else { 00302 m_toolBarWasHidden = false; 00303 } 00304 m_combo->setFocus(); // Will call startSearch() 00305 } else { 00306 nextMatch( reverse ); 00307 } 00308 } 00309 00310 void ISearchPluginView::nextMatch( bool reverse ) 00311 { 00312 QString text = m_combo->currentText(); 00313 if( text.isEmpty() ) 00314 return; 00315 if( state != MatchSearch ) { 00316 // Last search was performed by typing, start from that match. 00317 if( !reverse ) { 00318 m_searchLine = m_foundLine; 00319 m_searchCol = m_foundCol + m_matchLen; 00320 } else { 00321 m_searchLine = m_foundLine; 00322 m_searchCol = m_foundCol; 00323 } 00324 state = MatchSearch; 00325 } 00326 bool found = false; 00327 if( !reverse ) { 00328 found = iSearch( m_searchLine, m_searchCol, text, reverse, m_autoWrap ); 00329 } else { 00330 found = iSearch( m_searchLine, m_searchCol, text, reverse, m_autoWrap ); 00331 } 00332 if( found ) { 00333 m_searchLine = m_foundLine; 00334 m_searchCol = m_foundCol + m_matchLen; 00335 } else { 00336 m_wrapped = true; 00337 m_searchLine = m_searchCol = 0; 00338 } 00339 } 00340 00341 void ISearchPluginView::startSearch() 00342 { 00343 if( !m_view ) return; 00344 00345 m_searchForwardAction->setText( i18n("Next Incremental Search Match") ); 00346 m_searchBackwardAction->setText( i18n("Previous Incremental Search Match") ); 00347 00348 m_wrapped = false; 00349 00350 if( m_fromBeginning ) { 00351 m_startLine = m_startCol = 0; 00352 } else { 00353 m_cursorIF->cursorPositionReal( &m_startLine, &m_startCol ); 00354 } 00355 m_searchLine = m_startLine; 00356 m_searchCol = m_startCol; 00357 00358 updateLabelText( false, m_searchBackward ); 00359 00360 m_combo->blockSignals( true ); 00361 00362 QString text = m_selectIF->selection(); 00363 if( text.isEmpty() ) 00364 text = m_lastString; 00365 m_combo->setCurrentText( text ); 00366 00367 m_combo->blockSignals( false ); 00368 m_combo->lineEdit()->selectAll(); 00369 00370 // kdDebug() << "Starting search at " << m_startLine << ", " << m_startCol << endl; 00371 } 00372 00373 void ISearchPluginView::endSearch() 00374 { 00375 m_searchForwardAction->setText( i18n("Search Incrementally") ); 00376 m_searchBackwardAction->setText( i18n("Search Incrementally Backwards") ); 00377 00378 updateLabelText(); 00379 00380 if( m_toolBarWasHidden && m_comboAction->containerCount() > 0 ) { 00381 m_comboAction->container(0)->setHidden( true ); 00382 } 00383 } 00384 00385 void ISearchPluginView::quitToView( const QString &text ) 00386 { 00387 if( text != QString::null && !text.isEmpty() ) { 00388 m_combo->addToHistory( text ); 00389 m_combo->insertItem( text ); 00390 m_lastString = text; 00391 } 00392 00393 m_combo->blockSignals( true ); 00394 m_combo->clear(); 00395 m_combo->blockSignals( false ); 00396 00397 if( m_view ) { 00398 m_view->setFocus(); // Will call endSearch() 00399 } 00400 } 00401 00402 void ISearchPluginView::slotTextChanged( const QString& text ) 00403 { 00404 state = TextSearch; 00405 00406 if( text.isEmpty() ) 00407 return; 00408 00409 iSearch( m_searchLine, m_searchCol, text, m_searchBackward, m_autoWrap ); 00410 } 00411 00412 void ISearchPluginView::slotReturnPressed( const QString& text ) 00413 { 00414 quitToView( text ); 00415 } 00416 00417 void ISearchPluginView::slotAddContextMenuItems( QPopupMenu *menu ) 00418 { 00419 if( menu ) { 00420 menu->insertSeparator(); 00421 menu->insertItem( i18n("Case Sensitive"), this, 00422 SLOT(setCaseSensitive(bool))); 00423 menu->insertItem( i18n("From Beginning"), this, 00424 SLOT(setFromBeginning(bool))); 00425 menu->insertItem( i18n("Regular Expression"), this, 00426 SLOT(setRegExp(bool))); 00427 //menu->insertItem( i18n("Auto-Wrap Search"), this, 00428 // SLOT(setAutoWrap(bool))); 00429 } 00430 } 00431 00432 bool ISearchPluginView::iSearch( 00433 uint startLine, uint startCol, 00434 const QString& text, bool reverse, 00435 bool autoWrap ) 00436 { 00437 if( !m_view ) return false; 00438 00439 // kdDebug() << "Searching for " << text << " at " << startLine << ", " << startCol << endl; 00440 bool found = false; 00441 if( !m_regExp ) { 00442 found = m_searchIF->searchText( startLine, 00443 startCol, 00444 text, 00445 &m_foundLine, 00446 &m_foundCol, 00447 &m_matchLen, 00448 m_caseSensitive, 00449 reverse ); 00450 } else { 00451 found = m_searchIF->searchText( startLine, 00452 startCol, 00453 QRegExp( text ), 00454 &m_foundLine, 00455 &m_foundCol, 00456 &m_matchLen, 00457 reverse ); 00458 } 00459 if( found ) { 00460 // kdDebug() << "Found '" << text << "' at " << m_foundLine << ", " << m_foundCol << endl; 00461 // v->gotoLineNumber( m_foundLine ); 00462 m_cursorIF->setCursorPositionReal( m_foundLine, m_foundCol + m_matchLen ); 00463 m_selectIF->setSelection( m_foundLine, m_foundCol, m_foundLine, m_foundCol + m_matchLen ); 00464 } else if ( autoWrap ) { 00465 m_wrapped = true; 00466 found = iSearch( 0, 0, text, reverse, false ); 00467 } 00468 // FIXME 00469 bool overwrapped = ( m_wrapped && 00470 ((m_foundLine > m_startLine ) || 00471 (m_foundLine == m_startLine && m_foundCol >= m_startCol)) ); 00472 // kdDebug() << "Overwrap = " << overwrapped << ". Start was " << m_startLine << ", " << m_startCol << endl; 00473 updateLabelText( !found, reverse, m_wrapped, overwrapped ); 00474 return found; 00475 } 00476 00477 ISearchPlugin::ISearchPlugin( QObject *parent, const char* name, const QStringList& ) 00478 : KTextEditor::Plugin ( (KTextEditor::Document*) parent, name ) 00479 { 00480 } 00481 00482 ISearchPlugin::~ISearchPlugin() 00483 { 00484 } 00485 00486 void ISearchPlugin::addView(KTextEditor::View *view) 00487 { 00488 ISearchPluginView *nview = new ISearchPluginView (view); 00489 nview->setView (view); 00490 m_views.append (nview); 00491 } 00492 00493 void ISearchPlugin::removeView(KTextEditor::View *view) 00494 { 00495 for (uint z=0; z < m_views.count(); z++) 00496 { 00497 if (m_views.at(z)->parentClient() == view) 00498 { 00499 ISearchPluginView *nview = m_views.at(z); 00500 m_views.remove (nview); 00501 delete nview; 00502 } 00503 } 00504 }
KDE Logo
This file is part of the documentation for kate Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Mon Aug 30 22:56:45 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003