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