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 00327 bool found = iSearch( m_searchLine, m_searchCol, text, reverse, m_autoWrap ); 00328 if( found ) { 00329 m_searchLine = m_foundLine; 00330 m_searchCol = m_foundCol + m_matchLen; 00331 } else { 00332 m_wrapped = true; 00333 m_searchLine = m_searchCol = 0; 00334 } 00335 } 00336 00337 void ISearchPluginView::startSearch() 00338 { 00339 if( !m_view ) return; 00340 00341 m_searchForwardAction->setText( i18n("Next Incremental Search Match") ); 00342 m_searchBackwardAction->setText( i18n("Previous Incremental Search Match") ); 00343 00344 m_wrapped = false; 00345 00346 if( m_fromBeginning ) { 00347 m_startLine = m_startCol = 0; 00348 } else { 00349 m_cursorIF->cursorPositionReal( &m_startLine, &m_startCol ); 00350 } 00351 m_searchLine = m_startLine; 00352 m_searchCol = m_startCol; 00353 00354 updateLabelText( false, m_searchBackward ); 00355 00356 m_combo->blockSignals( true ); 00357 00358 QString text = m_selectIF->selection(); 00359 if( text.isEmpty() ) 00360 text = m_lastString; 00361 m_combo->setCurrentText( text ); 00362 00363 m_combo->blockSignals( false ); 00364 m_combo->lineEdit()->selectAll(); 00365 00366 // kdDebug() << "Starting search at " << m_startLine << ", " << m_startCol << endl; 00367 } 00368 00369 void ISearchPluginView::endSearch() 00370 { 00371 m_searchForwardAction->setText( i18n("Search Incrementally") ); 00372 m_searchBackwardAction->setText( i18n("Search Incrementally Backwards") ); 00373 00374 updateLabelText(); 00375 00376 if( m_toolBarWasHidden && m_comboAction->containerCount() > 0 ) { 00377 m_comboAction->container(0)->setHidden( true ); 00378 } 00379 } 00380 00381 void ISearchPluginView::quitToView( const QString &text ) 00382 { 00383 if( !text.isNull() && !text.isEmpty() ) { 00384 m_combo->addToHistory( text ); 00385 m_combo->insertItem( text ); 00386 m_lastString = text; 00387 } 00388 00389 m_combo->blockSignals( true ); 00390 m_combo->clear(); 00391 m_combo->blockSignals( false ); 00392 00393 if( m_view ) { 00394 m_view->setFocus(); // Will call endSearch() 00395 } 00396 } 00397 00398 void ISearchPluginView::slotTextChanged( const QString& text ) 00399 { 00400 state = TextSearch; 00401 00402 if( text.isEmpty() ) 00403 return; 00404 00405 iSearch( m_searchLine, m_searchCol, text, m_searchBackward, m_autoWrap ); 00406 } 00407 00408 void ISearchPluginView::slotReturnPressed( const QString& text ) 00409 { 00410 quitToView( text ); 00411 } 00412 00413 void ISearchPluginView::slotAddContextMenuItems( QPopupMenu *menu ) 00414 { 00415 if( menu ) { 00416 menu->insertSeparator(); 00417 menu->insertItem( i18n("Case Sensitive"), this, 00418 SLOT(setCaseSensitive(bool))); 00419 menu->insertItem( i18n("From Beginning"), this, 00420 SLOT(setFromBeginning(bool))); 00421 menu->insertItem( i18n("Regular Expression"), this, 00422 SLOT(setRegExp(bool))); 00423 //menu->insertItem( i18n("Auto-Wrap Search"), this, 00424 // SLOT(setAutoWrap(bool))); 00425 } 00426 } 00427 00428 bool ISearchPluginView::iSearch( 00429 uint startLine, uint startCol, 00430 const QString& text, bool reverse, 00431 bool autoWrap ) 00432 { 00433 if( !m_view ) return false; 00434 00435 // kdDebug() << "Searching for " << text << " at " << startLine << ", " << startCol << endl; 00436 bool found = false; 00437 if( !m_regExp ) { 00438 found = m_searchIF->searchText( startLine, 00439 startCol, 00440 text, 00441 &m_foundLine, 00442 &m_foundCol, 00443 &m_matchLen, 00444 m_caseSensitive, 00445 reverse ); 00446 } else { 00447 found = m_searchIF->searchText( startLine, 00448 startCol, 00449 QRegExp( text ), 00450 &m_foundLine, 00451 &m_foundCol, 00452 &m_matchLen, 00453 reverse ); 00454 } 00455 if( found ) { 00456 // kdDebug() << "Found '" << text << "' at " << m_foundLine << ", " << m_foundCol << endl; 00457 // v->gotoLineNumber( m_foundLine ); 00458 m_cursorIF->setCursorPositionReal( m_foundLine, m_foundCol + m_matchLen ); 00459 m_selectIF->setSelection( m_foundLine, m_foundCol, m_foundLine, m_foundCol + m_matchLen ); 00460 } else if ( autoWrap ) { 00461 m_wrapped = true; 00462 found = iSearch( 0, 0, text, reverse, false ); 00463 } 00464 // FIXME 00465 bool overwrapped = ( m_wrapped && 00466 ((m_foundLine > m_startLine ) || 00467 (m_foundLine == m_startLine && m_foundCol >= m_startCol)) ); 00468 // kdDebug() << "Overwrap = " << overwrapped << ". Start was " << m_startLine << ", " << m_startCol << endl; 00469 updateLabelText( !found, reverse, m_wrapped, overwrapped ); 00470 return found; 00471 } 00472 00473 ISearchPlugin::ISearchPlugin( QObject *parent, const char* name, const QStringList& ) 00474 : KTextEditor::Plugin ( (KTextEditor::Document*) parent, name ) 00475 { 00476 } 00477 00478 ISearchPlugin::~ISearchPlugin() 00479 { 00480 } 00481 00482 void ISearchPlugin::addView(KTextEditor::View *view) 00483 { 00484 ISearchPluginView *nview = new ISearchPluginView (view); 00485 nview->setView (view); 00486 m_views.append (nview); 00487 } 00488 00489 void ISearchPlugin::removeView(KTextEditor::View *view) 00490 { 00491 for (uint z=0; z < m_views.count(); z++) 00492 { 00493 if (m_views.at(z)->parentClient() == view) 00494 { 00495 ISearchPluginView *nview = m_views.at(z); 00496 m_views.remove (nview); 00497 delete nview; 00498 } 00499 } 00500 }
KDE Logo
This file is part of the documentation for kate Library Version 3.4.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Apr 14 00:46:02 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003