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 \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"DTD/xhtml1-strict.dtd\">" << endl;
00617 ts << "<html xmlns=\"http://www.w3.org/1999/xhtml\">" << endl;
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 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
03320
03321
03322 if (!textLine)
03323 return;
03324
03325 int colX = textLine->cursorX(col, config()->tabWidth());
03326 int pos = textLine->firstChar();
03327 if (pos > 0)
03328 pos = textLine->cursorX(pos, config()->tabWidth());
03329
03330 if (pos < 0 || pos >= (int)colX)
03331 {
03332
03333
03334 int y = line;
03335 while (--y >= 0)
03336 {
03337
03338 textLine = m_buffer->plainLine(y);
03339
03340 pos = textLine->firstChar();
03341
03342 if (pos >= 0)
03343 {
03344 pos = textLine->cursorX(pos, config()->tabWidth());
03345 if (pos < (int)colX)
03346 {
03347 replaceWithOptimizedSpace(line, col, pos, config()->configFlags());
03348 break;
03349 }
03350 }
03351 }
03352 if (y < 0) {
03353
03354 removeText(line, 0, line, col);
03355 }
03356 }
03357 else
03358 removeText(line, col-1, line, col);
03359 }
03360 }
03361 else
03362 {
03363
03364 if (line >= 1)
03365 {
03366 KateTextLine::Ptr textLine = m_buffer->plainLine(line-1);
03367
03368
03369 if (!textLine)
03370 return;
03371
03372 if (config()->wordWrap() && textLine->endingWith(QString::fromLatin1(" ")))
03373 {
03374
03375 removeText (line-1, textLine->length()-1, line, 0);
03376 }
03377 else
03378 removeText (line-1, textLine->length(), line, 0);
03379 }
03380 }
03381
03382 emit backspacePressed();
03383 }
03384
03385 void KateDocument::del( const KateTextCursor& c )
03386 {
03387 if ( !(config()->configFlags() & cfPersistent) && hasSelection() ) {
03388 removeSelectedText();
03389 return;
03390 }
03391
03392 if( c.col() < (int) m_buffer->plainLine(c.line())->length())
03393 {
03394 removeText(c.line(), c.col(), c.line(), c.col()+1);
03395 }
03396 else if ( c.line() < lastLine() )
03397 {
03398 removeText(c.line(), c.col(), c.line()+1, 0);
03399 }
03400 }
03401
03402 void KateDocument::cut()
03403 {
03404 if (!hasSelection())
03405 return;
03406
03407 copy();
03408 removeSelectedText();
03409 }
03410
03411 void KateDocument::copy()
03412 {
03413 kdDebug(13020) << "in katedocument::copy()" << endl;
03414 if (!hasSelection())
03415 return;
03416 #ifndef QT_NO_MIMECLIPBOARD
03417 QClipboard *cb = QApplication::clipboard();
03418
03419 KMultipleDrag *drag = new KMultipleDrag();
03420 QString htmltext;
03421 if(!cb->selectionModeEnabled())
03422 htmltext = selectionAsHtml();
03423
03424 if(!htmltext.isEmpty()) {
03425 QTextDrag *htmltextdrag = new QTextDrag(htmltext) ;
03426 htmltextdrag->setSubtype("html");
03427
03428 drag->addDragObject( htmltextdrag);
03429 }
03430 drag->addDragObject( new QTextDrag( selection()));
03431
03432 QApplication::clipboard()->setData(drag);
03433 #else
03434 QApplication::clipboard()->setText(selection ());
03435 #endif
03436 }
03437
03438 void KateDocument::paste ( KateView* view )
03439 {
03440 QString s = QApplication::clipboard()->text();
03441
03442 if (s.isEmpty())
03443 return;
03444
03445 uint lines = s.contains (QChar ('\n'));
03446
03447 m_undoDontMerge = true;
03448
03449 editStart ();
03450
03451 if (!(config()->configFlags() & KateDocument::cfPersistent) && hasSelection() )
03452 removeSelectedText();
03453
03454 uint line = view->cursorLine ();
03455 uint column = view->cursorColumnReal ();
03456
03457 insertText ( line, column, s, blockSelect );
03458
03459 editEnd();
03460
03461
03462
03463
03464 if (blockSelect)
03465 view->setCursorPositionInternal (line+lines, column);
03466
03467 if (m_indenter->canProcessLine())
03468 {
03469 editStart();
03470
03471 KateDocCursor begin(line, 0, this);
03472 KateDocCursor end(line + lines, 0, this);
03473
03474 m_indenter->processSection (begin, end);
03475
03476 editEnd();
03477 }
03478
03479 if (!blockSelect) emit charactersSemiInteractivelyInserted (line, column, s);
03480 m_undoDontMerge = true;
03481 }
03482
03483 void KateDocument::selectWord( const KateTextCursor& cursor )
03484 {
03485 int start, end, len;
03486
03487 KateTextLine::Ptr textLine = m_buffer->plainLine(cursor.line());
03488
03489 if (!textLine)
03490 return;
03491
03492 len = textLine->length();
03493 start = end = cursor.col();
03494 while (start > 0 && highlight()->isInWord(textLine->getChar(start - 1), textLine->attribute(start - 1))) start--;
03495 while (end < len && highlight()->isInWord(textLine->getChar(end), textLine->attribute(start - 1))) end++;
03496 if (end <= start) return;
03497
03498 if (!(config()->configFlags() & KateDocument::cfKeepSelection))
03499 clearSelection ();
03500
03501 setSelection (cursor.line(), start, cursor.line(), end);
03502 }
03503
03504 void KateDocument::selectLine( const KateTextCursor& cursor )
03505 {
03506 if (!(config()->configFlags() & KateDocument::cfKeepSelection))
03507 clearSelection ();
03508
03509 setSelection (cursor.line(), 0, cursor.line()+1, 0);
03510 }
03511
03512 void KateDocument::selectLength( const KateTextCursor& cursor, int length )
03513 {
03514 int start, end;
03515
03516 KateTextLine::Ptr textLine = m_buffer->plainLine(cursor.line());
03517 start = cursor.col();
03518 end = start + length;
03519 if (end <= start) return;
03520
03521 if (!(config()->configFlags() & KateDocument::cfKeepSelection))
03522 clearSelection ();
03523 setSelection (cursor.line(), start, cursor.line(), end);
03524 }
03525
03526 void KateDocument::insertIndentChars ( KateView *view )
03527 {
03528 editStart ();
03529
03530 QString s;
03531 if (config()->configFlags() & KateDocument::cfSpaceIndent)
03532 {
03533 int width = config()->indentationWidth();
03534 s.fill (' ', width - (view->cursorColumnReal() % width));
03535 }
03536 else
03537 s.append ('\t');
03538
03539 insertText (view->cursorLine(), view->cursorColumnReal(), s);
03540
03541 editEnd ();
03542 }
03543
03544 void KateDocument::indent ( KateView *, uint line, int change)
03545 {
03546 editStart ();
03547
03548 if (!hasSelection())
03549 {
03550
03551 optimizeLeadingSpace(line, config()->configFlags(), change);
03552 }
03553 else
03554 {
03555 int sl = selectStart.line();
03556 int el = selectEnd.line();
03557 int ec = selectEnd.col();
03558
03559 if ((ec == 0) && ((el-1) >= 0))
03560 {
03561 el--;
03562 }
03563
03564 if (config()->configFlags() & KateDocument::cfKeepIndentProfile && change < 0) {
03565
03566
03567 int adjustedChange = -change;
03568
03569 for (line = sl; (int) line <= el && adjustedChange > 0; line++) {
03570 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
03571 int firstChar = textLine->firstChar();
03572 if (firstChar >= 0 && (lineSelected(line) || lineHasSelected(line))) {
03573 int maxUnindent = textLine->cursorX(firstChar, config()->tabWidth()) / config()->indentationWidth();
03574 if (maxUnindent < adjustedChange)
03575 adjustedChange = maxUnindent;
03576 }
03577 }
03578
03579 change = -adjustedChange;
03580 }
03581
03582 for (line = sl; (int) line <= el; line++) {
03583 if (lineSelected(line) || lineHasSelected(line)) {
03584 optimizeLeadingSpace(line, config()->configFlags(), change);
03585 }
03586 }
03587 }
03588
03589 editEnd ();
03590 }
03591
03592 void KateDocument::align(uint line)
03593 {
03594 if (m_indenter->canProcessLine())
03595 {
03596 editStart ();
03597
03598 if (!hasSelection())
03599 {
03600 KateDocCursor curLine(line, 0, this);
03601 m_indenter->processLine (curLine);
03602 editEnd ();
03603 activeView()->setCursorPosition (line, curLine.col());
03604 }
03605 else
03606 {
03607 m_indenter->processSection(selectStart, selectEnd);
03608 editEnd ();
03609 }
03610 }
03611 }
03612
03613
03614
03615
03616
03617
03618
03619
03620
03621
03622 void KateDocument::optimizeLeadingSpace(uint line, int flags, int change)
03623 {
03624 KateTextLine::Ptr textline = m_buffer->plainLine(line);
03625
03626 int first_char = textline->firstChar();
03627
03628 int w = 0;
03629 if (flags & KateDocument::cfSpaceIndent)
03630 w = config()->indentationWidth();
03631 else
03632 w = config()->tabWidth();
03633
03634 if (first_char < 0)
03635 first_char = textline->length();
03636
03637 int space = textline->cursorX(first_char, config()->tabWidth()) + change * w;
03638 if (space < 0)
03639 space = 0;
03640
03641 if (!(flags & KateDocument::cfKeepExtraSpaces))
03642 {
03643 uint extra = space % w;
03644
03645 space -= extra;
03646 if (extra && change < 0) {
03647
03648 space += w;
03649 }
03650 }
03651
03652
03653 replaceWithOptimizedSpace(line, first_char, space, flags);
03654 }
03655
03656 void KateDocument::replaceWithOptimizedSpace(uint line, uint upto_column, uint space, int flags)
03657 {
03658 uint length;
03659 QString new_space;
03660
03661 if (flags & KateDocument::cfSpaceIndent && ! (flags & KateDocumentConfig::cfMixedIndent) ) {
03662 length = space;
03663 new_space.fill(' ', length);
03664 }
03665 else {
03666 length = space / config()->tabWidth();
03667 new_space.fill('\t', length);
03668
03669 QString extra_space;
03670 extra_space.fill(' ', space % config()->tabWidth());
03671 length += space % config()->tabWidth();
03672 new_space += extra_space;
03673 }
03674
03675 KateTextLine::Ptr textline = m_buffer->plainLine(line);
03676 uint change_from;
03677 for (change_from = 0; change_from < upto_column && change_from < length; change_from++) {
03678 if (textline->getChar(change_from) != new_space[change_from])
03679 break;
03680 }
03681
03682 editStart();
03683
03684 if (change_from < upto_column)
03685 removeText(line, change_from, line, upto_column);
03686
03687 if (change_from < length)
03688 insertText(line, change_from, new_space.right(length - change_from));
03689
03690 editEnd();
03691 }
03692
03693
03694
03695
03696
03697 bool KateDocument::removeStringFromBegining(int line, QString &str)
03698 {
03699 KateTextLine::Ptr textline = m_buffer->plainLine(line);
03700
03701 int index = 0;
03702 bool there = false;
03703
03704 if (textline->startingWith(str))
03705 there = true;
03706 else
03707 {
03708 index = textline->firstChar ();
03709
03710 if ((index >= 0) && (textline->length() >= (index + str.length())) && (textline->string(index, str.length()) == str))
03711 there = true;
03712 }
03713
03714 if (there)
03715 {
03716
03717 removeText (line, index, line, index+str.length());
03718 }
03719
03720 return there;
03721 }
03722
03723
03724
03725
03726
03727 bool KateDocument::removeStringFromEnd(int line, QString &str)
03728 {
03729 KateTextLine::Ptr textline = m_buffer->plainLine(line);
03730
03731 int index = 0;
03732 bool there = false;
03733
03734 if(textline->endingWith(str))
03735 {
03736 index = textline->length() - str.length();
03737 there = true;
03738 }
03739 else
03740 {
03741 index = textline->lastChar ()-str.length()+1;
03742
03743 if ((index >= 0) && (textline->length() >= (index + str.length())) && (textline->string(index, str.length()) == str))
03744 there = true;
03745 }
03746
03747 if (there)
03748 {
03749
03750 removeText (line, index, line, index+str.length());
03751 }
03752
03753 return there;
03754 }
03755
03756
03757
03758
03759
03760 void KateDocument::addStartLineCommentToSingleLine( int line, int attrib )
03761 {
03762 QString commentLineMark = highlight()->getCommentSingleLineStart( attrib ) + " ";
03763 insertText (line, 0, commentLineMark);
03764 }
03765
03766
03767
03768
03769
03770 bool KateDocument::removeStartLineCommentFromSingleLine( int line, int attrib )
03771 {
03772 QString shortCommentMark = highlight()->getCommentSingleLineStart( attrib );
03773 QString longCommentMark = shortCommentMark + " ";
03774
03775 editStart();
03776
03777
03778 bool removed = (removeStringFromBegining(line, longCommentMark)
03779 || removeStringFromBegining(line, shortCommentMark));
03780
03781 editEnd();
03782
03783 return removed;
03784 }
03785
03786
03787
03788
03789
03790 void KateDocument::addStartStopCommentToSingleLine( int line, int attrib )
03791 {
03792 QString startCommentMark = highlight()->getCommentStart( attrib ) + " ";
03793 QString stopCommentMark = " " + highlight()->getCommentEnd( attrib );
03794
03795 editStart();
03796
03797
03798 insertText (line, 0, startCommentMark);
03799
03800
03801 int col = m_buffer->plainLine(line)->length();
03802
03803
03804 insertText (line, col, stopCommentMark);
03805
03806 editEnd();
03807 }
03808
03809
03810
03811
03812
03813 bool KateDocument::removeStartStopCommentFromSingleLine( int line, int attrib )
03814 {
03815 QString shortStartCommentMark = highlight()->getCommentStart( attrib );
03816 QString longStartCommentMark = shortStartCommentMark + " ";
03817 QString shortStopCommentMark = highlight()->getCommentEnd( attrib );
03818 QString longStopCommentMark = " " + shortStopCommentMark;
03819
03820 editStart();
03821
03822 #ifdef __GNUC__
03823 #warning "that's a bad idea, can lead to stray endings, FIXME"
03824 #endif
03825
03826 bool removedStart = (removeStringFromBegining(line, longStartCommentMark)
03827 || removeStringFromBegining(line, shortStartCommentMark));
03828
03829 bool removedStop = false;
03830 if (removedStart)
03831 {
03832
03833 removedStop = (removeStringFromEnd(line, longStopCommentMark)
03834 || removeStringFromEnd(line, shortStopCommentMark));
03835 }
03836
03837 editEnd();
03838
03839 return (removedStart || removedStop);
03840 }
03841
03842
03843
03844
03845
03846
03847 void KateDocument::addStartStopCommentToSelection( int attrib )
03848 {
03849 QString startComment = highlight()->getCommentStart( attrib );
03850 QString endComment = highlight()->getCommentEnd( attrib );
03851
03852 int sl = selectStart.line();
03853 int el = selectEnd.line();
03854 int sc = selectStart.col();
03855 int ec = selectEnd.col();
03856
03857 if ((ec == 0) && ((el-1) >= 0))
03858 {
03859 el--;
03860 ec = m_buffer->plainLine (el)->length();
03861 }
03862
03863 editStart();
03864
03865 insertText (el, ec, endComment);
03866 insertText (sl, sc, startComment);
03867
03868 editEnd ();
03869
03870
03871 ec += endComment.length() + ( (el == sl) ? startComment.length() : 0 );
03872 setSelection(sl, sc, el, ec);
03873 }
03874
03875
03876
03877
03878
03879 void KateDocument::addStartLineCommentToSelection( int attrib )
03880 {
03881 QString commentLineMark = highlight()->getCommentSingleLineStart( attrib ) + " ";
03882
03883 int sl = selectStart.line();
03884 int el = selectEnd.line();
03885
03886 if ((selectEnd.col() == 0) && ((el-1) >= 0))
03887 {
03888 el--;
03889 }
03890
03891 editStart();
03892
03893
03894 for (int z = el; z >= sl; z--) {
03895 insertText (z, 0, commentLineMark);
03896 }
03897
03898 editEnd ();
03899
03900
03901 selectEnd.setCol(selectEnd.col() + ((el == selectEnd.line()) ? commentLineMark.length() : 0) );
03902 setSelection(selectStart.line(), 0, selectEnd.line(), selectEnd.col());
03903 }
03904
03905 bool KateDocument::nextNonSpaceCharPos(int &line, int &col)
03906 {
03907 for(; line < (int)m_buffer->count(); line++) {
03908 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
03909
03910 if (!textLine)
03911 break;
03912
03913 col = textLine->nextNonSpaceChar(col);
03914 if(col != -1)
03915 return true;
03916 col = 0;
03917 }
03918
03919 line = -1;
03920 col = -1;
03921 return false;
03922 }
03923
03924 bool KateDocument::previousNonSpaceCharPos(int &line, int &col)
03925 {
03926 while(true)
03927 {
03928 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
03929
03930 if (!textLine)
03931 break;
03932
03933 col = textLine->previousNonSpaceChar(col);
03934 if(col != -1) return true;
03935 if(line == 0) return false;
03936 --line;
03937 col = textLine->length();
03938 }
03939
03940 line = -1;
03941 col = -1;
03942 return false;
03943 }
03944
03945
03946
03947
03948
03949 bool KateDocument::removeStartStopCommentFromSelection( int attrib )
03950 {
03951 QString startComment = highlight()->getCommentStart( attrib );
03952 QString endComment = highlight()->getCommentEnd( attrib );
03953
03954 int sl = kMax<int> (0, selectStart.line());
03955 int el = kMin<int> (selectEnd.line(), lastLine());
03956 int sc = selectStart.col();
03957 int ec = selectEnd.col();
03958
03959
03960 if (ec != 0) {
03961 ec--;
03962 } else {
03963 if (el > 0) {
03964 el--;
03965 ec = m_buffer->plainLine(el)->length() - 1;
03966 }
03967 }
03968
03969 int startCommentLen = startComment.length();
03970 int endCommentLen = endComment.length();
03971
03972
03973
03974 bool remove = nextNonSpaceCharPos(sl, sc)
03975 && m_buffer->plainLine(sl)->stringAtPos(sc, startComment)
03976 && previousNonSpaceCharPos(el, ec)
03977 && ( (ec - endCommentLen + 1) >= 0 )
03978 && m_buffer->plainLine(el)->stringAtPos(ec - endCommentLen + 1, endComment);
03979
03980 if (remove) {
03981 editStart();
03982
03983 removeText (el, ec - endCommentLen + 1, el, ec + 1);
03984 removeText (sl, sc, sl, sc + startCommentLen);
03985
03986 editEnd ();
03987
03988
03989 ec -= endCommentLen + ( (el == sl) ? startCommentLen : 0 );
03990 setSelection(sl, sc, el, ec + 1);
03991 }
03992
03993 return remove;
03994 }
03995
03996 bool KateDocument::removeStartStopCommentFromRegion(const KateTextCursor &start,const KateTextCursor &end,int attrib) {
03997 QString startComment = highlight()->getCommentStart( attrib );
03998 QString endComment = highlight()->getCommentEnd( attrib );
03999 int startCommentLen = startComment.length();
04000 int endCommentLen = endComment.length();
04001
04002 bool remove = m_buffer->plainLine(start.line())->stringAtPos(start.col(), startComment)
04003 && ( (end.col() - endCommentLen ) >= 0 )
04004 && m_buffer->plainLine(end.line())->stringAtPos(end.col() - endCommentLen , endComment);
04005 if (remove) {
04006 editStart();
04007 removeText(end.line(),end.col()-endCommentLen,end.line(),end.col());
04008 removeText(start.line(),start.col(),start.line(),start.col()+startCommentLen);
04009 editEnd();
04010 }
04011 return remove;
04012 }
04013
04014
04015
04016
04017
04018 bool KateDocument::removeStartLineCommentFromSelection( int attrib )
04019 {
04020 QString shortCommentMark = highlight()->getCommentSingleLineStart( attrib );
04021 QString longCommentMark = shortCommentMark + " ";
04022
04023 int sl = selectStart.line();
04024 int el = selectEnd.line();
04025
04026 if ((selectEnd.col() == 0) && ((el-1) >= 0))
04027 {
04028 el--;
04029 }
04030
04031
04032 int removeLength = 0;
04033 if (m_buffer->plainLine(el)->startingWith(longCommentMark))
04034 removeLength = longCommentMark.length();
04035 else if (m_buffer->plainLine(el)->startingWith(shortCommentMark))
04036 removeLength = shortCommentMark.length();
04037
04038 bool removed = false;
04039
04040 editStart();
04041
04042
04043 for (int z = el; z >= sl; z--)
04044 {
04045
04046 removed = (removeStringFromBegining(z, longCommentMark)
04047 || removeStringFromBegining(z, shortCommentMark)
04048 || removed);
04049 }
04050
04051 editEnd();
04052
04053 if(removed) {
04054
04055 selectEnd.setCol(selectEnd.col() - ((el == selectEnd.line()) ? removeLength : 0) );
04056 setSelection(selectStart.line(), selectStart.col(), selectEnd.line(), selectEnd.col());
04057 }
04058
04059 return removed;
04060 }
04061
04062
04063
04064
04065
04066 void KateDocument::comment( KateView *, uint line,uint column, int change)
04067 {
04068
04069
04070
04071
04072 bool hassel = hasSelection();
04073 int startAttrib, endAttrib;
04074 if ( hassel )
04075 {
04076 KateTextLine::Ptr ln = kateTextLine( selectStart.line() );
04077 int l = selectStart.line(), c = selectStart.col();
04078 startAttrib = nextNonSpaceCharPos( l, c ) ? kateTextLine( l )->attribute( c ) : 0;
04079
04080 ln = kateTextLine( selectEnd.line() );
04081 l = selectEnd.line(), c = selectEnd.col();
04082 endAttrib = previousNonSpaceCharPos( l, c ) ? kateTextLine( l )->attribute( c ) : 0;
04083 }
04084 else
04085 {
04086 KateTextLine::Ptr ln = kateTextLine( line );
04087 if ( ln->length() )
04088 {
04089 startAttrib = ln->attribute( ln->firstChar() );
04090 endAttrib = ln->attribute( ln->lastChar() );
04091 }
04092 else
04093 {
04094 int l = line, c = 0;
04095 if ( nextNonSpaceCharPos( l, c ) || previousNonSpaceCharPos( l, c ) )
04096 startAttrib = endAttrib = kateTextLine( l )->attribute( c );
04097 else
04098 startAttrib = endAttrib = 0;
04099 }
04100 }
04101
04102 if ( ! highlight()->canComment( startAttrib, endAttrib ) )
04103 {
04104 kdDebug(13020)<<"canComment( "<<startAttrib<<", "<<endAttrib<<" ) returned false!"<<endl;
04105 return;
04106 }
04107
04108 bool hasStartLineCommentMark = !(highlight()->getCommentSingleLineStart( startAttrib ).isEmpty());
04109 bool hasStartStopCommentMark = ( !(highlight()->getCommentStart( startAttrib ).isEmpty())
04110 && !(highlight()->getCommentEnd( endAttrib ).isEmpty()) );
04111
04112 bool removed = false;
04113
04114 if (change > 0)
04115 {
04116 if ( !hassel )
04117 {
04118 if ( hasStartLineCommentMark )
04119 addStartLineCommentToSingleLine( line, startAttrib );
04120 else if ( hasStartStopCommentMark )
04121 addStartStopCommentToSingleLine( line, startAttrib );
04122 }
04123 else
04124 {
04125
04126
04127
04128
04129
04130
04131
04132 if ( hasStartStopCommentMark &&
04133 ( !hasStartLineCommentMark || (
04134 ( selectStart.col() > m_buffer->plainLine( selectStart.line() )->firstChar() ) ||
04135 ( selectEnd.col() < ((int)m_buffer->plainLine( selectEnd.line() )->length()) )
04136 ) ) )
04137 addStartStopCommentToSelection( startAttrib );
04138 else if ( hasStartLineCommentMark )
04139 addStartLineCommentToSelection( startAttrib );
04140 }
04141 }
04142 else
04143 {
04144 if ( !hassel )
04145 {
04146 removed = ( hasStartLineCommentMark
04147 && removeStartLineCommentFromSingleLine( line, startAttrib ) )
04148 || ( hasStartStopCommentMark
04149 && removeStartStopCommentFromSingleLine( line, startAttrib ) );
04150 if ((!removed) && foldingTree()) {
04151 kdDebug(13020)<<"easy approach for uncommenting did not work, trying harder (folding tree)"<<endl;
04152 uint commentRegion=(highlight()->commentRegion(startAttrib));
04153 if (commentRegion){
04154 KateCodeFoldingNode *n=foldingTree()->findNodeForPosition(line,column);
04155 if (n) {
04156 KateTextCursor start,end;
04157 if ((n->nodeType()==commentRegion) && n->getBegin(foldingTree(), &start) && n->getEnd(foldingTree(), &end)) {
04158 kdDebug(13020)<<"Enclosing region found:"<<start.col()<<"/"<<start.line()<<"-"<<end.col()<<"/"<<end.line()<<endl;
04159 removeStartStopCommentFromRegion(start,end,startAttrib);
04160 } else {
04161 kdDebug(13020)<<"Enclosing region found, but not valid"<<endl;
04162 kdDebug(13020)<<"Region found: "<<n->nodeType()<<" region needed: "<<commentRegion<<endl;
04163 }
04164
04165 } else kdDebug(13020)<<"No enclosing region found"<<endl;
04166 } else kdDebug(13020)<<"No comment region specified for current hl"<<endl;
04167 }
04168 }
04169 else
04170 {
04171
04172 removed = ( hasStartLineCommentMark
04173 && removeStartLineCommentFromSelection( startAttrib ) )
04174 || ( hasStartStopCommentMark
04175 && removeStartStopCommentFromSelection( startAttrib ) );
04176 }
04177 }
04178 }
04179
04180 void KateDocument::transform( KateView *, const KateTextCursor &c,
04181 KateDocument::TextTransform t )
04182 {
04183 editStart();
04184 uint cl( c.line() ), cc( c.col() );
04185
04186 if ( hasSelection() )
04187 {
04188
04189 KateTextCursor s = selectStart;
04190 KateTextCursor e = selectEnd;
04191
04192 int ln = selStartLine();
04193 while ( ln <= selEndLine() )
04194 {
04195 uint start, end;
04196 start = (ln == selStartLine() || blockSelectionMode()) ?
04197 selStartCol() : 0;
04198 end = (ln == selEndLine() || blockSelectionMode()) ?
04199 selEndCol() : lineLength( ln );
04200 QString s = text( ln, start, ln, end );
04201
04202 if ( t == Uppercase )
04203 s = s.upper();
04204 else if ( t == Lowercase )
04205 s = s.lower();
04206 else
04207 {
04208 KateTextLine::Ptr l = m_buffer->plainLine( ln );
04209 uint p ( 0 );
04210 while( p < s.length() )
04211 {
04212
04213
04214
04215
04216 if ( ( ! start && ! p ) ||
04217 ( ( ln == selStartLine() || blockSelectionMode() ) &&
04218 ! p && ! highlight()->isInWord( l->getChar( start - 1 )) ) ||
04219 ( p && ! highlight()->isInWord( s.at( p-1 ) ) )
04220 )
04221 s[p] = s.at(p).upper();
04222 p++;
04223 }
04224 }
04225
04226 removeText( ln, start, ln, end );
04227 insertText( ln, start, s );
04228
04229 ln++;
04230 }
04231
04232
04233 setSelection( s, e );
04234
04235 } else {
04236 QString s;
04237 int n ( cc );
04238 switch ( t ) {
04239 case Uppercase:
04240 s = text( cl, cc, cl, cc + 1 ).upper();
04241 break;
04242 case Lowercase:
04243 s = text( cl, cc, cl, cc + 1 ).lower();
04244 break;
04245 case Capitalize:
04246 {
04247 KateTextLine::Ptr l = m_buffer->plainLine( cl );
04248 while ( n > 0 && highlight()->isInWord( l->getChar( n-1 ), l->attribute( n-1 ) ) )
04249 n--;
04250 s = text( cl, n, cl, n + 1 ).upper();
04251 }
04252 break;
04253 default:
04254 break;
04255 }
04256 removeText( cl, n, cl, n+1 );
04257 insertText( cl, n, s );
04258 }
04259
04260 editEnd();
04261
04262 if ( activeView() )
04263 activeView()->setCursorPosition( cl, cc );
04264 }
04265
04266 void KateDocument::joinLines( uint first, uint last )
04267 {
04268
04269 editStart();
04270 int line( first );
04271 while ( first < last )
04272 {
04273
04274
04275
04276
04277
04278 KateTextLine::Ptr l = m_buffer->line( line );
04279 KateTextLine::Ptr tl = m_buffer->line( line + 1 );
04280
04281 if ( !l || !tl )
04282 {
04283 editEnd();
04284 return;
04285 }
04286
04287 int pos = tl->firstChar();
04288 if ( pos >= 0 )
04289 {
04290 if (pos != 0)
04291 editRemoveText( line + 1, 0, pos );
04292 if ( !( l->length() == 0 || l->getChar( l->length() - 1 ).isSpace() ) )
04293 editInsertText( line + 1, 0, " " );
04294 }
04295 else
04296 {
04297
04298 editRemoveText( line + 1, 0, tl->length() );
04299 }
04300
04301 editUnWrapLine( line );
04302 first++;
04303 }
04304 editEnd();
04305 }
04306
04307 QString KateDocument::getWord( const KateTextCursor& cursor ) {
04308 int start, end, len;
04309
04310 KateTextLine::Ptr textLine = m_buffer->plainLine(cursor.line());
04311 len = textLine->length();
04312 start = end = cursor.col();
04313 if (start > len)
04314 return QString("");
04315
04316 while (start > 0 && highlight()->isInWord(textLine->getChar(start - 1), textLine->attribute(start - 1))) start--;
04317 while (end < len && highlight()->isInWord(textLine->getChar(end), textLine->attribute(end))) end++;
04318 len = end - start;
04319 return QString(&textLine->text()[start], len);
04320 }
04321
04322 void KateDocument::tagLines(int start, int end)
04323 {
04324 for (uint z = 0; z < m_views.count(); z++)
04325 m_views.at(z)->tagLines (start, end, true);
04326 }
04327
04328 void KateDocument::tagLines(KateTextCursor start, KateTextCursor end)
04329 {
04330
04331 if (blockSelectionMode() && start.col() > end.col()) {
04332 int sc = start.col();
04333 start.setCol(end.col());
04334 end.setCol(sc);
04335 }
04336
04337 for (uint z = 0; z < m_views.count(); z++)
04338 m_views.at(z)->tagLines(start, end, true);
04339 }
04340
04341 void KateDocument::tagSelection(const KateTextCursor &oldSelectStart, const KateTextCursor &oldSelectEnd)
04342 {
04343 if (hasSelection()) {
04344 if (oldSelectStart.line() == -1) {
04345
04346
04347
04348 tagLines(selectStart, selectEnd);
04349
04350 } else if (blockSelectionMode() && (oldSelectStart.col() != selectStart.col() || oldSelectEnd.col() != selectEnd.col())) {
04351
04352 tagLines(selectStart, selectEnd);
04353 tagLines(oldSelectStart, oldSelectEnd);
04354
04355 } else {
04356 if (oldSelectStart != selectStart) {
04357 if (oldSelectStart < selectStart)
04358 tagLines(oldSelectStart, selectStart);
04359 else
04360 tagLines(selectStart, oldSelectStart);
04361 }
04362
04363 if (oldSelectEnd != selectEnd) {
04364 if (oldSelectEnd < selectEnd)
04365 tagLines(oldSelectEnd, selectEnd);
04366 else
04367 tagLines(selectEnd, oldSelectEnd);
04368 }
04369 }
04370
04371 } else {
04372
04373 tagLines(oldSelectStart, oldSelectEnd);
04374 }
04375 }
04376
04377 void KateDocument::repaintViews(bool paintOnlyDirty)
04378 {
04379 for (uint z = 0; z < m_views.count(); z++)
04380 m_views.at(z)->repaintText(paintOnlyDirty);
04381 }
04382
04383 void KateDocument::tagAll()
04384 {
04385 for (uint z = 0; z < m_views.count(); z++)
04386 {
04387 m_views.at(z)->tagAll();
04388 m_views.at(z)->updateView (true);
04389 }
04390 }
04391
04392 void KateDocument::updateViews()
04393 {
04394 if (noViewUpdates)
04395 return;
04396
04397 for (KateView * view = m_views.first(); view != 0L; view = m_views.next() )
04398 {
04399 view->updateView(true);
04400 }
04401 }
04402
04403 uint KateDocument::configFlags ()
04404 {
04405 return config()->configFlags();
04406 }
04407
04408 void KateDocument::setConfigFlags (uint flags)
04409 {
04410 config()->setConfigFlags(flags);
04411 }
04412
04413 bool KateDocument::lineColSelected (int line, int col)
04414 {
04415 if ( (!blockSelect) && (col < 0) )
04416 col = 0;
04417
04418 KateTextCursor cursor(line, col);
04419
04420 if (blockSelect)
04421 return cursor.line() >= selectStart.line() && cursor.line() <= selectEnd.line() && cursor.col() >= selectStart.col() && cursor.col() < selectEnd.col();
04422 else
04423 return (cursor >= selectStart) && (cursor < selectEnd);
04424 }
04425
04426 bool KateDocument::lineSelected (int line)
04427 {
04428 return (!blockSelect)
04429 && (selectStart <= KateTextCursor(line, 0))
04430 && (line < selectEnd.line());
04431 }
04432
04433 bool KateDocument::lineEndSelected (int line, int endCol)
04434 {
04435 return (!blockSelect)
04436 && (line > selectStart.line() || (line == selectStart.line() && (selectStart.col() < endCol || endCol == -1)))
04437 && (line < selectEnd.line() || (line == selectEnd.line() && (endCol <= selectEnd.col() && endCol != -1)));
04438 }
04439
04440 bool KateDocument::lineHasSelected (int line)
04441 {
04442 return (selectStart < selectEnd)
04443 && (line >= selectStart.line())
04444 && (line <= selectEnd.line());
04445 }
04446
04447 bool KateDocument::lineIsSelection (int line)
04448 {
04449 return (line == selectStart.line() && line == selectEnd.line());
04450 }
04451
04452 inline bool isStartBracket( const QChar& c ) { return c == '{' || c == '[' || c == '('; }
04453 inline bool isEndBracket ( const QChar& c ) { return c == '}' || c == ']' || c == ')'; }
04454 inline bool isBracket ( const QChar& c ) { return isStartBracket( c ) || isEndBracket( c ); }
04455
04456
04457
04458
04459
04460
04461
04462
04463
04464
04465
04466 void KateDocument::newBracketMark( const KateTextCursor& cursor, KateTextRange& bm, int maxLines )
04467 {
04468 bm.setValid(false);
04469
04470 bm.start() = cursor;
04471
04472 if( !findMatchingBracket( bm.start(), bm.end(), maxLines ) )
04473 return;
04474
04475 bm.setValid(true);
04476 }
04477
04478 bool KateDocument::findMatchingBracket( KateTextCursor& start, KateTextCursor& end, int maxLines )
04479 {
04480 KateTextLine::Ptr textLine = m_buffer->plainLine( start.line() );
04481 if( !textLine )
04482 return false;
04483
04484 QChar right = textLine->getChar( start.col() );
04485 QChar left = textLine->getChar( start.col() - 1 );
04486 QChar bracket;
04487
04488 if ( config()->configFlags() & cfOvr ) {
04489 if( isBracket( right ) ) {
04490 bracket = right;
04491 } else {
04492 return false;
04493 }
04494 } else if ( isStartBracket( right ) ) {
04495 bracket = right;
04496 } else if ( isEndBracket( left ) ) {
04497 start.setCol(start.col() - 1);
04498 bracket = left;
04499 } else if ( isBracket( left ) ) {
04500 start.setCol(start.col() - 1);
04501 bracket = left;
04502 } else if ( isBracket( right ) ) {
04503 bracket = right;
04504 } else {
04505 return false;
04506 }
04507
04508 QChar opposite;
04509
04510 switch( bracket ) {
04511 case '{': opposite = '}'; break;
04512 case '}': opposite = '{'; break;
04513 case '[': opposite = ']'; break;
04514 case ']': opposite = '['; break;
04515 case '(': opposite = ')'; break;
04516 case ')': opposite = '('; break;
04517 default: return false;
04518 }
04519
04520 bool forward = isStartBracket( bracket );
04521 int startAttr = textLine->attribute( start.col() );
04522 uint count = 0;
04523 int lines = 0;
04524 end = start;
04525
04526 while( true ) {
04527
04528 if( forward ) {
04529 end.setCol(end.col() + 1);
04530 if( end.col() >= lineLength( end.line() ) ) {
04531 if( end.line() >= (int)lastLine() )
04532 return false;
04533 end.setPos(end.line() + 1, 0);
04534 textLine = m_buffer->plainLine( end.line() );
04535 lines++;
04536 }
04537 } else {
04538 end.setCol(end.col() - 1);
04539 if( end.col() < 0 ) {
04540 if( end.line() <= 0 )
04541 return false;
04542 end.setLine(end.line() - 1);
04543 end.setCol(lineLength( end.line() ) - 1);
04544 textLine = m_buffer->plainLine( end.line() );
04545 lines++;
04546 }
04547 }
04548
04549 if ((maxLines != -1) && (lines > maxLines))
04550 return false;
04551
04552
04553 if( textLine->attribute( end.col() ) != startAttr )
04554 continue;
04555
04556
04557 QChar c = textLine->getChar( end.col() );
04558 if( c == bracket ) {
04559 count++;
04560 } else if( c == opposite ) {
04561 if( count == 0 )
04562 return true;
04563 count--;
04564 }
04565
04566 }
04567 }
04568
04569 void KateDocument::guiActivateEvent( KParts::GUIActivateEvent *ev )
04570 {
04571 KParts::ReadWritePart::guiActivateEvent( ev );
04572 if ( ev->activated() )
04573 emit selectionChanged();
04574 }
04575
04576 void KateDocument::setDocName (QString name )
04577 {
04578 if ( name == m_docName )
04579 return;
04580
04581 if ( !name.isEmpty() )
04582 {
04583
04584 m_docName = name;
04585 updateFileType (KateFactory::self()->fileTypeManager()->fileType (this));
04586 emit nameChanged((Kate::Document *) this);
04587 return;
04588 }
04589
04590
04591 if ( ! url().isEmpty() && m_docName.startsWith( url().filename() ) ) return;
04592
04593 int count = -1;
04594
04595 for (uint z=0; z < KateFactory::self()->documents()->count(); z++)
04596 {
04597 if ( (KateFactory::self()->documents()->at(z) != this) && (KateFactory::self()->documents()->at(z)->url().filename() == url().filename()) )
04598 if ( KateFactory::self()->documents()->at(z)->m_docNameNumber > count )
04599 count = KateFactory::self()->documents()->at(z)->m_docNameNumber;
04600 }
04601
04602 m_docNameNumber = count + 1;
04603
04604 m_docName = url().filename();
04605
04606 if (m_docName.isEmpty())
04607 m_docName = i18n ("Untitled");
04608
04609 if (m_docNameNumber > 0)
04610 m_docName = QString(m_docName + " (%1)").arg(m_docNameNumber+1);
04611
04612 updateFileType (KateFactory::self()->fileTypeManager()->fileType (this));
04613 emit nameChanged ((Kate::Document *) this);
04614 }
04615
04616 void KateDocument::slotModifiedOnDisk( Kate::View * )
04617 {
04618 if ( m_isasking < 0 )
04619 {
04620 m_isasking = 0;
04621 return;
04622 }
04623
04624 if ( !s_fileChangedDialogsActivated || m_isasking )
04625 return;
04626
04627 if (m_modOnHd && !url().isEmpty())
04628 {
04629 m_isasking = 1;
04630
04631 KateModOnHdPrompt p( this, m_modOnHdReason, reasonedMOHString(), widget() );
04632 switch ( p.exec() )
04633 {
04634 case KateModOnHdPrompt::Save:
04635 {
04636 m_modOnHd = false;
04637 KEncodingFileDialog::Result res=KEncodingFileDialog::getSaveURLAndEncoding(config()->encoding(),
04638 url().url(),QString::null,widget(),i18n("Save File"));
04639
04640 kdDebug(13020)<<"got "<<res.URLs.count()<<" URLs"<<endl;
04641 if( ! res.URLs.isEmpty() && ! res.URLs.first().isEmpty() && checkOverwrite( res.URLs.first() ) )
04642 {
04643 setEncoding( res.encoding );
04644
04645 if( ! saveAs( res.URLs.first() ) )
04646 {
04647 KMessageBox::error( widget(), i18n("Save failed") );
04648 m_modOnHd = true;
04649 }
04650 else
04651 emit modifiedOnDisc( this, false, 0 );
04652 }
04653 else
04654 {
04655 m_modOnHd = true;
04656 }
04657
04658 m_isasking = 0;
04659 break;
04660 }
04661
04662 case KateModOnHdPrompt::Reload:
04663 m_modOnHd = false;
04664 emit modifiedOnDisc( this, false, 0 );
04665 reloadFile();
04666 m_isasking = 0;
04667 break;
04668
04669 case KateModOnHdPrompt::Ignore:
04670 m_modOnHd = false;
04671 emit modifiedOnDisc( this, false, 0 );
04672 m_isasking = 0;
04673 break;
04674
04675 case KateModOnHdPrompt::Overwrite:
04676 m_modOnHd = false;
04677 emit modifiedOnDisc( this, false, 0 );
04678 m_isasking = 0;
04679 save();
04680 break;
04681
04682 default:
04683 m_isasking = -1;
04684 }
04685 }
04686 }
04687
04688 void KateDocument::setModifiedOnDisk( int reason )
04689 {
04690 m_modOnHdReason = reason;
04691 m_modOnHd = (reason > 0);
04692 emit modifiedOnDisc( this, (reason > 0), reason );
04693 }
04694
04695 class KateDocumentTmpMark
04696 {
04697 public:
04698 QString line;
04699 KTextEditor::Mark mark;
04700 };
04701
04702 void KateDocument::reloadFile()
04703 {
04704 if ( !url().isEmpty() )
04705 {
04706 if (m_modOnHd && s_fileChangedDialogsActivated)
04707 {
04708 int i = KMessageBox::warningYesNoCancel
04709 (0, reasonedMOHString() + "\n\n" + i18n("What do you want to do?"),
04710 i18n("File Was Changed on Disk"), i18n("&Reload File"), i18n("&Ignore Changes"));
04711
04712 if ( i != KMessageBox::Yes)
04713 {
04714 if (i == KMessageBox::No)
04715 {
04716 m_modOnHd = false;
04717 m_modOnHdReason = 0;
04718 emit modifiedOnDisc (this, m_modOnHd, 0);
04719 }
04720
04721 return;
04722 }
04723 }
04724
04725 QValueList<KateDocumentTmpMark> tmp;
04726
04727 for( QIntDictIterator<KTextEditor::Mark> it( m_marks ); it.current(); ++it )
04728 {
04729 KateDocumentTmpMark m;
04730
04731 m.line = textLine (it.current()->line);
04732 m.mark = *it.current();
04733
04734 tmp.append (m);
04735 }
04736
04737 uint mode = hlMode ();
04738 bool byUser = hlSetByUser;
04739
04740 m_storedVariables.clear();
04741
04742 m_reloading = true;
04743 KateDocument::openURL( url() );
04744 m_reloading = false;
04745
04746 for (uint z=0; z < tmp.size(); z++)
04747 {
04748 if (z < numLines())
04749 {
04750 if (textLine(tmp[z].mark.line) == tmp[z].line)
04751 setMark (tmp[z].mark.line, tmp[z].mark.type);
04752 }
04753 }
04754
04755 if (byUser)
04756 setHlMode (mode);
04757 }
04758 }
04759
04760 void KateDocument::flush ()
04761 {
04762 closeURL ();
04763 }
04764
04765 void KateDocument::setWordWrap (bool on)
04766 {
04767 config()->setWordWrap (on);
04768 }
04769
04770 bool KateDocument::wordWrap ()
04771 {
04772 return config()->wordWrap ();
04773 }
04774
04775 void KateDocument::setWordWrapAt (uint col)
04776 {
04777 config()->setWordWrapAt (col);
04778 }
04779
04780 unsigned int KateDocument::wordWrapAt ()
04781 {
04782 return config()->wordWrapAt ();
04783 }
04784
04785 void KateDocument::applyWordWrap ()
04786 {
04787 if (hasSelection())
04788 wrapText (selectStart.line(), selectEnd.line());
04789 else
04790 wrapText (0, lastLine());
04791 }
04792
04793 void KateDocument::setPageUpDownMovesCursor (bool on)
04794 {
04795 config()->setPageUpDownMovesCursor (on);
04796 }
04797
04798 bool KateDocument::pageUpDownMovesCursor ()
04799 {
04800 return config()->pageUpDownMovesCursor ();
04801 }
04802
04803 void KateDocument::exportAs(const QString& filter)
04804 {
04805 if (filter=="kate_html_export")
04806 {
04807 KURL url = KFileDialog::getSaveURL(QString::null,"text/html",0,i18n("Export File As"));
04808 if ( url.isEmpty() )
04809 return;
04810
04811 QString filename;
04812 KTempFile tmp;
04813
04814 if ( url.isLocalFile() )
04815 filename = url.path();
04816 else
04817 filename = tmp.name();
04818
04819 KSaveFile *savefile=new KSaveFile(filename);
04820 if (!savefile->status())
04821 {
04822 if (exportDocumentToHTML(savefile->textStream(),filename))
04823 savefile->close();
04824 else savefile->abort();
04825
04826 }
04827
04828
04829 delete savefile;
04830
04831 if ( url.isLocalFile() )
04832 return;
04833
04834 KIO::NetAccess::upload( filename, url, 0 );
04835 }
04836 }
04837
04838
04839 bool KateDocument::exportDocumentToHTML(QTextStream *outputStream,const QString &name)
04840 {
04841 outputStream->setEncoding(QTextStream::UnicodeUTF8);
04842
04843 (*outputStream) << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl;
04844 (*outputStream) << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"DTD/xhtml1-strict.dtd\">" << endl;
04845 (*outputStream) << "<html xmlns=\"http://www.w3.org/1999/xhtml\">" << endl;
04846 (*outputStream) << "<head>" << endl;
04847 (*outputStream) << "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />" << endl;
04848 (*outputStream) << "<meta name=\"Generator\" content=\"Kate, the KDE Advanced Text Editor\" />" << endl;
04849
04850 (*outputStream) << "<title>" << name.right(name.length() - name.findRev('/')-1) << "</title>" << endl;
04851 (*outputStream) << "</head>" << endl;
04852 (*outputStream) << "<body>" << endl;
04853
04854 textAsHtmlStream(0,0,lastLine(), lineLength(lastLine()), false, outputStream);
04855
04856 (*outputStream) << "</body>" << endl;
04857 (*outputStream) << "</html>" << endl;
04858 return true;
04859 }
04860
04861 QString KateDocument::HTMLEncode(QChar theChar)
04862 {
04863 switch (theChar.latin1())
04864 {
04865 case '>':
04866 return QString(">");
04867 case '<':
04868 return QString("<");
04869 case '&':
04870 return QString("&");
04871 };
04872 return theChar;
04873 }
04874
04875 Kate::ConfigPage *KateDocument::colorConfigPage (QWidget *p)
04876 {
04877 return (Kate::ConfigPage*) new KateSchemaConfigPage (p, this);
04878 }
04879
04880 Kate::ConfigPage *KateDocument::viewDefaultsConfigPage (QWidget *p)
04881 {
04882 return (Kate::ConfigPage*) new KateViewDefaultsConfig(p);
04883 }
04884
04885 Kate::ConfigPage *KateDocument::fontConfigPage (QWidget *p)
04886 {
04887 return (Kate::ConfigPage*) new KateSchemaConfigPage ( p );
04888 }
04889
04890 Kate::ConfigPage *KateDocument::indentConfigPage (QWidget *p)
04891 {
04892 return (Kate::ConfigPage*) new KateIndentConfigTab(p);
04893 }
04894
04895 Kate::ConfigPage *KateDocument::selectConfigPage (QWidget *p)
04896 {
04897 return (Kate::ConfigPage*) new KateSelectConfigTab(p);
04898 }
04899
04900 Kate::ConfigPage *KateDocument::editConfigPage (QWidget *p)
04901 {
04902 return (Kate::ConfigPage*) new KateEditConfigTab(p);
04903 }
04904
04905 Kate::ConfigPage *KateDocument::keysConfigPage (QWidget *p)
04906 {
04907 return (Kate::ConfigPage*) new KateEditKeyConfiguration(p, this);
04908 }
04909
04910 Kate::ConfigPage *KateDocument::hlConfigPage (QWidget *p)
04911 {
04912 return (Kate::ConfigPage*) new KateHlConfigPage (p);
04913 }
04914
04915 Kate::ConfigPage *KateDocument::saveConfigPage(QWidget *p)
04916 {
04917 return (Kate::ConfigPage*) new KateSaveConfigTab(p);
04918 }
04919
04920 Kate::ActionMenu *KateDocument::hlActionMenu (const QString& text, QObject* parent, const char* name)
04921 {
04922 KateViewHighlightAction *menu = new KateViewHighlightAction (text, parent, name);
04923 menu->setWhatsThis(i18n("Here you can choose how the current document should be highlighted."));
04924 menu->updateMenu (this);
04925
04926 return (Kate::ActionMenu *)menu;
04927 }
04928
04929 Kate::ActionMenu *KateDocument::exportActionMenu (const QString& text, QObject* parent, const char* name)
04930 {
04931 KateExportAction *menu = new KateExportAction (text, parent, name);
04932 menu->updateMenu (this);
04933 menu->setWhatsThis(i18n("This command allows you to export the current document"
04934 " with all highlighting information into a markup document, e.g. HTML."));
04935 return (Kate::ActionMenu *)menu;
04936 }
04937
04938 void KateDocument::dumpRegionTree()
04939 {
04940 m_buffer->foldingTree()->debugDump();
04941 }
04942
04943
04944
04945
04946 KTextEditor::Cursor *KateDocument::createCursor ( )
04947 {
04948 return new KateSuperCursor (this, false, 0, 0, this);
04949 }
04950
04951 void KateDocument::tagArbitraryLines(KateView* view, KateSuperRange* range)
04952 {
04953 if (view)
04954 view->tagLines(range->start(), range->end());
04955 else
04956 tagLines(range->start(), range->end());
04957 }
04958
04959
04960
04961
04962
04963 void KateDocument::spellcheck()
04964 {
04965 spellcheck( KateTextCursor( 0, 0 ) );
04966 }
04967
04968 void KateDocument::spellcheck( const KateTextCursor &from, const KateTextCursor &to )
04969 {
04970 if( !isReadWrite() || text().isEmpty() )
04971 return;
04972
04973
04974 m_spellStart = from;
04975 m_spellEnd = to;
04976
04977 if ( to.line() == 0 && to.col() == 0 )
04978 {
04979 int lln = lastLine();
04980 m_spellEnd.setLine( lln );
04981 m_spellEnd.setCol( lineLength( lln ) );
04982 }
04983
04984 m_spellPosCursor = from;
04985 m_spellLastPos = 0;
04986
04987 QString mt = mimeType();
04988
04989 KSpell::SpellerType type = KSpell::Text;
04990 if ( mt == "text/x-tex" || mt == "text/x-latex" )
04991 type = KSpell::TeX;
04992 else if ( mt == "text/html" || mt == "text/xml" )
04993 type = KSpell::HTML;
04994
04995 m_kspell = new KSpell( 0, i18n("Spellcheck"),
04996 this, SLOT(ready(KSpell *)), 0, true, false, type );
04997
04998 connect( m_kspell, SIGNAL(death()),
04999 this, SLOT(spellCleanDone()) );
05000
05001 connect( m_kspell, SIGNAL(misspelling(const QString&, const QStringList&, unsigned int)),
05002 this, SLOT(misspelling(const QString&, const QStringList&, unsigned int)) );
05003 connect( m_kspell, SIGNAL(corrected(const QString&, const QString&, unsigned int)),
05004 this, SLOT(corrected(const QString&, const QString&, unsigned int)) );
05005 connect( m_kspell, SIGNAL(done(const QString&)),
05006 this, SLOT(spellResult(const QString&)) );
05007 }
05008
05009 void KateDocument::ready(KSpell *)
05010 {
05011 m_kspell->setProgressResolution( 1 );
05012
05013 m_kspell->check( text( m_spellStart.line(), m_spellStart.col(), m_spellEnd.line(), m_spellEnd.col() ) );
05014
05015 kdDebug (13020) << "SPELLING READY STATUS: " << m_kspell->status () << endl;
05016 }
05017
05018 void KateDocument::locatePosition( uint pos, uint& line, uint& col )
05019 {
05020 uint remains;
05021
05022 while ( m_spellLastPos < pos )
05023 {
05024 remains = pos - m_spellLastPos;
05025 uint l = lineLength( m_spellPosCursor.line() ) - m_spellPosCursor.col();
05026 if ( l > remains )
05027 {
05028 m_spellPosCursor.setCol( m_spellPosCursor.col() + remains );
05029 m_spellLastPos = pos;
05030 }
05031 else
05032 {
05033 m_spellPosCursor.setLine( m_spellPosCursor.line() + 1 );
05034 m_spellPosCursor.setCol(0);
05035 m_spellLastPos += l + 1;
05036 }
05037 }
05038
05039 line = m_spellPosCursor.line();
05040 col = m_spellPosCursor.col();
05041 }
05042
05043 void KateDocument::misspelling( const QString& origword, const QStringList&, unsigned int pos )
05044 {
05045 uint line, col;
05046
05047 locatePosition( pos, line, col );
05048
05049 if (activeView())
05050 activeView()->setCursorPositionInternal (line, col, 1);
05051
05052 setSelection( line, col, line, col + origword.length() );
05053 }
05054
05055 void KateDocument::corrected( const QString& originalword, const QString& newword, unsigned int pos )
05056 {
05057 uint line, col;
05058
05059 locatePosition( pos, line, col );
05060
05061 removeText( line, col, line, col + originalword.length() );
05062 insertText( line, col, newword );
05063 }
05064
05065 void KateDocument::spellResult( const QString& )
05066 {
05067 clearSelection();
05068 m_kspell->cleanUp();
05069 }
05070
05071 void KateDocument::spellCleanDone()
05072 {
05073 KSpell::spellStatus status = m_kspell->status();
05074
05075 if( status == KSpell::Error ) {
05076 KMessageBox::sorry( 0,
05077 i18n("The spelling program could not be started. "
05078 "Please make sure you have set the correct spelling program "
05079 "and that it is properly configured and in your PATH."));
05080 } else if( status == KSpell::Crashed ) {
05081 KMessageBox::sorry( 0,
05082 i18n("The spelling program seems to have crashed."));
05083 }
05084
05085 delete m_kspell;
05086 m_kspell = 0;
05087
05088 kdDebug (13020) << "SPELLING END" << endl;
05089 }
05090
05091
05092 void KateDocument::lineInfo (KateLineInfo *info, unsigned int line)
05093 {
05094 m_buffer->lineInfo(info,line);
05095 }
05096
05097 KateCodeFoldingTree *KateDocument::foldingTree ()
05098 {
05099 return m_buffer->foldingTree();
05100 }
05101
05102 void KateDocument::setEncoding (const QString &e)
05103 {
05104 m_config->setEncoding(e);
05105 }
05106
05107 QString KateDocument::encoding() const
05108 {
05109 return m_config->encoding();
05110 }
05111
05112 void KateDocument::updateConfig ()
05113 {
05114 emit undoChanged ();
05115 tagAll();
05116
05117 for (KateView * view = m_views.first(); view != 0L; view = m_views.next() )
05118 {
05119 view->updateDocumentConfig ();
05120 }
05121
05122
05123 if (m_indenter->modeNumber() != m_config->indentationMode())
05124 {
05125 delete m_indenter;
05126 m_indenter = KateAutoIndent::createIndenter ( this, m_config->indentationMode() );
05127 }
05128
05129 m_indenter->updateConfig();
05130
05131 m_buffer->setTabWidth (config()->tabWidth());
05132
05133
05134 for (uint i=0; i<KateFactory::self()->plugins().count(); i++)
05135 {
05136 if (config()->plugin (i))
05137 loadPlugin (i);
05138 else
05139 unloadPlugin (i);
05140 }
05141 }
05142
05143
05144
05145
05146
05147
05148
05149
05150 QRegExp KateDocument::kvLine = QRegExp("kate:(.*)");
05151 QRegExp KateDocument::kvVar = QRegExp("([\\w\\-]+)\\s+([^;]+)");
05152
05153 void KateDocument::readVariables(bool onlyViewAndRenderer)
05154 {
05155 if (!onlyViewAndRenderer)
05156 m_config->configStart();
05157
05158
05159 KateView *v;
05160 for (v = m_views.first(); v != 0L; v= m_views.next() )
05161 {
05162 v->config()->configStart();
05163 v->renderer()->config()->configStart();
05164 }
05165
05166 for (uint i=0; i < QMIN( 9, numLines() ); ++i )
05167 {
05168 readVariableLine( textLine( i ), onlyViewAndRenderer );
05169 }
05170 if ( numLines() > 10 )
05171 {
05172 for ( uint i = QMAX(10, numLines() - 10); i < numLines(); ++i )
05173 {
05174 readVariableLine( textLine( i ), onlyViewAndRenderer );
05175 }
05176 }
05177
05178 if (!onlyViewAndRenderer)
05179 m_config->configEnd();
05180
05181 for (v = m_views.first(); v != 0L; v= m_views.next() )
05182 {
05183 v->config()->configEnd();
05184 v->renderer()->config()->configEnd();
05185 }
05186 }
05187
05188 void KateDocument::readVariableLine( QString t, bool onlyViewAndRenderer )
05189 {
05190 if ( kvLine.search( t ) > -1 )
05191 {
05192 QStringList vvl;
05193 vvl << "dynamic-word-wrap" << "dynamic-word-wrap-indicators"
05194 << "line-numbers" << "icon-border" << "folding-markers"
05195 << "bookmark-sorting" << "auto-center-lines"
05196 << "icon-bar-color"
05197
05198 << "background-color" << "selection-color"
05199 << "current-line-color" << "bracket-highlight-color"
05200 << "word-wrap-marker-color"
05201 << "font" << "font-size" << "scheme";
05202 int p( 0 );
05203 QString s = kvLine.cap(1);
05204 QString var, val;
05205 while ( (p = kvVar.search( s, p )) > -1 )
05206 {
05207 p += kvVar.matchedLength();
05208 var = kvVar.cap( 1 );
05209 val = kvVar.cap( 2 ).stripWhiteSpace();
05210 bool state;
05211 int n;
05212
05213
05214 if (onlyViewAndRenderer)
05215 {
05216 if ( vvl.contains( var ) )
05217 setViewVariable( var, val );
05218 }
05219 else
05220 {
05221
05222 if ( var == "word-wrap" && checkBoolValue( val, &state ) )
05223 setWordWrap( state );
05224 else if ( var == "block-selection" && checkBoolValue( val, &state ) )
05225 setBlockSelectionMode( state );
05226
05227
05228 else if ( var == "backspace-indents" && checkBoolValue( val, &state ) )
05229 m_config->setConfigFlags( KateDocumentConfig::cfBackspaceIndents, state );
05230 else if ( var == "replace-tabs" && checkBoolValue( val, &state ) )
05231 m_config->setConfigFlags( KateDocumentConfig::cfReplaceTabsDyn, state );
05232 else if ( var == "remove-trailing-space" && checkBoolValue( val, &state ) )
05233 m_config->setConfigFlags( KateDocumentConfig::cfRemoveTrailingDyn, state );
05234 else if ( var == "wrap-cursor" && checkBoolValue( val, &state ) )
05235 m_config->setConfigFlags( KateDocumentConfig::cfWrapCursor, state );
05236 else if ( var == "auto-brackets" && checkBoolValue( val, &state ) )
05237 m_config->setConfigFlags( KateDocumentConfig::cfAutoBrackets, state );
05238 else if ( var == "persistent-selection" && checkBoolValue( val, &state ) )
05239 m_config->setConfigFlags( KateDocumentConfig::cfPersistent, state );
05240
05241
05242 else if ( var == "overwrite-mode" && checkBoolValue( val, &state ) )
05243 m_config->setConfigFlags( KateDocumentConfig::cfOvr, state );
05244 else if ( var == "keep-indent-profile" && checkBoolValue( val, &state ) )
05245 m_config->setConfigFlags( KateDocumentConfig::cfKeepIndentProfile, state );
05246 else if ( var == "keep-extra-spaces" && checkBoolValue( val, &state ) )
05247 m_config->setConfigFlags( KateDocumentConfig::cfKeepExtraSpaces, state );
05248 else if ( var == "tab-indents" && checkBoolValue( val, &state ) )
05249 m_config->setConfigFlags( KateDocumentConfig::cfTabIndents, state );
05250 else if ( var == "show-tabs" && checkBoolValue( val, &state ) )
05251 m_config->setConfigFlags( KateDocumentConfig::cfShowTabs, state );
05252 else if ( var == "space-indent" && checkBoolValue( val, &state ) )
05253 m_config->setConfigFlags( KateDocumentConfig::cfSpaceIndent, state );
05254 else if ( var == "smart-home" && checkBoolValue( val, &state ) )
05255 m_config->setConfigFlags( KateDocumentConfig::cfSmartHome, state );
05256 else if ( var == "replace-tabs-save" && checkBoolValue( val, &state ) )
05257 m_config->setConfigFlags( KateDocumentConfig::cfReplaceTabs, state );
05258 else if ( var == "replace-trailing-space-save" && checkBoolValue( val, &state ) )
05259 m_config->setConfigFlags( KateDocumentConfig::cfRemoveSpaces, state );
05260 else if ( var == "auto-insert-doxygen" && checkBoolValue( val, &state) )
05261 m_config->setConfigFlags( KateDocumentConfig::cfDoxygenAutoTyping, state);
05262 else if ( var == "mixed-indent" && checkBoolValue( val, &state ) )
05263 m_config->setConfigFlags( KateDocumentConfig::cfMixedIndent, &state );
05264
05265
05266 else if ( var == "tab-width" && checkIntValue( val, &n ) )
05267 m_config->setTabWidth( n );
05268 else if ( var == "indent-width" && checkIntValue( val, &n ) )
05269 m_config->setIndentationWidth( n );
05270 else if ( var == "indent-mode" )
05271 {
05272 if ( checkIntValue( val, &n ) )
05273 m_config->setIndentationMode( n );
05274 else
05275 m_config->setIndentationMode( KateAutoIndent::modeNumber( val) );
05276 }
05277 else if ( var == "word-wrap-column" && n > 0 && checkIntValue( val, &n ) )
05278 m_config->setWordWrapAt( n );
05279 else if ( var == "undo-steps" && n >= 0 && checkIntValue( val, &n ) )
05280 setUndoSteps( n );
05281
05282
05283 else if ( var == "eol" || var == "end-of-line" )
05284 {
05285 QStringList l;
05286 l << "unix" << "dos" << "mac";
05287 if ( (n = l.findIndex( val.lower() )) != -1 )
05288 m_config->setEol( n );
05289 }
05290 else if ( var == "encoding" )
05291 m_config->setEncoding( val );
05292 else if ( var == "syntax" || var == "hl" )
05293 {
05294 for ( uint i=0; i < hlModeCount(); i++ )
05295 {
05296 if ( hlModeName( i ).lower() == val.lower() )
05297 {
05298 setHlMode( i );
05299 break;
05300 }
05301 }
05302 }
05303
05304
05305 else if ( vvl.contains( var ) )
05306 setViewVariable( var, val );
05307 else
05308 {
05309 m_storedVariables.insert( var, val );
05310 emit variableChanged( var, val );
05311 }
05312 }
05313 }
05314 }
05315 }
05316
05317 void KateDocument::setViewVariable( QString var, QString val )
05318 {
05319 KateView *v;
05320 bool state;
05321 int n;
05322 QColor c;
05323 for (v = m_views.first(); v != 0L; v= m_views.next() )
05324 {
05325 if ( var == "dynamic-word-wrap" && checkBoolValue( val, &state ) )
05326 v->config()->setDynWordWrap( state );
05327
05328 else if ( var == "line-numbers" && checkBoolValue( val, &state ) )
05329 v->config()->setLineNumbers( state );
05330 else if (var == "icon-border" && checkBoolValue( val, &state ) )
05331 v->config()->setIconBar( state );
05332 else if (var == "folding-markers" && checkBoolValue( val, &state ) )
05333 v->config()->setFoldingBar( state );
05334 else if ( var == "auto-center-lines" && checkIntValue( val, &n ) )
05335 v->config()->setAutoCenterLines( n );
05336 else if ( var == "icon-bar-color" && checkColorValue( val, c ) )
05337 v->renderer()->config()->setIconBarColor( c );
05338
05339 else if ( var == "background-color" && checkColorValue( val, c ) )
05340 v->renderer()->config()->setBackgroundColor( c );
05341 else if ( var == "selection-color" && checkColorValue( val, c ) )
05342 v->renderer()->config()->setSelectionColor( c );
05343 else if ( var == "current-line-color" && checkColorValue( val, c ) )
05344 v->renderer()->config()->setHighlightedLineColor( c );
05345 else if ( var == "bracket-highlight-color" && checkColorValue( val, c ) )
05346 v->renderer()->config()->setHighlightedBracketColor( c );
05347 else if ( var == "word-wrap-marker-color" && checkColorValue( val, c ) )
05348 v->renderer()->config()->setWordWrapMarkerColor( c );
05349 else if ( var == "font" || ( var == "font-size" && checkIntValue( val, &n ) ) )
05350 {
05351 QFont _f( *v->renderer()->config()->font( ) );
05352
05353 if ( var == "font" )
05354 {
05355 _f.setFamily( val );
05356 _f.setFixedPitch( QFont( val ).fixedPitch() );
05357 }
05358 else
05359 _f.setPointSize( n );
05360
05361 v->renderer()->config()->setFont( _f );
05362 }
05363 else if ( var == "scheme" )
05364 {
05365 v->renderer()->config()->setSchema( KateFactory::self()->schemaManager()->number( val ) );
05366 }
05367 }
05368 }
05369
05370 bool KateDocument::checkBoolValue( QString val, bool *result )
05371 {
05372 val = val.stripWhiteSpace().lower();
05373 QStringList l;
05374 l << "1" << "on" << "true";
05375 if ( l.contains( val ) )
05376 {
05377 *result = true;
05378 return true;
05379 }
05380 l.clear();
05381 l << "0" << "off" << "false";
05382 if ( l.contains( val ) )
05383 {
05384 *result = false;
05385 return true;
05386 }
05387 return false;
05388 }
05389
05390 bool KateDocument::checkIntValue( QString val, int *result )
05391 {
05392 bool ret( false );
05393 *result = val.toInt( &ret );
05394 return ret;
05395 }
05396
05397 bool KateDocument::checkColorValue( QString val, QColor &c )
05398 {
05399 c.setNamedColor( val );
05400 return c.isValid();
05401 }
05402
05403
05404 QString KateDocument::variable( const QString &name ) const
05405 {
05406 if ( m_storedVariables.contains( name ) )
05407 return m_storedVariables[ name ];
05408
05409 return "";
05410 }
05411
05412
05413
05414 void KateDocument::slotModOnHdDirty (const QString &path)
05415 {
05416 if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != 1))
05417 {
05418
05419 if ( ! m_digest.isEmpty() )
05420 {
05421 QCString tmp;
05422 if ( createDigest( tmp ) && tmp == m_digest )
05423 return;
05424 }
05425
05426 m_modOnHd = true;
05427 m_modOnHdReason = 1;
05428
05429
05430 if (m_isasking == -1)
05431 m_isasking = false;
05432
05433 emit modifiedOnDisc (this, m_modOnHd, m_modOnHdReason);
05434 }
05435 }
05436
05437 void KateDocument::slotModOnHdCreated (const QString &path)
05438 {
05439 if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != 2))
05440 {
05441 m_modOnHd = true;
05442 m_modOnHdReason = 2;
05443
05444
05445 if (m_isasking == -1)
05446 m_isasking = false;
05447
05448 emit modifiedOnDisc (this, m_modOnHd, m_modOnHdReason);
05449 }
05450 }
05451
05452 void KateDocument::slotModOnHdDeleted (const QString &path)
05453 {
05454 if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != 3))
05455 {
05456 m_modOnHd = true;
05457 m_modOnHdReason = 3;
05458
05459
05460 if (m_isasking == -1)
05461 m_isasking = false;
05462
05463 emit modifiedOnDisc (this, m_modOnHd, m_modOnHdReason);
05464 }
05465 }
05466
05467 bool KateDocument::createDigest( QCString &result )
05468 {
05469 bool ret = false;
05470 result = "";
05471 if ( url().isLocalFile() )
05472 {
05473 QFile f ( url().path() );
05474 if ( f.open( IO_ReadOnly) )
05475 {
05476 KMD5 md5;
05477 ret = md5.update( f );
05478 md5.hexDigest( result );
05479 f.close();
05480 }
05481 }
05482 return ret;
05483 }
05484
05485 QString KateDocument::reasonedMOHString() const
05486 {
05487 switch( m_modOnHdReason )
05488 {
05489 case 1:
05490 return i18n("The file '%1' was modified by another program.").arg( url().prettyURL() );
05491 break;
05492 case 2:
05493 return i18n("The file '%1' was created by another program.").arg( url().prettyURL() );
05494 break;
05495 case 3:
05496 return i18n("The file '%1' was deleted by another program.").arg( url().prettyURL() );
05497 break;
05498 default:
05499 return QString();
05500 }
05501 }
05502
05503 void KateDocument::removeTrailingSpace( uint line )
05504 {
05505
05506 if ( config()->configFlags() & KateDocumentConfig::cfRemoveTrailingDyn )
05507 {
05508 KateTextLine::Ptr ln = kateTextLine( line );
05509
05510 if ( ! ln ) return;
05511
05512 if ( line == activeView()->cursorLine()
05513 && activeView()->cursorColumnReal() >= (uint)QMAX(0,ln->lastChar()) )
05514 return;
05515
05516 if ( ln->length() )
05517 {
05518 uint p = ln->lastChar() + 1;
05519 uint l = ln->length() - p;
05520 if ( l )
05521 editRemoveText( line, p, l);
05522 }
05523 }
05524 }
05525
05526 bool KateDocument::wrapCursor ()
05527 {
05528 return !blockSelect && (configFlags() & KateDocument::cfWrapCursor);
05529 }
05530
05531 void KateDocument::updateFileType (int newType, bool user)
05532 {
05533 if (user || !m_fileTypeSetByUser)
05534 {
05535 const KateFileType *t = 0;
05536 if ((newType == -1) || (t = KateFactory::self()->fileTypeManager()->fileType (newType)))
05537 {
05538 m_fileType = newType;
05539
05540 if (t)
05541 {
05542 m_config->configStart();
05543
05544 KateView *v;
05545 for (v = m_views.first(); v != 0L; v= m_views.next() )
05546 {
05547 v->config()->configStart();
05548 v->renderer()->config()->configStart();
05549 }
05550
05551 readVariableLine( t->varLine );
05552
05553 m_config->configEnd();
05554 for (v = m_views.first(); v != 0L; v= m_views.next() )
05555 {
05556 v->config()->configEnd();
05557 v->renderer()->config()->configEnd();
05558 }
05559 }
05560 }
05561 }
05562 }
05563
05564 uint KateDocument::documentNumber () const
05565 {
05566 return KTextEditor::Document::documentNumber ();
05567 }
05568
05569
05570
05571
05572 void KateDocument::slotQueryClose_save(bool *handled, bool* abortClosing) {
05573 *handled=true;
05574 *abortClosing=true;
05575 if (m_url.isEmpty())
05576 {
05577 KEncodingFileDialog::Result res=KEncodingFileDialog::getSaveURLAndEncoding(config()->encoding(),
05578 QString::null,QString::null,0,i18n("Save File"));
05579
05580 if( res.URLs.isEmpty() || !checkOverwrite( res.URLs.first() ) ) {
05581 *abortClosing=true;
05582 return;
05583 }
05584 setEncoding( res.encoding );
05585 saveAs( res.URLs.first() );
05586 *abortClosing=false;
05587 }
05588 else
05589 {
05590 save();
05591 *abortClosing=false;
05592 }
05593
05594 }
05595
05596 bool KateDocument::checkOverwrite( KURL u )
05597 {
05598 if( !u.isLocalFile() )
05599 return true;
05600
05601 QFileInfo info( u.path() );
05602 if( !info.exists() )
05603 return true;
05604
05605 return KMessageBox::Cancel != KMessageBox::warningContinueCancel( 0,
05606 i18n( "A file named \"%1\" already exists. "
05607 "Are you sure you want to overwrite it?" ).arg( info.fileName() ),
05608 i18n( "Overwrite File?" ),
05609 i18n( "&Overwrite" ) );
05610 }
05611
05612 void KateDocument::setDefaultEncoding (const QString &encoding)
05613 {
05614 s_defaultEncoding = encoding;
05615 }
05616
05617
05618 bool KateDocument::insertTemplateTextImplementation ( uint line, uint column, const QString &templateString, const QMap<QString,QString> &initialValues, QWidget *) {
05619 return (new KateTemplateHandler(this,line,column,templateString,initialValues))->initOk();
05620 }
05621
05622 void KateDocument::testTemplateCode() {
05623 int col=activeView()->cursorColumn();
05624 int line=activeView()->cursorLine();
05625 insertTemplateText(line,col,"for ${index} \\${NOPLACEHOLDER} ${index} ${blah} ${fullname} \\$${Placeholder} \\${${PLACEHOLDER2}}\n next line:${ANOTHERPLACEHOLDER} $${DOLLARBEFOREPLACEHOLDER} {NOTHING} {\n${cursor}\n}",QMap<QString,QString>());
05626 }
05627
05628 bool KateDocument::invokeTabInterceptor(KKey key) {
05629 if (m_tabInterceptor) return (*m_tabInterceptor)(key);
05630 return false;
05631 }
05632
05633 bool KateDocument::setTabInterceptor(KateKeyInterceptorFunctor *interceptor) {
05634 if (m_tabInterceptor) return false;
05635 m_tabInterceptor=interceptor;
05636 return true;
05637 }
05638
05639 bool KateDocument::removeTabInterceptor(KateKeyInterceptorFunctor *interceptor) {
05640 if (m_tabInterceptor!=interceptor) return false;
05641 m_tabInterceptor=0;
05642 return true;
05643 }
05644
05645
05646
05647 void KateDocument::setIMSelectionValue( uint imStartLine, uint imStart, uint imEnd,
05648 uint imSelStart, uint imSelEnd, bool imComposeEvent )
05649 {
05650 m_imStartLine = imStartLine;
05651 m_imStart = imStart;
05652 m_imEnd = imEnd;
05653 m_imSelStart = imSelStart;
05654 m_imSelEnd = imSelEnd;
05655 m_imComposeEvent = imComposeEvent;
05656 }
05657
05658 bool KateDocument::isIMSelection( int _line, int _column )
05659 {
05660 return ( ( int( m_imStartLine ) == _line ) && ( m_imSelStart < m_imSelEnd ) && ( _column >= int( m_imSelStart ) ) &&
05661 ( _column < int( m_imSelEnd ) ) );
05662 }
05663
05664 bool KateDocument::isIMEdit( int _line, int _column )
05665 {
05666 return ( ( int( m_imStartLine ) == _line ) && ( m_imStart < m_imEnd ) && ( _column >= int( m_imStart ) ) &&
05667 ( _column < int( m_imEnd ) ) );
05668 }
05669
05670 void KateDocument::getIMSelectionValue( uint *imStartLine, uint *imStart, uint *imEnd,
05671 uint *imSelStart, uint *imSelEnd )
05672 {
05673 *imStartLine = m_imStartLine;
05674 *imStart = m_imStart;
05675 *imEnd = m_imEnd;
05676 *imSelStart = m_imSelStart;
05677 *imSelEnd = m_imSelEnd;
05678 }
05679
05680