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
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
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();
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
00424
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
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
00457
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
00465
bool overwrapped = ( m_wrapped &&
00466 ((m_foundLine > m_startLine ) ||
00467 (m_foundLine == m_startLine && m_foundCol >= m_startCol)) );
00468
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 }