# kate Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# katedocument.cpp

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

This file is part of the documentation for kate Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:36:35 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003