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
01565
01566
01567
01568
01569
01570
01571
01572
01573
01574 unsigned char currentPattern = 0;
01575 const unsigned char patterns[] = {5,16,24,26,88,90,93,133,144,149,165};
01576 const unsigned char patternCount = sizeof(patterns);
01577 KateUndoGroup* undoLast = 0;
01578 KateUndoGroup* redoLast = 0;
01579
01580 if (undoItems.isEmpty())
01581 {
01582 currentPattern |= 1;
01583 }
01584 else
01585 {
01586 undoLast = undoItems.last();
01587 }
01588
01589 if (redoItems.isEmpty())
01590 {
01591 currentPattern |= 2;
01592 }
01593 else
01594 {
01595 redoLast = redoItems.last();
01596 }
01597
01598 if (docWasSavedWhenUndoWasEmpty) currentPattern |= 4;
01599 if (docWasSavedWhenRedoWasEmpty) currentPattern |= 8;
01600 if (lastUndoGroupWhenSaved == undoLast) currentPattern |= 16;
01601 if (lastUndoGroupWhenSaved == redoLast) currentPattern |= 32;
01602 if (lastRedoGroupWhenSaved == undoLast) currentPattern |= 64;
01603 if (lastRedoGroupWhenSaved == redoLast) currentPattern |= 128;
01604
01605
01606
01607 kdDebug(13020) << k_funcinfo
01608 << "Pattern:" << static_cast<unsigned int>(currentPattern) << endl;
01609
01610 for (uint patternIndex = 0; patternIndex < patternCount; ++patternIndex)
01611 {
01612 if ( currentPattern == patterns[patternIndex] )
01613 {
01614 setModified( false );
01615 kdDebug(13020) << k_funcinfo << "setting modified to false!" << endl;
01616 break;
01617 }
01618 }
01619 }
01620
01621 void KateDocument::clearUndo()
01622 {
01623 undoItems.setAutoDelete (true);
01624 undoItems.clear ();
01625 undoItems.setAutoDelete (false);
01626
01627 lastUndoGroupWhenSaved = 0;
01628 docWasSavedWhenUndoWasEmpty = false;
01629
01630 emit undoChanged ();
01631 }
01632
01633 void KateDocument::clearRedo()
01634 {
01635 redoItems.setAutoDelete (true);
01636 redoItems.clear ();
01637 redoItems.setAutoDelete (false);
01638
01639 lastRedoGroupWhenSaved = 0;
01640 docWasSavedWhenRedoWasEmpty = false;
01641
01642 emit undoChanged ();
01643 }
01644
01645 QPtrList<KTextEditor::Cursor> KateDocument::cursors () const
01646 {
01647 return myCursors;
01648 }
01649
01650
01651
01652
01653 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)
01654 {
01655 if (text.isEmpty())
01656 return false;
01657
01658 int line = startLine;
01659 int col = startCol;
01660
01661 if (!backwards)
01662 {
01663 int searchEnd = lastLine();
01664
01665 while (line <= searchEnd)
01666 {
01667 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
01668
01669 if (!textLine)
01670 return false;
01671
01672 uint foundAt, myMatchLen;
01673 bool found = textLine->searchText (col, text, &foundAt, &myMatchLen, casesensitive, false);
01674
01675 if (found)
01676 {
01677 (*foundAtLine) = line;
01678 (*foundAtCol) = foundAt;
01679 (*matchLen) = myMatchLen;
01680 return true;
01681 }
01682
01683 col = 0;
01684 line++;
01685 }
01686 }
01687 else
01688 {
01689
01690 int searchEnd = 0;
01691
01692 while (line >= searchEnd)
01693 {
01694 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
01695
01696 if (!textLine)
01697 return false;
01698
01699 uint foundAt, myMatchLen;
01700 bool found = textLine->searchText (col, text, &foundAt, &myMatchLen, casesensitive, true);
01701
01702 if (found)
01703 {
01704
01705
01706
01707
01708
01709
01710
01711
01712
01713
01714
01715
01716
01717
01718
01719 (*foundAtLine) = line;
01720 (*foundAtCol) = foundAt;
01721 (*matchLen) = myMatchLen;
01722 return true;
01723 }
01724
01725 if (line >= 1)
01726 col = lineLength(line-1);
01727
01728 line--;
01729 }
01730 }
01731
01732 return false;
01733 }
01734
01735 bool KateDocument::searchText (unsigned int startLine, unsigned int startCol, const QRegExp ®exp, unsigned int *foundAtLine, unsigned int *foundAtCol, unsigned int *matchLen, bool backwards)
01736 {
01737 kdDebug(13020)<<"KateDocument::searchText( "<<startLine<<", "<<startCol<<", "<<regexp.pattern()<<", "<<backwards<<" )"<<endl;
01738 if (regexp.isEmpty() || !regexp.isValid())
01739 return false;
01740
01741 int line = startLine;
01742 int col = startCol;
01743
01744 if (!backwards)
01745 {
01746 int searchEnd = lastLine();
01747
01748 while (line <= searchEnd)
01749 {
01750 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
01751
01752 if (!textLine)
01753 return false;
01754
01755 uint foundAt, myMatchLen;
01756 bool found = textLine->searchText (col, regexp, &foundAt, &myMatchLen, false);
01757
01758 if (found)
01759 {
01760
01761
01762 if (myMatchLen == 0 && (uint) line == startLine && foundAt == (uint) col)
01763 {
01764 if (col < lineLength(line))
01765 col++;
01766 else {
01767 line++;
01768 col = 0;
01769 }
01770 continue;
01771 }
01772
01773 (*foundAtLine) = line;
01774 (*foundAtCol) = foundAt;
01775 (*matchLen) = myMatchLen;
01776 return true;
01777 }
01778
01779 col = 0;
01780 line++;
01781 }
01782 }
01783 else
01784 {
01785
01786 int searchEnd = 0;
01787
01788 while (line >= searchEnd)
01789 {
01790 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
01791
01792 if (!textLine)
01793 return false;
01794
01795 uint foundAt, myMatchLen;
01796 bool found = textLine->searchText (col, regexp, &foundAt, &myMatchLen, true);
01797
01798 if (found)
01799 {
01800
01801
01802
01803
01804
01805
01806
01807
01808
01809
01810
01811
01812
01813
01814
01815 (*foundAtLine) = line;
01816 (*foundAtCol) = foundAt;
01817 (*matchLen) = myMatchLen;
01818 return true;
01819 }
01820
01821 if (line >= 1)
01822 col = lineLength(line-1);
01823
01824 line--;
01825 }
01826 }
01827
01828 return false;
01829 }
01830
01831
01832
01833
01834 uint KateDocument::hlMode ()
01835 {
01836 return KateHlManager::self()->findHl(highlight());
01837 }
01838
01839 bool KateDocument::setHlMode (uint mode)
01840 {
01841 m_buffer->setHighlight (mode);
01842
01843 if (true)
01844 {
01845 setDontChangeHlOnSave();
01846 return true;
01847 }
01848
01849 return false;
01850 }
01851
01852 void KateDocument::bufferHlChanged ()
01853 {
01854
01855 makeAttribs(false);
01856
01857 emit hlChanged();
01858 }
01859
01860 uint KateDocument::hlModeCount ()
01861 {
01862 return KateHlManager::self()->highlights();
01863 }
01864
01865 QString KateDocument::hlModeName (uint mode)
01866 {
01867 return KateHlManager::self()->hlName (mode);
01868 }
01869
01870 QString KateDocument::hlModeSectionName (uint mode)
01871 {
01872 return KateHlManager::self()->hlSection (mode);
01873 }
01874
01875 void KateDocument::setDontChangeHlOnSave()
01876 {
01877 hlSetByUser = true;
01878 }
01879
01880
01881
01882 void KateDocument::readConfig(KConfig *config)
01883 {
01884 config->setGroup("Kate Document Defaults");
01885
01886
01887 KateBuffer::setMaxLoadedBlocks (config->readNumEntry("Maximal Loaded Blocks", KateBuffer::maxLoadedBlocks()));
01888
01889 KateDocumentConfig::global()->readConfig (config);
01890
01891 config->setGroup("Kate View Defaults");
01892 KateViewConfig::global()->readConfig (config);
01893
01894 config->setGroup("Kate Renderer Defaults");
01895 KateRendererConfig::global()->readConfig (config);
01896 }
01897
01898 void KateDocument::writeConfig(KConfig *config)
01899 {
01900 config->setGroup("Kate Document Defaults");
01901
01902
01903 config->writeEntry("Maximal Loaded Blocks", KateBuffer::maxLoadedBlocks());
01904
01905 KateDocumentConfig::global()->writeConfig (config);
01906
01907 config->setGroup("Kate View Defaults");
01908 KateViewConfig::global()->writeConfig (config);
01909
01910 config->setGroup("Kate Renderer Defaults");
01911 KateRendererConfig::global()->writeConfig (config);
01912 }
01913
01914 void KateDocument::readConfig()
01915 {
01916 KConfig *config = kapp->config();
01917 readConfig (config);
01918 }
01919
01920 void KateDocument::writeConfig()
01921 {
01922 KConfig *config = kapp->config();
01923 writeConfig (config);
01924 config->sync();
01925 }
01926
01927 void KateDocument::readSessionConfig(KConfig *kconfig)
01928 {
01929
01930 KURL url (kconfig->readEntry("URL"));
01931
01932
01933 QString tmpenc=kconfig->readEntry("Encoding");
01934 if (!tmpenc.isEmpty() && (tmpenc != encoding()))
01935 setEncoding(tmpenc);
01936
01937
01938 if (!url.isEmpty() && url.isValid())
01939 openURL (url);
01940
01941
01942 m_buffer->setHighlight(KateHlManager::self()->nameFind(kconfig->readEntry("Highlighting")));
01943
01944 if (hlMode() > 0)
01945 hlSetByUser = true;
01946
01947
01948 config()->setIndentationMode( (uint)kconfig->readNumEntry("Indentation Mode", config()->indentationMode() ) );
01949
01950
01951 QValueList<int> marks = kconfig->readIntListEntry("Bookmarks");
01952 for( uint i = 0; i < marks.count(); i++ )
01953 addMark( marks[i], KateDocument::markType01 );
01954 }
01955
01956 void KateDocument::writeSessionConfig(KConfig *kconfig)
01957 {
01958 if ( m_url.isLocalFile() && !KGlobal::dirs()->relativeLocation("tmp", m_url.path()).startsWith("/"))
01959 return;
01960
01961 kconfig->writeEntry("URL", m_url.prettyURL() );
01962
01963
01964 kconfig->writeEntry("Encoding",encoding());
01965
01966
01967 kconfig->writeEntry("Highlighting", highlight()->name());
01968
01969 kconfig->writeEntry("Indentation Mode", config()->indentationMode() );
01970
01971
01972 QValueList<int> marks;
01973 for( QIntDictIterator<KTextEditor::Mark> it( m_marks );
01974 it.current() && it.current()->type & KTextEditor::MarkInterface::markType01;
01975 ++it )
01976 marks << it.current()->line;
01977
01978 kconfig->writeEntry( "Bookmarks", marks );
01979 }
01980
01981 void KateDocument::configDialog()
01982 {
01983 KDialogBase *kd = new KDialogBase ( KDialogBase::IconList,
01984 i18n("Configure"),
01985 KDialogBase::Ok | KDialogBase::Cancel | KDialogBase::Help,
01986 KDialogBase::Ok,
01987 kapp->mainWidget() );
01988
01989 #ifndef Q_WS_WIN //TODO: reenable
01990 KWin::setIcons( kd->winId(), kapp->icon(), kapp->miniIcon() );
01991 #endif
01992
01993 QPtrList<KTextEditor::ConfigPage> editorPages;
01994
01995 for (uint i = 0; i < KTextEditor::configInterfaceExtension (this)->configPages (); i++)
01996 {
01997 QStringList path;
01998 path.clear();
01999 path << KTextEditor::configInterfaceExtension (this)->configPageName (i);
02000 QVBox *page = kd->addVBoxPage(path, KTextEditor::configInterfaceExtension (this)->configPageFullName (i),
02001 KTextEditor::configInterfaceExtension (this)->configPagePixmap(i, KIcon::SizeMedium) );
02002
02003 editorPages.append (KTextEditor::configInterfaceExtension (this)->configPage(i, page));
02004 }
02005
02006 kd->resize(800, 480);
02007
02008 if (kd->exec())
02009 {
02010 KateDocumentConfig::global()->configStart ();
02011 KateViewConfig::global()->configStart ();
02012 KateRendererConfig::global()->configStart ();
02013
02014 for (uint i=0; i<editorPages.count(); i++)
02015 {
02016 editorPages.at(i)->apply();
02017 }
02018
02019 KateDocumentConfig::global()->configEnd ();
02020 KateViewConfig::global()->configEnd ();
02021 KateRendererConfig::global()->configEnd ();
02022
02023 writeConfig ();
02024 }
02025
02026 delete kd;
02027 }
02028
02029 uint KateDocument::mark( uint line )
02030 {
02031 if( !m_marks[line] )
02032 return 0;
02033 return m_marks[line]->type;
02034 }
02035
02036 void KateDocument::setMark( uint line, uint markType )
02037 {
02038 clearMark( line );
02039 addMark( line, markType );
02040 }
02041
02042 void KateDocument::clearMark( uint line )
02043 {
02044 if( line > lastLine() )
02045 return;
02046
02047 if( !m_marks[line] )
02048 return;
02049
02050 KTextEditor::Mark* mark = m_marks.take( line );
02051 emit markChanged( *mark, MarkRemoved );
02052 emit marksChanged();
02053 delete mark;
02054 tagLines( line, line );
02055 repaintViews(true);
02056 }
02057
02058 void KateDocument::addMark( uint line, uint markType )
02059 {
02060 if( line > lastLine())
02061 return;
02062
02063 if( markType == 0 )
02064 return;
02065
02066 if( m_marks[line] ) {
02067 KTextEditor::Mark* mark = m_marks[line];
02068
02069
02070 markType &= ~mark->type;
02071
02072 if( markType == 0 )
02073 return;
02074
02075
02076 mark->type |= markType;
02077 } else {
02078 KTextEditor::Mark *mark = new KTextEditor::Mark;
02079 mark->line = line;
02080 mark->type = markType;
02081 m_marks.insert( line, mark );
02082 }
02083
02084
02085 KTextEditor::Mark temp;
02086 temp.line = line;
02087 temp.type = markType;
02088 emit markChanged( temp, MarkAdded );
02089
02090 emit marksChanged();
02091 tagLines( line, line );
02092 repaintViews(true);
02093 }
02094
02095 void KateDocument::removeMark( uint line, uint markType )
02096 {
02097 if( line > lastLine() )
02098 return;
02099 if( !m_marks[line] )
02100 return;
02101
02102 KTextEditor::Mark* mark = m_marks[line];
02103
02104
02105 markType &= mark->type;
02106
02107 if( markType == 0 )
02108 return;
02109
02110
02111 mark->type &= ~markType;
02112
02113
02114 KTextEditor::Mark temp;
02115 temp.line = line;
02116 temp.type = markType;
02117 emit markChanged( temp, MarkRemoved );
02118
02119 if( mark->type == 0 )
02120 m_marks.remove( line );
02121
02122 emit marksChanged();
02123 tagLines( line, line );
02124 repaintViews(true);
02125 }
02126
02127 QPtrList<KTextEditor::Mark> KateDocument::marks()
02128 {
02129 QPtrList<KTextEditor::Mark> list;
02130
02131 for( QIntDictIterator<KTextEditor::Mark> it( m_marks );
02132 it.current(); ++it ) {
02133 list.append( it.current() );
02134 }
02135
02136 return list;
02137 }
02138
02139 void KateDocument::clearMarks()
02140 {
02141 for( QIntDictIterator<KTextEditor::Mark> it( m_marks );
02142 it.current(); ++it ) {
02143 KTextEditor::Mark* mark = it.current();
02144 emit markChanged( *mark, MarkRemoved );
02145 tagLines( mark->line, mark->line );
02146 }
02147
02148 m_marks.clear();
02149
02150 emit marksChanged();
02151 repaintViews(true);
02152 }
02153
02154 void KateDocument::setPixmap( MarkInterface::MarkTypes type, const QPixmap& pixmap )
02155 {
02156 m_markPixmaps.replace( type, new QPixmap( pixmap ) );
02157 }
02158
02159 void KateDocument::setDescription( MarkInterface::MarkTypes type, const QString& description )
02160 {
02161 m_markDescriptions.replace( type, new QString( description ) );
02162 }
02163
02164 QPixmap *KateDocument::markPixmap( MarkInterface::MarkTypes type )
02165 {
02166 return m_markPixmaps[type];
02167 }
02168
02169 QColor KateDocument::markColor( MarkInterface::MarkTypes type )
02170 {
02171 uint reserved = (0x1 << KTextEditor::MarkInterface::reservedMarkersCount()) - 1;
02172 if ((uint)type >= (uint)markType01 && (uint)type <= reserved) {
02173 return KateRendererConfig::global()->lineMarkerColor(type);
02174 } else {
02175 return QColor();
02176 }
02177 }
02178
02179 QString KateDocument::markDescription( MarkInterface::MarkTypes type )
02180 {
02181 if( m_markDescriptions[type] )
02182 return *m_markDescriptions[type];
02183 return QString::null;
02184 }
02185
02186 void KateDocument::setMarksUserChangable( uint markMask )
02187 {
02188 m_editableMarks = markMask;
02189 }
02190
02191 uint KateDocument::editableMarks()
02192 {
02193 return m_editableMarks;
02194 }
02195
02196
02197
02198 bool KateDocument::printDialog ()
02199 {
02200 return KatePrinter::print (this);
02201 }
02202
02203 bool KateDocument::print ()
02204 {
02205 return KatePrinter::print (this);
02206 }
02207
02208
02209
02210 QString KateDocument::mimeType()
02211 {
02212 KMimeType::Ptr result = KMimeType::defaultMimeTypePtr();
02213
02214
02215 if ( ! m_url.isEmpty() )
02216 result = KMimeType::findByURL( m_url );
02217
02218 else if ( m_url.isEmpty() || ! m_url.isLocalFile() )
02219 result = mimeTypeForContent();
02220
02221 return result->name();
02222 }
02223
02224
02225 long KateDocument::fileSize()
02226 {
02227 return 0;
02228 }
02229
02230
02231 QString KateDocument::niceFileSize()
02232 {
02233 return "UNKNOWN";
02234 }
02235
02236 KMimeType::Ptr KateDocument::mimeTypeForContent()
02237 {
02238 QByteArray buf (1024);
02239 uint bufpos = 0;
02240
02241 for (uint i=0; i < numLines(); i++)
02242 {
02243 QString line = textLine( i );
02244 uint len = line.length() + 1;
02245
02246 if (bufpos + len > 1024)
02247 len = 1024 - bufpos;
02248
02249 memcpy(&buf[bufpos], (line + "\n").latin1(), len);
02250
02251 bufpos += len;
02252
02253 if (bufpos >= 1024)
02254 break;
02255 }
02256 buf.resize( bufpos );
02257
02258 int accuracy = 0;
02259 return KMimeType::findByContent( buf, &accuracy );
02260 }
02261
02262
02263
02264
02265
02266 bool KateDocument::openURL( const KURL &url )
02267 {
02268
02269
02270 if ( !url.isValid() )
02271 return false;
02272
02273
02274 if ( !closeURL() )
02275 return false;
02276
02277
02278 m_url = url;
02279
02280 if ( m_url.isLocalFile() )
02281 {
02282
02283
02284 m_file = m_url.path();
02285
02286 emit started( 0 );
02287
02288 if (openFile())
02289 {
02290 emit completed();
02291 emit setWindowCaption( m_url.prettyURL() );
02292
02293 return true;
02294 }
02295
02296 return false;
02297 }
02298 else
02299 {
02300
02301
02302 m_bTemp = true;
02303
02304 m_tempFile = new KTempFile ();
02305 m_file = m_tempFile->name();
02306
02307 m_job = KIO::get ( url, false, isProgressInfoEnabled() );
02308
02309
02310 connect( m_job, SIGNAL( data( KIO::Job*, const QByteArray& ) ),
02311 SLOT( slotDataKate( KIO::Job*, const QByteArray& ) ) );
02312
02313 connect( m_job, SIGNAL( result( KIO::Job* ) ),
02314 SLOT( slotFinishedKate( KIO::Job* ) ) );
02315
02316 QWidget *w = widget ();
02317 if (!w && !m_views.isEmpty ())
02318 w = m_views.first();
02319
02320 if (w)
02321 m_job->setWindow (w->topLevelWidget());
02322
02323 emit started( m_job );
02324
02325 return true;
02326 }
02327 }
02328
02329 void KateDocument::slotDataKate ( KIO::Job *, const QByteArray &data )
02330 {
02331
02332
02333 if (!m_tempFile || !m_tempFile->file())
02334 return;
02335
02336 m_tempFile->file()->writeBlock (data);
02337 }
02338
02339 void KateDocument::slotFinishedKate ( KIO::Job * job )
02340 {
02341
02342
02343 if (!m_tempFile)
02344 return;
02345
02346 delete m_tempFile;
02347 m_tempFile = 0;
02348 m_job = 0;
02349
02350 if (job->error())
02351 emit canceled( job->errorString() );
02352 else
02353 {
02354 if ( openFile(job) )
02355 emit setWindowCaption( m_url.prettyURL() );
02356 emit completed();
02357 }
02358 }
02359
02360 void KateDocument::abortLoadKate()
02361 {
02362 if ( m_job )
02363 {
02364 kdDebug(13020) << "Aborting job " << m_job << endl;
02365 m_job->kill();
02366 m_job = 0;
02367 }
02368
02369 delete m_tempFile;
02370 m_tempFile = 0;
02371 }
02372
02373 bool KateDocument::openFile()
02374 {
02375 return openFile (0);
02376 }
02377
02378 bool KateDocument::openFile(KIO::Job * job)
02379 {
02380 m_loading = true;
02381
02382 activateDirWatch ();
02383
02384
02385
02386
02387 if (job)
02388 {
02389 QString metaDataCharset = job->queryMetaData("charset");
02390
02391
02392 if (!metaDataCharset.isEmpty () && (!m_config->isSetEncoding() || m_config->encoding().isEmpty()))
02393 setEncoding (metaDataCharset);
02394 }
02395
02396
02397
02398
02399 QString serviceType = m_extension->urlArgs().serviceType.simplifyWhiteSpace();
02400 int pos = serviceType.find(';');
02401 if (pos != -1)
02402 setEncoding (serviceType.mid(pos+1));
02403
02404
02405
02406 bool encodingSticky = m_encodingSticky;
02407 m_encodingSticky = m_config->isSetEncoding();
02408
02409
02410 int fileTypeFound = KateFactory::self()->fileTypeManager()->fileType (this);
02411 if ( fileTypeFound > -1 )
02412 updateFileType( fileTypeFound );
02413
02414
02415 bool success = m_buffer->openFile (m_file);
02416
02417
02418
02419 m_loading = false;
02420 if (success)
02421 {
02422
02423
02424
02425
02426
02427
02428 if (!hlSetByUser)
02429 {
02430 int hl (KateHlManager::self()->detectHighlighting (this));
02431
02432 if (hl >= 0)
02433 m_buffer->setHighlight(hl);
02434 }
02435
02436
02437 if ( fileTypeFound < 0 )
02438 updateFileType (KateFactory::self()->fileTypeManager()->fileType (this));
02439
02440
02441 readDirConfig ();
02442
02443
02444 readVariables();
02445
02446
02447 createDigest( m_digest );
02448 }
02449
02450
02451
02452
02453 for (KateView * view = m_views.first(); view != 0L; view = m_views.next() )
02454 {
02455 view->updateView(true);
02456 }
02457
02458
02459
02460
02461 emit fileNameChanged ();
02462
02463
02464
02465
02466 setDocName (QString::null);
02467
02468
02469
02470
02471 if (m_modOnHd)
02472 {
02473 m_modOnHd = false;
02474 m_modOnHdReason = 0;
02475 emit modifiedOnDisc (this, m_modOnHd, 0);
02476 }
02477
02478
02479
02480
02481 if (s_openErrorDialogsActivated)
02482 {
02483 if (!success && m_buffer->loadingBorked())
02484 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()));
02485 else if (!success)
02486 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()));
02487 }
02488
02489
02490 if (m_buffer->binary())
02491 {
02492
02493 setReadWrite( false );
02494
02495 KMessageBox::information (widget()
02496 , i18n ("The file %1 is a binary, saving it will result in a corrupt file.").arg(m_url.url())
02497 , i18n ("Binary File Opened")
02498 , "Binary File Opened Warning");
02499 }
02500
02501 m_encodingSticky = encodingSticky;
02502
02503
02504
02505
02506 return success;
02507 }
02508
02509 bool KateDocument::save()
02510 {
02511 bool l ( url().isLocalFile() );
02512
02513 if ( ( l && config()->backupFlags() & KateDocumentConfig::LocalFiles )
02514 || ( ! l && config()->backupFlags() & KateDocumentConfig::RemoteFiles ) )
02515 {
02516 KURL u( url() );
02517 u.setFileName( config()->backupPrefix() + url().fileName() + config()->backupSuffix() );
02518
02519 kdDebug () << "backup src file name: " << url() << endl;
02520 kdDebug () << "backup dst file name: " << u << endl;
02521
02522
02523 mode_t perms = 0600;
02524 KIO::UDSEntry fentry;
02525 if (KIO::NetAccess::stat (url(), fentry, kapp->mainWidget()))
02526 {
02527 kdDebug () << "stating succesfull: " << url() << endl;
02528 KFileItem item (fentry, url());
02529 perms = item.permissions();
02530 }
02531
02532
02533
02534 if ( (!KIO::NetAccess::exists( u, false, kapp->mainWidget() ) || KIO::NetAccess::del( u, kapp->mainWidget() ))
02535 && KIO::NetAccess::file_copy( url(), u, perms, true, false, kapp->mainWidget() ) )
02536 {
02537 kdDebug(13020)<<"backing up successfull ("<<url().prettyURL()<<" -> "<<u.prettyURL()<<")"<<endl;
02538 }
02539 else
02540 {
02541 kdDebug(13020)<<"backing up failed ("<<url().prettyURL()<<" -> "<<u.prettyURL()<<")"<<endl;
02542
02543 }
02544 }
02545
02546 return KParts::ReadWritePart::save();
02547 }
02548
02549 bool KateDocument::saveFile()
02550 {
02551
02552
02553
02554 if (m_buffer->loadingBorked() && (KMessageBox::warningContinueCancel(widget(),
02555 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))
02556 return false;
02557
02558
02559
02560
02561 if (m_buffer->binary() && (KMessageBox::warningContinueCancel (widget()
02562 , i18n ("The file %1 is a binary, saving it will result in a corrupt file.").arg(m_url.url())
02563 , i18n ("Trying to Save Binary File")
02564 , i18n("Save Nevertheless"), "Binary File Save Warning") != KMessageBox::Continue))
02565 return false;
02566
02567 if ( !url().isEmpty() )
02568 {
02569 if (s_fileChangedDialogsActivated && m_modOnHd)
02570 {
02571 QString str = reasonedMOHString() + "\n\n";
02572
02573 if (!isModified())
02574 {
02575 if (KMessageBox::warningContinueCancel(0,
02576 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)
02577 return false;
02578 }
02579 else
02580 {
02581 if (KMessageBox::warningContinueCancel(0,
02582 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)
02583 return false;
02584 }
02585 }
02586 }
02587
02588
02589
02590
02591 if (!m_buffer->canEncode ()
02592 && (KMessageBox::warningContinueCancel(0,
02593 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))
02594 {
02595 return false;
02596 }
02597
02598
02599 deactivateDirWatch ();
02600
02601
02602
02603
02604 bool success = m_buffer->saveFile (m_file);
02605
02606
02607 createDigest( m_digest );
02608
02609
02610 activateDirWatch ();
02611
02612
02613
02614
02615 if (success)
02616 {
02617
02618 if (!hlSetByUser)
02619 {
02620 int hl (KateHlManager::self()->detectHighlighting (this));
02621
02622 if (hl >= 0)
02623 m_buffer->setHighlight(hl);
02624 }
02625
02626
02627 readVariables();
02628 }
02629
02630
02631
02632
02633 if (success && m_modOnHd)
02634 {
02635 m_modOnHd = false;
02636 m_modOnHdReason = 0;
02637 emit modifiedOnDisc (this, m_modOnHd, 0);
02638 }
02639
02640
02641
02642
02643 if (!success)
02644 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()));
02645
02646
02647
02648
02649 return success;
02650 }
02651
02652 bool KateDocument::saveAs( const KURL &u )
02653 {
02654 QString oldDir = url().directory();
02655
02656 if ( KParts::ReadWritePart::saveAs( u ) )
02657 {
02658
02659 setDocName( QString::null );
02660
02661 if ( u.directory() != oldDir )
02662 readDirConfig();
02663
02664 emit fileNameChanged();
02665 emit nameChanged((Kate::Document *) this);
02666
02667 return true;
02668 }
02669
02670 return false;
02671 }
02672
02673 void KateDocument::readDirConfig ()
02674 {
02675 int depth = config()->searchDirConfigDepth ();
02676
02677 if (m_url.isLocalFile() && (depth > -1))
02678 {
02679 QString currentDir = QFileInfo (m_file).dirPath();
02680
02681
02682 while (depth > -1)
02683 {
02684 kdDebug (13020) << "search for config file in path: " << currentDir << endl;
02685
02686
02687 QFile f (currentDir + "/.kateconfig");
02688
02689 if (f.open (IO_ReadOnly))
02690 {
02691 QTextStream stream (&f);
02692
02693 uint linesRead = 0;
02694 QString line = stream.readLine();
02695 while ((linesRead < 32) && !line.isNull())
02696 {
02697 readVariableLine( line );
02698
02699 line = stream.readLine();
02700
02701 linesRead++;
02702 }
02703
02704 break;
02705 }
02706
02707 QString newDir = QFileInfo (currentDir).dirPath();
02708
02709
02710 if (currentDir == newDir)
02711 break;
02712
02713 currentDir = newDir;
02714 --depth;
02715 }
02716 }
02717 }
02718
02719 void KateDocument::activateDirWatch ()
02720 {
02721
02722 if (m_file == m_dirWatchFile)
02723 return;
02724
02725
02726 deactivateDirWatch ();
02727
02728
02729 if (m_url.isLocalFile() && !m_file.isEmpty())
02730 {
02731 KateFactory::self()->dirWatch ()->addFile (m_file);
02732 m_dirWatchFile = m_file;
02733 }
02734 }
02735
02736 void KateDocument::deactivateDirWatch ()
02737 {
02738 if (!m_dirWatchFile.isEmpty())
02739 KateFactory::self()->dirWatch ()->removeFile (m_dirWatchFile);
02740
02741 m_dirWatchFile = QString::null;
02742 }
02743
02744 bool KateDocument::closeURL()
02745 {
02746 abortLoadKate();
02747
02748
02749
02750
02751 if ( !m_reloading && !url().isEmpty() )
02752 {
02753 if (s_fileChangedDialogsActivated && m_modOnHd)
02754 {
02755 if (!(KMessageBox::warningContinueCancel(
02756 widget(),
02757 reasonedMOHString() + "\n\n" + i18n("Do you really want to continue to close this file? Data loss may occur."),
02758 i18n("Possible Data Loss"), i18n("Close Nevertheless"),
02759 QString("kate_close_modonhd_%1").arg( m_modOnHdReason ) ) == KMessageBox::Continue))
02760 return false;
02761 }
02762 }
02763
02764
02765
02766
02767 if (!KParts::ReadWritePart::closeURL ())
02768 return false;
02769
02770
02771 deactivateDirWatch ();
02772
02773
02774
02775
02776 m_url = KURL ();
02777 m_file = QString::null;
02778
02779
02780 if (m_modOnHd)
02781 {
02782 m_modOnHd = false;
02783 m_modOnHdReason = 0;
02784 emit modifiedOnDisc (this, m_modOnHd, 0);
02785 }
02786
02787
02788 m_buffer->clear();
02789
02790
02791 clearMarks ();
02792
02793
02794 clearUndo();
02795 clearRedo();
02796
02797
02798 setModified(false);
02799
02800
02801 m_buffer->setHighlight(0);
02802
02803
02804 for (KateView * view = m_views.first(); view != 0L; view = m_views.next() )
02805 {
02806
02807
02808 view->setCursorPositionInternal(0, 0, 1, false);
02809 view->clearSelection();
02810 view->updateView(true);
02811 }
02812
02813
02814 emit fileNameChanged ();
02815
02816
02817 setDocName (QString::null);
02818
02819
02820 return true;
02821 }
02822
02823 void KateDocument::setReadWrite( bool rw )
02824 {
02825 if (isReadWrite() != rw)
02826 {
02827 KParts::ReadWritePart::setReadWrite (rw);
02828
02829 for( KateView* view = m_views.first(); view != 0L; view = m_views.next() )
02830 {
02831 view->slotUpdate();
02832 view->slotReadWriteChanged ();
02833 }
02834 }
02835 }
02836
02837 void KateDocument::setModified(bool m) {
02838
02839 if (isModified() != m) {
02840 KParts::ReadWritePart::setModified (m);
02841
02842 for( KateView* view = m_views.first(); view != 0L; view = m_views.next() )
02843 {
02844 view->slotUpdate();
02845 }
02846
02847 emit modifiedChanged ();
02848 emit modStateChanged ((Kate::Document *)this);
02849 }
02850 if ( m == false )
02851 {
02852 if ( ! undoItems.isEmpty() )
02853 {
02854 lastUndoGroupWhenSaved = undoItems.last();
02855 }
02856
02857 if ( ! redoItems.isEmpty() )
02858 {
02859 lastRedoGroupWhenSaved = redoItems.last();
02860 }
02861
02862 docWasSavedWhenUndoWasEmpty = undoItems.isEmpty();
02863 docWasSavedWhenRedoWasEmpty = redoItems.isEmpty();
02864 }
02865 }
02866
02867
02868
02869
02870 void KateDocument::makeAttribs(bool needInvalidate)
02871 {
02872 for (uint z = 0; z < m_views.count(); z++)
02873 m_views.at(z)->renderer()->updateAttributes ();
02874
02875 if (needInvalidate)
02876 m_buffer->invalidateHighlighting();
02877
02878 tagAll ();
02879 }
02880
02881
02882 void KateDocument::internalHlChanged()
02883 {
02884 makeAttribs();
02885 }
02886
02887 void KateDocument::addView(KTextEditor::View *view) {
02888 if (!view)
02889 return;
02890
02891 m_views.append( (KateView *) view );
02892 m_textEditViews.append( view );
02893
02894
02895 const KateFileType *t = 0;
02896 if ((m_fileType > -1) && (t = KateFactory::self()->fileTypeManager()->fileType(m_fileType)))
02897 readVariableLine (t->varLine, true);
02898
02899
02900 readVariables (true);
02901
02902 m_activeView = (KateView *) view;
02903 }
02904
02905 void KateDocument::removeView(KTextEditor::View *view) {
02906 if (!view)
02907 return;
02908
02909 if (m_activeView == view)
02910 m_activeView = 0L;
02911
02912 m_views.removeRef( (KateView *) view );
02913 m_textEditViews.removeRef( view );
02914 }
02915
02916 void KateDocument::addSuperCursor(KateSuperCursor *cursor, bool privateC) {
02917 if (!cursor)
02918 return;
02919
02920 m_superCursors.append( cursor );
02921
02922 if (!privateC)
02923 myCursors.append( cursor );
02924 }
02925
02926 void KateDocument::removeSuperCursor(KateSuperCursor *cursor, bool privateC) {
02927 if (!cursor)
02928 return;
02929
02930 if (!privateC)
02931 myCursors.removeRef( cursor );
02932
02933 m_superCursors.removeRef( cursor );
02934 }
02935
02936 bool KateDocument::ownedView(KateView *view) {
02937
02938 return (m_views.containsRef(view) > 0);
02939 }
02940
02941 bool KateDocument::isLastView(int numViews) {
02942 return ((int) m_views.count() == numViews);
02943 }
02944
02945 uint KateDocument::currentColumn( const KateTextCursor& cursor )
02946 {
02947 KateTextLine::Ptr textLine = m_buffer->plainLine(cursor.line());
02948
02949 if (textLine)
02950 return textLine->cursorX(cursor.col(), config()->tabWidth());
02951 else
02952 return 0;
02953 }
02954
02955 bool KateDocument::typeChars ( KateView *view, const QString &chars )
02956 {
02957 KateTextLine::Ptr textLine = m_buffer->plainLine(view->cursorLine ());
02958
02959 if (!textLine)
02960 return false;
02961
02962 bool bracketInserted = false;
02963 QString buf;
02964 QChar c;
02965
02966 for( uint z = 0; z < chars.length(); z++ )
02967 {
02968 QChar ch = c = chars[z];
02969 if (ch.isPrint() || ch == '\t')
02970 {
02971 buf.append (ch);
02972
02973 if (!bracketInserted && (config()->configFlags() & KateDocument::cfAutoBrackets))
02974 {
02975 QChar end_ch;
02976 bool complete = true;
02977 QChar prevChar = textLine->getChar(view->cursorColumnReal()-1);
02978 QChar nextChar = textLine->getChar(view->cursorColumnReal());
02979 switch(ch) {
02980 case '(': end_ch = ')'; break;
02981 case '[': end_ch = ']'; break;
02982 case '{': end_ch = '}'; break;
02983 case '\'':end_ch = '\'';break;
02984 case '"': end_ch = '"'; break;
02985 default: complete = false;
02986 }
02987 if (complete)
02988 {
02989 if (view->hasSelection())
02990 {
02991 buf.append (view->selection());
02992 buf.append (end_ch);
02993 bracketInserted = true;
02994 }
02995 else
02996 {
02997 if ( ( (ch == '\'' || ch == '"') &&
02998 (prevChar.isLetterOrNumber() || prevChar == ch) )
02999 || nextChar.isLetterOrNumber()
03000 || (nextChar == end_ch && prevChar != ch) )
03001 {
03002 kdDebug(13020) << "AutoBracket refused before: " << nextChar << "\n";
03003 }
03004 else
03005 {
03006 buf.append (end_ch);
03007 bracketInserted = true;
03008 }
03009 }
03010 }
03011 }
03012 }
03013 }
03014
03015 if (buf.isEmpty())
03016 return false;
03017
03018 editStart ();
03019
03020 if (!view->config()->persistentSelection() && view->hasSelection() )
03021 view->removeSelectedText();
03022
03023 int oldLine = view->cursorLine ();
03024 int oldCol = view->cursorColumnReal ();
03025
03026
03027 if (config()->configFlags() & KateDocument::cfOvr)
03028 removeText (view->cursorLine(), view->cursorColumnReal(), view->cursorLine(), kMin( view->cursorColumnReal()+buf.length(), textLine->length() ) );
03029
03030 insertText (view->cursorLine(), view->cursorColumnReal(), buf);
03031 m_indenter->processChar(c);
03032
03033 editEnd ();
03034
03035 if (bracketInserted)
03036 view->setCursorPositionInternal (view->cursorLine(), view->cursorColumnReal()-1);
03037
03038 emit charactersInteractivelyInserted (oldLine, oldCol, chars);
03039
03040 return true;
03041 }
03042
03043 void KateDocument::newLine( KateTextCursor& c, KateViewInternal *v )
03044 {
03045 editStart();
03046
03047 if( !v->view()->config()->persistentSelection() && v->view()->hasSelection() )
03048 v->view()->removeSelectedText();
03049
03050
03051 c = v->getCursor ();
03052
03053 if (c.line() > (int)lastLine())
03054 c.setLine(lastLine());
03055
03056 if ( c.line() < 0 )
03057 c.setLine( 0 );
03058
03059 uint ln = c.line();
03060
03061 KateTextLine::Ptr textLine = kateTextLine(c.line());
03062
03063 if (c.col() > (int)textLine->length())
03064 c.setCol(textLine->length());
03065
03066 if (m_indenter->canProcessNewLine ())
03067 {
03068 int pos = textLine->firstChar();
03069
03070
03071 if (pos < 0)
03072 pos = textLine->length();
03073
03074 if (c.col() < pos)
03075 c.setCol(pos);
03076
03077 editWrapLine (c.line(), c.col());
03078
03079 KateDocCursor cursor (c.line() + 1, pos, this);
03080 m_indenter->processNewline(cursor, true);
03081
03082 c.setPos(cursor);
03083 }
03084 else
03085 {
03086 editWrapLine (c.line(), c.col());
03087 c.setPos(c.line() + 1, 0);
03088 }
03089
03090 removeTrailingSpace( ln );
03091
03092 editEnd();
03093 }
03094
03095 void KateDocument::transpose( const KateTextCursor& cursor)
03096 {
03097 KateTextLine::Ptr textLine = m_buffer->plainLine(cursor.line());
03098
03099 if (!textLine || (textLine->length() < 2))
03100 return;
03101
03102 uint col = cursor.col();
03103
03104 if (col > 0)
03105 col--;
03106
03107 if ((textLine->length() - col) < 2)
03108 return;
03109
03110 uint line = cursor.line();
03111 QString s;
03112
03113
03114
03115 s.append (textLine->getChar(col+1));
03116 s.append (textLine->getChar(col));
03117
03118
03119
03120 editStart ();
03121 editRemoveText (line, col, 2);
03122 editInsertText (line, col, s);
03123 editEnd ();
03124 }
03125
03126 void KateDocument::backspace( KateView *view, const KateTextCursor& c )
03127 {
03128 if ( !view->config()->persistentSelection() && view->hasSelection() ) {
03129 view->removeSelectedText();
03130 return;
03131 }
03132
03133 uint col = kMax( c.col(), 0 );
03134 uint line = kMax( c.line(), 0 );
03135
03136 if ((col == 0) && (line == 0))
03137 return;
03138
03139 int complement = 0;
03140 if (col > 0)
03141 {
03142 if (config()->configFlags() & KateDocument::cfAutoBrackets)
03143 {
03144
03145 KateTextLine::Ptr tl = m_buffer->plainLine(line);
03146 if(!tl) return;
03147 QChar prevChar = tl->getChar(col-1);
03148 QChar nextChar = tl->getChar(col);
03149
03150 if ( (prevChar == '"' && nextChar == '"') ||
03151 (prevChar == '\'' && nextChar == '\'') ||
03152 (prevChar == '(' && nextChar == ')') ||
03153 (prevChar == '[' && nextChar == ']') ||
03154 (prevChar == '{' && nextChar == '}') )
03155 {
03156 complement = 1;
03157 }
03158 }
03159 if (!(config()->configFlags() & KateDocument::cfBackspaceIndents))
03160 {
03161
03162
03163 removeText(line, col-1, line, col+complement);
03164 }
03165 else
03166 {
03167
03168 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
03169
03170
03171 if (!textLine)
03172 return;
03173
03174 int colX = textLine->cursorX(col, config()->tabWidth());
03175 int pos = textLine->firstChar();
03176 if (pos > 0)
03177 pos = textLine->cursorX(pos, config()->tabWidth());
03178
03179 if (pos < 0 || pos >= (int)colX)
03180 {
03181
03182 indent( view, line, -1);
03183 }
03184 else
03185 removeText(line, col-1, line, col+complement);
03186 }
03187 }
03188 else
03189 {
03190
03191 if (line >= 1)
03192 {
03193 KateTextLine::Ptr textLine = m_buffer->plainLine(line-1);
03194
03195
03196 if (!textLine)
03197 return;
03198
03199 if (config()->wordWrap() && textLine->endingWith(QString::fromLatin1(" ")))
03200 {
03201
03202 removeText (line-1, textLine->length()-1, line, 0);
03203 }
03204 else
03205 removeText (line-1, textLine->length(), line, 0);
03206 }
03207 }
03208
03209 emit backspacePressed();
03210 }
03211
03212 void KateDocument::del( KateView *view, const KateTextCursor& c )
03213 {
03214 if ( !view->config()->persistentSelection() && view->hasSelection() ) {
03215 view->removeSelectedText();
03216 return;
03217 }
03218
03219 if( c.col() < (int) m_buffer->plainLine(c.line())->length())
03220 {
03221 removeText(c.line(), c.col(), c.line(), c.col()+1);
03222 }
03223 else if ( (uint)c.line() < lastLine() )
03224 {
03225 removeText(c.line(), c.col(), c.line()+1, 0);
03226 }
03227 }
03228
03229 void KateDocument::paste ( KateView* view )
03230 {
03231 QString s = QApplication::clipboard()->text();
03232
03233 if (s.isEmpty())
03234 return;
03235
03236 uint lines = s.contains (QChar ('\n'));
03237
03238 m_undoDontMerge = true;
03239
03240 editStart ();
03241
03242 if (!view->config()->persistentSelection() && view->hasSelection() )
03243 view->removeSelectedText();
03244
03245 uint line = view->cursorLine ();
03246 uint column = view->cursorColumnReal ();
03247
03248 insertText ( line, column, s, view->blockSelectionMode() );
03249
03250 editEnd();
03251
03252
03253
03254
03255 if (view->blockSelectionMode())
03256 view->setCursorPositionInternal (line+lines, column);
03257
03258 if (m_indenter->canProcessLine()
03259 && config()->configFlags() & KateDocumentConfig::cfIndentPastedText)
03260 {
03261 editStart();
03262
03263 KateDocCursor begin(line, 0, this);
03264 KateDocCursor end(line + lines, 0, this);
03265
03266 m_indenter->processSection (begin, end);
03267
03268 editEnd();
03269 }
03270
03271 if (!view->blockSelectionMode()) emit charactersSemiInteractivelyInserted (line, column, s);
03272 m_undoDontMerge = true;
03273 }
03274
03275 void KateDocument::insertIndentChars ( KateView *view )
03276 {
03277 editStart ();
03278
03279 QString s;
03280 if (config()->configFlags() & KateDocument::cfSpaceIndent)
03281 {
03282 int width = config()->indentationWidth();
03283 s.fill (' ', width - (view->cursorColumnReal() % width));
03284 }
03285 else
03286 s.append ('\t');
03287
03288 insertText (view->cursorLine(), view->cursorColumnReal(), s);
03289
03290 editEnd ();
03291 }
03292
03293 void KateDocument::indent ( KateView *v, uint line, int change)
03294 {
03295 editStart ();
03296
03297 if (!hasSelection())
03298 {
03299
03300 optimizeLeadingSpace(line, config()->configFlags(), change);
03301 }
03302 else
03303 {
03304 int sl = v->selStartLine();
03305 int el = v->selEndLine();
03306 int ec = v->selEndCol();
03307
03308 if ((ec == 0) && ((el-1) >= 0))
03309 {
03310 el--;
03311 }
03312
03313 if (config()->configFlags() & KateDocument::cfKeepIndentProfile && change < 0) {
03314
03315
03316 int adjustedChange = -change;
03317
03318 for (line = sl; (int) line <= el && adjustedChange > 0; line++) {
03319 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
03320 int firstChar = textLine->firstChar();
03321 if (firstChar >= 0 && (v->lineSelected(line) || v->lineHasSelected(line))) {
03322 int maxUnindent = textLine->cursorX(firstChar, config()->tabWidth()) / config()->indentationWidth();
03323 if (maxUnindent < adjustedChange)
03324 adjustedChange = maxUnindent;
03325 }
03326 }
03327
03328 change = -adjustedChange;
03329 }
03330
03331 const bool rts = config()->configFlags() & KateDocumentConfig::cfRemoveTrailingDyn;
03332 for (line = sl; (int) line <= el; line++) {
03333 if ((v->lineSelected(line) || v->lineHasSelected(line))
03334 && (!rts || lineLength(line) > 0)) {
03335 optimizeLeadingSpace(line, config()->configFlags(), change);
03336 }
03337 }
03338 }
03339
03340 editEnd ();
03341 }
03342
03343 void KateDocument::align(KateView *view, uint line)
03344 {
03345 if (m_indenter->canProcessLine())
03346 {
03347 editStart ();
03348
03349 if (!view->hasSelection())
03350 {
03351 KateDocCursor curLine(line, 0, this);
03352 m_indenter->processLine (curLine);
03353 editEnd ();
03354 activeView()->setCursorPosition (line, curLine.col());
03355 }
03356 else
03357 {
03358 m_indenter->processSection (view->selStart(), view->selEnd());
03359 editEnd ();
03360 }
03361 }
03362 }
03363
03364
03365
03366
03367
03368
03369
03370
03371
03372
03373 void KateDocument::optimizeLeadingSpace(uint line, int flags, int change)
03374 {
03375 KateTextLine::Ptr textline = m_buffer->plainLine(line);
03376
03377 int first_char = textline->firstChar();
03378
03379 int w = 0;
03380 if (flags & KateDocument::cfSpaceIndent)
03381 w = config()->indentationWidth();
03382 else
03383 w = config()->tabWidth();
03384
03385 if (first_char < 0)
03386 first_char = textline->length();
03387
03388 int space = textline->cursorX(first_char, config()->tabWidth()) + change * w;
03389 if (space < 0)
03390 space = 0;
03391
03392 if (!(flags & KateDocument::cfKeepExtraSpaces))
03393 {
03394 uint extra = space % w;
03395
03396 space -= extra;
03397 if (extra && change < 0) {
03398
03399 space += w;
03400 }
03401 }
03402
03403
03404 replaceWithOptimizedSpace(line, first_char, space, flags);
03405 }
03406
03407 void KateDocument::replaceWithOptimizedSpace(uint line, uint upto_column, uint space, int flags)
03408 {
03409 uint length;
03410 QString new_space;
03411
03412 if (flags & KateDocument::cfSpaceIndent && ! (flags & KateDocumentConfig::cfMixedIndent) ) {
03413 length = space;
03414 new_space.fill(' ', length);
03415 }
03416 else {
03417 length = space / config()->tabWidth();
03418 new_space.fill('\t', length);
03419
03420 QString extra_space;
03421 extra_space.fill(' ', space % config()->tabWidth());
03422 length += space % config()->tabWidth();
03423 new_space += extra_space;
03424 }
03425
03426 KateTextLine::Ptr textline = m_buffer->plainLine(line);
03427 uint change_from;
03428 for (change_from = 0; change_from < upto_column && change_from < length; change_from++) {
03429 if (textline->getChar(change_from) != new_space[change_from])
03430 break;
03431 }
03432
03433 editStart();
03434
03435 if (change_from < upto_column)
03436 removeText(line, change_from, line, upto_column);
03437
03438 if (change_from < length)
03439 insertText(line, change_from, new_space.right(length - change_from));
03440
03441 editEnd();
03442 }
03443
03444
03445
03446
03447
03448 bool KateDocument::removeStringFromBegining(int line, QString &str)
03449 {
03450 KateTextLine::Ptr textline = m_buffer->plainLine(line);
03451
03452 int index = 0;
03453 bool there = false;
03454
03455 if (textline->startingWith(str))
03456 there = true;
03457 else
03458 {
03459 index = textline->firstChar ();
03460
03461 if ((index >= 0) && (textline->length() >= (index + str.length())) && (textline->string(index, str.length()) == str))
03462 there = true;
03463 }
03464
03465 if (there)
03466 {
03467
03468 removeText (line, index, line, index+str.length());
03469 }
03470
03471 return there;
03472 }
03473
03474
03475
03476
03477
03478 bool KateDocument::removeStringFromEnd(int line, QString &str)
03479 {
03480 KateTextLine::Ptr textline = m_buffer->plainLine(line);
03481
03482 int index = 0;
03483 bool there = false;
03484
03485 if(textline->endingWith(str))
03486 {
03487 index = textline->length() - str.length();
03488 there = true;
03489 }
03490 else
03491 {
03492 index = textline->lastChar ()-str.length()+1;
03493
03494 if ((index >= 0) && (textline->length() >= (index + str.length())) && (textline->string(index, str.length()) == str))
03495 there = true;
03496 }
03497
03498 if (there)
03499 {
03500
03501 removeText (line, index, line, index+str.length());
03502 }
03503
03504 return there;
03505 }
03506
03507
03508
03509
03510
03511 void KateDocument::addStartLineCommentToSingleLine( int line, int attrib )
03512 {
03513 if (highlight()->getCommentSingleLinePosition(attrib)==KateHighlighting::CSLPosColumn0)
03514 {
03515 QString commentLineMark = highlight()->getCommentSingleLineStart( attrib ) + " ";
03516 insertText (line, 0, commentLineMark);
03517 }
03518 else
03519 {
03520 QString commentLineMark=highlight()->getCommentSingleLineStart(attrib);
03521 KateTextLine::Ptr l = m_buffer->line(line);
03522 int pos=l->firstChar();
03523 if (pos >=0)
03524 insertText(line,pos,commentLineMark);
03525 }
03526 }
03527
03528
03529
03530
03531
03532 bool KateDocument::removeStartLineCommentFromSingleLine( int line, int attrib )
03533 {
03534 QString shortCommentMark = highlight()->getCommentSingleLineStart( attrib );
03535 QString longCommentMark = shortCommentMark + " ";
03536
03537 editStart();
03538
03539
03540 bool removed = (removeStringFromBegining(line, longCommentMark)
03541 || removeStringFromBegining(line, shortCommentMark));
03542
03543 editEnd();
03544
03545 return removed;
03546 }
03547
03548
03549
03550
03551
03552 void KateDocument::addStartStopCommentToSingleLine( int line, int attrib )
03553 {
03554 QString startCommentMark = highlight()->getCommentStart( attrib ) + " ";
03555 QString stopCommentMark = " " + highlight()->getCommentEnd( attrib );
03556
03557 editStart();
03558
03559
03560 insertText (line, 0, startCommentMark);
03561
03562
03563 int col = m_buffer->plainLine(line)->length();
03564
03565
03566 insertText (line, col, stopCommentMark);
03567
03568 editEnd();
03569 }
03570
03571
03572
03573
03574
03575 bool KateDocument::removeStartStopCommentFromSingleLine( int line, int attrib )
03576 {
03577 QString shortStartCommentMark = highlight()->getCommentStart( attrib );
03578 QString longStartCommentMark = shortStartCommentMark + " ";
03579 QString shortStopCommentMark = highlight()->getCommentEnd( attrib );
03580 QString longStopCommentMark = " " + shortStopCommentMark;
03581
03582 editStart();
03583
03584 #ifdef __GNUC__
03585 #warning "that's a bad idea, can lead to stray endings, FIXME"
03586 #endif
03587
03588 bool removedStart = (removeStringFromBegining(line, longStartCommentMark)
03589 || removeStringFromBegining(line, shortStartCommentMark));
03590
03591 bool removedStop = false;
03592 if (removedStart)
03593 {
03594
03595 removedStop = (removeStringFromEnd(line, longStopCommentMark)
03596 || removeStringFromEnd(line, shortStopCommentMark));
03597 }
03598
03599 editEnd();
03600
03601 return (removedStart || removedStop);
03602 }
03603
03604
03605
03606
03607
03608
03609 void KateDocument::addStartStopCommentToSelection( KateView *view, int attrib )
03610 {
03611 QString startComment = highlight()->getCommentStart( attrib );
03612 QString endComment = highlight()->getCommentEnd( attrib );
03613
03614 int sl = view->selStartLine();
03615 int el = view->selEndLine();
03616 int sc = view->selStartCol();
03617 int ec = view->selEndCol();
03618
03619 if ((ec == 0) && ((el-1) >= 0))
03620 {
03621 el--;
03622 ec = m_buffer->plainLine (el)->length();
03623 }
03624
03625 editStart();
03626
03627 insertText (el, ec, endComment);
03628 insertText (sl, sc, startComment);
03629
03630 editEnd ();
03631
03632
03633 ec += endComment.length() + ( (el == sl) ? startComment.length() : 0 );
03634 view->setSelection(sl, sc, el, ec);
03635 }
03636
03637
03638
03639
03640
03641 void KateDocument::addStartLineCommentToSelection( KateView *view, int attrib )
03642 {
03643 QString commentLineMark = highlight()->getCommentSingleLineStart( attrib ) + " ";
03644
03645 int sl = view->selStartLine();
03646 int el = view->selEndLine();
03647
03648 if ((view->selEndCol() == 0) && ((el-1) >= 0))
03649 {
03650 el--;
03651 }
03652
03653 editStart();
03654
03655
03656 for (int z = el; z >= sl; z--) {
03657
03658 addStartLineCommentToSingleLine(z, attrib );
03659 }
03660
03661 editEnd ();
03662
03663
03664
03665 KateDocCursor end (view->selEnd());
03666 end.setCol(view->selEndCol() + ((el == view->selEndLine()) ? commentLineMark.length() : 0) );
03667
03668 view->setSelection(view->selStartLine(), 0, end.line(), end.col());
03669 }
03670
03671 bool KateDocument::nextNonSpaceCharPos(int &line, int &col)
03672 {
03673 for(; line < (int)m_buffer->count(); line++) {
03674 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
03675
03676 if (!textLine)
03677 break;
03678
03679 col = textLine->nextNonSpaceChar(col);
03680 if(col != -1)
03681 return true;
03682 col = 0;
03683 }
03684
03685 line = -1;
03686 col = -1;
03687 return false;
03688 }
03689
03690 bool KateDocument::previousNonSpaceCharPos(int &line, int &col)
03691 {
03692 while(true)
03693 {
03694 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
03695
03696 if (!textLine)
03697 break;
03698
03699 col = textLine->previousNonSpaceChar(col);
03700 if(col != -1) return true;
03701 if(line == 0) return false;
03702 --line;
03703 col = textLine->length();
03704 }
03705
03706 line = -1;
03707 col = -1;
03708 return false;
03709 }
03710
03711
03712
03713
03714
03715 bool KateDocument::removeStartStopCommentFromSelection( KateView *view, int attrib )
03716 {
03717 QString startComment = highlight()->getCommentStart( attrib );
03718 QString endComment = highlight()->getCommentEnd( attrib );
03719
03720 int sl = kMax<int> (0, view->selStartLine());
03721 int el = kMin<int> (view->selEndLine(), lastLine());
03722 int sc = view->selStartCol();
03723 int ec = view->selEndCol();
03724
03725
03726 if (ec != 0) {
03727 ec--;
03728 } else {
03729 if (el > 0) {
03730 el--;
03731 ec = m_buffer->plainLine(el)->length() - 1;
03732 }
03733 }
03734
03735 int startCommentLen = startComment.length();
03736 int endCommentLen = endComment.length();
03737
03738
03739
03740 bool remove = nextNonSpaceCharPos(sl, sc)
03741 && m_buffer->plainLine(sl)->stringAtPos(sc, startComment)
03742 && previousNonSpaceCharPos(el, ec)
03743 && ( (ec - endCommentLen + 1) >= 0 )
03744 && m_buffer->plainLine(el)->stringAtPos(ec - endCommentLen + 1, endComment);
03745
03746 if (remove) {
03747 editStart();
03748
03749 removeText (el, ec - endCommentLen + 1, el, ec + 1);
03750 removeText (sl, sc, sl, sc + startCommentLen);
03751
03752 editEnd ();
03753
03754 }
03755
03756 return remove;
03757 }
03758
03759 bool KateDocument::removeStartStopCommentFromRegion(const KateTextCursor &start,const KateTextCursor &end,int attrib)
03760 {
03761 QString startComment = highlight()->getCommentStart( attrib );
03762 QString endComment = highlight()->getCommentEnd( attrib );
03763 int startCommentLen = startComment.length();
03764 int endCommentLen = endComment.length();
03765
03766 bool remove = m_buffer->plainLine(start.line())->stringAtPos(start.col(), startComment)
03767 && ( (end.col() - endCommentLen ) >= 0 )
03768 && m_buffer->plainLine(end.line())->stringAtPos(end.col() - endCommentLen , endComment);
03769 if (remove) {
03770 editStart();
03771 removeText(end.line(),end.col()-endCommentLen,end.line(),end.col());
03772 removeText(start.line(),start.col(),start.line(),start.col()+startCommentLen);
03773 editEnd();
03774 }
03775 return remove;
03776 }
03777
03778
03779
03780
03781
03782 bool KateDocument::removeStartLineCommentFromSelection( KateView *view, int attrib )
03783 {
03784 QString shortCommentMark = highlight()->getCommentSingleLineStart( attrib );
03785 QString longCommentMark = shortCommentMark + " ";
03786
03787 int sl = view->selStartLine();
03788 int el = view->selEndLine();
03789
03790 if ((view->selEndCol() == 0) && ((el-1) >= 0))
03791 {
03792 el--;
03793 }
03794
03795
03796 int removeLength = 0;
03797 if (m_buffer->plainLine(el)->startingWith(longCommentMark))
03798 removeLength = longCommentMark.length();
03799 else if (m_buffer->plainLine(el)->startingWith(shortCommentMark))
03800 removeLength = shortCommentMark.length();
03801
03802 bool removed = false;
03803
03804 editStart();
03805
03806
03807 for (int z = el; z >= sl; z--)
03808 {
03809
03810 removed = (removeStringFromBegining(z, longCommentMark)
03811 || removeStringFromBegining(z, shortCommentMark)
03812 || removed);
03813 }
03814
03815 editEnd();
03816
03817 return removed;
03818 }
03819
03820
03821
03822
03823
03824 void KateDocument::comment( KateView *v, uint line,uint column, int change)
03825 {
03826
03827
03828
03829
03830 bool hassel = v->hasSelection();
03831 int startAttrib, endAttrib;
03832 if ( hassel )
03833 {
03834 KateTextLine::Ptr ln = kateTextLine( v->selStartLine() );
03835 int l = v->selStartLine(), c = v->selStartCol();
03836 startAttrib = nextNonSpaceCharPos( l, c ) ? kateTextLine( l )->attribute( c ) : 0;
03837
03838 ln = kateTextLine( v->selEndLine() );
03839 l = v->selEndLine(), c = v->selEndCol();
03840 endAttrib = previousNonSpaceCharPos( l, c ) ? kateTextLine( l )->attribute( c ) : 0;
03841 }
03842 else
03843 {
03844 KateTextLine::Ptr ln = kateTextLine( line );
03845 if ( ln->length() )
03846 {
03847 startAttrib = ln->attribute( ln->firstChar() );
03848 endAttrib = ln->attribute( ln->lastChar() );
03849 }
03850 else
03851 {
03852 int l = line, c = 0;
03853 if ( nextNonSpaceCharPos( l, c ) || previousNonSpaceCharPos( l, c ) )
03854 startAttrib = endAttrib = kateTextLine( l )->attribute( c );
03855 else
03856 startAttrib = endAttrib = 0;
03857 }
03858 }
03859
03860 if ( ! highlight()->canComment( startAttrib, endAttrib ) )
03861 {
03862 kdDebug(13020)<<"canComment( "<<startAttrib<<", "<<endAttrib<<" ) returned false!"<<endl;
03863 return;
03864 }
03865
03866 bool hasStartLineCommentMark = !(highlight()->getCommentSingleLineStart( startAttrib ).isEmpty());
03867 bool hasStartStopCommentMark = ( !(highlight()->getCommentStart( startAttrib ).isEmpty())
03868 && !(highlight()->getCommentEnd( endAttrib ).isEmpty()) );
03869
03870 bool removed = false;
03871
03872 if (change > 0)
03873 {
03874 if ( !hassel )
03875 {
03876 if ( hasStartLineCommentMark )
03877 addStartLineCommentToSingleLine( line, startAttrib );
03878 else if ( hasStartStopCommentMark )
03879 addStartStopCommentToSingleLine( line, startAttrib );
03880 }
03881 else
03882 {
03883
03884
03885
03886
03887
03888
03889
03890 if ( hasStartStopCommentMark &&
03891 ( !hasStartLineCommentMark || (
03892 ( v->selStartCol() > m_buffer->plainLine( v->selStartLine() )->firstChar() ) ||
03893 ( v->selEndCol() < ((int)m_buffer->plainLine( v->selEndLine() )->length()) )
03894 ) ) )
03895 addStartStopCommentToSelection( v, startAttrib );
03896 else if ( hasStartLineCommentMark )
03897 addStartLineCommentToSelection( v, startAttrib );
03898 }
03899 }
03900 else
03901 {
03902 if ( !hassel )
03903 {
03904 removed = ( hasStartLineCommentMark
03905 && removeStartLineCommentFromSingleLine( line, startAttrib ) )
03906 || ( hasStartStopCommentMark
03907 && removeStartStopCommentFromSingleLine( line, startAttrib ) );
03908 if ((!removed) && foldingTree()) {
03909 kdDebug(13020)<<"easy approach for uncommenting did not work, trying harder (folding tree)"<<endl;
03910 int commentRegion=(highlight()->commentRegion(startAttrib));
03911 if (commentRegion){
03912 KateCodeFoldingNode *n=foldingTree()->findNodeForPosition(line,column);
03913 if (n) {
03914 KateTextCursor start,end;
03915 if ((n->nodeType()==commentRegion) && n->getBegin(foldingTree(), &start) && n->getEnd(foldingTree(), &end)) {
03916 kdDebug(13020)<<"Enclosing region found:"<<start.col()<<"/"<<start.line()<<"-"<<end.col()<<"/"<<end.line()<<endl;
03917 removeStartStopCommentFromRegion(start,end,startAttrib);
03918 } else {
03919 kdDebug(13020)<<"Enclosing region found, but not valid"<<endl;
03920 kdDebug(13020)<<"Region found: "<<n->nodeType()<<" region needed: "<<commentRegion<<endl;
03921 }
03922
03923 } else kdDebug(13020)<<"No enclosing region found"<<endl;
03924 } else kdDebug(13020)<<"No comment region specified for current hl"<<endl;
03925 }
03926 }
03927 else
03928 {
03929
03930 removed = ( hasStartLineCommentMark
03931 && removeStartLineCommentFromSelection( v, startAttrib ) )
03932 || ( hasStartStopCommentMark
03933 && removeStartStopCommentFromSelection( v, startAttrib ) );
03934 }
03935 }
03936 }
03937
03938 void KateDocument::transform( KateView *v, const KateTextCursor &c,
03939 KateDocument::TextTransform t )
03940 {
03941 editStart();
03942 uint cl( c.line() ), cc( c.col() );
03943 bool selectionRestored = false;
03944
03945 if ( hasSelection() )
03946 {
03947
03948 KateTextCursor selstart = v->selStart();
03949 KateTextCursor selend = v->selEnd();
03950
03951 int ln = v->selStartLine();
03952 while ( ln <= selend.line() )
03953 {
03954 uint start, end;
03955 start = (ln == selstart.line() || v->blockSelectionMode()) ?
03956 selstart.col() : 0;
03957 end = (ln == selend.line() || v->blockSelectionMode()) ?
03958 selend.col() : lineLength( ln );
03959 if ( start > end )
03960 {
03961 uint t = start;
03962 start = end;
03963 end = t;
03964 }
03965 QString s = text( ln, start, ln, end );
03966 QString o = s;
03967
03968 if ( t == Uppercase )
03969 s = s.upper();
03970 else if ( t == Lowercase )
03971 s = s.lower();
03972 else
03973 {
03974 KateTextLine::Ptr l = m_buffer->plainLine( ln );
03975 uint p ( 0 );
03976 while( p < s.length() )
03977 {
03978
03979
03980
03981
03982 if ( ( ! start && ! p ) ||
03983 ( ( ln == selstart.line() || v->blockSelectionMode() ) &&
03984 ! p && ! highlight()->isInWord( l->getChar( start - 1 )) ) ||
03985 ( p && ! highlight()->isInWord( s.at( p-1 ) ) )
03986 )
03987 s[p] = s.at(p).upper();
03988 p++;
03989 }
03990 }
03991
03992 if ( o != s )
03993 {
03994 removeText( ln, start, ln, end );
03995 insertText( ln, start, s );
03996 }
03997
03998 ln++;
03999 }
04000
04001
04002 v->setSelection( selstart, selend );
04003 selectionRestored = true;
04004
04005 } else {
04006 QString o = text( cl, cc, cl, cc + 1 );
04007 QString s;
04008 int n ( cc );
04009 switch ( t ) {
04010 case Uppercase:
04011 s = o.upper();
04012 break;
04013 case Lowercase:
04014 s = o.lower();
04015 break;
04016 case Capitalize:
04017 {
04018 KateTextLine::Ptr l = m_buffer->plainLine( cl );
04019 while ( n > 0 && highlight()->isInWord( l->getChar( n-1 ), l->attribute( n-1 ) ) )
04020 n--;
04021 o = text( cl, n, cl, n + 1 );
04022 s = o.upper();
04023 }
04024 break;
04025 default:
04026 break;
04027 }
04028
04029 if ( s != o )
04030 {
04031 removeText( cl, n, cl, n+1 );
04032 insertText( cl, n, s );
04033 }
04034 }
04035 editEnd();
04036
04037 if ( ! selectionRestored )
04038 v->setCursorPosition( cl, cc );
04039 }
04040
04041 void KateDocument::joinLines( uint first, uint last )
04042 {
04043
04044 editStart();
04045 int line( first );
04046 while ( first < last )
04047 {
04048
04049
04050
04051
04052
04053 KateTextLine::Ptr l = m_buffer->line( line );
04054 KateTextLine::Ptr tl = m_buffer->line( line + 1 );
04055
04056 if ( !l || !tl )
04057 {
04058 editEnd();
04059 return;
04060 }
04061
04062 int pos = tl->firstChar();
04063 if ( pos >= 0 )
04064 {
04065 if (pos != 0)
04066 editRemoveText( line + 1, 0, pos );
04067 if ( !( l->length() == 0 || l->getChar( l->length() - 1 ).isSpace() ) )
04068 editInsertText( line + 1, 0, " " );
04069 }
04070 else
04071 {
04072
04073 editRemoveText( line + 1, 0, tl->length() );
04074 }
04075
04076 editUnWrapLine( line );
04077 first++;
04078 }
04079 editEnd();
04080 }
04081
04082 QString KateDocument::getWord( const KateTextCursor& cursor ) {
04083 int start, end, len;
04084
04085 KateTextLine::Ptr textLine = m_buffer->plainLine(cursor.line());
04086 len = textLine->length();
04087 start = end = cursor.col();
04088 if (start > len)
04089 return QString("");
04090
04091 while (start > 0 && highlight()->isInWord(textLine->getChar(start - 1), textLine->attribute(start - 1))) start--;
04092 while (end < len && highlight()->isInWord(textLine->getChar(end), textLine->attribute(end))) end++;
04093 len = end - start;
04094 return QString(&textLine->text()[start], len);
04095 }
04096
04097 void KateDocument::tagLines(int start, int end)
04098 {
04099 for (uint z = 0; z < m_views.count(); z++)
04100 m_views.at(z)->tagLines (start, end, true);
04101 }
04102
04103 void KateDocument::tagLines(KateTextCursor start, KateTextCursor end)
04104 {
04105
04106 if (blockSelectionMode() && start.col() > end.col()) {
04107 int sc = start.col();
04108 start.setCol(end.col());
04109 end.setCol(sc);
04110 }
04111
04112 for (uint z = 0; z < m_views.count(); z++)
04113 m_views.at(z)->tagLines(start, end, true);
04114 }
04115
04116 void KateDocument::repaintViews(bool paintOnlyDirty)
04117 {
04118 for (uint z = 0; z < m_views.count(); z++)
04119 m_views.at(z)->repaintText(paintOnlyDirty);
04120 }
04121
04122 void KateDocument::tagAll()
04123 {
04124 for (uint z = 0; z < m_views.count(); z++)
04125 {
04126 m_views.at(z)->tagAll();
04127 m_views.at(z)->updateView (true);
04128 }
04129 }
04130
04131 uint KateDocument::configFlags ()
04132 {
04133 return config()->configFlags();
04134 }
04135
04136 void KateDocument::setConfigFlags (uint flags)
04137 {
04138 config()->setConfigFlags(flags);
04139 }
04140
04141 inline bool isStartBracket( const QChar& c ) { return c == '{' || c == '[' || c == '('; }
04142 inline bool isEndBracket ( const QChar& c ) { return c == '}' || c == ']' || c == ')'; }
04143 inline bool isBracket ( const QChar& c ) { return isStartBracket( c ) || isEndBracket( c ); }
04144
04145
04146
04147
04148
04149
04150
04151
04152
04153
04154
04155 void KateDocument::newBracketMark( const KateTextCursor& cursor, KateBracketRange& bm, int maxLines )
04156 {
04157 bm.setValid(false);
04158
04159 bm.start() = cursor;
04160
04161 if( !findMatchingBracket( bm.start(), bm.end(), maxLines ) )
04162 return;
04163
04164 bm.setValid(true);
04165
04166 const int tw = config()->tabWidth();
04167 const int indentStart = m_buffer->plainLine(bm.start().line())->indentDepth(tw);
04168 const int indentEnd = m_buffer->plainLine(bm.end().line())->indentDepth(tw);
04169 bm.setIndentMin(kMin(indentStart, indentEnd));
04170 }
04171
04172 bool KateDocument::findMatchingBracket( KateTextCursor& start, KateTextCursor& end, int maxLines )
04173 {
04174 KateTextLine::Ptr textLine = m_buffer->plainLine( start.line() );
04175 if( !textLine )
04176 return false;
04177
04178 QChar right = textLine->getChar( start.col() );
04179 QChar left = textLine->getChar( start.col() - 1 );
04180 QChar bracket;
04181
04182 if ( config()->configFlags() & cfOvr ) {
04183 if( isBracket( right ) ) {
04184 bracket = right;
04185 } else {
04186 return false;
04187 }
04188 } else if ( isStartBracket( right ) ) {
04189 bracket = right;
04190 } else if ( isEndBracket( left ) ) {
04191 start.setCol(start.col() - 1);
04192 bracket = left;
04193 } else if ( isBracket( left ) ) {
04194 start.setCol(start.col() - 1);
04195 bracket = left;
04196 } else if ( isBracket( right ) ) {
04197 bracket = right;
04198 } else {
04199 return false;
04200 }
04201
04202 QChar opposite;
04203
04204 switch( bracket ) {
04205 case '{': opposite = '}'; break;
04206 case '}': opposite = '{'; break;
04207 case '[': opposite = ']'; break;
04208 case ']': opposite = '['; break;
04209 case '(': opposite = ')'; break;
04210 case ')': opposite = '('; break;
04211 default: return false;
04212 }
04213
04214 bool forward = isStartBracket( bracket );
04215 int startAttr = textLine->attribute( start.col() );
04216 uint count = 0;
04217 int lines = 0;
04218 end = start;
04219
04220 while( true ) {
04221
04222 if( forward ) {
04223 end.setCol(end.col() + 1);
04224 if( end.col() >= lineLength( end.line() ) ) {
04225 if( end.line() >= (int)lastLine() )
04226 return false;
04227 end.setPos(end.line() + 1, 0);
04228 textLine = m_buffer->plainLine( end.line() );
04229 lines++;
04230 }
04231 } else {
04232 end.setCol(end.col() - 1);
04233 if( end.col() < 0 ) {
04234 if( end.line() <= 0 )
04235 return false;
04236 end.setLine(end.line() - 1);
04237 end.setCol(lineLength( end.line() ) - 1);
04238 textLine = m_buffer->plainLine( end.line() );
04239 lines++;
04240 }
04241 }
04242
04243 if ((maxLines != -1) && (lines > maxLines))
04244 return false;
04245
04246
04247 if( textLine->attribute( end.col() ) != startAttr )
04248 continue;
04249
04250
04251 QChar c = textLine->getChar( end.col() );
04252 if( c == bracket ) {
04253 count++;
04254 } else if( c == opposite ) {
04255 if( count == 0 )
04256 return true;
04257 count--;
04258 }
04259
04260 }
04261 }
04262
04263 void KateDocument::guiActivateEvent( KParts::GUIActivateEvent *ev )
04264 {
04265 KParts::ReadWritePart::guiActivateEvent( ev );
04266 if ( ev->activated() )
04267 emit selectionChanged();
04268 }
04269
04270 void KateDocument::setDocName (QString name )
04271 {
04272 if ( name == m_docName )
04273 return;
04274
04275 if ( !name.isEmpty() )
04276 {
04277
04278 m_docName = name;
04279 updateFileType (KateFactory::self()->fileTypeManager()->fileType (this));
04280 emit nameChanged((Kate::Document *) this);
04281 return;
04282 }
04283
04284
04285 if ( ! url().isEmpty() && m_docName.startsWith( url().filename() ) ) return;
04286
04287 int count = -1;
04288
04289 for (uint z=0; z < KateFactory::self()->documents()->count(); z++)
04290 {
04291 if ( (KateFactory::self()->documents()->at(z) != this) && (KateFactory::self()->documents()->at(z)->url().filename() == url().filename()) )
04292 if ( KateFactory::self()->documents()->at(z)->m_docNameNumber > count )
04293 count = KateFactory::self()->documents()->at(z)->m_docNameNumber;
04294 }
04295
04296 m_docNameNumber = count + 1;
04297
04298 m_docName = url().filename();
04299
04300 if (m_docName.isEmpty())
04301 m_docName = i18n ("Untitled");
04302
04303 if (m_docNameNumber > 0)
04304 m_docName = QString(m_docName + " (%1)").arg(m_docNameNumber+1);
04305
04306 updateFileType (KateFactory::self()->fileTypeManager()->fileType (this));
04307 emit nameChanged ((Kate::Document *) this);
04308 }
04309
04310 void KateDocument::slotModifiedOnDisk( Kate::View * )
04311 {
04312 if ( m_isasking < 0 )
04313 {
04314 m_isasking = 0;
04315 return;
04316 }
04317
04318 if ( !s_fileChangedDialogsActivated || m_isasking )
04319 return;
04320
04321 if (m_modOnHd && !url().isEmpty())
04322 {
04323 m_isasking = 1;
04324
04325 KateModOnHdPrompt p( this, m_modOnHdReason, reasonedMOHString(), widget() );
04326 switch ( p.exec() )
04327 {
04328 case KateModOnHdPrompt::Save:
04329 {
04330 m_modOnHd = false;
04331 KEncodingFileDialog::Result res=KEncodingFileDialog::getSaveURLAndEncoding(config()->encoding(),
04332 url().url(),QString::null,widget(),i18n("Save File"));
04333
04334 kdDebug(13020)<<"got "<<res.URLs.count()<<" URLs"<<endl;
04335 if( ! res.URLs.isEmpty() && ! res.URLs.first().isEmpty() && checkOverwrite( res.URLs.first() ) )
04336 {
04337 setEncoding( res.encoding );
04338
04339 if( ! saveAs( res.URLs.first() ) )
04340 {
04341 KMessageBox::error( widget(), i18n("Save failed") );
04342 m_modOnHd = true;
04343 }
04344 else
04345 emit modifiedOnDisc( this, false, 0 );
04346 }
04347 else
04348 {
04349 m_modOnHd = true;
04350 }
04351
04352 m_isasking = 0;
04353 break;
04354 }
04355
04356 case KateModOnHdPrompt::Reload:
04357 m_modOnHd = false;
04358 emit modifiedOnDisc( this, false, 0 );
04359 reloadFile();
04360 m_isasking = 0;
04361 break;
04362
04363 case KateModOnHdPrompt::Ignore:
04364 m_modOnHd = false;
04365 emit modifiedOnDisc( this, false, 0 );
04366 m_isasking = 0;
04367 break;
04368
04369 case KateModOnHdPrompt::Overwrite:
04370 m_modOnHd = false;
04371 emit modifiedOnDisc( this, false, 0 );
04372 m_isasking = 0;
04373 save();
04374 break;
04375
04376 default:
04377 m_isasking = -1;
04378 }
04379 }
04380 }
04381
04382 void KateDocument::setModifiedOnDisk( int reason )
04383 {
04384 m_modOnHdReason = reason;
04385 m_modOnHd = (reason > 0);
04386 emit modifiedOnDisc( this, (reason > 0), reason );
04387 }
04388
04389 class KateDocumentTmpMark
04390 {
04391 public:
04392 QString line;
04393 KTextEditor::Mark mark;
04394 };
04395
04396 void KateDocument::reloadFile()
04397 {
04398 if ( !url().isEmpty() )
04399 {
04400 if (m_modOnHd && s_fileChangedDialogsActivated)
04401 {
04402 int i = KMessageBox::warningYesNoCancel
04403 (0, reasonedMOHString() + "\n\n" + i18n("What do you want to do?"),
04404 i18n("File Was Changed on Disk"), i18n("&Reload File"), i18n("&Ignore Changes"));
04405
04406 if ( i != KMessageBox::Yes)
04407 {
04408 if (i == KMessageBox::No)
04409 {
04410 m_modOnHd = false;
04411 m_modOnHdReason = 0;
04412 emit modifiedOnDisc (this, m_modOnHd, 0);
04413 }
04414
04415 return;
04416 }
04417 }
04418
04419 QValueList<KateDocumentTmpMark> tmp;
04420
04421 for( QIntDictIterator<KTextEditor::Mark> it( m_marks ); it.current(); ++it )
04422 {
04423 KateDocumentTmpMark m;
04424
04425 m.line = textLine (it.current()->line);
04426 m.mark = *it.current();
04427
04428 tmp.append (m);
04429 }
04430
04431 uint mode = hlMode ();
04432 bool byUser = hlSetByUser;
04433
04434 m_storedVariables.clear();
04435
04436 m_reloading = true;
04437
04438 QValueList<int> lines, cols;
04439 for ( uint i=0; i < m_views.count(); i++ )
04440 {
04441 lines.append( m_views.at( i )->cursorLine() );
04442 cols.append( m_views.at( i )->cursorColumn() );
04443 }
04444
04445 KateDocument::openURL( url() );
04446
04447 for ( uint i=0; i < m_views.count(); i++ )
04448 m_views.at( i )->setCursorPositionInternal( lines[ i ], cols[ i ], m_config->tabWidth(), false );
04449
04450 m_reloading = false;
04451
04452 for ( QValueList<int>::size_type z=0; z < tmp.size(); z++ )
04453 {
04454 if (z < numLines())
04455 {
04456 if (textLine(tmp[z].mark.line) == tmp[z].line)
04457 setMark (tmp[z].mark.line, tmp[z].mark.type);
04458 }
04459 }
04460
04461 if (byUser)
04462 setHlMode (mode);
04463 }
04464 }
04465
04466 void KateDocument::flush ()
04467 {
04468 closeURL ();
04469 }
04470
04471 void KateDocument::setWordWrap (bool on)
04472 {
04473 config()->setWordWrap (on);
04474 }
04475
04476 bool KateDocument::wordWrap ()
04477 {
04478 return config()->wordWrap ();
04479 }
04480
04481 void KateDocument::setWordWrapAt (uint col)
04482 {
04483 config()->setWordWrapAt (col);
04484 }
04485
04486 unsigned int KateDocument::wordWrapAt ()
04487 {
04488 return config()->wordWrapAt ();
04489 }
04490
04491 void KateDocument::applyWordWrap ()
04492 {
04493
04494 }
04495
04496 void KateDocument::setPageUpDownMovesCursor (bool on)
04497 {
04498 config()->setPageUpDownMovesCursor (on);
04499 }
04500
04501 bool KateDocument::pageUpDownMovesCursor ()
04502 {
04503 return config()->pageUpDownMovesCursor ();
04504 }
04505
04506 void KateDocument::dumpRegionTree()
04507 {
04508 m_buffer->foldingTree()->debugDump();
04509 }
04510
04511
04512
04513
04514 KTextEditor::Cursor *KateDocument::createCursor ( )
04515 {
04516 return new KateSuperCursor (this, false, 0, 0, this);
04517 }
04518
04519 void KateDocument::tagArbitraryLines(KateView* view, KateSuperRange* range)
04520 {
04521 if (view)
04522 view->tagLines(range->start(), range->end());
04523 else
04524 tagLines(range->start(), range->end());
04525 }
04526
04527 void KateDocument::lineInfo (KateLineInfo *info, unsigned int line)
04528 {
04529 m_buffer->lineInfo(info,line);
04530 }
04531
04532 KateCodeFoldingTree *KateDocument::foldingTree ()
04533 {
04534 return m_buffer->foldingTree();
04535 }
04536
04537 void KateDocument::setEncoding (const QString &e)
04538 {
04539 if ( m_encodingSticky )
04540 return;
04541
04542 QString ce = m_config->encoding().lower();
04543 if ( e.lower() == ce )
04544 return;
04545
04546 m_config->setEncoding( e );
04547 if ( ! m_loading )
04548 reloadFile();
04549 }
04550
04551 QString KateDocument::encoding() const
04552 {
04553 return m_config->encoding();
04554 }
04555
04556 void KateDocument::updateConfig ()
04557 {
04558 emit undoChanged ();
04559 tagAll();
04560
04561 for (KateView * view = m_views.first(); view != 0L; view = m_views.next() )
04562 {
04563 view->updateDocumentConfig ();
04564 }
04565
04566
04567 if (m_indenter->modeNumber() != m_config->indentationMode())
04568 {
04569 delete m_indenter;
04570 m_indenter = KateAutoIndent::createIndenter ( this, m_config->indentationMode() );
04571 }
04572
04573 m_indenter->updateConfig();
04574
04575 m_buffer->setTabWidth (config()->tabWidth());
04576
04577
04578 for (uint i=0; i<KateFactory::self()->plugins().count(); i++)
04579 {
04580 if (config()->plugin (i))
04581 loadPlugin (i);
04582 else
04583 unloadPlugin (i);
04584 }
04585 }
04586
04587
04588
04589
04590
04591
04592
04593
04594 QRegExp KateDocument::kvLine = QRegExp("kate:(.*)");
04595 QRegExp KateDocument::kvLineWildcard = QRegExp("kate-wildcard\\((.*)\\):(.*)");
04596 QRegExp KateDocument::kvLineMime = QRegExp("kate-mimetype\\((.*)\\):(.*)");
04597 QRegExp KateDocument::kvVar = QRegExp("([\\w\\-]+)\\s+([^;]+)");
04598
04599 void KateDocument::readVariables(bool onlyViewAndRenderer)
04600 {
04601 if (!onlyViewAndRenderer)
04602 m_config->configStart();
04603
04604
04605 KateView *v;
04606 for (v = m_views.first(); v != 0L; v= m_views.next() )
04607 {
04608 v->config()->configStart();
04609 v->renderer()->config()->configStart();
04610 }
04611
04612 for (uint i=0; i < kMin( 9U, numLines() ); ++i )
04613 {
04614 readVariableLine( textLine( i ), onlyViewAndRenderer );
04615 }
04616 if ( numLines() > 10 )
04617 {
04618 for ( uint i = kMax(10U, numLines() - 10); i < numLines(); ++i )
04619 {
04620 readVariableLine( textLine( i ), onlyViewAndRenderer );
04621 }
04622 }
04623
04624 if (!onlyViewAndRenderer)
04625 m_config->configEnd();
04626
04627 for (v = m_views.first(); v != 0L; v= m_views.next() )
04628 {
04629 v->config()->configEnd();
04630 v->renderer()->config()->configEnd();
04631 }
04632 }
04633
04634 void KateDocument::readVariableLine( QString t, bool onlyViewAndRenderer )
04635 {
04636
04637
04638 if (t.find("kate") < 0)
04639 return;
04640
04641
04642 QString s;
04643
04644 if ( kvLine.search( t ) > -1 )
04645 {
04646 s = kvLine.cap(1);
04647
04648 kdDebug (13020) << "normal variable line kate: matched: " << s << endl;
04649 }
04650 else if (kvLineWildcard.search( t ) > -1)
04651 {
04652 QStringList wildcards (QStringList::split(';', kvLineWildcard.cap(1)));
04653 QString nameOfFile = url().fileName();
04654
04655 bool found = false;
04656 for (QStringList::size_type i = 0; !found && i < wildcards.size(); ++i)
04657 {
04658 QRegExp wildcard (wildcards[i], true, true);
04659
04660 found = wildcard.exactMatch (nameOfFile);
04661 }
04662
04663
04664 if (!found)
04665 return;
04666
04667 s = kvLineWildcard.cap(2);
04668
04669 kdDebug (13020) << "guarded variable line kate-wildcard: matched: " << s << endl;
04670 }
04671 else if (kvLineMime.search( t ) > -1)
04672 {
04673 QStringList types (QStringList::split(';', kvLineMime.cap(1)));
04674
04675
04676 if (!types.contains (mimeType ()))
04677 return;
04678
04679 s = kvLineMime.cap(2);
04680
04681 kdDebug (13020) << "guarded variable line kate-mimetype: matched: " << s << endl;
04682 }
04683 else
04684 {
04685 return;
04686 }
04687
04688 QStringList vvl;
04689 vvl << "dynamic-word-wrap" << "dynamic-word-wrap-indicators"
04690 << "line-numbers" << "icon-border" << "folding-markers"
04691 << "bookmark-sorting" << "auto-center-lines"
04692 << "icon-bar-color"
04693
04694 << "background-color" << "selection-color"
04695 << "current-line-color" << "bracket-highlight-color"
04696 << "word-wrap-marker-color"
04697 << "font" << "font-size" << "scheme";
04698 int p( 0 );
04699
04700 QString var, val;
04701 while ( (p = kvVar.search( s, p )) > -1 )
04702 {
04703 p += kvVar.matchedLength();
04704 var = kvVar.cap( 1 );
04705 val = kvVar.cap( 2 ).stripWhiteSpace();
04706 bool state;
04707 int n;
04708
04709
04710 if (onlyViewAndRenderer)
04711 {
04712 if ( vvl.contains( var ) )
04713 setViewVariable( var, val );
04714 }
04715 else
04716 {
04717
04718 if ( var == "word-wrap" && checkBoolValue( val, &state ) )
04719 setWordWrap( state );
04720 else if ( var == "block-selection" && checkBoolValue( val, &state ) )
04721 setBlockSelectionMode( state );
04722
04723
04724 else if ( var == "backspace-indents" && checkBoolValue( val, &state ) )
04725 m_config->setConfigFlags( KateDocumentConfig::cfBackspaceIndents, state );
04726 else if ( var == "replace-tabs" && checkBoolValue( val, &state ) )
04727 m_config->setConfigFlags( KateDocumentConfig::cfReplaceTabsDyn, state );
04728 else if ( var == "remove-trailing-space" && checkBoolValue( val, &state ) )
04729 m_config->setConfigFlags( KateDocumentConfig::cfRemoveTrailingDyn, state );
04730 else if ( var == "wrap-cursor" && checkBoolValue( val, &state ) )
04731 m_config->setConfigFlags( KateDocumentConfig::cfWrapCursor, state );
04732 else if ( var == "auto-brackets" && checkBoolValue( val, &state ) )
04733 m_config->setConfigFlags( KateDocumentConfig::cfAutoBrackets, state );
04734 else if ( var == "overwrite-mode" && checkBoolValue( val, &state ) )
04735 m_config->setConfigFlags( KateDocumentConfig::cfOvr, state );
04736 else if ( var == "keep-indent-profile" && checkBoolValue( val, &state ) )
04737 m_config->setConfigFlags( KateDocumentConfig::cfKeepIndentProfile, state );
04738 else if ( var == "keep-extra-spaces" && checkBoolValue( val, &state ) )
04739 m_config->setConfigFlags( KateDocumentConfig::cfKeepExtraSpaces, state );
04740 else if ( var == "tab-indents" && checkBoolValue( val, &state ) )
04741 m_config->setConfigFlags( KateDocumentConfig::cfTabIndents, state );
04742 else if ( var == "show-tabs" && checkBoolValue( val, &state ) )
04743 m_config->setConfigFlags( KateDocumentConfig::cfShowTabs, state );
04744 else if ( var == "space-indent" && checkBoolValue( val, &state ) )
04745 m_config->setConfigFlags( KateDocumentConfig::cfSpaceIndent, state );
04746 else if ( var == "smart-home" && checkBoolValue( val, &state ) )
04747 m_config->setConfigFlags( KateDocumentConfig::cfSmartHome, state );
04748 else if ( var == "replace-trailing-space-save" && checkBoolValue( val, &state ) )
04749 m_config->setConfigFlags( KateDocumentConfig::cfRemoveSpaces, state );
04750 else if ( var == "auto-insert-doxygen" && checkBoolValue( val, &state) )
04751 m_config->setConfigFlags( KateDocumentConfig::cfDoxygenAutoTyping, state);
04752 else if ( var == "mixed-indent" && checkBoolValue( val, &state ) )
04753 m_config->setConfigFlags( KateDocumentConfig::cfMixedIndent, state );
04754
04755
04756 else if ( var == "tab-width" && checkIntValue( val, &n ) )
04757 m_config->setTabWidth( n );
04758 else if ( var == "indent-width" && checkIntValue( val, &n ) )
04759 m_config->setIndentationWidth( n );
04760 else if ( var == "indent-mode" )
04761 {
04762 if ( checkIntValue( val, &n ) )
04763 m_config->setIndentationMode( n );
04764 else
04765 m_config->setIndentationMode( KateAutoIndent::modeNumber( val) );
04766 }
04767 else if ( var == "word-wrap-column" && checkIntValue( val, &n ) && n > 0 )
04768 m_config->setWordWrapAt( n );
04769 else if ( var == "undo-steps" && checkIntValue( val, &n ) && n >= 0 )
04770 setUndoSteps( n );
04771
04772
04773 else if ( var == "eol" || var == "end-of-line" )
04774 {
04775 QStringList l;
04776 l << "unix" << "dos" << "mac";
04777 if ( (n = l.findIndex( val.lower() )) != -1 )
04778 m_config->setEol( n );
04779 }
04780 else if ( var == "encoding" )
04781 m_config->setEncoding( val );
04782 else if ( var == "syntax" || var == "hl" )
04783 {
04784 for ( uint i=0; i < hlModeCount(); i++ )
04785 {
04786 if ( hlModeName( i ).lower() == val.lower() )
04787 {
04788 setHlMode( i );
04789 break;
04790 }
04791 }
04792 }
04793
04794
04795 else if ( vvl.contains( var ) )
04796 setViewVariable( var, val );
04797 else
04798 {
04799 m_storedVariables.insert( var, val );
04800 emit variableChanged( var, val );
04801 }
04802 }
04803 }
04804 }
04805
04806 void KateDocument::setViewVariable( QString var, QString val )
04807 {
04808 KateView *v;
04809 bool state;
04810 int n;
04811 QColor c;
04812 for (v = m_views.first(); v != 0L; v= m_views.next() )
04813 {
04814 if ( var == "dynamic-word-wrap" && checkBoolValue( val, &state ) )
04815 v->config()->setDynWordWrap( state );
04816 else if ( var == "persistent-selection" && checkBoolValue( val, &state ) )
04817 v->config()->setPersistentSelection( state );
04818
04819 else if ( var == "line-numbers" && checkBoolValue( val, &state ) )
04820 v->config()->setLineNumbers( state );
04821 else if (var == "icon-border" && checkBoolValue( val, &state ) )
04822 v->config()->setIconBar( state );
04823 else if (var == "folding-markers" && checkBoolValue( val, &state ) )
04824 v->config()->setFoldingBar( state );
04825 else if ( var == "auto-center-lines" && checkIntValue( val, &n ) )
04826 v->config()->setAutoCenterLines( n );
04827 else if ( var == "icon-bar-color" && checkColorValue( val, c ) )
04828 v->renderer()->config()->setIconBarColor( c );
04829
04830 else if ( var == "background-color" && checkColorValue( val, c ) )
04831 v->renderer()->config()->setBackgroundColor( c );
04832 else if ( var == "selection-color" && checkColorValue( val, c ) )
04833 v->renderer()->config()->setSelectionColor( c );
04834 else if ( var == "current-line-color" && checkColorValue( val, c ) )
04835 v->renderer()->config()->setHighlightedLineColor( c );
04836 else if ( var == "bracket-highlight-color" && checkColorValue( val, c ) )
04837 v->renderer()->config()->setHighlightedBracketColor( c );
04838 else if ( var == "word-wrap-marker-color" && checkColorValue( val, c ) )
04839 v->renderer()->config()->setWordWrapMarkerColor( c );
04840 else if ( var == "font" || ( var == "font-size" && checkIntValue( val, &n ) ) )
04841 {
04842 QFont _f( *v->renderer()->config()->font( ) );
04843
04844 if ( var == "font" )
04845 {
04846 _f.setFamily( val );
04847 _f.setFixedPitch( QFont( val ).fixedPitch() );
04848 }
04849 else
04850 _f.setPointSize( n );
04851
04852 v->renderer()->config()->setFont( _f );
04853 }
04854 else if ( var == "scheme" )
04855 {
04856 v->renderer()->config()->setSchema( KateFactory::self()->schemaManager()->number( val ) );
04857 }
04858 }
04859 }
04860
04861 bool KateDocument::checkBoolValue( QString val, bool *result )
04862 {
04863 val = val.stripWhiteSpace().lower();
04864 QStringList l;
04865 l << "1" << "on" << "true";
04866 if ( l.contains( val ) )
04867 {
04868 *result = true;
04869 return true;
04870 }
04871 l.clear();
04872 l << "0" << "off" << "false";
04873 if ( l.contains( val ) )
04874 {
04875 *result = false;
04876 return true;
04877 }
04878 return false;
04879 }
04880
04881 bool KateDocument::checkIntValue( QString val, int *result )
04882 {
04883 bool ret( false );
04884 *result = val.toInt( &ret );
04885 return ret;
04886 }
04887
04888 bool KateDocument::checkColorValue( QString val, QColor &c )
04889 {
04890 c.setNamedColor( val );
04891 return c.isValid();
04892 }
04893
04894
04895 QString KateDocument::variable( const QString &name ) const
04896 {
04897 if ( m_storedVariables.contains( name ) )
04898 return m_storedVariables[ name ];
04899
04900 return "";
04901 }
04902
04903
04904
04905 void KateDocument::slotModOnHdDirty (const QString &path)
04906 {
04907 if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != 1))
04908 {
04909
04910 if ( ! m_digest.isEmpty() )
04911 {
04912 QCString tmp;
04913 if ( createDigest( tmp ) && tmp == m_digest )
04914 return;
04915 }
04916
04917 m_modOnHd = true;
04918 m_modOnHdReason = 1;
04919
04920
04921 if (m_isasking == -1)
04922 m_isasking = false;
04923
04924 emit modifiedOnDisc (this, m_modOnHd, m_modOnHdReason);
04925 }
04926 }
04927
04928 void KateDocument::slotModOnHdCreated (const QString &path)
04929 {
04930 if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != 2))
04931 {
04932 m_modOnHd = true;
04933 m_modOnHdReason = 2;
04934
04935
04936 if (m_isasking == -1)
04937 m_isasking = false;
04938
04939 emit modifiedOnDisc (this, m_modOnHd, m_modOnHdReason);
04940 }
04941 }
04942
04943 void KateDocument::slotModOnHdDeleted (const QString &path)
04944 {
04945 if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != 3))
04946 {
04947 m_modOnHd = true;
04948 m_modOnHdReason = 3;
04949
04950
04951 if (m_isasking == -1)
04952 m_isasking = false;
04953
04954 emit modifiedOnDisc (this, m_modOnHd, m_modOnHdReason);
04955 }
04956 }
04957
04958 bool KateDocument::createDigest( QCString &result )
04959 {
04960 bool ret = false;
04961 result = "";
04962 if ( url().isLocalFile() )
04963 {
04964 QFile f ( url().path() );
04965 if ( f.open( IO_ReadOnly) )
04966 {
04967 KMD5 md5;
04968 ret = md5.update( f );
04969 md5.hexDigest( result );
04970 f.close();
04971 ret = true;
04972 }
04973 }
04974 return ret;
04975 }
04976
04977 QString KateDocument::reasonedMOHString() const
04978 {
04979 switch( m_modOnHdReason )
04980 {
04981 case 1:
04982 return i18n("The file '%1' was modified by another program.").arg( url().prettyURL() );
04983 break;
04984 case 2:
04985 return i18n("The file '%1' was created by another program.").arg( url().prettyURL() );
04986 break;
04987 case 3:
04988 return i18n("The file '%1' was deleted by another program.").arg( url().prettyURL() );
04989 break;
04990 default:
04991 return QString();
04992 }
04993 }
04994
04995 void KateDocument::removeTrailingSpace( uint line )
04996 {
04997
04998 if ( config()->configFlags() & KateDocumentConfig::cfRemoveTrailingDyn )
04999 {
05000 KateTextLine::Ptr ln = kateTextLine( line );
05001
05002 if ( ! ln ) return;
05003
05004 if ( line == activeView()->cursorLine()
05005 && activeView()->cursorColumnReal() >= (uint)kMax(0,ln->lastChar()) )
05006 return;
05007
05008 if ( ln->length() )
05009 {
05010 uint p = ln->lastChar() + 1;
05011 uint l = ln->length() - p;
05012 if ( l )
05013 editRemoveText( line, p, l);
05014 }
05015 }
05016 }
05017
05018 void KateDocument::updateFileType (int newType, bool user)
05019 {
05020 if (user || !m_fileTypeSetByUser)
05021 {
05022 const KateFileType *t = 0;
05023 if ((newType == -1) || (t = KateFactory::self()->fileTypeManager()->fileType (newType)))
05024 {
05025 m_fileType = newType;
05026
05027 if (t)
05028 {
05029 m_config->configStart();
05030
05031 KateView *v;
05032 for (v = m_views.first(); v != 0L; v= m_views.next() )
05033 {
05034 v->config()->configStart();
05035 v->renderer()->config()->configStart();
05036 }
05037
05038 readVariableLine( t->varLine );
05039
05040 m_config->configEnd();
05041 for (v = m_views.first(); v != 0L; v= m_views.next() )
05042 {
05043 v->config()->configEnd();
05044 v->renderer()->config()->configEnd();
05045 }
05046 }
05047 }
05048 }
05049 }
05050
05051 uint KateDocument::documentNumber () const
05052 {
05053 return KTextEditor::Document::documentNumber ();
05054 }
05055
05056
05057
05058
05059 void KateDocument::slotQueryClose_save(bool *handled, bool* abortClosing) {
05060 *handled=true;
05061 *abortClosing=true;
05062 if (m_url.isEmpty())
05063 {
05064 KEncodingFileDialog::Result res=KEncodingFileDialog::getSaveURLAndEncoding(config()->encoding(),
05065 QString::null,QString::null,0,i18n("Save File"));
05066
05067 if( res.URLs.isEmpty() || !checkOverwrite( res.URLs.first() ) ) {
05068 *abortClosing=true;
05069 return;
05070 }
05071 setEncoding( res.encoding );
05072 saveAs( res.URLs.first() );
05073 *abortClosing=false;
05074 }
05075 else
05076 {
05077 save();
05078 *abortClosing=false;
05079 }
05080
05081 }
05082
05083 bool KateDocument::checkOverwrite( KURL u )
05084 {
05085 if( !u.isLocalFile() )
05086 return true;
05087
05088 QFileInfo info( u.path() );
05089 if( !info.exists() )
05090 return true;
05091
05092 return KMessageBox::Cancel != KMessageBox::warningContinueCancel( 0,
05093 i18n( "A file named \"%1\" already exists. "
05094 "Are you sure you want to overwrite it?" ).arg( info.fileName() ),
05095 i18n( "Overwrite File?" ),
05096 i18n( "&Overwrite" ) );
05097 }
05098
05099 void KateDocument::setDefaultEncoding (const QString &encoding)
05100 {
05101 s_defaultEncoding = encoding;
05102 }
05103
05104
05105 bool KateDocument::insertTemplateTextImplementation ( uint line, uint column, const QString &templateString, const QMap<QString,QString> &initialValues, QWidget *) {
05106 return (new KateTemplateHandler(this,line,column,templateString,initialValues))->initOk();
05107 }
05108
05109 void KateDocument::testTemplateCode() {
05110 int col=activeView()->cursorColumn();
05111 int line=activeView()->cursorLine();
05112 insertTemplateText(line,col,"for ${index} \\${NOPLACEHOLDER} ${index} ${blah} ${fullname} \\$${Placeholder} \\${${PLACEHOLDER2}}\n next line:${ANOTHERPLACEHOLDER} $${DOLLARBEFOREPLACEHOLDER} {NOTHING} {\n${cursor}\n}",QMap<QString,QString>());
05113 }
05114
05115 bool KateDocument::invokeTabInterceptor(KKey key) {
05116 if (m_tabInterceptor) return (*m_tabInterceptor)(key);
05117 return false;
05118 }
05119
05120 bool KateDocument::setTabInterceptor(KateKeyInterceptorFunctor *interceptor) {
05121 if (m_tabInterceptor) return false;
05122 m_tabInterceptor=interceptor;
05123 return true;
05124 }
05125
05126 bool KateDocument::removeTabInterceptor(KateKeyInterceptorFunctor *interceptor) {
05127 if (m_tabInterceptor!=interceptor) return false;
05128 m_tabInterceptor=0;
05129 return true;
05130 }
05131
05132
05133
05134 bool KateDocument::setSelection ( uint startLine, uint startCol, uint endLine, uint endCol )
05135 { if (m_activeView) return m_activeView->setSelection (startLine, startCol, endLine, endCol); return false; }
05136
05137 bool KateDocument::clearSelection ()
05138 { if (m_activeView) return m_activeView->clearSelection(); return false; }
05139
05140 bool KateDocument::hasSelection () const
05141 { if (m_activeView) return m_activeView->hasSelection (); return false; }
05142
05143 QString KateDocument::selection () const
05144 { if (m_activeView) return m_activeView->selection (); return QString(""); }
05145
05146 bool KateDocument::removeSelectedText ()
05147 { if (m_activeView) return m_activeView->removeSelectedText (); return false; }
05148
05149 bool KateDocument::selectAll()
05150 { if (m_activeView) return m_activeView->selectAll (); return false; }
05151
05152 int KateDocument::selStartLine()
05153 { if (m_activeView) return m_activeView->selStartLine (); return 0; }
05154
05155 int KateDocument::selStartCol()
05156 { if (m_activeView) return m_activeView->selStartCol (); return 0; }
05157
05158 int KateDocument::selEndLine()
05159 { if (m_activeView) return m_activeView->selEndLine (); return 0; }
05160
05161 int KateDocument::selEndCol()
05162 { if (m_activeView) return m_activeView->selEndCol (); return 0; }
05163
05164 bool KateDocument::blockSelectionMode ()
05165 { if (m_activeView) return m_activeView->blockSelectionMode (); return false; }
05166
05167 bool KateDocument::setBlockSelectionMode (bool on)
05168 { if (m_activeView) return m_activeView->setBlockSelectionMode (on); return false; }
05169
05170 bool KateDocument::toggleBlockSelectionMode ()
05171 { if (m_activeView) return m_activeView->toggleBlockSelectionMode (); return false; }
05172
05173
05174
05175
05176