• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kate
 

kate

  • kate
  • part
katedocument.cpp
1/* This file is part of the KDE libraries
2 Copyright (C) 2001-2004 Christoph Cullmann <cullmann@kde.org>
3 Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org>
4 Copyright (C) 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License version 2 as published by the Free Software Foundation.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02111-13020, USA.
19*/
20
21//BEGIN includes
22#include "katedocument.h"
23#include "katedocument.moc"
24#include "katekeyinterceptorfunctor.h"
25#include "katefactory.h"
26#include "katedialogs.h"
27#include "katehighlight.h"
28#include "kateview.h"
29#include "katesearch.h"
30#include "kateautoindent.h"
31#include "katetextline.h"
32#include "katedocumenthelpers.h"
33#include "kateprinter.h"
34#include "katelinerange.h"
35#include "katesupercursor.h"
36#include "katearbitraryhighlight.h"
37#include "katerenderer.h"
38#include "kateattribute.h"
39#include "kateconfig.h"
40#include "katefiletype.h"
41#include "kateschema.h"
42#include "katetemplatehandler.h"
43#include <tdetexteditor/plugin.h>
44
45#include <tdeio/job.h>
46#include <tdeio/netaccess.h>
47#include <tdeio/tdefileitem.h>
48
49
50#include <tdeparts/event.h>
51
52#include <tdelocale.h>
53#include <tdeglobal.h>
54#include <tdeapplication.h>
55#include <tdepopupmenu.h>
56#include <tdeconfig.h>
57#include <tdefiledialog.h>
58#include <tdemessagebox.h>
59#include <kstdaction.h>
60#include <kiconloader.h>
61#include <kxmlguifactory.h>
62#include <kdialogbase.h>
63#include <kdebug.h>
64#include <tdeglobalsettings.h>
65#include <klibloader.h>
66#include <kdirwatch.h>
67#include <twin.h>
68#include <kencodingfiledialog.h>
69#include <tdetempfile.h>
70#include <kmdcodec.h>
71#include <tdestandarddirs.h>
72
73#include <tqtimer.h>
74#include <tqfile.h>
75#include <tqclipboard.h>
76#include <tqtextstream.h>
77#include <tqtextcodec.h>
78#include <tqmap.h>
79//END includes
80
81//BEGIN PRIVATE CLASSES
82class KatePartPluginItem
83{
84 public:
85 KTextEditor::Plugin *plugin;
86};
87//END PRIVATE CLASSES
88
89//BEGIN d'tor, c'tor
90//
91// KateDocument Constructor
92//
93KateDocument::KateDocument ( bool bSingleViewMode, bool bBrowserView,
94 bool bReadOnly, TQWidget *parentWidget,
95 const char *widgetName, TQObject *parent, const char *name)
96: Kate::Document(parent, name),
97 m_plugins (KateFactory::self()->plugins().count()),
98 m_undoDontMerge(false),
99 m_undoIgnoreCancel(false),
100 lastUndoGroupWhenSaved( 0 ),
101 lastRedoGroupWhenSaved( 0 ),
102 docWasSavedWhenUndoWasEmpty( true ),
103 docWasSavedWhenRedoWasEmpty( true ),
104 m_modOnHd (false),
105 m_modOnHdReason (0),
106 m_job (0),
107 m_tempFile (0),
108 m_tabInterceptor(0)
109{
110 m_undoComplexMerge=false;
111 m_isInUndo = false;
112 // my dcop object
113 setObjId ("KateDocument#"+documentDCOPSuffix());
114
115 // tdetexteditor interfaces
116 setBlockSelectionInterfaceDCOPSuffix (documentDCOPSuffix());
117 setConfigInterfaceDCOPSuffix (documentDCOPSuffix());
118 setConfigInterfaceExtensionDCOPSuffix (documentDCOPSuffix());
119 setCursorInterfaceDCOPSuffix (documentDCOPSuffix());
120 setEditInterfaceDCOPSuffix (documentDCOPSuffix());
121 setEncodingInterfaceDCOPSuffix (documentDCOPSuffix());
122 setHighlightingInterfaceDCOPSuffix (documentDCOPSuffix());
123 setMarkInterfaceDCOPSuffix (documentDCOPSuffix());
124 setMarkInterfaceExtensionDCOPSuffix (documentDCOPSuffix());
125 setPrintInterfaceDCOPSuffix (documentDCOPSuffix());
126 setSearchInterfaceDCOPSuffix (documentDCOPSuffix());
127 setSelectionInterfaceDCOPSuffix (documentDCOPSuffix());
128 setSelectionInterfaceExtDCOPSuffix (documentDCOPSuffix());
129 setSessionConfigInterfaceDCOPSuffix (documentDCOPSuffix());
130 setUndoInterfaceDCOPSuffix (documentDCOPSuffix());
131 setWordWrapInterfaceDCOPSuffix (documentDCOPSuffix());
132
133 // init local plugin array
134 m_plugins.fill (0);
135
136 // register doc at factory
137 KateFactory::self()->registerDocument (this);
138
139 m_reloading = false;
140 m_loading = false;
141 m_encodingSticky = false;
142
143 m_buffer = new KateBuffer (this);
144
145 // init the config object, be careful not to use it
146 // until the initial readConfig() call is done
147 m_config = new KateDocumentConfig (this);
148
149 // init some more vars !
150 m_activeView = 0L;
151
152 hlSetByUser = false;
153 m_fileType = -1;
154 m_fileTypeSetByUser = false;
155 setInstance( KateFactory::self()->instance() );
156
157 editSessionNumber = 0;
158 editIsRunning = false;
159 m_editCurrentUndo = 0L;
160 editWithUndo = false;
161
162 m_docNameNumber = 0;
163
164 m_bSingleViewMode = bSingleViewMode;
165 m_bBrowserView = bBrowserView;
166 m_bReadOnly = bReadOnly;
167
168 m_marks.setAutoDelete( true );
169 m_markPixmaps.setAutoDelete( true );
170 m_markDescriptions.setAutoDelete( true );
171 setMarksUserChangable( markType01 );
172
173 m_undoMergeTimer = new TQTimer(this);
174 connect(m_undoMergeTimer, TQ_SIGNAL(timeout()), TQ_SLOT(undoCancel()));
175
176 clearMarks ();
177 clearUndo ();
178 clearRedo ();
179 setModified (false);
180 docWasSavedWhenUndoWasEmpty = true;
181
182 // normal hl
183 m_buffer->setHighlight (0);
184
185 m_extension = new KateBrowserExtension( this );
186 m_arbitraryHL = new KateArbitraryHighlight();
187 m_indenter = KateAutoIndent::createIndenter ( this, 0 );
188
189 m_indenter->updateConfig ();
190
191 // some nice signals from the buffer
192 connect(m_buffer, TQ_SIGNAL(tagLines(int,int)), this, TQ_SLOT(tagLines(int,int)));
193 connect(m_buffer, TQ_SIGNAL(codeFoldingUpdated()),this,TQ_SIGNAL(codeFoldingUpdated()));
194
195 // if the user changes the highlight with the dialog, notify the doc
196 connect(KateHlManager::self(),TQ_SIGNAL(changed()),TQ_SLOT(internalHlChanged()));
197
198 // signal for the arbitrary HL
199 connect(m_arbitraryHL, TQ_SIGNAL(tagLines(KateView*, KateSuperRange*)), TQ_SLOT(tagArbitraryLines(KateView*, KateSuperRange*)));
200
201 // signals for mod on hd
202 connect( KateFactory::self()->dirWatch(), TQ_SIGNAL(dirty (const TQString &)),
203 this, TQ_SLOT(slotModOnHdDirty (const TQString &)) );
204
205 connect( KateFactory::self()->dirWatch(), TQ_SIGNAL(created (const TQString &)),
206 this, TQ_SLOT(slotModOnHdCreated (const TQString &)) );
207
208 connect( KateFactory::self()->dirWatch(), TQ_SIGNAL(deleted (const TQString &)),
209 this, TQ_SLOT(slotModOnHdDeleted (const TQString &)) );
210
211 // update doc name
212 setDocName ("");
213
214 // if single view mode, like in the konqui embedding, create a default view ;)
215 if ( m_bSingleViewMode )
216 {
217 KTextEditor::View *view = createView( parentWidget, widgetName );
218 insertChildClient( view );
219 view->show();
220 setWidget( view );
221 }
222
223 connect(this,TQ_SIGNAL(sigQueryClose(bool *, bool*)),this,TQ_SLOT(slotQueryClose_save(bool *, bool*)));
224
225 m_isasking = 0;
226
227 // plugins
228 for (uint i=0; i<KateFactory::self()->plugins().count(); i++)
229 {
230 if (config()->plugin (i))
231 loadPlugin (i);
232 }
233}
234
235//
236// KateDocument Destructor
237//
238KateDocument::~KateDocument()
239{
240 // remove file from dirwatch
241 deactivateDirWatch ();
242
243 if (!singleViewMode())
244 {
245 // clean up remaining views
246 m_views.setAutoDelete( true );
247 m_views.clear();
248 }
249
250 delete m_editCurrentUndo;
251
252 delete m_arbitraryHL;
253
254 // cleanup the undo items, very important, truee :/
255 undoItems.setAutoDelete(true);
256 undoItems.clear();
257
258 // clean up plugins
259 unloadAllPlugins ();
260
261 delete m_config;
262 delete m_indenter;
263 KateFactory::self()->deregisterDocument (this);
264}
265//END
266
267//BEGIN Plugins
268void KateDocument::unloadAllPlugins ()
269{
270 for (uint i=0; i<m_plugins.count(); i++)
271 unloadPlugin (i);
272}
273
274void KateDocument::enableAllPluginsGUI (KateView *view)
275{
276 for (uint i=0; i<m_plugins.count(); i++)
277 enablePluginGUI (m_plugins[i], view);
278}
279
280void KateDocument::disableAllPluginsGUI (KateView *view)
281{
282 for (uint i=0; i<m_plugins.count(); i++)
283 disablePluginGUI (m_plugins[i], view);
284}
285
286void KateDocument::loadPlugin (uint pluginIndex)
287{
288 if (m_plugins[pluginIndex]) return;
289
290 m_plugins[pluginIndex] = KTextEditor::createPlugin (TQFile::encodeName((KateFactory::self()->plugins())[pluginIndex]->library()), this);
291
292 enablePluginGUI (m_plugins[pluginIndex]);
293}
294
295void KateDocument::unloadPlugin (uint pluginIndex)
296{
297 if (!m_plugins[pluginIndex]) return;
298
299 disablePluginGUI (m_plugins[pluginIndex]);
300
301 delete m_plugins[pluginIndex];
302 m_plugins[pluginIndex] = 0L;
303}
304
305void KateDocument::enablePluginGUI (KTextEditor::Plugin *plugin, KateView *view)
306{
307 if (!plugin) return;
308 if (!KTextEditor::pluginViewInterface(plugin)) return;
309
310 KXMLGUIFactory *factory = view->factory();
311 if ( factory )
312 factory->removeClient( view );
313
314 KTextEditor::pluginViewInterface(plugin)->addView(view);
315
316 if ( factory )
317 factory->addClient( view );
318}
319
320void KateDocument::enablePluginGUI (KTextEditor::Plugin *plugin)
321{
322 if (!plugin) return;
323 if (!KTextEditor::pluginViewInterface(plugin)) return;
324
325 for (uint i=0; i< m_views.count(); i++)
326 enablePluginGUI (plugin, m_views.at(i));
327}
328
329void KateDocument::disablePluginGUI (KTextEditor::Plugin *plugin, KateView *view)
330{
331 if (!plugin) return;
332 if (!KTextEditor::pluginViewInterface(plugin)) return;
333
334 KXMLGUIFactory *factory = view->factory();
335 if ( factory )
336 factory->removeClient( view );
337
338 KTextEditor::pluginViewInterface( plugin )->removeView( view );
339
340 if ( factory )
341 factory->addClient( view );
342}
343
344void KateDocument::disablePluginGUI (KTextEditor::Plugin *plugin)
345{
346 if (!plugin) return;
347 if (!KTextEditor::pluginViewInterface(plugin)) return;
348
349 for (uint i=0; i< m_views.count(); i++)
350 disablePluginGUI (plugin, m_views.at(i));
351}
352//END
353
354//BEGIN KTextEditor::Document stuff
355
356KTextEditor::View *KateDocument::createView( TQWidget *parent, const char *name )
357{
358 KateView* newView = new KateView( this, parent, name);
359 connect(newView, TQ_SIGNAL(cursorPositionChanged()), TQ_SLOT(undoCancel()));
360 if ( s_fileChangedDialogsActivated )
361 connect( newView, TQ_SIGNAL(gotFocus( Kate::View * )), this, TQ_SLOT(slotModifiedOnDisk()) );
362 return newView;
363}
364
365TQPtrList<KTextEditor::View> KateDocument::views () const
366{
367 return m_textEditViews;
368}
369
370void KateDocument::setActiveView( KateView *view )
371{
372 if ( m_activeView == view ) return;
373
374 m_activeView = view;
375}
376//END
377
378//BEGIN KTextEditor::ConfigInterfaceExtension stuff
379
380uint KateDocument::configPages () const
381{
382 return 10;
383}
384
385KTextEditor::ConfigPage *KateDocument::configPage (uint number, TQWidget *parent, const char * )
386{
387 switch( number )
388 {
389 case 0:
390 return new KateViewDefaultsConfig (parent);
391
392 case 1:
393 return new KateSchemaConfigPage (parent, this);
394
395 case 2:
396 return new KateSelectConfigTab (parent);
397
398 case 3:
399 return new KateEditConfigTab (parent);
400
401 case 4:
402 return new KateIndentConfigTab (parent);
403
404 case 5:
405 return new KateSaveConfigTab (parent);
406
407 case 6:
408 return new KateHlConfigPage (parent, this);
409
410 case 7:
411 return new KateFileTypeConfigTab (parent);
412
413 case 8:
414 return new KateEditKeyConfiguration (parent, this);
415
416 case 9:
417 return new KatePartPluginConfigPage (parent);
418
419 default:
420 return 0;
421 }
422
423 return 0;
424}
425
426TQString KateDocument::configPageName (uint number) const
427{
428 switch( number )
429 {
430 case 0:
431 return i18n ("Appearance");
432
433 case 1:
434 return i18n ("Fonts & Colors");
435
436 case 2:
437 return i18n ("Cursor & Selection");
438
439 case 3:
440 return i18n ("Editing");
441
442 case 4:
443 return i18n ("Indentation");
444
445 case 5:
446 return i18n("Open/Save");
447
448 case 6:
449 return i18n ("Highlighting");
450
451 case 7:
452 return i18n("Filetypes");
453
454 case 8:
455 return i18n ("Shortcuts");
456
457 case 9:
458 return i18n ("Plugins");
459
460 default:
461 return TQString ("");
462 }
463
464 return TQString ("");
465}
466
467TQString KateDocument::configPageFullName (uint number) const
468{
469 switch( number )
470 {
471 case 0:
472 return i18n("Appearance");
473
474 case 1:
475 return i18n ("Font & Color Schemas");
476
477 case 2:
478 return i18n ("Cursor & Selection Behavior");
479
480 case 3:
481 return i18n ("Editing Options");
482
483 case 4:
484 return i18n ("Indentation Rules");
485
486 case 5:
487 return i18n("File Opening & Saving");
488
489 case 6:
490 return i18n ("Highlighting Rules");
491
492 case 7:
493 return i18n("Filetype Specific Settings");
494
495 case 8:
496 return i18n ("Shortcuts Configuration");
497
498 case 9:
499 return i18n ("Plugin Manager");
500
501 default:
502 return TQString ("");
503 }
504
505 return TQString ("");
506}
507
508TQPixmap KateDocument::configPagePixmap (uint number, int size) const
509{
510 switch( number )
511 {
512 case 0:
513 return BarIcon("view_text",size);
514
515 case 1:
516 return BarIcon("colorize", size);
517
518 case 2:
519 return BarIcon("frame_edit", size);
520
521 case 3:
522 return BarIcon("edit", size);
523
524 case 4:
525 return BarIcon("format-justify-right", size);
526
527 case 5:
528 return BarIcon("document-save", size);
529
530 case 6:
531 return BarIcon("text-x-src", size);
532
533 case 7:
534 return BarIcon("edit", size);
535
536 case 8:
537 return BarIcon("key_enter", size);
538
539 case 9:
540 return BarIcon("connect_established", size);
541
542 default:
543 return BarIcon("edit", size);
544 }
545
546 return BarIcon("edit", size);
547}
548//END
549
550//BEGIN KTextEditor::EditInterface stuff
551
552TQString KateDocument::text() const
553{
554 TQString s;
555
556 for (uint i = 0; i < m_buffer->count(); i++)
557 {
558 KateTextLine::Ptr textLine = m_buffer->plainLine(i);
559
560 if (textLine)
561 {
562 s.append (textLine->string());
563
564 if ((i+1) < m_buffer->count())
565 s.append('\n');
566 }
567 }
568
569 return s;
570}
571
572TQString KateDocument::text ( uint startLine, uint startCol, uint endLine, uint endCol ) const
573{
574 return text(startLine, startCol, endLine, endCol, false);
575}
576
577TQString KateDocument::text ( uint startLine, uint startCol, uint endLine, uint endCol, bool blockwise) const
578{
579 if ( blockwise && (startCol > endCol) )
580 return TQString ();
581
582 TQString s;
583
584 if (startLine == endLine)
585 {
586 if (startCol > endCol)
587 return TQString ();
588
589 KateTextLine::Ptr textLine = m_buffer->plainLine(startLine);
590
591 if ( !textLine )
592 return TQString ();
593
594 return textLine->string(startCol, endCol-startCol);
595 }
596 else
597 {
598
599 for (uint i = startLine; (i <= endLine) && (i < m_buffer->count()); i++)
600 {
601 KateTextLine::Ptr textLine = m_buffer->plainLine(i);
602
603 if ( !blockwise )
604 {
605 if (i == startLine)
606 s.append (textLine->string(startCol, textLine->length()-startCol));
607 else if (i == endLine)
608 s.append (textLine->string(0, endCol));
609 else
610 s.append (textLine->string());
611 }
612 else
613 {
614 s.append( textLine->string( startCol, endCol-startCol));
615 }
616
617 if ( i < endLine )
618 s.append('\n');
619 }
620 }
621
622 return s;
623}
624
625TQString KateDocument::textLine( uint line ) const
626{
627 KateTextLine::Ptr l = m_buffer->plainLine(line);
628
629 if (!l)
630 return TQString();
631
632 return l->string();
633}
634
635bool KateDocument::setText(const TQString &s)
636{
637 if (!isReadWrite())
638 return false;
639
640 TQPtrList<KTextEditor::Mark> m = marks ();
641 TQValueList<KTextEditor::Mark> msave;
642
643 for (uint i=0; i < m.count(); i++)
644 msave.append (*m.at(i));
645
646 editStart ();
647
648 // delete the text
649 clear();
650
651 // insert the new text
652 insertText (0, 0, s);
653
654 editEnd ();
655
656 for (uint i=0; i < msave.count(); i++)
657 setMark (msave[i].line, msave[i].type);
658
659 return true;
660}
661
662bool KateDocument::clear()
663{
664 if (!isReadWrite())
665 return false;
666
667 for (KateView * view = m_views.first(); view != 0L; view = m_views.next() ) {
668 view->clear();
669 view->tagAll();
670 view->update();
671 }
672
673 clearMarks ();
674
675 return removeText (0,0,lastLine()+1, 0);
676}
677
678bool KateDocument::insertText( uint line, uint col, const TQString &s)
679{
680 return insertText (line, col, s, false);
681}
682
683bool KateDocument::insertText( uint line, uint col, const TQString &s, bool blockwise )
684{
685 if (!isReadWrite())
686 return false;
687
688 if (s.isEmpty())
689 return true;
690
691 if (line == numLines())
692 editInsertLine(line,"");
693 else if (line > lastLine())
694 return false;
695
696 editStart ();
697
698 uint insertPos = col;
699 uint len = s.length();
700
701 TQString buf;
702
703 bool replacetabs = ( config()->configFlags() & KateDocumentConfig::cfReplaceTabsDyn && ! m_isInUndo );
704 uint tw = config()->tabWidth();
705 uint insertPosExpanded = insertPos;
706 KateTextLine::Ptr l = m_buffer->line( line );
707 if (l != 0)
708 insertPosExpanded = l->cursorX( insertPos, tw );
709
710 for (uint pos = 0; pos < len; pos++)
711 {
712 TQChar ch = s[pos];
713
714 if (ch == '\n')
715 {
716 editInsertText (line, insertPos, buf);
717
718 if ( !blockwise )
719 {
720 editWrapLine (line, insertPos + buf.length());
721 insertPos = insertPosExpanded = 0;
722 }
723 else
724 {
725 if ( line == lastLine() )
726 editWrapLine (line, insertPos + buf.length());
727 }
728
729 line++;
730 buf.truncate(0);
731 l = m_buffer->line( line );
732 if (l)
733 insertPosExpanded = l->cursorX( insertPos, tw );
734 }
735 else
736 {
737 if ( replacetabs && ch == '\t' )
738 {
739 uint tr = tw - ( insertPosExpanded+buf.length() )%tw;
740 for ( uint i=0; i < tr; i++ )
741 buf += ' ';
742 }
743 else
744 buf += ch; // append char to buffer
745 }
746 }
747
748 editInsertText (line, insertPos, buf);
749
750 editEnd ();
751 emit textInserted(line,insertPos);
752 return true;
753}
754
755bool KateDocument::removeText ( uint startLine, uint startCol, uint endLine, uint endCol )
756{
757 return removeText (startLine, startCol, endLine, endCol, false);
758}
759
760bool KateDocument::removeText ( uint startLine, uint startCol, uint endLine, uint endCol, bool blockwise)
761{
762 if (!isReadWrite())
763 return false;
764
765 if ( blockwise && (startCol > endCol) )
766 return false;
767
768 if ( startLine > endLine )
769 return false;
770
771 if ( startLine > lastLine() )
772 return false;
773
774 if (!blockwise) {
775 emit aboutToRemoveText(KateTextRange(startLine,startCol,endLine,endCol));
776 }
777 editStart ();
778
779 if ( !blockwise )
780 {
781 if ( endLine > lastLine() )
782 {
783 endLine = lastLine()+1;
784 endCol = 0;
785 }
786
787 if (startLine == endLine)
788 {
789 editRemoveText (startLine, startCol, endCol-startCol);
790 }
791 else if ((startLine+1) == endLine)
792 {
793 if ( (m_buffer->plainLine(startLine)->length()-startCol) > 0 )
794 editRemoveText (startLine, startCol, m_buffer->plainLine(startLine)->length()-startCol);
795
796 editRemoveText (startLine+1, 0, endCol);
797 editUnWrapLine (startLine);
798 }
799 else
800 {
801 for (uint line = endLine; line >= startLine; line--)
802 {
803 if ((line > startLine) && (line < endLine))
804 {
805 editRemoveLine (line);
806 }
807 else
808 {
809 if (line == endLine)
810 {
811 if ( endLine <= lastLine() )
812 editRemoveText (line, 0, endCol);
813 }
814 else
815 {
816 if ( (m_buffer->plainLine(line)->length()-startCol) > 0 )
817 editRemoveText (line, startCol, m_buffer->plainLine(line)->length()-startCol);
818
819 editUnWrapLine (startLine);
820 }
821 }
822
823 if ( line == 0 )
824 break;
825 }
826 }
827 } // if ( ! blockwise )
828 else
829 {
830 if ( endLine > lastLine() )
831 endLine = lastLine ();
832
833 for (uint line = endLine; line >= startLine; line--)
834 {
835
836 editRemoveText (line, startCol, endCol-startCol);
837
838 if ( line == 0 )
839 break;
840 }
841 }
842
843 editEnd ();
844 emit textRemoved();
845 return true;
846}
847
848bool KateDocument::insertLine( uint l, const TQString &str )
849{
850 if (!isReadWrite())
851 return false;
852
853 if (l > numLines())
854 return false;
855
856 return editInsertLine (l, str);
857}
858
859bool KateDocument::removeLine( uint line )
860{
861 if (!isReadWrite())
862 return false;
863
864 if (line > lastLine())
865 return false;
866
867 return editRemoveLine (line);
868}
869
870uint KateDocument::length() const
871{
872 uint l = 0;
873
874 for (uint i = 0; i < m_buffer->count(); i++)
875 {
876 KateTextLine::Ptr line = m_buffer->plainLine(i);
877
878 if (line)
879 l += line->length();
880 }
881
882 return l;
883}
884
885uint KateDocument::numLines() const
886{
887 return m_buffer->count();
888}
889
890uint KateDocument::numVisLines() const
891{
892 return m_buffer->countVisible ();
893}
894
895int KateDocument::lineLength ( uint line ) const
896{
897 KateTextLine::Ptr l = m_buffer->plainLine(line);
898
899 if (!l)
900 return -1;
901
902 return l->length();
903}
904//END
905
906//BEGIN KTextEditor::EditInterface internal stuff
907//
908// Starts an edit session with (or without) undo, update of view disabled during session
909//
910void KateDocument::editStart (bool withUndo)
911{
912 editSessionNumber++;
913
914 if (editSessionNumber > 1)
915 return;
916
917 editIsRunning = true;
918 editWithUndo = withUndo;
919
920 if (editWithUndo)
921 undoStart();
922 else
923 undoCancel();
924
925 for (uint z = 0; z < m_views.count(); z++)
926 {
927 m_views.at(z)->editStart ();
928 }
929
930 m_buffer->editStart ();
931}
932
933void KateDocument::undoStart()
934{
935 if (m_editCurrentUndo || (m_activeView && m_activeView->imComposeEvent())) return;
936
937 // Make sure the buffer doesn't get bigger than requested
938 if ((config()->undoSteps() > 0) && (undoItems.count() > config()->undoSteps()))
939 {
940 undoItems.setAutoDelete(true);
941 undoItems.removeFirst();
942 undoItems.setAutoDelete(false);
943 docWasSavedWhenUndoWasEmpty = false;
944 }
945
946 // new current undo item
947 m_editCurrentUndo = new KateUndoGroup(this);
948}
949
950void KateDocument::undoEnd()
951{
952 if (m_activeView && m_activeView->imComposeEvent())
953 return;
954
955 if (m_editCurrentUndo)
956 {
957 bool changedUndo = false;
958
959 if (m_editCurrentUndo->isEmpty())
960 delete m_editCurrentUndo;
961 else if (!m_undoDontMerge && undoItems.last() && undoItems.last()->merge(m_editCurrentUndo,m_undoComplexMerge))
962 delete m_editCurrentUndo;
963 else
964 {
965 undoItems.append(m_editCurrentUndo);
966 changedUndo = true;
967 }
968
969 m_undoDontMerge = false;
970 m_undoIgnoreCancel = true;
971
972 m_editCurrentUndo = 0L;
973
974 // (Re)Start the single-shot timer to cancel the undo merge
975 // the user has 5 seconds to input more data, or undo merging gets canceled for the current undo item.
976 m_undoMergeTimer->start(5000, true);
977
978 if (changedUndo)
979 emit undoChanged();
980 }
981}
982
983void KateDocument::undoCancel()
984{
985 if (m_undoIgnoreCancel) {
986 m_undoIgnoreCancel = false;
987 return;
988 }
989
990 m_undoDontMerge = true;
991
992 Q_ASSERT(!m_editCurrentUndo);
993
994 // As you can see by the above assert, neither of these should really be required
995 delete m_editCurrentUndo;
996 m_editCurrentUndo = 0L;
997}
998
999void KateDocument::undoSafePoint() {
1000 Q_ASSERT(m_editCurrentUndo);
1001 if (!m_editCurrentUndo) return;
1002 m_editCurrentUndo->safePoint();
1003}
1004
1005//
1006// End edit session and update Views
1007//
1008void KateDocument::editEnd ()
1009{
1010 if (editSessionNumber == 0)
1011 return;
1012
1013 // wrap the new/changed text, if something really changed!
1014 if (m_buffer->editChanged() && (editSessionNumber == 1))
1015 if (editWithUndo && config()->wordWrap())
1016 wrapText (m_buffer->editTagStart(), m_buffer->editTagEnd());
1017
1018 editSessionNumber--;
1019
1020 if (editSessionNumber > 0)
1021 return;
1022
1023 // end buffer edit, will trigger hl update
1024 // this will cause some possible adjustment of tagline start/end
1025 m_buffer->editEnd ();
1026
1027 if (editWithUndo)
1028 undoEnd();
1029
1030 // edit end for all views !!!!!!!!!
1031 for (uint z = 0; z < m_views.count(); z++)
1032 m_views.at(z)->editEnd (m_buffer->editTagStart(), m_buffer->editTagEnd(), m_buffer->editTagFrom());
1033
1034 if (m_buffer->editChanged())
1035 {
1036 setModified(true);
1037 emit textChanged ();
1038 }
1039
1040 editIsRunning = false;
1041}
1042
1043bool KateDocument::wrapText (uint startLine, uint endLine)
1044{
1045 uint col = config()->wordWrapAt();
1046
1047 if (col == 0)
1048 return false;
1049
1050 editStart ();
1051
1052 for (uint line = startLine; (line <= endLine) && (line < numLines()); line++)
1053 {
1054 KateTextLine::Ptr l = m_buffer->line(line);
1055
1056 if (!l)
1057 return false;
1058
1059 kdDebug (13020) << "try wrap line: " << line << endl;
1060
1061 if (l->lengthWithTabs(m_buffer->tabWidth()) > col)
1062 {
1063 KateTextLine::Ptr nextl = m_buffer->line(line+1);
1064
1065 kdDebug (13020) << "do wrap line: " << line << endl;
1066
1067 const TQChar *text = l->text();
1068 uint eolPosition = l->length()-1;
1069
1070 // take tabs into account here, too
1071 uint x = 0;
1072 const TQString & t = l->string();
1073 uint z2 = 0;
1074 for ( ; z2 < l->length(); z2++)
1075 {
1076 if (t[z2] == TQChar('\t'))
1077 x += m_buffer->tabWidth() - (x % m_buffer->tabWidth());
1078 else
1079 x++;
1080
1081 if (x > col)
1082 break;
1083 }
1084
1085 uint searchStart = kMin (z2, l->length()-1);
1086
1087 // If where we are wrapping is an end of line and is a space we don't
1088 // want to wrap there
1089 if (searchStart == eolPosition && text[searchStart].isSpace())
1090 searchStart--;
1091
1092 // Scan backwards looking for a place to break the line
1093 // We are not interested in breaking at the first char
1094 // of the line (if it is a space), but we are at the second
1095 // anders: if we can't find a space, try breaking on a word
1096 // boundry, using KateHighlight::canBreakAt().
1097 // This could be a priority (setting) in the hl/filetype/document
1098 int z = 0;
1099 uint nw = 0; // alternative position, a non word character
1100 for (z=searchStart; z > 0; z--)
1101 {
1102 if (text[z].isSpace()) break;
1103 if ( ! nw && highlight()->canBreakAt( text[z] , l->attribute(z) ) )
1104 nw = z;
1105 }
1106
1107 if (z > 0)
1108 {
1109 // cu space
1110 editRemoveText (line, z, 1);
1111 }
1112 else
1113 {
1114 // There was no space to break at so break at a nonword character if
1115 // found, or at the wrapcolumn ( that needs be configurable )
1116 // Don't try and add any white space for the break
1117 if ( nw && nw < col ) nw++; // break on the right side of the character
1118 z = nw ? nw : col;
1119 }
1120
1121 if (nextl && !nextl->isAutoWrapped())
1122 {
1123 editWrapLine (line, z, true);
1124 editMarkLineAutoWrapped (line+1, true);
1125
1126 endLine++;
1127 }
1128 else
1129 {
1130 if (nextl && (nextl->length() > 0) && !nextl->getChar(0).isSpace() && ((l->length() < 1) || !l->getChar(l->length()-1).isSpace()))
1131 editInsertText (line+1, 0, TQString (" "));
1132
1133 bool newLineAdded = false;
1134 editWrapLine (line, z, false, &newLineAdded);
1135
1136 editMarkLineAutoWrapped (line+1, true);
1137
1138 endLine++;
1139 }
1140 }
1141 }
1142
1143 editEnd ();
1144
1145 return true;
1146}
1147
1148void KateDocument::editAddUndo (KateUndoGroup::UndoType type, uint line, uint col, uint len, const TQString &text)
1149{
1150 if (editIsRunning && editWithUndo && m_editCurrentUndo) {
1151 m_editCurrentUndo->addItem(type, line, col, len, text);
1152
1153 // Clear redo buffer
1154 if (redoItems.count()) {
1155 redoItems.setAutoDelete(true);
1156 redoItems.clear();
1157 redoItems.setAutoDelete(false);
1158 }
1159 }
1160}
1161
1162bool KateDocument::editInsertText ( uint line, uint col, const TQString &str )
1163{
1164 if (!isReadWrite())
1165 return false;
1166
1167 TQString s = str;
1168
1169 KateTextLine::Ptr l = m_buffer->line(line);
1170
1171 if (!l)
1172 return false;
1173
1174 if ( config()->configFlags() & KateDocumentConfig::cfReplaceTabsDyn && ! m_isInUndo )
1175 {
1176 uint tw = config()->tabWidth();
1177 int pos = 0;
1178 uint l = 0;
1179 while ( (pos = s.find('\t')) > -1 )
1180 {
1181 l = tw - ( (col + pos)%tw );
1182 s.replace( pos, 1, TQString().fill( ' ', l ) );
1183 }
1184 }
1185
1186 editStart ();
1187
1188 editAddUndo (KateUndoGroup::editInsertText, line, col, s.length(), s);
1189
1190 l->insertText (col, s.length(), s.unicode());
1191// removeTrailingSpace(line); // ### nessecary?
1192
1193 m_buffer->changeLine(line);
1194
1195 for( TQPtrListIterator<KateSuperCursor> it (m_superCursors); it.current(); ++it )
1196 it.current()->editTextInserted (line, col, s.length());
1197
1198 editEnd ();
1199
1200 return true;
1201}
1202
1203bool KateDocument::editRemoveText ( uint line, uint col, uint len )
1204{
1205 if (!isReadWrite())
1206 return false;
1207
1208 KateTextLine::Ptr l = m_buffer->line(line);
1209
1210 if (!l)
1211 return false;
1212
1213 editStart ();
1214
1215 editAddUndo (KateUndoGroup::editRemoveText, line, col, len, l->string().mid(col, len));
1216
1217 l->removeText (col, len);
1218 removeTrailingSpace( line );
1219
1220 m_buffer->changeLine(line);
1221
1222 for( TQPtrListIterator<KateSuperCursor> it (m_superCursors); it.current(); ++it )
1223 it.current()->editTextRemoved (line, col, len);
1224
1225 editEnd ();
1226
1227 return true;
1228}
1229
1230bool KateDocument::editMarkLineAutoWrapped ( uint line, bool autowrapped )
1231{
1232 if (!isReadWrite())
1233 return false;
1234
1235 KateTextLine::Ptr l = m_buffer->line(line);
1236
1237 if (!l)
1238 return false;
1239
1240 editStart ();
1241
1242 editAddUndo (KateUndoGroup::editMarkLineAutoWrapped, line, autowrapped ? 1 : 0, 0, TQString::null);
1243
1244 l->setAutoWrapped (autowrapped);
1245
1246 m_buffer->changeLine(line);
1247
1248 editEnd ();
1249
1250 return true;
1251}
1252
1253bool KateDocument::editWrapLine ( uint line, uint col, bool newLine, bool *newLineAdded)
1254{
1255 if (!isReadWrite())
1256 return false;
1257
1258 KateTextLine::Ptr l = m_buffer->line(line);
1259
1260 if (!l)
1261 return false;
1262
1263 editStart ();
1264
1265 KateTextLine::Ptr nextLine = m_buffer->line(line+1);
1266
1267 int pos = l->length() - col;
1268
1269 if (pos < 0)
1270 pos = 0;
1271
1272 editAddUndo (KateUndoGroup::editWrapLine, line, col, pos, (!nextLine || newLine) ? "1" : "0");
1273
1274 if (!nextLine || newLine)
1275 {
1276 KateTextLine::Ptr textLine = new KateTextLine();
1277
1278 textLine->insertText (0, pos, l->text()+col, l->attributes()+col);
1279 l->truncate(col);
1280
1281 m_buffer->insertLine (line+1, textLine);
1282 m_buffer->changeLine(line);
1283
1284 TQPtrList<KTextEditor::Mark> list;
1285 for( TQIntDictIterator<KTextEditor::Mark> it( m_marks ); it.current(); ++it )
1286 {
1287 if( it.current()->line >= line )
1288 {
1289 if ((col == 0) || (it.current()->line > line))
1290 list.append( it.current() );
1291 }
1292 }
1293
1294 for( TQPtrListIterator<KTextEditor::Mark> it( list ); it.current(); ++it )
1295 {
1296 KTextEditor::Mark* mark = m_marks.take( it.current()->line );
1297 mark->line++;
1298 m_marks.insert( mark->line, mark );
1299 }
1300
1301 if( !list.isEmpty() )
1302 emit marksChanged();
1303
1304 // yes, we added a new line !
1305 if (newLineAdded)
1306 (*newLineAdded) = true;
1307 }
1308 else
1309 {
1310 nextLine->insertText (0, pos, l->text()+col, l->attributes()+col);
1311 l->truncate(col);
1312
1313 m_buffer->changeLine(line);
1314 m_buffer->changeLine(line+1);
1315
1316 // no, no new line added !
1317 if (newLineAdded)
1318 (*newLineAdded) = false;
1319 }
1320
1321 for( TQPtrListIterator<KateSuperCursor> it (m_superCursors); it.current(); ++it )
1322 it.current()->editLineWrapped (line, col, !nextLine || newLine);
1323
1324 editEnd ();
1325
1326 return true;
1327}
1328
1329bool KateDocument::editUnWrapLine ( uint line, bool removeLine, uint length )
1330{
1331 if (!isReadWrite())
1332 return false;
1333
1334 KateTextLine::Ptr l = m_buffer->line(line);
1335 KateTextLine::Ptr nextLine = m_buffer->line(line+1);
1336
1337 if (!l || !nextLine)
1338 return false;
1339
1340 editStart ();
1341
1342 uint col = l->length ();
1343
1344 editAddUndo (KateUndoGroup::editUnWrapLine, line, col, length, removeLine ? "1" : "0");
1345
1346 if (removeLine)
1347 {
1348 l->insertText (col, nextLine->length(), nextLine->text(), nextLine->attributes());
1349
1350 m_buffer->changeLine(line);
1351 m_buffer->removeLine(line+1);
1352 }
1353 else
1354 {
1355 l->insertText (col, (nextLine->length() < length) ? nextLine->length() : length,
1356 nextLine->text(), nextLine->attributes());
1357 nextLine->removeText (0, (nextLine->length() < length) ? nextLine->length() : length);
1358
1359 m_buffer->changeLine(line);
1360 m_buffer->changeLine(line+1);
1361 }
1362
1363 TQPtrList<KTextEditor::Mark> list;
1364 for( TQIntDictIterator<KTextEditor::Mark> it( m_marks ); it.current(); ++it )
1365 {
1366 if( it.current()->line >= line+1 )
1367 list.append( it.current() );
1368
1369 if ( it.current()->line == line+1 )
1370 {
1371 KTextEditor::Mark* mark = m_marks.take( line );
1372
1373 if (mark)
1374 {
1375 it.current()->type |= mark->type;
1376 }
1377 }
1378 }
1379
1380 for( TQPtrListIterator<KTextEditor::Mark> it( list ); it.current(); ++it )
1381 {
1382 KTextEditor::Mark* mark = m_marks.take( it.current()->line );
1383 mark->line--;
1384 m_marks.insert( mark->line, mark );
1385 }
1386
1387 if( !list.isEmpty() )
1388 emit marksChanged();
1389
1390 for( TQPtrListIterator<KateSuperCursor> it (m_superCursors); it.current(); ++it )
1391 it.current()->editLineUnWrapped (line, col, removeLine, length);
1392
1393 editEnd ();
1394
1395 return true;
1396}
1397
1398bool KateDocument::editInsertLine ( uint line, const TQString &s )
1399{
1400 if (!isReadWrite())
1401 return false;
1402
1403 if ( line > numLines() )
1404 return false;
1405
1406 editStart ();
1407
1408 editAddUndo (KateUndoGroup::editInsertLine, line, 0, s.length(), s);
1409
1410 removeTrailingSpace( line ); // old line
1411
1412 KateTextLine::Ptr tl = new KateTextLine();
1413 tl->insertText (0, s.length(), s.unicode(), 0);
1414 m_buffer->insertLine(line, tl);
1415 m_buffer->changeLine(line);
1416
1417 removeTrailingSpace( line ); // new line
1418
1419 TQPtrList<KTextEditor::Mark> list;
1420 for( TQIntDictIterator<KTextEditor::Mark> it( m_marks ); it.current(); ++it )
1421 {
1422 if( it.current()->line >= line )
1423 list.append( it.current() );
1424 }
1425
1426 for( TQPtrListIterator<KTextEditor::Mark> it( list ); it.current(); ++it )
1427 {
1428 KTextEditor::Mark* mark = m_marks.take( it.current()->line );
1429 mark->line++;
1430 m_marks.insert( mark->line, mark );
1431 }
1432
1433 if( !list.isEmpty() )
1434 emit marksChanged();
1435
1436 for( TQPtrListIterator<KateSuperCursor> it (m_superCursors); it.current(); ++it )
1437 it.current()->editLineInserted (line);
1438
1439 editEnd ();
1440
1441 return true;
1442}
1443
1444bool KateDocument::editRemoveLine ( uint line )
1445{
1446 if (!isReadWrite())
1447 return false;
1448
1449 if ( line > lastLine() )
1450 return false;
1451
1452 if ( numLines() == 1 )
1453 return editRemoveText (0, 0, m_buffer->line(0)->length());
1454
1455 editStart ();
1456
1457 editAddUndo (KateUndoGroup::editRemoveLine, line, 0, lineLength(line), textLine(line));
1458
1459 m_buffer->removeLine(line);
1460
1461 TQPtrList<KTextEditor::Mark> list;
1462 KTextEditor::Mark* rmark = 0;
1463 for( TQIntDictIterator<KTextEditor::Mark> it( m_marks ); it.current(); ++it )
1464 {
1465 if ( (it.current()->line > line) )
1466 list.append( it.current() );
1467 else if ( (it.current()->line == line) )
1468 rmark = it.current();
1469 }
1470
1471 if (rmark)
1472 delete (m_marks.take (rmark->line));
1473
1474 for( TQPtrListIterator<KTextEditor::Mark> it( list ); it.current(); ++it )
1475 {
1476 KTextEditor::Mark* mark = m_marks.take( it.current()->line );
1477 mark->line--;
1478 m_marks.insert( mark->line, mark );
1479 }
1480
1481 if( !list.isEmpty() )
1482 emit marksChanged();
1483
1484 for( TQPtrListIterator<KateSuperCursor> it (m_superCursors); it.current(); ++it )
1485 it.current()->editLineRemoved (line);
1486
1487 editEnd();
1488
1489 return true;
1490}
1491//END
1492
1493//BEGIN KTextEditor::UndoInterface stuff
1494
1495uint KateDocument::undoCount () const
1496{
1497 return undoItems.count ();
1498}
1499
1500uint KateDocument::redoCount () const
1501{
1502 return redoItems.count ();
1503}
1504
1505uint KateDocument::undoSteps () const
1506{
1507 return m_config->undoSteps();
1508}
1509
1510void KateDocument::setUndoSteps(uint steps)
1511{
1512 m_config->setUndoSteps (steps);
1513}
1514
1515void KateDocument::undo()
1516{
1517 m_isInUndo = true;
1518 if ((undoItems.count() > 0) && undoItems.last())
1519 {
1520 clearSelection ();
1521
1522 undoItems.last()->undo();
1523 redoItems.append (undoItems.last());
1524 undoItems.removeLast ();
1525 updateModified();
1526
1527 emit undoChanged ();
1528 }
1529 m_isInUndo = false;
1530}
1531
1532void KateDocument::redo()
1533{
1534 m_isInUndo = true;
1535 if ((redoItems.count() > 0) && redoItems.last())
1536 {
1537 clearSelection ();
1538
1539 redoItems.last()->redo();
1540 undoItems.append (redoItems.last());
1541 redoItems.removeLast ();
1542 updateModified();
1543
1544 emit undoChanged ();
1545 }
1546 m_isInUndo = false;
1547}
1548
1549void KateDocument::updateModified()
1550{
1551 /*
1552 How this works:
1553
1554 After noticing that there where to many scenarios to take into
1555 consideration when using 'if's to toggle the "Modified" flag
1556 I came up with this baby, flexible and repetitive calls are
1557 minimal.
1558
1559 A numeric unique pattern is generated by toggleing a set of bits,
1560 each bit symbolizes a different state in the Undo Redo structure.
1561
1562 undoItems.isEmpty() != null BIT 1
1563 redoItems.isEmpty() != null BIT 2
1564 docWasSavedWhenUndoWasEmpty == true BIT 3
1565 docWasSavedWhenRedoWasEmpty == true BIT 4
1566 lastUndoGroupWhenSavedIsLastUndo BIT 5
1567 lastUndoGroupWhenSavedIsLastRedo BIT 6
1568 lastRedoGroupWhenSavedIsLastUndo BIT 7
1569 lastRedoGroupWhenSavedIsLastRedo BIT 8
1570
1571 If you find a new pattern, please add it to the patterns array
1572 */
1573
1574 unsigned char currentPattern = 0;
1575 const unsigned char patterns[] = {5,16,24,26,88,90,93,133,144,149,165};
1576 const unsigned char patternCount = sizeof(patterns);
1577 KateUndoGroup* undoLast = 0;
1578 KateUndoGroup* redoLast = 0;
1579
1580 if (undoItems.isEmpty())
1581 {
1582 currentPattern |= 1;
1583 }
1584 else
1585 {
1586 undoLast = undoItems.last();
1587 }
1588
1589 if (redoItems.isEmpty())
1590 {
1591 currentPattern |= 2;
1592 }
1593 else
1594 {
1595 redoLast = redoItems.last();
1596 }
1597
1598 if (docWasSavedWhenUndoWasEmpty) currentPattern |= 4;
1599 if (docWasSavedWhenRedoWasEmpty) currentPattern |= 8;
1600 if (lastUndoGroupWhenSaved == undoLast) currentPattern |= 16;
1601 if (lastUndoGroupWhenSaved == redoLast) currentPattern |= 32;
1602 if (lastRedoGroupWhenSaved == undoLast) currentPattern |= 64;
1603 if (lastRedoGroupWhenSaved == redoLast) currentPattern |= 128;
1604
1605 // This will print out the pattern information
1606
1607 kdDebug(13020) << k_funcinfo
1608 << "Pattern:" << static_cast<unsigned int>(currentPattern) << endl;
1609
1610 for (uint patternIndex = 0; patternIndex < patternCount; ++patternIndex)
1611 {
1612 if ( currentPattern == patterns[patternIndex] )
1613 {
1614 setModified( false );
1615 kdDebug(13020) << k_funcinfo << "setting modified to false!" << endl;
1616 break;
1617 }
1618 }
1619}
1620
1621void KateDocument::clearUndo()
1622{
1623 undoItems.setAutoDelete (true);
1624 undoItems.clear ();
1625 undoItems.setAutoDelete (false);
1626
1627 lastUndoGroupWhenSaved = 0;
1628 docWasSavedWhenUndoWasEmpty = false;
1629
1630 emit undoChanged ();
1631}
1632
1633void KateDocument::clearRedo()
1634{
1635 redoItems.setAutoDelete (true);
1636 redoItems.clear ();
1637 redoItems.setAutoDelete (false);
1638
1639 lastRedoGroupWhenSaved = 0;
1640 docWasSavedWhenRedoWasEmpty = false;
1641
1642 emit undoChanged ();
1643}
1644
1645TQPtrList<KTextEditor::Cursor> KateDocument::cursors () const
1646{
1647 return myCursors;
1648}
1649//END
1650
1651//BEGIN KTextEditor::SearchInterface stuff
1652
1653bool KateDocument::searchText (unsigned int startLine, unsigned int startCol, const TQString &text, unsigned int *foundAtLine, unsigned int *foundAtCol, unsigned int *matchLen, bool casesensitive, bool backwards)
1654{
1655 if (text.isEmpty())
1656 return false;
1657
1658 int line = startLine;
1659 int col = startCol;
1660
1661 if (!backwards)
1662 {
1663 int searchEnd = lastLine();
1664
1665 while (line <= searchEnd)
1666 {
1667 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
1668
1669 if (!textLine)
1670 return false;
1671
1672 uint foundAt, myMatchLen;
1673 bool found = textLine->searchText (col, text, &foundAt, &myMatchLen, casesensitive, false);
1674
1675 if (found)
1676 {
1677 (*foundAtLine) = line;
1678 (*foundAtCol) = foundAt;
1679 (*matchLen) = myMatchLen;
1680 return true;
1681 }
1682
1683 col = 0;
1684 line++;
1685 }
1686 }
1687 else
1688 {
1689 // backward search
1690 int searchEnd = 0;
1691
1692 while (line >= searchEnd)
1693 {
1694 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
1695
1696 if (!textLine)
1697 return false;
1698
1699 uint foundAt, myMatchLen;
1700 bool found = textLine->searchText (col, text, &foundAt, &myMatchLen, casesensitive, true);
1701
1702 if (found)
1703 {
1704 /* if ((uint) line == startLine && foundAt + myMatchLen >= (uint) col
1705 && line == selectStart.line() && foundAt == (uint) selectStart.col()
1706 && line == selectEnd.line() && foundAt + myMatchLen == (uint) selectEnd.col())
1707 {
1708 // To avoid getting stuck at one match we skip a match if it is already
1709 // selected (most likely because it has just been found).
1710 if (foundAt > 0)
1711 col = foundAt - 1;
1712 else {
1713 if (--line >= 0)
1714 col = lineLength(line);
1715 }
1716 continue;
1717 }*/
1718
1719 (*foundAtLine) = line;
1720 (*foundAtCol) = foundAt;
1721 (*matchLen) = myMatchLen;
1722 return true;
1723 }
1724
1725 if (line >= 1)
1726 col = lineLength(line-1);
1727
1728 line--;
1729 }
1730 }
1731
1732 return false;
1733}
1734
1735bool KateDocument::searchText (unsigned int startLine, unsigned int startCol, const TQRegExp &regexp, unsigned int *foundAtLine, unsigned int *foundAtCol, unsigned int *matchLen, bool backwards)
1736{
1737 kdDebug(13020)<<"KateDocument::searchText( "<<startLine<<", "<<startCol<<", "<<TQString(regexp.pattern())<<", "<<backwards<<" )"<<endl;
1738 if (regexp.isEmpty() || !regexp.isValid())
1739 return false;
1740
1741 int line = startLine;
1742 int col = startCol;
1743
1744 if (!backwards)
1745 {
1746 int searchEnd = lastLine();
1747
1748 while (line <= searchEnd)
1749 {
1750 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
1751
1752 if (!textLine)
1753 return false;
1754
1755 uint foundAt, myMatchLen;
1756 bool found = textLine->searchText (col, regexp, &foundAt, &myMatchLen, false);
1757
1758 if (found)
1759 {
1760 // A special case which can only occur when searching with a regular expression consisting
1761 // only of a lookahead (e.g. ^(?=\{) for a function beginning without selecting '{').
1762 if (myMatchLen == 0 && (uint) line == startLine && foundAt == (uint) col)
1763 {
1764 if (col < lineLength(line))
1765 col++;
1766 else {
1767 line++;
1768 col = 0;
1769 }
1770 continue;
1771 }
1772
1773 (*foundAtLine) = line;
1774 (*foundAtCol) = foundAt;
1775 (*matchLen) = myMatchLen;
1776 return true;
1777 }
1778
1779 col = 0;
1780 line++;
1781 }
1782 }
1783 else
1784 {
1785 // backward search
1786 int searchEnd = 0;
1787
1788 while (line >= searchEnd)
1789 {
1790 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
1791
1792 if (!textLine)
1793 return false;
1794
1795 uint foundAt, myMatchLen;
1796 bool found = textLine->searchText (col, regexp, &foundAt, &myMatchLen, true);
1797
1798 if (found)
1799 {
1800 /*if ((uint) line == startLine && foundAt + myMatchLen >= (uint) col
1801 && line == selectStart.line() && foundAt == (uint) selectStart.col()
1802 && line == selectEnd.line() && foundAt + myMatchLen == (uint) selectEnd.col())
1803 {
1804 // To avoid getting stuck at one match we skip a match if it is already
1805 // selected (most likely because it has just been found).
1806 if (foundAt > 0)
1807 col = foundAt - 1;
1808 else {
1809 if (--line >= 0)
1810 col = lineLength(line);
1811 }
1812 continue;
1813 }*/
1814
1815 (*foundAtLine) = line;
1816 (*foundAtCol) = foundAt;
1817 (*matchLen) = myMatchLen;
1818 return true;
1819 }
1820
1821 if (line >= 1)
1822 col = lineLength(line-1);
1823
1824 line--;
1825 }
1826 }
1827
1828 return false;
1829}
1830//END
1831
1832//BEGIN KTextEditor::HighlightingInterface stuff
1833
1834uint KateDocument::hlMode ()
1835{
1836 return KateHlManager::self()->findHl(highlight());
1837}
1838
1839bool KateDocument::setHlMode (uint mode)
1840{
1841 m_buffer->setHighlight (mode);
1842
1843 if (true)
1844 {
1845 setDontChangeHlOnSave();
1846 return true;
1847 }
1848
1849 return false;
1850}
1851
1852void KateDocument::bufferHlChanged ()
1853{
1854 // update all views
1855 makeAttribs(false);
1856
1857 emit hlChanged();
1858}
1859
1860uint KateDocument::hlModeCount ()
1861{
1862 return KateHlManager::self()->highlights();
1863}
1864
1865TQString KateDocument::hlModeName (uint mode)
1866{
1867 return KateHlManager::self()->hlName (mode);
1868}
1869
1870TQString KateDocument::hlModeSectionName (uint mode)
1871{
1872 return KateHlManager::self()->hlSection (mode);
1873}
1874
1875void KateDocument::setDontChangeHlOnSave()
1876{
1877 hlSetByUser = true;
1878}
1879//END
1880
1881//BEGIN KTextEditor::ConfigInterface stuff
1882void KateDocument::readConfig(TDEConfig *config)
1883{
1884 config->setGroup("Kate Document Defaults");
1885
1886 // read max loadable blocks, more blocks will be swapped out
1887 KateBuffer::setMaxLoadedBlocks (config->readNumEntry("Maximal Loaded Blocks", KateBuffer::maxLoadedBlocks()));
1888
1889 KateDocumentConfig::global()->readConfig (config);
1890
1891 config->setGroup("Kate View Defaults");
1892 KateViewConfig::global()->readConfig (config);
1893
1894 config->setGroup("Kate Renderer Defaults");
1895 KateRendererConfig::global()->readConfig (config);
1896}
1897
1898void KateDocument::writeConfig(TDEConfig *config)
1899{
1900 config->setGroup("Kate Document Defaults");
1901
1902 // write max loadable blocks, more blocks will be swapped out
1903 config->writeEntry("Maximal Loaded Blocks", KateBuffer::maxLoadedBlocks());
1904
1905 KateDocumentConfig::global()->writeConfig (config);
1906
1907 config->setGroup("Kate View Defaults");
1908 KateViewConfig::global()->writeConfig (config);
1909
1910 config->setGroup("Kate Renderer Defaults");
1911 KateRendererConfig::global()->writeConfig (config);
1912}
1913
1914void KateDocument::readConfig()
1915{
1916 TDEConfig *config = tdeApp->config();
1917 readConfig (config);
1918}
1919
1920void KateDocument::writeConfig()
1921{
1922 TDEConfig *config = tdeApp->config();
1923 writeConfig (config);
1924 config->sync();
1925}
1926
1927void KateDocument::readSessionConfig(TDEConfig *tdeconfig)
1928{
1929 // restore the url
1930 KURL url (tdeconfig->readEntry("URL"));
1931
1932 // get the encoding
1933 TQString tmpenc=tdeconfig->readEntry("Encoding");
1934 if (!tmpenc.isEmpty() && (tmpenc != encoding()))
1935 setEncoding(tmpenc);
1936
1937 // open the file if url valid
1938 if (!url.isEmpty() && url.isValid())
1939 openURL (url);
1940
1941 // restore the hl stuff
1942 m_buffer->setHighlight(KateHlManager::self()->nameFind(tdeconfig->readEntry("Highlighting")));
1943
1944 if (hlMode() > 0)
1945 hlSetByUser = true;
1946
1947 // indent mode
1948 config()->setIndentationMode( (uint)tdeconfig->readNumEntry("Indentation Mode", config()->indentationMode() ) );
1949
1950 // Restore Bookmarks
1951 TQValueList<int> marks = tdeconfig->readIntListEntry("Bookmarks");
1952 for( uint i = 0; i < marks.count(); i++ )
1953 addMark( marks[i], KateDocument::markType01 );
1954}
1955
1956void KateDocument::writeSessionConfig(TDEConfig *tdeconfig)
1957{
1958 if ( m_url.isLocalFile() && !TDEGlobal::dirs()->relativeLocation("tmp", m_url.path()).startsWith("/"))
1959 return;
1960 // save url
1961 tdeconfig->writeEntry("URL", m_url.prettyURL() );
1962
1963 // save encoding
1964 tdeconfig->writeEntry("Encoding",encoding());
1965
1966 // save hl
1967 tdeconfig->writeEntry("Highlighting", highlight()->name());
1968
1969 tdeconfig->writeEntry("Indentation Mode", config()->indentationMode() );
1970
1971 // Save Bookmarks
1972 TQValueList<int> marks;
1973 for( TQIntDictIterator<KTextEditor::Mark> it( m_marks );
1974 it.current() && it.current()->type & KTextEditor::MarkInterface::markType01;
1975 ++it )
1976 marks << it.current()->line;
1977
1978 tdeconfig->writeEntry( "Bookmarks", marks );
1979}
1980
1981void KateDocument::configDialog()
1982{
1983 KDialogBase *kd = new KDialogBase ( KDialogBase::IconList,
1984 i18n("Configure"),
1985 KDialogBase::Ok | KDialogBase::Cancel | KDialogBase::Help,
1986 KDialogBase::Ok,
1987 tdeApp->mainWidget() );
1988
1989#ifndef TQ_WS_WIN //TODO: reenable
1990 KWin::setIcons( kd->winId(), tdeApp->icon(), tdeApp->miniIcon() );
1991#endif
1992
1993 TQPtrList<KTextEditor::ConfigPage> editorPages;
1994
1995 for (uint i = 0; i < KTextEditor::configInterfaceExtension (this)->configPages (); i++)
1996 {
1997 TQStringList path;
1998 path.clear();
1999 path << KTextEditor::configInterfaceExtension (this)->configPageName (i);
2000 TQVBox *page = kd->addVBoxPage(path, KTextEditor::configInterfaceExtension (this)->configPageFullName (i),
2001 KTextEditor::configInterfaceExtension (this)->configPagePixmap(i, TDEIcon::SizeMedium) );
2002
2003 editorPages.append (KTextEditor::configInterfaceExtension (this)->configPage(i, page));
2004 }
2005
2006 if (kd->exec())
2007 {
2008 KateDocumentConfig::global()->configStart ();
2009 KateViewConfig::global()->configStart ();
2010 KateRendererConfig::global()->configStart ();
2011
2012 for (uint i=0; i<editorPages.count(); i++)
2013 {
2014 editorPages.at(i)->apply();
2015 }
2016
2017 KateDocumentConfig::global()->configEnd ();
2018 KateViewConfig::global()->configEnd ();
2019 KateRendererConfig::global()->configEnd ();
2020
2021 writeConfig ();
2022 }
2023
2024 delete kd;
2025}
2026
2027uint KateDocument::mark( uint line )
2028{
2029 if( !m_marks[line] )
2030 return 0;
2031 return m_marks[line]->type;
2032}
2033
2034void KateDocument::setMark( uint line, uint markType )
2035{
2036 clearMark( line );
2037 addMark( line, markType );
2038}
2039
2040void KateDocument::clearMark( uint line )
2041{
2042 if( line > lastLine() )
2043 return;
2044
2045 if( !m_marks[line] )
2046 return;
2047
2048 KTextEditor::Mark* mark = m_marks.take( line );
2049 emit markChanged( *mark, MarkRemoved );
2050 emit marksChanged();
2051 delete mark;
2052 tagLines( line, line );
2053 repaintViews(true);
2054}
2055
2056void KateDocument::addMark( uint line, uint markType )
2057{
2058 if( line > lastLine())
2059 return;
2060
2061 if( markType == 0 )
2062 return;
2063
2064 if( m_marks[line] ) {
2065 KTextEditor::Mark* mark = m_marks[line];
2066
2067 // Remove bits already set
2068 markType &= ~mark->type;
2069
2070 if( markType == 0 )
2071 return;
2072
2073 // Add bits
2074 mark->type |= markType;
2075 } else {
2076 KTextEditor::Mark *mark = new KTextEditor::Mark;
2077 mark->line = line;
2078 mark->type = markType;
2079 m_marks.insert( line, mark );
2080 }
2081
2082 // Emit with a mark having only the types added.
2083 KTextEditor::Mark temp;
2084 temp.line = line;
2085 temp.type = markType;
2086 emit markChanged( temp, MarkAdded );
2087
2088 emit marksChanged();
2089 tagLines( line, line );
2090 repaintViews(true);
2091}
2092
2093void KateDocument::removeMark( uint line, uint markType )
2094{
2095 if( line > lastLine() )
2096 return;
2097 if( !m_marks[line] )
2098 return;
2099
2100 KTextEditor::Mark* mark = m_marks[line];
2101
2102 // Remove bits not set
2103 markType &= mark->type;
2104
2105 if( markType == 0 )
2106 return;
2107
2108 // Subtract bits
2109 mark->type &= ~markType;
2110
2111 // Emit with a mark having only the types removed.
2112 KTextEditor::Mark temp;
2113 temp.line = line;
2114 temp.type = markType;
2115 emit markChanged( temp, MarkRemoved );
2116
2117 if( mark->type == 0 )
2118 m_marks.remove( line );
2119
2120 emit marksChanged();
2121 tagLines( line, line );
2122 repaintViews(true);
2123}
2124
2125TQPtrList<KTextEditor::Mark> KateDocument::marks()
2126{
2127 TQPtrList<KTextEditor::Mark> list;
2128
2129 for( TQIntDictIterator<KTextEditor::Mark> it( m_marks );
2130 it.current(); ++it ) {
2131 list.append( it.current() );
2132 }
2133
2134 return list;
2135}
2136
2137void KateDocument::clearMarks()
2138{
2139 for( TQIntDictIterator<KTextEditor::Mark> it( m_marks );
2140 it.current(); ++it ) {
2141 KTextEditor::Mark* mark = it.current();
2142 emit markChanged( *mark, MarkRemoved );
2143 tagLines( mark->line, mark->line );
2144 }
2145
2146 m_marks.clear();
2147
2148 emit marksChanged();
2149 repaintViews(true);
2150}
2151
2152void KateDocument::setPixmap( MarkInterface::MarkTypes type, const TQPixmap& pixmap )
2153{
2154 m_markPixmaps.replace( type, new TQPixmap( pixmap ) );
2155}
2156
2157void KateDocument::setDescription( MarkInterface::MarkTypes type, const TQString& description )
2158{
2159 m_markDescriptions.replace( type, new TQString( description ) );
2160}
2161
2162TQPixmap *KateDocument::markPixmap( MarkInterface::MarkTypes type )
2163{
2164 return m_markPixmaps[type];
2165}
2166
2167TQColor KateDocument::markColor( MarkInterface::MarkTypes type )
2168{
2169 uint reserved = (0x1 << KTextEditor::MarkInterface::reservedMarkersCount()) - 1;
2170 if ((uint)type >= (uint)markType01 && (uint)type <= reserved) {
2171 return KateRendererConfig::global()->lineMarkerColor(type);
2172 } else {
2173 return TQColor();
2174 }
2175}
2176
2177TQString KateDocument::markDescription( MarkInterface::MarkTypes type )
2178{
2179 if( m_markDescriptions[type] )
2180 return *m_markDescriptions[type];
2181 return TQString::null;
2182}
2183
2184void KateDocument::setMarksUserChangable( uint markMask )
2185{
2186 m_editableMarks = markMask;
2187}
2188
2189uint KateDocument::editableMarks()
2190{
2191 return m_editableMarks;
2192}
2193//END
2194
2195//BEGIN KTextEditor::PrintInterface stuff
2196bool KateDocument::printDialog ()
2197{
2198 return KatePrinter::print (this);
2199}
2200
2201bool KateDocument::print ()
2202{
2203 return KatePrinter::print (this);
2204}
2205//END
2206
2207//BEGIN KTextEditor::DocumentInfoInterface (### unfinished)
2208TQString KateDocument::mimeType()
2209{
2210 KMimeType::Ptr result = KMimeType::defaultMimeTypePtr();
2211
2212 // if the document has a URL, try KMimeType::findByURL
2213 if ( ! m_url.isEmpty() )
2214 result = KMimeType::findByURL( m_url );
2215
2216 else if ( m_url.isEmpty() || ! m_url.isLocalFile() )
2217 result = mimeTypeForContent();
2218
2219 return result->name();
2220}
2221
2222// TODO implement this -- how to calculate?
2223long KateDocument::fileSize()
2224{
2225 return 0;
2226}
2227
2228// TODO implement this
2229TQString KateDocument::niceFileSize()
2230{
2231 return "UNKNOWN";
2232}
2233
2234KMimeType::Ptr KateDocument::mimeTypeForContent()
2235{
2236 TQByteArray buf (1024);
2237 uint bufpos = 0;
2238
2239 for (uint i=0; i < numLines(); i++)
2240 {
2241 TQString line = textLine( i );
2242 uint len = line.length() + 1;
2243
2244 if (bufpos + len > 1024)
2245 len = 1024 - bufpos;
2246
2247 memcpy(&buf[bufpos], (line + "\n").latin1(), len);
2248
2249 bufpos += len;
2250
2251 if (bufpos >= 1024)
2252 break;
2253 }
2254 buf.resize( bufpos );
2255
2256 int accuracy = 0;
2257 return KMimeType::findByContent( buf, &accuracy );
2258}
2259//END KTextEditor::DocumentInfoInterface
2260
2261
2262//BEGIN KParts::ReadWrite stuff
2263
2264bool KateDocument::openURL( const KURL &url )
2265{
2266// kdDebug(13020)<<"KateDocument::openURL( "<<url.prettyURL()<<")"<<endl;
2267 // no valid URL
2268 if ( !url.isValid() )
2269 return false;
2270
2271 // could not close old one
2272 if ( !closeURL() )
2273 return false;
2274
2275 // set my url
2276 m_url = url;
2277
2278 if ( m_url.isLocalFile() )
2279 {
2280 // local mode, just like in kpart
2281
2282 m_file = m_url.path();
2283
2284 emit started( 0 );
2285
2286 if (openFile())
2287 {
2288 emit completed();
2289 emit setWindowCaption( m_url.prettyURL() );
2290
2291 return true;
2292 }
2293
2294 return false;
2295 }
2296 else
2297 {
2298 // remote mode
2299
2300 m_bTemp = true;
2301
2302 m_tempFile = new KTempFile ();
2303 m_file = m_tempFile->name();
2304
2305 m_job = TDEIO::get ( url, false, isProgressInfoEnabled() );
2306
2307 // connect to slots
2308 connect( m_job, TQ_SIGNAL( data( TDEIO::Job*, const TQByteArray& ) ),
2309 TQ_SLOT( slotDataKate( TDEIO::Job*, const TQByteArray& ) ) );
2310
2311 connect( m_job, TQ_SIGNAL( result( TDEIO::Job* ) ),
2312 TQ_SLOT( slotFinishedKate( TDEIO::Job* ) ) );
2313
2314 TQWidget *w = widget ();
2315 if (!w && !m_views.isEmpty ())
2316 w = m_views.first();
2317
2318 if (w)
2319 m_job->setWindow (w->topLevelWidget());
2320
2321 emit started( m_job );
2322
2323 return true;
2324 }
2325}
2326
2327void KateDocument::slotDataKate ( TDEIO::Job *, const TQByteArray &data )
2328{
2329// kdDebug(13020) << "KateDocument::slotData" << endl;
2330
2331 if (!m_tempFile || !m_tempFile->file())
2332 return;
2333
2334 m_tempFile->file()->writeBlock (data);
2335}
2336
2337void KateDocument::slotFinishedKate ( TDEIO::Job * job )
2338{
2339// kdDebug(13020) << "KateDocument::slotJobFinished" << endl;
2340
2341 if (!m_tempFile)
2342 return;
2343
2344 delete m_tempFile;
2345 m_tempFile = 0;
2346 m_job = 0;
2347
2348 if (job->error())
2349 emit canceled( job->errorString() );
2350 else
2351 {
2352 if ( openFile(job) )
2353 emit setWindowCaption( m_url.prettyURL() );
2354 emit completed();
2355 }
2356}
2357
2358void KateDocument::abortLoadKate()
2359{
2360 if ( m_job )
2361 {
2362 kdDebug(13020) << "Aborting job " << m_job << endl;
2363 m_job->kill();
2364 m_job = 0;
2365 }
2366
2367 delete m_tempFile;
2368 m_tempFile = 0;
2369}
2370
2371bool KateDocument::openFile()
2372{
2373 return openFile (0);
2374}
2375
2376bool KateDocument::openFile(TDEIO::Job * job)
2377{
2378 m_loading = true;
2379 // add new m_file to dirwatch
2380 activateDirWatch ();
2381
2382 //
2383 // use metadata
2384 //
2385 if (job)
2386 {
2387 TQString metaDataCharset = job->queryMetaData("charset");
2388
2389 // only overwrite config if nothing set
2390 if (!metaDataCharset.isEmpty () && (!m_config->isSetEncoding() || m_config->encoding().isEmpty()))
2391 setEncoding (metaDataCharset);
2392 }
2393
2394 //
2395 // service type magic to get encoding right
2396 //
2397 TQString serviceType = m_extension->urlArgs().serviceType.simplifyWhiteSpace();
2398 int pos = serviceType.find(';');
2399 if (pos != -1)
2400 setEncoding (serviceType.mid(pos+1));
2401
2402 // if the encoding is set here - on the command line/from the dialog/from TDEIO
2403 // we prevent file type and document variables from changing it
2404 bool encodingSticky = m_encodingSticky;
2405 m_encodingSticky = m_config->isSetEncoding();
2406
2407 // Try getting the filetype here, so that variables does not have to be reset.
2408 int fileTypeFound = KateFactory::self()->fileTypeManager()->fileType (this);
2409 if ( fileTypeFound > -1 )
2410 updateFileType( fileTypeFound );
2411
2412 // read dir config (if possible and wanted)
2413 if (!m_reloading)
2414 readDirConfig ();
2415
2416 // do we have success ?
2417 bool success = m_buffer->openFile (m_file);
2418 //
2419 // yeah, success
2420 //
2421 m_loading = false; // done reading file.
2422 if (success)
2423 {
2424 /*if (highlight() && !m_url.isLocalFile()) {
2425 // The buffer's highlighting gets nuked by KateBuffer::clear()
2426 m_buffer->setHighlight(m_highlight);
2427 }*/
2428
2429 // update our hl type if needed
2430 if (!hlSetByUser)
2431 {
2432 int hl (KateHlManager::self()->detectHighlighting (this));
2433
2434 if (hl >= 0)
2435 m_buffer->setHighlight(hl);
2436 }
2437
2438 // update file type if we haven't allready done so.
2439 if ( fileTypeFound < 0 )
2440 updateFileType (KateFactory::self()->fileTypeManager()->fileType (this));
2441
2442 // read vars
2443 readVariables();
2444
2445 // update the md5 digest
2446 createDigest( m_digest );
2447 }
2448
2449 //
2450 // update views
2451 //
2452 for (KateView * view = m_views.first(); view != 0L; view = m_views.next() )
2453 {
2454 view->updateView(true);
2455 }
2456
2457 //
2458 // emit the signal we need for example for kate app
2459 //
2460 emit fileNameChanged ();
2461
2462 //
2463 // set doc name, dummy value as arg, don't need it
2464 //
2465 setDocName (TQString::null);
2466
2467 //
2468 // to houston, we are not modified
2469 //
2470 if (m_modOnHd)
2471 {
2472 m_modOnHd = false;
2473 m_modOnHdReason = 0;
2474 emit modifiedOnDisc (this, m_modOnHd, 0);
2475 }
2476
2477 //
2478 // display errors
2479 //
2480 if (s_openErrorDialogsActivated)
2481 {
2482 if (!success && m_buffer->loadingBorked())
2483 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()));
2484 else if (!success)
2485 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()));
2486 }
2487
2488 // warn -> opened binary file!!!!!!!
2489 if (m_buffer->binary())
2490 {
2491 // this file can't be saved again without killing it
2492 setReadWrite( false );
2493
2494 KMessageBox::information (widget()
2495 , i18n ("The file %1 is a binary, saving it will result in a corrupt file.").arg(m_url.url())
2496 , i18n ("Binary File Opened")
2497 , "Binary File Opened Warning");
2498 }
2499
2500 m_encodingSticky = encodingSticky;
2501
2502 //
2503 // return the success
2504 //
2505 return success;
2506}
2507
2508bool KateDocument::save()
2509{
2510 bool l ( url().isLocalFile() );
2511
2512 if ( ( l && config()->backupFlags() & KateDocumentConfig::LocalFiles )
2513 || ( ! l && config()->backupFlags() & KateDocumentConfig::RemoteFiles ) )
2514 {
2515 KURL u( url() );
2516 u.setFileName( config()->backupPrefix() + url().fileName() + config()->backupSuffix() );
2517
2518 kdDebug () << "backup src file name: " << url() << endl;
2519 kdDebug () << "backup dst file name: " << u << endl;
2520
2521 // get the right permissions, start with safe default
2522 mode_t perms = 0600;
2523 TDEIO::UDSEntry fentry;
2524 if (TDEIO::NetAccess::stat (url(), fentry, tdeApp->mainWidget()))
2525 {
2526 kdDebug () << "stating succesfull: " << url() << endl;
2527 KFileItem item (fentry, url());
2528 perms = item.permissions();
2529 }
2530
2531 // first del existing file if any, than copy over the file we have
2532 // failure if a: the existing file could not be deleted, b: the file could not be copied
2533 if ( (!TDEIO::NetAccess::exists( u, false, tdeApp->mainWidget() ) || TDEIO::NetAccess::del( u, tdeApp->mainWidget() ))
2534 && TDEIO::NetAccess::file_copy( url(), u, perms, true, false, tdeApp->mainWidget() ) )
2535 {
2536 kdDebug(13020)<<"backing up successfull ("<<url().prettyURL()<<" -> "<<u.prettyURL()<<")"<<endl;
2537 }
2538 else
2539 {
2540 kdDebug(13020)<<"backing up failed ("<<url().prettyURL()<<" -> "<<u.prettyURL()<<")"<<endl;
2541 // FIXME: notify user for real ;)
2542 }
2543 }
2544
2545 return KParts::ReadWritePart::save();
2546}
2547
2548bool KateDocument::saveFile()
2549{
2550 //
2551 // we really want to save this file ?
2552 //
2553 if (m_buffer->loadingBorked() && (KMessageBox::warningContinueCancel(widget(),
2554 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))
2555 return false;
2556
2557 //
2558 // warn -> try to save binary file!!!!!!!
2559 //
2560 if (m_buffer->binary() && (KMessageBox::warningContinueCancel (widget()
2561 , i18n ("The file %1 is a binary, saving it will result in a corrupt file.").arg(m_url.url())
2562 , i18n ("Trying to Save Binary File")
2563 , i18n("Save Nevertheless"), "Binary File Save Warning") != KMessageBox::Continue))
2564 return false;
2565
2566 if ( !url().isEmpty() )
2567 {
2568 if (s_fileChangedDialogsActivated && m_modOnHd)
2569 {
2570 TQString str = reasonedMOHString() + "\n\n";
2571
2572 if (!isModified())
2573 {
2574 if (KMessageBox::warningContinueCancel(0,
2575 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)
2576 return false;
2577 }
2578 else
2579 {
2580 if (KMessageBox::warningContinueCancel(0,
2581 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)
2582 return false;
2583 }
2584 }
2585 }
2586
2587 //
2588 // can we encode it if we want to save it ?
2589 //
2590 if (!m_buffer->canEncode ()
2591 && (KMessageBox::warningContinueCancel(0,
2592 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))
2593 {
2594 return false;
2595 }
2596
2597 // remove file from dirwatch
2598 deactivateDirWatch ();
2599
2600 //
2601 // try to save
2602 //
2603 bool success = m_buffer->saveFile (m_file);
2604
2605 // update the md5 digest
2606 createDigest( m_digest );
2607
2608 // add m_file again to dirwatch
2609 activateDirWatch ();
2610
2611 //
2612 // hurray, we had success, do stuff we need
2613 //
2614 if (success)
2615 {
2616 // update our hl type if needed
2617 if (!hlSetByUser)
2618 {
2619 int hl (KateHlManager::self()->detectHighlighting (this));
2620
2621 if (hl >= 0)
2622 m_buffer->setHighlight(hl);
2623 }
2624
2625 // read our vars
2626 readVariables();
2627 }
2628
2629 //
2630 // we are not modified
2631 //
2632 if (success && m_modOnHd)
2633 {
2634 m_modOnHd = false;
2635 m_modOnHdReason = 0;
2636 emit modifiedOnDisc (this, m_modOnHd, 0);
2637 }
2638
2639 //
2640 // display errors
2641 //
2642 if (!success)
2643 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()));
2644
2645 //
2646 // return success
2647 //
2648 return success;
2649}
2650
2651bool KateDocument::saveAs( const KURL &u )
2652{
2653 TQString oldDir = url().directory();
2654
2655 if ( KParts::ReadWritePart::saveAs( u ) )
2656 {
2657 // null means base on filename
2658 setDocName( TQString::null );
2659
2660 if ( u.directory() != oldDir )
2661 readDirConfig();
2662
2663 emit fileNameChanged();
2664 emit nameChanged((Kate::Document *) this);
2665
2666 return true;
2667 }
2668
2669 return false;
2670}
2671
2672void KateDocument::readDirConfig ()
2673{
2674 int depth = config()->searchDirConfigDepth ();
2675
2676 if (m_url.isLocalFile() && (depth > -1))
2677 {
2678 TQString currentDir = TQFileInfo (m_file).dirPath();
2679
2680 // only search as deep as specified or not at all ;)
2681 while (depth > -1)
2682 {
2683 kdDebug (13020) << "search for config file in path: " << currentDir << endl;
2684
2685 // try to open config file in this dir
2686 TQFile f (currentDir + "/.kateconfig");
2687
2688 if (f.open (IO_ReadOnly))
2689 {
2690 TQTextStream stream (&f);
2691
2692 uint linesRead = 0;
2693 TQString line = stream.readLine();
2694 while ((linesRead < 32) && !line.isNull())
2695 {
2696 readVariableLine( line );
2697
2698 line = stream.readLine();
2699
2700 linesRead++;
2701 }
2702
2703 break;
2704 }
2705
2706 TQString newDir = TQFileInfo (currentDir).dirPath();
2707
2708 // bail out on looping (for example reached /)
2709 if (currentDir == newDir)
2710 break;
2711
2712 currentDir = newDir;
2713 --depth;
2714 }
2715 }
2716}
2717
2718void KateDocument::activateDirWatch ()
2719{
2720 // same file as we are monitoring, return
2721 if (m_file == m_dirWatchFile)
2722 return;
2723
2724 // remove the old watched file
2725 deactivateDirWatch ();
2726
2727 // add new file if needed
2728 if (m_url.isLocalFile() && !m_file.isEmpty())
2729 {
2730 KateFactory::self()->dirWatch ()->addFile (m_file);
2731 m_dirWatchFile = m_file;
2732 }
2733}
2734
2735void KateDocument::deactivateDirWatch ()
2736{
2737 if (!m_dirWatchFile.isEmpty())
2738 KateFactory::self()->dirWatch ()->removeFile (m_dirWatchFile);
2739
2740 m_dirWatchFile = TQString::null;
2741}
2742
2743bool KateDocument::closeURL()
2744{
2745 abortLoadKate();
2746
2747 //
2748 // file mod on hd
2749 //
2750 if ( !m_reloading && !url().isEmpty() )
2751 {
2752 if (s_fileChangedDialogsActivated && m_modOnHd)
2753 {
2754 if (!(KMessageBox::warningContinueCancel(
2755 widget(),
2756 reasonedMOHString() + "\n\n" + i18n("Do you really want to continue to close this file? Data loss may occur."),
2757 i18n("Possible Data Loss"), i18n("Close Nevertheless"),
2758 TQString("kate_close_modonhd_%1").arg( m_modOnHdReason ) ) == KMessageBox::Continue))
2759 return false;
2760 }
2761 }
2762
2763 //
2764 // first call the normal tdeparts implementation
2765 //
2766 if (!KParts::ReadWritePart::closeURL ())
2767 return false;
2768
2769 // remove file from dirwatch
2770 deactivateDirWatch ();
2771
2772 //
2773 // empty url + filename
2774 //
2775 m_url = KURL ();
2776 m_file = TQString::null;
2777
2778 // we are not modified
2779 if (m_modOnHd)
2780 {
2781 m_modOnHd = false;
2782 m_modOnHdReason = 0;
2783 emit modifiedOnDisc (this, m_modOnHd, 0);
2784 }
2785
2786 // clear the buffer
2787 m_buffer->clear();
2788
2789 // remove all marks
2790 clearMarks ();
2791
2792 // clear undo/redo history
2793 clearUndo();
2794 clearRedo();
2795
2796 // no, we are no longer modified
2797 setModified(false);
2798
2799 // we have no longer any hl
2800 m_buffer->setHighlight(0);
2801
2802 // update all our views
2803 for (KateView * view = m_views.first(); view != 0L; view = m_views.next() )
2804 {
2805 // Explicitly call the internal version because we don't want this to look like
2806 // an external request (and thus have the view not TQWidget::scroll()ed.
2807 view->setCursorPositionInternal(0, 0, 1, false);
2808 view->clearSelection();
2809 view->updateView(true);
2810 }
2811
2812 // uh, filename changed
2813 emit fileNameChanged ();
2814
2815 // update doc name
2816 setDocName (TQString::null);
2817
2818 // success
2819 return true;
2820}
2821
2822void KateDocument::setReadWrite( bool rw )
2823{
2824 if (isReadWrite() != rw)
2825 {
2826 KParts::ReadWritePart::setReadWrite (rw);
2827
2828 for( KateView* view = m_views.first(); view != 0L; view = m_views.next() )
2829 {
2830 view->slotUpdate();
2831 view->slotReadWriteChanged ();
2832 }
2833 }
2834}
2835
2836void KateDocument::setModified(bool m) {
2837
2838 if (isModified() != m) {
2839 KParts::ReadWritePart::setModified (m);
2840
2841 for( KateView* view = m_views.first(); view != 0L; view = m_views.next() )
2842 {
2843 view->slotUpdate();
2844 }
2845
2846 emit modifiedChanged ();
2847 emit modStateChanged ((Kate::Document *)this);
2848 }
2849 if ( m == false )
2850 {
2851 if ( ! undoItems.isEmpty() )
2852 {
2853 lastUndoGroupWhenSaved = undoItems.last();
2854 }
2855
2856 if ( ! redoItems.isEmpty() )
2857 {
2858 lastRedoGroupWhenSaved = redoItems.last();
2859 }
2860
2861 docWasSavedWhenUndoWasEmpty = undoItems.isEmpty();
2862 docWasSavedWhenRedoWasEmpty = redoItems.isEmpty();
2863 }
2864}
2865//END
2866
2867//BEGIN Kate specific stuff ;)
2868
2869void KateDocument::makeAttribs(bool needInvalidate)
2870{
2871 for (uint z = 0; z < m_views.count(); z++)
2872 m_views.at(z)->renderer()->updateAttributes ();
2873
2874 if (needInvalidate)
2875 m_buffer->invalidateHighlighting();
2876
2877 tagAll ();
2878}
2879
2880// the attributes of a hl have changed, update
2881void KateDocument::internalHlChanged()
2882{
2883 makeAttribs();
2884}
2885
2886void KateDocument::addView(KTextEditor::View *view) {
2887 if (!view)
2888 return;
2889
2890 m_views.append( (KateView *) view );
2891 m_textEditViews.append( view );
2892
2893 // apply the view & renderer vars from the file type
2894 const KateFileType *t = 0;
2895 if ((m_fileType > -1) && (t = KateFactory::self()->fileTypeManager()->fileType(m_fileType)))
2896 readVariableLine (t->varLine, true);
2897
2898 // apply the view & renderer vars from the file
2899 readVariables (true);
2900
2901 m_activeView = (KateView *) view;
2902}
2903
2904void KateDocument::removeView(KTextEditor::View *view) {
2905 if (!view)
2906 return;
2907
2908 if (m_activeView == view)
2909 m_activeView = 0L;
2910
2911 m_views.removeRef( (KateView *) view );
2912 m_textEditViews.removeRef( view );
2913}
2914
2915void KateDocument::addSuperCursor(KateSuperCursor *cursor, bool privateC) {
2916 if (!cursor)
2917 return;
2918
2919 m_superCursors.append( cursor );
2920
2921 if (!privateC)
2922 myCursors.append( cursor );
2923}
2924
2925void KateDocument::removeSuperCursor(KateSuperCursor *cursor, bool privateC) {
2926 if (!cursor)
2927 return;
2928
2929 if (!privateC)
2930 myCursors.removeRef( cursor );
2931
2932 m_superCursors.removeRef( cursor );
2933}
2934
2935bool KateDocument::ownedView(KateView *view) {
2936 // do we own the given view?
2937 return (m_views.containsRef(view) > 0);
2938}
2939
2940bool KateDocument::isLastView(int numViews) {
2941 return ((int) m_views.count() == numViews);
2942}
2943
2944uint KateDocument::currentColumn( const KateTextCursor& cursor )
2945{
2946 KateTextLine::Ptr textLine = m_buffer->plainLine(cursor.line());
2947
2948 if (textLine)
2949 return textLine->cursorX(cursor.col(), config()->tabWidth());
2950 else
2951 return 0;
2952}
2953
2954bool KateDocument::typeChars ( KateView *view, const TQString &chars )
2955{
2956 KateTextLine::Ptr textLine = m_buffer->plainLine(view->cursorLine ());
2957
2958 if (!textLine)
2959 return false;
2960
2961 bool bracketInserted = false;
2962 TQString buf;
2963 TQChar c;
2964
2965 for( uint z = 0; z < chars.length(); z++ )
2966 {
2967 TQChar ch = c = chars[z];
2968 if (ch.isPrint() || ch == '\t')
2969 {
2970 buf.append (ch);
2971
2972 if (!bracketInserted && (config()->configFlags() & KateDocument::cfAutoBrackets))
2973 {
2974 TQChar end_ch;
2975 bool complete = true;
2976 TQChar prevChar = textLine->getChar(view->cursorColumnReal()-1);
2977 TQChar nextChar = textLine->getChar(view->cursorColumnReal());
2978 switch(ch) {
2979 case '(': end_ch = ')'; break;
2980 case '[': end_ch = ']'; break;
2981 case '{': end_ch = '}'; break;
2982 case '\'':end_ch = '\'';break;
2983 case '"': end_ch = '"'; break;
2984 default: complete = false;
2985 }
2986 if (complete)
2987 {
2988 if (view->hasSelection())
2989 { // there is a selection, enclose the selection
2990 buf.append (view->selection());
2991 buf.append (end_ch);
2992 bracketInserted = true;
2993 }
2994 else
2995 { // no selection, check whether we should better refuse to complete
2996 if ( ( (ch == '\'' || ch == '"') &&
2997 (prevChar.isLetterOrNumber() || prevChar == ch) )
2998 || nextChar.isLetterOrNumber()
2999 || (nextChar == end_ch && prevChar != ch) )
3000 {
3001 kdDebug(13020) << "AutoBracket refused before: " << nextChar << "\n";
3002 }
3003 else
3004 {
3005 buf.append (end_ch);
3006 bracketInserted = true;
3007 }
3008 }
3009 }
3010 }
3011 }
3012 }
3013
3014 if (buf.isEmpty())
3015 return false;
3016
3017 editStart ();
3018
3019 if (!view->config()->persistentSelection() && view->hasSelection() )
3020 view->removeSelectedText();
3021
3022 int oldLine = view->cursorLine ();
3023 int oldCol = view->cursorColumnReal ();
3024
3025
3026 if (config()->configFlags() & KateDocument::cfOvr)
3027 removeText (view->cursorLine(), view->cursorColumnReal(), view->cursorLine(), kMin( view->cursorColumnReal()+buf.length(), textLine->length() ) );
3028
3029 insertText (view->cursorLine(), view->cursorColumnReal(), buf);
3030 m_indenter->processChar(c);
3031
3032 editEnd ();
3033
3034 if (bracketInserted)
3035 view->setCursorPositionInternal (view->cursorLine(), view->cursorColumnReal()-1);
3036
3037 emit charactersInteractivelyInserted (oldLine, oldCol, chars);
3038
3039 return true;
3040}
3041
3042void KateDocument::newLine( KateTextCursor& c, KateViewInternal *v )
3043{
3044 editStart();
3045
3046 if( !v->view()->config()->persistentSelection() && v->view()->hasSelection() )
3047 v->view()->removeSelectedText();
3048
3049 // temporary hack to get the cursor pos right !!!!!!!!!
3050 c = v->getCursor ();
3051
3052 if (c.line() > (int)lastLine())
3053 c.setLine(lastLine());
3054
3055 if ( c.line() < 0 )
3056 c.setLine( 0 );
3057
3058 uint ln = c.line();
3059
3060 KateTextLine::Ptr textLine = kateTextLine(c.line());
3061
3062 if (c.col() > (int)textLine->length())
3063 c.setCol(textLine->length());
3064
3065 if (m_indenter->canProcessNewLine ())
3066 {
3067 int pos = textLine->firstChar();
3068
3069 // length should do the job better
3070 if (pos < 0)
3071 pos = textLine->length();
3072
3073 if (c.col() < pos)
3074 c.setCol(pos); // place cursor on first char if before
3075
3076 editWrapLine (c.line(), c.col());
3077
3078 KateDocCursor cursor (c.line() + 1, pos, this);
3079 m_indenter->processNewline(cursor, true);
3080
3081 c.setPos(cursor);
3082 }
3083 else
3084 {
3085 editWrapLine (c.line(), c.col());
3086 c.setPos(c.line() + 1, 0);
3087 }
3088
3089 removeTrailingSpace( ln );
3090
3091 editEnd();
3092}
3093
3094void KateDocument::transpose( const KateTextCursor& cursor)
3095{
3096 KateTextLine::Ptr textLine = m_buffer->plainLine(cursor.line());
3097
3098 if (!textLine || (textLine->length() < 2))
3099 return;
3100
3101 uint col = cursor.col();
3102
3103 if (col > 0)
3104 col--;
3105
3106 if ((textLine->length() - col) < 2)
3107 return;
3108
3109 uint line = cursor.line();
3110 TQString s;
3111
3112 //clever swap code if first character on the line swap right&left
3113 //otherwise left & right
3114 s.append (textLine->getChar(col+1));
3115 s.append (textLine->getChar(col));
3116 //do the swap
3117
3118 // do it right, never ever manipulate a textline
3119 editStart ();
3120 editRemoveText (line, col, 2);
3121 editInsertText (line, col, s);
3122 editEnd ();
3123}
3124
3125void KateDocument::backspace( KateView *view, const KateTextCursor& c )
3126{
3127 if ( !view->config()->persistentSelection() && view->hasSelection() ) {
3128 view->removeSelectedText();
3129 return;
3130 }
3131
3132 uint col = kMax( c.col(), 0 );
3133 uint line = kMax( c.line(), 0 );
3134
3135 if ((col == 0) && (line == 0))
3136 return;
3137
3138 KateTextLine::Ptr tl = m_buffer->plainLine(line);
3139 if (!tl)
3140 {
3141 return;
3142 }
3143
3144 // Make sure to handle surrogate pairs correctly
3145 uint fromCol = col - 1;
3146 TQChar prevChar = tl->getChar(col - 1);
3147 if (prevChar.isLowSurrogate() && tl->getChar(col - 2).isHighSurrogate())
3148 {
3149 fromCol = col - 2;
3150 prevChar = tl->getChar(col - 2);
3151 }
3152
3153 int complement = 0;
3154 if (col > 0)
3155 {
3156 if (config()->configFlags() & KateDocument::cfAutoBrackets)
3157 {
3158 // if inside empty (), {}, [], '', "" delete both
3159 TQChar nextChar = tl->getChar(col);
3160
3161 if ( (prevChar == '"' && nextChar == '"') ||
3162 (prevChar == '\'' && nextChar == '\'') ||
3163 (prevChar == '(' && nextChar == ')') ||
3164 (prevChar == '[' && nextChar == ']') ||
3165 (prevChar == '{' && nextChar == '}') )
3166 {
3167 complement = 1;
3168 }
3169 }
3170 if (!(config()->configFlags() & KateDocument::cfBackspaceIndents))
3171 {
3172 // ordinary backspace
3173 removeText(line, fromCol, line, col+complement);
3174 }
3175 else
3176 {
3177 // backspace indents: erase to next indent position
3178 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
3179
3180 // don't forget this check!!!! really!!!!
3181 if (!textLine)
3182 return;
3183
3184 int colX = textLine->cursorX(col, config()->tabWidth());
3185 int pos = textLine->firstChar();
3186 if (pos > 0)
3187 pos = textLine->cursorX(pos, config()->tabWidth());
3188
3189 if (pos < 0 || pos >= (int)colX)
3190 {
3191 // only spaces on left side of cursor
3192 indent( view, line, -1);
3193 }
3194 else
3195 removeText(line, col-1, line, col+complement);
3196 }
3197 }
3198 else
3199 {
3200 // col == 0: wrap to previous line
3201 if (line >= 1)
3202 {
3203 KateTextLine::Ptr textLine = m_buffer->plainLine(line-1);
3204
3205 // don't forget this check!!!! really!!!!
3206 if (!textLine)
3207 return;
3208
3209 if (config()->wordWrap() && textLine->endingWith(TQString::fromLatin1(" ")))
3210 {
3211 // gg: in hard wordwrap mode, backspace must also eat the trailing space
3212 removeText (line-1, textLine->length()-1, line, 0);
3213 }
3214 else
3215 removeText (line-1, textLine->length(), line, 0);
3216 }
3217 }
3218
3219 emit backspacePressed();
3220}
3221
3222void KateDocument::del( KateView *view, const KateTextCursor& c )
3223{
3224 if ( !view->config()->persistentSelection() && view->hasSelection() ) {
3225 view->removeSelectedText();
3226 return;
3227 }
3228
3229 KateTextLine::Ptr tl = m_buffer->plainLine(c.line());
3230 if (!tl)
3231 {
3232 return;
3233 }
3234 uint lineLen = tl->length();
3235 uint col = (uint)c.col();
3236 if (col < lineLen)
3237 {
3238 // Make sure to handle surrogate pairs correctly
3239 uint toCol = col + 1;
3240 if (tl->getChar(col).isHighSurrogate() && tl->getChar(col + 1).isLowSurrogate())
3241 {
3242 toCol = col + 2;
3243 }
3244
3245 removeText(c.line(), col, c.line(), toCol);
3246 }
3247 else if ( (uint)c.line() < lastLine() )
3248 {
3249 removeText(c.line(), c.col(), c.line()+1, 0);
3250 }
3251}
3252
3253void KateDocument::paste ( KateView* view )
3254{
3255 TQString s = TQApplication::clipboard()->text();
3256
3257 if (s.isEmpty())
3258 return;
3259
3260 uint lines = s.contains (TQChar ('\n'));
3261
3262 m_undoDontMerge = true;
3263
3264 editStart ();
3265
3266 if (!view->config()->persistentSelection() && view->hasSelection() )
3267 view->removeSelectedText();
3268
3269 uint line = view->cursorLine ();
3270 uint column = view->cursorColumnReal ();
3271
3272 insertText ( line, column, s, view->blockSelectionMode() );
3273
3274 editEnd();
3275
3276 // move cursor right for block select, as the user is moved right internal
3277 // even in that case, but user expects other behavior in block selection
3278 // mode !
3279 if (view->blockSelectionMode())
3280 view->setCursorPositionInternal (line+lines, column);
3281
3282 if (m_indenter->canProcessLine()
3283 && config()->configFlags() & KateDocumentConfig::cfIndentPastedText)
3284 {
3285 editStart();
3286
3287 KateDocCursor begin(line, 0, this);
3288 KateDocCursor end(line + lines, 0, this);
3289
3290 m_indenter->processSection (begin, end);
3291
3292 editEnd();
3293 }
3294
3295 if (!view->blockSelectionMode()) emit charactersSemiInteractivelyInserted (line, column, s);
3296 m_undoDontMerge = true;
3297}
3298
3299void KateDocument::insertIndentChars ( KateView *view )
3300{
3301 editStart ();
3302
3303 TQString s;
3304 if (config()->configFlags() & KateDocument::cfSpaceIndent)
3305 {
3306 int width = config()->indentationWidth();
3307 s.fill (' ', width - (view->cursorColumnReal() % width));
3308 }
3309 else
3310 s.append ('\t');
3311
3312 insertText (view->cursorLine(), view->cursorColumnReal(), s);
3313
3314 editEnd ();
3315}
3316
3317void KateDocument::indent ( KateView *v, uint line, int change)
3318{
3319 editStart ();
3320
3321 if (!hasSelection())
3322 {
3323 // single line
3324 optimizeLeadingSpace(line, config()->configFlags(), change);
3325 }
3326 else
3327 {
3328 int sl = v->selStartLine();
3329 int el = v->selEndLine();
3330 int ec = v->selEndCol();
3331
3332 if ((ec == 0) && ((el-1) >= 0))
3333 {
3334 el--; /* */
3335 }
3336
3337 if (config()->configFlags() & KateDocument::cfKeepIndentProfile && change < 0) {
3338 // unindent so that the existing indent profile doesn't get screwed
3339 // if any line we may unindent is already full left, don't do anything
3340 int adjustedChange = -change;
3341
3342 for (line = sl; (int) line <= el && adjustedChange > 0; line++) {
3343 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
3344 int firstChar = textLine->firstChar();
3345 if (firstChar >= 0 && (v->lineSelected(line) || v->lineHasSelected(line))) {
3346 int maxUnindent = textLine->cursorX(firstChar, config()->tabWidth()) / config()->indentationWidth();
3347 if (maxUnindent < adjustedChange)
3348 adjustedChange = maxUnindent;
3349 }
3350 }
3351
3352 change = -adjustedChange;
3353 }
3354
3355 const bool rts = config()->configFlags() & KateDocumentConfig::cfRemoveTrailingDyn;
3356 for (line = sl; (int) line <= el; line++) {
3357 if ((v->lineSelected(line) || v->lineHasSelected(line))
3358 && (!rts || lineLength(line) > 0)) {
3359 optimizeLeadingSpace(line, config()->configFlags(), change);
3360 }
3361 }
3362 }
3363
3364 editEnd ();
3365}
3366
3367void KateDocument::align(KateView *view, uint line)
3368{
3369 if (m_indenter->canProcessLine())
3370 {
3371 editStart ();
3372
3373 if (!view->hasSelection())
3374 {
3375 KateDocCursor curLine(line, 0, this);
3376 m_indenter->processLine (curLine);
3377 editEnd ();
3378 activeView()->setCursorPosition (line, curLine.col());
3379 }
3380 else
3381 {
3382 m_indenter->processSection (view->selStart(), view->selEnd());
3383 editEnd ();
3384 }
3385 }
3386}
3387
3388/*
3389 Optimize the leading whitespace for a single line.
3390 If change is > 0, it adds indentation units (indentationChars)
3391 if change is == 0, it only optimizes
3392 If change is < 0, it removes indentation units
3393 This will be used to indent, unindent, and optimal-fill a line.
3394 If excess space is removed depends on the flag cfKeepExtraSpaces
3395 which has to be set by the user
3396*/
3397void KateDocument::optimizeLeadingSpace(uint line, int flags, int change)
3398{
3399 KateTextLine::Ptr textline = m_buffer->plainLine(line);
3400
3401 int first_char = textline->firstChar();
3402
3403 int w = 0;
3404 if (flags & KateDocument::cfSpaceIndent)
3405 w = config()->indentationWidth();
3406 else
3407 w = config()->tabWidth();
3408
3409 if (first_char < 0)
3410 first_char = textline->length();
3411
3412 int space = textline->cursorX(first_char, config()->tabWidth()) + change * w;
3413 if (space < 0)
3414 space = 0;
3415
3416 if (!(flags & KateDocument::cfKeepExtraSpaces))
3417 {
3418 uint extra = space % w;
3419
3420 space -= extra;
3421 if (extra && change < 0) {
3422 // otherwise it unindents too much (e.g. 12 chars when indentation is 8 chars wide)
3423 space += w;
3424 }
3425 }
3426
3427 //kdDebug(13020) << "replace With Op: " << line << " " << first_char << " " << space << endl;
3428 replaceWithOptimizedSpace(line, first_char, space, flags);
3429}
3430
3431void KateDocument::replaceWithOptimizedSpace(uint line, uint upto_column, uint space, int flags)
3432{
3433 uint length;
3434 TQString new_space;
3435
3436 if (flags & KateDocument::cfSpaceIndent && ! (flags & KateDocumentConfig::cfMixedIndent) ) {
3437 length = space;
3438 new_space.fill(' ', length);
3439 }
3440 else {
3441 length = space / config()->tabWidth();
3442 new_space.fill('\t', length);
3443
3444 TQString extra_space;
3445 extra_space.fill(' ', space % config()->tabWidth());
3446 length += space % config()->tabWidth();
3447 new_space += extra_space;
3448 }
3449
3450 KateTextLine::Ptr textline = m_buffer->plainLine(line);
3451 uint change_from;
3452 for (change_from = 0; change_from < upto_column && change_from < length; change_from++) {
3453 if (textline->getChar(change_from) != new_space[change_from])
3454 break;
3455 }
3456
3457 editStart();
3458
3459 if (change_from < upto_column)
3460 removeText(line, change_from, line, upto_column);
3461
3462 if (change_from < length)
3463 insertText(line, change_from, new_space.right(length - change_from));
3464
3465 editEnd();
3466}
3467
3468/*
3469 Remove a given string at the begining
3470 of the current line.
3471*/
3472bool KateDocument::removeStringFromBegining(int line, TQString &str)
3473{
3474 KateTextLine::Ptr textline = m_buffer->plainLine(line);
3475
3476 int index = 0;
3477 bool there = false;
3478
3479 if (textline->startingWith(str))
3480 there = true;
3481 else
3482 {
3483 index = textline->firstChar ();
3484
3485 if ((index >= 0) && (textline->length() >= (index + str.length())) && (textline->string(index, str.length()) == str))
3486 there = true;
3487 }
3488
3489 if (there)
3490 {
3491 // Remove some chars
3492 removeText (line, index, line, index+str.length());
3493 }
3494
3495 return there;
3496}
3497
3498/*
3499 Remove a given string at the end
3500 of the current line.
3501*/
3502bool KateDocument::removeStringFromEnd(int line, TQString &str)
3503{
3504 KateTextLine::Ptr textline = m_buffer->plainLine(line);
3505
3506 int index = 0;
3507 bool there = false;
3508
3509 if(textline->endingWith(str))
3510 {
3511 index = textline->length() - str.length();
3512 there = true;
3513 }
3514 else
3515 {
3516 index = textline->lastChar ()-str.length()+1;
3517
3518 if ((index >= 0) && (textline->length() >= (index + str.length())) && (textline->string(index, str.length()) == str))
3519 there = true;
3520 }
3521
3522 if (there)
3523 {
3524 // Remove some chars
3525 removeText (line, index, line, index+str.length());
3526 }
3527
3528 return there;
3529}
3530
3531/*
3532 Add to the current line a comment line mark at
3533 the begining.
3534*/
3535void KateDocument::addStartLineCommentToSingleLine( int line, int attrib )
3536{
3537 if (highlight()->getCommentSingleLinePosition(attrib)==KateHighlighting::CSLPosColumn0)
3538 {
3539 TQString commentLineMark = highlight()->getCommentSingleLineStart( attrib ) + " ";
3540 insertText (line, 0, commentLineMark);
3541 }
3542 else
3543 {
3544 TQString commentLineMark=highlight()->getCommentSingleLineStart(attrib);
3545 KateTextLine::Ptr l = m_buffer->line(line);
3546 int pos=l->firstChar();
3547 if (pos >=0)
3548 insertText(line,pos,commentLineMark);
3549 }
3550}
3551
3552/*
3553 Remove from the current line a comment line mark at
3554 the begining if there is one.
3555*/
3556bool KateDocument::removeStartLineCommentFromSingleLine( int line, int attrib )
3557{
3558 TQString shortCommentMark = highlight()->getCommentSingleLineStart( attrib );
3559 TQString longCommentMark = shortCommentMark + " ";
3560
3561 editStart();
3562
3563 // Try to remove the long comment mark first
3564 bool removed = (removeStringFromBegining(line, longCommentMark)
3565 || removeStringFromBegining(line, shortCommentMark));
3566
3567 editEnd();
3568
3569 return removed;
3570}
3571
3572/*
3573 Add to the current line a start comment mark at the
3574 begining and a stop comment mark at the end.
3575*/
3576void KateDocument::addStartStopCommentToSingleLine( int line, int attrib )
3577{
3578 TQString startCommentMark = highlight()->getCommentStart( attrib ) + " ";
3579 TQString stopCommentMark = " " + highlight()->getCommentEnd( attrib );
3580
3581 editStart();
3582
3583 // Add the start comment mark
3584 insertText (line, 0, startCommentMark);
3585
3586 // Go to the end of the line
3587 int col = m_buffer->plainLine(line)->length();
3588
3589 // Add the stop comment mark
3590 insertText (line, col, stopCommentMark);
3591
3592 editEnd();
3593}
3594
3595/*
3596 Remove from the current line a start comment mark at
3597 the begining and a stop comment mark at the end.
3598*/
3599bool KateDocument::removeStartStopCommentFromSingleLine( int line, int attrib )
3600{
3601 TQString shortStartCommentMark = highlight()->getCommentStart( attrib );
3602 TQString longStartCommentMark = shortStartCommentMark + " ";
3603 TQString shortStopCommentMark = highlight()->getCommentEnd( attrib );
3604 TQString longStopCommentMark = " " + shortStopCommentMark;
3605
3606 editStart();
3607
3608#ifdef __GNUC__
3609#warning "that's a bad idea, can lead to stray endings, FIXME"
3610#endif
3611 // Try to remove the long start comment mark first
3612 bool removedStart = (removeStringFromBegining(line, longStartCommentMark)
3613 || removeStringFromBegining(line, shortStartCommentMark));
3614
3615 bool removedStop = false;
3616 if (removedStart)
3617 {
3618 // Try to remove the long stop comment mark first
3619 removedStop = (removeStringFromEnd(line, longStopCommentMark)
3620 || removeStringFromEnd(line, shortStopCommentMark));
3621 }
3622
3623 editEnd();
3624
3625 return (removedStart || removedStop);
3626}
3627
3628/*
3629 Add to the current selection a start comment
3630 mark at the begining and a stop comment mark
3631 at the end.
3632*/
3633void KateDocument::addStartStopCommentToSelection( KateView *view, int attrib )
3634{
3635 TQString startComment = highlight()->getCommentStart( attrib );
3636 TQString endComment = highlight()->getCommentEnd( attrib );
3637
3638 int sl = view->selStartLine();
3639 int el = view->selEndLine();
3640 int sc = view->selStartCol();
3641 int ec = view->selEndCol();
3642
3643 if ((ec == 0) && ((el-1) >= 0))
3644 {
3645 el--;
3646 ec = m_buffer->plainLine (el)->length();
3647 }
3648
3649 editStart();
3650
3651 insertText (el, ec, endComment);
3652 insertText (sl, sc, startComment);
3653
3654 editEnd ();
3655
3656 // Set the new selection
3657 ec += endComment.length() + ( (el == sl) ? startComment.length() : 0 );
3658 view->setSelection(sl, sc, el, ec);
3659}
3660
3661/*
3662 Add to the current selection a comment line
3663 mark at the begining of each line.
3664*/
3665void KateDocument::addStartLineCommentToSelection( KateView *view, int attrib )
3666{
3667 TQString commentLineMark = highlight()->getCommentSingleLineStart( attrib ) + " ";
3668
3669 int sl = view->selStartLine();
3670 int el = view->selEndLine();
3671
3672 if ((view->selEndCol() == 0) && ((el-1) >= 0))
3673 {
3674 el--;
3675 }
3676
3677 editStart();
3678
3679 // For each line of the selection
3680 for (int z = el; z >= sl; z--) {
3681 //insertText (z, 0, commentLineMark);
3682 addStartLineCommentToSingleLine(z, attrib );
3683 }
3684
3685 editEnd ();
3686
3687 // Set the new selection
3688
3689 KateDocCursor end (view->selEnd());
3690 end.setCol(view->selEndCol() + ((el == view->selEndLine()) ? commentLineMark.length() : 0) );
3691
3692 view->setSelection(view->selStartLine(), 0, end.line(), end.col());
3693}
3694
3695bool KateDocument::nextNonSpaceCharPos(int &line, int &col)
3696{
3697 for(; line < (int)m_buffer->count(); line++) {
3698 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
3699
3700 if (!textLine)
3701 break;
3702
3703 col = textLine->nextNonSpaceChar(col);
3704 if(col != -1)
3705 return true; // Next non-space char found
3706 col = 0;
3707 }
3708 // No non-space char found
3709 line = -1;
3710 col = -1;
3711 return false;
3712}
3713
3714bool KateDocument::previousNonSpaceCharPos(int &line, int &col)
3715{
3716 while(true)
3717 {
3718 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
3719
3720 if (!textLine)
3721 break;
3722
3723 col = textLine->previousNonSpaceChar(col);
3724 if(col != -1) return true;
3725 if(line == 0) return false;
3726 --line;
3727 col = textLine->length();
3728}
3729 // No non-space char found
3730 line = -1;
3731 col = -1;
3732 return false;
3733}
3734
3735/*
3736 Remove from the selection a start comment mark at
3737 the begining and a stop comment mark at the end.
3738*/
3739bool KateDocument::removeStartStopCommentFromSelection( KateView *view, int attrib )
3740{
3741 TQString startComment = highlight()->getCommentStart( attrib );
3742 TQString endComment = highlight()->getCommentEnd( attrib );
3743
3744 int sl = kMax<int> (0, view->selStartLine());
3745 int el = kMin<int> (view->selEndLine(), lastLine());
3746 int sc = view->selStartCol();
3747 int ec = view->selEndCol();
3748
3749 // The selection ends on the char before selectEnd
3750 if (ec != 0) {
3751 ec--;
3752 } else {
3753 if (el > 0) {
3754 el--;
3755 ec = m_buffer->plainLine(el)->length() - 1;
3756 }
3757 }
3758
3759 int startCommentLen = startComment.length();
3760 int endCommentLen = endComment.length();
3761
3762 // had this been perl or sed: s/^\s*$startComment(.+?)$endComment\s*/$1/
3763
3764 bool remove = nextNonSpaceCharPos(sl, sc)
3765 && m_buffer->plainLine(sl)->stringAtPos(sc, startComment)
3766 && previousNonSpaceCharPos(el, ec)
3767 && ( (ec - endCommentLen + 1) >= 0 )
3768 && m_buffer->plainLine(el)->stringAtPos(ec - endCommentLen + 1, endComment);
3769
3770 if (remove) {
3771 editStart();
3772
3773 removeText (el, ec - endCommentLen + 1, el, ec + 1);
3774 removeText (sl, sc, sl, sc + startCommentLen);
3775
3776 editEnd ();
3777 // set new selection not necessary, as the selection cursors are KateSuperCursors
3778 }
3779
3780 return remove;
3781}
3782
3783bool KateDocument::removeStartStopCommentFromRegion(const KateTextCursor &start,const KateTextCursor &end,int attrib)
3784{
3785 TQString startComment = highlight()->getCommentStart( attrib );
3786 TQString endComment = highlight()->getCommentEnd( attrib );
3787 int startCommentLen = startComment.length();
3788 int endCommentLen = endComment.length();
3789
3790 bool remove = m_buffer->plainLine(start.line())->stringAtPos(start.col(), startComment)
3791 && ( (end.col() - endCommentLen ) >= 0 )
3792 && m_buffer->plainLine(end.line())->stringAtPos(end.col() - endCommentLen , endComment);
3793 if (remove) {
3794 editStart();
3795 removeText(end.line(),end.col()-endCommentLen,end.line(),end.col());
3796 removeText(start.line(),start.col(),start.line(),start.col()+startCommentLen);
3797 editEnd();
3798 }
3799 return remove;
3800}
3801
3802/*
3803 Remove from the begining of each line of the
3804 selection a start comment line mark.
3805*/
3806bool KateDocument::removeStartLineCommentFromSelection( KateView *view, int attrib )
3807{
3808 TQString shortCommentMark = highlight()->getCommentSingleLineStart( attrib );
3809 TQString longCommentMark = shortCommentMark + " ";
3810
3811 int sl = view->selStartLine();
3812 int el = view->selEndLine();
3813
3814 if ((view->selEndCol() == 0) && ((el-1) >= 0))
3815 {
3816 el--;
3817 }
3818
3819 // Find out how many char will be removed from the last line
3820 int removeLength = 0;
3821 if (m_buffer->plainLine(el)->startingWith(longCommentMark))
3822 removeLength = longCommentMark.length();
3823 else if (m_buffer->plainLine(el)->startingWith(shortCommentMark))
3824 removeLength = shortCommentMark.length();
3825
3826 bool removed = false;
3827
3828 editStart();
3829
3830 // For each line of the selection
3831 for (int z = el; z >= sl; z--)
3832 {
3833 // Try to remove the long comment mark first
3834 removed = (removeStringFromBegining(z, longCommentMark)
3835 || removeStringFromBegining(z, shortCommentMark)
3836 || removed);
3837 }
3838
3839 editEnd();
3840 // updating selection already done by the KateSuperCursors
3841 return removed;
3842}
3843
3844/*
3845 Comment or uncomment the selection or the current
3846 line if there is no selection.
3847*/
3848void KateDocument::comment( KateView *v, uint line,uint column, int change)
3849{
3850 // We need to check that we can sanely comment the selectino or region.
3851 // It is if the attribute of the first and last character of the range to
3852 // comment belongs to the same language definition.
3853 // for lines with no text, we need the attribute for the lines context.
3854 bool hassel = v->hasSelection();
3855 int startAttrib, endAttrib;
3856 if ( hassel )
3857 {
3858 KateTextLine::Ptr ln = kateTextLine( v->selStartLine() );
3859 int l = v->selStartLine(), c = v->selStartCol();
3860 startAttrib = nextNonSpaceCharPos( l, c ) ? kateTextLine( l )->attribute( c ) : 0;
3861
3862 ln = kateTextLine( v->selEndLine() );
3863 l = v->selEndLine(), c = v->selEndCol();
3864 endAttrib = previousNonSpaceCharPos( l, c ) ? kateTextLine( l )->attribute( c ) : 0;
3865 }
3866 else
3867 {
3868 KateTextLine::Ptr ln = kateTextLine( line );
3869 if ( ln->length() )
3870 {
3871 startAttrib = ln->attribute( ln->firstChar() );
3872 endAttrib = ln->attribute( ln->lastChar() );
3873 }
3874 else
3875 {
3876 int l = line, c = 0;
3877 if ( nextNonSpaceCharPos( l, c ) || previousNonSpaceCharPos( l, c ) )
3878 startAttrib = endAttrib = kateTextLine( l )->attribute( c );
3879 else
3880 startAttrib = endAttrib = 0;
3881 }
3882 }
3883
3884 if ( ! highlight()->canComment( startAttrib, endAttrib ) )
3885 {
3886 kdDebug(13020)<<"canComment( "<<startAttrib<<", "<<endAttrib<<" ) returned false!"<<endl;
3887 return;
3888 }
3889
3890 bool hasStartLineCommentMark = !(highlight()->getCommentSingleLineStart( startAttrib ).isEmpty());
3891 bool hasStartStopCommentMark = ( !(highlight()->getCommentStart( startAttrib ).isEmpty())
3892 && !(highlight()->getCommentEnd( endAttrib ).isEmpty()) );
3893
3894 bool removed = false;
3895
3896 if (change > 0) // comment
3897 {
3898 if ( !hassel )
3899 {
3900 if ( hasStartLineCommentMark )
3901 addStartLineCommentToSingleLine( line, startAttrib );
3902 else if ( hasStartStopCommentMark )
3903 addStartStopCommentToSingleLine( line, startAttrib );
3904 }
3905 else
3906 {
3907 // anders: prefer single line comment to avoid nesting probs
3908 // If the selection starts after first char in the first line
3909 // or ends before the last char of the last line, we may use
3910 // multiline comment markers.
3911 // TODO We should try to detect nesting.
3912 // - if selection ends at col 0, most likely she wanted that
3913 // line ignored
3914 if ( hasStartStopCommentMark &&
3915 ( !hasStartLineCommentMark || (
3916 ( v->selStartCol() > m_buffer->plainLine( v->selStartLine() )->firstChar() ) ||
3917 ( v->selEndCol() < ((int)m_buffer->plainLine( v->selEndLine() )->length()) )
3918 ) ) )
3919 addStartStopCommentToSelection( v, startAttrib );
3920 else if ( hasStartLineCommentMark )
3921 addStartLineCommentToSelection( v, startAttrib );
3922 }
3923 }
3924 else // uncomment
3925 {
3926 if ( !hassel )
3927 {
3928 removed = ( hasStartLineCommentMark
3929 && removeStartLineCommentFromSingleLine( line, startAttrib ) )
3930 || ( hasStartStopCommentMark
3931 && removeStartStopCommentFromSingleLine( line, startAttrib ) );
3932 if ((!removed) && foldingTree()) {
3933 kdDebug(13020)<<"easy approach for uncommenting did not work, trying harder (folding tree)"<<endl;
3934 int commentRegion=(highlight()->commentRegion(startAttrib));
3935 if (commentRegion){
3936 KateCodeFoldingNode *n=foldingTree()->findNodeForPosition(line,column);
3937 if (n) {
3938 KateTextCursor start,end;
3939 if ((n->nodeType()==commentRegion) && n->getBegin(foldingTree(), &start) && n->getEnd(foldingTree(), &end)) {
3940 kdDebug(13020)<<"Enclosing region found:"<<start.col()<<"/"<<start.line()<<"-"<<end.col()<<"/"<<end.line()<<endl;
3941 removeStartStopCommentFromRegion(start,end,startAttrib);
3942 } else {
3943 kdDebug(13020)<<"Enclosing region found, but not valid"<<endl;
3944 kdDebug(13020)<<"Region found: "<<n->nodeType()<<" region needed: "<<commentRegion<<endl;
3945 }
3946 //perhaps nested regions should be hadled here too...
3947 } else kdDebug(13020)<<"No enclosing region found"<<endl;
3948 } else kdDebug(13020)<<"No comment region specified for current hl"<<endl;
3949 }
3950 }
3951 else
3952 {
3953 // anders: this seems like it will work with above changes :)
3954 removed = ( hasStartLineCommentMark
3955 && removeStartLineCommentFromSelection( v, startAttrib ) )
3956 || ( hasStartStopCommentMark
3957 && removeStartStopCommentFromSelection( v, startAttrib ) );
3958 }
3959 }
3960}
3961
3962void KateDocument::transform( KateView *v, const KateTextCursor &c,
3963 KateDocument::TextTransform t )
3964{
3965 editStart();
3966 uint cl( c.line() ), cc( c.col() );
3967 bool selectionRestored = false;
3968
3969 if ( hasSelection() )
3970 {
3971 // cache the selection and cursor, so we can be sure to restore.
3972 KateTextCursor selstart = v->selStart();
3973 KateTextCursor selend = v->selEnd();
3974
3975 int ln = v->selStartLine();
3976 while ( ln <= selend.line() )
3977 {
3978 uint start, end;
3979 start = (ln == selstart.line() || v->blockSelectionMode()) ?
3980 selstart.col() : 0;
3981 end = (ln == selend.line() || v->blockSelectionMode()) ?
3982 selend.col() : lineLength( ln );
3983 if ( start > end )
3984 {
3985 uint t = start;
3986 start = end;
3987 end = t;
3988 }
3989 TQString s = text( ln, start, ln, end );
3990 TQString o = s;
3991
3992 if ( t == Uppercase )
3993 s = s.upper();
3994 else if ( t == Lowercase )
3995 s = s.lower();
3996 else // Capitalize
3997 {
3998 KateTextLine::Ptr l = m_buffer->plainLine( ln );
3999 uint p ( 0 );
4000 while( p < s.length() )
4001 {
4002 // If bol or the character before is not in a word, up this one:
4003 // 1. if both start and p is 0, upper char.
4004 // 2. if blockselect or first line, and p == 0 and start-1 is not in a word, upper
4005 // 3. if p-1 is not in a word, upper.
4006 if ( ( ! start && ! p ) ||
4007 ( ( ln == selstart.line() || v->blockSelectionMode() ) &&
4008 ! p && ! highlight()->isInWord( l->getChar( start - 1 )) ) ||
4009 ( p && ! highlight()->isInWord( s.at( p-1 ) ) )
4010 )
4011 s[p] = s.at(p).upper();
4012 p++;
4013 }
4014 }
4015
4016 if ( o != s )
4017 {
4018 removeText( ln, start, ln, end );
4019 insertText( ln, start, s );
4020 }
4021
4022 ln++;
4023 }
4024
4025 // restore selection
4026 v->setSelection( selstart, selend );
4027 selectionRestored = true;
4028
4029 } else { // no selection
4030 TQString o = text( cl, cc, cl, cc + 1 );
4031 TQString s;
4032 int n ( cc );
4033 switch ( t ) {
4034 case Uppercase:
4035 s = o.upper();
4036 break;
4037 case Lowercase:
4038 s = o.lower();
4039 break;
4040 case Capitalize:
4041 {
4042 KateTextLine::Ptr l = m_buffer->plainLine( cl );
4043 while ( n > 0 && highlight()->isInWord( l->getChar( n-1 ), l->attribute( n-1 ) ) )
4044 n--;
4045 o = text( cl, n, cl, n + 1 );
4046 s = o.upper();
4047 }
4048 break;
4049 default:
4050 break;
4051 }
4052
4053 if ( s != o )
4054 {
4055 removeText( cl, n, cl, n+1 );
4056 insertText( cl, n, s );
4057 }
4058 }
4059 editEnd();
4060
4061 if ( ! selectionRestored )
4062 v->setCursorPosition( cl, cc );
4063}
4064
4065void KateDocument::joinLines( uint first, uint last )
4066{
4067// if ( first == last ) last += 1;
4068 editStart();
4069 int line( first );
4070 while ( first < last )
4071 {
4072 // Normalize the whitespace in the joined lines by making sure there's
4073 // always exactly one space between the joined lines
4074 // This cannot be done in editUnwrapLine, because we do NOT want this
4075 // behaviour when deleting from the start of a line, just when explicitly
4076 // calling the join command
4077 KateTextLine::Ptr l = m_buffer->line( line );
4078 KateTextLine::Ptr tl = m_buffer->line( line + 1 );
4079
4080 if ( !l || !tl )
4081 {
4082 editEnd();
4083 return;
4084 }
4085
4086 int pos = tl->firstChar();
4087 if ( pos >= 0 )
4088 {
4089 if (pos != 0)
4090 editRemoveText( line + 1, 0, pos );
4091 if ( !( l->length() == 0 || l->getChar( l->length() - 1 ).isSpace() ) )
4092 editInsertText( line + 1, 0, " " );
4093 }
4094 else
4095 {
4096 // Just remove the whitespace and let Kate handle the rest
4097 editRemoveText( line + 1, 0, tl->length() );
4098 }
4099
4100 editUnWrapLine( line );
4101 first++;
4102 }
4103 editEnd();
4104}
4105
4106TQString KateDocument::getWord( const KateTextCursor& cursor ) {
4107 int start, end, len;
4108
4109 KateTextLine::Ptr textLine = m_buffer->plainLine(cursor.line());
4110 len = textLine->length();
4111 start = end = cursor.col();
4112 if (start > len) // Probably because of non-wrapping cursor mode.
4113 return TQString("");
4114
4115 while (start > 0 && highlight()->isInWord(textLine->getChar(start - 1), textLine->attribute(start - 1))) start--;
4116 while (end < len && highlight()->isInWord(textLine->getChar(end), textLine->attribute(end))) end++;
4117 len = end - start;
4118 return TQString(&textLine->text()[start], len);
4119}
4120
4121void KateDocument::tagLines(int start, int end)
4122{
4123 for (uint z = 0; z < m_views.count(); z++)
4124 m_views.at(z)->tagLines (start, end, true);
4125}
4126
4127void KateDocument::tagLines(KateTextCursor start, KateTextCursor end)
4128{
4129 // May need to switch start/end cols if in block selection mode
4130 if (blockSelectionMode() && start.col() > end.col()) {
4131 int sc = start.col();
4132 start.setCol(end.col());
4133 end.setCol(sc);
4134 }
4135
4136 for (uint z = 0; z < m_views.count(); z++)
4137 m_views.at(z)->tagLines(start, end, true);
4138}
4139
4140void KateDocument::repaintViews(bool paintOnlyDirty)
4141{
4142 for (uint z = 0; z < m_views.count(); z++)
4143 m_views.at(z)->repaintText(paintOnlyDirty);
4144}
4145
4146void KateDocument::tagAll()
4147{
4148 for (uint z = 0; z < m_views.count(); z++)
4149 {
4150 m_views.at(z)->tagAll();
4151 m_views.at(z)->updateView (true);
4152 }
4153}
4154
4155uint KateDocument::configFlags ()
4156{
4157 return config()->configFlags();
4158}
4159
4160void KateDocument::setConfigFlags (uint flags)
4161{
4162 config()->setConfigFlags(flags);
4163}
4164
4165inline bool isStartBracket( const TQChar& c ) { return c == '{' || c == '[' || c == '('; }
4166inline bool isEndBracket ( const TQChar& c ) { return c == '}' || c == ']' || c == ')'; }
4167inline bool isBracket ( const TQChar& c ) { return isStartBracket( c ) || isEndBracket( c ); }
4168
4169/*
4170 Bracket matching uses the following algorithm:
4171 If in overwrite mode, match the bracket currently underneath the cursor.
4172 Otherwise, if the character to the right of the cursor is an starting bracket,
4173 match it. Otherwise if the character to the left of the cursor is a
4174 ending bracket, match it. Otherwise, if the the character to the left
4175 of the cursor is an starting bracket, match it. Otherwise, if the character
4176 to the right of the cursor is an ending bracket, match it. Otherwise, don't
4177 match anything.
4178*/
4179void KateDocument::newBracketMark( const KateTextCursor& cursor, KateBracketRange& bm, int maxLines )
4180{
4181 bm.setValid(false);
4182
4183 bm.start() = cursor;
4184
4185 if( !findMatchingBracket( bm.start(), bm.end(), maxLines ) )
4186 return;
4187
4188 bm.setValid(true);
4189
4190 const int tw = config()->tabWidth();
4191 const int indentStart = m_buffer->plainLine(bm.start().line())->indentDepth(tw);
4192 const int indentEnd = m_buffer->plainLine(bm.end().line())->indentDepth(tw);
4193 bm.setIndentMin(kMin(indentStart, indentEnd));
4194}
4195
4196bool KateDocument::findMatchingBracket( KateTextCursor& start, KateTextCursor& end, int maxLines )
4197{
4198 KateTextLine::Ptr textLine = m_buffer->plainLine( start.line() );
4199 if( !textLine )
4200 return false;
4201
4202 TQChar right = textLine->getChar( start.col() );
4203 TQChar left = textLine->getChar( start.col() - 1 );
4204 TQChar bracket;
4205
4206 if ( config()->configFlags() & cfOvr ) {
4207 if( isBracket( right ) ) {
4208 bracket = right;
4209 } else {
4210 return false;
4211 }
4212 } else if ( isStartBracket( right ) ) {
4213 bracket = right;
4214 } else if ( isEndBracket( left ) ) {
4215 start.setCol(start.col() - 1);
4216 bracket = left;
4217 } else if ( isBracket( left ) ) {
4218 start.setCol(start.col() - 1);
4219 bracket = left;
4220 } else if ( isBracket( right ) ) {
4221 bracket = right;
4222 } else {
4223 return false;
4224 }
4225
4226 TQChar opposite;
4227
4228 switch( bracket ) {
4229 case '{': opposite = '}'; break;
4230 case '}': opposite = '{'; break;
4231 case '[': opposite = ']'; break;
4232 case ']': opposite = '['; break;
4233 case '(': opposite = ')'; break;
4234 case ')': opposite = '('; break;
4235 default: return false;
4236 }
4237
4238 bool forward = isStartBracket( bracket );
4239 int startAttr = textLine->attribute( start.col() );
4240 uint count = 0;
4241 int lines = 0;
4242 end = start;
4243
4244 while( true ) {
4245 /* Increment or decrement, check base cases */
4246 if( forward ) {
4247 end.setCol(end.col() + 1);
4248 if( end.col() >= lineLength( end.line() ) ) {
4249 if( end.line() >= (int)lastLine() )
4250 return false;
4251 end.setPos(end.line() + 1, 0);
4252 textLine = m_buffer->plainLine( end.line() );
4253 lines++;
4254 }
4255 } else {
4256 end.setCol(end.col() - 1);
4257 if( end.col() < 0 ) {
4258 if( end.line() <= 0 )
4259 return false;
4260 end.setLine(end.line() - 1);
4261 end.setCol(lineLength( end.line() ) - 1);
4262 textLine = m_buffer->plainLine( end.line() );
4263 lines++;
4264 }
4265 }
4266
4267 if ((maxLines != -1) && (lines > maxLines))
4268 return false;
4269
4270 /* Easy way to skip comments */
4271 if( textLine->attribute( end.col() ) != startAttr )
4272 continue;
4273
4274 /* Check for match */
4275 TQChar c = textLine->getChar( end.col() );
4276 if( c == bracket ) {
4277 count++;
4278 } else if( c == opposite ) {
4279 if( count == 0 )
4280 return true;
4281 count--;
4282 }
4283
4284 }
4285}
4286
4287void KateDocument::guiActivateEvent( KParts::GUIActivateEvent *ev )
4288{
4289 KParts::ReadWritePart::guiActivateEvent( ev );
4290 if ( ev->activated() )
4291 emit selectionChanged();
4292}
4293
4294void KateDocument::setDocName (TQString name )
4295{
4296 if ( name == m_docName )
4297 return;
4298
4299 if ( !name.isEmpty() )
4300 {
4301 // TODO check for similarly named documents
4302 m_docName = name;
4303 updateFileType (KateFactory::self()->fileTypeManager()->fileType (this));
4304 emit nameChanged((Kate::Document *) this);
4305 return;
4306 }
4307
4308 // if the name is set, and starts with FILENAME, it should not be changed!
4309 if ( ! url().isEmpty() && m_docName.startsWith( url().filename() ) ) return;
4310
4311 int count = -1;
4312
4313 for (uint z=0; z < KateFactory::self()->documents()->count(); z++)
4314 {
4315 if ( (KateFactory::self()->documents()->at(z) != this) && (KateFactory::self()->documents()->at(z)->url().filename() == url().filename()) )
4316 if ( KateFactory::self()->documents()->at(z)->m_docNameNumber > count )
4317 count = KateFactory::self()->documents()->at(z)->m_docNameNumber;
4318 }
4319
4320 m_docNameNumber = count + 1;
4321
4322 m_docName = url().filename();
4323
4324 if (m_docName.isEmpty())
4325 m_docName = i18n ("Untitled");
4326
4327 if (m_docNameNumber > 0)
4328 m_docName = TQString(m_docName + " (%1)").arg(m_docNameNumber+1);
4329
4330 updateFileType (KateFactory::self()->fileTypeManager()->fileType (this));
4331 emit nameChanged ((Kate::Document *) this);
4332}
4333
4334void KateDocument::slotModifiedOnDisk( Kate::View * /*v*/ )
4335{
4336 if ( m_isasking < 0 )
4337 {
4338 m_isasking = 0;
4339 return;
4340 }
4341
4342 if ( !s_fileChangedDialogsActivated || m_isasking )
4343 return;
4344
4345 if (m_modOnHd && !url().isEmpty())
4346 {
4347 m_isasking = 1;
4348
4349 KateModOnHdPrompt p( this, m_modOnHdReason, reasonedMOHString(), widget() );
4350 switch ( p.exec() )
4351 {
4352 case KateModOnHdPrompt::Save:
4353 {
4354 m_modOnHd = false;
4355 KEncodingFileDialog::Result res=KEncodingFileDialog::getSaveURLAndEncoding(config()->encoding(),
4356 url().url(),TQString::null,widget(),i18n("Save File"));
4357
4358 kdDebug(13020)<<"got "<<res.URLs.count()<<" URLs"<<endl;
4359 if( ! res.URLs.isEmpty() && ! res.URLs.first().isEmpty() && checkOverwrite( res.URLs.first() ) )
4360 {
4361 setEncoding( res.encoding );
4362
4363 if( ! saveAs( res.URLs.first() ) )
4364 {
4365 KMessageBox::error( widget(), i18n("Save failed") );
4366 m_modOnHd = true;
4367 }
4368 else
4369 emit modifiedOnDisc( this, false, 0 );
4370 }
4371 else // the save as dialog was cancelled, we are still modified on disk
4372 {
4373 m_modOnHd = true;
4374 }
4375
4376 m_isasking = 0;
4377 break;
4378 }
4379
4380 case KateModOnHdPrompt::Reload:
4381 m_modOnHd = false;
4382 emit modifiedOnDisc( this, false, 0 );
4383 reloadFile();
4384 m_isasking = 0;
4385 break;
4386
4387 case KateModOnHdPrompt::Ignore:
4388 m_modOnHd = false;
4389 emit modifiedOnDisc( this, false, 0 );
4390 m_isasking = 0;
4391 break;
4392
4393 case KateModOnHdPrompt::Overwrite:
4394 m_modOnHd = false;
4395 emit modifiedOnDisc( this, false, 0 );
4396 m_isasking = 0;
4397 save();
4398 break;
4399
4400 default: // cancel: ignore next focus event
4401 m_isasking = -1;
4402 }
4403 }
4404}
4405
4406void KateDocument::setModifiedOnDisk( int reason )
4407{
4408 m_modOnHdReason = reason;
4409 m_modOnHd = (reason > 0);
4410 emit modifiedOnDisc( this, (reason > 0), reason );
4411}
4412
4413class KateDocumentTmpMark
4414{
4415 public:
4416 TQString line;
4417 KTextEditor::Mark mark;
4418};
4419
4420void KateDocument::reloadFile()
4421{
4422 if ( !url().isEmpty() )
4423 {
4424 if (m_modOnHd && s_fileChangedDialogsActivated)
4425 {
4426 int i = KMessageBox::warningYesNoCancel
4427 (0, reasonedMOHString() + "\n\n" + i18n("What do you want to do?"),
4428 i18n("File Was Changed on Disk"), i18n("&Reload File"), i18n("&Ignore Changes"));
4429
4430 if ( i != KMessageBox::Yes)
4431 {
4432 if (i == KMessageBox::No)
4433 {
4434 m_modOnHd = false;
4435 m_modOnHdReason = 0;
4436 emit modifiedOnDisc (this, m_modOnHd, 0);
4437 }
4438
4439 return;
4440 }
4441 }
4442
4443 TQValueList<KateDocumentTmpMark> tmp;
4444
4445 for( TQIntDictIterator<KTextEditor::Mark> it( m_marks ); it.current(); ++it )
4446 {
4447 KateDocumentTmpMark m;
4448
4449 m.line = textLine (it.current()->line);
4450 m.mark = *it.current();
4451
4452 tmp.append (m);
4453 }
4454
4455 uint mode = hlMode ();
4456 bool byUser = hlSetByUser;
4457
4458 m_storedVariables.clear();
4459
4460 m_reloading = true;
4461
4462 TQValueList<int> lines, cols;
4463 for ( uint i=0; i < m_views.count(); i++ )
4464 {
4465 lines.append( m_views.at( i )->cursorLine() );
4466 cols.append( m_views.at( i )->cursorColumn() );
4467 }
4468
4469 KateDocument::openURL( url() );
4470
4471 for ( uint i=0; i < m_views.count(); i++ )
4472 m_views.at( i )->setCursorPositionInternal( lines[ i ], cols[ i ], m_config->tabWidth(), false );
4473
4474 m_reloading = false;
4475
4476 for ( TQValueList<int>::size_type z=0; z < tmp.size(); z++ )
4477 {
4478 if (z < numLines())
4479 {
4480 if (textLine(tmp[z].mark.line) == tmp[z].line)
4481 setMark (tmp[z].mark.line, tmp[z].mark.type);
4482 }
4483 }
4484
4485 if (byUser)
4486 setHlMode (mode);
4487 }
4488}
4489
4490void KateDocument::flush ()
4491{
4492 closeURL ();
4493}
4494
4495void KateDocument::setWordWrap (bool on)
4496{
4497 config()->setWordWrap (on);
4498}
4499
4500bool KateDocument::wordWrap ()
4501{
4502 return config()->wordWrap ();
4503}
4504
4505void KateDocument::setWordWrapAt (uint col)
4506{
4507 config()->setWordWrapAt (col);
4508}
4509
4510unsigned int KateDocument::wordWrapAt ()
4511{
4512 return config()->wordWrapAt ();
4513}
4514
4515void KateDocument::applyWordWrap ()
4516{
4517 // dummy to make the API happy
4518}
4519
4520void KateDocument::setPageUpDownMovesCursor (bool on)
4521{
4522 config()->setPageUpDownMovesCursor (on);
4523}
4524
4525bool KateDocument::pageUpDownMovesCursor ()
4526{
4527 return config()->pageUpDownMovesCursor ();
4528}
4529
4530void KateDocument::dumpRegionTree()
4531{
4532 m_buffer->foldingTree()->debugDump();
4533}
4534//END
4535
4536//BEGIN KTextEditor::CursorInterface stuff
4537
4538KTextEditor::Cursor *KateDocument::createCursor ( )
4539{
4540 return new KateSuperCursor (this, false, 0, 0, this);
4541}
4542
4543void KateDocument::tagArbitraryLines(KateView* view, KateSuperRange* range)
4544{
4545 if (view)
4546 view->tagLines(range->start(), range->end());
4547 else
4548 tagLines(range->start(), range->end());
4549}
4550
4551void KateDocument::lineInfo (KateLineInfo *info, unsigned int line)
4552{
4553 m_buffer->lineInfo(info,line);
4554}
4555
4556KateCodeFoldingTree *KateDocument::foldingTree ()
4557{
4558 return m_buffer->foldingTree();
4559}
4560
4561void KateDocument::setEncoding (const TQString &e)
4562{
4563 if ( m_encodingSticky )
4564 return;
4565
4566 TQString ce = m_config->encoding().lower();
4567 if ( e.lower() == ce )
4568 return;
4569
4570 m_config->setEncoding( e );
4571 if ( ! m_loading )
4572 reloadFile();
4573}
4574
4575TQString KateDocument::encoding() const
4576{
4577 return m_config->encoding();
4578}
4579
4580void KateDocument::updateConfig ()
4581{
4582 emit undoChanged ();
4583 tagAll();
4584
4585 for (KateView * view = m_views.first(); view != 0L; view = m_views.next() )
4586 {
4587 view->updateDocumentConfig ();
4588 }
4589
4590 // switch indenter if needed
4591 if (m_indenter->modeNumber() != m_config->indentationMode())
4592 {
4593 delete m_indenter;
4594 m_indenter = KateAutoIndent::createIndenter ( this, m_config->indentationMode() );
4595 }
4596
4597 m_indenter->updateConfig();
4598
4599 m_buffer->setTabWidth (config()->tabWidth());
4600
4601 // plugins
4602 for (uint i=0; i<KateFactory::self()->plugins().count(); i++)
4603 {
4604 if (config()->plugin (i))
4605 loadPlugin (i);
4606 else
4607 unloadPlugin (i);
4608 }
4609}
4610
4611//BEGIN Variable reader
4612// "local variable" feature by anders, 2003
4613/* TODO
4614 add config options (how many lines to read, on/off)
4615 add interface for plugins/apps to set/get variables
4616 add view stuff
4617*/
4618TQRegExp KateDocument::kvLine = TQRegExp("kate:(.*)");
4619TQRegExp KateDocument::kvLineWildcard = TQRegExp("kate-wildcard\\((.*)\\):(.*)");
4620TQRegExp KateDocument::kvLineMime = TQRegExp("kate-mimetype\\((.*)\\):(.*)");
4621TQRegExp KateDocument::kvVar = TQRegExp("([\\w\\-]+)\\s+([^;]+)");
4622
4623void KateDocument::readVariables(bool onlyViewAndRenderer)
4624{
4625 if (!onlyViewAndRenderer)
4626 m_config->configStart();
4627
4628 // views!
4629 KateView *v;
4630 for (v = m_views.first(); v != 0L; v= m_views.next() )
4631 {
4632 v->config()->configStart();
4633 v->renderer()->config()->configStart();
4634 }
4635 // read a number of lines in the top/bottom of the document
4636 for (uint i=0; i < kMin( 9U, numLines() ); ++i )
4637 {
4638 readVariableLine( textLine( i ), onlyViewAndRenderer );
4639 }
4640 if ( numLines() > 10 )
4641 {
4642 for ( uint i = kMax(10U, numLines() - 10); i < numLines(); ++i )
4643 {
4644 readVariableLine( textLine( i ), onlyViewAndRenderer );
4645 }
4646 }
4647
4648 if (!onlyViewAndRenderer)
4649 m_config->configEnd();
4650
4651 for (v = m_views.first(); v != 0L; v= m_views.next() )
4652 {
4653 v->config()->configEnd();
4654 v->renderer()->config()->configEnd();
4655 }
4656}
4657
4658void KateDocument::readVariableLine( TQString t, bool onlyViewAndRenderer )
4659{
4660 // simple check first, no regex
4661 // no kate inside, no vars, simple...
4662 if (t.find("kate") < 0)
4663 return;
4664
4665 // found vars, if any
4666 TQString s;
4667
4668 if ( kvLine.search( t ) > -1 )
4669 {
4670 s = kvLine.cap(1);
4671
4672 kdDebug (13020) << "normal variable line kate: matched: " << s << endl;
4673 }
4674 else if (kvLineWildcard.search( t ) > -1) // regex given
4675 {
4676 TQStringList wildcards (TQStringList::split(';', kvLineWildcard.cap(1)));
4677 TQString nameOfFile = url().fileName();
4678
4679 bool found = false;
4680 for (TQStringList::size_type i = 0; !found && i < wildcards.size(); ++i)
4681 {
4682 TQRegExp wildcard (wildcards[i], true/*TQt::CaseSensitive*/, true/*TQRegExp::Wildcard*/);
4683
4684 found = wildcard.exactMatch (nameOfFile);
4685 }
4686
4687 // nothing usable found...
4688 if (!found)
4689 return;
4690
4691 s = kvLineWildcard.cap(2);
4692
4693 kdDebug (13020) << "guarded variable line kate-wildcard: matched: " << s << endl;
4694 }
4695 else if (kvLineMime.search( t ) > -1) // mime-type given
4696 {
4697 TQStringList types (TQStringList::split(';', kvLineMime.cap(1)));
4698
4699 // no matching type found
4700 if (!types.contains (mimeType ()))
4701 return;
4702
4703 s = kvLineMime.cap(2);
4704
4705 kdDebug (13020) << "guarded variable line kate-mimetype: matched: " << s << endl;
4706 }
4707 else // nothing found
4708 {
4709 return;
4710 }
4711
4712 TQStringList vvl; // view variable names
4713 vvl << "dynamic-word-wrap" << "dynamic-word-wrap-indicators"
4714 << "line-numbers" << "icon-border" << "folding-markers"
4715 << "bookmark-sorting" << "auto-center-lines"
4716 << "icon-bar-color"
4717 // renderer
4718 << "background-color" << "selection-color"
4719 << "current-line-color" << "bracket-highlight-color"
4720 << "word-wrap-marker-color"
4721 << "font" << "font-size" << "scheme";
4722 int p( 0 );
4723
4724 TQString var, val;
4725 while ( (p = kvVar.search( s, p )) > -1 )
4726 {
4727 p += kvVar.matchedLength();
4728 var = kvVar.cap( 1 );
4729 val = TQString(kvVar.cap( 2 )).stripWhiteSpace();
4730 bool state; // store booleans here
4731 int n; // store ints here
4732
4733 // only apply view & renderer config stuff
4734 if (onlyViewAndRenderer)
4735 {
4736 if ( vvl.contains( var ) ) // FIXME define above
4737 setViewVariable( var, val );
4738 }
4739 else
4740 {
4741 // BOOL SETTINGS
4742 if ( var == "word-wrap" && checkBoolValue( val, &state ) )
4743 setWordWrap( state ); // ??? FIXME CHECK
4744 else if ( var == "block-selection" && checkBoolValue( val, &state ) )
4745 setBlockSelectionMode( state );
4746 // KateConfig::configFlags
4747 // FIXME should this be optimized to only a few calls? how?
4748 else if ( var == "backspace-indents" && checkBoolValue( val, &state ) )
4749 m_config->setConfigFlags( KateDocumentConfig::cfBackspaceIndents, state );
4750 else if ( var == "replace-tabs" && checkBoolValue( val, &state ) )
4751 m_config->setConfigFlags( KateDocumentConfig::cfReplaceTabsDyn, state );
4752 else if ( var == "remove-trailing-space" && checkBoolValue( val, &state ) )
4753 m_config->setConfigFlags( KateDocumentConfig::cfRemoveTrailingDyn, state );
4754 else if ( var == "wrap-cursor" && checkBoolValue( val, &state ) )
4755 m_config->setConfigFlags( KateDocumentConfig::cfWrapCursor, state );
4756 else if ( var == "auto-brackets" && checkBoolValue( val, &state ) )
4757 m_config->setConfigFlags( KateDocumentConfig::cfAutoBrackets, state );
4758 else if ( var == "overwrite-mode" && checkBoolValue( val, &state ) )
4759 m_config->setConfigFlags( KateDocumentConfig::cfOvr, state );
4760 else if ( var == "keep-indent-profile" && checkBoolValue( val, &state ) )
4761 m_config->setConfigFlags( KateDocumentConfig::cfKeepIndentProfile, state );
4762 else if ( var == "keep-extra-spaces" && checkBoolValue( val, &state ) )
4763 m_config->setConfigFlags( KateDocumentConfig::cfKeepExtraSpaces, state );
4764 else if ( var == "tab-indents" && checkBoolValue( val, &state ) )
4765 m_config->setConfigFlags( KateDocumentConfig::cfTabIndents, state );
4766 else if ( var == "show-tabs" && checkBoolValue( val, &state ) )
4767 m_config->setConfigFlags( KateDocumentConfig::cfShowTabs, state );
4768 else if ( var == "space-indent" && checkBoolValue( val, &state ) )
4769 m_config->setConfigFlags( KateDocumentConfig::cfSpaceIndent, state );
4770 else if ( var == "smart-home" && checkBoolValue( val, &state ) )
4771 m_config->setConfigFlags( KateDocumentConfig::cfSmartHome, state );
4772 else if ( var == "replace-trailing-space-save" && checkBoolValue( val, &state ) )
4773 m_config->setConfigFlags( KateDocumentConfig::cfRemoveSpaces, state );
4774 else if ( var == "auto-insert-doxygen" && checkBoolValue( val, &state) )
4775 m_config->setConfigFlags( KateDocumentConfig::cfDoxygenAutoTyping, state);
4776 else if ( var == "mixed-indent" && checkBoolValue( val, &state ) )
4777 m_config->setConfigFlags( KateDocumentConfig::cfMixedIndent, state );
4778
4779 // INTEGER SETTINGS
4780 else if ( var == "tab-width" && checkIntValue( val, &n ) )
4781 m_config->setTabWidth( n );
4782 else if ( var == "indent-width" && checkIntValue( val, &n ) )
4783 m_config->setIndentationWidth( n );
4784 else if ( var == "indent-mode" )
4785 {
4786 if ( checkIntValue( val, &n ) )
4787 m_config->setIndentationMode( n );
4788 else
4789 m_config->setIndentationMode( KateAutoIndent::modeNumber( val) );
4790 }
4791 else if ( var == "word-wrap-column" && checkIntValue( val, &n ) && n > 0 ) // uint, but hard word wrap at 0 will be no fun ;)
4792 m_config->setWordWrapAt( n );
4793 else if ( var == "undo-steps" && checkIntValue( val, &n ) && n >= 0 )
4794 setUndoSteps( n );
4795
4796 // STRING SETTINGS
4797 else if ( var == "eol" || var == "end-of-line" )
4798 {
4799 TQStringList l;
4800 l << "unix" << "dos" << "mac";
4801 if ( (n = l.findIndex( val.lower() )) != -1 )
4802 m_config->setEol( n );
4803 }
4804 else if ( var == "encoding" )
4805 m_config->setEncoding( val );
4806 else if ( var == "syntax" || var == "hl" )
4807 {
4808 for ( uint i=0; i < hlModeCount(); i++ )
4809 {
4810 if ( hlModeName( i ).lower() == val.lower() )
4811 {
4812 setHlMode( i );
4813 break;
4814 }
4815 }
4816 }
4817
4818 // VIEW SETTINGS
4819 else if ( vvl.contains( var ) )
4820 setViewVariable( var, val );
4821 else
4822 {
4823 m_storedVariables.insert( var, val );
4824 emit variableChanged( var, val );
4825 }
4826 }
4827 }
4828}
4829
4830void KateDocument::setViewVariable( TQString var, TQString val )
4831{
4832 KateView *v;
4833 bool state;
4834 int n;
4835 TQColor c;
4836 for (v = m_views.first(); v != 0L; v= m_views.next() )
4837 {
4838 if ( var == "dynamic-word-wrap" && checkBoolValue( val, &state ) )
4839 v->config()->setDynWordWrap( state );
4840 else if ( var == "persistent-selection" && checkBoolValue( val, &state ) )
4841 v->config()->setPersistentSelection( state );
4842 //else if ( var = "dynamic-word-wrap-indicators" )
4843 else if ( var == "line-numbers" && checkBoolValue( val, &state ) )
4844 v->config()->setLineNumbers( state );
4845 else if (var == "icon-border" && checkBoolValue( val, &state ) )
4846 v->config()->setIconBar( state );
4847 else if (var == "folding-markers" && checkBoolValue( val, &state ) )
4848 v->config()->setFoldingBar( state );
4849 else if ( var == "auto-center-lines" && checkIntValue( val, &n ) )
4850 v->config()->setAutoCenterLines( n ); // FIXME uint, > N ??
4851 else if ( var == "icon-bar-color" && checkColorValue( val, c ) )
4852 v->renderer()->config()->setIconBarColor( c );
4853 // RENDERER
4854 else if ( var == "background-color" && checkColorValue( val, c ) )
4855 v->renderer()->config()->setBackgroundColor( c );
4856 else if ( var == "selection-color" && checkColorValue( val, c ) )
4857 v->renderer()->config()->setSelectionColor( c );
4858 else if ( var == "current-line-color" && checkColorValue( val, c ) )
4859 v->renderer()->config()->setHighlightedLineColor( c );
4860 else if ( var == "bracket-highlight-color" && checkColorValue( val, c ) )
4861 v->renderer()->config()->setHighlightedBracketColor( c );
4862 else if ( var == "word-wrap-marker-color" && checkColorValue( val, c ) )
4863 v->renderer()->config()->setWordWrapMarkerColor( c );
4864 else if ( var == "font" || ( var == "font-size" && checkIntValue( val, &n ) ) )
4865 {
4866 TQFont _f( *v->renderer()->config()->font( ) );
4867
4868 if ( var == "font" )
4869 {
4870 _f.setFamily( val );
4871 _f.setFixedPitch( TQFont( val ).fixedPitch() );
4872 }
4873 else
4874 _f.setPointSize( n );
4875
4876 v->renderer()->config()->setFont( _f );
4877 }
4878 else if ( var == "scheme" )
4879 {
4880 v->renderer()->config()->setSchema( KateFactory::self()->schemaManager()->number( val ) );
4881 }
4882 }
4883}
4884
4885bool KateDocument::checkBoolValue( TQString val, bool *result )
4886{
4887 val = val.stripWhiteSpace().lower();
4888 TQStringList l;
4889 l << "1" << "on" << "true";
4890 if ( l.contains( val ) )
4891 {
4892 *result = true;
4893 return true;
4894 }
4895 l.clear();
4896 l << "0" << "off" << "false";
4897 if ( l.contains( val ) )
4898 {
4899 *result = false;
4900 return true;
4901 }
4902 return false;
4903}
4904
4905bool KateDocument::checkIntValue( TQString val, int *result )
4906{
4907 bool ret( false );
4908 *result = val.toInt( &ret );
4909 return ret;
4910}
4911
4912bool KateDocument::checkColorValue( TQString val, TQColor &c )
4913{
4914 c.setNamedColor( val );
4915 return c.isValid();
4916}
4917
4918// KTextEditor::variable
4919TQString KateDocument::variable( const TQString &name ) const
4920{
4921 if ( m_storedVariables.contains( name ) )
4922 return m_storedVariables[ name ];
4923
4924 return "";
4925}
4926
4927//END
4928
4929void KateDocument::slotModOnHdDirty (const TQString &path)
4930{
4931 if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != 1))
4932 {
4933 // compare md5 with the one we have (if we have one)
4934 if ( ! m_digest.isEmpty() )
4935 {
4936 TQCString tmp;
4937 if ( createDigest( tmp ) && tmp == m_digest )
4938 return;
4939 }
4940
4941 m_modOnHd = true;
4942 m_modOnHdReason = 1;
4943
4944 // reenable dialog if not running atm
4945 if (m_isasking == -1)
4946 m_isasking = false;
4947
4948 emit modifiedOnDisc (this, m_modOnHd, m_modOnHdReason);
4949 }
4950}
4951
4952void KateDocument::slotModOnHdCreated (const TQString &path)
4953{
4954 if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != 2))
4955 {
4956 m_modOnHd = true;
4957 m_modOnHdReason = 2;
4958
4959 // reenable dialog if not running atm
4960 if (m_isasking == -1)
4961 m_isasking = false;
4962
4963 emit modifiedOnDisc (this, m_modOnHd, m_modOnHdReason);
4964 }
4965}
4966
4967void KateDocument::slotModOnHdDeleted (const TQString &path)
4968{
4969 if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != 3))
4970 {
4971 m_modOnHd = true;
4972 m_modOnHdReason = 3;
4973
4974 // reenable dialog if not running atm
4975 if (m_isasking == -1)
4976 m_isasking = false;
4977
4978 emit modifiedOnDisc (this, m_modOnHd, m_modOnHdReason);
4979 }
4980}
4981
4982bool KateDocument::createDigest( TQCString &result )
4983{
4984 bool ret = false;
4985 result = "";
4986 if ( url().isLocalFile() )
4987 {
4988 TQFile f ( url().path() );
4989 if ( f.open( IO_ReadOnly) )
4990 {
4991 KMD5 md5;
4992 ret = md5.update( f );
4993 md5.hexDigest( result );
4994 f.close();
4995 ret = true;
4996 }
4997 }
4998 return ret;
4999}
5000
5001TQString KateDocument::reasonedMOHString() const
5002{
5003 switch( m_modOnHdReason )
5004 {
5005 case 1:
5006 return i18n("The file '%1' was modified by another program.").arg( url().pathOrURL() );
5007 break;
5008 case 2:
5009 return i18n("The file '%1' was created by another program.").arg( url().pathOrURL() );
5010 break;
5011 case 3:
5012 return i18n("The file '%1' was deleted by another program.").arg( url().pathOrURL() );
5013 break;
5014 default:
5015 return TQString();
5016 }
5017}
5018
5019void KateDocument::removeTrailingSpace( uint line )
5020{
5021 // remove trailing spaces from left line if required
5022 if ( config()->configFlags() & KateDocumentConfig::cfRemoveTrailingDyn )
5023 {
5024 KateTextLine::Ptr ln = kateTextLine( line );
5025
5026 if ( ! ln ) return;
5027
5028 if ( line == activeView()->cursorLine()
5029 && activeView()->cursorColumnReal() >= (uint)kMax(0,ln->lastChar()) )
5030 return;
5031
5032 if ( ln->length() )
5033 {
5034 uint p = ln->lastChar() + 1;
5035 uint l = ln->length() - p;
5036 if ( l )
5037 editRemoveText( line, p, l);
5038 }
5039 }
5040}
5041
5042void KateDocument::updateFileType (int newType, bool user)
5043{
5044 if (user || !m_fileTypeSetByUser)
5045 {
5046 const KateFileType *t = 0;
5047 if ((newType == -1) || (t = KateFactory::self()->fileTypeManager()->fileType (newType)))
5048 {
5049 m_fileType = newType;
5050
5051 if (t)
5052 {
5053 m_config->configStart();
5054 // views!
5055 KateView *v;
5056 for (v = m_views.first(); v != 0L; v= m_views.next() )
5057 {
5058 v->config()->configStart();
5059 v->renderer()->config()->configStart();
5060 }
5061
5062 readVariableLine( t->varLine );
5063
5064 m_config->configEnd();
5065 for (v = m_views.first(); v != 0L; v= m_views.next() )
5066 {
5067 v->config()->configEnd();
5068 v->renderer()->config()->configEnd();
5069 }
5070 }
5071 }
5072 }
5073}
5074
5075uint KateDocument::documentNumber () const
5076{
5077 return KTextEditor::Document::documentNumber ();
5078}
5079
5080long KateDocument::documentListPosition () const
5081{
5082 return KTextEditor::Document::documentListPosition ();
5083}
5084
5085void KateDocument::setDocumentListPosition (long pos)
5086{
5087 KTextEditor::Document::setDocumentListPosition (pos);
5088}
5089
5090
5091
5092void KateDocument::slotQueryClose_save(bool *handled, bool* abortClosing) {
5093 *handled=true;
5094 *abortClosing=true;
5095 if (m_url.isEmpty())
5096 {
5097 KEncodingFileDialog::Result res=KEncodingFileDialog::getSaveURLAndEncoding(config()->encoding(),
5098 TQString::null,TQString::null,0,i18n("Save File"));
5099
5100 if( res.URLs.isEmpty() || !checkOverwrite( res.URLs.first() ) ) {
5101 *abortClosing=true;
5102 return;
5103 }
5104 setEncoding( res.encoding );
5105 saveAs( res.URLs.first() );
5106 *abortClosing=false;
5107 }
5108 else
5109 {
5110 save();
5111 *abortClosing=false;
5112 }
5113
5114}
5115
5116bool KateDocument::checkOverwrite( KURL u )
5117{
5118 if( !u.isLocalFile() )
5119 return true;
5120
5121 TQFileInfo info( u.path() );
5122 if( !info.exists() )
5123 return true;
5124
5125 return KMessageBox::Cancel != KMessageBox::warningContinueCancel( 0,
5126 i18n( "A file named \"%1\" already exists. "
5127 "Are you sure you want to overwrite it?" ).arg( info.fileName() ),
5128 i18n( "Overwrite File?" ),
5129 i18n( "&Overwrite" ) );
5130}
5131
5132void KateDocument::setDefaultEncoding (const TQString &encoding)
5133{
5134 s_defaultEncoding = encoding;
5135}
5136
5137//BEGIN KTextEditor::TemplateInterface
5138bool KateDocument::insertTemplateTextImplementation ( uint line, uint column, const TQString &templateString, const TQMap<TQString,TQString> &initialValues, TQWidget *) {
5139 return (new KateTemplateHandler(this,line,column,templateString,initialValues))->initOk();
5140}
5141
5142void KateDocument::testTemplateCode() {
5143 int col=activeView()->cursorColumn();
5144 int line=activeView()->cursorLine();
5145 insertTemplateText(line,col,"for ${index} \\${NOPLACEHOLDER} ${index} ${blah} ${fullname} \\$${Placeholder} \\${${PLACEHOLDER2}}\n next line:${ANOTHERPLACEHOLDER} $${DOLLARBEFOREPLACEHOLDER} {NOTHING} {\n${cursor}\n}",TQMap<TQString,TQString>());
5146}
5147
5148bool KateDocument::invokeTabInterceptor(KKey key) {
5149 if (m_tabInterceptor) return (*m_tabInterceptor)(key);
5150 return false;
5151}
5152
5153bool KateDocument::setTabInterceptor(KateKeyInterceptorFunctor *interceptor) {
5154 if (m_tabInterceptor) return false;
5155 m_tabInterceptor=interceptor;
5156 return true;
5157}
5158
5159bool KateDocument::removeTabInterceptor(KateKeyInterceptorFunctor *interceptor) {
5160 if (m_tabInterceptor!=interceptor) return false;
5161 m_tabInterceptor=0;
5162 return true;
5163}
5164//END KTextEditor::TemplateInterface
5165
5166//BEGIN DEPRECATED STUFF
5167 bool KateDocument::setSelection ( uint startLine, uint startCol, uint endLine, uint endCol )
5168{ if (m_activeView) return m_activeView->setSelection (startLine, startCol, endLine, endCol); return false; }
5169
5170 bool KateDocument::clearSelection ()
5171 { if (m_activeView) return m_activeView->clearSelection(); return false; }
5172
5173 bool KateDocument::hasSelection () const
5174 { if (m_activeView) return m_activeView->hasSelection (); return false; }
5175
5176 TQString KateDocument::selection () const
5177 { if (m_activeView) return m_activeView->selection (); return TQString(""); }
5178
5179 bool KateDocument::removeSelectedText ()
5180 { if (m_activeView) return m_activeView->removeSelectedText (); return false; }
5181
5182 bool KateDocument::selectAll()
5183 { if (m_activeView) return m_activeView->selectAll (); return false; }
5184
5185 int KateDocument::selStartLine()
5186 { if (m_activeView) return m_activeView->selStartLine (); return 0; }
5187
5188 int KateDocument::selStartCol()
5189 { if (m_activeView) return m_activeView->selStartCol (); return 0; }
5190
5191 int KateDocument::selEndLine()
5192 { if (m_activeView) return m_activeView->selEndLine (); return 0; }
5193
5194 int KateDocument::selEndCol()
5195 { if (m_activeView) return m_activeView->selEndCol (); return 0; }
5196
5197 bool KateDocument::blockSelectionMode ()
5198 { if (m_activeView) return m_activeView->blockSelectionMode (); return false; }
5199
5200bool KateDocument::setBlockSelectionMode (bool on)
5201 { if (m_activeView) return m_activeView->setBlockSelectionMode (on); return false; }
5202
5203bool KateDocument::toggleBlockSelectionMode ()
5204 { if (m_activeView) return m_activeView->toggleBlockSelectionMode (); return false; }
5205//END DEPRECATED
5206
5207//END DEPRECATED STUFF
KDialogBase
KDialogBase::addVBoxPage
TQVBox * addVBoxPage(const TQString &itemName, const TQString &header=TQString::null, const TQPixmap &pixmap=TQPixmap())
KDialogBase::Help
Help
KDialogBase::Ok
Ok
KDialogBase::Cancel
Cancel
KKey
KMD5
KMD5::update
void update(const char *in, int len=-1)
KMD5::hexDigest
TQCString hexDigest()
KMessageBox::information
static void information(TQWidget *parent, const TQString &text, const TQString &caption=TQString::null, const TQString &dontShowAgainName=TQString::null, int options=Notify)
KMessageBox::error
static void error(TQWidget *parent, const TQString &text, const TQString &caption=TQString::null, int options=Notify)
KMessageBox::warningYesNoCancel
static int warningYesNoCancel(TQWidget *parent, const TQString &text, const TQString &caption=TQString::null, const KGuiItem &buttonYes=KStdGuiItem::yes(), const KGuiItem &buttonNo=KStdGuiItem::no(), const TQString &dontAskAgainName=TQString::null, int options=Notify)
KMessageBox::warningContinueCancel
static int warningContinueCancel(TQWidget *parent, const TQString &text, const TQString &caption=TQString::null, const KGuiItem &buttonContinue=KStdGuiItem::cont(), const TQString &dontAskAgainName=TQString::null, int options=Notify)
KParts::GUIActivateEvent
KParts::ReadOnlyPart::guiActivateEvent
virtual void guiActivateEvent(GUIActivateEvent *event)
KParts::ReadWritePart::setReadWrite
virtual void setReadWrite(bool readwrite=true)
KParts::ReadWritePart::saveAs
virtual bool saveAs(const KURL &url)
KParts::ReadWritePart::closeURL
virtual bool closeURL()
KParts::ReadWritePart::save
virtual bool save()
KParts::ReadWritePart::setModified
virtual void setModified()
KTempFile
KURL
KURL::path
TQString path() const
KURL::directory
TQString directory(bool _strip_trailing_slash_from_result=true, bool _ignore_trailing_slash_in_path=true) const
KURL::fileName
TQString fileName(bool _ignore_trailing_slash_in_path=true) const
KURL::filename
TQString filename(bool _ignore_trailing_slash_in_path=true) const
KURL::isLocalFile
bool isLocalFile() const
KURL::prettyURL
TQString prettyURL(int _trailing=0) const
KURL::isValid
bool isValid() const
KWin::setIcons
static void setIcons(WId win, const TQPixmap &icon, const TQPixmap &miniIcon)
KXMLGUIFactory
KXMLGUIFactory::removeClient
void removeClient(KXMLGUIClient *client)
KXMLGUIFactory::addClient
void addClient(KXMLGUIClient *client)
KateArbitraryHighlight
An arbitrary highlighting interface for Kate.
Definition: katearbitraryhighlight.h:61
KateAutoIndent::modeNumber
virtual uint modeNumber() const
Mode index of this mode.
Definition: kateautoindent.h:185
KateAutoIndent::createIndenter
static KateAutoIndent * createIndenter(KateDocument *doc, uint mode)
Static methods to create and list indention modes.
Definition: kateautoindent.cpp:38
KateBrowserExtension
Interface for embedding KateDocument into a browser.
Definition: katedocumenthelpers.h:37
KateBuffer
The KateBuffer class maintains a collections of lines.
Definition: katebuffer.h:342
KateBuffer::setMaxLoadedBlocks
static void setMaxLoadedBlocks(uint count)
modifier for max loaded blocks limit
Definition: katebuffer.cpp:79
KateBuffer::maxLoadedBlocks
static uint maxLoadedBlocks()
maximal loaded block count
Definition: katebuffer.h:352
KateDocCursor
Cursor class with a pointer to its document.
Definition: katecursor.h:93
KateModOnHdPrompt
This dialog will prompt the user for what do with a file that is modified on disk.
Definition: katedialogs.h:371
KateSuperCursor
Possible additional features:
Definition: katesupercursor.h:46
KateSuperRange
Represents a range of text, from the start() to the end().
Definition: katesupercursor.h:169
KateTextCursor
Simple cursor class with no document pointer.
Definition: katecursor.h:34
KateTextLine
The KateTextLine represents a line of text.
Definition: katetextline.h:42
KateUndoGroup
Class to manage a group of undo items.
Definition: kateundo.h:34
KateUndoGroup::UndoType
UndoType
Types for undo items.
Definition: kateundo.h:63
Kate::Document
This interface provides access to the Kate Document class.
Definition: document.h:190
Kate::View
The Kate::View text editor interface.
Definition: view.h:45
TDEConfigBase::readEntry
TQString readEntry(const TQString &pKey, const TQString &aDefault=TQString::null) const
TDEConfigBase::readNumEntry
int readNumEntry(const TQString &pKey, int nDefault=0) const
TDEConfigBase::readIntListEntry
TQValueList< int > readIntListEntry(const TQString &pKey) const
TDEConfigBase::sync
virtual void sync()
TDEConfigBase::writeEntry
void writeEntry(const TQString &pKey, const TQString &pValue, bool bPersistent=true, bool bGlobal=false, bool bNLS=false)
TDEConfigBase::setGroup
void setGroup(const TQString &group)
TDEConfig
TDEGlobal::dirs
static TDEStandardDirs * dirs()
TDEIcon::SizeMedium
SizeMedium
TDESharedPtr
TDESharedPtr::count
int count() const
TDEStandardDirs::relativeLocation
TQString relativeLocation(const char *type, const TQString &absPath)
endl
kndbgstream & endl(kndbgstream &s)
kdDebug
kdbgstream kdDebug(int area=0)
flush
kndbgstream & flush(kndbgstream &s)
KNotifyClient::instance
TDEInstance * instance()
KStdAction::clear
TDEAction * clear(const TQObject *recvr, const char *slot, TDEActionCollection *parent, const char *name=0)
KStdAction::saveAs
TDEAction * saveAs(const TQObject *recvr, const char *slot, TDEActionCollection *parent, const char *name=0)
Kate
Kate namespace All classes in this namespace must stay BC during one major release series (e....
Definition: document.h:51
TDEStdAccel::forward
const TDEShortcut & forward()
TDEStdAccel::key
int key(StdAccel id)
TDEStdAccel::name
TQString name(StdAccel id)
TDEStdAccel::end
const TDEShortcut & end()
TDEStdAccel::save
const TDEShortcut & save()
tdelocale.h

kate

Skip menu "kate"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kate

Skip menu "kate"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for kate by doxygen 1.9.4
This website is maintained by Timothy Pearson.