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