kate Library: ISearchPlugin.cpp Source File (kate Library)

| # kate Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# 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 }

This file is part of the documentation for kate Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:36:29 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003