/***************************************************************************
document . cpp - description
- - - - - - - - - - - - - - - - - - -
begin : Tue Jun 6 2000
copyright : ( C ) 2000 by Dmitry Poplavsky & Alexander Yakovlev & Eric Laffoon < pdima @ users . sourceforge . net , yshurik @ penguinpowered . com , sequitur @ easystreet . com >
( C ) 2001 - 2004 Andras Mantia < amantia @ kde . org >
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/***************************************************************************
* *
* This program is free software ; you can redistribute it and / or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation ; either version 2 of the License , or *
* ( at your option ) any later version . *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <list>
# include <cctype>
# include <cstdlib>
# include <stdlib.h>
//QT includes
# include <tqcheckbox.h>
# include <tqdir.h>
# include <tqeventloop.h>
# include <tqfile.h>
# include <tqfileinfo.h>
# include <tqlineedit.h>
# include <tqtextcodec.h>
# include <tqtextstream.h>
# include <tqregexp.h>
# include <tqradiobutton.h>
// KDE includes
# include <kapplication.h>
# include <kwin.h>
# include <klocale.h>
# include <kaction.h>
# include <kactionclasses.h>
# include <kdialogbase.h>
# include <kiconloader.h>
# include <kmdcodec.h>
# include <kmessagebox.h>
# include <ktempfile.h>
# include <kdirwatch.h>
# include <kdebug.h>
# include <kprogress.h>
# include <kio/netaccess.h>
# include <kstandarddirs.h>
# include <ktexteditor/document.h>
# include <ktexteditor/view.h>
# include <ktexteditor/cursorinterface.h>
# include <ktexteditor/clipboardinterface.h>
# include <ktexteditor/codecompletioninterface.h>
# include <ktexteditor/configinterface.h>
# include <ktexteditor/editinterface.h>
# include <ktexteditor/editinterfaceext.h>
# include <ktexteditor/encodinginterface.h>
# include <ktexteditor/selectioninterface.h>
# include <ktexteditor/selectioninterfaceext.h>
# include <ktexteditor/viewcursorinterface.h>
# include <ktexteditor/wordwrapinterface.h>
# include <ktexteditor/markinterfaceextension.h>
# include <kate/view.h>
# include "tag.h"
# include "quantacommon.h"
# include "document.h"
# include "resource.h"
# include "dirtydlg.h"
# include "dirtydialog.h"
# include "casewidget.h"
# include "project.h"
# include "dtdselectdialog.h"
# include "quanta.h"
# include "quantaview.h"
# include "structtreeview.h"
# include "qextfileinfo.h"
# include "viewmanager.h"
# include "messageoutput.h"
# include "undoredo.h"
# include "dtds.h"
# include "sagroupparser.h"
# define STEP 1
extern GroupElementMapList globalGroupMap ;
Document : : Document ( KTextEditor : : Document * doc ,
TQWidget * parent , const char * name , WFlags f )
: TQWidget ( parent , name , f )
{
m_dirty = false ;
busy = false ;
changed = false ;
m_md5sum = " " ;
m_doc = doc ;
m_view = 0L ; //needed, because createView() calls processEvents() and the "this" may be deleted before m_view gets a value => crash on delete m_view;
m_view = m_doc - > createView ( parent , 0L ) ;
completionInProgress = false ;
argHintVisible = false ;
completionRequested = false ;
userTagList . setAutoDelete ( true ) ;
// remove the unwanted actions
KAction * a = m_view - > actionCollection ( ) - > action ( " file_export " ) ;
if ( a )
m_view - > actionCollection ( ) - > take ( a ) ;
a = m_view - > actionCollection ( ) - > action ( " file_save " ) ;
if ( a )
m_view - > actionCollection ( ) - > take ( a ) ;
a = m_view - > actionCollection ( ) - > action ( " file_save_as " ) ;
if ( a )
m_view - > actionCollection ( ) - > take ( a ) ;
a = m_view - > actionCollection ( ) - > action ( " file_reload " ) ;
if ( a )
m_view - > actionCollection ( ) - > take ( a ) ;
a = m_view - > actionCollection ( ) - > action ( " edit_undo " ) ;
if ( a )
m_view - > actionCollection ( ) - > take ( a ) ;
a = m_view - > actionCollection ( ) - > action ( " edit_redo " ) ;
if ( a )
m_view - > actionCollection ( ) - > take ( a ) ;
//because they are not implemented in VPL
a = m_view - > actionCollection ( ) - > action ( " edit_copy " ) ;
if ( a )
m_view - > actionCollection ( ) - > take ( a ) ;
a = m_view - > actionCollection ( ) - > action ( " edit_cut " ) ;
if ( a )
m_view - > actionCollection ( ) - > take ( a ) ;
a = m_view - > actionCollection ( ) - > action ( " edit_paste " ) ;
if ( a )
m_view - > actionCollection ( ) - > take ( a ) ;
//conflicting shortcuts, so change them
a = m_view - > actionCollection ( ) - > action ( " view_border " ) ;
if ( a )
a - > setShortcut ( Qt : : SHIFT + Qt : : Key_F9 ) ;
a = m_view - > actionCollection ( ) - > action ( " view_folding_markers " ) ;
if ( a )
a - > setShortcut ( Qt : : SHIFT + Qt : : Key_F11 ) ;
KActionMenu * bookmarkAction = dynamic_cast < KActionMenu * > ( m_view - > actionCollection ( ) - > action ( " bookmarks " ) ) ;
if ( bookmarkAction )
{
m_view - > actionCollection ( ) - > take ( bookmarkAction ) ;
//kdDebug(24000) << "Bookmarks found!" << endl;
//bookmarkAction->insert(quantaApp->actionCollection()->action( "file_quit" ));
}
editIf = dynamic_cast < KTextEditor : : EditInterface * > ( m_doc ) ;
editIfExt = dynamic_cast < KTextEditor : : EditInterfaceExt * > ( m_doc ) ;
encodingIf = dynamic_cast < KTextEditor : : EncodingInterface * > ( m_doc ) ;
m_encoding = quantaApp - > defaultEncoding ( ) ;
if ( encodingIf )
m_encoding = encodingIf - > encoding ( ) ;
if ( m_encoding . isEmpty ( ) )
m_encoding = " utf8 " ; //final fallback
m_codec = TQTextCodec : : codecForName ( m_encoding . ascii ( ) ) ;
selectionIf = dynamic_cast < KTextEditor : : SelectionInterface * > ( m_doc ) ;
selectionIfExt = dynamic_cast < KTextEditor : : SelectionInterfaceExt * > ( m_doc ) ;
configIf = dynamic_cast < KTextEditor : : ConfigInterface * > ( m_doc ) ;
if ( configIf )
configIf - > readConfig ( ) ;
viewCursorIf = dynamic_cast < KTextEditor : : ViewCursorInterface * > ( m_view ) ;
codeCompletionIf = dynamic_cast < KTextEditor : : CodeCompletionInterface * > ( m_view ) ;
markIf = dynamic_cast < KTextEditor : : MarkInterface * > ( m_doc ) ;
KTextEditor : : MarkInterfaceExtension * iface = dynamic_cast < KTextEditor : : MarkInterfaceExtension * > ( m_doc ) ;
if ( iface )
{
iface - > setPixmap ( KTextEditor : : MarkInterface : : markType07 , SmallIcon ( " stop " ) ) ;
iface - > setPixmap ( KTextEditor : : MarkInterface : : markType02 , SmallIcon ( " debug_breakpoint " ) ) ;
iface - > setDescription ( KTextEditor : : MarkInterface : : markType02 , i18n ( " Breakpoint " ) ) ;
iface - > setPixmap ( KTextEditor : : MarkInterface : : markType05 , SmallIcon ( " debug_currentline " ) ) ;
iface - > setDescription ( KTextEditor : : MarkInterface : : markType08 , i18n ( " Annotation " ) ) ;
iface - > setPixmap ( KTextEditor : : MarkInterface : : markType08 , SmallIcon ( " stamp " ) ) ;
// This is allows user to set breakpoints and bookmarks by clicking or rightclicking on the icon border.
iface - > setMarksUserChangable ( KTextEditor : : MarkInterface : : markType01 + KTextEditor : : MarkInterface : : markType02 ) ;
}
tempFile = 0 ;
m_tempFileName = TQString : : null ;
dtdName = Project : : ref ( ) - > defaultDTD ( ) ;
reparseEnabled = true ;
repaintEnabled = true ;
delayedTextChangedEnabled = true ;
docUndoRedo = new undoRedo ( this ) ;
//path of the backup copy file of the document
m_backupPathValue = TQString : : null ;
connect ( m_doc , TQT_SIGNAL ( charactersInteractivelyInserted ( int , int , const TQString & ) ) ,
this , TQT_SLOT ( slotCharactersInserted ( int , int , const TQString & ) ) ) ;
connect ( m_view , TQT_SIGNAL ( completionAborted ( ) ) ,
this , TQT_SLOT ( slotCompletionAborted ( ) ) ) ;
connect ( m_view , TQT_SIGNAL ( completionDone ( KTextEditor : : CompletionEntry ) ) ,
this , TQT_SLOT ( slotCompletionDone ( KTextEditor : : CompletionEntry ) ) ) ;
connect ( m_view , TQT_SIGNAL ( filterInsertString ( KTextEditor : : CompletionEntry * , TQString * ) ) ,
this , TQT_SLOT ( slotFilterCompletion ( KTextEditor : : CompletionEntry * , TQString * ) ) ) ;
connect ( m_doc , TQT_SIGNAL ( textChanged ( ) ) , TQT_SLOT ( slotTextChanged ( ) ) ) ;
connect ( m_view , TQT_SIGNAL ( gotFocus ( Kate : : View * ) ) , TQT_SIGNAL ( editorGotFocus ( ) ) ) ;
connect ( fileWatcher , TQT_SIGNAL ( dirty ( const TQString & ) ) , TQT_SLOT ( slotFileDirty ( const TQString & ) ) ) ;
// connect(m_doc, TQT_SIGNAL(marksChanged()), this, TQT_SLOT(slotMarksChanged()));
connect ( m_doc , TQT_SIGNAL ( markChanged ( KTextEditor : : Mark , KTextEditor : : MarkInterfaceExtension : : MarkChangeAction ) ) , this , TQT_SLOT ( slotMarkChanged ( KTextEditor : : Mark , KTextEditor : : MarkInterfaceExtension : : MarkChangeAction ) ) ) ;
}
Document : : ~ Document ( )
{
if ( configIf )
configIf - > writeConfig ( ) ;
parser - > clearGroups ( ) ;
// kdDebug(24000) << "Document::~ Document: " << this << endl;
m_doc - > closeURL ( false ) ; //TODO: Workaround for a Kate bug. Remove when KDE < 3.2.0 support is dropped.
delete m_doc ;
}
void Document : : setUntitledUrl ( const TQString & url )
{
untitledUrl = url ;
openURL ( KURL ( ) ) ;
}
bool Document : : isUntitled ( )
{
return ( m_doc - > url ( ) . url ( ) . isEmpty ( ) ) ? true : false ;
}
KURL Document : : url ( )
{
return ( isUntitled ( ) ) ? KURL ( " file: " + untitledUrl ) : m_doc - > url ( ) ;
}
// kwrite addons
void Document : : insertTag ( const TQString & s1 , const TQString & s2 )
{
TQString selection ;
if ( selectionIf & & selectionIf - > hasSelection ( ) )
{
reparseEnabled = false ;
selection = selectionIf - > selection ( ) ;
selectionIf - > removeSelectedText ( ) ;
reparseEnabled = true ;
}
insertText ( s1 + selection ) ;
insertText ( s2 , false ) ; // don't adjust cursor, thereby leaving it in the middle of tag
}
/** Change the current tag's attributes with those from dict */
void Document : : changeTag ( Tag * tag , TQDict < TQString > * dict )
{
tag - > modifyAttributes ( dict ) ;
TQString tagStr = tag - > toString ( ) ;
reparseEnabled = false ;
int bLine , bCol , eLine , eCol ;
tag - > beginPos ( bLine , bCol ) ;
tag - > endPos ( eLine , eCol ) ;
editIf - > removeText ( bLine , bCol , eLine , eCol + 1 ) ;
viewCursorIf - > setCursorPositionReal ( ( uint ) bLine , ( uint ) bCol ) ;
insertText ( tagStr ) ;
}
/**Change the namespace in a tag. Add if it's not present, or remove if the
namespace argument is empty */
void Document : : changeTagNamespace ( Tag * tag , const TQString & nameSpace )
{
int bl , bc ;
int nl , nc ;
if ( ! tag - > nameSpace . isEmpty ( ) )
{
tag - > beginPos ( bl , bc ) ;
if ( tag - > type = = Tag : : XmlTagEnd )
bc + + ;
tag - > namePos ( nl , nc ) ;
reparseEnabled = false ;
editIf - > removeText ( bl , bc + 1 , nl , nc ) ;
reparseEnabled = true ;
} else
{
tag - > beginPos ( bl , bc ) ;
if ( tag - > type = = Tag : : XmlTagEnd )
bc + + ;
}
if ( ! nameSpace . isEmpty ( ) )
{
viewCursorIf - > setCursorPositionReal ( ( uint ) bl , ( uint ) ( bc + 1 ) ) ;
insertText ( nameSpace + " : " , true , false ) ;
}
slotDelayedTextChanged ( true ) ;
quantaApp - > slotNewLineColumn ( ) ;
}
/**Change the attr value of the called attrName to attrValue*/
void Document : : changeTagAttribute ( Tag * tag , const TQString & attrName , const TQString & attrValue )
{
TQString value ;
int line , col ;
int index = tag - > attributeIndex ( attrName ) ;
if ( index ! = - 1 )
{
int endCol ;
value = tag - > attributeValue ( index ) ;
if ( value = = attrValue )
return ;
int aLine , aCol ;
tag - > attributeNamePos ( index , aLine , aCol ) ;
tag - > attributeValuePos ( index , line , col ) ;
if ( line = = aLine & & col = = aCol )
{
col + = tag - > attribute ( index ) . length ( ) ;
value = TQString ( " = " ) + qConfig . attrValueQuotation + attrValue + qConfig . attrValueQuotation ;
} else
{
endCol = col + value . length ( ) ;
if ( attrValue . isEmpty ( ) )
{
tag - > attributeNamePos ( index , line , col ) ;
endCol + + ;
}
reparseEnabled = false ;
TQString textLine = editIf - > textLine ( line ) ;
while ( col > 1 & & textLine [ col - 1 ] . isSpace ( ) )
col - - ;
editIf - > removeText ( line , col , line , endCol ) ;
reparseEnabled = true ;
value = attrValue ;
}
} else
{
index = tag - > attrCount ( ) - 1 ;
if ( tag - > attribute ( index ) = = " / " )
{
tag - > attributeNamePos ( index , line , col ) ;
col - - ;
} else
{
tag - > endPos ( line , col ) ;
}
if ( attrValue . isEmpty ( ) )
{
value = " " ;
} else
{
value = " " + QuantaCommon : : attrCase ( attrName ) + " = " + qConfig . attrValueQuotation + attrValue + qConfig . attrValueQuotation ;
}
}
if ( ! value . isEmpty ( ) )
{
viewCursorIf - > setCursorPositionReal ( ( uint ) line , ( uint ) col ) ;
insertText ( value ) ;
}
quantaApp - > slotNewLineColumn ( ) ;
//else
// slotDelayedTextChanged();
}
void Document : : selectText ( int x1 , int y1 , int x2 , int y2 )
{
if ( selectionIf )
selectionIf - > setSelection ( x1 , y1 , x2 , y2 ) ;
}
void Document : : replaceSelected ( const TQString & s )
{
if ( selectionIf )
{
unsigned int line , col ;
viewCursorIf - > cursorPositionReal ( & line , & col ) ;
reparseEnabled = false ;
selectionIf - > removeSelectedText ( ) ;
reparseEnabled = true ;
editIf - > insertText ( line , col , s ) ;
}
}
void Document : : insertFile ( const KURL & url )
{
TQString fileName ;
if ( url . isLocalFile ( ) )
{
fileName = url . path ( ) ;
} else
{
if ( ! KIO : : NetAccess : : download ( url , fileName , this ) )
{
KMessageBox : : error ( this , i18n ( " <qt>Cannot download <b>%1</b>.</qt> " ) . arg ( url . prettyURL ( 0 , KURL : : StripFileProtocol ) ) ) ;
return ;
}
}
TQFile file ( fileName ) ;
if ( file . open ( IO_ReadOnly ) )
{
TQTextStream stream ( & file ) ;
stream . setEncoding ( TQTextStream : : UnicodeUTF8 ) ;
insertText ( stream . read ( ) ) ;
file . close ( ) ;
} else
KMessageBox : : error ( this , i18n ( " <qt>Cannot open <b>%1</b> for reading.</qt> " ) . arg ( url . prettyURL ( 0 , KURL : : StripFileProtocol ) ) ) ;
}
/** Inserts text at the current cursor position */
void Document : : insertText ( const TQString & a_text , bool adjustCursor , bool reparse )
{
TQString text = a_text ;
if ( text . isEmpty ( ) )
return ;
reparseEnabled = false ;
unsigned int line , col ;
viewCursorIf - > cursorPositionReal ( & line , & col ) ;
Node * n = parser - > nodeAt ( line , col , true ) ;
if ( n & & n - > tag - > dtd ( ) - > family ! = Xml )
{
int bLine , bCol ;
n - > tag - > beginPos ( bLine , bCol ) ;
TQString s = this - > text ( bLine , bCol , line , col ) ;
bool insideQuotes = false ;
for ( int i = 0 ; i < ( int ) s . length ( ) - 1 ; i + + )
{
if ( s [ i ] = = ' " ' & & ( i = = 0 | | s [ i - 1 ] ! = ' \\ ' ) )
insideQuotes = ! insideQuotes ;
}
int eLine , eCol ;
n - > tag - > endPos ( eLine , eCol ) ;
s = this - > text ( line + 1 , col , eLine , eCol ) ;
bool closeQuotationFound = false ;
for ( int i = 0 ; i < ( int ) s . length ( ) - 1 ; i + + )
{
if ( s [ i ] = = ' " ' & & ( i = = 0 | | s [ i - 1 ] ! = ' \\ ' ) )
{
closeQuotationFound = true ;
break ;
}
}
if ( insideQuotes & & closeQuotationFound )
{
text . replace ( " \\ \" " , " \" " ) ;
text . replace ( " \" " , " \\ \" " ) ;
}
}
editIf - > insertText ( line , col , text ) ;
// calculate new cursor position
// counts the words and whitespace of the text so we can place the
// cursor correctly and quickly with the viewCursorInterace, avoiding
// the KTexEditor::insertText method
if ( adjustCursor )
{
unsigned textLength = text . length ( ) ;
unsigned int wordWrapAt = 80 ;
bool noWordWrap = false ;
KTextEditor : : WordWrapInterface * wordWrapIf = dynamic_cast < KTextEditor : : WordWrapInterface * > ( m_doc ) ;
if ( wordWrapIf )
{
wordWrapAt = wordWrapIf - > wordWrapAt ( ) ;
noWordWrap = ! ( wordWrapIf - > wordWrap ( ) ) ;
}
uint i = 0 , j = 0 ;
int wordLength ;
const char * ascii = text . latin1 ( ) ; // use ascii for maximum speed
bool lineLock = false ;
while ( i < textLength )
{
if ( ascii [ i ] = = ' \n ' ) // add a line, first column
{
+ + line ; col = 0 ; + + i ; lineLock = false ;
}
else if ( ascii [ i ] = = ' \r ' )
{
col = 0 ; + + i ;
}
else if ( ! noWordWrap & & ! ( isspace ( ascii [ i ] ) ) ) // new word, see if it wraps
{
// TOO SLOW int wordLength = (text.mid(i).section(TQRegExp("[ \t\r\n]"), 0, 0).length());
wordLength = - 1 ;
for ( j = i + 1 ; ascii [ j ] ; + + j ) // get word size, ascii is MUCH faster
{
if ( isspace ( ascii [ j ] ) )
{
wordLength = j - i ;
break ;
}
}
if ( wordLength = = - 1 )
wordLength = ( textLength ) - i ;
if ( ( wordLength + col ) > wordWrapAt )
{
if ( col & & ! lineLock ) // wraps onto new line unless locked by kate
{
col = 0 ;
+ + line ;
}
}
col + = wordLength ;
i + = wordLength ;
if ( wordLength > ( int ) wordWrapAt )
lineLock = true ; // words > wordWrapAt lock the rest of the line
}
else // whitespace
{
+ + col ; + + i ;
if ( ! noWordWrap )
if ( col > wordWrapAt & & ! lineLock ) // wrap like words
{
col - = wordWrapAt ;
+ + line ;
}
}
}
}
viewCursorIf - > setCursorPositionReal ( line , col ) ;
reparseEnabled = true ;
if ( reparse )
{
baseNode = parser - > rebuild ( this ) ;
if ( qConfig . instantUpdate & & quantaApp - > structTreeVisible ( ) )
{
typingInProgress = false ;
StructTreeView : : ref ( ) - > slotReparse ( this , baseNode , qConfig . expandLevel ) ;
}
quantaApp - > updateTreeViews ( ) ;
}
}
bool Document : : insertChildTags ( QTag * tag , QTag * lastTag )
{
bool childInserted = false ;
if ( ! tag | | tag = = lastTag ) //avoid infinite recursion
{
return false ;
}
TQMap < TQString , bool > : : Iterator it ;
for ( it = tag - > childTags . begin ( ) ; it ! = tag - > childTags . end ( ) ; + + it )
{
if ( it . data ( ) )
{
childInserted = true ;
QTag * childTag = QuantaCommon : : tagFromDTD ( tag - > parentDTD , it . key ( ) ) ;
TQString tagStr = QuantaCommon : : tagCase ( it . key ( ) ) ;
if ( tag - > parentDTD - > singleTagStyle = = " xml " & &
( childTag - > isSingle ( ) | |
( childTag - > isOptional ( ) & & ! qConfig . closeOptionalTags ) ) )
{
insertText ( " < " + tagStr + " /> " , true , false ) ;
} else
{
insertText ( " < " + tagStr + " > " , true , false ) ;
}
TQString closingStr ;
if ( insertChildTags ( childTag , tag ) )
{
closingStr = " " ;
}
if ( ( ! childTag - > isSingle ( ) & & ! childTag - > isOptional ( ) & & qConfig . closeTags ) | |
( childTag - > isOptional ( ) & & qConfig . closeOptionalTags ) )
{
insertText ( closingStr + " </ " + tagStr + " > " , true , false ) ;
}
}
}
return childInserted ;
}
/** Get the view of the document */
KTextEditor : : View * Document : : view ( )
{
return m_view ;
}
/** Get the KTextEditor::Document of the document */
KTextEditor : : Document * Document : : doc ( )
{
return m_doc ;
}
/** Returns true if the document was modified. */
bool Document : : isModified ( )
{
bool modified = false ;
if ( m_doc )
modified = m_doc - > isModified ( ) ;
return modified ;
}
void Document : : setModified ( bool flag )
{
if ( m_doc )
m_doc - > setModified ( flag ) ;
}
void Document : : createTempFile ( )
{
closeTempFile ( ) ;
tempFile = new KTempFile ( tmpDir ) ;
tempFile - > setAutoDelete ( true ) ;
m_tempFileName = TQFileInfo ( * ( tempFile - > file ( ) ) ) . filePath ( ) ;
TQString encoding = quantaApp - > defaultEncoding ( ) ;
if ( encodingIf )
encoding = encodingIf - > encoding ( ) ;
if ( encoding . isEmpty ( ) )
encoding = " utf8 " ; //final fallback
tempFile - > textStream ( ) - > setCodec ( TQTextCodec : : codecForName ( encoding . ascii ( ) ) ) ;
* ( tempFile - > textStream ( ) ) < < editIf - > text ( ) ;
m_tempFileName = TQFileInfo ( * ( tempFile - > file ( ) ) ) . filePath ( ) ;
tempFile - > close ( ) ;
// kdDebug(24000) << "Creating tempfile " << m_tempFileName << " for " << url() << endl;
}
void Document : : closeTempFile ( )
{
if ( tempFile ! = 0 )
{
delete tempFile ;
tempFile = 0L ;
}
if ( TQFileInfo ( m_tempFileName ) . exists ( ) )
TQFile : : remove ( m_tempFileName ) ;
m_tempFileName = TQString : : null ;
}
TQString Document : : tempFileName ( )
{
return m_tempFileName ;
}
/** This will return the current tag name at the given position.
It will work even if the tag has not been completed yet . An
empty string will be returned if no tag is found .
*/
TQString Document : : getTagNameAt ( int line , int col )
{
TQString name = " " ;
TQString textLine = editIf - > textLine ( line ) ;
textLine = textLine . left ( col ) ;
while ( line > = 0 )
{
QuantaCommon : : removeCommentsAndQuotes ( textLine , completionDTD ) ;
int pos = textLine . findRev ( " < " ) ;
int pos2 = textLine . findRev ( " > " ) ;
if ( pos ! = - 1 & & pos2 < pos )
{
textLine . remove ( 0 , pos + 1 ) ;
pos = 0 ;
while ( pos < ( int ) textLine . length ( ) & &
! textLine [ pos ] . isSpace ( ) & &
textLine [ pos ] ! = ' > ' )
pos + + ;
name = textLine . left ( pos ) . stripWhiteSpace ( ) ;
pos = name . find ( " : " ) ;
if ( pos ! = - 1 )
name = name . mid ( pos + 1 ) ;
break ;
} else
{
if ( pos2 = = - 1 )
{
line - - ;
if ( line > = 0 )
textLine = editIf - > textLine ( line ) ;
} else
{
name = " " ;
break ;
}
}
}
return name ;
}
/** Show the code completions passed in as an argument */
void Document : : showCodeCompletions ( TQValueList < KTextEditor : : CompletionEntry > * completions ) {
bool reparse = reparseEnabled ;
reparseEnabled = false ;
codeCompletionIf - > showCompletionBox ( * completions , false ) ;
reparseEnabled = reparse ;
argHintVisible = false ;
delete completions ;
}
/** Once the completed text has been inserted into the document we
want to update the cursor position .
*/
void Document : : slotCompletionDone ( KTextEditor : : CompletionEntry completion )
{
unsigned int line , col ;
completionInProgress = false ;
argHintVisible = false ;
viewCursorIf - > cursorPositionReal ( & line , & col ) ;
const DTDStruct * dtd = currentDTD ( ) ;
/* if (completion.type == "charCompletion")
{
m_lastCompletionList = getCharacterCompletions ( completion . userdata ) ;
TQTimer : : singleShot ( 0 , this , TQT_SLOT ( slotDelayedShowCodeCompletion ( ) ) ) ;
} else */
if ( completion . type = = " attribute " )
{
viewCursorIf - > setCursorPositionReal ( line , col - 1 ) ;
if ( dtd )
{
QTag * tag = QuantaCommon : : tagFromDTD ( dtd , completion . userdata ) ;
if ( tag )
{
m_lastCompletionList = getAttributeValueCompletions ( tag - > name ( ) , completion . text ) ;
TQTimer : : singleShot ( 0 , this , TQT_SLOT ( slotDelayedShowCodeCompletion ( ) ) ) ;
}
}
} else
if ( completion . type = = " attributeValue " )
{
viewCursorIf - > setCursorPositionReal ( line , col ) ;
} else
if ( completion . type = = " doctypeList " )
{
viewCursorIf - > setCursorPositionReal ( line , col + 1 ) ;
} else
if ( completion . type = = " script " )
{
viewCursorIf - > setCursorPositionReal ( line , col ) ;
if ( dtd )
{
m_lastLine = line ;
m_lastCol = col - 1 ;
TQTimer : : singleShot ( 0 , this , TQT_SLOT ( slotDelayedScriptAutoCompletion ( ) ) ) ;
}
}
}
void Document : : slotDelayedScriptAutoCompletion ( )
{
scriptAutoCompletion ( m_lastLine , m_lastCol , " " ) ;
}
void Document : : slotDelayedShowCodeCompletion ( )
{
showCodeCompletions ( m_lastCompletionList ) ;
}
/** This is called when the user selects a completion. We
can filter this completion to allow more intelligent
code compeltions
*/
void Document : : slotFilterCompletion ( KTextEditor : : CompletionEntry * completion , TQString * string )
{
kdDebug ( 24000 ) < < * string < < endl ;
kdDebug ( 24000 ) < < completion - > userdata < < endl ;
int pos = completion - > userdata . find ( " | " ) ;
TQString s = completion - > userdata . left ( pos ) ;
completion - > userdata . remove ( 0 , pos + 1 ) ;
string - > remove ( 0 , s . length ( ) ) ;
kdDebug ( 24000 ) < < * string < < endl ;
kdDebug ( 24000 ) < < completion - > userdata < < endl ;
if ( completion - > type = = " charCompletion " )
{
* string = completion - > userdata ;
uint line , col ;
viewCursorIf - > cursorPositionReal ( & line , & col ) ;
TQString s2 = editIf - > textLine ( line ) . left ( col ) ;
kdDebug ( 24000 ) < < s2 < < endl ;
int pos = s2 . findRev ( ' & ' ) ;
if ( pos ! = - 1 )
{
s2 = s2 . mid ( pos + 1 ) ;
string - > remove ( s2 ) ;
}
string - > append ( " ; " ) ;
kdDebug ( 24000 ) < < * string < < endl ;
} else
if ( completion - > type = = " attributeValue " )
{
uint line , col ;
viewCursorIf - > cursorPositionReal ( & line , & col ) ;
TQString textLine = editIf - > textLine ( line ) ;
TQChar tagSeparator = completionDTD - > tagSeparator ;
if ( tagSeparator = = ' \' ' | | tagSeparator = = ' " ' )
tagSeparator = qConfig . attrValueQuotation ;
if ( textLine [ col ] ! = tagSeparator )
string - > append ( tagSeparator ) ;
} else
if ( completion - > type = = " attribute " )
{
string - > append ( " = " + TQString ( qConfig . attrValueQuotation ) + TQString ( qConfig . attrValueQuotation ) ) ;
} else
if ( completion - > type = = " doctypeList " )
{
s = * string ;
string - > remove ( 0 , string - > length ( ) ) ;
TQString s2 = TQString ( " public \" " + DTDs : : ref ( ) - > getDTDNameFromNickName ( s ) + " \" " ) ;
const DTDStruct * dtd = DTDs : : ref ( ) - > find ( DTDs : : ref ( ) - > getDTDNameFromNickName ( s ) ) ;
if ( dtd & & ! dtd - > url . isEmpty ( ) )
{
s2 + = " \" " + dtd - > url + " \" " ;
}
string - > append ( QuantaCommon : : attrCase ( s2 ) ) ;
} else
if ( completion - > type = = " script " )
{
string - > append ( completionDTD - > attrAutoCompleteAfter ) ;
}
}
void Document : : slotReplaceChar ( )
{
reparseEnabled = false ;
editIf - > removeText ( m_replaceLine , m_replaceCol , m_replaceLine , m_replaceCol + 1 ) ;
insertText ( m_replaceStr , true , false ) ;
}
/** Called when a user types in a character. From this we can show possibile
completions based on what they are trying to input .
*/
void Document : : slotCharactersInserted ( int line , int column , const TQString & string )
{
if ( qConfig . replaceNotInEncoding )
{
if ( encodingIf )
{
TQString encoding = encodingIf - > encoding ( ) ;
if ( encoding ! = m_encoding )
{
m_encoding = encoding ;
m_codec = TQTextCodec : : codecForName ( encoding . ascii ( ) ) ;
}
if ( ! m_codec - > canEncode ( string [ 0 ] ) )
{
m_replaceLine = line ;
m_replaceCol = column ;
m_replaceStr = QuantaCommon : : encodedChar ( string [ 0 ] . unicode ( ) ) ;
TQTimer : : singleShot ( 0 , this , TQT_SLOT ( slotReplaceChar ( ) ) ) ;
return ;
}
}
}
if ( qConfig . replaceAccented )
{
uint c = string [ 0 ] . unicode ( ) ;
if ( c > 191 )
{
m_replaceLine = line ;
m_replaceCol = column ;
m_replaceStr = QuantaCommon : : encodedChar ( c ) ;
TQTimer : : singleShot ( 0 , this , TQT_SLOT ( slotReplaceChar ( ) ) ) ;
return ;
}
}
if ( ( string = = " > " ) | |
( string = = " < " ) )
{
slotDelayedTextChanged ( true ) ;
}
bool handled = false ;
if ( qConfig . useAutoCompletion )
{
if ( completionInProgress )
{
handleCodeCompletion ( ) ;
} else
{
completionDTD = currentDTD ( ) ;
if ( completionDTD - > family = = Xml )
{
handled = xmlAutoCompletion ( line , column , string ) ;
}
if ( completionDTD - > family = = Script )
{
handled = scriptAutoCompletion ( line , column , string ) ;
if ( ! handled & & string = = " > " )
{
Node * node = parser - > nodeAt ( line , column , false ) ;
if ( node & & node - > tag - > validXMLTag & & node - > tag - > type = = Tag : : ScriptTag )
{
column + + ;
editIf - > insertText ( line , column , " </ " + node - > tag - > name + " > " ) ;
viewCursorIf - > setCursorPositionReal ( line , column ) ;
}
}
handled = true ;
}
if ( ! handled )
{
const DTDStruct * lastDTD = completionDTD ;
completionDTD = defaultDTD ( ) ;
if ( lastDTD ! = completionDTD & & completionDTD - > family = = Xml )
{
handled = xmlAutoCompletion ( line , column , string ) ;
}
/*TODO: Can the default DTD be a script?
if ( dtd - > family = = Script )
{
scriptAutoCompletion ( dtd , line , column , string ) ;
}
*/
}
}
}
}
/** Called whenever a user inputs text in an XML type document.
Returns true if the code completionw as handled .
*/
bool Document : : xmlAutoCompletion ( int line , int column , const TQString & string )
{
QTag * tag ;
TQString tagName ;
bool handled = false ;
tagName = getTagNameAt ( line , column ) ;
tag = QuantaCommon : : tagFromDTD ( completionDTD , tagName ) ;
if ( ! tag & & ! tagName . isEmpty ( ) )
tag = userTagList . find ( tagName . lower ( ) ) ;
TQString s = editIf - > textLine ( line ) . left ( column + 1 ) ;
bool namespacecompletion = false ;
if ( ! tagName . isEmpty ( ) & & string = = " : " & & s . endsWith ( " < " + tagName + " : " ) )
namespacecompletion = true ;
int i = column ;
while ( i > 0 & & s [ i ] . isSpace ( ) )
i - - ;
s = s . left ( i + 1 ) ;
if ( ! tag | | tagName . isEmpty ( ) | | namespacecompletion ) //we are outside of any tag
{
if ( s . endsWith ( completionDTD - > tagAutoCompleteAfter ) | |
namespacecompletion ) // a tag is started, either with < or <namespace:
{
//we need to complete a tag name
showCodeCompletions ( getTagCompletions ( line , column + 1 ) ) ;
handled = true ;
} else
if ( string = = " > " & & ! tagName . isEmpty ( ) & & tagName [ 0 ] ! = ' ! ' & & tagName [ 0 ] ! = ' ? ' & &
tagName [ 0 ] ! = ' / ' & & ! tagName . endsWith ( " / " ) & & ! s . endsWith ( " /> " ) & &
qConfig . closeTags & &
currentDTD ( true ) - > family = = Xml ) //close unknown tags
{
//add closing tag if wanted
column + + ;
editIf - > insertText ( line , column , " </ " + tagName + " > " ) ;
docUndoRedo - > dontAddModifsSet ( 2 ) ;
viewCursorIf - > setCursorPositionReal ( line , column ) ;
handled = true ;
} else
if ( string = = " / " & & s . endsWith ( " </ " ) & & tagName . isEmpty ( ) )
{
Node * node = parser - > nodeAt ( line , column , false ) ;
if ( node & & node - > parent )
{
node = node - > parent ;
if ( node - > tag - > type = = Tag : : XmlTag & & ( ! node - > next | | ! QuantaCommon : : closesTag ( node - > tag , node - > next - > tag ) ) )
{
TQString name = node - > tag - > name ;
name = name . left ( name . find ( " | " ) ) ;
if ( ! node - > tag - > nameSpace . isEmpty ( ) )
name . prepend ( node - > tag - > nameSpace + " : " ) ;
editIf - > insertText ( line , column + 1 , name + " > " ) ;
docUndoRedo - > dontAddModifsSet ( 2 ) ;
viewCursorIf - > setCursorPositionReal ( line , column + name . length ( ) + 2 ) ;
handled = true ;
}
}
}
}
else // we are inside of a tag
{
if ( string = = " > " & & tagName [ 0 ] ! = ' / ' & & ! tagName . endsWith ( " / " ) & &
! s . endsWith ( " /> " ) & & tag )
{
if ( tag - > parentDTD - > singleTagStyle = = " xml " & &
( tag - > isSingle ( ) | | ( ! qConfig . closeOptionalTags & & tag - > isOptional ( ) ) )
)
{
editIf - > insertText ( line , column , " / " ) ;
docUndoRedo - > dontAddModifsSet ( 2 ) ;
viewCursorIf - > setCursorPositionReal ( line , column + 3 ) ;
handled = true ;
}
if ( ( ! tag - > isSingle ( ) & & ! tag - > isOptional ( ) & & qConfig . closeTags ) | |
( tag - > isOptional ( ) & & qConfig . closeOptionalTags ) )
{
//add closing tag if wanted
Node * node = parser - > nodeAt ( line , column , false ) ;
if ( node & & ( ! node - > next | | ! QuantaCommon : : closesTag ( node - > tag , node - > next - > tag ) ) )
{
if ( node & & ! node - > tag - > nameSpace . isEmpty ( ) )
tagName . prepend ( node - > tag - > nameSpace + " : " ) ;
column + + ;
editIf - > insertText ( line , column , " </ " + tagName + " > " ) ;
docUndoRedo - > dontAddModifsSet ( 2 ) ;
viewCursorIf - > setCursorPositionReal ( line , column ) ;
handled = true ;
}
}
if ( ! tag - > childTags . isEmpty ( ) )
{
reparseEnabled = false ;
// insertText("\n", false, false);
insertChildTags ( tag ) ;
reparseEnabled = true ;
baseNode = parser - > rebuild ( this ) ;
if ( qConfig . instantUpdate & & quantaApp - > structTreeVisible ( ) )
{
typingInProgress = false ;
StructTreeView : : ref ( ) - > slotReparse ( this , baseNode , qConfig . expandLevel ) ;
}
}
}
else if ( string = = " " )
{
TQString textLine = editIf - > textLine ( line ) ;
if ( ! QuantaCommon : : insideCommentsOrQuotes ( column , textLine , completionDTD ) )
{
showCodeCompletions ( getAttributeCompletions ( tagName , " " ) ) ;
handled = true ;
}
}
else if ( string [ 0 ] = = qConfig . attrValueQuotation )
{
//we need to find the attribute name
TQString textLine = editIf - > textLine ( line ) . left ( column - 1 ) ;
TQString attribute = textLine . mid ( textLine . findRev ( ' ' ) + 1 ) ;
if ( attribute = = " style " & & completionDTD - > insideDTDs . contains ( " css " ) )
{
completionDTD = DTDs : : ref ( ) - > find ( " text/css " ) ;
completionRequested = true ;
return scriptAutoCompletion ( line , column + 1 , string ) ;
}
showCodeCompletions ( getAttributeValueCompletions ( tagName , attribute ) ) ;
handled = true ;
}
} // else - we are inside of a tag
if ( ! handled )
{
//check if we are inside a style attribute, and use css autocompletion if we are
TQString textLine = editIf - > textLine ( line ) ;
textLine = textLine . left ( column ) ;
int pos = textLine . findRev ( ' " ' ) ;
if ( pos ! = - 1 )
{
pos = textLine . findRev ( ' ' , pos ) ;
if ( pos ! = - 1 )
{
textLine = textLine . mid ( pos + 1 ) ;
pos = textLine . find ( ' = ' ) ;
if ( pos ! = - 1 )
{
TQString attribute = textLine . left ( pos ) ;
if ( attribute = = " style " & & completionDTD - > insideDTDs . contains ( " css " ) )
{
completionDTD = DTDs : : ref ( ) - > find ( " text/css " ) ;
completionRequested = true ;
return scriptAutoCompletion ( line , column + 1 , string ) ;
}
}
}
}
TQString s = editIf - > textLine ( line ) . left ( column + 1 ) ;
pos = s . findRev ( ' & ' ) ;
if ( pos ! = - 1 )
{
//complete character codes
s = s . mid ( pos + 1 ) ;
showCodeCompletions ( getCharacterCompletions ( s ) ) ;
handled = true ;
}
}
return handled ;
}
/** Return a list of possible variable name completions */
TQValueList < KTextEditor : : CompletionEntry > * Document : : getGroupCompletions ( Node * node , const StructTreeGroup & group , int line , int col )
{
TQValueList < KTextEditor : : CompletionEntry > * completions = new TQValueList < KTextEditor : : CompletionEntry > ( ) ;
KTextEditor : : CompletionEntry completion ;
completion . type = " variable " ;
TQString textLine = editIf - > textLine ( line ) . left ( col ) ;
TQString word = findWordRev ( textLine ) ;
if ( ! group . removeFromAutoCompleteWordRx . pattern ( ) . isEmpty ( ) )
word . remove ( group . removeFromAutoCompleteWordRx ) ;
completion . userdata = word + " | " ;
GroupElementMapList : : Iterator it ;
TQString str = group . name ;
str . append ( " | " ) ;
str . append ( word ) ;
for ( it = globalGroupMap . begin ( ) ; it ! = globalGroupMap . end ( ) ; + + it )
{
if ( it . key ( ) . startsWith ( str ) & & it . key ( ) ! = str )
{
GroupElementList elementList = it . data ( ) ;
for ( uint i = 0 ; i < elementList . count ( ) ; i + + )
{
if ( elementList [ i ] - > parentNode = = 0L | | elementList [ i ] - > global )
{
completion . text = it . key ( ) . section ( ' | ' , - 1 ) . stripWhiteSpace ( ) ;
completions - > append ( completion ) ;
break ;
} else
{
Node * n = node ;
while ( n & & n ! = elementList [ i ] - > parentNode )
{
n = n - > parent ;
}
if ( n = = elementList [ i ] - > parentNode )
{
completion . text = it . key ( ) . section ( ' | ' , - 1 ) . stripWhiteSpace ( ) ;
completions - > append ( completion ) ;
break ;
}
}
}
}
}
IncludedGroupElementsMap elements = parser - > includedMap ;
IncludedGroupElementsMap : : Iterator it2 ;
for ( it2 = elements . begin ( ) ; it2 ! = elements . end ( ) ; + + it2 )
{
TQStringList list = it2 . data ( ) [ group . name ] . keys ( ) ;
list . sort ( ) ;
for ( uint i = 0 ; i < list . count ( ) ; i + + )
{
if ( list [ i ] . startsWith ( word ) & & list [ i ] ! = word )
{
completion . text = list [ i ] . stripWhiteSpace ( ) ;
completions - > append ( completion ) ;
}
}
}
return completions ;
}
bool Document : : isDerivatedFrom ( const TQString & className , const TQString & baseClass )
{
if ( className . isEmpty ( ) | | ! completionDTD - > classInheritance . contains ( className ) )
return false ;
TQString parentClass = completionDTD - > classInheritance [ className ] ;
int result = 0 ;
do {
if ( parentClass = = baseClass )
result = 1 ; //className extends baseClass
else
{
if ( completionDTD - > classInheritance . contains ( parentClass ) )
parentClass = completionDTD - > classInheritance [ parentClass ] ;
else
result = - 1 ; //nothing was found in the inheritance list
}
} while ( result = = 0 ) ;
return ( result = = 1 ) ;
}
/** Return a list of possible tag name completions */
TQValueList < KTextEditor : : CompletionEntry > * Document : : getTagCompletions ( int line , int col )
{
TQValueList < KTextEditor : : CompletionEntry > * completions = new TQValueList < KTextEditor : : CompletionEntry > ( ) ;
KTextEditor : : CompletionEntry completion ;
switch ( completionDTD - > family )
{
case Xml : completion . type = " tag " ;
break ;
case Script :
completion . type = " script " ;
break ;
}
Node * node = parser - > nodeAt ( line , col ) ;
if ( node & & node - > tag - > type ! = Tag : : XmlTag )
node = node - > parent ;
if ( node & & node - > tag - > type ! = Tag : : XmlTag )
node = 0L ;
QTag * parentQTag = 0L ;
if ( node & & node - > parent )
parentQTag = QuantaCommon : : tagFromDTD ( node - > parent ) ;
TQString textLine = editIf - > textLine ( line ) . left ( col ) ;
TQString word = findWordRev ( textLine , completionDTD ) . upper ( ) ;
TQString classStr = " " ;
TQString objStr ;
if ( completionDTD - > classGroupIndex ! = - 1 & & completionDTD - > objectGroupIndex ! = - 1 )
{
textLine = textLine . left ( textLine . length ( ) - word . length ( ) ) ;
int pos = completionDTD - > memberAutoCompleteAfter . searchRev ( textLine ) ;
if ( pos ! = - 1 )
{
textLine = textLine . left ( pos ) ;
TQRegExp * r = & ( completionDTD - > structTreeGroups [ completionDTD - > classGroupIndex ] . usageRx ) ;
pos = r - > searchRev ( textLine ) ;
if ( pos ! = - 1 )
{
objStr = r - > cap ( 1 ) ;
if ( objStr = = " this " )
{
TQString parentGroupStr = " " ;
bool classFound = false ;
parser - > synchParseInDetail ( ) ;
Node * n = parser - > nodeAt ( line , col ) ;
while ( n & & ! classFound )
{
//Need to parser for groups, as the node tree is rebuilt before
//autocompletion and none of the node has links to group elements
//at this position.
SAGroupParser * gParser = new SAGroupParser ( 0L , this , n , n - > nextSibling ( ) , true , false , false ) ;
gParser - > slotParseForScriptGroup ( ) ;
GroupElementList : : Iterator it = n - > m_groupElements . begin ( ) ;
while ( it ! = n - > m_groupElements . end ( ) )
{
GroupElement * e = * it ;
if ( parentGroupStr . isEmpty ( ) & & e - > group - > appendToTags )
{
parentGroupStr = e - > group - > parentGroup ;
}
if ( ! parentGroupStr . isEmpty ( ) & & e - > group - > name = = parentGroupStr )
{
classStr = e - > tag - > name ;
classFound = true ;
}
//detach the groupelement from the node
e - > node = 0L ;
e - > group = 0L ;
e - > deleted = true ;
it = n - > m_groupElements . erase ( it ) ;
}
delete gParser ;
n = n - > parent ;
}
} else
{
GroupElementList groupElementList = globalGroupMap [ completionDTD - > structTreeGroups [ completionDTD - > objectGroupIndex ] . name + " | " + objStr ] ;
for ( GroupElementList : : Iterator it = groupElementList . begin ( ) ; it ! = groupElementList . end ( ) ; + + it )
{
if ( ! ( * it ) - > tag )
continue ;
# ifdef DEBUG_PARSER
kdDebug ( 24000 ) < < " GroupElement: " < < ( * it ) < < " " < < ( * it ) - > tag - > area ( ) . bLine < < " " < < ( * it ) - > tag - > area ( ) . bCol < < " " < < ( * it ) - > tag - > area ( ) . eLine < < " " < < ( * it ) - > tag - > area ( ) . eCol < < " " < < ( * it ) - > tag - > tagStr ( ) < < " " < < ( * it ) - > type < < endl ;
# endif
if ( ! ( * it ) - > type . isEmpty ( ) )
{
classStr = ( * it ) - > type ;
break ;
}
}
}
}
}
if ( ( ! objStr . isEmpty ( ) | | ! completionRequested ) & & classStr . isEmpty ( ) ) //the class cannot be identified for the object or there is no object.
return completions ;
}
completion . userdata = word + " | " ;
TQStringList tagNameList ;
TQMap < TQString , TQString > comments ;
//A TQMap to hold the completion type (function/string/class/etc)
TQMap < TQString , TQString > type ;
TQString tagName ;
TQDictIterator < QTag > it ( * ( completionDTD - > tagsList ) ) ;
int i = 0 ;
for ( ; it . current ( ) ; + + it )
{
QTag * tag = it . current ( ) ;
if ( ( tag - > type ! = " entity " ) & & ( tag - > className = = classStr | |
isDerivatedFrom ( classStr , tag - > className ) ) )
{
tagName = tag - > name ( ) ;
if ( ! tagName . isEmpty ( ) & & tagName . upper ( ) . startsWith ( word ) )
{
if ( ! parentQTag | | ( parentQTag & & parentQTag - > isChild ( tagName ) ) )
{
tagName = tag - > name ( ) + TQString ( " %1 " ) . arg ( i , 10 ) ;
tagNameList + = tagName ;
comments . insert ( tagName , tag - > comment ) ;
i + + ;
}
}
}
}
TQDictIterator < QTag > it2 ( userTagList ) ;
for ( ; it2 . current ( ) ; + + it2 )
{
QTag * tag = it2 . current ( ) ;
if ( ( tag - > className = = classStr | |
isDerivatedFrom ( classStr , tag - > className ) ) & & tag - > name ( ) . upper ( ) . startsWith ( word ) )
{
tagName = tag - > name ( ) + TQString ( " %1 " ) . arg ( i , 10 ) ;
tagNameList + = tagName ;
comments . insert ( tagName , tag - > comment ) ;
// If the completion family is script, then we want to update the tag type
// it appears we use "script" for adding the completionDTD->attrAutoCompleteAfter when we run the slotFilterCompletion
// so we will continue to use that for functions (they need the attribute added), but variables get a new type - and we do not
// have to auto-complete them
if ( completionDTD - > family = = Script )
{
if ( tag - > type = = " variable " )
type . insert ( tagName , tag - > type ) ;
else if ( tag - > type = = " function " )
type . insert ( tagName , " script " ) ;
// We add the type to the comment variable, so it displays on the screen, giving the user some feedback
if ( comments [ tagName ] . length ( ) )
comments [ tagName ] = tag - > type + " \n " + comments [ tagName ] ;
else
comments [ tagName ] = tag - > type + comments [ tagName ] ;
}
i + + ;
}
}
tagNameList . sort ( ) ;
// tagNameList is sorted above to sort the completions by name alphabetically
// Now we want to sort the completions by their types.
// We only want to do this if we are completing Script DTDs
// We are going to use a couple of iterators to sort the list by Type
// Type Sorting is as follows: 0:Other, 1:Variables, 2: Functions (script)
TQValueList < KTextEditor : : CompletionEntry > : : Iterator otherIt = completions - > begin ( ) ;
TQValueList < KTextEditor : : CompletionEntry > : : Iterator variableIt = completions - > begin ( ) ;
for ( uint i = 0 ; i < tagNameList . count ( ) ; i + + )
{
if ( completionDTD - > family = = Xml )
completion . text = QuantaCommon : : tagCase ( tagNameList [ i ] ) ;
else
completion . text = tagNameList [ i ] ;
completion . text = completion . text . left ( completion . text . length ( ) - 10 ) . stripWhiteSpace ( ) ;
completion . comment = comments [ tagNameList [ i ] ] ;
if ( completionDTD - > family = = Script )
{
// Here we actually append the completion type
completion . type = type [ tagNameList [ i ] ] ;
// And here is out sorting...
if ( completion . type . contains ( " variable " ) )
{
// Insert after the last variable
variableIt + + ;
variableIt = completions - > insert ( variableIt , completion ) ;
}
else
{
if ( completion . type . contains ( " script " ) )
{
//Scripts can go at the end of the list
completions - > append ( completion ) ;
}
else
{
// Other types go first, after the last other type
otherIt + + ;
otherIt = completions - > insert ( otherIt , completion ) ;
// If we have no variables in the list, we need to point variableIt to otherIt, so they will go after the 'others'
if ( ( * variableIt ) . text . length ( ) = = 0 )
variableIt = otherIt ;
}
}
}
else
completions - > append ( completion ) ;
}
// completionInProgress = true;
return completions ;
}
/** Return a list of valid attributes for the given tag */
TQValueList < KTextEditor : : CompletionEntry > * Document : : getAttributeCompletions ( const TQString & tagName , const TQString & a_startsWith )
{
TQValueList < KTextEditor : : CompletionEntry > * completions = new TQValueList < KTextEditor : : CompletionEntry > ( ) ;
KTextEditor : : CompletionEntry completion ;
QTag * tag = QuantaCommon : : tagFromDTD ( completionDTD , tagName ) ;
if ( ! tag )
{
tag = userTagList . find ( tagName . lower ( ) ) ;
}
TQString startsWith = a_startsWith . upper ( ) ;
if ( tag )
{
switch ( completionDTD - > family )
{
case Xml :
{
completion . type = " attribute " ;
completion . userdata = startsWith + " | " + tag - > name ( ) ;
//list specified attributes for this tag
AttributeList * list = tag - > attributes ( ) ;
TQValueList < KTextEditor : : CompletionEntry > tempCompletions ;
TQStringList nameList ;
for ( uint i = 0 ; i < list - > count ( ) ; i + + )
{
TQString item = list - > at ( i ) - > name ;
if ( item . upper ( ) . startsWith ( startsWith ) )
{
completion . text = QuantaCommon : : attrCase ( item ) ;
completion . comment = list - > at ( i ) - > type ;
tempCompletions . append ( completion ) ;
nameList . append ( completion . text ) ;
}
}
//list common attributes for this tag
for ( TQStringList : : Iterator it = tag - > commonGroups . begin ( ) ; it ! = tag - > commonGroups . end ( ) ; + + it )
{
AttributeList * attrs = tag - > parentDTD - > commonAttrs - > find ( * it ) ;
for ( uint j = 0 ; j < attrs - > count ( ) ; j + + )
{
TQString name = attrs - > at ( j ) - > name ;
if ( name . upper ( ) . startsWith ( startsWith ) )
{
completion . text = QuantaCommon : : attrCase ( name ) ;
completion . comment = attrs - > at ( j ) - > type ;
tempCompletions . append ( completion ) ;
nameList . append ( completion . text ) ;
}
}
}
if ( tag - > name ( ) . contains ( " !doctype " , false ) ) //special case, list all the known document types
{
TQStringList nickNames = DTDs : : ref ( ) - > nickNameList ( true ) ;
for ( TQStringList : : Iterator it = nickNames . begin ( ) ; it ! = nickNames . end ( ) ; + + it )
{
completion . type = " doctypeList " ;
completion . text = * it ;
tempCompletions . append ( completion ) ;
nameList . append ( completion . text ) ;
}
}
//below isn't fast, but enough here. May be better with TQMap<TQString, KTextEditor::CompletionEntry>
nameList . sort ( ) ;
for ( TQStringList : : Iterator it = nameList . begin ( ) ; it ! = nameList . end ( ) ; + + it )
{
for ( TQValueList < KTextEditor : : CompletionEntry > : : Iterator compIt = tempCompletions . begin ( ) ; compIt ! = tempCompletions . end ( ) ; + + compIt )
{
if ( ( * compIt ) . text = = * it )
{
completions - > append ( * compIt ) ;
break ;
}
}
}
break ;
}
case Script :
{
completion . userdata = startsWith + " | " + tag - > name ( ) ;
completion . type = " script " ;
AttributeList * list = tag - > attributes ( ) ;
for ( uint i = 0 ; i < list - > count ( ) ; i + + )
{
TQString item = list - > at ( i ) - > name ;
completion . text = item ;
completion . comment = list - > at ( i ) - > type ;
completions - > append ( completion ) ;
}
}
}
} // if (tag)
// completionInProgress = true;
return completions ;
}
/** Return a list of valid attribute values for the given tag and attribute */
TQValueList < KTextEditor : : CompletionEntry > * Document : : getAttributeValueCompletions ( const TQString & tagName , const TQString & attribute , const TQString & startsWith )
{
TQValueList < KTextEditor : : CompletionEntry > * completions = new TQValueList < KTextEditor : : CompletionEntry > ( ) ;
KTextEditor : : CompletionEntry completion ;
completion . type = " attributeValue " ;
completion . userdata = startsWith + " | " + tagName + " , " + attribute ;
bool deleteValues ;
TQStringList * values = tagAttributeValues ( completionDTD - > name , tagName , attribute , deleteValues ) ;
if ( attribute . lower ( ) = = " class " )
{
if ( ! values )
{
values = new TQStringList ( quantaApp - > selectors ( tagName ) ) ;
deleteValues = true ;
}
} else
if ( attribute . lower ( ) = = " id " )
{
if ( ! values )
{
values = new TQStringList ( quantaApp - > idSelectors ( ) ) ;
deleteValues = true ;
}
}
if ( values )
{
for ( TQStringList : : Iterator it = values - > begin ( ) ; it ! = values - > end ( ) ; + + it )
{
completion . text = * it ;
if ( completion . text . startsWith ( startsWith ) )
{
completions - > append ( completion ) ;
}
}
}
if ( deleteValues )
delete values ;
int andSignPos = startsWith . find ( ' & ' ) ;
if ( andSignPos ! = - 1 )
{
TQValueList < KTextEditor : : CompletionEntry > * charCompletions = getCharacterCompletions ( startsWith . mid ( andSignPos + 1 ) ) ;
* completions + = * charCompletions ;
delete charCompletions ;
}
// completionInProgress = true;
return completions ;
}
/** Return a list of character completions (like ...) */
TQValueList < KTextEditor : : CompletionEntry > * Document : : getCharacterCompletions ( const TQString & startsWith )
{
TQValueList < KTextEditor : : CompletionEntry > * completions = 0L ;
TQMap < TQString , KTextEditor : : CompletionEntry > completionMap ;
//first search for entities defined in the document
const DTDStruct * dtdDTD = DTDs : : ref ( ) - > find ( " dtd " ) ;
if ( dtdDTD )
{
StructTreeGroup group ;
for ( uint j = 0 ; j < dtdDTD - > structTreeGroups . count ( ) ; j + + )
{
group = dtdDTD - > structTreeGroups [ j ] ;
if ( ! group . autoCompleteAfterRx . pattern ( ) . isEmpty ( ) & &
group . autoCompleteAfterRx . search ( " & " ) ! = - 1 )
{
uint line , col ;
viewCursorIf - > cursorPositionReal ( & line , & col ) ;
Node * node = parser - > nodeAt ( line , col , false ) ;
completions = getGroupCompletions ( node , group , line , col ) ;
for ( uint i = 0 ; i < completions - > count ( ) ; i + + )
{
( * completions ) [ i ] . type = " charCompletion " ;
( * completions ) [ i ] . userdata = ( * completions ) [ i ] . text ;
completionMap [ ( * completions ) [ i ] . text ] = ( * completions ) [ i ] ;
}
break ;
}
}
}
if ( ! completions )
completions = new TQValueList < KTextEditor : : CompletionEntry > ( ) ;
KTextEditor : : CompletionEntry completion ;
completion . type = " charCompletion " ;
//add the entities from the tag files
TQDictIterator < QTag > it ( * ( completionDTD - > tagsList ) ) ;
for ( ; it . current ( ) ; + + it )
{
QTag * tag = it . current ( ) ;
if ( tag - > type = = " entity " )
{
TQString tagName = tag - > name ( true ) ;
if ( tagName . upper ( ) . startsWith ( startsWith . upper ( ) ) | | startsWith . isEmpty ( ) )
{
completion . text = tagName ;
completion . userdata = tagName ;
completions - > append ( completion ) ;
completionMap [ tagName ] = completion ;
}
}
}
TQValueList < KTextEditor : : CompletionEntry > * completions2 = new TQValueList < KTextEditor : : CompletionEntry > ( ) ;
for ( TQMap < TQString , KTextEditor : : CompletionEntry > : : ConstIterator it = completionMap . constBegin ( ) ; it ! = completionMap . constEnd ( ) ; + + it )
{
completions2 - > append ( it . data ( ) ) ;
}
delete completions ;
completions = completions2 ;
for ( TQStringList : : Iterator it = charList . begin ( ) ; it ! = charList . end ( ) ; + + it )
{
completion . text = * it ;
int begin = completion . text . find ( " (& " ) + 2 ;
if ( begin = = 1 )
continue ;
int length = completion . text . find ( " ;) " ) - begin + 1 ;
TQString s = completion . text . mid ( begin , length - 1 ) ;
completion . text = s + " : " + completion . text . left ( begin - 2 ) + " - " + completion . text . mid ( begin + length + 1 ) ;
if ( s . startsWith ( startsWith ) )
{
completion . userdata = s . mid ( startsWith . length ( ) ) ;
completions - > append ( completion ) ;
}
}
return completions ;
}
/** Returns the DTD identifier for the document */
TQString Document : : getDTDIdentifier ( )
{
return dtdName ;
}
/** Sets the DTD identifier */
void Document : : setDTDIdentifier ( const TQString & id )
{
dtdName = id . lower ( ) ;
m_groupsForDTEPs . clear ( ) ;
}
/** Get a pointer to the current active DTD. If fallback is true, this always gives back a valid and known DTD pointer: the active, the document specified and in last case the application default document type. */
const DTDStruct * Document : : currentDTD ( bool fallback )
{
uint line , col ;
viewCursorIf - > cursorPositionReal ( & line , & col ) ;
const DTDStruct * dtd = parser - > currentDTD ( line , col ) ;
if ( fallback & & ! dtd ) return defaultDTD ( ) ;
return dtd ;
}
/** Get a pointer to the default DTD (document, or app). */
const DTDStruct * Document : : defaultDTD ( ) const
{
const DTDStruct * dtd = DTDs : : ref ( ) - > find ( dtdName ) ;
if ( ! dtd ) dtd = DTDs : : ref ( ) - > find ( Project : : ref ( ) - > defaultDTD ( ) ) ;
if ( ! dtd ) dtd = DTDs : : ref ( ) - > find ( qConfig . defaultDocType ) ; //this will always exists
return dtd ;
}
/** Find the DTD name for a part of the document. */
TQString Document : : findDTDName ( Tag * * tag )
{
//Do some magic to find the document type
int endLine = editIf - > numLines ( ) ;
TQString foundText = " " ;
int pos = 0 ;
int i = 0 ;
int line , startPos ;
TQString text ;
do
{
text = editIf - > textLine ( i ) ;
//search for !DOCTYPE tags
pos = text . find ( " !doctype " , 0 , false ) ;
if ( pos ! = - 1 ) //parse the found !DOCTYPE tag
{
int bl , bc , el , ec ;
line = i ;
bl = line ;
startPos = text . findRev ( ' < ' , pos ) ;
while ( startPos = = - 1 & & line > = 0 )
{
text = editIf - > textLine ( line ) ;
startPos = text . findRev ( ' < ' ) ;
bl = line ;
line - - ;
}
if ( startPos = = - 1 )
{
i + + ;
continue ;
}
bc = startPos ;
line = i ;
text = editIf - > textLine ( i ) ;
startPos = text . find ( ' > ' , pos ) ;
el = line ;
while ( startPos = = - 1 & & line < endLine )
{
text = editIf - > textLine ( line ) ;
startPos = text . find ( ' > ' ) ;
el = line ;
line + + ;
}
if ( startPos = = - 1 )
{
i + + ;
continue ;
}
ec = startPos + 1 ;
* tag = new Tag ( ) ;
( * tag ) - > setTagPosition ( bl , bc , el , ec ) ;
text = this - > text ( bl , bc , el , ec ) ;
( * tag ) - > parse ( text , this ) ;
( * tag ) - > type = Tag : : XmlTag ;
text . replace ( " \\ \" " , " \" " ) ;
pos = text . find ( " public " , 0 , false ) ;
if ( pos = = - 1 ) //if no PUBLIC info, use the word after !DOCTYPE as the doc.type
{
foundText = ( * tag ) - > attribute ( 0 ) ;
} else
{ //use the quoted string after PUBLIC as doc. type
pos = text . find ( " \" " , pos + 1 ) ;
if ( pos ! = - 1 )
{
int endPos = text . find ( " \" " , pos + 1 ) ;
foundText = text . mid ( pos + 1 , endPos - pos - 1 ) ;
}
}
break ;
}
i + + ;
} while ( i < endLine ) ;
return foundText . lower ( ) ;
}
/** Called whenever a user inputs text in a script type document. */
bool Document : : scriptAutoCompletion ( int line , int column , const TQString & insertedString )
{
bool handled = false ;
Node * node = parser - > nodeAt ( line , column ) ;
if ( ! node ) //happens in some cases in CSS
return false ;
if ( node - > tag - > type = = Tag : : Comment )
return true ; //nothing to do
const DTDStruct * dtd = node - > tag - > dtd ( ) ;
if ( node - > prev )
node = node - > prev ;
else
if ( node - > parent )
node = node - > parent ;
int bl , bc ;
node - > tag - > beginPos ( bl , bc ) ;
TQString s = text ( bl , bc , line , column ) ;
if ( QuantaCommon : : insideCommentsOrQuotes ( s . length ( ) - 1 , s , dtd ) )
return true ; //again, nothing to do
TQString s2 = s ;
int i = s . length ( ) - 1 ;
while ( i > 0 & & s [ i ] . isSpace ( ) )
i - - ;
while ( i > 0 & & ( s [ i ] . isLetterOrNumber ( ) | | s [ i ] = = ' _ ' | |
( completionDTD - > minusAllowedInWord & & s [ i ] = = ' - ' ) ) )
i - - ;
TQString startStr = s . mid ( i + 1 ) . stripWhiteSpace ( ) ;
s = s . left ( i + 1 ) ;
if ( s [ i ] = = completionDTD - > attributeSeparator )
{
while ( i > 0 & & s [ i ] ! = completionDTD - > attrAutoCompleteAfter )
i - - ;
s = s . left ( i + 1 ) ;
} else
if ( s [ i ] = = completionDTD - > tagSeparator )
{
while ( i > 0 & & s [ i ] ! = completionDTD - > tagAutoCompleteAfter )
i - - ;
s = s . left ( i + 1 ) ;
}
if ( s [ i ] = = completionDTD - > attrAutoCompleteAfter | |
s [ i ] = = completionDTD - > attributeSeparator ) //if we need to list the arguments of a function
{
TQString textLine = s . left ( i ) ;
TQString word = findWordRev ( textLine , completionDTD ) ;
TQValueList < QTag * > tags ;
if ( ! word . isEmpty ( ) )
{
tags . append ( userTagList . find ( word . lower ( ) ) ) ;
TQDictIterator < QTag > it ( * ( completionDTD - > tagsList ) ) ;
for ( ; it . current ( ) ; + + it )
{
if ( it . currentKey ( ) = = word )
tags . append ( it . current ( ) ) ;
}
}
TQStringList argList ;
for ( TQValueList < QTag * > : : ConstIterator it = tags . constBegin ( ) ; it ! = tags . constEnd ( ) ; + + it )
{
QTag * tag = * it ;
if ( ! tag )
continue ;
TQString arguments ;
if ( tag - > type ! = " property " )
{
for ( int i = 0 ; i < tag - > attributeCount ( ) ; i + + )
{
Attribute * attr = tag - > attributeAt ( i ) ;
if ( attr - > status = = " optional " )
{
arguments = arguments + " [ " + attr - > type + " " + attr - > name + " ], " ;
} else
{
arguments = arguments + attr - > type + " " + attr - > name + " , " ;
}
}
arguments = tag - > returnType + " " + tag - > name ( ) + " ( " + arguments . left ( arguments . length ( ) - 2 ) + " ) " ;
argList . append ( arguments ) ;
codeCompletionIf - > showArgHint ( argList , " () " , completionDTD - > attributeSeparator ) ;
argHintVisible = true ;
} else
{
if ( hintRequested )
{
arguments = tag - > name ( ) + " : " + tag - > attributeAt ( 0 ) - > name + " ; " ;
argList . append ( arguments ) ;
codeCompletionIf - > showArgHint ( argList , " :; " , completionDTD - > attributeSeparator ) ;
} else
showCodeCompletions ( getAttributeValueCompletions ( tag - > name ( ) , tag - > attributeAt ( 0 ) - > name , startStr ) ) ;
}
handled = true ;
}
} else
{
StructTreeGroup group ;
for ( uint j = 0 ; j < completionDTD - > structTreeGroups . count ( ) ; j + + )
{
group = completionDTD - > structTreeGroups [ j ] ;
if ( ! group . autoCompleteAfterRx . pattern ( ) . isEmpty ( ) & &
( group . autoCompleteAfterRx . search ( s2 ) ! = - 1 | |
group . autoCompleteAfterRx . search ( s ) ! = - 1 ) )
{
Node * node = parser - > nodeAt ( line , column , false ) ;
showCodeCompletions ( getGroupCompletions ( node , group , line , column + 1 ) ) ;
handled = true ;
break ;
}
}
}
if ( ! handled & & ! argHintVisible & &
( completionRequested | |
( s [ i ] = = completionDTD - > tagAutoCompleteAfter & & ( insertedString = = " " | | ( insertedString [ 0 ] = = completionDTD - > tagAutoCompleteAfter & & ! completionDTD - > requestSpaceBeforeTagAutoCompletion ) ) ) | |
completionDTD - > tagAutoCompleteAfter = = ' \1 ' | | ( ! completionDTD - > memberAutoCompleteAfter . pattern ( ) . isEmpty ( ) & & completionDTD - > memberAutoCompleteAfter . searchRev ( s ) ! = - 1 ) )
)
{
showCodeCompletions ( getTagCompletions ( line , column + 1 ) ) ;
handled = true ;
}
return handled ;
}
/** Retrives the text from the specified rectangle. The KTextEditor::EditInterface::text seems to not
work correctly . */
TQString Document : : text ( int bLine , int bCol , int eLine , int eCol ) const
{
if ( bLine > eLine )
{
int tmp = bLine ;
bLine = eLine ;
eLine = tmp ;
tmp = bCol ;
bCol = eCol ;
eCol = tmp ;
}
TQString t = editIf - > textLine ( bLine ) ;
if ( bLine = = eLine )
{
return t . mid ( bCol , eCol - bCol + 1 ) ;
}
t . remove ( 0 , bCol ) ;
t . append ( " \n " ) ;
//TODO: This is slow if the area is big. We need to speed it up!!
for ( int i = bLine + 1 ; i < eLine ; i + + )
{
t . append ( editIf - > textLine ( i ) + " \n " ) ;
}
t = t + editIf - > textLine ( eLine ) . left ( eCol + 1 ) ;
return t ;
}
//TODO: profile which one is used more often and time critical places and use
//that one as the default and call from that one the other version
TQString Document : : text ( const AreaStruct & area ) const
{
return text ( area . bLine , area . bCol , area . eLine , area . eCol ) ;
}
TQString Document : : find ( const TQRegExp & regExp , int sLine , int sCol , int & fbLine , int & fbCol , int & feLine , int & feCol )
{
TQRegExp rx = regExp ;
TQString foundText = " " ;
int maxLine = editIf - > numLines ( ) ;
TQString textToSearch = text ( sLine , sCol , sLine , editIf - > lineLength ( sLine ) ) ;
int pos ;
int line = sLine ;
do
{
pos = rx . search ( textToSearch ) ;
if ( pos = = - 1 )
{
/* if (line + STEP < maxLine)
{
line + = STEP ;
textToSearch . append ( " \n " + text ( line - STEP + 1 , 0 , line , editIf - > lineLength ( line ) ) ) ;
} else */
{
line + + ;
if ( line < maxLine ) textToSearch . append ( " \n " + editIf - > textLine ( line ) ) ;
}
}
} while ( line < maxLine & & pos = = - 1 ) ;
// pos = rx.search(text(sLine, sCol, maxLine -1, 100));
if ( pos ! = - 1 )
{
foundText = rx . cap ( ) ;
TQString s = textToSearch . left ( pos ) ;
int linesUntilFound = s . contains ( " \n " ) ;
fbLine = sLine + linesUntilFound ;
fbCol = s . length ( ) - s . findRev ( " \n " ) - 1 ;
int linesInFound = foundText . contains ( " \n " ) ;
feCol = foundText . length ( ) - foundText . findRev ( " \n " ) - 2 ;
feLine = fbLine + linesInFound ;
if ( linesUntilFound = = 0 )
{
fbCol = fbCol + sCol ;
}
if ( linesInFound = = 0 )
{
feCol = feCol + fbCol ;
}
if ( fbCol < 0 ) fbCol = 0 ;
if ( feCol < 0 ) feCol = 0 ;
/*
s = text ( fbLine , fbCol , feLine , feCol ) ;
if ( s ! = foundText ) //debug, error
{
KMessageBox : : error ( this , " Found: " + foundText + " \n Read: " + s ) ;
}
*/
}
return foundText ;
}
TQString Document : : findRev ( const TQRegExp & regExp , int sLine , int sCol , int & fbLine , int & fbCol , int & feLine , int & feCol )
{
TQRegExp rx = regExp ;
TQString foundText = " " ;
int pos = - 1 ;
int line = sLine ;
TQString textToSearch = text ( sLine , 0 , sLine , sCol ) ;
do
{
pos = rx . searchRev ( textToSearch ) ;
if ( pos = = - 1 )
{
/* if (line - STEP >= 0)
{
textToSearch . prepend ( text ( line - STEP , 0 , line - 1 , editIf - > lineLength ( line - 1 ) ) + " \n " ) ;
line - = STEP ;
} else */
{
line - - ;
if ( line > = 0 ) textToSearch . prepend ( editIf - > textLine ( line ) + " \n " ) ;
}
}
} while ( line > = 0 & & pos = = - 1 ) ;
if ( pos ! = - 1 )
{
foundText = rx . cap ( ) ;
fbLine = line ;
fbCol = pos ;
int linesInFound = foundText . contains ( " \n " ) ;
feCol = foundText . length ( ) - foundText . findRev ( " \n " ) - 2 ;
feLine = fbLine + linesInFound ;
if ( linesInFound = = 0 )
{
feCol = feCol + fbCol ;
}
if ( fbCol < 0 ) fbCol = 0 ;
if ( feCol < 0 ) feCol = 0 ;
/*
TQString s = text ( fbLine , fbCol , feLine , feCol ) ;
if ( s ! = foundText ) //debug, error
{
KMessageBox : : error ( this , " FindRev \n Found: " + foundText + " \n Read: " + s ) ;
}
*/
}
return foundText ;
}
/** Code completion was requested by the user. */
void Document : : codeCompletionRequested ( )
{
completionRequested = true ;
completionInProgress = false ;
argHintVisible = false ;
hintRequested = false ;
handleCodeCompletion ( ) ;
completionRequested = false ;
}
void Document : : handleCodeCompletion ( )
{
slotDelayedTextChanged ( true ) ;
bool handled = false ;
uint line , col ;
viewCursorIf - > cursorPositionReal ( & line , & col ) ;
completionDTD = currentDTD ( ) ;
if ( completionDTD - > family = = Xml )
{
handled = xmlCodeCompletion ( line , col ) ;
}
if ( completionDTD - > family = = Script )
{
if ( completionDTD - > tagAutoCompleteAfter = = ' \0 ' )
completionDTD - > tagAutoCompleteAfter = ' \1 ' ;
handled = scriptAutoCompletion ( line , col - 1 , " " ) ;
if ( completionDTD - > tagAutoCompleteAfter = = ' \1 ' )
completionDTD - > tagAutoCompleteAfter = ' \0 ' ;
/* if (!handled)
{
completionDTD = defaultDTD ( ) ;
TQString s = text ( line , 0 , line , col ) . stripWhiteSpace ( ) ;
if ( s . findRev ( " < " ) ! = - 1 )
{
//showCodeCompletions(getTagCompletions(line, col + 1));
handled = true ;
}
} */
}
if ( ! handled )
{
completionDTD = defaultDTD ( ) ;
if ( completionDTD - > family = = Xml )
{
// xmlCodeCompletion(line, col);
xmlAutoCompletion ( line , col , " " ) ;
}
}
completionInProgress = true ;
}
/** Bring up the code completion tooltip. */
void Document : : codeCompletionHintRequested ( )
{
completionRequested = true ;
slotDelayedTextChanged ( true ) ;
uint line , col ;
viewCursorIf - > cursorPositionReal ( & line , & col ) ;
completionDTD = currentDTD ( ) ;
if ( completionDTD - > family = = Script )
{
// TQString textLine = editIf->textLine(line).left(col);
// int pos = textLine.findRev("(");
// int pos2 = textLine.findRev(")");
//if (pos > pos2 )
hintRequested = true ;
scriptAutoCompletion ( line , col - 1 , " " ) ;
}
completionRequested = false ;
}
TQString Document : : currentWord ( )
{
uint line , col ;
viewCursorIf - > cursorPositionReal ( & line , & col ) ;
TQString textLine = editIf - > textLine ( line ) ;
int startPos = textLine . findRev ( TQRegExp ( " \\ W " ) , col ) ;
int endPos = textLine . find ( TQRegExp ( " \\ W " ) , col ) ;
if ( startPos = = - 1 )
startPos = 0 ;
else
startPos + + ;
if ( endPos = = - 1 )
endPos = textLine . length ( ) ;
return textLine . mid ( startPos , endPos - startPos ) ;
}
/** Find the word until the first word boundary backwards */
TQString Document : : findWordRev ( const TQString & textToSearch , const DTDStruct * dtd )
{
TQString t = textToSearch ;
while ( t . endsWith ( " " ) )
t = t . left ( t . length ( ) - 1 ) ;
int startPos = - 1 ;
int pos ;
bool end = false ;
do {
pos = t . findRev ( TQRegExp ( " \\ W " ) , startPos ) ;
if ( t [ pos ] = = ' _ ' | |
( dtd & & dtd - > minusAllowedInWord & & t [ pos ] = = ' - ' ) )
{
startPos = pos - t . length ( ) - 1 ;
end = false ;
} else
{
end = true ;
}
} while ( ! end ) ;
return t . remove ( 0 , pos + 1 ) ;
}
/** Invoke code completion dialog for XML like tags according to the position (line, col), using DTD dtd. */
bool Document : : xmlCodeCompletion ( int line , int col )
{
bool handled = false ;
Node * node = parser - > nodeAt ( line , col ) ;
if ( node & & node - > tag & & node - > tag - > type = = Tag : : XmlTag )
{
Tag * tag = node - > tag ;
int bLine , bCol ;
tag - > beginPos ( bLine , bCol ) ;
TQString s ;
int index ;
TQString tagName = tag - > name . section ( ' | ' , 0 , 0 ) . stripWhiteSpace ( ) ;
int nameCol = bCol + tagName . length ( ) + 1 ;
if ( ! tag - > nameSpace . isEmpty ( ) )
nameCol + = 1 + tag - > nameSpace . length ( ) ;
if ( col > bCol & & col < = nameCol ) //we are inside a tag name, so show the possible tags
{
showCodeCompletions ( getTagCompletions ( line , col ) ) ;
handled = true ;
} else
{
index = tag - > valueIndexAtPos ( line , col ) ;
if ( index ! = - 1 ) //inside a value
{
s = tag - > attribute ( index ) ;
if ( s = = " style " & & completionDTD - > insideDTDs . contains ( " css " ) )
{
completionDTD = DTDs : : ref ( ) - > find ( " text/css " ) ;
return scriptAutoCompletion ( line , col , " " ) ;
} else
{
tag - > attributeValuePos ( index , bLine , bCol ) ;
s = tag - > attributeValue ( index ) . left ( col - bCol ) ;
showCodeCompletions ( getAttributeValueCompletions ( tagName , tag - > attribute ( index ) , s ) ) ;
handled = true ;
}
} else
{
index = tag - > attributeIndexAtPos ( line , col ) ;
s = text ( line , col , line , col ) ;
if ( index ! = - 1 | | s = = " " | | s = = " > " | | s = = " / " ) //inside an attribute or between attributes
{
if ( index ! = - 1 )
{
tag - > attributeNamePos ( index , bLine , bCol ) ;
s = tag - > attribute ( index ) . left ( col - bCol ) ;
} else
{
s = text ( line , 0 , line , col - 1 ) ;
s = s . section ( ' ' , - 1 ) ;
}
showCodeCompletions ( getAttributeCompletions ( tagName , s ) ) ;
handled = true ;
}
}
}
}
if ( ! handled )
{
TQString s = editIf - > textLine ( line ) . left ( col ) ;
int pos = s . findRev ( ' & ' ) ;
if ( pos ! = - 1 )
{
s = s . mid ( pos + 1 ) ;
if ( ! s . stripWhiteSpace ( ) . isEmpty ( ) )
{
//complete character codes
showCodeCompletions ( getCharacterCompletions ( s ) ) ;
handled = true ;
}
}
}
return handled ;
}
void Document : : slotCompletionAborted ( )
{
completionInProgress = false ;
argHintVisible = false ;
}
/** Ask for user confirmation if the file was changed outside. */
void Document : : checkDirtyStatus ( )
{
TQString fileName ;
if ( url ( ) . isLocalFile ( ) )
fileName = url ( ) . path ( ) ;
if ( m_dirty )
{
createTempFile ( ) ;
if ( ! fileName . isEmpty ( ) )
{
TQDateTime modifTime = TQFileInfo ( fileName ) . lastModified ( ) ;
if ( modifTime = = m_modifTime )
m_dirty = false ;
}
if ( m_dirty )
{
if ( m_md5sum . isEmpty ( ) )
{
TQFile f ( fileName ) ;
if ( f . open ( IO_ReadOnly ) )
{
const char * c = " " ;
KMD5 context ( c ) ;
context . reset ( ) ;
context . update ( f ) ;
m_md5sum = context . hexDigest ( ) ;
f . close ( ) ;
}
m_dirty = false ;
} else
{
//check if the file is changed, also by file content. Might help to reduce
//unwanted warning on NFS
TQFile f ( fileName ) ;
if ( f . open ( IO_ReadOnly ) )
{
TQString md5sum ;
const char * c = " " ;
KMD5 context ( c ) ;
context . reset ( ) ;
context . update ( f ) ;
md5sum = context . hexDigest ( ) ;
kdDebug ( 24000 ) < < " MD5 sum of current doc: " < < m_md5sum < < endl ;
kdDebug ( 24000 ) < < " MD5 sum of doc on disc : " < < md5sum < < endl ;
if ( md5sum = = m_md5sum )
{
m_dirty = false ;
}
f . close ( ) ;
}
}
}
if ( m_dirty )
{
DirtyDlg * dlg = new DirtyDlg ( url ( ) . path ( ) , m_tempFileName , false , this ) ;
DirtyDialog * w = static_cast < DirtyDialog * > ( dlg - > mainWidget ( ) ) ;
TQString kompareStr = KStandardDirs : : findExe ( " kompare " ) ;
if ( kompareStr . isEmpty ( ) )
{
w - > buttonCompare - > setEnabled ( false ) ;
w - > buttonLoad - > setChecked ( true ) ;
}
if ( dlg - > exec ( ) )
{
m_doc - > setModified ( false ) ;
openURL ( url ( ) ) ;
}
m_modifTime = TQFileInfo ( fileName ) . lastModified ( ) ;
delete dlg ;
}
closeTempFile ( ) ;
m_dirty = false ;
}
}
/** Save the document and reset the dirty status. */
void Document : : save ( )
{
if ( url ( ) . isLocalFile ( ) )
{
TQString fileName ;
fileName = url ( ) . path ( ) ;
fileWatcher - > removeFile ( fileName ) ;
// kdDebug(24000) << "removeFile[save]: " << fileName << endl;
m_doc - > save ( ) ;
m_dirty = false ;
m_modifTime = TQFileInfo ( fileName ) . lastModified ( ) ;
fileWatcher - > addFile ( fileName ) ;
// kdDebug(24000) << "addFile[save]: " << fileName << endl;
} else
{
m_doc - > save ( ) ;
m_dirty = false ;
}
// kdDebug(24000) << "Document " << url() << " saved." << endl;
}
bool Document : : saveAs ( const KURL & url )
{
bool result = m_doc - > saveAs ( url ) ;
if ( result )
{
m_md5sum = " " ;
if ( url . isLocalFile ( ) )
{
TQFile f ( url . path ( ) ) ;
if ( f . open ( IO_ReadOnly ) )
{
const char * c = " " ;
KMD5 context ( c ) ;
context . reset ( ) ;
context . update ( f ) ;
m_md5sum = context . hexDigest ( ) ;
f . close ( ) ;
}
}
}
return result ;
}
void Document : : enableGroupsForDTEP ( const TQString & dtepName , bool enable )
{
if ( m_groupsForDTEPs . isEmpty ( ) )
m_groupsForDTEPs = m_DTEPList ;
if ( enable )
{
if ( m_groupsForDTEPs . contains ( dtepName ) = = 0 )
m_groupsForDTEPs . append ( dtepName ) ;
} else
{
m_groupsForDTEPs . remove ( dtepName ) ;
}
}
void Document : : resetGroupsForDTEPList ( )
{
m_groupsForDTEPs . clear ( ) ;
}
/** Returns true if the number of " (excluding \") inside text is even. */
bool Document : : evenQuotes ( const TQString & text )
{
int num = text . contains ( TQRegExp ( " [^ \\ \\ ] \" " ) ) ;
return ( num / 2 * 2 = = num ) ;
}
void Document : : slotTextChanged ( )
{
changed = true ;
parser - > setSAParserEnabled ( false ) ; //disable special area parsing if the text was changed.
if ( reparseEnabled & & delayedTextChangedEnabled )
{
kdDebug ( 24000 ) < < " Delayed text changed called. " < < endl ;
//delay the handling, otherwise we may get wrong values for (line,column)
TQTimer : : singleShot ( 0 , this , TQT_SLOT ( slotDelayedTextChanged ( ) ) ) ;
delayedTextChangedEnabled = false ;
}
}
void Document : : slotDelayedTextChanged ( bool forced )
{
if ( ! forced & & typingInProgress )
{
kdDebug ( 24000 ) < < " Reparsing delayed! " < < endl ;
parser - > setParsingNeeded ( true ) ;
TQTimer : : singleShot ( 1000 , this , TQT_SLOT ( slotDelayedTextChanged ( ) ) ) ;
reparseEnabled = false ;
delayedTextChangedEnabled = false ;
return ;
}
uint line , column ;
TQString oldNodeName = " " ;
Node * node ;
Node * currentNode = 0L ; //holds a copy of the node which is at (line,column)
Node * previousNode = 0L ; //holds a copy of the node before currentNode
if ( qConfig . updateClosingTags )
{
viewCursorIf - > cursorPositionReal ( & line , & column ) ;
node = parser - > nodeAt ( line , column , false ) ;
if ( node & &
( ( node - > tag - > type = = Tag : : XmlTag & & ! node - > tag - > single ) | |
node - > tag - > type = = Tag : : XmlTagEnd )
)
{
Tag * tag ;
tag = new Tag ( * node - > tag ) ;
currentNode = new Node ( 0L ) ;
currentNode - > removeAll = false ;
currentNode - > tag = tag ;
node = node - > previousSibling ( ) ;
if ( node )
{
tag = new Tag ( * node - > tag ) ;
previousNode = new Node ( 0L ) ;
previousNode - > removeAll = false ;
previousNode - > tag = tag ;
}
}
}
parser - > setSAParserEnabled ( true ) ; //enable special area parsing, it was disabled in slotTextChanged()
baseNode = parser - > rebuild ( this ) ;
if ( qConfig . updateClosingTags & & currentNode )
{
viewCursorIf - > cursorPositionReal ( & line , & column ) ;
node = parser - > nodeAt ( line , column , false ) ;
if ( node & &
node - > tag - > nameSpace + node - > tag - > name ! = currentNode - > tag - > nameSpace + currentNode - > tag - > name & &
( ( node - > tag - > type = = Tag : : XmlTag & & ! node - > tag - > single ) | | node - > tag - > type = = Tag : : XmlTagEnd ) & & node - > tag - > validXMLTag )
{
int bl , bc , bl2 , bc2 ;
node - > tag - > beginPos ( bl , bc ) ;
currentNode - > tag - > beginPos ( bl2 , bc2 ) ;
if ( ( bl ! = bl2 | | bc ! = bc2 ) & & previousNode )
{
previousNode - > tag - > beginPos ( bl2 , bc2 ) ;
Node : : deleteNode ( currentNode ) ;
currentNode = previousNode ;
previousNode = 0L ;
} else
{
Node : : deleteNode ( previousNode ) ;
previousNode = 0L ;
}
if ( bl = = bl2 & & bc = = bc2 & &
( ( node - > tag - > type = = Tag : : XmlTag & & ! node - > tag - > single ) | | currentNode - > tag - > type = = Tag : : XmlTagEnd ) )
{
TQString newName = node - > tag - > name ;
bool updateClosing = ( currentNode - > tag - > type = = Tag : : XmlTag ) & & ! newName . startsWith ( " ! " ) ;
int num = 1 ;
if ( ! node - > tag - > nameSpace . isEmpty ( ) )
newName . prepend ( node - > tag - > nameSpace + " : " ) ;
if ( updateClosing )
node = node - > nextSibling ( ) ;
else
node = node - > previousSibling ( ) ;
while ( node )
{
if ( node - > tag - > validXMLTag & & ( ( node - > tag - > type = = Tag : : XmlTag & & ! node - > tag - > single ) | | node - > tag - > type = = Tag : : XmlTagEnd ) )
{
if ( node - > tag - > nameSpace + node - > tag - > name = = currentNode - > tag - > nameSpace + currentNode - > tag - > name )
{
num + + ;
}
if ( ( updateClosing & & QuantaCommon : : closesTag ( currentNode - > tag , node - > tag ) ) | |
( ! updateClosing & & QuantaCommon : : closesTag ( node - > tag , currentNode - > tag ) ) )
{
num - - ;
}
if ( num = = 0 )
{
reparseEnabled = false ;
node - > tag - > beginPos ( bl , bc ) ;
bc + + ;
if ( editIfExt )
editIfExt - > editBegin ( ) ;
int len = node - > tag - > name . length ( ) ;
if ( ! node - > tag - > nameSpace . isEmpty ( ) )
len + = 1 + node - > tag - > nameSpace . length ( ) ;
editIf - > removeText ( bl , bc , bl , bc + len ) ;
if ( updateClosing )
{
editIf - > insertText ( bl , bc , " / " + newName ) ;
} else
{
editIf - > insertText ( bl , bc , newName . mid ( 1 ) ) ;
if ( bl = = ( int ) line )
{
column + = ( newName . length ( ) - currentNode - > tag - > name . length ( ) ) ;
}
}
if ( editIfExt )
editIfExt - > editEnd ( ) ;
viewCursorIf - > setCursorPositionReal ( bl , bc ) ;
docUndoRedo - > mergeNextModifsSet ( ) ;
baseNode = parser - > parse ( this , true ) ;
viewCursorIf - > setCursorPositionReal ( line , column ) ;
reparseEnabled = true ;
break ;
}
}
if ( updateClosing )
node = node - > nextSibling ( ) ;
else
node = node - > previousSibling ( ) ;
}
}
}
Node : : deleteNode ( currentNode ) ;
Node : : deleteNode ( previousNode ) ;
}
quantaApp - > slotNewLineColumn ( ) ;
if ( qConfig . instantUpdate & & quantaApp - > structTreeVisible ( ) )
{
typingInProgress = false ;
StructTreeView : : ref ( ) - > slotReparse ( this , baseNode , qConfig . expandLevel ) ;
}
reparseEnabled = true ;
delayedTextChangedEnabled = true ;
}
/** Returns list of values for attribute */
TQStringList * Document : : tagAttributeValues ( const TQString & dtdName , const TQString & tag , const TQString & attribute , bool & deleteResult )
{
TQStringList * values = 0L ;
deleteResult = true ;
const DTDStruct * dtd = DTDs : : ref ( ) - > find ( dtdName ) ;
if ( dtd )
{
TQString searchForAttr = ( dtd - > caseSensitive ) ? attribute : attribute . upper ( ) ;
AttributeList * attrs = QuantaCommon : : tagAttributes ( dtdName , tag ) ;
if ( attrs )
{
Attribute * attr ;
KURL u ;
KURL base = url ( ) ;
base . setPath ( base . directory ( false , false ) ) ;
TQString s ;
for ( attr = attrs - > first ( ) ; attr ; attr = attrs - > next ( ) )
{
TQString attrName = ( dtd - > caseSensitive ) ? attr - > name : attr - > name . upper ( ) ;
if ( attrName = = searchForAttr )
{
if ( attr - > type = = " url " ) {
Project * project = Project : : ref ( ) ;
if ( project - > hasProject ( ) )
{
values = new TQStringList ( project - > fileNameList ( ) ) ;
for ( uint i = 0 ; i < values - > count ( ) ; i + + )
{
u = ( * values ) [ i ] ;
u = QExtFileInfo : : toRelative ( u , base ) ;
( * values ) [ i ] = u . path ( ) ;
}
values - > remove ( values - > at ( 0 ) ) ;
values - > append ( " mailto: " + project - > email ( ) ) ;
} else
{
TQDir dir = TQDir ( url ( ) . directory ( ) ) ;
values = new TQStringList ( dir . entryList ( ) ) ;
}
break ;
} else {
values = & attr - > values ;
deleteResult = false ;
break ;
}
}
}
}
}
return values ;
}
bool Document : : hasChanged ( )
{
bool b = changed ;
changed = false ;
return b ;
}
void Document : : setChanged ( bool newStatus )
{
changed = newStatus ;
}
void Document : : paste ( )
{
reparseEnabled = false ;
dynamic_cast < KTextEditor : : ClipboardInterface * > ( view ( ) ) - > paste ( ) ;
reparseEnabled = true ;
baseNode = parser - > rebuild ( this ) ;
}
/** returns all the areas that are between tag and it's closing pair */
TQStringList Document : : tagAreas ( const TQString & tag , bool includeCoordinates , bool skipFoundContent )
{
Node * node = baseNode ;
int bl , bc , el , ec ;
TQStringList result ;
while ( node )
{
if ( node - > tag - > type = = Tag : : XmlTag )
{
if ( ( node - > tag - > dtd ( ) - > caseSensitive & & node - > tag - > name = = tag ) | |
( ! node - > tag - > dtd ( ) - > caseSensitive & & node - > tag - > name . lower ( ) = = tag . lower ( ) ) )
{
node - > tag - > beginPos ( bl , bc ) ;
if ( node - > next )
node - > next - > tag - > endPos ( el , ec ) ;
else
{
el = editIf - > numLines ( ) - 1 ;
ec = editIf - > lineLength ( el ) ;
}
TQString s = text ( bl , bc , el , ec ) ;
if ( includeCoordinates )
{
s . prepend ( TQString ( " %1,%2,%3,%4 \n " ) . arg ( bl ) . arg ( bc ) . arg ( el ) . arg ( ec ) ) ;
}
result + = s ;
if ( skipFoundContent )
node = node - > next ;
else
node = node - > nextSibling ( ) ;
} else
node = node - > nextSibling ( ) ;
} else
node = node - > nextSibling ( ) ;
}
return result ;
}
void Document : : activateRepaintView ( bool activation )
{
repaintEnabled = activation ;
m_view - > setUpdatesEnabled ( activation ) ;
}
void Document : : setErrorMark ( int line )
{
if ( ! markIf )
return ;
markIf - > addMark ( line , KTextEditor : : MarkInterface : : markType07 ) ;
}
void Document : : clearErrorMarks ( )
{
if ( ! markIf )
return ;
TQPtrList < KTextEditor : : Mark > marks = markIf - > marks ( ) ;
KTextEditor : : Mark * mark ;
for ( mark = marks . first ( ) ; mark ; mark = marks . next ( ) )
{
if ( mark - > type & KTextEditor : : MarkInterface : : markType07 )
markIf - > removeMark ( mark - > line , KTextEditor : : MarkInterface : : markType07 ) ;
}
}
TQString Document : : backupPathEntryValue ( )
{
return m_backupPathValue ;
}
void Document : : setBackupPathEntryValue ( const TQString & ev )
{
m_backupPathValue = ev ;
}
/** if the document is modified then backup it and insert an entry in quantarc */
void Document : : createBackup ( KConfig * config )
{
if ( isModified ( ) )
{
if ( isUntitled ( ) )
{
m_backupPathValue = qConfig . backupDirPath + untitledUrl + " . " + hashFilePath ( " file:/// " + untitledUrl ) + " U " ;
} else
{
m_backupPathValue = qConfig . backupDirPath + url ( ) . fileName ( ) + " . " + hashFilePath ( url ( ) . url ( ) ) ;
}
TQString backupPathValueURL = KURL : : fromPathOrURL ( m_backupPathValue ) . url ( ) ;
//the encoding used for the current document
TQString encoding = quantaApp - > defaultEncoding ( ) ;
if ( encodingIf )
encoding = encodingIf - > encoding ( ) ;
if ( encoding . isEmpty ( ) )
encoding = " utf8 " ; //final fallback
//creates an entry string in quantarc if it does not exist yet
config - > setGroup ( " General Options " ) ;
TQStringList backedupFilesEntryList = QuantaCommon : : readPathListEntry ( config , " List of backedup files " ) ; //the files that were backedup
TQStringList autosavedFilesEntryList = QuantaCommon : : readPathListEntry ( config , " List of autosaved files " ) ; //the list of actual backup files inside $KDEHOME/share/apps/quanta/backups
if ( ! autosavedFilesEntryList . contains ( backupPathValueURL ) ) //not yet backed up, add an entry for this file
{
autosavedFilesEntryList . append ( backupPathValueURL ) ;
config - > writePathEntry ( " List of autosaved files " , autosavedFilesEntryList ) ;
if ( ! isUntitled ( ) )
backedupFilesEntryList . append ( KURL : : fromPathOrURL ( url ( ) . path ( ) + " . " + qConfig . quantaPID ) . url ( ) ) ;
else
backedupFilesEntryList . append ( url ( ) . url ( ) + " . " + qConfig . quantaPID ) ;
config - > writePathEntry ( " List of backedup files " , backedupFilesEntryList ) ;
config - > sync ( ) ;
}
//creates a copy of this specific document
TQFile file ( m_backupPathValue ) ;
if ( file . open ( IO_WriteOnly ) )
{
TQTextStream stream ( & file ) ;
stream . setCodec ( TQTextCodec : : codecForName ( encoding . ascii ( ) ) ) ;
stream < < editIf - > text ( ) ;
file . close ( ) ;
}
}
}
/** if there is no more need for a backup copy then remove it */
void Document : : removeBackup ( KConfig * config )
{
TQString backupPathValueURL = KURL : : fromPathOrURL ( m_backupPathValue ) . url ( ) ;
config - > reparseConfiguration ( ) ;
config - > setGroup ( " General Options " ) ;
TQStringList backedupFilesEntryList = QuantaCommon : : readPathListEntry ( config , " List of backedup files " ) ;
TQStringList autosavedFilesEntryList = QuantaCommon : : readPathListEntry ( config , " List of autosaved files " ) ;
autosavedFilesEntryList . remove ( backupPathValueURL ) ;
config - > writePathEntry ( " List of autosaved files " , autosavedFilesEntryList ) ;
backedupFilesEntryList . remove ( KURL : : fromPathOrURL ( url ( ) . path ( ) + " . " + qConfig . quantaPID ) . url ( ) ) ;
config - > writePathEntry ( " List of backedup files " , backedupFilesEntryList ) ;
config - > sync ( ) ;
if ( TQFile : : exists ( m_backupPathValue ) )
TQFile : : remove ( m_backupPathValue ) ;
}
/** creates a string by hashing a bit the path string of this document */
TQString Document : : hashFilePath ( const TQString & p )
{
switch ( p . length ( ) )
{
case 1 : {
int c = int ( p [ 0 ] ) ;
return TQString : : number ( c , 10 ) + " P " + qConfig . quantaPID ;
}
case 2 : {
int c = int ( p [ 1 ] ) * 2 ;
return TQString : : number ( c , 10 ) + " P " + qConfig . quantaPID ;
}
default : {
int sign = 1 ,
sum = 0 ;
uint plen = p . length ( ) ;
for ( uint i = 0 ; i + 1 < plen ; i + + )
{
sum + = int ( p [ i ] ) + int ( p [ i + 1 ] ) * sign ;
sign * = - 1 ;
}
if ( sum > = 0 )
return TQString : : number ( sum , 10 ) + " P " + qConfig . quantaPID ;
else
return TQString : : number ( sum * ( - 1 ) , 10 ) + " N " + qConfig . quantaPID ;
}
}
}
void Document : : convertCase ( )
{
int tagCase = 0 ;
int attrCase = 0 ;
KDialogBase dlg ( this , 0L , false , i18n ( " Change Tag & Attribute Case " ) , KDialogBase : : Ok | KDialogBase : : Cancel ) ;
CaseWidget w ( & dlg ) ;
dlg . setMainWidget ( & w ) ;
const DTDStruct * dtd = defaultDTD ( ) ;
switch ( qConfig . attrCase )
{
case 1 : { w . lowerAttr - > setChecked ( true ) ; break ; }
case 2 : { w . upperAttr - > setChecked ( true ) ; break ; }
default : { w . unchangedAttr - > setChecked ( true ) ; break ; }
}
switch ( qConfig . tagCase )
{
case 1 : { w . lowerTag - > setChecked ( true ) ; break ; }
case 2 : { w . upperTag - > setChecked ( true ) ; break ; }
default : { w . unchangedTag - > setChecked ( true ) ; break ; }
}
if ( dlg . exec ( ) )
{
KProgressDialog progressDlg ( this , 0 , i18n ( " Working... " ) ) ;
progressDlg . setLabel ( i18n ( " Changing tag and attribute case. This may take some time, depending on the document complexity. " ) ) ;
progressDlg . setAllowCancel ( false ) ;
progressDlg . show ( ) ;
kapp - > eventLoop ( ) - > processEvents ( TQEventLoop : : ExcludeUserInput | TQEventLoop : : ExcludeSocketNotifiers ) ;
KProgress * pBar = progressDlg . progressBar ( ) ;
pBar - > setValue ( 0 ) ;
pBar - > setTotalSteps ( nodeNum ) ;
pBar - > setTextEnabled ( true ) ;
if ( w . lowerTag - > isChecked ( ) )
tagCase = 1 ;
if ( w . upperTag - > isChecked ( ) )
tagCase = 2 ;
if ( w . lowerAttr - > isChecked ( ) )
attrCase = 1 ;
if ( w . upperAttr - > isChecked ( ) )
attrCase = 2 ;
if ( tagCase = = 0 & & attrCase = = 0 )
return ;
reparseEnabled = false ;
int bl , bc , ec ;
uint line , col ;
viewCursorIf - > cursorPositionReal ( & line , & col ) ;
Node * node = baseNode ;
while ( node )
{
pBar - > advance ( 1 ) ;
if ( node - > tag - > dtd ( ) = = dtd )
{
if ( tagCase ! = 0 )
{
if ( editIfExt )
editIfExt - > editBegin ( ) ;
node - > tag - > namePos ( bl , bc ) ;
ec = bc + node - > tag - > name . length ( ) ;
editIf - > removeText ( bl , bc , bl , ec ) ;
viewCursorIf - > setCursorPositionReal ( bl , bc ) ;
TQString newName = node - > tag - > name ;
if ( tagCase = = 1 )
newName = newName . lower ( ) ;
else if ( tagCase = = 2 )
newName = newName . upper ( ) ;
editIf - > insertText ( bl , bc , newName ) ;
if ( editIfExt )
editIfExt - > editEnd ( ) ;
}
if ( attrCase ! = 0 )
{
TQString newName ;
for ( int i = 0 ; i < node - > tag - > attrCount ( ) ; i + + )
{
if ( editIfExt )
editIfExt - > editBegin ( ) ;
node - > tag - > attributeNamePos ( i , bl , bc ) ;
newName = node - > tag - > attribute ( i ) ;
ec = bc + newName . length ( ) ;
editIf - > removeText ( bl , bc , bl , ec ) ;
if ( attrCase = = 1 )
newName = newName . lower ( ) ;
else if ( attrCase = = 2 )
newName = newName . upper ( ) ;
editIf - > insertText ( bl , bc , newName ) ;
if ( editIfExt )
editIfExt - > editEnd ( ) ;
}
}
}
node = node - > nextSibling ( ) ;
}
reparseEnabled = true ;
viewCursorIf - > setCursorPositionReal ( line , col ) ;
quantaApp - > reparse ( true ) ;
}
}
void Document : : open ( const KURL & url , const TQString & encoding )
{
if ( encodingIf )
{
encodingIf - > setEncoding ( encoding ) ;
m_encoding = encoding ;
m_codec = TQTextCodec : : codecForName ( m_encoding . ascii ( ) ) ;
}
connect ( m_doc , TQT_SIGNAL ( completed ( ) ) , this , TQT_SLOT ( slotOpeningCompleted ( ) ) ) ;
connect ( m_doc , TQT_SIGNAL ( canceled ( const TQString & ) ) , this , TQT_SLOT ( slotOpeningFailed ( const TQString & ) ) ) ;
if ( ! openURL ( url ) )
slotOpeningFailed ( TQString : : null ) ;
if ( ! url . isLocalFile ( ) )
{
QExtFileInfo internalFileInfo ;
internalFileInfo . enter_loop ( ) ;
}
}
void Document : : slotOpeningCompleted ( )
{
KURL u = url ( ) ;
if ( ! u . isLocalFile ( ) )
{
m_modifTime = TQDateTime ( ) ;
qApp - > exit_loop ( ) ;
}
else
{
fileWatcher - > addFile ( u . path ( ) ) ;
m_modifTime = TQFileInfo ( u . path ( ) ) . lastModified ( ) ;
// kdDebug(24000) << "addFile[Document::open]: " << u.path() << endl;
}
disconnect ( m_doc , TQT_SIGNAL ( completed ( ) ) , this , TQT_SLOT ( slotOpeningCompleted ( ) ) ) ;
disconnect ( m_doc , TQT_SIGNAL ( canceled ( const TQString & ) ) , this , TQT_SLOT ( slotOpeningFailed ( const TQString & ) ) ) ;
m_dirty = false ;
m_view - > setFocus ( ) ;
processDTD ( ) ;
emit openingCompleted ( u ) ;
}
void Document : : slotOpeningFailed ( const TQString & errorMessage )
{
m_md5sum = " " ;
Q_UNUSED ( errorMessage ) ; //TODO: append the error message to our own error message
if ( ! url ( ) . isLocalFile ( ) )
qApp - > exit_loop ( ) ;
disconnect ( m_doc , TQT_SIGNAL ( completed ( ) ) , this , TQT_SLOT ( slotOpeningCompleted ( ) ) ) ;
disconnect ( m_doc , TQT_SIGNAL ( canceled ( const TQString & ) ) , this , TQT_SLOT ( slotOpeningFailed ( const TQString & ) ) ) ;
emit openingFailed ( url ( ) ) ;
}
void Document : : processDTD ( const TQString & documentType )
{
TQString foundName ;
TQString projectDTD = Project : : ref ( ) - > defaultDTD ( ) ;
setDTDIdentifier ( projectDTD ) ;
Tag * tag = 0L ;
if ( documentType . isEmpty ( ) )
{
foundName = findDTDName ( & tag ) ; //look up the whole file for DTD definition
bool found = false ;
if ( ! foundName . isEmpty ( ) ) //!DOCTYPE found in file
{
KDialogBase dlg ( this , 0L , true , i18n ( " DTD Selector " ) , KDialogBase : : Ok | KDialogBase : : Cancel ) ;
DTDSelectDialog * dtdWidget = new DTDSelectDialog ( & dlg ) ;
dlg . setMainWidget ( dtdWidget ) ;
TQStringList lst = DTDs : : ref ( ) - > nickNameList ( true ) ;
TQString foundNickName = DTDs : : ref ( ) - > getDTDNickNameFromName ( foundName ) ;
for ( uint i = 0 ; i < lst . count ( ) ; i + + )
{
dtdWidget - > dtdCombo - > insertItem ( lst [ i ] ) ;
if ( lst [ i ] = = foundNickName )
{
setDTDIdentifier ( foundName ) ;
found = true ;
}
}
if ( ! DTDs : : ref ( ) - > find ( foundName ) )
{
//try to find the closest matching DTD
TQString s = foundName . lower ( ) ;
uint spaceNum = s . contains ( ' ' ) ;
TQStringList dtdList = DTDs : : ref ( ) - > nameList ( ) ;
TQStringList lastDtdList ;
for ( uint i = 0 ; i < = spaceNum & & ! dtdList . empty ( ) ; i + + )
{
lastDtdList = dtdList ;
TQStringList : : Iterator strIt = dtdList . begin ( ) ;
while ( strIt ! = dtdList . end ( ) )
{
if ( ! ( * strIt ) . startsWith ( s . section ( ' ' , 0 , i ) ) )
{
strIt = dtdList . remove ( strIt ) ;
} else
{
+ + strIt ;
}
}
}
dtdList = lastDtdList ;
for ( uint i = 0 ; i < = spaceNum & & ! dtdList . empty ( ) ; i + + )
{
lastDtdList = dtdList ;
TQStringList : : Iterator strIt = dtdList . begin ( ) ;
while ( strIt ! = dtdList . end ( ) )
{
if ( ! ( * strIt ) . endsWith ( s . section ( ' ' , - ( i + 1 ) , - 1 ) ) )
{
strIt = dtdList . remove ( strIt ) ;
} else
{
+ + strIt ;
}
}
}
if ( lastDtdList . count ( ) = = 1 | | lastDtdList [ 0 ] . startsWith ( s . section ( ' ' , 0 , 0 ) ) )
{
projectDTD = lastDtdList [ 0 ] ;
}
}
// dlg->dtdCombo->insertItem(i18n("Create New DTD Info"));
dtdWidget - > messageLabel - > setText ( i18n ( " This DTD is not known for Quanta. Choose a DTD or create a new one. " ) ) ;
dtdWidget - > currentDTD - > setText ( DTDs : : ref ( ) - > getDTDNickNameFromName ( foundName ) ) ;
TQString projectDTDNickName = DTDs : : ref ( ) - > getDTDNickNameFromName ( projectDTD ) ;
for ( int i = 0 ; i < dtdWidget - > dtdCombo - > count ( ) ; i + + )
{
if ( dtdWidget - > dtdCombo - > text ( i ) = = projectDTDNickName )
{
dtdWidget - > dtdCombo - > setCurrentItem ( i ) ;
break ;
}
}
if ( ! found & & qConfig . showDTDSelectDialog )
{
quantaApp - > slotHideSplash ( ) ;
if ( dlg . exec ( ) )
{
qConfig . showDTDSelectDialog = ! dtdWidget - > useClosestMatching - > isChecked ( ) ;
setDTDIdentifier ( DTDs : : ref ( ) - > getDTDNameFromNickName ( dtdWidget - > dtdCombo - > currentText ( ) ) ) ;
const DTDStruct * dtd = DTDs : : ref ( ) - > find ( dtdName ) ;
if ( dtdWidget - > convertDTD - > isChecked ( ) & & dtd - > family = = Xml )
{
int bLine , bCol , eLine , eCol ;
tag - > beginPos ( bLine , bCol ) ;
tag - > endPos ( eLine , eCol ) ;
editIf - > removeText ( bLine , bCol , eLine , eCol + 1 ) ;
viewCursorIf - > setCursorPositionReal ( ( uint ) bLine , ( uint ) bCol ) ;
insertText ( " <!DOCTYPE " + dtd - > doctypeStr + " > " ) ;
}
}
}
} else //DOCTYPE not found in file
{
KURL u = url ( ) ;
TQString dtdId = DTDs : : ref ( ) - > DTDforURL ( u ) - > name ;
// if (dtdId == "empty")
{
const DTDStruct * dtd = DTDs : : ref ( ) - > find ( projectDTD ) ;
if ( DTDs : : canHandle ( dtd , u ) )
dtdId = projectDTD ;
else
{
dtd = DTDs : : ref ( ) - > find ( qConfig . defaultDocType ) ;
if ( DTDs : : canHandle ( dtd , u ) )
dtdId = qConfig . defaultDocType ;
}
}
setDTDIdentifier ( dtdId ) ;
}
} else //dtdName is read from the method's parameter
{
setDTDIdentifier ( documentType ) ;
}
if ( ! isUntitled ( ) )
{
quantaApp - > messageOutput ( ) - > showMessage ( i18n ( " \" %1 \" is used for \" %2 \" . \n " ) . arg ( DTDs : : ref ( ) - > getDTDNickNameFromName ( dtdName ) ) . arg ( url ( ) . prettyURL ( 0 , KURL : : StripFileProtocol ) ) ) ;
}
quantaApp - > slotLoadToolbarForDTD ( dtdName ) ;
StructTreeView : : ref ( ) - > useOpenLevelSetting = true ;
delete tag ;
}
/** Called when a file on the disk has changed. */
void Document : : slotFileDirty ( const TQString & fileName )
{
if ( url ( ) . path ( ) = = fileName & & ! dirty ( ) )
{
setDirtyStatus ( true ) ;
if ( this = = ViewManager : : ref ( ) - > activeDocument ( ) )
{
checkDirtyStatus ( ) ;
}
}
}
void Document : : slotMarkChanged ( KTextEditor : : Mark mark , KTextEditor : : MarkInterfaceExtension : : MarkChangeAction action )
{
if ( mark . type & KTextEditor : : MarkInterface : : markType02 )
{
if ( action = = KTextEditor : : MarkInterfaceExtension : : MarkRemoved )
emit breakpointUnmarked ( this , mark . line ) ;
else
emit breakpointMarked ( this , mark . line ) ;
}
}
void Document : : resetDTEPs ( )
{
m_DTEPList . clear ( ) ;
m_DTEPList . append ( defaultDTD ( ) - > name ) ;
}
void Document : : addDTEP ( const TQString & dtepName )
{
if ( m_DTEPList . contains ( dtepName ) = = 0 )
{
m_DTEPList . append ( dtepName ) ;
}
}
TQStringList Document : : groupsForDTEPs ( )
{
if ( m_groupsForDTEPs . isEmpty ( ) )
return m_DTEPList ;
else
return m_groupsForDTEPs ;
}
TQString Document : : annotationText ( uint line )
{
TQMap < uint , QPair < TQString , TQString > > : : Iterator it = m_annotations . find ( line ) ;
if ( it ! = m_annotations . end ( ) )
return it . data ( ) . first ;
else
return TQString : : null ;
}
void Document : : setAnnotationText ( uint line , const TQString & text )
{
if ( text . isEmpty ( ) )
{
m_annotations . remove ( line ) ;
if ( markIf )
markIf - > removeMark ( line , KTextEditor : : MarkInterface : : markType08 ) ;
} else
{
m_annotations . insert ( line , qMakePair ( text , TQString ( " " ) ) ) ;
if ( markIf )
markIf - > setMark ( line , KTextEditor : : MarkInterface : : markType08 ) ;
uint line , column ;
viewCursorIf - > cursorPositionReal ( & line , & column ) ;
viewCursorIf - > setCursorPositionReal ( line , 0 ) ;
const DTDStruct * dtd = currentDTD ( true ) ;
TQString commentBegin = " " ;
TQString commentEnd = " " ;
for ( TQMap < TQString , TQString > : : ConstIterator it = dtd - > comments . constBegin ( ) ; it ! = dtd - > comments . constEnd ( ) ; + + it )
{
commentBegin = it . key ( ) ;
commentEnd = it . data ( ) ;
if ( commentEnd ! = " \n " )
break ;
}
if ( commentBegin . isEmpty ( ) )
{
if ( dtd - > family = = Xml )
{
commentBegin = " <!-- " ;
commentEnd = " --> " ;
} else
{
commentBegin = " /* " ;
commentEnd = " */ " ;
}
}
TQString s = " @annotation: " + text ;
s . prepend ( commentBegin + " " ) ;
s . append ( " " + commentEnd + " \n " ) ;
insertText ( s , true , true ) ;
emit showAnnotation ( line , " " , qMakePair ( text , TQString ( " " ) ) ) ;
}
}
void Document : : addAnnotation ( uint line , const QPair < TQString , TQString > & annotation )
{
m_annotations . insert ( line , annotation ) ;
if ( markIf )
markIf - > setMark ( line , KTextEditor : : MarkInterface : : markType08 ) ;
emit showAnnotation ( line , " " , annotation ) ;
}
void Document : : clearAnnotations ( )
{
if ( markIf )
{
TQPtrList < KTextEditor : : Mark > m = markIf - > marks ( ) ;
for ( uint i = 0 ; i < m . count ( ) ; i + + )
markIf - > removeMark ( m . at ( i ) - > line , KTextEditor : : MarkInterface : : markType08 ) ;
}
m_annotations . clear ( ) ;
}
bool Document : : openURL ( const KURL & url )
{
m_md5sum = " " ;
if ( url . isLocalFile ( ) )
{
TQFile f ( url . path ( ) ) ;
if ( f . open ( IO_ReadOnly ) )
{
const char * c = " " ;
KMD5 context ( c ) ;
context . reset ( ) ;
context . update ( f ) ;
m_md5sum = context . hexDigest ( ) ;
f . close ( ) ;
}
}
return m_doc - > openURL ( url ) ;
}
# include "document.moc"