1 /***************************************************************************
2 Copyright 2006 David Nolden <david.nolden.kdevelop@art-master.de>
3 ***************************************************************************/
5 /***************************************************************************
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
12 ***************************************************************************/
14 #include "documentwrapper.h"
15 #include "kdevteamwork_messages.h"
16 #include "kdevteamworkplugin.h"
17 #include <QStandardItemModel>
18 #include <QModelIndex>
23 #include <kmessagebox.h>
24 #include <klocalizedstring.h>
25 #include <k3process.h>
26 #include <ktexteditor/document.h>
27 #include <ktexteditor/range.h>
28 #include <interfaces/idocumentcontroller.h>
29 #include <interfaces/idocument.h>
30 #include "lib/dynamictext/dynamictext.h"
31 #include "kdevteamwork_helpers.h"
32 #include "collaborationmanager.h"
33 #include "filecollaborationmessages.h"
34 #include "lib/network/basicsession.h"
36 #include "lib/dynamictext/verify.h"
37 #include "filesynchronizemessage.h"
38 #include "qdynamictext.h"
39 #include "vectortimestampeditor.h"
40 #include "kdevteamwork.h"
41 #include "patchesmanager.h"
42 #include "teamworkfoldermanager.h"
43 #include "filecollaborationsession.h"
44 #include "patchmessage.h"
45 #include "filecollaborationmanager.h"
46 #include "lib/network/messagetypeset.h"
47 #include "lib/network/messagesendhelper.h"
48 #include <interfaces/iuicontroller.h> /* defines [function] activeMainWindow */
49 #include <interfaces/icore.h> /* defines [function] uiController */
51 /* Exclude this file from doublequote_chars check as krazy doesn't understand
53 //krazy:excludeall=doublequote_chars
55 using namespace KDevelop
;
57 #define IFDEBUG( x ) /**/
58 //#define IFDEBUG( x ) x
60 struct DocumentWrapperTreeAction
: public StandardCollaborationTreeAction
<DocumentWrapper
> {
61 DocumentWrapperTreeAction( DocumentWrapper
* w
) : StandardCollaborationTreeAction
<DocumentWrapper
>( w
) {}
62 virtual void doubleClicked() {
64 target
->openDocument( true );
67 virtual void clicked() {}
68 virtual void fillContextMenu( QMenu
* menu
) {
70 target
->fillContextMenu( 0, menu
);
75 bool DocumentWrapper::hadError() const {
79 uint
DocumentWrapper::id() const {
83 DocumentWrapper::DocumentWrapper( uint id
, const LoggerPointer
& logger
, QString fileName
, uint ownIndex
, bool readFile_
, FileCollaborationSession
* session
, bool fromBuffer
) :
84 SafeLogger( logger
, ~( "document-wrapper \"" + fileName
+ "\": " ) ),
85 m_text( new QDynamicText() ),
87 m_realFile( readFile_
),
88 m_fileName( fileName
),
91 m_ownIndex( ownIndex
),
96 m_dispatcher( *this ){
98 out( Logger::Debug
) << "DocumentWrapper for" << fileName
<< "created:" << ownIndex
<< "" << readFile_
;
100 readFile( fromBuffer
);
102 connect( m_text
.data(), SIGNAL( stateChanged( QDynamicText
& ) ), this, SLOT( stateChanged() ) );
105 QIcon
DocumentWrapper::icon() const {
107 return IconCache::getIconStatic( "collaboration_file_dead" );
109 return IconCache::getIconStatic( "collaboration_file" );
111 return IconCache::getIconStatic( "collaboration_file_disabled" );
114 void DocumentWrapper::updateTree( QModelIndex
& i
, QStandardItemModel
* model
) {
115 model
->setData( i
, fileName(), Qt::DisplayRole
);
116 model
->setData( i
, icon(), Qt::DecorationRole
);
118 v
.setValue
<CollaborationTreeActionPointer
>( new DocumentWrapperTreeAction( this ) );
119 model
->setData( i
, v
, Qt::UserRole
);
122 void DocumentWrapper::fillContextMenu( int /*var*/, QMenu
* menu
) {
123 QMenu
* m
= new QMenu( menu
);
124 m
->setTitle( "Save Visible State" );
125 m
->addAction( "As Patch", this, SLOT( saveAsPatch() ) );
126 //m->addAction( "To New Buffer", this, SLOT( saveNewBuffer() ) );
128 m
->addAction( QString( "As %1" ).arg( m_fileName
), this, SLOT( saveAsBufferFile() ) );
133 menu
->addAction( "Enable Editing", this, SLOT( toggleEnabled() ) );
134 else if ( m_session
->isMasterSession() )
135 menu
->addAction( "Disable Editing", this, SLOT( toggleEnabled() ) );
137 if ( m_session
->isMasterSession() || m_dead
) {
138 menu
->addSeparator();
139 menu
->addAction( "Remove", this, SLOT( remove
143 menu
->addSeparator();
144 menu
->addAction( "Manage Dynamic Text", this, SLOT( manageDynamicText() ) );
147 QString
DocumentWrapper::text() const {
148 return ~m_text
->text().text();
151 VectorTimestamp
DocumentWrapper::state() const {
152 return m_text
->state();
155 const QDynamicText
& DocumentWrapper::dynamicText() const {
159 bool DocumentWrapper::checkDocumentSync() const {
160 if ( m_document
&& m_document
->textDocument() ) {
161 return m_document
->textDocument() ->text() == ~m_text
->text().text();
167 void DocumentWrapper::remove
171 void DocumentWrapper::toggleEnabled() {
172 m_disabled
= !m_disabled
;
173 out( Logger::Debug
) << "Editing is now" << ( m_disabled
? "disabled" : "enabled");
176 void DocumentWrapper::saveAsBufferFile() {
177 KUrl u
= TeamworkFolderManager::workspaceAbsolute( m_fileName
);
179 IDocument
* doc
= KDevTeamworkPlugin::staticDocumentController() ->openDocument( u
, KTextEditor::Cursor() );
181 if ( doc
&& doc
->textDocument() ) {
182 if ( doc
->state() == IDocument::Modified
|| doc
->state() == IDocument::DirtyAndModified
) {
183 int answer
= KMessageBox::warningYesNo( KDevTeamworkPlugin::staticCore()->uiController()->activeMainWindow()->window(), i18n( "The buffer of %1 is modified, should the content be replaced?" , m_fileName
) );
184 if ( answer
!= KMessageBox::Yes
)
187 doc
->textDocument() ->setText( ~m_text
->text().text() );
190 err() << "saveAsBufferFile(): could not open document for" << u
.toLocalFile();
194 OutputFileWriter::OutputFileWriter( const QString
& file
) : m_file( file
), m_failed( false ) {
195 if ( !m_file
.open( QIODevice::WriteOnly
) )
196 throw QString( "could not open file %1" ).arg( file
);
199 bool OutputFileWriter::failed() const {
203 void OutputFileWriter::receivedStdout( K3Process */
*proc*/
, char *buffer
, int buflen
) {
204 if ( m_file
.write( buffer
, buflen
) != buflen
) {
209 LocalPatchSourcePointer
DocumentWrapper::saveAsPatch( bool addToList
, bool edit
) {
211 KDevTeamwork
* tw
= KDevTeamwork::self();
213 PatchesManager
* pm
= tw
->patchesManager();
215 QString peer
= m_session
->firstPeerName();
216 if ( m_session
->isMasterSession() )
219 LocalPatchSourcePointer::Locked l
= new LocalPatchSource();
220 l
->name
= ~( m_session
->name() + "@" + peer
+ "_" + QDateTime::currentDateTime().toString( Qt::ISODate
) );
221 l
->type
= "text/x-diff";
222 l
->applyCommand
= "-p0";
223 l
->unApplyCommand
= "-p0 -R";
224 l
->userIdentity
= m_session
->manager() ->teamwork() ->currentUserIdentity();
226 KUrl u
= TeamworkFolderManager::createUniqueFile( "patches", "diff", ~l
->name
, "collab_", "" );
228 l
->filename
= ~TeamworkFolderManager::teamworkRelative( u
, "patches" );
230 KUrl workingDir
= TeamworkFolderManager::createUniqueDirectory( "temp", m_session
->name(), "diff_" );
231 KUrl
subFolder( TeamworkFolderManager::teamworkRelative( workingDir
) );
232 subFolder
.addPath( QFileInfo( m_fileName
).path() );
234 KUrl tempCurrent
= TeamworkFolderManager::createUniqueFile( subFolder
.toLocalFile(), m_fileName
);
235 KUrl tempBase
= TeamworkFolderManager::createUniqueFile( subFolder
.toLocalFile(), m_fileName
, "base_" );
237 TeamworkFolderManager::self() ->registerTempItem( tempCurrent
);
238 TeamworkFolderManager::self() ->registerTempItem( tempBase
);
241 QByteArray path
= tempCurrent
.toLocalFile().toUtf8();
242 std::ofstream
fCurrent( path
.data(), ios_base::out
);
243 if ( !fCurrent
.is_open() )
244 throw "could not open file for writing: " + tempCurrent
.toLocalFile();
245 fCurrent
<< m_text
->text().text();
248 QByteArray path
= tempBase
.toLocalFile().toUtf8();
249 std::ofstream
fBase( path
.data(), ios_base::out
);
250 if ( !fBase
.is_open() )
251 throw "could not open file for writing: " + tempBase
.toLocalFile();
252 fBase
<< m_text
->initialText();
255 ///@todo make this work with remote files
256 OutputFileWriter
ow( u
.toLocalFile() );
257 proc
.setWorkingDirectory( workingDir
.toLocalFile() );
258 QString cmdLine
= + + " " + tempCurrent
.toLocalFile() + " > " + u
.toLocalFile();
259 proc
.setPriority( K3Process::PrioLowest
);
261 proc
<< "--unified=4";
262 proc
<< tempBase
.toLocalFile();
263 proc
<< tempCurrent
.toLocalFile();
265 connect( &proc
, SIGNAL( receivedStdout ( K3Process
*, char *, int ) ), &ow
, SLOT( receivedStdout( K3Process
*, char*, int ) ) );
268 throw QString( "writing to %1 failed" ).arg( u
.prettyUrl() );
270 out( Logger::Debug
) << "saveAsPatch(..) executing \"diff --unified=4 " + tempBase
.toLocalFile() + " " + tempCurrent
.toLocalFile() + "\"";
272 proc
.start( K3Process::Block
, K3Process::Stdout
);
276 pm
->showPatchInfo( l
, true );
279 } catch ( const QString
& str
) {
280 err() << "saveAsPatch():" << str
;
281 } catch ( const char * str
) {
282 err() << "saveAsPatch():" << str
;
287 void DocumentWrapper::saveNewBuffer() {
288 ///It would be nice to create a nameless buffer here and insert the text
291 void DocumentWrapper::manageDynamicText() {
292 new VectorTimestampEditor( logger(), this, false, m_text
, true );
295 void DocumentWrapper::stateChanged() {
301 bool DocumentWrapper::synchronize( const UserPointer
& user
) {
305 out( Logger::Debug
) << "synchronizing with" << user
.unsafe()->safeName();
307 UserPointer::Locked l
= user
;
308 if ( l
&& l
->online().session() ) {
309 return globalMessageSendHelper().send
<FileSynchronize
>( l
->online().session().unsafe(), fileName(), *m_text
, true, id(), m_session
->id() );
311 err() << "cannot send synchronization-message because the user cannot be locked, or is not online";
316 int DocumentWrapper::receiveMessage( FileEditRejectMessage
* msg
) {
317 if ( m_session
->isMasterSession() ) {
318 out( Logger::Warning
) << "got a reject-message from a client, sending complete synchronization";
319 synchronize( msg
->info().user() );
323 ///A reject-message contains a new state that should be applied
324 VectorTimestamp v
= msg
->timeStamp();
326 m_text
->changeState( v
);
328 } catch ( const DynamicTextError
& err
) {
329 ///There is no other way than resynchronizing the whole file
330 out() << "error while handling a reject, resynchronizing. Error:" << err
.what();
331 globalMessageSendHelper().sendReply
<FileEditRejectMessage
>( msg
, VectorTimestamp(), id(), m_session
->id() );
336 int DocumentWrapper::receiveMessage( MessageInterface
* msg
) {
337 out( Logger::Warning
) << "got unknown message of type" << msg
->name();
341 int DocumentWrapper::receiveMessage( FileEditMessage
* msg
) {
343 if ( ( m_disabled
|| m_dead
) && m_session
->isMasterSession() ) {
344 globalMessageSendHelper().sendReply
<FileEditRejectMessage
>( msg
, m_text
->tailState(), id(), m_session
->id() );
347 FileEditMessage
* emsg
= dynamic_cast<FileEditMessage
*>( msg
);
350 bool wasTail
= m_text
->state() == m_text
->tailState();
351 m_text
->insert( emsg
->timeStamp(), emsg
->replacement() );
354 m_text
->text().registerNotifier( this );
355 m_text
->changeState();
356 m_text
->text().unregisterNotifier();
360 } catch ( const DynamicTextError
& error
) {
361 ///@todo error-handling
362 err() << "receiveMessage( FileEditMessage" << msg
->timeStamp() << "" << msg
->replacement() << "):" << error
.what();
363 globalMessageSendHelper().sendReply
<FileEditRejectMessage
>( msg
, m_text
->tailState(), id(), m_session
->id() );
364 m_text
->text().unregisterNotifier(); //@todo use a little wrapper-class for this
369 void DocumentWrapper::notifyFlexibleTextErase( int position
, int length
) {
370 if ( m_document
&& m_document
->textDocument() ) {
374 m_text
->text().linearToLineColumn( position
, line
, column
);
375 if ( line
== -1 || column
== -1 )
376 throw DynamicTextError( "receiveMessage( FileEditMessage ): could not convert index to cursor" );
378 KTextEditor::Cursor
start( line
, column
);
381 m_text
->text().linearToLineColumn( position
+ length
, line
, column
);
383 if ( line
== -1 || column
== -1 )
384 throw DynamicTextError( "receiveMessage( FileEditMessage ): could not convert index to cursor" );
386 KTextEditor::Cursor
end( line
, column
);
389 m_document
->textDocument() ->replaceText( KTextEditor::Range( start
, end
), "" );
393 void DocumentWrapper::notifyFlexibleTextInsert( int position
, const std::string
& text
) {
394 if ( m_document
&& m_document
->textDocument() ) {
398 m_text
->text().linearToLineColumn( position
, line
, column
);
399 if ( line
== -1 || column
== -1 )
400 throw DynamicTextError( "receiveMessage( FileEditMessage ): could not convert index to cursor" );
402 KTextEditor::Cursor
start( line
, column
);
404 m_document
->textDocument() ->replaceText( KTextEditor::Range( start
, start
), toQ( text
.c_str() ) );
408 void DocumentWrapper::notifyFlexibleTextReplace( int position
, int length
, const std::string
& replacement
) {
409 if ( m_document
&& m_document
->textDocument() ) {
413 m_text
->text().linearToLineColumn( position
, line
, column
);
414 if ( line
== -1 || column
== -1 )
415 throw DynamicTextError( "receiveMessage( FileEditMessage ): could not convert index to cursor" );
417 KTextEditor::Cursor
start( line
, column
);
420 m_text
->text().linearToLineColumn( position
+ length
, line
, column
);
422 if ( line
== -1 || column
== -1 )
423 throw DynamicTextError( "receiveMessage( FileEditMessage ): could not convert index to cursor" );
425 KTextEditor::Cursor
end( line
, column
);
428 m_document
->textDocument() ->replaceText( KTextEditor::Range( start
, end
), toQ( replacement
.c_str() ) );
432 void DocumentWrapper::processMessage( DocumentWrapperMessage
* msg
) {
434 /*if ( !checkDocumentSync() ) {
435 if ( m_document && m_document->textDocument() ) {
436 out( Logger::Warning ) << "processMessage(begin): document and dynamictext got out of sync! Resynchronizing";
441 IFDEBUG( out( Logger::Debug
) << "processMessage(..) processing" << msg
->name() );
445 if ( !checkDocumentSync() ) {
446 if ( m_document && m_document->textDocument() ) {
447 out( Logger::Warning ) << "processMessage(end): document and dynamictext got out of sync! Resynchronizing";
453 void DocumentWrapper::documentDestroyed() {
457 QString
DocumentWrapper::fileName() const {
461 IDocument
* DocumentWrapper::document() {
465 void DocumentWrapper::fillDocumentText() {
467 if ( m_document
&& m_document
->textDocument() ) {
468 m_document
->textDocument() ->setText( ~m_text
->text().text() );
470 err() << "cannot update document-text: no document available";
474 void DocumentWrapper::openDocument( bool toForeground
) {
478 KDevTeamworkPlugin::staticDocumentController() ->activateDocument( m_document
);
482 out( Logger::Debug
) << "openDocument()" << fileName() << "" << toForeground
;
484 if ( m_tempFile
.isEmpty() ) {
485 KUrl
subfolder( QString( "filecollaboration" ) );
486 subfolder
.addPath( m_session
->name() + "_" + QString( "%1").arg(m_session
->id() ) );
489 if ( m_session
->isMasterSession() ) {
492 location
= m_session
->firstPeerName();
495 ///@todo make this work work remote files
496 m_tempFile
= TeamworkFolderManager::createUniqueFile( subfolder
.toLocalFile(), m_fileName
, "", "@" + m_session
->name() ).toLocalFile();
499 out( Logger::Debug
) << "temporary file for" << fileName() << "is" << m_tempFile
;
501 m_document
= KDevTeamworkPlugin::staticDocumentController() ->openDocument( m_tempFile
, KTextEditor::Cursor(), toForeground
== true ? KDevelop::IDocumentController::DefaultMode
: KDevelop::IDocumentController::DoNotActivate
);
504 KTextEditor::Document
* doc
= m_document
->textDocument();
507 throw "could not open as text-document";
511 /*connect( m_document, SIGNAL( destroyed( QObject* ) ), this, SLOT( documentDestroyed() ) );*/
512 connect( m_document
->textDocument(), SIGNAL( destroyed( QObject
* ) ), this, SLOT( documentDestroyed() ) );
513 connect( doc
, SIGNAL( textInserted ( KTextEditor::Document
*,
514 const KTextEditor::Range
& ) ), this, SLOT( textInserted ( KTextEditor::Document
*,
515 const KTextEditor::Range
& ) ) );
516 connect( doc
, SIGNAL( textRemoved ( KTextEditor::Document
*,
517 const KTextEditor::Range
& ) ), this, SLOT( textRemoved ( KTextEditor::Document
*,
518 const KTextEditor::Range
& ) ) );
519 connect( doc
, SIGNAL( textChanged ( KTextEditor::Document
*,
520 const KTextEditor::Range
&,
521 const KTextEditor::Range
& ) ), this, SLOT( textChanged ( KTextEditor::Document
*,
522 const KTextEditor::Range
&,
523 const KTextEditor::Range
& ) ) );
525 throw "could not open document";
527 } catch ( const QString
& str
) {
528 err() << "openDocument():" << str
;
529 } catch ( const char * str
) {
530 err() << "openDocument():" << str
;
534 uint
getPositionInDocument( KTextEditor::Document
* doc
, const KTextEditor::Cursor
& cursor
) {
535 QString str
= doc
->text( KTextEditor::Range( KTextEditor::Cursor( 0, 0 ), cursor
) );
539 void DocumentWrapper::textChanged ( KTextEditor::Document
* document
, const KTextEditor::Range
& oldRange
, const KTextEditor::Range
& newRange
) {
542 out( Logger::Debug
) << "textChanged";
544 VectorTimestamp
v( m_text
->state() );
545 v
.setPrimaryIndex( m_ownIndex
);
548 int start
= m_text
->text().lineColumnToLinear( oldRange
.start().line(), oldRange
.start().column() );
549 int end
= m_text
->text().lineColumnToLinear( oldRange
.end().line(), oldRange
.end().column() );
551 if ( start
== -1 || end
== -1 || start
== end
) {
552 err() << "textRemoved(..): DynamicText and Document seem to be out of sync";
558 std::string oldText
= m_text
->text().substr( start
, end
- start
);
559 QString newText
= document
->text( newRange
);
561 if ( oldRange
.end().line() == oldRange
.start().line() && newRange
.end().line() == newRange
.start().line() ) {
562 out( Logger::Debug
) << "textChanged at" << start
<< ":" << oldText
<< "->" << newText
;
564 out( Logger::Debug
) << "textChanged at" << start
;
567 ///It might be better to model the edit by one removal and one insertion, because that allows better resolution of conflicts.(Think about if it should be like that)
568 SimpleReplacement
r( start
, ~newText
, oldText
);
571 DYN_VERIFY( !m_disabled
);
572 DYN_VERIFY_SAME( m_text
->state(), m_text
->tailState() );
574 m_text
->insert( v
, r
);
575 } catch ( const DynamicTextError
& error
) {
576 err() << "error in textRemoved(..):" << error
.what();
582 emit
publishEdit( v
, r
, this );
585 ///All the line/column to/from linear conversion is very slow and should be done different
586 void DocumentWrapper::textRemoved ( KTextEditor::Document
* /*document*/, const KTextEditor::Range
& range
) {
589 int start
= m_text
->text().lineColumnToLinear( range
.start().line(), range
.start().column() );
590 int end
= m_text
->text().lineColumnToLinear( range
.end().line(), range
.end().column() );
592 if ( start
== -1 || end
== -1 ) {
593 err() << "textRemoved(..): DynamicText and Document seem to be out of sync";
598 std::string oldText
= m_text
->text().substr( start
, end
- start
);
600 if ( range
.end().line() == range
.start().line() ) {
601 IFDEBUG( out( Logger::Debug
) << "textRemoved at" << start
<< ":" << document
->text( range
) );
603 IFDEBUG( out( Logger::Debug
) << "textRemoved at" << start
);
606 SimpleReplacement
r( start
, "", oldText
);
610 DYN_VERIFY( !m_disabled
);
611 DYN_VERIFY_SAME( m_text
->state(), m_text
->tailState() );
613 v
= m_text
->insert( m_ownIndex
, r
);
614 } catch ( const DynamicTextError
& error
) {
615 err() << "error in textRemoved(..):" << error
.what();
621 emit
publishEdit( v
, r
, this );
624 void DocumentWrapper::textInserted ( KTextEditor::Document
* document
, const KTextEditor::Range
& range
) {
629 QString newText
= document
->text( range
);
630 uint pos
= m_text
->text().lineColumnToLinear( range
.start().line(), range
.start().column() );
632 if ( range
.end().line() == range
.start().line() ) {
633 IFDEBUG( out( Logger::Debug
) << "textInserted at" << pos
<< ":" << document
->text( range
) );
635 IFDEBUG( out( Logger::Debug
) << "textInserted at" << pos
);
638 SimpleReplacement r
= SimpleReplacement( pos
, ~newText
, "" );
641 DYN_VERIFY_SAME( m_text
->state(), m_text
->tailState() );
642 DYN_VERIFY( !m_disabled
);
644 v
= m_text
->insert( m_ownIndex
, r
);
645 } catch ( const DynamicTextError
& error
) {
646 err() << "error in textInserted(..):" << error
.what();
652 emit
publishEdit( v
, r
, this );
655 std::string
DocumentWrapper::logPrefix() {
656 return "DocumentWrapper for " + ~fileName() + ": ";
659 int DocumentWrapper::receiveMessage( FileSynchronize
* msg
) {
660 ///@todo merge synchronizations from different clients when self was crashed
661 /*if ( !m_text->state().isZero() ) {
662 err() << "got synchronization although timestamp already is" << m_text->state().print();
665 out( Logger::Debug
) << "got synchronization - current Timestamp:" << m_text
->state().print() << "new:" << msg
->state().print();
668 m_text
= msg
->createDynamicText();
669 connect( m_text
.data(), SIGNAL( stateChanged( QDynamicText
& ) ), this, SLOT( stateChanged() ) );
671 globalMessageSendHelper().sendReply
<KDevSystemMessage
>( msg
, KDevSystemMessage::ActionSuccessful
);
672 } catch ( const DynamicTextError
& error
) {
673 err() << "error while synchronization:" << error
.what();
674 globalMessageSendHelper().sendReply
<KDevSystemMessage
>( msg
, KDevSystemMessage::ActionFailed
);
680 bool DocumentWrapper::dead() const {
684 bool DocumentWrapper::disabled() const {
688 void DocumentWrapper::setDisabled( bool disabled
) {
689 m_disabled
= disabled
;
692 void DocumentWrapper::setDead( bool dead
) {
696 void DocumentWrapper::readFile( bool fromBuffer
) throw ( QString
) {
697 KUrl u
= TeamworkFolderManager::workspaceAbsolute( m_fileName
);
699 if ( !m_text
->state().isZero() ) {
700 out( Logger::Warning
) << "readFile called although state already is" << m_text
->state().print();
706 IDocument
* doc
= KDevTeamworkPlugin::staticDocumentController() ->documentForUrl( u
);
707 if ( doc
&& doc
->textDocument() ) {
708 txt
= doc
->textDocument() ->text();
712 if ( txt
.isEmpty() ) {
713 if ( !u
.isLocalFile() )
714 throw QString( "file is not local" );
715 if ( !QFileInfo( u
.toLocalFile() ).exists() )
716 throw QString( "file does not exist" );
718 QFile
f( u
.toLocalFile() );
719 if ( !f
.open( QIODevice::ReadOnly
) )
720 throw QString( "could not open file" );
722 ///@todo What about encoding etc. ?
723 QByteArray b
= f
.readAll();
725 m_text
= new QDynamicText( VectorTimestamp( m_ownIndex
, VectorTimestamp() ), b
.data() );
727 m_text
= new QDynamicText( VectorTimestamp( m_ownIndex
, VectorTimestamp() ), txt
.toUtf8().data() );
729 /*m_text->changeState();
730 m_text->insert( m_ownIndex, SimpleReplacement( 0, b.data(), m_text->text() ) );*/
733 #include "documentwrapper.moc"
735 // kate: space-indent on; indent-width 2; tab-width 2; replace-tabs on