00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
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
00133
00134
00135
00136
00137
00138
00139
00140
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
00174 }
00175
00176
void ISearchPluginView::writeConfig()
00177 {
00178
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
00236
void ISearchPluginView::updateLabelText(
00237
bool failing ,
bool reverse ,
00238
bool wrapped ,
bool overwrapped )
00239 {
00240
QString text;
00241
00242
00243
if( !failing && !reverse && !wrapped && !overwrapped ) {
00244 text = i18n(
"Incremental Search",
"I-Search:");
00245
00246 }
else if ( failing && !reverse && !wrapped && !overwrapped ) {
00247 text = i18n(
"Incremental Search found no match",
"Failing I-Search:");
00248
00249 }
else if ( !failing && reverse && !wrapped && !overwrapped ) {
00250 text = i18n(
"Incremental Search in the reverse direction",
"I-Search Backward:");
00251
00252 }
else if ( failing && reverse && !wrapped && !overwrapped ) {
00253 text = i18n(
"Failing I-Search Backward:");
00254
00255 }
else if ( !failing && !reverse && wrapped && !overwrapped ) {
00256 text = i18n(
"Incremental Search has passed the end of the document",
"Wrapped I-Search:");
00257
00258 }
else if ( failing && !reverse && wrapped && !overwrapped ) {
00259 text = i18n(
"Failing Wrapped I-Search:");
00260
00261 }
else if ( !failing && reverse && wrapped && !overwrapped ) {
00262 text = i18n(
"Wrapped I-Search Backward:");
00263
00264 }
else if ( failing && reverse && wrapped && !overwrapped ) {
00265 text = i18n(
"Failing Wrapped I-Search Backward:");
00266
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
00271 }
else if ( failing && !reverse && overwrapped ) {
00272 text = i18n(
"Failing Overwrapped I-Search:");
00273
00274 }
else if ( !failing && reverse && overwrapped ) {
00275 text = i18n(
"Overwrapped I-Search Backwards:");
00276
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();
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
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
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();
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
00428
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
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
00461
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
00469
bool overwrapped = ( m_wrapped &&
00470 ((m_foundLine > m_startLine ) ||
00471 (m_foundLine == m_startLine && m_foundCol >= m_startCol)) );
00472
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 }