00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "katedocument.h"
00023 #include "katedocument.moc"
00024 #include "katekeyinterceptorfunctor.h"
00025 #include "katefactory.h"
00026 #include "katedialogs.h"
00027 #include "katehighlight.h"
00028 #include "kateview.h"
00029 #include "kateviewinternal.h"
00030 #include "katesearch.h"
00031 #include "kateautoindent.h"
00032 #include "katetextline.h"
00033 #include "katedocumenthelpers.h"
00034 #include "kateprinter.h"
00035 #include "katelinerange.h"
00036 #include "katesupercursor.h"
00037 #include "katearbitraryhighlight.h"
00038 #include "katerenderer.h"
00039 #include "kateattribute.h"
00040 #include "kateconfig.h"
00041 #include "katefiletype.h"
00042 #include "kateschema.h"
00043 #include "katetemplatehandler.h"
00044 #include <ktexteditor/plugin.h>
00045
00046 #include <kio/job.h>
00047 #include <kio/netaccess.h>
00048 #include <kio/kfileitem.h>
00049
00050
00051 #include <kparts/event.h>
00052
00053 #include <klocale.h>
00054 #include <kglobal.h>
00055 #include <kapplication.h>
00056 #include <kpopupmenu.h>
00057 #include <kconfig.h>
00058 #include <kfiledialog.h>
00059 #include <kmessagebox.h>
00060 #include <kspell.h>
00061 #include <kstdaction.h>
00062 #include <kiconloader.h>
00063 #include <kxmlguifactory.h>
00064 #include <kdialogbase.h>
00065 #include <kdebug.h>
00066 #include <kglobalsettings.h>
00067 #include <ksavefile.h>
00068 #include <klibloader.h>
00069 #include <kdirwatch.h>
00070 #include <kwin.h>
00071 #include <kencodingfiledialog.h>
00072 #include <ktempfile.h>
00073 #include <kmdcodec.h>
00074 #include <kmultipledrag.h>
00075
00076 #include <qtimer.h>
00077 #include <qfile.h>
00078 #include <qclipboard.h>
00079 #include <qtextstream.h>
00080 #include <qtextcodec.h>
00081 #include <qmap.h>
00082
00083
00084
00085 class KatePartPluginItem
00086 {
00087 public:
00088 KTextEditor::Plugin *plugin;
00089 };
00090
00091
00092
00093
00094
00095
00096 KateDocument::KateDocument ( bool bSingleViewMode, bool bBrowserView,
00097 bool bReadOnly, QWidget *parentWidget,
00098 const char *widgetName, QObject *parent, const char *name)
00099 : Kate::Document(parent, name),
00100 m_plugins (KateFactory::self()->plugins().count()),
00101 selectStart(this, true),
00102 selectEnd(this, true),
00103 m_undoDontMerge(false),
00104 m_undoIgnoreCancel(false),
00105 lastUndoGroupWhenSaved( 0 ),
00106 docWasSavedWhenUndoWasEmpty( true ),
00107 m_modOnHd (false),
00108 m_modOnHdReason (0),
00109 m_job (0),
00110 m_tempFile (0),
00111 m_tabInterceptor(0),
00112 m_imStartLine( 0 ),
00113 m_imStart( 0 ),
00114 m_imEnd( 0 ),
00115 m_imSelStart( 0 ),
00116 m_imSelEnd( 0 ),
00117 m_imComposeEvent( false )
00118 {
00119 m_undoComplexMerge=false;
00120
00121 setObjId ("KateDocument#"+documentDCOPSuffix());
00122
00123
00124 setBlockSelectionInterfaceDCOPSuffix (documentDCOPSuffix());
00125 setConfigInterfaceDCOPSuffix (documentDCOPSuffix());
00126 setConfigInterfaceExtensionDCOPSuffix (documentDCOPSuffix());
00127 setCursorInterfaceDCOPSuffix (documentDCOPSuffix());
00128 setEditInterfaceDCOPSuffix (documentDCOPSuffix());
00129 setEncodingInterfaceDCOPSuffix (documentDCOPSuffix());
00130 setHighlightingInterfaceDCOPSuffix (documentDCOPSuffix());
00131 setMarkInterfaceDCOPSuffix (documentDCOPSuffix());
00132 setMarkInterfaceExtensionDCOPSuffix (documentDCOPSuffix());
00133 setPrintInterfaceDCOPSuffix (documentDCOPSuffix());
00134 setSearchInterfaceDCOPSuffix (documentDCOPSuffix());
00135 setSelectionInterfaceDCOPSuffix (documentDCOPSuffix());
00136 setSelectionInterfaceExtDCOPSuffix (documentDCOPSuffix());
00137 setSessionConfigInterfaceDCOPSuffix (documentDCOPSuffix());
00138 setUndoInterfaceDCOPSuffix (documentDCOPSuffix());
00139 setWordWrapInterfaceDCOPSuffix (documentDCOPSuffix());
00140
00141
00142 m_plugins.fill (0);
00143
00144
00145 KateFactory::self()->registerDocument (this);
00146
00147 m_reloading = false;
00148
00149 m_buffer = new KateBuffer (this);
00150
00151
00152
00153 m_config = new KateDocumentConfig (this);
00154
00155
00156 m_activeView = 0L;
00157
00158 hlSetByUser = false;
00159 m_fileType = -1;
00160 m_fileTypeSetByUser = false;
00161 setInstance( KateFactory::self()->instance() );
00162
00163 editSessionNumber = 0;
00164 editIsRunning = false;
00165 noViewUpdates = false;
00166 m_editCurrentUndo = 0L;
00167 editWithUndo = false;
00168 editTagFrom = false;
00169
00170 m_docNameNumber = 0;
00171
00172 m_kspell = 0;
00173
00174 blockSelect = false;
00175
00176 m_bSingleViewMode = bSingleViewMode;
00177 m_bBrowserView = bBrowserView;
00178 m_bReadOnly = bReadOnly;
00179
00180 m_marks.setAutoDelete( true );
00181 m_markPixmaps.setAutoDelete( true );
00182 m_markDescriptions.setAutoDelete( true );
00183 setMarksUserChangable( markType01 );
00184
00185 m_undoMergeTimer = new QTimer(this);
00186 connect(m_undoMergeTimer, SIGNAL(timeout()), SLOT(undoCancel()));
00187
00188 clearMarks ();
00189 clearUndo ();
00190 clearRedo ();
00191 setModified (false);
00192 docWasSavedWhenUndoWasEmpty = true;
00193
00194
00195 m_buffer->setHighlight (0);
00196
00197 m_extension = new KateBrowserExtension( this );
00198 m_arbitraryHL = new KateArbitraryHighlight();
00199 m_indenter = KateAutoIndent::createIndenter ( this, 0 );
00200
00201 m_indenter->updateConfig ();
00202
00203
00204 connect(m_buffer, SIGNAL(tagLines(int,int)), this, SLOT(tagLines(int,int)));
00205 connect(m_buffer, SIGNAL(codeFoldingUpdated()),this,SIGNAL(codeFoldingUpdated()));
00206
00207
00208 connect(KateHlManager::self(),SIGNAL(changed()),SLOT(internalHlChanged()));
00209
00210
00211 connect(m_arbitraryHL, SIGNAL(tagLines(KateView*, KateSuperRange*)), SLOT(tagArbitraryLines(KateView*, KateSuperRange*)));
00212
00213
00214 connect( KateFactory::self()->dirWatch(), SIGNAL(dirty (const QString &)),
00215 this, SLOT(slotModOnHdDirty (const QString &)) );
00216
00217 connect( KateFactory::self()->dirWatch(), SIGNAL(created (const QString &)),
00218 this, SLOT(slotModOnHdCreated (const QString &)) );
00219
00220 connect( KateFactory::self()->dirWatch(), SIGNAL(deleted (const QString &)),
00221 this, SLOT(slotModOnHdDeleted (const QString &)) );
00222
00223
00224 setDocName ("");
00225
00226
00227 if ( m_bSingleViewMode )
00228 {
00229 KTextEditor::View *view = createView( parentWidget, widgetName );
00230 insertChildClient( view );
00231 view->show();
00232 setWidget( view );
00233 }
00234
00235 connect(this,SIGNAL(sigQueryClose(bool *, bool*)),this,SLOT(slotQueryClose_save(bool *, bool*)));
00236
00237
00238 if ( s_fileChangedDialogsActivated )
00239 for (uint z = 0; z < m_views.count(); z++)
00240 connect( m_views.at(z), SIGNAL(gotFocus( Kate::View * )), this, SLOT(slotModifiedOnDisk()) );
00241
00242 m_isasking = 0;
00243
00244
00245 for (uint i=0; i<KateFactory::self()->plugins().count(); i++)
00246 {
00247 if (config()->plugin (i))
00248 loadPlugin (i);
00249 }
00250 }
00251
00252
00253
00254
00255 KateDocument::~KateDocument()
00256 {
00257
00258 deactivateDirWatch ();
00259
00260 if (!singleViewMode())
00261 {
00262
00263 m_views.setAutoDelete( true );
00264 m_views.clear();
00265 }
00266
00267 delete m_editCurrentUndo;
00268
00269 delete m_arbitraryHL;
00270
00271
00272 undoItems.setAutoDelete(true);
00273 undoItems.clear();
00274
00275
00276 unloadAllPlugins ();
00277
00278
00279 if( m_kspell )
00280 {
00281 m_kspell->setAutoDelete(true);
00282 m_kspell->cleanUp();
00283 delete m_kspell;
00284 }
00285
00286 delete m_config;
00287 delete m_indenter;
00288 KateFactory::self()->deregisterDocument (this);
00289 }
00290
00291
00292
00293 void KateDocument::unloadAllPlugins ()
00294 {
00295 for (uint i=0; i<m_plugins.count(); i++)
00296 unloadPlugin (i);
00297 }
00298
00299 void KateDocument::enableAllPluginsGUI (KateView *view)
00300 {
00301 for (uint i=0; i<m_plugins.count(); i++)
00302 enablePluginGUI (m_plugins[i], view);
00303 }
00304
00305 void KateDocument::disableAllPluginsGUI (KateView *view)
00306 {
00307 for (uint i=0; i<m_plugins.count(); i++)
00308 disablePluginGUI (m_plugins[i], view);
00309 }
00310
00311 void KateDocument::loadPlugin (uint pluginIndex)
00312 {
00313 if (m_plugins[pluginIndex]) return;
00314
00315 m_plugins[pluginIndex] = KTextEditor::createPlugin (QFile::encodeName((KateFactory::self()->plugins())[pluginIndex]->library()), this);
00316
00317 enablePluginGUI (m_plugins[pluginIndex]);
00318 }
00319
00320 void KateDocument::unloadPlugin (uint pluginIndex)
00321 {
00322 if (!m_plugins[pluginIndex]) return;
00323
00324 disablePluginGUI (m_plugins[pluginIndex]);
00325
00326 delete m_plugins[pluginIndex];
00327 m_plugins[pluginIndex] = 0L;
00328 }
00329
00330 void KateDocument::enablePluginGUI (KTextEditor::Plugin *plugin, KateView *view)
00331 {
00332 if (!plugin) return;
00333 if (!KTextEditor::pluginViewInterface(plugin)) return;
00334
00335 KXMLGUIFactory *factory = view->factory();
00336 if ( factory )
00337 factory->removeClient( view );
00338
00339 KTextEditor::pluginViewInterface(plugin)->addView(view);
00340
00341 if ( factory )
00342 factory->addClient( view );
00343 }
00344
00345 void KateDocument::enablePluginGUI (KTextEditor::Plugin *plugin)
00346 {
00347 if (!plugin) return;
00348 if (!KTextEditor::pluginViewInterface(plugin)) return;
00349
00350 for (uint i=0; i< m_views.count(); i++)
00351 enablePluginGUI (plugin, m_views.at(i));
00352 }
00353
00354 void KateDocument::disablePluginGUI (KTextEditor::Plugin *plugin, KateView *view)
00355 {
00356 if (!plugin) return;
00357 if (!KTextEditor::pluginViewInterface(plugin)) return;
00358
00359 KXMLGUIFactory *factory = view->factory();
00360 if ( factory )
00361 factory->removeClient( view );
00362
00363 KTextEditor::pluginViewInterface( plugin )->removeView( view );
00364
00365 if ( factory )
00366 factory->addClient( view );
00367 }
00368
00369 void KateDocument::disablePluginGUI (KTextEditor::Plugin *plugin)
00370 {
00371 if (!plugin) return;
00372 if (!KTextEditor::pluginViewInterface(plugin)) return;
00373
00374 for (uint i=0; i< m_views.count(); i++)
00375 disablePluginGUI (plugin, m_views.at(i));
00376 }
00377
00378
00379
00380
00381 KTextEditor::View *KateDocument::createView( QWidget *parent, const char *name )
00382 {
00383 KateView* newView = new KateView( this, parent, name);
00384 connect(newView, SIGNAL(cursorPositionChanged()), SLOT(undoCancel()));
00385 if ( s_fileChangedDialogsActivated )
00386 connect( newView, SIGNAL(gotFocus( Kate::View * )), this, SLOT(slotModifiedOnDisk()) );
00387 return newView;
00388 }
00389
00390 QPtrList<KTextEditor::View> KateDocument::views () const
00391 {
00392 return m_textEditViews;
00393 }
00394
00395 void KateDocument::setActiveView( KateView *view )
00396 {
00397 if ( m_activeView == view ) return;
00398
00399 m_activeView = view;
00400
00401
00402
00403 }
00404
00405
00406
00407
00408 uint KateDocument::configPages () const
00409 {
00410 return 11;
00411 }
00412
00413 KTextEditor::ConfigPage *KateDocument::configPage (uint number, QWidget *parent, const char * )
00414 {
00415 switch( number )
00416 {
00417 case 0:
00418 return colorConfigPage (parent);
00419
00420 case 1:
00421 return editConfigPage (parent);
00422
00423 case 2:
00424 return keysConfigPage (parent);
00425
00426 case 3:
00427 return indentConfigPage(parent);
00428
00429 case 4:
00430 return selectConfigPage(parent);
00431
00432 case 5:
00433 return saveConfigPage( parent );
00434
00435 case 6:
00436 return viewDefaultsConfigPage(parent);
00437
00438 case 7:
00439 return hlConfigPage (parent);
00440
00441 case 9:
00442 return new KateSpellConfigPage (parent);
00443
00444 case 10:
00445 return new KatePartPluginConfigPage (parent);
00446
00447 case 8:
00448 return new KateFileTypeConfigTab (parent);
00449
00450 default:
00451 return 0;
00452 }
00453 }
00454
00455 QString KateDocument::configPageName (uint number) const
00456 {
00457 switch( number )
00458 {
00459 case 0:
00460 return i18n ("Fonts & Colors");
00461
00462 case 3:
00463 return i18n ("Indentation");
00464
00465 case 4:
00466 return i18n ("Selection");
00467
00468 case 1:
00469 return i18n ("Editing");
00470
00471 case 2:
00472 return i18n ("Shortcuts");
00473
00474 case 7:
00475 return i18n ("Highlighting");
00476
00477 case 6:
00478 return i18n ("View Defaults");
00479
00480 case 10:
00481 return i18n ("Plugins");
00482
00483 case 5:
00484 return i18n("Open/Save");
00485
00486 case 9:
00487 return i18n("Spelling");
00488
00489 case 8:
00490 return i18n("Filetypes");
00491
00492 default:
00493 return 0;
00494 }
00495 }
00496
00497 QString KateDocument::configPageFullName (uint number) const
00498 {
00499 switch( number )
00500 {
00501 case 0:
00502 return i18n ("Font & Color Schemas");
00503
00504 case 3:
00505 return i18n ("Indentation Rules");
00506
00507 case 4:
00508 return i18n ("Selection Behavior");
00509
00510 case 1:
00511 return i18n ("Editing Options");
00512
00513 case 2:
00514 return i18n ("Shortcuts Configuration");
00515
00516 case 7:
00517 return i18n ("Highlighting Rules");
00518
00519 case 6:
00520 return i18n("View Defaults");
00521
00522 case 10:
00523 return i18n ("Plugin Manager");
00524
00525 case 5:
00526 return i18n("File Opening & Saving");
00527
00528 case 9:
00529 return i18n("Spell Checker Behavior");
00530
00531 case 8:
00532 return i18n("Filetype Specific Settings");
00533
00534 default:
00535 return 0;
00536 }
00537 }
00538
00539 QPixmap KateDocument::configPagePixmap (uint number, int size) const
00540 {
00541 switch( number )
00542 {
00543 case 0:
00544 return BarIcon("colorize", size);
00545
00546 case 3:
00547 return BarIcon("rightjust", size);
00548
00549 case 4:
00550 return BarIcon("frame_edit", size);
00551
00552 case 1:
00553 return BarIcon("edit", size);
00554
00555 case 2:
00556 return BarIcon("key_enter", size);
00557
00558 case 7:
00559 return BarIcon("source", size);
00560
00561 case 6:
00562 return BarIcon("view_text",size);
00563
00564 case 10:
00565 return BarIcon("connect_established", size);
00566
00567 case 5:
00568 return BarIcon("filesave", size);
00569
00570 case 9:
00571 return BarIcon("spellcheck", size);
00572
00573 case 8:
00574 return BarIcon("edit", size);
00575
00576 default:
00577 return 0;
00578 }
00579 }
00580
00581
00582
00583
00584 QString KateDocument::text() const
00585 {
00586 QString s;
00587
00588 for (uint i = 0; i < m_buffer->count(); i++)
00589 {
00590 KateTextLine::Ptr textLine = m_buffer->plainLine(i);
00591
00592 if (textLine)
00593 {
00594 s.append (textLine->string());
00595
00596 if ((i+1) < m_buffer->count())
00597 s.append('\n');
00598 }
00599 }
00600
00601 return s;
00602 }
00603
00604 QString KateDocument::text ( uint startLine, uint startCol, uint endLine, uint endCol ) const
00605 {
00606 return text(startLine, startCol, endLine, endCol, false);
00607 }
00608
00609 QString KateDocument::textAsHtml ( uint startLine, uint startCol, uint endLine, uint endCol, bool blockwise) const
00610 {
00611 kdDebug(13020) << "textAsHtml" << endl;
00612 if ( blockwise && (startCol > endCol) )
00613 return QString ();
00614
00615 QString s;
00616 QTextStream ts( &s, IO_WriteOnly );
00617 ts.setEncoding(QTextStream::UnicodeUTF8);
00618 ts << "<!DOCTYPE html PUBLIC \"-
00619 ts << "<html xmlns=\"http:
00620 ts << "<head>" << endl;
00621 ts << "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />" << endl;
00622 ts << "<meta name=\"Generator\" content=\"Kate, the KDE Advanced Text Editor\" />" << endl;
00623 ts << "</head>" << endl;
00624
00625 ts << "<body>" << endl;
00626 textAsHtmlStream(startLine, startCol, endLine, endCol, blockwise, &ts);
00627
00628 ts << "</body>" << endl;
00629 ts << "</html>" << endl;
00630 kdDebug(13020) << "html is: " << s << endl;
00631 return s;
00632 }
00633
00634 void KateDocument::textAsHtmlStream ( uint startLine, uint startCol, uint endLine, uint endCol, bool blockwise, QTextStream *ts) const
00635 {
00636 if ( (blockwise || startLine == endLine) && (startCol > endCol) )
00637 return;
00638
00639
00640 if (startLine == endLine)
00641 {
00642 KateTextLine::Ptr textLine = m_buffer->line(startLine);
00643 if ( !textLine )
00644 return;
00645
00646 (*ts) << "<pre>" << endl;
00647
00648 kdDebug(13020) << "there are " << m_views.count() << " view for this document. Using the first one" << endl;
00649
00650 KateView *firstview = m_views.getFirst();
00651 KateRenderer *renderer = firstview->renderer();
00652 textLine->stringAsHtml(startCol, endCol-startCol, renderer, ts);
00653 }
00654 else
00655 {
00656 (*ts) << "<pre>" << endl;
00657
00658 KateView *firstview = m_views.getFirst();
00659 KateRenderer *renderer = firstview->renderer();
00660
00661 for (uint i = startLine; (i <= endLine) && (i < m_buffer->count()); i++)
00662 {
00663 KateTextLine::Ptr textLine = m_buffer->line(i);
00664
00665 if ( !blockwise )
00666 {
00667 if (i == startLine)
00668 textLine->stringAsHtml(startCol, textLine->length()-startCol, renderer,ts);
00669 else if (i == endLine)
00670 textLine->stringAsHtml(0, endCol, renderer,ts);
00671 else
00672 textLine->stringAsHtml(renderer,ts);
00673 }
00674 else
00675 {
00676 textLine->stringAsHtml( startCol, endCol-startCol, renderer,ts);
00677 }
00678
00679 if ( i < endLine )
00680 (*ts) << "\n";
00681 }
00682 }
00683 (*ts) << "</pre>";
00684 }
00685
00686 QString KateDocument::text ( uint startLine, uint startCol, uint endLine, uint endCol, bool blockwise) const
00687 {
00688 if ( blockwise && (startCol > endCol) )
00689 return QString ();
00690
00691 QString s;
00692
00693 if (startLine == endLine)
00694 {
00695 if (startCol > endCol)
00696 return QString ();
00697
00698 KateTextLine::Ptr textLine = m_buffer->plainLine(startLine);
00699
00700 if ( !textLine )
00701 return QString ();
00702
00703 return textLine->string(startCol, endCol-startCol);
00704 }
00705 else
00706 {
00707
00708 for (uint i = startLine; (i <= endLine) && (i < m_buffer->count()); i++)
00709 {
00710 KateTextLine::Ptr textLine = m_buffer->plainLine(i);
00711
00712 if ( !blockwise )
00713 {
00714 if (i == startLine)
00715 s.append (textLine->string(startCol, textLine->length()-startCol));
00716 else if (i == endLine)
00717 s.append (textLine->string(0, endCol));
00718 else
00719 s.append (textLine->string());
00720 }
00721 else
00722 {
00723 s.append( textLine->string( startCol, endCol-startCol));
00724 }
00725
00726 if ( i < endLine )
00727 s.append('\n');
00728 }
00729 }
00730
00731 return s;
00732 }
00733
00734 QString KateDocument::textLine( uint line ) const
00735 {
00736 KateTextLine::Ptr l = m_buffer->plainLine(line);
00737
00738 if (!l)
00739 return QString();
00740
00741 return l->string();
00742 }
00743
00744 bool KateDocument::setText(const QString &s)
00745 {
00746 if (!isReadWrite())
00747 return false;
00748
00749 QPtrList<KTextEditor::Mark> m = marks ();
00750 QValueList<KTextEditor::Mark> msave;
00751
00752 for (uint i=0; i < m.count(); i++)
00753 msave.append (*m.at(i));
00754
00755 editStart ();
00756
00757
00758 clear();
00759
00760
00761 insertText (0, 0, s);
00762
00763 editEnd ();
00764
00765 for (uint i=0; i < msave.count(); i++)
00766 setMark (msave[i].line, msave[i].type);
00767
00768 return true;
00769 }
00770
00771 bool KateDocument::clear()
00772 {
00773 if (!isReadWrite())
00774 return false;
00775
00776 for (KateView * view = m_views.first(); view != 0L; view = m_views.next() ) {
00777 view->clear();
00778 view->tagAll();
00779 view->update();
00780 }
00781
00782 clearMarks ();
00783
00784 return removeText (0,0,lastLine()+1, 0);
00785 }
00786
00787 bool KateDocument::insertText( uint line, uint col, const QString &s)
00788 {
00789 return insertText (line, col, s, false);
00790 }
00791
00792 bool KateDocument::insertText( uint line, uint col, const QString &s, bool blockwise )
00793 {
00794 if (!isReadWrite())
00795 return false;
00796
00797 if (s.isEmpty())
00798 return true;
00799
00800 if (line == numLines())
00801 editInsertLine(line,"");
00802 else if (line > lastLine())
00803 return false;
00804
00805 editStart ();
00806
00807 uint insertPos = col;
00808 uint len = s.length();
00809
00810 QString buf;
00811
00812 bool replacetabs = ( config()->configFlags() & KateDocumentConfig::cfReplaceTabsDyn );
00813 uint tw = config()->tabWidth();
00814
00815 for (uint pos = 0; pos < len; pos++)
00816 {
00817 QChar ch = s[pos];
00818
00819 if (ch == '\n')
00820 {
00821 if ( !blockwise )
00822 {
00823 editInsertText (line, insertPos, buf);
00824 editWrapLine (line, insertPos + buf.length());
00825 }
00826 else
00827 {
00828 editInsertText (line, col, buf);
00829
00830 if ( line == lastLine() )
00831 editWrapLine (line, col + buf.length());
00832 }
00833
00834 line++;
00835 insertPos = 0;
00836 buf.truncate(0);
00837 }
00838 else
00839 {
00840 if ( replacetabs && ch == '\t' )
00841 {
00842 uint tr = tw - ( ((blockwise?col:insertPos)+buf.length())%tw );
00843 for ( uint i=0; i < tr; i++ )
00844 buf += ' ';
00845 }
00846 else
00847 buf += ch;
00848 }
00849 }
00850
00851 if ( !blockwise )
00852 editInsertText (line, insertPos, buf);
00853 else
00854 editInsertText (line, col, buf);
00855
00856 editEnd ();
00857 emit textInserted(line,insertPos);
00858 return true;
00859 }
00860
00861 bool KateDocument::removeText ( uint startLine, uint startCol, uint endLine, uint endCol )
00862 {
00863 return removeText (startLine, startCol, endLine, endCol, false);
00864 }
00865
00866 bool KateDocument::removeText ( uint startLine, uint startCol, uint endLine, uint endCol, bool blockwise)
00867 {
00868 if (!isReadWrite())
00869 return false;
00870
00871 if ( blockwise && (startCol > endCol) )
00872 return false;
00873
00874 if ( startLine > endLine )
00875 return false;
00876
00877 if ( startLine > lastLine() )
00878 return false;
00879
00880 if (!blockwise) {
00881 emit aboutToRemoveText(KateTextRange(startLine,startCol,endLine,endCol));
00882 }
00883 editStart ();
00884
00885 if ( !blockwise )
00886 {
00887 if ( endLine > lastLine() )
00888 {
00889 endLine = lastLine()+1;
00890 endCol = 0;
00891 }
00892
00893 if (startLine == endLine)
00894 {
00895 editRemoveText (startLine, startCol, endCol-startCol);
00896 }
00897 else if ((startLine+1) == endLine)
00898 {
00899 if ( (m_buffer->plainLine(startLine)->length()-startCol) > 0 )
00900 editRemoveText (startLine, startCol, m_buffer->plainLine(startLine)->length()-startCol);
00901
00902 editRemoveText (startLine+1, 0, endCol);
00903 editUnWrapLine (startLine);
00904 }
00905 else
00906 {
00907 for (uint line = endLine; line >= startLine; line--)
00908 {
00909 if ((line > startLine) && (line < endLine))
00910 {
00911 editRemoveLine (line);
00912 }
00913 else
00914 {
00915 if (line == endLine)
00916 {
00917 if ( endLine <= lastLine() )
00918 editRemoveText (line, 0, endCol);
00919 }
00920 else
00921 {
00922 if ( (m_buffer->plainLine(line)->length()-startCol) > 0 )
00923 editRemoveText (line, startCol, m_buffer->plainLine(line)->length()-startCol);
00924
00925 editUnWrapLine (startLine);
00926 }
00927 }
00928
00929 if ( line == 0 )
00930 break;
00931 }
00932 }
00933 }
00934 else
00935 {
00936 if ( endLine > lastLine() )
00937 endLine = lastLine ();
00938
00939 for (uint line = endLine; line >= startLine; line--)
00940 {
00941
00942 editRemoveText (line, startCol, endCol-startCol);
00943
00944 if ( line == 0 )
00945 break;
00946 }
00947 }
00948
00949 editEnd ();
00950 emit textRemoved();
00951 return true;
00952 }
00953
00954 bool KateDocument::insertLine( uint l, const QString &str )
00955 {
00956 if (!isReadWrite())
00957 return false;
00958
00959 if (l > numLines())
00960 return false;
00961
00962 return editInsertLine (l, str);
00963 }
00964
00965 bool KateDocument::removeLine( uint line )
00966 {
00967 if (!isReadWrite())
00968 return false;
00969
00970 if (line > lastLine())
00971 return false;
00972
00973 return editRemoveLine (line);
00974 }
00975
00976 uint KateDocument::length() const
00977 {
00978 uint l = 0;
00979
00980 for (uint i = 0; i < m_buffer->count(); i++)
00981 {
00982 KateTextLine::Ptr line = m_buffer->plainLine(i);
00983
00984 if (line)
00985 l += line->length();
00986 }
00987
00988 return l;
00989 }
00990
00991 uint KateDocument::numLines() const
00992 {
00993 return m_buffer->count();
00994 }
00995
00996 uint KateDocument::numVisLines() const
00997 {
00998 return m_buffer->countVisible ();
00999 }
01000
01001 int KateDocument::lineLength ( uint line ) const
01002 {
01003 KateTextLine::Ptr l = m_buffer->plainLine(line);
01004
01005 if (!l)
01006 return -1;
01007
01008 return l->length();
01009 }
01010
01011
01012
01013
01014
01015
01016 void KateDocument::editStart (bool withUndo)
01017 {
01018 editSessionNumber++;
01019
01020 if (editSessionNumber > 1)
01021 return;
01022
01023 editIsRunning = true;
01024 noViewUpdates = true;
01025 editWithUndo = withUndo;
01026
01027 editTagLineStart = 0xffffffff;
01028 editTagLineEnd = 0;
01029 editTagFrom = false;
01030
01031 if (editWithUndo)
01032 undoStart();
01033 else
01034 undoCancel();
01035
01036 for (uint z = 0; z < m_views.count(); z++)
01037 {
01038 m_views.at(z)->editStart ();
01039 }
01040
01041 m_buffer->editStart ();
01042 }
01043
01044 void KateDocument::undoStart()
01045 {
01046 if (m_editCurrentUndo || m_imComposeEvent) return;
01047
01048
01049 if ((config()->undoSteps() > 0) && (undoItems.count() > config()->undoSteps()))
01050 {
01051 undoItems.setAutoDelete(true);
01052 undoItems.removeFirst();
01053 undoItems.setAutoDelete(false);
01054 docWasSavedWhenUndoWasEmpty = false;
01055 }
01056
01057
01058 m_editCurrentUndo = new KateUndoGroup(this);
01059 }
01060
01061 void KateDocument::undoEnd()
01062 {
01063 if (m_imComposeEvent)
01064 return;
01065
01066 if (m_editCurrentUndo)
01067 {
01068 if (!m_undoDontMerge && undoItems.last() && undoItems.last()->merge(m_editCurrentUndo,m_undoComplexMerge))
01069 delete m_editCurrentUndo;
01070 else
01071 undoItems.append(m_editCurrentUndo);
01072
01073 m_undoDontMerge = false;
01074 m_undoIgnoreCancel = true;
01075
01076 m_editCurrentUndo = 0L;
01077
01078
01079
01080 m_undoMergeTimer->start(5000, true);
01081
01082 emit undoChanged();
01083 }
01084 }
01085
01086 void KateDocument::undoCancel()
01087 {
01088 if (m_undoIgnoreCancel) {
01089 m_undoIgnoreCancel = false;
01090 return;
01091 }
01092
01093 m_undoDontMerge = true;
01094
01095 Q_ASSERT(!m_editCurrentUndo);
01096
01097
01098 delete m_editCurrentUndo;
01099 m_editCurrentUndo = 0L;
01100 }
01101
01102 void KateDocument::undoSafePoint() {
01103 Q_ASSERT(m_editCurrentUndo);
01104 if (!m_editCurrentUndo) return;
01105 m_editCurrentUndo->safePoint();
01106 }
01107
01108
01109
01110
01111 void KateDocument::editEnd ()
01112 {
01113 if (editSessionNumber == 0)
01114 return;
01115
01116
01117 if (editSessionNumber == 1)
01118 if (editWithUndo && config()->wordWrap())
01119 wrapText (editTagLineStart, editTagLineEnd);
01120
01121 editSessionNumber--;
01122
01123 if (editSessionNumber > 0)
01124 return;
01125
01126
01127 m_buffer->editEnd ();
01128
01129 if (editWithUndo)
01130 undoEnd();
01131
01132 for (uint z = 0; z < m_views.count(); z++)
01133 {
01134 m_views.at(z)->editEnd (editTagLineStart, editTagLineEnd, editTagFrom);
01135 }
01136
01137 setModified(true);
01138 emit textChanged ();
01139
01140 noViewUpdates = false;
01141 editIsRunning = false;
01142 }
01143
01144 bool KateDocument::wrapText (uint startLine, uint endLine)
01145 {
01146 uint col = config()->wordWrapAt();
01147
01148 if (col == 0)
01149 return false;
01150
01151 editStart ();
01152
01153 for (uint line = startLine; (line <= endLine) && (line < numLines()); line++)
01154 {
01155 KateTextLine::Ptr l = m_buffer->line(line);
01156
01157 if (!l)
01158 return false;
01159
01160 kdDebug (13020) << "try wrap line: " << line << endl;
01161
01162 if (l->lengthWithTabs(m_buffer->tabWidth()) > col)
01163 {
01164 KateTextLine::Ptr nextl = m_buffer->line(line+1);
01165
01166 kdDebug (13020) << "do wrap line: " << line << endl;
01167
01168 const QChar *text = l->text();
01169 uint eolPosition = l->length()-1;
01170
01171
01172 uint x = 0;
01173 const QString & t = l->string();
01174 uint z2 = 0;
01175 for ( ; z2 < l->length(); z2++)
01176 {
01177 if (t[z2] == QChar('\t'))
01178 x += m_buffer->tabWidth() - (x % m_buffer->tabWidth());
01179 else
01180 x++;
01181
01182 if (x > col)
01183 break;
01184 }
01185
01186 uint searchStart = KMIN (z2, l->length()-1);
01187
01188
01189
01190 if (searchStart == eolPosition && text[searchStart].isSpace())
01191 searchStart--;
01192
01193
01194
01195
01196
01197
01198
01199 int z = 0;
01200 uint nw = 0;
01201 for (z=searchStart; z > 0; z--)
01202 {
01203 if (text[z].isSpace()) break;
01204 if ( ! nw && highlight()->canBreakAt( text[z] , l->attribute(z) ) )
01205 nw = z;
01206 }
01207
01208 if (z > 0)
01209 {
01210
01211 editRemoveText (line, z, 1);
01212 }
01213 else
01214 {
01215
01216
01217
01218 if ( nw && nw < col ) nw++;
01219 z = nw ? nw : col;
01220 }
01221
01222 if (nextl && !nextl->isAutoWrapped())
01223 {
01224 editWrapLine (line, z, true);
01225 editMarkLineAutoWrapped (line+1, true);
01226
01227 endLine++;
01228 }
01229 else
01230 {
01231 if (nextl && (nextl->length() > 0) && !nextl->getChar(0).isSpace() && ((l->length() < 1) || !l->getChar(l->length()-1).isSpace()))
01232 editInsertText (line+1, 0, QString (" "));
01233
01234 bool newLineAdded = false;
01235 editWrapLine (line, z, false, &newLineAdded);
01236
01237 editMarkLineAutoWrapped (line+1, true);
01238
01239 endLine++;
01240 }
01241 }
01242 }
01243
01244 editEnd ();
01245
01246 return true;
01247 }
01248
01249 void KateDocument::editAddUndo (KateUndoGroup::UndoType type, uint line, uint col, uint len, const QString &text)
01250 {
01251 if (editIsRunning && editWithUndo && m_editCurrentUndo) {
01252 m_editCurrentUndo->addItem(type, line, col, len, text);
01253
01254
01255 if (redoItems.count()) {
01256 redoItems.setAutoDelete(true);
01257 redoItems.clear();
01258 redoItems.setAutoDelete(false);
01259 }
01260 }
01261 }
01262
01263 void KateDocument::editTagLine (uint line)
01264 {
01265 if (line < editTagLineStart)
01266 editTagLineStart = line;
01267
01268 if (line > editTagLineEnd)
01269 editTagLineEnd = line;
01270 }
01271
01272 void KateDocument::editInsertTagLine (uint line)
01273 {
01274 if (line < editTagLineStart)
01275 editTagLineStart = line;
01276
01277 if (line <= editTagLineEnd)
01278 editTagLineEnd++;
01279
01280 if (line > editTagLineEnd)
01281 editTagLineEnd = line;
01282
01283 editTagFrom = true;
01284 }
01285
01286 void KateDocument::editRemoveTagLine (uint line)
01287 {
01288 if (line < editTagLineStart)
01289 editTagLineStart = line;
01290
01291 if (line < editTagLineEnd)
01292 editTagLineEnd--;
01293
01294 if (line > editTagLineEnd)
01295 editTagLineEnd = line;
01296
01297 editTagFrom = true;
01298 }
01299
01300 bool KateDocument::editInsertText ( uint line, uint col, const QString &str )
01301 {
01302 if (!isReadWrite())
01303 return false;
01304
01305 QString s = str;
01306
01307 KateTextLine::Ptr l = m_buffer->line(line);
01308
01309 if (!l)
01310 return false;
01311
01312 if ( config()->configFlags() & KateDocumentConfig::cfReplaceTabsDyn )
01313 {
01314 uint tw = config()->tabWidth();
01315 int pos = 0;
01316 uint l = 0;
01317 while ( (pos = s.find('\t')) > -1 )
01318 {
01319 l = tw - ( (col + pos)%tw );
01320 s.replace( pos, 1, QString().fill( ' ', l ) );
01321 }
01322 }
01323
01324 editStart ();
01325
01326 editAddUndo (KateUndoGroup::editInsertText, line, col, s.length(), s);
01327
01328 l->insertText (col, s.length(), s.unicode());
01329
01330
01331 m_buffer->changeLine(line);
01332 editTagLine (line);
01333
01334 for( QPtrListIterator<KateSuperCursor> it (m_superCursors); it.current(); ++it )
01335 it.current()->editTextInserted (line, col, s.length());
01336
01337 editEnd ();
01338
01339 return true;
01340 }
01341
01342 bool KateDocument::editRemoveText ( uint line, uint col, uint len )
01343 {
01344 if (!isReadWrite())
01345 return false;
01346
01347 KateTextLine::Ptr l = m_buffer->line(line);
01348
01349 if (!l)
01350 return false;
01351
01352 editStart ();
01353
01354 editAddUndo (KateUndoGroup::editRemoveText, line, col, len, l->string().mid(col, len));
01355
01356 l->removeText (col, len);
01357 removeTrailingSpace( line );
01358
01359 m_buffer->changeLine(line);
01360
01361 editTagLine(line);
01362
01363 for( QPtrListIterator<KateSuperCursor> it (m_superCursors); it.current(); ++it )
01364 it.current()->editTextRemoved (line, col, len);
01365
01366 editEnd ();
01367
01368 return true;
01369 }
01370
01371 bool KateDocument::editMarkLineAutoWrapped ( uint line, bool autowrapped )
01372 {
01373 if (!isReadWrite())
01374 return false;
01375
01376 KateTextLine::Ptr l = m_buffer->line(line);
01377
01378 if (!l)
01379 return false;
01380
01381 editStart ();
01382
01383 editAddUndo (KateUndoGroup::editMarkLineAutoWrapped, line, autowrapped ? 1 : 0, 0, QString::null);
01384
01385 l->setAutoWrapped (autowrapped);
01386
01387 m_buffer->changeLine(line);
01388
01389 editEnd ();
01390
01391 return true;
01392 }
01393
01394 bool KateDocument::editWrapLine ( uint line, uint col, bool newLine, bool *newLineAdded)
01395 {
01396 if (!isReadWrite())
01397 return false;
01398
01399 KateTextLine::Ptr l = m_buffer->line(line);
01400
01401 if (!l)
01402 return false;
01403
01404 editStart ();
01405
01406 KateTextLine::Ptr nextLine = m_buffer->line(line+1);
01407
01408 int pos = l->length() - col;
01409
01410 if (pos < 0)
01411 pos = 0;
01412
01413 editAddUndo (KateUndoGroup::editWrapLine, line, col, pos, (!nextLine || newLine) ? "1" : "0");
01414
01415 if (!nextLine || newLine)
01416 {
01417 KateTextLine::Ptr textLine = new KateTextLine();
01418
01419 textLine->insertText (0, pos, l->text()+col, l->attributes()+col);
01420 l->truncate(col);
01421
01422 m_buffer->insertLine (line+1, textLine);
01423 m_buffer->changeLine(line);
01424
01425 QPtrList<KTextEditor::Mark> list;
01426 for( QIntDictIterator<KTextEditor::Mark> it( m_marks ); it.current(); ++it )
01427 {
01428 if( it.current()->line >= line )
01429 {
01430 if ((col == 0) || (it.current()->line > line))
01431 list.append( it.current() );
01432 }
01433 }
01434
01435 for( QPtrListIterator<KTextEditor::Mark> it( list ); it.current(); ++it )
01436 {
01437 KTextEditor::Mark* mark = m_marks.take( it.current()->line );
01438 mark->line++;
01439 m_marks.insert( mark->line, mark );
01440 }
01441
01442 if( !list.isEmpty() )
01443 emit marksChanged();
01444
01445 editInsertTagLine (line);
01446
01447
01448 if (newLineAdded)
01449 (*newLineAdded) = true;
01450 }
01451 else
01452 {
01453 nextLine->insertText (0, pos, l->text()+col, l->attributes()+col);
01454 l->truncate(col);
01455
01456 m_buffer->changeLine(line);
01457 m_buffer->changeLine(line+1);
01458
01459
01460 if (newLineAdded)
01461 (*newLineAdded) = false;
01462 }
01463
01464 editTagLine(line);
01465 editTagLine(line+1);
01466
01467 for( QPtrListIterator<KateSuperCursor> it (m_superCursors); it.current(); ++it )
01468 it.current()->editLineWrapped (line, col, !nextLine || newLine);
01469
01470 editEnd ();
01471
01472 return true;
01473 }
01474
01475 bool KateDocument::editUnWrapLine ( uint line, bool removeLine, uint length )
01476 {
01477 if (!isReadWrite())
01478 return false;
01479
01480 KateTextLine::Ptr l = m_buffer->line(line);
01481 KateTextLine::Ptr nextLine = m_buffer->line(line+1);
01482
01483 if (!l || !nextLine)
01484 return false;
01485
01486 editStart ();
01487
01488 uint col = l->length ();
01489
01490 editAddUndo (KateUndoGroup::editUnWrapLine, line, col, length, removeLine ? "1" : "0");
01491
01492 if (removeLine)
01493 {
01494 l->insertText (col, nextLine->length(), nextLine->text(), nextLine->attributes());
01495
01496 m_buffer->changeLine(line);
01497 m_buffer->removeLine(line+1);
01498 }
01499 else
01500 {
01501 l->insertText (col, (nextLine->length() < length) ? nextLine->length() : length,
01502 nextLine->text(), nextLine->attributes());
01503 nextLine->removeText (0, (nextLine->length() < length) ? nextLine->length() : length);
01504
01505 m_buffer->changeLine(line);
01506 m_buffer->changeLine(line+1);
01507 }
01508
01509 QPtrList<KTextEditor::Mark> list;
01510 for( QIntDictIterator<KTextEditor::Mark> it( m_marks ); it.current(); ++it )
01511 {
01512 if( it.current()->line >= line+1 )
01513 list.append( it.current() );
01514
01515 if ( it.current()->line == line+1 )
01516 {
01517 KTextEditor::Mark* mark = m_marks.take( line );
01518
01519 if (mark)
01520 {
01521 it.current()->type |= mark->type;
01522 }
01523 }
01524 }
01525
01526 for( QPtrListIterator<KTextEditor::Mark> it( list ); it.current(); ++it )
01527 {
01528 KTextEditor::Mark* mark = m_marks.take( it.current()->line );
01529 mark->line--;
01530 m_marks.insert( mark->line, mark );
01531 }
01532
01533 if( !list.isEmpty() )
01534 emit marksChanged();
01535
01536 if (removeLine)
01537 editRemoveTagLine(line);
01538
01539 editTagLine(line);
01540 editTagLine(line+1);
01541
01542 for( QPtrListIterator<KateSuperCursor> it (m_superCursors); it.current(); ++it )
01543 it.current()->editLineUnWrapped (line, col, removeLine, length);
01544
01545 editEnd ();
01546
01547 return true;
01548 }
01549
01550 bool KateDocument::editInsertLine ( uint line, const QString &s )
01551 {
01552 if (!isReadWrite())
01553 return false;
01554
01555 if ( line > numLines() )
01556 return false;
01557
01558 editStart ();
01559
01560 editAddUndo (KateUndoGroup::editInsertLine, line, 0, s.length(), s);
01561
01562 removeTrailingSpace( line );
01563
01564 KateTextLine::Ptr tl = new KateTextLine();
01565 tl->insertText (0, s.length(), s.unicode(), 0);
01566 m_buffer->insertLine(line, tl);
01567 m_buffer->changeLine(line);
01568
01569 editInsertTagLine (line);
01570 editTagLine(line);
01571
01572 removeTrailingSpace( line );
01573
01574 QPtrList<KTextEditor::Mark> list;
01575 for( QIntDictIterator<KTextEditor::Mark> it( m_marks ); it.current(); ++it )
01576 {
01577 if( it.current()->line >= line )
01578 list.append( it.current() );
01579 }
01580
01581 for( QPtrListIterator<KTextEditor::Mark> it( list ); it.current(); ++it )
01582 {
01583 KTextEditor::Mark* mark = m_marks.take( it.current()->line );
01584 mark->line++;
01585 m_marks.insert( mark->line, mark );
01586 }
01587
01588 if( !list.isEmpty() )
01589 emit marksChanged();
01590
01591 for( QPtrListIterator<KateSuperCursor> it (m_superCursors); it.current(); ++it )
01592 it.current()->editLineInserted (line);
01593
01594 editEnd ();
01595
01596 return true;
01597 }
01598
01599 bool KateDocument::editRemoveLine ( uint line )
01600 {
01601 if (!isReadWrite())
01602 return false;
01603
01604 if ( line > lastLine() )
01605 return false;
01606
01607 if ( numLines() == 1 )
01608 return editRemoveText (0, 0, m_buffer->line(0)->length());
01609
01610 editStart ();
01611
01612 editAddUndo (KateUndoGroup::editRemoveLine, line, 0, lineLength(line), textLine(line));
01613
01614 m_buffer->removeLine(line);
01615
01616 editRemoveTagLine (line);
01617
01618 QPtrList<KTextEditor::Mark> list;
01619 KTextEditor::Mark* rmark = 0;
01620 for( QIntDictIterator<KTextEditor::Mark> it( m_marks ); it.current(); ++it )
01621 {
01622 if ( (it.current()->line > line) )
01623 list.append( it.current() );
01624 else if ( (it.current()->line == line) )
01625 rmark = it.current();
01626 }
01627
01628 if (rmark)
01629 delete (m_marks.take (rmark->line));
01630
01631 for( QPtrListIterator<KTextEditor::Mark> it( list ); it.current(); ++it )
01632 {
01633 KTextEditor::Mark* mark = m_marks.take( it.current()->line );
01634 mark->line--;
01635 m_marks.insert( mark->line, mark );
01636 }
01637
01638 if( !list.isEmpty() )
01639 emit marksChanged();
01640
01641 for( QPtrListIterator<KateSuperCursor> it (m_superCursors); it.current(); ++it )
01642 it.current()->editLineRemoved (line);
01643
01644 editEnd();
01645
01646 return true;
01647 }
01648
01649
01650
01651
01652 bool KateDocument::setSelection( const KateTextCursor& start, const KateTextCursor& end )
01653 {
01654 KateTextCursor oldSelectStart = selectStart;
01655 KateTextCursor oldSelectEnd = selectEnd;
01656
01657 if (start <= end) {
01658 selectStart.setPos(start);
01659 selectEnd.setPos(end);
01660 } else {
01661 selectStart.setPos(end);
01662 selectEnd.setPos(start);
01663 }
01664
01665 tagSelection(oldSelectStart, oldSelectEnd);
01666
01667 repaintViews();
01668
01669 emit selectionChanged ();
01670
01671 return true;
01672 }
01673
01674 bool KateDocument::setSelection( uint startLine, uint startCol, uint endLine, uint endCol )
01675 {
01676 if (hasSelection())
01677 clearSelection(false, false);
01678
01679 return setSelection( KateTextCursor(startLine, startCol), KateTextCursor(endLine, endCol) );
01680 }
01681
01682 bool KateDocument::clearSelection()
01683 {
01684 return clearSelection(true);
01685 }
01686
01687 bool KateDocument::clearSelection(bool redraw, bool finishedChangingSelection)
01688 {
01689 if( !hasSelection() )
01690 return false;
01691
01692 KateTextCursor oldSelectStart = selectStart;
01693 KateTextCursor oldSelectEnd = selectEnd;
01694
01695 selectStart.setPos(-1, -1);
01696 selectEnd.setPos(-1, -1);
01697
01698 tagSelection(oldSelectStart, oldSelectEnd);
01699
01700 oldSelectStart = selectStart;
01701 oldSelectEnd = selectEnd;
01702
01703 if (redraw)
01704 repaintViews();
01705
01706 if (finishedChangingSelection)
01707 emit selectionChanged();
01708
01709 return true;
01710 }
01711
01712 bool KateDocument::hasSelection() const
01713 {
01714 return selectStart != selectEnd;
01715 }
01716
01717 QString KateDocument::selectionAsHtml() const
01718 {
01719 kdDebug(13020) << "KateDocument::selection()" << endl;
01720 int sc = selectStart.col();
01721 int ec = selectEnd.col();
01722
01723 if ( blockSelect )
01724 {
01725 if (sc > ec)
01726 {
01727 uint tmp = sc;
01728 sc = ec;
01729 ec = tmp;
01730 }
01731 }
01732 return textAsHtml (selectStart.line(), sc, selectEnd.line(), ec, blockSelect);
01733 }
01734 QString KateDocument::selection() const
01735 {
01736 kdDebug(13020) << "KateDocument::selection()" << endl;
01737 int sc = selectStart.col();
01738 int ec = selectEnd.col();
01739
01740 if ( blockSelect )
01741 {
01742 if (sc > ec)
01743 {
01744 uint tmp = sc;
01745 sc = ec;
01746 ec = tmp;
01747 }
01748 }
01749 return text (selectStart.line(), sc, selectEnd.line(), ec, blockSelect);
01750 }
01751
01752 bool KateDocument::removeSelectedText ()
01753 {
01754 if (!hasSelection())
01755 return false;
01756
01757 editStart ();
01758
01759 int sc = selectStart.col();
01760 int ec = selectEnd.col();
01761
01762 if ( blockSelect )
01763 {
01764 if (sc > ec)
01765 {
01766 uint tmp = sc;
01767 sc = ec;
01768 ec = tmp;
01769 }
01770 }
01771
01772 removeText (selectStart.line(), sc, selectEnd.line(), ec, blockSelect);
01773
01774
01775 clearSelection(false);
01776
01777 editEnd ();
01778
01779 return true;
01780 }
01781
01782 bool KateDocument::selectAll()
01783 {
01784 setBlockSelectionMode (false);
01785
01786 return setSelection (0, 0, lastLine(), lineLength(lastLine()));
01787 }
01788
01789
01790
01791
01792 bool KateDocument::blockSelectionMode ()
01793 {
01794 return blockSelect;
01795 }
01796
01797 bool KateDocument::setBlockSelectionMode (bool on)
01798 {
01799 if (on != blockSelect)
01800 {
01801 blockSelect = on;
01802
01803 KateTextCursor oldSelectStart = selectStart;
01804 KateTextCursor oldSelectEnd = selectEnd;
01805
01806 clearSelection(false, false);
01807
01808 setSelection(oldSelectStart, oldSelectEnd);
01809
01810 for (KateView * view = m_views.first(); view; view = m_views.next())
01811 {
01812 view->slotSelectionTypeChanged();
01813 }
01814 }
01815
01816 return true;
01817 }
01818
01819 bool KateDocument::toggleBlockSelectionMode ()
01820 {
01821 return setBlockSelectionMode (!blockSelect);
01822 }
01823
01824
01825
01826
01827 uint KateDocument::undoCount () const
01828 {
01829 return undoItems.count ();
01830 }
01831
01832 uint KateDocument::redoCount () const
01833 {
01834 return redoItems.count ();
01835 }
01836
01837 uint KateDocument::undoSteps () const
01838 {
01839 return m_config->undoSteps();
01840 }
01841
01842 void KateDocument::setUndoSteps(uint steps)
01843 {
01844 m_config->setUndoSteps (steps);
01845 }
01846
01847 void KateDocument::undo()
01848 {
01849 if ((undoItems.count() > 0) && undoItems.last())
01850 {
01851 clearSelection ();
01852
01853 undoItems.last()->undo();
01854 redoItems.append (undoItems.last());
01855 undoItems.removeLast ();
01856 updateModified();
01857
01858 emit undoChanged ();
01859 }
01860 }
01861
01862 void KateDocument::redo()
01863 {
01864 if ((redoItems.count() > 0) && redoItems.last())
01865 {
01866 clearSelection ();
01867
01868 redoItems.last()->redo();
01869 undoItems.append (redoItems.last());
01870 redoItems.removeLast ();
01871 updateModified();
01872
01873 emit undoChanged ();
01874 }
01875 }
01876
01877 void KateDocument::updateModified()
01878 {
01879 if ( ( lastUndoGroupWhenSaved &&
01880 !undoItems.isEmpty() &&
01881 undoItems.last() == lastUndoGroupWhenSaved )
01882 || ( undoItems.isEmpty() && docWasSavedWhenUndoWasEmpty ) )
01883 {
01884 setModified( false );
01885 kdDebug(13020) << k_funcinfo << "setting modified to false!" << endl;
01886 };
01887 }
01888
01889 void KateDocument::clearUndo()
01890 {
01891 undoItems.setAutoDelete (true);
01892 undoItems.clear ();
01893 undoItems.setAutoDelete (false);
01894
01895 lastUndoGroupWhenSaved = 0;
01896 docWasSavedWhenUndoWasEmpty = false;
01897
01898 emit undoChanged ();
01899 }
01900
01901 void KateDocument::clearRedo()
01902 {
01903 redoItems.setAutoDelete (true);
01904 redoItems.clear ();
01905 redoItems.setAutoDelete (false);
01906
01907 emit undoChanged ();
01908 }
01909
01910 QPtrList<KTextEditor::Cursor> KateDocument::cursors () const
01911 {
01912 return myCursors;
01913 }
01914
01915
01916
01917
01918 bool KateDocument::searchText (unsigned int startLine, unsigned int startCol, const QString &text, unsigned int *foundAtLine, unsigned int *foundAtCol, unsigned int *matchLen, bool casesensitive, bool backwards)
01919 {
01920 if (text.isEmpty())
01921 return false;
01922
01923 int line = startLine;
01924 int col = startCol;
01925
01926 if (!backwards)
01927 {
01928 int searchEnd = lastLine();
01929
01930 while (line <= searchEnd)
01931 {
01932 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
01933
01934 if (!textLine)
01935 return false;
01936
01937 uint foundAt, myMatchLen;
01938 bool found = textLine->searchText (col, text, &foundAt, &myMatchLen, casesensitive, false);
01939
01940 if (found)
01941 {
01942 (*foundAtLine) = line;
01943 (*foundAtCol) = foundAt;
01944 (*matchLen) = myMatchLen;
01945 return true;
01946 }
01947
01948 col = 0;
01949 line++;
01950 }
01951 }
01952 else
01953 {
01954
01955 int searchEnd = 0;
01956
01957 while (line >= searchEnd)
01958 {
01959 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
01960
01961 if (!textLine)
01962 return false;
01963
01964 uint foundAt, myMatchLen;
01965 bool found = textLine->searchText (col, text, &foundAt, &myMatchLen, casesensitive, true);
01966
01967 if (found)
01968 {
01969 if ((uint) line == startLine && foundAt + myMatchLen >= (uint) col
01970 && line == selectStart.line() && foundAt == (uint) selectStart.col()
01971 && line == selectEnd.line() && foundAt + myMatchLen == (uint) selectEnd.col())
01972 {
01973
01974
01975 if (foundAt > 0)
01976 col = foundAt - 1;
01977 else {
01978 if (--line >= 0)
01979 col = lineLength(line);
01980 }
01981 continue;
01982 }
01983
01984 (*foundAtLine) = line;
01985 (*foundAtCol) = foundAt;
01986 (*matchLen) = myMatchLen;
01987 return true;
01988 }
01989
01990 if (line >= 1)
01991 col = lineLength(line-1);
01992
01993 line--;
01994 }
01995 }
01996
01997 return false;
01998 }
01999
02000 bool KateDocument::searchText (unsigned int startLine, unsigned int startCol, const QRegExp ®exp, unsigned int *foundAtLine, unsigned int *foundAtCol, unsigned int *matchLen, bool backwards)
02001 {
02002 kdDebug(13020)<<"KateDocument::searchText( "<<startLine<<", "<<startCol<<", "<<regexp.pattern()<<", "<<backwards<<" )"<<endl;
02003 if (regexp.isEmpty() || !regexp.isValid())
02004 return false;
02005
02006 int line = startLine;
02007 int col = startCol;
02008
02009 if (!backwards)
02010 {
02011 int searchEnd = lastLine();
02012
02013 while (line <= searchEnd)
02014 {
02015 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
02016
02017 if (!textLine)
02018 return false;
02019
02020 uint foundAt, myMatchLen;
02021 bool found = textLine->searchText (col, regexp, &foundAt, &myMatchLen, false);
02022
02023 if (found)
02024 {
02025
02026
02027 if (myMatchLen == 0 && (uint) line == startLine && foundAt == (uint) col)
02028 {
02029 if (col < lineLength(line))
02030 col++;
02031 else {
02032 line++;
02033 col = 0;
02034 }
02035 continue;
02036 }
02037
02038 (*foundAtLine) = line;
02039 (*foundAtCol) = foundAt;
02040 (*matchLen) = myMatchLen;
02041 return true;
02042 }
02043
02044 col = 0;
02045 line++;
02046 }
02047 }
02048 else
02049 {
02050
02051 int searchEnd = 0;
02052
02053 while (line >= searchEnd)
02054 {
02055 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
02056
02057 if (!textLine)
02058 return false;
02059
02060 uint foundAt, myMatchLen;
02061 bool found = textLine->searchText (col, regexp, &foundAt, &myMatchLen, true);
02062
02063 if (found)
02064 {
02065 if ((uint) line == startLine && foundAt + myMatchLen >= (uint) col
02066 && line == selectStart.line() && foundAt == (uint) selectStart.col()
02067 && line == selectEnd.line() && foundAt + myMatchLen == (uint) selectEnd.col())
02068 {
02069
02070
02071 if (foundAt > 0)
02072 col = foundAt - 1;
02073 else {
02074 if (--line >= 0)
02075 col = lineLength(line);
02076 }
02077 continue;
02078 }
02079
02080 (*foundAtLine) = line;
02081 (*foundAtCol) = foundAt;
02082 (*matchLen) = myMatchLen;
02083 return true;
02084 }
02085
02086 if (line >= 1)
02087 col = lineLength(line-1);
02088
02089 line--;
02090 }
02091 }
02092
02093 return false;
02094 }
02095
02096
02097
02098
02099 uint KateDocument::hlMode ()
02100 {
02101 return KateHlManager::self()->findHl(highlight());
02102 }
02103
02104 bool KateDocument::setHlMode (uint mode)
02105 {
02106 m_buffer->setHighlight (mode);
02107
02108 if (true)
02109 {
02110 setDontChangeHlOnSave();
02111 return true;
02112 }
02113
02114 return false;
02115 }
02116
02117 void KateDocument::bufferHlChanged ()
02118 {
02119
02120 makeAttribs(false);
02121
02122 emit hlChanged();
02123 }
02124
02125 uint KateDocument::hlModeCount ()
02126 {
02127 return KateHlManager::self()->highlights();
02128 }
02129
02130 QString KateDocument::hlModeName (uint mode)
02131 {
02132 return KateHlManager::self()->hlName (mode);
02133 }
02134
02135 QString KateDocument::hlModeSectionName (uint mode)
02136 {
02137 return KateHlManager::self()->hlSection (mode);
02138 }
02139
02140 void KateDocument::setDontChangeHlOnSave()
02141 {
02142 hlSetByUser = true;
02143 }
02144
02145
02146
02147 void KateDocument::readConfig(KConfig *config)
02148 {
02149 config->setGroup("Kate Document Defaults");
02150
02151
02152 KateBuffer::setMaxLoadedBlocks (config->readNumEntry("Maximal Loaded Blocks", KateBuffer::maxLoadedBlocks()));
02153
02154 KateDocumentConfig::global()->readConfig (config);
02155
02156 config->setGroup("Kate View Defaults");
02157 KateViewConfig::global()->readConfig (config);
02158
02159 config->setGroup("Kate Renderer Defaults");
02160 KateRendererConfig::global()->readConfig (config);
02161 }
02162
02163 void KateDocument::writeConfig(KConfig *config)
02164 {
02165 config->setGroup("Kate Document Defaults");
02166
02167
02168 config->writeEntry("Maximal Loaded Blocks", KateBuffer::maxLoadedBlocks());
02169
02170 KateDocumentConfig::global()->writeConfig (config);
02171
02172 config->setGroup("Kate View Defaults");
02173 KateViewConfig::global()->writeConfig (config);
02174
02175 config->setGroup("Kate Renderer Defaults");
02176 KateRendererConfig::global()->writeConfig (config);
02177 }
02178
02179 void KateDocument::readConfig()
02180 {
02181 KConfig *config = kapp->config();
02182 readConfig (config);
02183 }
02184
02185 void KateDocument::writeConfig()
02186 {
02187 KConfig *config = kapp->config();
02188 writeConfig (config);
02189 config->sync();
02190 }
02191
02192 void KateDocument::readSessionConfig(KConfig *kconfig)
02193 {
02194
02195 KURL url (kconfig->readEntry("URL"));
02196
02197
02198 QString tmpenc=kconfig->readEntry("Encoding");
02199 if (!tmpenc.isEmpty() && (tmpenc != encoding()))
02200 setEncoding(tmpenc);
02201
02202
02203 if (!url.isEmpty() && url.isValid())
02204 openURL (url);
02205
02206
02207 m_buffer->setHighlight(KateHlManager::self()->nameFind(kconfig->readEntry("Highlighting")));
02208
02209 if (hlMode() > 0)
02210 hlSetByUser = true;
02211
02212
02213 config()->setIndentationMode( (uint)kconfig->readNumEntry("Indentation Mode", config()->indentationMode() ) );
02214
02215
02216 QValueList<int> marks = kconfig->readIntListEntry("Bookmarks");
02217 for( uint i = 0; i < marks.count(); i++ )
02218 addMark( marks[i], KateDocument::markType01 );
02219 }
02220
02221 void KateDocument::writeSessionConfig(KConfig *kconfig)
02222 {
02223
02224 kconfig->writeEntry("URL", m_url.prettyURL() );
02225
02226
02227 kconfig->writeEntry("Encoding",encoding());
02228
02229
02230 kconfig->writeEntry("Highlighting", highlight()->name());
02231
02232 kconfig->writeEntry("Indentation Mode", config()->indentationMode() );
02233
02234
02235 QValueList<int> marks;
02236 for( QIntDictIterator<KTextEditor::Mark> it( m_marks );
02237 it.current() && it.current()->type & KTextEditor::MarkInterface::markType01;
02238 ++it )
02239 marks << it.current()->line;
02240
02241 kconfig->writeEntry( "Bookmarks", marks );
02242 }
02243
02244 void KateDocument::configDialog()
02245 {
02246 KDialogBase *kd = new KDialogBase ( KDialogBase::IconList,
02247 i18n("Configure"),
02248 KDialogBase::Ok | KDialogBase::Cancel | KDialogBase::Help,
02249 KDialogBase::Ok,
02250 kapp->mainWidget() );
02251
02252 #ifndef Q_WS_WIN //TODO: reenable
02253 KWin::setIcons( kd->winId(), kapp->icon(), kapp->miniIcon() );
02254 #endif
02255
02256 QPtrList<KTextEditor::ConfigPage> editorPages;
02257
02258 for (uint i = 0; i < KTextEditor::configInterfaceExtension (this)->configPages (); i++)
02259 {
02260 QStringList path;
02261 path.clear();
02262 path << KTextEditor::configInterfaceExtension (this)->configPageName (i);
02263 QVBox *page = kd->addVBoxPage(path, KTextEditor::configInterfaceExtension (this)->configPageFullName (i),
02264 KTextEditor::configInterfaceExtension (this)->configPagePixmap(i, KIcon::SizeMedium) );
02265
02266 editorPages.append (KTextEditor::configInterfaceExtension (this)->configPage(i, page));
02267 }
02268
02269 if (kd->exec())
02270 {
02271 KateDocumentConfig::global()->configStart ();
02272 KateViewConfig::global()->configStart ();
02273 KateRendererConfig::global()->configStart ();
02274
02275 for (uint i=0; i<editorPages.count(); i++)
02276 {
02277 editorPages.at(i)->apply();
02278 }
02279
02280 KateDocumentConfig::global()->configEnd ();
02281 KateViewConfig::global()->configEnd ();
02282 KateRendererConfig::global()->configEnd ();
02283
02284 writeConfig ();
02285 }
02286
02287 delete kd;
02288 }
02289
02290 uint KateDocument::mark( uint line )
02291 {
02292 if( !m_marks[line] )
02293 return 0;
02294 return m_marks[line]->type;
02295 }
02296
02297 void KateDocument::setMark( uint line, uint markType )
02298 {
02299 clearMark( line );
02300 addMark( line, markType );
02301 }
02302
02303 void KateDocument::clearMark( uint line )
02304 {
02305 if( line > lastLine() )
02306 return;
02307
02308 if( !m_marks[line] )
02309 return;
02310
02311 KTextEditor::Mark* mark = m_marks.take( line );
02312 emit markChanged( *mark, MarkRemoved );
02313 emit marksChanged();
02314 delete mark;
02315 tagLines( line, line );
02316 repaintViews(true);
02317 }
02318
02319 void KateDocument::addMark( uint line, uint markType )
02320 {
02321 if( line > lastLine())
02322 return;
02323
02324 if( markType == 0 )
02325 return;
02326
02327 if( m_marks[line] ) {
02328 KTextEditor::Mark* mark = m_marks[line];
02329
02330
02331 markType &= ~mark->type;
02332
02333 if( markType == 0 )
02334 return;
02335
02336
02337 mark->type |= markType;
02338 } else {
02339 KTextEditor::Mark *mark = new KTextEditor::Mark;
02340 mark->line = line;
02341 mark->type = markType;
02342 m_marks.insert( line, mark );
02343 }
02344
02345
02346 KTextEditor::Mark temp;
02347 temp.line = line;
02348 temp.type = markType;
02349 emit markChanged( temp, MarkAdded );
02350
02351 emit marksChanged();
02352 tagLines( line, line );
02353 repaintViews(true);
02354 }
02355
02356 void KateDocument::removeMark( uint line, uint markType )
02357 {
02358 if( line > lastLine() )
02359 return;
02360 if( !m_marks[line] )
02361 return;
02362
02363 KTextEditor::Mark* mark = m_marks[line];
02364
02365
02366 markType &= mark->type;
02367
02368 if( markType == 0 )
02369 return;
02370
02371
02372 mark->type &= ~markType;
02373
02374
02375 KTextEditor::Mark temp;
02376 temp.line = line;
02377 temp.type = markType;
02378 emit markChanged( temp, MarkRemoved );
02379
02380 if( mark->type == 0 )
02381 m_marks.remove( line );
02382
02383 emit marksChanged();
02384 tagLines( line, line );
02385 repaintViews(true);
02386 }
02387
02388 QPtrList<KTextEditor::Mark> KateDocument::marks()
02389 {
02390 QPtrList<KTextEditor::Mark> list;
02391
02392 for( QIntDictIterator<KTextEditor::Mark> it( m_marks );
02393 it.current(); ++it ) {
02394 list.append( it.current() );
02395 }
02396
02397 return list;
02398 }
02399
02400 void KateDocument::clearMarks()
02401 {
02402 for( QIntDictIterator<KTextEditor::Mark> it( m_marks );
02403 it.current(); ++it ) {
02404 KTextEditor::Mark* mark = it.current();
02405 emit markChanged( *mark, MarkRemoved );
02406 tagLines( mark->line, mark->line );
02407 }
02408
02409 m_marks.clear();
02410
02411 emit marksChanged();
02412 repaintViews(true);
02413 }
02414
02415 void KateDocument::setPixmap( MarkInterface::MarkTypes type, const QPixmap& pixmap )
02416 {
02417 m_markPixmaps.replace( type, new QPixmap( pixmap ) );
02418 }
02419
02420 void KateDocument::setDescription( MarkInterface::MarkTypes type, const QString& description )
02421 {
02422 m_markDescriptions.replace( type, new QString( description ) );
02423 }
02424
02425 QPixmap *KateDocument::markPixmap( MarkInterface::MarkTypes type )
02426 {
02427 return m_markPixmaps[type];
02428 }
02429
02430 QColor KateDocument::markColor( MarkInterface::MarkTypes type )
02431 {
02432 uint reserved = (0x1 << KTextEditor::MarkInterface::reservedMarkersCount()) - 1;
02433 if ((uint)type >= (uint)markType01 && (uint)type <= reserved) {
02434 return KateRendererConfig::global()->lineMarkerColor(type);
02435 } else {
02436 return QColor();
02437 }
02438 }
02439
02440 QString KateDocument::markDescription( MarkInterface::MarkTypes type )
02441 {
02442 if( m_markDescriptions[type] )
02443 return *m_markDescriptions[type];
02444 return QString::null;
02445 }
02446
02447 void KateDocument::setMarksUserChangable( uint markMask )
02448 {
02449 m_editableMarks = markMask;
02450 }
02451
02452 uint KateDocument::editableMarks()
02453 {
02454 return m_editableMarks;
02455 }
02456
02457
02458
02459 bool KateDocument::printDialog ()
02460 {
02461 return KatePrinter::print (this);
02462 }
02463
02464 bool KateDocument::print ()
02465 {
02466 return KatePrinter::print (this);
02467 }
02468
02469
02470
02471 QString KateDocument::mimeType()
02472 {
02473 KMimeType::Ptr result = KMimeType::defaultMimeTypePtr();
02474
02475
02476 if ( ! m_url.isEmpty() )
02477 result = KMimeType::findByURL( m_url );
02478
02479 else if ( m_url.isEmpty() || ! m_url.isLocalFile() )
02480 result = mimeTypeForContent();
02481
02482 return result->name();
02483 }
02484
02485
02486 long KateDocument::fileSize()
02487 {
02488 return 0;
02489 }
02490
02491
02492 QString KateDocument::niceFileSize()
02493 {
02494 return "UNKNOWN";
02495 }
02496
02497 KMimeType::Ptr KateDocument::mimeTypeForContent()
02498 {
02499 QByteArray buf (1024);
02500 uint bufpos = 0;
02501
02502 for (uint i=0; i < numLines(); i++)
02503 {
02504 QString line = textLine( i );
02505 uint len = line.length() + 1;
02506
02507 if (bufpos + len > 1024)
02508 len = 1024 - bufpos;
02509
02510 memcpy(&buf[bufpos], (line + "\n").latin1(), len);
02511
02512 bufpos += len;
02513
02514 if (bufpos >= 1024)
02515 break;
02516 }
02517 buf.resize( bufpos );
02518
02519 int accuracy = 0;
02520 return KMimeType::findByContent( buf, &accuracy );
02521 }
02522
02523
02524
02525
02526
02527 bool KateDocument::openURL( const KURL &url )
02528 {
02529
02530
02531 if ( !url.isValid() )
02532 return false;
02533
02534
02535 if ( !closeURL() )
02536 return false;
02537
02538
02539 m_url = url;
02540
02541 if ( m_url.isLocalFile() )
02542 {
02543
02544
02545 m_file = m_url.path();
02546
02547 emit started( 0 );
02548
02549 if (openFile())
02550 {
02551 emit completed();
02552 emit setWindowCaption( m_url.prettyURL() );
02553
02554 return true;
02555 }
02556
02557 return false;
02558 }
02559 else
02560 {
02561
02562
02563 m_bTemp = true;
02564
02565 m_tempFile = new KTempFile ();
02566 m_file = m_tempFile->name();
02567
02568 m_job = KIO::get ( url, false, isProgressInfoEnabled() );
02569
02570
02571 connect( m_job, SIGNAL( data( KIO::Job*, const QByteArray& ) ),
02572 SLOT( slotDataKate( KIO::Job*, const QByteArray& ) ) );
02573
02574 connect( m_job, SIGNAL( result( KIO::Job* ) ),
02575 SLOT( slotFinishedKate( KIO::Job* ) ) );
02576
02577 QWidget *w = widget ();
02578 if (!w && !m_views.isEmpty ())
02579 w = m_views.first();
02580
02581 if (w)
02582 m_job->setWindow (w->topLevelWidget());
02583
02584 emit started( m_job );
02585
02586 return true;
02587 }
02588 }
02589
02590 void KateDocument::slotDataKate ( KIO::Job *, const QByteArray &data )
02591 {
02592
02593
02594 if (!m_tempFile || !m_tempFile->file())
02595 return;
02596
02597 m_tempFile->file()->writeBlock (data);
02598 }
02599
02600 void KateDocument::slotFinishedKate ( KIO::Job * job )
02601 {
02602
02603
02604 if (!m_tempFile)
02605 return;
02606
02607 delete m_tempFile;
02608 m_tempFile = 0;
02609 m_job = 0;
02610
02611 if (job->error())
02612 emit canceled( job->errorString() );
02613 else
02614 {
02615 if ( openFile(job) )
02616 emit setWindowCaption( m_url.prettyURL() );
02617 emit completed();
02618 }
02619 }
02620
02621 void KateDocument::abortLoadKate()
02622 {
02623 if ( m_job )
02624 {
02625 kdDebug(13020) << "Aborting job " << m_job << endl;
02626 m_job->kill();
02627 m_job = 0;
02628 }
02629
02630 delete m_tempFile;
02631 m_tempFile = 0;
02632 }
02633
02634 bool KateDocument::openFile()
02635 {
02636 return openFile (0);
02637 }
02638
02639 bool KateDocument::openFile(KIO::Job * job)
02640 {
02641
02642 activateDirWatch ();
02643
02644
02645
02646
02647 if (job)
02648 {
02649 QString metaDataCharset = job->queryMetaData("charset");
02650
02651
02652 if (!metaDataCharset.isEmpty () && (!m_config->isSetEncoding() || m_config->encoding().isEmpty()))
02653 setEncoding (metaDataCharset);
02654 }
02655
02656
02657
02658
02659 QString serviceType = m_extension->urlArgs().serviceType.simplifyWhiteSpace();
02660 int pos = serviceType.find(';');
02661 if (pos != -1)
02662 setEncoding (serviceType.mid(pos+1));
02663
02664
02665 bool success = m_buffer->openFile (m_file);
02666
02667
02668
02669 if (success)
02670 {
02671
02672
02673
02674
02675
02676
02677 if (!hlSetByUser)
02678 {
02679 int hl (KateHlManager::self()->detectHighlighting (this));
02680
02681 if (hl >= 0)
02682 m_buffer->setHighlight(hl);
02683 }
02684
02685
02686 updateFileType (KateFactory::self()->fileTypeManager()->fileType (this));
02687
02688
02689 readDirConfig ();
02690
02691
02692 readVariables();
02693
02694
02695 createDigest( m_digest );
02696 }
02697
02698
02699
02700
02701 updateViews();
02702
02703
02704
02705
02706 emit fileNameChanged ();
02707
02708
02709
02710
02711 setDocName (QString::null);
02712
02713
02714
02715
02716 if (m_modOnHd)
02717 {
02718 m_modOnHd = false;
02719 m_modOnHdReason = 0;
02720 emit modifiedOnDisc (this, m_modOnHd, 0);
02721 }
02722
02723
02724
02725
02726 if (s_openErrorDialogsActivated)
02727 {
02728 if (!success && m_buffer->loadingBorked())
02729 KMessageBox::error (widget(), i18n ("The file %1 could not be loaded completely, as there is not enough temporary disk storage for it.").arg(m_url.url()));
02730 else if (!success)
02731 KMessageBox::error (widget(), i18n ("The file %1 could not be loaded, as it was not possible to read from it.\n\nCheck if you have read access to this file.").arg(m_url.url()));
02732 }
02733
02734
02735 if (m_buffer->binary())
02736 {
02737
02738 setReadWrite( false );
02739
02740 KMessageBox::information (widget()
02741 , i18n ("The file %1 is a binary, saving it will result in a corrupt file.").arg(m_url.url())
02742 , i18n ("Binary File Opened")
02743 , "Binary File Opened Warning");
02744 }
02745
02746
02747
02748
02749 return success;
02750 }
02751
02752 bool KateDocument::save()
02753 {
02754 bool l ( url().isLocalFile() );
02755
02756 if ( ( l && config()->backupFlags() & KateDocumentConfig::LocalFiles )
02757 || ( ! l && config()->backupFlags() & KateDocumentConfig::RemoteFiles ) )
02758 {
02759 KURL u( url() );
02760 u.setFileName( config()->backupPrefix() + url().fileName() + config()->backupSuffix() );
02761
02762 kdDebug () << "backup src file name: " << url() << endl;
02763 kdDebug () << "backup dst file name: " << u << endl;
02764
02765
02766 mode_t perms = 0600;
02767 KIO::UDSEntry fentry;
02768 if (KIO::NetAccess::stat (url(), fentry, kapp->mainWidget()))
02769 {
02770 kdDebug () << "stating succesfull: " << url() << endl;
02771 KFileItem item (fentry, url());
02772 perms = item.permissions();
02773 }
02774
02775
02776
02777 if ( (!KIO::NetAccess::exists( u, false, kapp->mainWidget() ) || KIO::NetAccess::del( u, kapp->mainWidget() ))
02778 && KIO::NetAccess::file_copy( url(), u, perms, true, false, kapp->mainWidget() ) )
02779 {
02780 kdDebug(13020)<<"backing up successfull ("<<url().prettyURL()<<" -> "<<u.prettyURL()<<")"<<endl;
02781 }
02782 else
02783 {
02784 kdDebug(13020)<<"backing up failed ("<<url().prettyURL()<<" -> "<<u.prettyURL()<<")"<<endl;
02785
02786 }
02787 }
02788
02789 return KParts::ReadWritePart::save();
02790 }
02791
02792 bool KateDocument::saveFile()
02793 {
02794
02795
02796
02797 if (m_buffer->loadingBorked() && (KMessageBox::warningYesNo(widget(),
02798 i18n("This file could not be loaded correctly due to lack of temporary disk space. Saving it could cause data loss.\n\nDo you really want to save it?")) != KMessageBox::Yes))
02799 return false;
02800
02801
02802
02803
02804 if (m_buffer->binary() && (KMessageBox::warningYesNo (widget()
02805 , i18n ("The file %1 is a binary, saving it will result in a corrupt file.").arg(m_url.url())
02806 , i18n ("Try To Save Binary File")
02807 , KStdGuiItem::yes(), KStdGuiItem::no(), "Binary File Save Warning") != KMessageBox::Yes))
02808 return false;
02809
02810 if ( !url().isEmpty() )
02811 {
02812 if (s_fileChangedDialogsActivated && m_modOnHd)
02813 {
02814 QString str = reasonedMOHString() + "\n\n";
02815
02816 if (!isModified())
02817 {
02818 if (KMessageBox::warningYesNo(0,
02819 str + i18n("Do you really want to save this unmodified file? You could overwrite changed data in the file on disk.")) != KMessageBox::Yes)
02820 return false;
02821 }
02822 else
02823 {
02824 if (KMessageBox::warningYesNo(0,
02825 str + i18n("Do you really want to save this file? Both your open file and the file on disk were changed. There could be some data lost.")) != KMessageBox::Yes)
02826 return false;
02827 }
02828 }
02829 }
02830
02831
02832
02833
02834 if (!m_buffer->canEncode ()
02835 && (KMessageBox::warningYesNo(0,
02836 i18n("The selected encoding cannot encode every unicode character in this document. Do you really want to save it? There could be some data lost.")) != KMessageBox::Yes))
02837 {
02838 return false;
02839 }
02840
02841
02842 deactivateDirWatch ();
02843
02844
02845
02846
02847 bool success = m_buffer->saveFile (m_file);
02848
02849
02850 createDigest( m_digest );
02851
02852
02853 activateDirWatch ();
02854
02855
02856
02857
02858 if (success)
02859 {
02860
02861 if (!hlSetByUser)
02862 {
02863 int hl (KateHlManager::self()->detectHighlighting (this));
02864
02865 if (hl >= 0)
02866 m_buffer->setHighlight(hl);
02867 }
02868
02869
02870 readVariables();
02871 }
02872
02873
02874
02875
02876 if (success && m_modOnHd)
02877 {
02878 m_modOnHd = false;
02879 m_modOnHdReason = 0;
02880 emit modifiedOnDisc (this, m_modOnHd, 0);
02881 }
02882
02883
02884
02885
02886 if (!success)
02887 KMessageBox::error (widget(), i18n ("The document could not be saved, as it was not possible to write to %1.\n\nCheck that you have write access to this file or that enough disk space is available.").arg(m_url.url()));
02888
02889
02890
02891
02892 return success;
02893 }
02894
02895 bool KateDocument::saveAs( const KURL &u )
02896 {
02897 QString oldDir = url().directory();
02898
02899 if ( KParts::ReadWritePart::saveAs( u ) )
02900 {
02901
02902 setDocName( QString::null );
02903
02904 if ( u.directory() != oldDir )
02905 readDirConfig();
02906
02907 emit fileNameChanged();
02908 return true;
02909 }
02910
02911 return false;
02912 }
02913
02914 void KateDocument::readDirConfig ()
02915 {
02916 int depth = config()->searchDirConfigDepth ();
02917
02918 if (m_url.isLocalFile() && (depth > -1))
02919 {
02920 QString currentDir = QFileInfo (m_file).dirPath();
02921
02922
02923 while (depth > -1)
02924 {
02925 kdDebug (13020) << "search for config file in path: " << currentDir << endl;
02926
02927
02928 QFile f (currentDir + "/.kateconfig");
02929
02930 if (f.open (IO_ReadOnly))
02931 {
02932 QTextStream stream (&f);
02933
02934 uint linesRead = 0;
02935 QString line = stream.readLine();
02936 while ((linesRead < 32) && !line.isNull())
02937 {
02938 readVariableLine( line );
02939
02940 line = stream.readLine();
02941
02942 linesRead++;
02943 }
02944
02945 break;
02946 }
02947
02948 QString newDir = QFileInfo (currentDir).dirPath();
02949
02950
02951 if (currentDir == newDir)
02952 break;
02953
02954 currentDir = newDir;
02955 --depth;
02956 }
02957 }
02958 }
02959
02960 void KateDocument::activateDirWatch ()
02961 {
02962
02963 if (m_file == m_dirWatchFile)
02964 return;
02965
02966
02967 deactivateDirWatch ();
02968
02969
02970 if (m_url.isLocalFile() && !m_file.isEmpty())
02971 {
02972 KateFactory::self()->dirWatch ()->addFile (m_file);
02973 m_dirWatchFile = m_file;
02974 }
02975 }
02976
02977 void KateDocument::deactivateDirWatch ()
02978 {
02979 if (!m_dirWatchFile.isEmpty())
02980 KateFactory::self()->dirWatch ()->removeFile (m_dirWatchFile);
02981
02982 m_dirWatchFile = QString::null;
02983 }
02984
02985 bool KateDocument::closeURL()
02986 {
02987 abortLoadKate();
02988
02989
02990
02991
02992 if ( !m_reloading && !url().isEmpty() )
02993 {
02994 if (s_fileChangedDialogsActivated && m_modOnHd)
02995 {
02996 if (!(KMessageBox::warningYesNo(
02997 widget(),
02998 reasonedMOHString() + "\n\n" + i18n("Do you really want to continue to close this file? Data loss may occur."),
02999 "", KStdGuiItem::yes(), KStdGuiItem::no(),
03000 QString("kate_close_modonhd_%1").arg( m_modOnHdReason ) ) == KMessageBox::Yes))
03001 return false;
03002 }
03003 }
03004
03005
03006
03007
03008 if (!KParts::ReadWritePart::closeURL ())
03009 return false;
03010
03011
03012 deactivateDirWatch ();
03013
03014
03015
03016
03017 m_url = KURL ();
03018 m_file = QString::null;
03019
03020
03021 if (m_modOnHd)
03022 {
03023 m_modOnHd = false;
03024 m_modOnHdReason = 0;
03025 emit modifiedOnDisc (this, m_modOnHd, 0);
03026 }
03027
03028
03029 m_buffer->clear();
03030
03031
03032 clearMarks ();
03033
03034
03035 clearUndo();
03036 clearRedo();
03037
03038
03039 setModified(false);
03040
03041
03042 m_buffer->setHighlight(0);
03043
03044
03045 for (KateView * view = m_views.first(); view != 0L; view = m_views.next() )
03046 {
03047
03048
03049 view->setCursorPositionInternal(0, 0, 1, false);
03050 view->updateView(true);
03051 }
03052
03053
03054 emit fileNameChanged ();
03055
03056
03057 setDocName (QString::null);
03058
03059
03060 return true;
03061 }
03062
03063 void KateDocument::setReadWrite( bool rw )
03064 {
03065 if (isReadWrite() != rw)
03066 {
03067 KParts::ReadWritePart::setReadWrite (rw);
03068
03069 for( KateView* view = m_views.first(); view != 0L; view = m_views.next() )
03070 {
03071 view->slotUpdate();
03072 view->slotReadWriteChanged ();
03073 }
03074 }
03075 }
03076
03077 void KateDocument::setModified(bool m) {
03078
03079 if (isModified() != m) {
03080 KParts::ReadWritePart::setModified (m);
03081
03082 for( KateView* view = m_views.first(); view != 0L; view = m_views.next() )
03083 {
03084 view->slotUpdate();
03085 }
03086
03087 emit modifiedChanged ();
03088 emit modStateChanged ((Kate::Document *)this);
03089 }
03090 if ( m == false && ! undoItems.isEmpty() )
03091 {
03092 lastUndoGroupWhenSaved = undoItems.last();
03093 }
03094
03095 if ( m == false ) docWasSavedWhenUndoWasEmpty = undoItems.isEmpty();
03096 }
03097
03098
03099
03100
03101 void KateDocument::makeAttribs(bool needInvalidate)
03102 {
03103 highlight()->clearAttributeArrays ();
03104
03105 for (uint z = 0; z < m_views.count(); z++)
03106 m_views.at(z)->renderer()->updateAttributes ();
03107
03108 if (needInvalidate)
03109 m_buffer->invalidateHighlighting();
03110
03111 tagAll ();
03112 }
03113
03114
03115 void KateDocument::internalHlChanged()
03116 {
03117 makeAttribs();
03118 }
03119
03120 void KateDocument::addView(KTextEditor::View *view) {
03121 if (!view)
03122 return;
03123
03124 m_views.append( (KateView *) view );
03125 m_textEditViews.append( view );
03126
03127
03128 const KateFileType *t = 0;
03129 if ((m_fileType > -1) && (t = KateFactory::self()->fileTypeManager()->fileType(m_fileType)))
03130 readVariableLine (t->varLine, true);
03131
03132
03133 readVariables (true);
03134
03135 m_activeView = (KateView *) view;
03136 }
03137
03138 void KateDocument::removeView(KTextEditor::View *view) {
03139 if (!view)
03140 return;
03141
03142 if (m_activeView == view)
03143 m_activeView = 0L;
03144
03145 m_views.removeRef( (KateView *) view );
03146 m_textEditViews.removeRef( view );
03147 }
03148
03149 void KateDocument::addSuperCursor(KateSuperCursor *cursor, bool privateC) {
03150 if (!cursor)
03151 return;
03152
03153 m_superCursors.append( cursor );
03154
03155 if (!privateC)
03156 myCursors.append( cursor );
03157 }
03158
03159 void KateDocument::removeSuperCursor(KateSuperCursor *cursor, bool privateC) {
03160 if (!cursor)
03161 return;
03162
03163 if (!privateC)
03164 myCursors.removeRef( cursor );
03165
03166 m_superCursors.removeRef( cursor );
03167 }
03168
03169 bool KateDocument::ownedView(KateView *view) {
03170
03171 return (m_views.containsRef(view) > 0);
03172 }
03173
03174 bool KateDocument::isLastView(int numViews) {
03175 return ((int) m_views.count() == numViews);
03176 }
03177
03178 uint KateDocument::currentColumn( const KateTextCursor& cursor )
03179 {
03180 KateTextLine::Ptr textLine = m_buffer->plainLine(cursor.line());
03181
03182 if (textLine)
03183 return textLine->cursorX(cursor.col(), config()->tabWidth());
03184 else
03185 return 0;
03186 }
03187
03188 bool KateDocument::typeChars ( KateView *view, const QString &chars )
03189 {
03190 KateTextLine::Ptr textLine = m_buffer->plainLine(view->cursorLine ());
03191
03192 if (!textLine)
03193 return false;
03194
03195
03196 bool bracketInserted = false;
03197 QString buf;
03198 QChar c;
03199 for( uint z = 0; z < chars.length(); z++ )
03200 {
03201 QChar ch = c = chars[z];
03202
03203 if (ch.isPrint() || ch == '\t')
03204 {
03205 buf.append (ch);
03206
03207 if (!bracketInserted && (config()->configFlags() & KateDocument::cfAutoBrackets))
03208 {
03209 if (ch == '(') { bracketInserted = true; buf.append (')'); }
03210 if (ch == '[') { bracketInserted = true; buf.append (']'); }
03211 if (ch == '{') { bracketInserted = true; buf.append ('}'); }
03212 }
03213 }
03214 }
03215
03216 if (buf.isEmpty())
03217 return false;
03218
03219 editStart ();
03220
03221 if (!(config()->configFlags() & KateDocument::cfPersistent) && hasSelection() )
03222 removeSelectedText();
03223
03224 int oldLine = view->cursorLine ();
03225 int oldCol = view->cursorColumnReal ();
03226
03227
03228 if (config()->configFlags() & KateDocument::cfOvr)
03229 removeText (view->cursorLine(), view->cursorColumnReal(), view->cursorLine(), QMIN( view->cursorColumnReal()+buf.length(), textLine->length() ) );
03230
03231 insertText (view->cursorLine(), view->cursorColumnReal(), buf);
03232 m_indenter->processChar(c);
03233
03234 editEnd ();
03235
03236 if (bracketInserted)
03237 view->setCursorPositionInternal (view->cursorLine(), view->cursorColumnReal()-1);
03238
03239 emit charactersInteractivelyInserted (oldLine, oldCol, chars);
03240
03241 return true;
03242 }
03243
03244 void KateDocument::newLine( KateTextCursor& c, KateViewInternal *v )
03245 {
03246 editStart();
03247
03248 if( !(config()->configFlags() & cfPersistent) && hasSelection() )
03249 removeSelectedText();
03250
03251
03252 c = v->getCursor ();
03253
03254 if (c.line() > (int)lastLine())
03255 c.setLine(lastLine());
03256
03257 if ( c.line() < 0 )
03258 c.setLine( 0 );
03259
03260 uint ln = c.line();
03261
03262 KateTextLine::Ptr textLine = kateTextLine(c.line());
03263
03264 if (c.col() > (int)textLine->length())
03265 c.setCol(textLine->length());
03266
03267 if (m_indenter->canProcessNewLine ())
03268 {
03269 int pos = textLine->firstChar();
03270
03271
03272 if (pos < 0)
03273 pos = textLine->length();
03274
03275 if (c.col() < pos)
03276 c.setCol(pos);
03277
03278 editWrapLine (c.line(), c.col());
03279
03280 KateDocCursor cursor (c.line() + 1, pos, this);
03281 m_indenter->processNewline(cursor, true);
03282 c.setPos(cursor);
03283 }
03284 else
03285 {
03286 editWrapLine (c.line(), c.col());
03287 c.setPos(c.line() + 1, 0);
03288 }
03289
03290 removeTrailingSpace( ln );
03291
03292 editEnd();
03293 }
03294
03295 void KateDocument::transpose( const KateTextCursor& cursor)
03296 {
03297 KateTextLine::Ptr textLine = m_buffer->plainLine(cursor.line());
03298
03299 if (!textLine || (textLine->length() < 2))
03300 return;
03301
03302 uint col = cursor.col();
03303
03304 if (col > 0)
03305 col--;
03306
03307 if ((textLine->length() - col) < 2)
03308 return;
03309
03310 uint line = cursor.line();
03311 QString s;
03312
03313
03314
03315 s.append (textLine->getChar(col+1));
03316 s.append (textLine->getChar(col));
03317
03318
03319
03320 editStart ();
03321 editRemoveText (line, col, 2);
03322 editInsertText (line, col, s);
03323 editEnd ();
03324 }
03325
03326 void KateDocument::backspace( const KateTextCursor& c )
03327 {
03328 if( !(config()->configFlags() & cfPersistent) && hasSelection() ) {
03329 removeSelectedText();
03330 return;
03331 }
03332
03333 uint col = QMAX( c.col(), 0 );
03334 uint line = QMAX( c.line(), 0 );
03335
03336 if ((col == 0) && (line == 0))
03337 return;
03338
03339 if (col > 0)
03340 {
03341 if (!(config()->configFlags() & KateDocument::cfBackspaceIndents))
03342 {
03343
03344
03345 removeText(line, col-1, line, col);
03346 }
03347 else
03348 {
03349
03350 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
03351
03352
03353 if (!textLine)
03354 return;
03355
03356 int colX = textLine->cursorX(col, config()->tabWidth());
03357 int pos = textLine->firstChar();
03358 if (pos > 0)
03359 pos = textLine->cursorX(pos, config()->tabWidth());
03360
03361 if (pos < 0 || pos >= (int)colX)
03362 {
03363
03364
03365 int y = line;
03366 while (--y >= 0)
03367 {
03368
03369 textLine = m_buffer->plainLine(y);
03370
03371 pos = textLine->firstChar();
03372
03373 if (pos >= 0)
03374 {
03375 pos = textLine->cursorX(pos, config()->tabWidth());
03376 if (pos < (int)colX)
03377 {
03378 replaceWithOptimizedSpace(line, col, pos, config()->configFlags());
03379 break;
03380 }
03381 }
03382 }
03383 if (y < 0) {
03384
03385 removeText(line, 0, line, col);
03386 }
03387 }
03388 else
03389 removeText(line, col-1, line, col);
03390 }
03391 }
03392 else
03393 {
03394
03395 if (line >= 1)
03396 {
03397 KateTextLine::Ptr textLine = m_buffer->plainLine(line-1);
03398
03399
03400 if (!textLine)
03401 return;
03402
03403 if (config()->wordWrap() && textLine->endingWith(QString::fromLatin1(" ")))
03404 {
03405
03406 removeText (line-1, textLine->length()-1, line, 0);
03407 }
03408 else
03409 removeText (line-1, textLine->length(), line, 0);
03410 }
03411 }
03412
03413 emit backspacePressed();
03414 }
03415
03416 void KateDocument::del( const KateTextCursor& c )
03417 {
03418 if ( !(config()->configFlags() & cfPersistent) && hasSelection() ) {
03419 removeSelectedText();
03420 return;
03421 }
03422
03423 if( c.col() < (int) m_buffer->plainLine(c.line())->length())
03424 {
03425 removeText(c.line(), c.col(), c.line(), c.col()+1);
03426 }
03427 else if ( c.line() < lastLine() )
03428 {
03429 removeText(c.line(), c.col(), c.line()+1, 0);
03430 }
03431 }
03432
03433 void KateDocument::cut()
03434 {
03435 if (!hasSelection())
03436 return;
03437
03438 copy();
03439 removeSelectedText();
03440 }
03441
03442 void KateDocument::copy()
03443 {
03444 kdDebug(13020) << "in katedocument::copy()" << endl;
03445 if (!hasSelection())
03446 return;
03447 #ifndef QT_NO_MIMECLIPBOARD
03448 QClipboard *cb = QApplication::clipboard();
03449
03450 KMultipleDrag *drag = new KMultipleDrag();
03451 QString htmltext;
03452 if(!cb->selectionModeEnabled())
03453 htmltext = selectionAsHtml();
03454
03455 if(!htmltext.isEmpty()) {
03456 QTextDrag *htmltextdrag = new QTextDrag(htmltext) ;
03457 htmltextdrag->setSubtype("html");
03458
03459 drag->addDragObject( htmltextdrag);
03460 }
03461 drag->addDragObject( new QTextDrag( selection()));
03462
03463 QApplication::clipboard()->setData(drag);
03464 #else
03465 QApplication::clipboard()->setText(selection ());
03466 #endif
03467 }
03468
03469 void KateDocument::paste ( KateView* view )
03470 {
03471 QString s = QApplication::clipboard()->text();
03472
03473 if (s.isEmpty())
03474 return;
03475
03476 uint lines = s.contains (QChar ('\n'));
03477
03478 m_undoDontMerge = true;
03479
03480 editStart ();
03481
03482 if (!(config()->configFlags() & KateDocument::cfPersistent) && hasSelection() )
03483 removeSelectedText();
03484
03485 uint line = view->cursorLine ();
03486 uint column = view->cursorColumnReal ();
03487
03488 insertText ( line, column, s, blockSelect );
03489
03490 editEnd();
03491
03492
03493
03494
03495 if (blockSelect)
03496 view->setCursorPositionInternal (line+lines, column);
03497
03498 if (m_indenter->canProcessLine())
03499 {
03500 editStart();
03501
03502 KateDocCursor begin(line, 0, this);
03503 KateDocCursor end(line + lines, 0, this);
03504
03505 m_indenter->processSection (begin, end);
03506
03507 editEnd();
03508 }
03509
03510 if (!blockSelect) emit charactersSemiInteractivelyInserted (line, column, s);
03511 m_undoDontMerge = true;
03512 }
03513
03514 void KateDocument::selectWord( const KateTextCursor& cursor )
03515 {
03516 int start, end, len;
03517
03518 KateTextLine::Ptr textLine = m_buffer->plainLine(cursor.line());
03519
03520 if (!textLine)
03521 return;
03522
03523 len = textLine->length();
03524 start = end = cursor.col();
03525 while (start > 0 && highlight()->isInWord(textLine->getChar(start - 1), textLine->attribute(start - 1))) start--;
03526 while (end < len && highlight()->isInWord(textLine->getChar(end), textLine->attribute(start - 1))) end++;
03527 if (end <= start) return;
03528
03529 if (!(config()->configFlags() & KateDocument::cfKeepSelection))
03530 clearSelection ();
03531
03532 setSelection (cursor.line(), start, cursor.line(), end);
03533 }
03534
03535 void KateDocument::selectLine( const KateTextCursor& cursor )
03536 {
03537 if (!(config()->configFlags() & KateDocument::cfKeepSelection))
03538 clearSelection ();
03539
03540 setSelection (cursor.line(), 0, cursor.line()+1, 0);
03541 }
03542
03543 void KateDocument::selectLength( const KateTextCursor& cursor, int length )
03544 {
03545 int start, end;
03546
03547 KateTextLine::Ptr textLine = m_buffer->plainLine(cursor.line());
03548 start = cursor.col();
03549 end = start + length;
03550 if (end <= start) return;
03551
03552 if (!(config()->configFlags() & KateDocument::cfKeepSelection))
03553 clearSelection ();
03554 setSelection (cursor.line(), start, cursor.line(), end);
03555 }
03556
03557 void KateDocument::insertIndentChars ( KateView *view )
03558 {
03559 editStart ();
03560
03561 QString s;
03562 if (config()->configFlags() & KateDocument::cfSpaceIndent)
03563 {
03564 int width = config()->indentationWidth();
03565 s.fill (' ', width - (view->cursorColumnReal() % width));
03566 }
03567 else
03568 s.append ('\t');
03569
03570 insertText (view->cursorLine(), view->cursorColumnReal(), s);
03571
03572 editEnd ();
03573 }
03574
03575 void KateDocument::indent ( KateView *, uint line, int change)
03576 {
03577 editStart ();
03578
03579 if (!hasSelection())
03580 {
03581
03582 optimizeLeadingSpace(line, config()->configFlags(), change);
03583 }
03584 else
03585 {
03586 int sl = selectStart.line();
03587 int el = selectEnd.line();
03588 int ec = selectEnd.col();
03589
03590 if ((ec == 0) && ((el-1) >= 0))
03591 {
03592 el--;
03593 }
03594
03595 if (config()->configFlags() & KateDocument::cfKeepIndentProfile && change < 0) {
03596
03597
03598 int adjustedChange = -change;
03599
03600 for (line = sl; (int) line <= el && adjustedChange > 0; line++) {
03601 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
03602 int firstChar = textLine->firstChar();
03603 if (firstChar >= 0 && (lineSelected(line) || lineHasSelected(line))) {
03604 int maxUnindent = textLine->cursorX(firstChar, config()->tabWidth()) / config()->indentationWidth();
03605 if (maxUnindent < adjustedChange)
03606 adjustedChange = maxUnindent;
03607 }
03608 }
03609
03610 change = -adjustedChange;
03611 }
03612
03613 for (line = sl; (int) line <= el; line++) {
03614 if (lineSelected(line) || lineHasSelected(line)) {
03615 optimizeLeadingSpace(line, config()->configFlags(), change);
03616 }
03617 }
03618 }
03619
03620 editEnd ();
03621 }
03622
03623 void KateDocument::align(uint line)
03624 {
03625 if (m_indenter->canProcessLine())
03626 {
03627 editStart ();
03628
03629 if (!hasSelection())
03630 {
03631 KateDocCursor curLine(line, 0, this);
03632 m_indenter->processLine (curLine);
03633 editEnd ();
03634 activeView()->setCursorPosition (line, curLine.col());
03635 }
03636 else
03637 {
03638 m_indenter->processSection(selectStart, selectEnd);
03639 editEnd ();
03640 }
03641 }
03642 }
03643
03644
03645
03646
03647
03648
03649
03650
03651
03652
03653 void KateDocument::optimizeLeadingSpace(uint line, int flags, int change)
03654 {
03655 KateTextLine::Ptr textline = m_buffer->plainLine(line);
03656
03657 int first_char = textline->firstChar();
03658
03659 int w = 0;
03660 if (flags & KateDocument::cfSpaceIndent)
03661 w = config()->indentationWidth();
03662 else
03663 w = config()->tabWidth();
03664
03665 if (first_char < 0)
03666 first_char = textline->length();
03667
03668 int space = textline->cursorX(first_char, config()->tabWidth()) + change * w;
03669 if (space < 0)
03670 space = 0;
03671
03672 if (!(flags & KateDocument::cfKeepExtraSpaces))
03673 {
03674 uint extra = space % w;
03675
03676 space -= extra;
03677 if (extra && change < 0) {
03678
03679 space += w;
03680 }
03681 }
03682
03683
03684 replaceWithOptimizedSpace(line, first_char, space, flags);
03685 }
03686
03687 void KateDocument::replaceWithOptimizedSpace(uint line, uint upto_column, uint space, int flags)
03688 {
03689 uint length;
03690 QString new_space;
03691
03692 if (flags & KateDocument::cfSpaceIndent && ! (flags & KateDocumentConfig::cfMixedIndent) ) {
03693 length = space;
03694 new_space.fill(' ', length);
03695 }
03696 else {
03697 length = space / config()->tabWidth();
03698 new_space.fill('\t', length);
03699
03700 QString extra_space;
03701 extra_space.fill(' ', space % config()->tabWidth());
03702 length += space % config()->tabWidth();
03703 new_space += extra_space;
03704 }
03705
03706 KateTextLine::Ptr textline = m_buffer->plainLine(line);
03707 uint change_from;
03708 for (change_from = 0; change_from < upto_column && change_from < length; change_from++) {
03709 if (textline->getChar(change_from) != new_space[change_from])
03710 break;
03711 }
03712
03713 editStart();
03714
03715 if (change_from < upto_column)
03716 removeText(line, change_from, line, upto_column);
03717
03718 if (change_from < length)
03719 insertText(line, change_from, new_space.right(length - change_from));
03720
03721 editEnd();
03722 }
03723
03724
03725
03726
03727
03728 bool KateDocument::removeStringFromBegining(int line, QString &str)
03729 {
03730 KateTextLine::Ptr textline = m_buffer->plainLine(line);
03731
03732 int index = 0;
03733 bool there = false;
03734
03735 if (textline->startingWith(str))
03736 there = true;
03737 else
03738 {
03739 index = textline->firstChar ();
03740
03741 if ((index >= 0) && (textline->length() >= (index + str.length())) && (textline->string(index, str.length()) == str))
03742 there = true;
03743 }
03744
03745 if (there)
03746 {
03747
03748 removeText (line, index, line, index+str.length());
03749 }
03750
03751 return there;
03752 }
03753
03754
03755
03756
03757
03758 bool KateDocument::removeStringFromEnd(int line, QString &str)
03759 {
03760 KateTextLine::Ptr textline = m_buffer->plainLine(line);
03761
03762 int index = 0;
03763 bool there = false;
03764
03765 if(textline->endingWith(str))
03766 {
03767 index = textline->length() - str.length();
03768 there = true;
03769 }
03770 else
03771 {
03772 index = textline->lastChar ()-str.length()+1;
03773
03774 if ((index >= 0) && (textline->length() >= (index + str.length())) && (textline->string(index, str.length()) == str))
03775 there = true;
03776 }
03777
03778 if (there)
03779 {
03780
03781 removeText (line, index, line, index+str.length());
03782 }
03783
03784 return there;
03785 }
03786
03787
03788
03789
03790
03791 void KateDocument::addStartLineCommentToSingleLine( int line, int attrib )
03792 {
03793 QString commentLineMark = highlight()->getCommentSingleLineStart( attrib ) + " ";
03794 insertText (line, 0, commentLineMark);
03795 }
03796
03797
03798
03799
03800
03801 bool KateDocument::removeStartLineCommentFromSingleLine( int line, int attrib )
03802 {
03803 QString shortCommentMark = highlight()->getCommentSingleLineStart( attrib );
03804 QString longCommentMark = shortCommentMark + " ";
03805
03806 editStart();
03807
03808
03809 bool removed = (removeStringFromBegining(line, longCommentMark)
03810 || removeStringFromBegining(line, shortCommentMark));
03811
03812 editEnd();
03813
03814 return removed;
03815 }
03816
03817
03818
03819
03820
03821 void KateDocument::addStartStopCommentToSingleLine( int line, int attrib )
03822 {
03823 QString startCommentMark = highlight()->getCommentStart( attrib ) + " ";
03824 QString stopCommentMark = " " + highlight()->getCommentEnd( attrib );
03825
03826 editStart();
03827
03828
03829 insertText (line, 0, startCommentMark);
03830
03831
03832 int col = m_buffer->plainLine(line)->length();
03833
03834
03835 insertText (line, col, stopCommentMark);
03836
03837 editEnd();
03838 }
03839
03840
03841
03842
03843
03844 bool KateDocument::removeStartStopCommentFromSingleLine( int line, int attrib )
03845 {
03846 QString shortStartCommentMark = highlight()->getCommentStart( attrib );
03847 QString longStartCommentMark = shortStartCommentMark + " ";
03848 QString shortStopCommentMark = highlight()->getCommentEnd( attrib );
03849 QString longStopCommentMark = " " + shortStopCommentMark;
03850
03851 editStart();
03852
03853 #ifdef __GNUC__
03854 #warning "that's a bad idea, can lead to stray endings, FIXME"
03855 #endif
03856
03857 bool removedStart = (removeStringFromBegining(line, longStartCommentMark)
03858 || removeStringFromBegining(line, shortStartCommentMark));
03859
03860 bool removedStop = false;
03861 if (removedStart)
03862 {
03863
03864 removedStop = (removeStringFromEnd(line, longStopCommentMark)
03865 || removeStringFromEnd(line, shortStopCommentMark));
03866 }
03867
03868 editEnd();
03869
03870 return (removedStart || removedStop);
03871 }
03872
03873
03874
03875
03876
03877
03878 void KateDocument::addStartStopCommentToSelection( int attrib )
03879 {
03880 QString startComment = highlight()->getCommentStart( attrib );
03881 QString endComment = highlight()->getCommentEnd( attrib );
03882
03883 int sl = selectStart.line();
03884 int el = selectEnd.line();
03885 int sc = selectStart.col();
03886 int ec = selectEnd.col();
03887
03888 if ((ec == 0) && ((el-1) >= 0))
03889 {
03890 el--;
03891 ec = m_buffer->plainLine (el)->length();
03892 }
03893
03894 editStart();
03895
03896 insertText (el, ec, endComment);
03897 insertText (sl, sc, startComment);
03898
03899 editEnd ();
03900
03901
03902 ec += endComment.length() + ( (el == sl) ? startComment.length() : 0 );
03903 setSelection(sl, sc, el, ec);
03904 }
03905
03906
03907
03908
03909
03910 void KateDocument::addStartLineCommentToSelection( int attrib )
03911 {
03912 QString commentLineMark = highlight()->getCommentSingleLineStart( attrib ) + " ";
03913
03914 int sl = selectStart.line();
03915 int el = selectEnd.line();
03916
03917 if ((selectEnd.col() == 0) && ((el-1) >= 0))
03918 {
03919 el--;
03920 }
03921
03922 editStart();
03923
03924
03925 for (int z = el; z >= sl; z--) {
03926 insertText (z, 0, commentLineMark);
03927 }
03928
03929 editEnd ();
03930
03931
03932 selectEnd.setCol(selectEnd.col() + ((el == selectEnd.line()) ? commentLineMark.length() : 0) );
03933 setSelection(selectStart.line(), 0, selectEnd.line(), selectEnd.col());
03934 }
03935
03936 bool KateDocument::nextNonSpaceCharPos(int &line, int &col)
03937 {
03938 for(; line < (int)m_buffer->count(); line++) {
03939 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
03940
03941 if (!textLine)
03942 break;
03943
03944 col = textLine->nextNonSpaceChar(col);
03945 if(col != -1)
03946 return true;
03947 col = 0;
03948 }
03949
03950 line = -1;
03951 col = -1;
03952 return false;
03953 }
03954
03955 bool KateDocument::previousNonSpaceCharPos(int &line, int &col)
03956 {
03957 while(true)
03958 {
03959 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
03960
03961 if (!textLine)
03962 break;
03963
03964 col = textLine->previousNonSpaceChar(col);
03965 if(col != -1) return true;
03966 if(line == 0) return false;
03967 --line;
03968 col = textLine->length();
03969 }
03970
03971 line = -1;
03972 col = -1;
03973 return false;
03974 }
03975
03976
03977
03978
03979
03980 bool KateDocument::removeStartStopCommentFromSelection( int attrib )
03981 {
03982 QString startComment = highlight()->getCommentStart( attrib );
03983 QString endComment = highlight()->getCommentEnd( attrib );
03984
03985 int sl = kMax<int> (0, selectStart.line());
03986 int el = kMin<int> (selectEnd.line(), lastLine());
03987 int sc = selectStart.col();
03988 int ec = selectEnd.col();
03989
03990
03991 if (ec != 0) {
03992 ec--;
03993 } else {
03994 if (el > 0) {
03995 el--;
03996 ec = m_buffer->plainLine(el)->length() - 1;
03997 }
03998 }
03999
04000 int startCommentLen = startComment.length();
04001 int endCommentLen = endComment.length();
04002
04003
04004
04005 bool remove = nextNonSpaceCharPos(sl, sc)
04006 && m_buffer->plainLine(sl)->stringAtPos(sc, startComment)
04007 && previousNonSpaceCharPos(el, ec)
04008 && ( (ec - endCommentLen + 1) >= 0 )
04009 && m_buffer->plainLine(el)->stringAtPos(ec - endCommentLen + 1, endComment);
04010
04011 if (remove) {
04012 editStart();
04013
04014 removeText (el, ec - endCommentLen + 1, el, ec + 1);
04015 removeText (sl, sc, sl, sc + startCommentLen);
04016
04017 editEnd ();
04018
04019
04020 ec -= endCommentLen + ( (el == sl) ? startCommentLen : 0 );
04021 setSelection(sl, sc, el, ec + 1);
04022 }
04023
04024 return remove;
04025 }
04026
04027 bool KateDocument::removeStartStopCommentFromRegion(const KateTextCursor &start,const KateTextCursor &end,int attrib) {
04028 QString startComment = highlight()->getCommentStart( attrib );
04029 QString endComment = highlight()->getCommentEnd( attrib );
04030 int startCommentLen = startComment.length();
04031 int endCommentLen = endComment.length();
04032
04033 bool remove = m_buffer->plainLine(start.line())->stringAtPos(start.col(), startComment)
04034 && ( (end.col() - endCommentLen ) >= 0 )
04035 && m_buffer->plainLine(end.line())->stringAtPos(end.col() - endCommentLen , endComment);
04036 if (remove) {
04037 editStart();
04038 removeText(end.line(),end.col()-endCommentLen,end.line(),end.col());
04039 removeText(start.line(),start.col(),start.line(),start.col()+startCommentLen);
04040 editEnd();
04041 }
04042 return remove;
04043 }
04044
04045
04046
04047
04048
04049 bool KateDocument::removeStartLineCommentFromSelection( int attrib )
04050 {
04051 QString shortCommentMark = highlight()->getCommentSingleLineStart( attrib );
04052 QString longCommentMark = shortCommentMark + " ";
04053
04054 int sl = selectStart.line();
04055 int el = selectEnd.line();
04056
04057 if ((selectEnd.col() == 0) && ((el-1) >= 0))
04058 {
04059 el--;
04060 }
04061
04062
04063 int removeLength = 0;
04064 if (m_buffer->plainLine(el)->startingWith(longCommentMark))
04065 removeLength = longCommentMark.length();
04066 else if (m_buffer->plainLine(el)->startingWith(shortCommentMark))
04067 removeLength = shortCommentMark.length();
04068
04069 bool removed = false;
04070
04071 editStart();
04072
04073
04074 for (int z = el; z >= sl; z--)
04075 {
04076
04077 removed = (removeStringFromBegining(z, longCommentMark)
04078 || removeStringFromBegining(z, shortCommentMark)
04079 || removed);
04080 }
04081
04082 editEnd();
04083
04084 if(removed) {
04085
04086 selectEnd.setCol(selectEnd.col() - ((el == selectEnd.line()) ? removeLength : 0) );
04087 setSelection(selectStart.line(), selectStart.col(), selectEnd.line(), selectEnd.col());
04088 }
04089
04090 return removed;
04091 }
04092
04093
04094
04095
04096
04097 void KateDocument::comment( KateView *, uint line,uint column, int change)
04098 {
04099
04100
04101
04102
04103 bool hassel = hasSelection();
04104 int startAttrib, endAttrib;
04105 if ( hassel )
04106 {
04107 KateTextLine::Ptr ln = kateTextLine( selectStart.line() );
04108 int l = selectStart.line(), c = selectStart.col();
04109 startAttrib = nextNonSpaceCharPos( l, c ) ? kateTextLine( l )->attribute( c ) : 0;
04110
04111 ln = kateTextLine( selectEnd.line() );
04112 l = selectEnd.line(), c = selectEnd.col();
04113 endAttrib = previousNonSpaceCharPos( l, c ) ? kateTextLine( l )->attribute( c ) : 0;
04114 }
04115 else
04116 {
04117 KateTextLine::Ptr ln = kateTextLine( line );
04118 if ( ln->length() )
04119 {
04120 startAttrib = ln->attribute( ln->firstChar() );
04121 endAttrib = ln->attribute( ln->lastChar() );
04122 }
04123 else
04124 {
04125 int l = line, c = 0;
04126 if ( nextNonSpaceCharPos( l, c ) || previousNonSpaceCharPos( l, c ) )
04127 startAttrib = endAttrib = kateTextLine( l )->attribute( c );
04128 else
04129 startAttrib = endAttrib = 0;
04130 }
04131 }
04132
04133 if ( ! highlight()->canComment( startAttrib, endAttrib ) )
04134 {
04135 kdDebug(13020)<<"canComment( "<<startAttrib<<", "<<endAttrib<<" ) returned false!"<<endl;
04136 return;
04137 }
04138
04139 bool hasStartLineCommentMark = !(highlight()->getCommentSingleLineStart( startAttrib ).isEmpty());
04140 bool hasStartStopCommentMark = ( !(highlight()->getCommentStart( startAttrib ).isEmpty())
04141 && !(highlight()->getCommentEnd( endAttrib ).isEmpty()) );
04142
04143 bool removed = false;
04144
04145 if (change > 0)
04146 {
04147 if ( !hassel )
04148 {
04149 if ( hasStartLineCommentMark )
04150 addStartLineCommentToSingleLine( line, startAttrib );
04151 else if ( hasStartStopCommentMark )
04152 addStartStopCommentToSingleLine( line, startAttrib );
04153 }
04154 else
04155 {
04156
04157
04158
04159
04160
04161
04162
04163 if ( hasStartStopCommentMark &&
04164 ( !hasStartLineCommentMark || (
04165 ( selectStart.col() > m_buffer->plainLine( selectStart.line() )->firstChar() ) ||
04166 ( selectEnd.col() < ((int)m_buffer->plainLine( selectEnd.line() )->length()) )
04167 ) ) )
04168 addStartStopCommentToSelection( startAttrib );
04169 else if ( hasStartLineCommentMark )
04170 addStartLineCommentToSelection( startAttrib );
04171 }
04172 }
04173 else
04174 {
04175 if ( !hassel )
04176 {
04177 removed = ( hasStartLineCommentMark
04178 && removeStartLineCommentFromSingleLine( line, startAttrib ) )
04179 || ( hasStartStopCommentMark
04180 && removeStartStopCommentFromSingleLine( line, startAttrib ) );
04181 if ((!removed) && foldingTree()) {
04182 kdDebug(13020)<<"easy approach for uncommenting did not work, trying harder (folding tree)"<<endl;
04183 uint commentRegion=(highlight()->commentRegion(startAttrib));
04184 if (commentRegion){
04185 KateCodeFoldingNode *n=foldingTree()->findNodeForPosition(line,column);
04186 if (n) {
04187 KateTextCursor start,end;
04188 if ((n->nodeType()==commentRegion) && n->getBegin(foldingTree(), &start) && n->getEnd(foldingTree(), &end)) {
04189 kdDebug(13020)<<"Enclosing region found:"<<start.col()<<"/"<<start.line()<<"-"<<end.col()<<"/"<<end.line()<<endl;
04190 removeStartStopCommentFromRegion(start,end,startAttrib);
04191 } else {
04192 kdDebug(13020)<<"Enclosing region found, but not valid"<<endl;
04193 kdDebug(13020)<<"Region found: "<<n->nodeType()<<" region needed: "<<commentRegion<<endl;
04194 }
04195
04196 } else kdDebug(13020)<<"No enclosing region found"<<endl;
04197 } else kdDebug(13020)<<"No comment region specified for current hl"<<endl;
04198 }
04199 }
04200 else
04201 {
04202
04203 removed = ( hasStartLineCommentMark
04204 && removeStartLineCommentFromSelection( startAttrib ) )
04205 || ( hasStartStopCommentMark
04206 && removeStartStopCommentFromSelection( startAttrib ) );
04207 }
04208 }
04209 }
04210
04211 void KateDocument::transform( KateView *, const KateTextCursor &c,
04212 KateDocument::TextTransform t )
04213 {
04214 editStart();
04215 uint cl( c.line() ), cc( c.col() );
04216
04217 if ( hasSelection() )
04218 {
04219
04220 KateTextCursor s = selectStart;
04221 KateTextCursor e = selectEnd;
04222
04223 int ln = selStartLine();
04224 while ( ln <= selEndLine() )
04225 {
04226 uint start, end;
04227 start = (ln == selStartLine() || blockSelectionMode()) ?
04228 selStartCol() : 0;
04229 end = (ln == selEndLine() || blockSelectionMode()) ?
04230 selEndCol() : lineLength( ln );
04231 QString s = text( ln, start, ln, end );
04232
04233 if ( t == Uppercase )
04234 s = s.upper();
04235 else if ( t == Lowercase )
04236 s = s.lower();
04237 else
04238 {
04239 KateTextLine::Ptr l = m_buffer->plainLine( ln );
04240 uint p ( 0 );
04241 while( p < s.length() )
04242 {
04243
04244
04245
04246
04247 if ( ( ! start && ! p ) ||
04248 ( ( ln == selStartLine() || blockSelectionMode() ) &&
04249 ! p && ! highlight()->isInWord( l->getChar( start - 1 )) ) ||
04250 ( p && ! highlight()->isInWord( s.at( p-1 ) ) )
04251 )
04252 s[p] = s.at(p).upper();
04253 p++;
04254 }
04255 }
04256
04257 removeText( ln, start, ln, end );
04258 insertText( ln, start, s );
04259
04260 ln++;
04261 }
04262
04263
04264 setSelection( s, e );
04265
04266 } else {
04267 QString s;
04268 int n ( cc );
04269 switch ( t ) {
04270 case Uppercase:
04271 s = text( cl, cc, cl, cc + 1 ).upper();
04272 break;
04273 case Lowercase:
04274 s = text( cl, cc, cl, cc + 1 ).lower();
04275 break;
04276 case Capitalize:
04277 {
04278 KateTextLine::Ptr l = m_buffer->plainLine( cl );
04279 while ( n > 0 && highlight()->isInWord( l->getChar( n-1 ), l->attribute( n-1 ) ) )
04280 n--;
04281 s = text( cl, n, cl, n + 1 ).upper();
04282 }
04283 break;
04284 default:
04285 break;
04286 }
04287 removeText( cl, n, cl, n+1 );
04288 insertText( cl, n, s );
04289 }
04290
04291 editEnd();
04292
04293 if ( activeView() )
04294 activeView()->setCursorPosition( cl, cc );
04295 }
04296
04297 void KateDocument::joinLines( uint first, uint last )
04298 {
04299
04300 editStart();
04301 int line( first );
04302 while ( first < last )
04303 {
04304
04305
04306
04307
04308
04309 KateTextLine::Ptr l = m_buffer->line( line );
04310 KateTextLine::Ptr tl = m_buffer->line( line + 1 );
04311
04312 if ( !l || !tl )
04313 {
04314 editEnd();
04315 return;
04316 }
04317
04318 int pos = tl->firstChar();
04319 if ( pos >= 0 )
04320 {
04321 if (pos != 0)
04322 editRemoveText( line + 1, 0, pos );
04323 if ( !( l->length() == 0 || l->getChar( l->length() - 1 ).isSpace() ) )
04324 editInsertText( line + 1, 0, " " );
04325 }
04326 else
04327 {
04328
04329 editRemoveText( line + 1, 0, tl->length() );
04330 }
04331
04332 editUnWrapLine( line );
04333 first++;
04334 }
04335 editEnd();
04336 }
04337
04338 QString KateDocument::getWord( const KateTextCursor& cursor ) {
04339 int start, end, len;
04340
04341 KateTextLine::Ptr textLine = m_buffer->plainLine(cursor.line());
04342 len = textLine->length();
04343 start = end = cursor.col();
04344 if (start > len)
04345 return QString("");
04346
04347 while (start > 0 && highlight()->isInWord(textLine->getChar(start - 1), textLine->attribute(start - 1))) start--;
04348 while (end < len && highlight()->isInWord(textLine->getChar(end), textLine->attribute(end))) end++;
04349 len = end - start;
04350 return QString(&textLine->text()[start], len);
04351 }
04352
04353 void KateDocument::tagLines(int start, int end)
04354 {
04355 for (uint z = 0; z < m_views.count(); z++)
04356 m_views.at(z)->tagLines (start, end, true);
04357 }
04358
04359 void KateDocument::tagLines(KateTextCursor start, KateTextCursor end)
04360 {
04361
04362 if (blockSelectionMode() && start.col() > end.col()) {
04363 int sc = start.col();
04364 start.setCol(end.col());
04365 end.setCol(sc);
04366 }
04367
04368 for (uint z = 0; z < m_views.count(); z++)
04369 m_views.at(z)->tagLines(start, end, true);
04370 }
04371
04372 void KateDocument::tagSelection(const KateTextCursor &oldSelectStart, const KateTextCursor &oldSelectEnd)
04373 {
04374 if (hasSelection()) {
04375 if (oldSelectStart.line() == -1) {
04376
04377
04378
04379 tagLines(selectStart, selectEnd);
04380
04381 } else if (blockSelectionMode() && (oldSelectStart.col() != selectStart.col() || oldSelectEnd.col() != selectEnd.col())) {
04382
04383 tagLines(selectStart, selectEnd);
04384 tagLines(oldSelectStart, oldSelectEnd);
04385
04386 } else {
04387 if (oldSelectStart != selectStart) {
04388 if (oldSelectStart < selectStart)
04389 tagLines(oldSelectStart, selectStart);
04390 else
04391 tagLines(selectStart, oldSelectStart);
04392 }
04393
04394 if (oldSelectEnd != selectEnd) {
04395 if (oldSelectEnd < selectEnd)
04396 tagLines(oldSelectEnd, selectEnd);
04397 else
04398 tagLines(selectEnd, oldSelectEnd);
04399 }
04400 }
04401
04402 } else {
04403
04404 tagLines(oldSelectStart, oldSelectEnd);
04405 }
04406 }
04407
04408 void KateDocument::repaintViews(bool paintOnlyDirty)
04409 {
04410 for (uint z = 0; z < m_views.count(); z++)
04411 m_views.at(z)->repaintText(paintOnlyDirty);
04412 }
04413
04414 void KateDocument::tagAll()
04415 {
04416 for (uint z = 0; z < m_views.count(); z++)
04417 {
04418 m_views.at(z)->tagAll();
04419 m_views.at(z)->updateView (true);
04420 }
04421 }
04422
04423 void KateDocument::updateViews()
04424 {
04425 if (noViewUpdates)
04426 return;
04427
04428 for (KateView * view = m_views.first(); view != 0L; view = m_views.next() )
04429 {
04430 view->updateView(true);
04431 }
04432 }
04433
04434 uint KateDocument::configFlags ()
04435 {
04436 return config()->configFlags();
04437 }
04438
04439 void KateDocument::setConfigFlags (uint flags)
04440 {
04441 config()->setConfigFlags(flags);
04442 }
04443
04444 bool KateDocument::lineColSelected (int line, int col)
04445 {
04446 if ( (!blockSelect) && (col < 0) )
04447 col = 0;
04448
04449 KateTextCursor cursor(line, col);
04450
04451 if (blockSelect)
04452 return cursor.line() >= selectStart.line() && cursor.line() <= selectEnd.line() && cursor.col() >= selectStart.col() && cursor.col() < selectEnd.col();
04453 else
04454 return (cursor >= selectStart) && (cursor < selectEnd);
04455 }
04456
04457 bool KateDocument::lineSelected (int line)
04458 {
04459 return (!blockSelect)
04460 && (selectStart <= KateTextCursor(line, 0))
04461 && (line < selectEnd.line());
04462 }
04463
04464 bool KateDocument::lineEndSelected (int line, int endCol)
04465 {
04466 return (!blockSelect)
04467 && (line > selectStart.line() || (line == selectStart.line() && (selectStart.col() < endCol || endCol == -1)))
04468 && (line < selectEnd.line() || (line == selectEnd.line() && (endCol <= selectEnd.col() && endCol != -1)));
04469 }
04470
04471 bool KateDocument::lineHasSelected (int line)
04472 {
04473 return (selectStart < selectEnd)
04474 && (line >= selectStart.line())
04475 && (line <= selectEnd.line());
04476 }
04477
04478 bool KateDocument::lineIsSelection (int line)
04479 {
04480 return (line == selectStart.line() && line == selectEnd.line());
04481 }
04482
04483 inline bool isStartBracket( const QChar& c ) { return c == '{' || c == '[' || c == '('; }
04484 inline bool isEndBracket ( const QChar& c ) { return c == '}' || c == ']' || c == ')'; }
04485 inline bool isBracket ( const QChar& c ) { return isStartBracket( c ) || isEndBracket( c ); }
04486
04487
04488
04489
04490
04491
04492
04493
04494
04495
04496
04497 void KateDocument::newBracketMark( const KateTextCursor& cursor, KateTextRange& bm, int maxLines )
04498 {
04499 bm.setValid(false);
04500
04501 bm.start() = cursor;
04502
04503 if( !findMatchingBracket( bm.start(), bm.end(), maxLines ) )
04504 return;
04505
04506 bm.setValid(true);
04507 }
04508
04509 bool KateDocument::findMatchingBracket( KateTextCursor& start, KateTextCursor& end, int maxLines )
04510 {
04511 KateTextLine::Ptr textLine = m_buffer->plainLine( start.line() );
04512 if( !textLine )
04513 return false;
04514
04515 QChar right = textLine->getChar( start.col() );
04516 QChar left = textLine->getChar( start.col() - 1 );
04517 QChar bracket;
04518
04519 if ( config()->configFlags() & cfOvr ) {
04520 if( isBracket( right ) ) {
04521 bracket = right;
04522 } else {
04523 return false;
04524 }
04525 } else if ( isStartBracket( right ) ) {
04526 bracket = right;
04527 } else if ( isEndBracket( left ) ) {
04528 start.setCol(start.col() - 1);
04529 bracket = left;
04530 } else if ( isBracket( left ) ) {
04531 start.setCol(start.col() - 1);
04532 bracket = left;
04533 } else if ( isBracket( right ) ) {
04534 bracket = right;
04535 } else {
04536 return false;
04537 }
04538
04539 QChar opposite;
04540
04541 switch( bracket ) {
04542 case '{': opposite = '}'; break;
04543 case '}': opposite = '{'; break;
04544 case '[': opposite = ']'; break;
04545 case ']': opposite = '['; break;
04546 case '(': opposite = ')'; break;
04547 case ')': opposite = '('; break;
04548 default: return false;
04549 }
04550
04551 bool forward = isStartBracket( bracket );
04552 int startAttr = textLine->attribute( start.col() );
04553 uint count = 0;
04554 int lines = 0;
04555 end = start;
04556
04557 while( true ) {
04558
04559 if( forward ) {
04560 end.setCol(end.col() + 1);
04561 if( end.col() >= lineLength( end.line() ) ) {
04562 if( end.line() >= (int)lastLine() )
04563 return false;
04564 end.setPos(end.line() + 1, 0);
04565 textLine = m_buffer->plainLine( end.line() );
04566 lines++;
04567 }
04568 } else {
04569 end.setCol(end.col() - 1);
04570 if( end.col() < 0 ) {
04571 if( end.line() <= 0 )
04572 return false;
04573 end.setLine(end.line() - 1);
04574 end.setCol(lineLength( end.line() ) - 1);
04575 textLine = m_buffer->plainLine( end.line() );
04576 lines++;
04577 }
04578 }
04579
04580 if ((maxLines != -1) && (lines > maxLines))
04581 return false;
04582
04583
04584 if( textLine->attribute( end.col() ) != startAttr )
04585 continue;
04586
04587
04588 QChar c = textLine->getChar( end.col() );
04589 if( c == bracket ) {
04590 count++;
04591 } else if( c == opposite ) {
04592 if( count == 0 )
04593 return true;
04594 count--;
04595 }
04596
04597 }
04598 }
04599
04600 void KateDocument::guiActivateEvent( KParts::GUIActivateEvent *ev )
04601 {
04602 KParts::ReadWritePart::guiActivateEvent( ev );
04603 if ( ev->activated() )
04604 emit selectionChanged();
04605 }
04606
04607 void KateDocument::setDocName (QString name )
04608 {
04609 if ( name == m_docName )
04610 return;
04611
04612 if ( !name.isEmpty() )
04613 {
04614
04615 m_docName = name;
04616 updateFileType (KateFactory::self()->fileTypeManager()->fileType (this));
04617 emit nameChanged((Kate::Document *) this);
04618 return;
04619 }
04620
04621
04622 if ( ! url().isEmpty() && m_docName.startsWith( url().filename() ) ) return;
04623
04624 int count = -1;
04625
04626 for (uint z=0; z < KateFactory::self()->documents()->count(); z++)
04627 {
04628 if ( (KateFactory::self()->documents()->at(z) != this) && (KateFactory::self()->documents()->at(z)->url().filename() == url().filename()) )
04629 if ( KateFactory::self()->documents()->at(z)->m_docNameNumber > count )
04630 count = KateFactory::self()->documents()->at(z)->m_docNameNumber;
04631 }
04632
04633 m_docNameNumber = count + 1;
04634
04635 m_docName = url().filename();
04636
04637 if (m_docName.isEmpty())
04638 m_docName = i18n ("Untitled");
04639
04640 if (m_docNameNumber > 0)
04641 m_docName = QString(m_docName + " (%1)").arg(m_docNameNumber+1);
04642
04643 updateFileType (KateFactory::self()->fileTypeManager()->fileType (this));
04644 emit nameChanged ((Kate::Document *) this);
04645 }
04646
04647 void KateDocument::slotModifiedOnDisk( Kate::View * )
04648 {
04649 if ( m_isasking < 0 )
04650 {
04651 m_isasking = 0;
04652 return;
04653 }
04654
04655 if ( !s_fileChangedDialogsActivated || m_isasking )
04656 return;
04657
04658 if (m_modOnHd && !url().isEmpty())
04659 {
04660 m_isasking = 1;
04661
04662 KateModOnHdPrompt p( this, m_modOnHdReason, reasonedMOHString(), widget() );
04663 switch ( p.exec() )
04664 {
04665 case KateModOnHdPrompt::Save:
04666 {
04667 m_modOnHd = false;
04668 KEncodingFileDialog::Result res=KEncodingFileDialog::getSaveURLAndEncoding(config()->encoding(),
04669 url().url(),QString::null,widget(),i18n("Save File"));
04670
04671 kdDebug(13020)<<"got "<<res.URLs.count()<<" URLs"<<endl;
04672 if( ! res.URLs.isEmpty() && ! res.URLs.first().isEmpty() && checkOverwrite( res.URLs.first() ) )
04673 {
04674 setEncoding( res.encoding );
04675
04676 if( ! saveAs( res.URLs.first() ) )
04677 {
04678 KMessageBox::error( widget(), i18n("Save failed") );
04679 m_modOnHd = true;
04680 }
04681 else
04682 emit modifiedOnDisc( this, false, 0 );
04683 }
04684 else
04685 {
04686 m_modOnHd = true;
04687 }
04688
04689 m_isasking = 0;
04690 break;
04691 }
04692
04693 case KateModOnHdPrompt::Reload:
04694 m_modOnHd = false;
04695 emit modifiedOnDisc( this, false, 0 );
04696 reloadFile();
04697 m_isasking = 0;
04698 break;
04699
04700 case KateModOnHdPrompt::Ignore:
04701 m_modOnHd = false;
04702 emit modifiedOnDisc( this, false, 0 );
04703 m_isasking = 0;
04704 break;
04705
04706 case KateModOnHdPrompt::Overwrite:
04707 m_modOnHd = false;
04708 emit modifiedOnDisc( this, false, 0 );
04709 m_isasking = 0;
04710 save();
04711 break;
04712
04713 default:
04714 m_isasking = -1;
04715 }
04716 }
04717 }
04718
04719 void KateDocument::setModifiedOnDisk( int reason )
04720 {
04721 m_modOnHdReason = reason;
04722 m_modOnHd = (reason > 0);
04723 emit modifiedOnDisc( this, (reason > 0), reason );
04724 }
04725
04726 class KateDocumentTmpMark
04727 {
04728 public:
04729 QString line;
04730 KTextEditor::Mark mark;
04731 };
04732
04733 void KateDocument::reloadFile()
04734 {
04735 if ( !url().isEmpty() )
04736 {
04737 if (m_modOnHd && s_fileChangedDialogsActivated)
04738 {
04739 int i = KMessageBox::warningYesNoCancel
04740 (0, reasonedMOHString() + "\n\n" + i18n("What do you want to do?"),
04741 i18n("File Was Changed on Disk"), i18n("&Reload File"), i18n("&Ignore Changes"));
04742
04743 if ( i != KMessageBox::Yes)
04744 {
04745 if (i == KMessageBox::No)
04746 {
04747 m_modOnHd = false;
04748 m_modOnHdReason = 0;
04749 emit modifiedOnDisc (this, m_modOnHd, 0);
04750 }
04751
04752 return;
04753 }
04754 }
04755
04756 QValueList<KateDocumentTmpMark> tmp;
04757
04758 for( QIntDictIterator<KTextEditor::Mark> it( m_marks ); it.current(); ++it )
04759 {
04760 KateDocumentTmpMark m;
04761
04762 m.line = textLine (it.current()->line);
04763 m.mark = *it.current();
04764
04765 tmp.append (m);
04766 }
04767
04768 uint mode = hlMode ();
04769 bool byUser = hlSetByUser;
04770
04771 m_storedVariables.clear();
04772
04773 m_reloading = true;
04774 KateDocument::openURL( url() );
04775 m_reloading = false;
04776
04777 for (uint z=0; z < tmp.size(); z++)
04778 {
04779 if (z < numLines())
04780 {
04781 if (textLine(tmp[z].mark.line) == tmp[z].line)
04782 setMark (tmp[z].mark.line, tmp[z].mark.type);
04783 }
04784 }
04785
04786 if (byUser)
04787 setHlMode (mode);
04788 }
04789 }
04790
04791 void KateDocument::flush ()
04792 {
04793 closeURL ();
04794 }
04795
04796 void KateDocument::setWordWrap (bool on)
04797 {
04798 config()->setWordWrap (on);
04799 }
04800
04801 bool KateDocument::wordWrap ()
04802 {
04803 return config()->wordWrap ();
04804 }
04805
04806 void KateDocument::setWordWrapAt (uint col)
04807 {
04808 config()->setWordWrapAt (col);
04809 }
04810
04811 unsigned int KateDocument::wordWrapAt ()
04812 {
04813 return config()->wordWrapAt ();
04814 }
04815
04816 void KateDocument::applyWordWrap ()
04817 {
04818 if (hasSelection())
04819 wrapText (selectStart.line(), selectEnd.line());
04820 else
04821 wrapText (0, lastLine());
04822 }
04823
04824 void KateDocument::setPageUpDownMovesCursor (bool on)
04825 {
04826 config()->setPageUpDownMovesCursor (on);
04827 }
04828
04829 bool KateDocument::pageUpDownMovesCursor ()
04830 {
04831 return config()->pageUpDownMovesCursor ();
04832 }
04833
04834 void KateDocument::exportAs(const QString& filter)
04835 {
04836 if (filter=="kate_html_export")
04837 {
04838 KURL url = KFileDialog::getSaveURL(QString::null,"text/html",0,i18n("Export File As"));
04839 if ( url.isEmpty() )
04840 return;
04841
04842 QString filename;
04843 KTempFile tmp;
04844
04845 if ( url.isLocalFile() )
04846 filename = url.path();
04847 else
04848 filename = tmp.name();
04849
04850 KSaveFile *savefile=new KSaveFile(filename);
04851 if (!savefile->status())
04852 {
04853 if (exportDocumentToHTML(savefile->textStream(),filename))
04854 savefile->close();
04855 else savefile->abort();
04856
04857 }
04858
04859
04860 delete savefile;
04861
04862 if ( url.isLocalFile() )
04863 return;
04864
04865 KIO::NetAccess::upload( filename, url, 0 );
04866 }
04867 }
04868
04869
04870 bool KateDocument::exportDocumentToHTML(QTextStream *outputStream,const QString &name)
04871 {
04872 outputStream->setEncoding(QTextStream::UnicodeUTF8);
04873
04874 (*outputStream) << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl;
04875 (*outputStream) << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"DTD/xhtml1-strict.dtd\">" << endl;
04876 (*outputStream) << "<html xmlns=\"http://www.w3.org/1999/xhtml\">" << endl;
04877 (*outputStream) << "<head>" << endl;
04878 (*outputStream) << "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />" << endl;
04879 (*outputStream) << "<meta name=\"Generator\" content=\"Kate, the KDE Advanced Text Editor\" />" << endl;
04880
04881 (*outputStream) << "<title>" << name.right(name.length() - name.findRev('/')-1) << "</title>" << endl;
04882 (*outputStream) << "</head>" << endl;
04883 (*outputStream) << "<body>" << endl;
04884
04885 textAsHtmlStream(0,0,lastLine(), lineLength(lastLine()), false, outputStream);
04886
04887 (*outputStream) << "</body>" << endl;
04888 (*outputStream) << "</html>" << endl;
04889 return true;
04890 }
04891
04892 QString KateDocument::HTMLEncode(QChar theChar)
04893 {
04894 switch (theChar.latin1())
04895 {
04896 case '>':
04897 return QString(">");
04898 case '<':
04899 return QString("<");
04900 case '&':
04901 return QString("&");
04902 };
04903 return theChar;
04904 }
04905
04906 Kate::ConfigPage *KateDocument::colorConfigPage (QWidget *p)
04907 {
04908 return (Kate::ConfigPage*) new KateSchemaConfigPage (p, this);
04909 }
04910
04911 Kate::ConfigPage *KateDocument::viewDefaultsConfigPage (QWidget *p)
04912 {
04913 return (Kate::ConfigPage*) new KateViewDefaultsConfig(p);
04914 }
04915
04916 Kate::ConfigPage *KateDocument::fontConfigPage (QWidget *p)
04917 {
04918 return (Kate::ConfigPage*) new KateSchemaConfigPage ( p );
04919 }
04920
04921 Kate::ConfigPage *KateDocument::indentConfigPage (QWidget *p)
04922 {
04923 return (Kate::ConfigPage*) new KateIndentConfigTab(p);
04924 }
04925
04926 Kate::ConfigPage *KateDocument::selectConfigPage (QWidget *p)
04927 {
04928 return (Kate::ConfigPage*) new KateSelectConfigTab(p);
04929 }
04930
04931 Kate::ConfigPage *KateDocument::editConfigPage (QWidget *p)
04932 {
04933 return (Kate::ConfigPage*) new KateEditConfigTab(p);
04934 }
04935
04936 Kate::ConfigPage *KateDocument::keysConfigPage (QWidget *p)
04937 {
04938 return (Kate::ConfigPage*) new KateEditKeyConfiguration(p, this);
04939 }
04940
04941 Kate::ConfigPage *KateDocument::hlConfigPage (QWidget *p)
04942 {
04943 return (Kate::ConfigPage*) new KateHlConfigPage (p);
04944 }
04945
04946 Kate::ConfigPage *KateDocument::saveConfigPage(QWidget *p)
04947 {
04948 return (Kate::ConfigPage*) new KateSaveConfigTab(p);
04949 }
04950
04951 Kate::ActionMenu *KateDocument::hlActionMenu (const QString& text, QObject* parent, const char* name)
04952 {
04953 KateViewHighlightAction *menu = new KateViewHighlightAction (text, parent, name);
04954 menu->setWhatsThis(i18n("Here you can choose how the current document should be highlighted."));
04955 menu->updateMenu (this);
04956
04957 return (Kate::ActionMenu *)menu;
04958 }
04959
04960 Kate::ActionMenu *KateDocument::exportActionMenu (const QString& text, QObject* parent, const char* name)
04961 {
04962 KateExportAction *menu = new KateExportAction (text, parent, name);
04963 menu->updateMenu (this);
04964 menu->setWhatsThis(i18n("This command allows you to export the current document"
04965 " with all highlighting information into a markup document, e.g. HTML."));
04966 return (Kate::ActionMenu *)menu;
04967 }
04968
04969 void KateDocument::dumpRegionTree()
04970 {
04971 m_buffer->foldingTree()->debugDump();
04972 }
04973
04974
04975
04976
04977 KTextEditor::Cursor *KateDocument::createCursor ( )
04978 {
04979 return new KateSuperCursor (this, false, 0, 0, this);
04980 }
04981
04982 void KateDocument::tagArbitraryLines(KateView* view, KateSuperRange* range)
04983 {
04984 if (view)
04985 view->tagLines(range->start(), range->end());
04986 else
04987 tagLines(range->start(), range->end());
04988 }
04989
04990
04991
04992
04993
04994 void KateDocument::spellcheck()
04995 {
04996 spellcheck( KateTextCursor( 0, 0 ) );
04997 }
04998
04999 void KateDocument::spellcheck( const KateTextCursor &from, const KateTextCursor &to )
05000 {
05001 if( !isReadWrite() || text().isEmpty() )
05002 return;
05003
05004
05005 m_spellStart = from;
05006 m_spellEnd = to;
05007
05008 if ( to.line() == 0 && to.col() == 0 )
05009 {
05010 int lln = lastLine();
05011 m_spellEnd.setLine( lln );
05012 m_spellEnd.setCol( lineLength( lln ) );
05013 }
05014
05015 m_spellPosCursor = from;
05016 m_spellLastPos = 0;
05017
05018 QString mt = mimeType();
05019
05020 KSpell::SpellerType type = KSpell::Text;
05021 if ( mt == "text/x-tex" || mt == "text/x-latex" )
05022 type = KSpell::TeX;
05023 else if ( mt == "text/html" || mt == "text/xml" )
05024 type = KSpell::HTML;
05025
05026 m_kspell = new KSpell( 0, i18n("Spellcheck"),
05027 this, SLOT(ready(KSpell *)), 0, true, false, type );
05028
05029 connect( m_kspell, SIGNAL(death()),
05030 this, SLOT(spellCleanDone()) );
05031
05032 connect( m_kspell, SIGNAL(misspelling(const QString&, const QStringList&, unsigned int)),
05033 this, SLOT(misspelling(const QString&, const QStringList&, unsigned int)) );
05034 connect( m_kspell, SIGNAL(corrected(const QString&, const QString&, unsigned int)),
05035 this, SLOT(corrected(const QString&, const QString&, unsigned int)) );
05036 connect( m_kspell, SIGNAL(done(const QString&)),
05037 this, SLOT(spellResult(const QString&)) );
05038 }
05039
05040 void KateDocument::ready(KSpell *)
05041 {
05042 m_kspell->setProgressResolution( 1 );
05043
05044 m_kspell->check( text( m_spellStart.line(), m_spellStart.col(), m_spellEnd.line(), m_spellEnd.col() ) );
05045
05046 kdDebug (13020) << "SPELLING READY STATUS: " << m_kspell->status () << endl;
05047 }
05048
05049 void KateDocument::locatePosition( uint pos, uint& line, uint& col )
05050 {
05051 uint remains;
05052
05053 while ( m_spellLastPos < pos )
05054 {
05055 remains = pos - m_spellLastPos;
05056 uint l = lineLength( m_spellPosCursor.line() ) - m_spellPosCursor.col();
05057 if ( l > remains )
05058 {
05059 m_spellPosCursor.setCol( m_spellPosCursor.col() + remains );
05060 m_spellLastPos = pos;
05061 }
05062 else
05063 {
05064 m_spellPosCursor.setLine( m_spellPosCursor.line() + 1 );
05065 m_spellPosCursor.setCol(0);
05066 m_spellLastPos += l + 1;
05067 }
05068 }
05069
05070 line = m_spellPosCursor.line();
05071 col = m_spellPosCursor.col();
05072 }
05073
05074 void KateDocument::misspelling( const QString& origword, const QStringList&, unsigned int pos )
05075 {
05076 uint line, col;
05077
05078 locatePosition( pos, line, col );
05079
05080 if (activeView())
05081 activeView()->setCursorPositionInternal (line, col, 1);
05082
05083 setSelection( line, col, line, col + origword.length() );
05084 }
05085
05086 void KateDocument::corrected( const QString& originalword, const QString& newword, unsigned int pos )
05087 {
05088 uint line, col;
05089
05090 locatePosition( pos, line, col );
05091
05092 removeText( line, col, line, col + originalword.length() );
05093 insertText( line, col, newword );
05094 }
05095
05096 void KateDocument::spellResult( const QString& )
05097 {
05098 clearSelection();
05099 m_kspell->cleanUp();
05100 }
05101
05102 void KateDocument::spellCleanDone()
05103 {
05104 KSpell::spellStatus status = m_kspell->status();
05105
05106 if( status == KSpell::Error ) {
05107 KMessageBox::sorry( 0,
05108 i18n("The spelling program could not be started. "
05109 "Please make sure you have set the correct spelling program "
05110 "and that it is properly configured and in your PATH."));
05111 } else if( status == KSpell::Crashed ) {
05112 KMessageBox::sorry( 0,
05113 i18n("The spelling program seems to have crashed."));
05114 }
05115
05116 delete m_kspell;
05117 m_kspell = 0;
05118
05119 kdDebug (13020) << "SPELLING END" << endl;
05120 }
05121
05122
05123 void KateDocument::lineInfo (KateLineInfo *info, unsigned int line)
05124 {
05125 m_buffer->lineInfo(info,line);
05126 }
05127
05128 KateCodeFoldingTree *KateDocument::foldingTree ()
05129 {
05130 return m_buffer->foldingTree();
05131 }
05132
05133 void KateDocument::setEncoding (const QString &e)
05134 {
05135 m_config->setEncoding(e);
05136 }
05137
05138 QString KateDocument::encoding() const
05139 {
05140 return m_config->encoding();
05141 }
05142
05143 void KateDocument::updateConfig ()
05144 {
05145 emit undoChanged ();
05146 tagAll();
05147
05148 for (KateView * view = m_views.first(); view != 0L; view = m_views.next() )
05149 {
05150 view->updateDocumentConfig ();
05151 }
05152
05153
05154 if (m_indenter->modeNumber() != m_config->indentationMode())
05155 {
05156 delete m_indenter;
05157 m_indenter = KateAutoIndent::createIndenter ( this, m_config->indentationMode() );
05158 }
05159
05160 m_indenter->updateConfig();
05161
05162 m_buffer->setTabWidth (config()->tabWidth());
05163
05164
05165 for (uint i=0; i<KateFactory::self()->plugins().count(); i++)
05166 {
05167 if (config()->plugin (i))
05168 loadPlugin (i);
05169 else
05170 unloadPlugin (i);
05171 }
05172 }
05173
05174
05175
05176
05177
05178
05179
05180
05181 QRegExp KateDocument::kvLine = QRegExp("kate:(.*)");
05182 QRegExp KateDocument::kvVar = QRegExp("([\\w\\-]+)\\s+([^;]+)");
05183
05184 void KateDocument::readVariables(bool onlyViewAndRenderer)
05185 {
05186 if (!onlyViewAndRenderer)
05187 m_config->configStart();
05188
05189
05190 KateView *v;
05191 for (v = m_views.first(); v != 0L; v= m_views.next() )
05192 {
05193 v->config()->configStart();
05194 v->renderer()->config()->configStart();
05195 }
05196
05197 for (uint i=0; i < QMIN( 9, numLines() ); ++i )
05198 {
05199 readVariableLine( textLine( i ), onlyViewAndRenderer );
05200 }
05201 if ( numLines() > 10 )
05202 {
05203 for ( uint i = QMAX(10, numLines() - 10); i < numLines(); ++i )
05204 {
05205 readVariableLine( textLine( i ), onlyViewAndRenderer );
05206 }
05207 }
05208
05209 if (!onlyViewAndRenderer)
05210 m_config->configEnd();
05211
05212 for (v = m_views.first(); v != 0L; v= m_views.next() )
05213 {
05214 v->config()->configEnd();
05215 v->renderer()->config()->configEnd();
05216 }
05217 }
05218
05219 void KateDocument::readVariableLine( QString t, bool onlyViewAndRenderer )
05220 {
05221 if ( kvLine.search( t ) > -1 )
05222 {
05223 QStringList vvl;
05224 vvl << "dynamic-word-wrap" << "dynamic-word-wrap-indicators"
05225 << "line-numbers" << "icon-border" << "folding-markers"
05226 << "bookmark-sorting" << "auto-center-lines"
05227 << "icon-bar-color"
05228
05229 << "background-color" << "selection-color"
05230 << "current-line-color" << "bracket-highlight-color"
05231 << "word-wrap-marker-color"
05232 << "font" << "font-size" << "scheme";
05233 int p( 0 );
05234 QString s = kvLine.cap(1);
05235 QString var, val;
05236 while ( (p = kvVar.search( s, p )) > -1 )
05237 {
05238 p += kvVar.matchedLength();
05239 var = kvVar.cap( 1 );
05240 val = kvVar.cap( 2 ).stripWhiteSpace();
05241 bool state;
05242 int n;
05243
05244
05245 if (onlyViewAndRenderer)
05246 {
05247 if ( vvl.contains( var ) )
05248 setViewVariable( var, val );
05249 }
05250 else
05251 {
05252
05253 if ( var == "word-wrap" && checkBoolValue( val, &state ) )
05254 setWordWrap( state );
05255 else if ( var == "block-selection" && checkBoolValue( val, &state ) )
05256 setBlockSelectionMode( state );
05257
05258
05259 else if ( var == "backspace-indents" && checkBoolValue( val, &state ) )
05260 m_config->setConfigFlags( KateDocumentConfig::cfBackspaceIndents, state );
05261 else if ( var == "replace-tabs" && checkBoolValue( val, &state ) )
05262 m_config->setConfigFlags( KateDocumentConfig::cfReplaceTabsDyn, state );
05263 else if ( var == "remove-trailing-space" && checkBoolValue( val, &state ) )
05264 m_config->setConfigFlags( KateDocumentConfig::cfRemoveTrailingDyn, state );
05265 else if ( var == "wrap-cursor" && checkBoolValue( val, &state ) )
05266 m_config->setConfigFlags( KateDocumentConfig::cfWrapCursor, state );
05267 else if ( var == "auto-brackets" && checkBoolValue( val, &state ) )
05268 m_config->setConfigFlags( KateDocumentConfig::cfAutoBrackets, state );
05269 else if ( var == "persistent-selection" && checkBoolValue( val, &state ) )
05270 m_config->setConfigFlags( KateDocumentConfig::cfPersistent, state );
05271
05272
05273 else if ( var == "overwrite-mode" && checkBoolValue( val, &state ) )
05274 m_config->setConfigFlags( KateDocumentConfig::cfOvr, state );
05275 else if ( var == "keep-indent-profile" && checkBoolValue( val, &state ) )
05276 m_config->setConfigFlags( KateDocumentConfig::cfKeepIndentProfile, state );
05277 else if ( var == "keep-extra-spaces" && checkBoolValue( val, &state ) )
05278 m_config->setConfigFlags( KateDocumentConfig::cfKeepExtraSpaces, state );
05279 else if ( var == "tab-indents" && checkBoolValue( val, &state ) )
05280 m_config->setConfigFlags( KateDocumentConfig::cfTabIndents, state );
05281 else if ( var == "show-tabs" && checkBoolValue( val, &state ) )
05282 m_config->setConfigFlags( KateDocumentConfig::cfShowTabs, state );
05283 else if ( var == "space-indent" && checkBoolValue( val, &state ) )
05284 m_config->setConfigFlags( KateDocumentConfig::cfSpaceIndent, state );
05285 else if ( var == "smart-home" && checkBoolValue( val, &state ) )
05286 m_config->setConfigFlags( KateDocumentConfig::cfSmartHome, state );
05287 else if ( var == "replace-tabs-save" && checkBoolValue( val, &state ) )
05288 m_config->setConfigFlags( KateDocumentConfig::cfReplaceTabs, state );
05289 else if ( var == "replace-trailing-space-save" && checkBoolValue( val, &state ) )
05290 m_config->setConfigFlags( KateDocumentConfig::cfRemoveSpaces, state );
05291 else if ( var == "auto-insert-doxygen" && checkBoolValue( val, &state) )
05292 m_config->setConfigFlags( KateDocumentConfig::cfDoxygenAutoTyping, state);
05293 else if ( var == "mixed-indent" && checkBoolValue( val, &state ) )
05294 m_config->setConfigFlags( KateDocumentConfig::cfMixedIndent, state );
05295
05296
05297 else if ( var == "tab-width" && checkIntValue( val, &n ) )
05298 m_config->setTabWidth( n );
05299 else if ( var == "indent-width" && checkIntValue( val, &n ) )
05300 m_config->setIndentationWidth( n );
05301 else if ( var == "indent-mode" )
05302 {
05303 if ( checkIntValue( val, &n ) )
05304 m_config->setIndentationMode( n );
05305 else
05306 m_config->setIndentationMode( KateAutoIndent::modeNumber( val) );
05307 }
05308 else if ( var == "word-wrap-column" && n > 0 && checkIntValue( val, &n ) )
05309 m_config->setWordWrapAt( n );
05310 else if ( var == "undo-steps" && n >= 0 && checkIntValue( val, &n ) )
05311 setUndoSteps( n );
05312
05313
05314 else if ( var == "eol" || var == "end-of-line" )
05315 {
05316 QStringList l;
05317 l << "unix" << "dos" << "mac";
05318 if ( (n = l.findIndex( val.lower() )) != -1 )
05319 m_config->setEol( n );
05320 }
05321 else if ( var == "encoding" )
05322 m_config->setEncoding( val );
05323 else if ( var == "syntax" || var == "hl" )
05324 {
05325 for ( uint i=0; i < hlModeCount(); i++ )
05326 {
05327 if ( hlModeName( i ).lower() == val.lower() )
05328 {
05329 setHlMode( i );
05330 break;
05331 }
05332 }
05333 }
05334
05335
05336 else if ( vvl.contains( var ) )
05337 setViewVariable( var, val );
05338 else
05339 {
05340 m_storedVariables.insert( var, val );
05341 emit variableChanged( var, val );
05342 }
05343 }
05344 }
05345 }
05346 }
05347
05348 void KateDocument::setViewVariable( QString var, QString val )
05349 {
05350 KateView *v;
05351 bool state;
05352 int n;
05353 QColor c;
05354 for (v = m_views.first(); v != 0L; v= m_views.next() )
05355 {
05356 if ( var == "dynamic-word-wrap" && checkBoolValue( val, &state ) )
05357 v->config()->setDynWordWrap( state );
05358
05359 else if ( var == "line-numbers" && checkBoolValue( val, &state ) )
05360 v->config()->setLineNumbers( state );
05361 else if (var == "icon-border" && checkBoolValue( val, &state ) )
05362 v->config()->setIconBar( state );
05363 else if (var == "folding-markers" && checkBoolValue( val, &state ) )
05364 v->config()->setFoldingBar( state );
05365 else if ( var == "auto-center-lines" && checkIntValue( val, &n ) )
05366 v->config()->setAutoCenterLines( n );
05367 else if ( var == "icon-bar-color" && checkColorValue( val, c ) )
05368 v->renderer()->config()->setIconBarColor( c );
05369
05370 else if ( var == "background-color" && checkColorValue( val, c ) )
05371 v->renderer()->config()->setBackgroundColor( c );
05372 else if ( var == "selection-color" && checkColorValue( val, c ) )
05373 v->renderer()->config()->setSelectionColor( c );
05374 else if ( var == "current-line-color" && checkColorValue( val, c ) )
05375 v->renderer()->config()->setHighlightedLineColor( c );
05376 else if ( var == "bracket-highlight-color" && checkColorValue( val, c ) )
05377 v->renderer()->config()->setHighlightedBracketColor( c );
05378 else if ( var == "word-wrap-marker-color" && checkColorValue( val, c ) )
05379 v->renderer()->config()->setWordWrapMarkerColor( c );
05380 else if ( var == "font" || ( var == "font-size" && checkIntValue( val, &n ) ) )
05381 {
05382 QFont _f( *v->renderer()->config()->font( ) );
05383
05384 if ( var == "font" )
05385 {
05386 _f.setFamily( val );
05387 _f.setFixedPitch( QFont( val ).fixedPitch() );
05388 }
05389 else
05390 _f.setPointSize( n );
05391
05392 v->renderer()->config()->setFont( _f );
05393 }
05394 else if ( var == "scheme" )
05395 {
05396 v->renderer()->config()->setSchema( KateFactory::self()->schemaManager()->number( val ) );
05397 }
05398 }
05399 }
05400
05401 bool KateDocument::checkBoolValue( QString val, bool *result )
05402 {
05403 val = val.stripWhiteSpace().lower();
05404 QStringList l;
05405 l << "1" << "on" << "true";
05406 if ( l.contains( val ) )
05407 {
05408 *result = true;
05409 return true;
05410 }
05411 l.clear();
05412 l << "0" << "off" << "false";
05413 if ( l.contains( val ) )
05414 {
05415 *result = false;
05416 return true;
05417 }
05418 return false;
05419 }
05420
05421 bool KateDocument::checkIntValue( QString val, int *result )
05422 {
05423 bool ret( false );
05424 *result = val.toInt( &ret );
05425 return ret;
05426 }
05427
05428 bool KateDocument::checkColorValue( QString val, QColor &c )
05429 {
05430 c.setNamedColor( val );
05431 return c.isValid();
05432 }
05433
05434
05435 QString KateDocument::variable( const QString &name ) const
05436 {
05437 if ( m_storedVariables.contains( name ) )
05438 return m_storedVariables[ name ];
05439
05440 return "";
05441 }
05442
05443
05444
05445 void KateDocument::slotModOnHdDirty (const QString &path)
05446 {
05447 if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != 1))
05448 {
05449
05450 if ( ! m_digest.isEmpty() )
05451 {
05452 QCString tmp;
05453 if ( createDigest( tmp ) && tmp == m_digest )
05454 return;
05455 }
05456
05457 m_modOnHd = true;
05458 m_modOnHdReason = 1;
05459
05460
05461 if (m_isasking == -1)
05462 m_isasking = false;
05463
05464 emit modifiedOnDisc (this, m_modOnHd, m_modOnHdReason);
05465 }
05466 }
05467
05468 void KateDocument::slotModOnHdCreated (const QString &path)
05469 {
05470 if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != 2))
05471 {
05472 m_modOnHd = true;
05473 m_modOnHdReason = 2;
05474
05475
05476 if (m_isasking == -1)
05477 m_isasking = false;
05478
05479 emit modifiedOnDisc (this, m_modOnHd, m_modOnHdReason);
05480 }
05481 }
05482
05483 void KateDocument::slotModOnHdDeleted (const QString &path)
05484 {
05485 if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != 3))
05486 {
05487 m_modOnHd = true;
05488 m_modOnHdReason = 3;
05489
05490
05491 if (m_isasking == -1)
05492 m_isasking = false;
05493
05494 emit modifiedOnDisc (this, m_modOnHd, m_modOnHdReason);
05495 }
05496 }
05497
05498 bool KateDocument::createDigest( QCString &result )
05499 {
05500 bool ret = false;
05501 result = "";
05502 if ( url().isLocalFile() )
05503 {
05504 QFile f ( url().path() );
05505 if ( f.open( IO_ReadOnly) )
05506 {
05507 KMD5 md5;
05508 ret = md5.update( f );
05509 md5.hexDigest( result );
05510 f.close();
05511 }
05512 }
05513 return ret;
05514 }
05515
05516 QString KateDocument::reasonedMOHString() const
05517 {
05518 switch( m_modOnHdReason )
05519 {
05520 case 1:
05521 return i18n("The file '%1' was modified by another program.").arg( url().prettyURL() );
05522 break;
05523 case 2:
05524 return i18n("The file '%1' was created by another program.").arg( url().prettyURL() );
05525 break;
05526 case 3:
05527 return i18n("The file '%1' was deleted by another program.").arg( url().prettyURL() );
05528 break;
05529 default:
05530 return QString();
05531 }
05532 }
05533
05534 void KateDocument::removeTrailingSpace( uint line )
05535 {
05536
05537 if ( config()->configFlags() & KateDocumentConfig::cfRemoveTrailingDyn )
05538 {
05539 KateTextLine::Ptr ln = kateTextLine( line );
05540
05541 if ( ! ln ) return;
05542
05543 if ( line == activeView()->cursorLine()
05544 && activeView()->cursorColumnReal() >= (uint)QMAX(0,ln->lastChar()) )
05545 return;
05546
05547 if ( ln->length() )
05548 {
05549 uint p = ln->lastChar() + 1;
05550 uint l = ln->length() - p;
05551 if ( l )
05552 editRemoveText( line, p, l);
05553 }
05554 }
05555 }
05556
05557 bool KateDocument::wrapCursor ()
05558 {
05559 return !blockSelect && (configFlags() & KateDocument::cfWrapCursor);
05560 }
05561
05562 void KateDocument::updateFileType (int newType, bool user)
05563 {
05564 if (user || !m_fileTypeSetByUser)
05565 {
05566 const KateFileType *t = 0;
05567 if ((newType == -1) || (t = KateFactory::self()->fileTypeManager()->fileType (newType)))
05568 {
05569 m_fileType = newType;
05570
05571 if (t)
05572 {
05573 m_config->configStart();
05574
05575 KateView *v;
05576 for (v = m_views.first(); v != 0L; v= m_views.next() )
05577 {
05578 v->config()->configStart();
05579 v->renderer()->config()->configStart();
05580 }
05581
05582 readVariableLine( t->varLine );
05583
05584 m_config->configEnd();
05585 for (v = m_views.first(); v != 0L; v= m_views.next() )
05586 {
05587 v->config()->configEnd();
05588 v->renderer()->config()->configEnd();
05589 }
05590 }
05591 }
05592 }
05593 }
05594
05595 uint KateDocument::documentNumber () const
05596 {
05597 return KTextEditor::Document::documentNumber ();
05598 }
05599
05600
05601
05602
05603 void KateDocument::slotQueryClose_save(bool *handled, bool* abortClosing) {
05604 *handled=true;
05605 *abortClosing=true;
05606 if (m_url.isEmpty())
05607 {
05608 KEncodingFileDialog::Result res=KEncodingFileDialog::getSaveURLAndEncoding(config()->encoding(),
05609 QString::null,QString::null,0,i18n("Save File"));
05610
05611 if( res.URLs.isEmpty() || !checkOverwrite( res.URLs.first() ) ) {
05612 *abortClosing=true;
05613 return;
05614 }
05615 setEncoding( res.encoding );
05616 saveAs( res.URLs.first() );
05617 *abortClosing=false;
05618 }
05619 else
05620 {
05621 save();
05622 *abortClosing=false;
05623 }
05624
05625 }
05626
05627 bool KateDocument::checkOverwrite( KURL u )
05628 {
05629 if( !u.isLocalFile() )
05630 return true;
05631
05632 QFileInfo info( u.path() );
05633 if( !info.exists() )
05634 return true;
05635
05636 return KMessageBox::Cancel != KMessageBox::warningContinueCancel( 0,
05637 i18n( "A file named \"%1\" already exists. "
05638 "Are you sure you want to overwrite it?" ).arg( info.fileName() ),
05639 i18n( "Overwrite File?" ),
05640 i18n( "&Overwrite" ) );
05641 }
05642
05643 void KateDocument::setDefaultEncoding (const QString &encoding)
05644 {
05645 s_defaultEncoding = encoding;
05646 }
05647
05648
05649 bool KateDocument::insertTemplateTextImplementation ( uint line, uint column, const QString &templateString, const QMap<QString,QString> &initialValues, QWidget *) {
05650 return (new KateTemplateHandler(this,line,column,templateString,initialValues))->initOk();
05651 }
05652
05653 void KateDocument::testTemplateCode() {
05654 int col=activeView()->cursorColumn();
05655 int line=activeView()->cursorLine();
05656 insertTemplateText(line,col,"for ${index} \\${NOPLACEHOLDER} ${index} ${blah} ${fullname} \\$${Placeholder} \\${${PLACEHOLDER2}}\n next line:${ANOTHERPLACEHOLDER} $${DOLLARBEFOREPLACEHOLDER} {NOTHING} {\n${cursor}\n}",QMap<QString,QString>());
05657 }
05658
05659 bool KateDocument::invokeTabInterceptor(KKey key) {
05660 if (m_tabInterceptor) return (*m_tabInterceptor)(key);
05661 return false;
05662 }
05663
05664 bool KateDocument::setTabInterceptor(KateKeyInterceptorFunctor *interceptor) {
05665 if (m_tabInterceptor) return false;
05666 m_tabInterceptor=interceptor;
05667 return true;
05668 }
05669
05670 bool KateDocument::removeTabInterceptor(KateKeyInterceptorFunctor *interceptor) {
05671 if (m_tabInterceptor!=interceptor) return false;
05672 m_tabInterceptor=0;
05673 return true;
05674 }
05675
05676
05677
05678 void KateDocument::setIMSelectionValue( uint imStartLine, uint imStart, uint imEnd,
05679 uint imSelStart, uint imSelEnd, bool imComposeEvent )
05680 {
05681 m_imStartLine = imStartLine;
05682 m_imStart = imStart;
05683 m_imEnd = imEnd;
05684 m_imSelStart = imSelStart;
05685 m_imSelEnd = imSelEnd;
05686 m_imComposeEvent = imComposeEvent;
05687 }
05688
05689 bool KateDocument::isIMSelection( int _line, int _column )
05690 {
05691 return ( ( int( m_imStartLine ) == _line ) && ( m_imSelStart < m_imSelEnd ) && ( _column >= int( m_imSelStart ) ) &&
05692 ( _column < int( m_imSelEnd ) ) );
05693 }
05694
05695 bool KateDocument::isIMEdit( int _line, int _column )
05696 {
05697 return ( ( int( m_imStartLine ) == _line ) && ( m_imStart < m_imEnd ) && ( _column >= int( m_imStart ) ) &&
05698 ( _column < int( m_imEnd ) ) );
05699 }
05700
05701 void KateDocument::getIMSelectionValue( uint *imStartLine, uint *imStart, uint *imEnd,
05702 uint *imSelStart, uint *imSelEnd )
05703 {
05704 *imStartLine = m_imStartLine;
05705 *imStart = m_imStart;
05706 *imEnd = m_imEnd;
05707 *imSelStart = m_imSelStart;
05708 *imSelEnd = m_imSelEnd;
05709 }
05710
05711