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