#ifndef _EDITWING_IP_DOC_H_ #define _EDITWING_IP_DOC_H_ #include "ewDoc.h" using namespace ki; #ifndef __ccdoc__ namespace editwing { namespace doc { #endif //@{ @pkg editwing.Doc.Impl //@} class Parser; //========================================================================= //@{ // 行バッファ構造体 // // UCS-2ベタの形式でテキストデータを保持する。またそれと同時に、 // キーワードファイルによって指定された強調語を区別するための // 解析処理結果用バッファも管理する。文字データに終端NULは // 付けないが、解析作業の高速化のため、終端 U+007f が入る。 //@} //========================================================================= class Line : public Object { public: //@{ 指定テキストで初期化 //@} Line( const unicode* str, ulong len ) : alen_( 10>len ? 10 : len ) , len_ ( len ) , str_ ( static_cast( mem().Alloc((alen_+1)*2+alen_) ) ) , flg_ ( reinterpret_cast(str_+alen_+1) ) , commentBitReady_( false ) , isLineHeadCommented_( 0 ) { memmove( str_, str, len*2 ); str_[ len ] = 0x007f; } ~Line() { mem().DeAlloc( str_, (alen_+1)*2+alen_ ); } //@{ テキスト挿入(指定位置に指定サイズ) //@} void InsertAt( ulong at, const unicode* buf, ulong siz ) { if( len_+siz > alen_ ) { // バッファ拡張 ulong psiz = (alen_+1)*2+alen_; alen_ = Max( alen_<<1, len_+siz ); unicode* tmpS = static_cast( mem().Alloc((alen_+1)*2+alen_) ); uchar* tmpF = reinterpret_cast(tmpS+alen_+1); // コピー memmove( tmpS, str_, at*2 ); memmove( tmpS+at+siz, str_+at, (len_-at+1)*2 ); memmove( tmpF, flg_, at ); // 古いのを削除 mem().DeAlloc( str_, psiz ); str_ = tmpS; flg_ = tmpF; } else { memmove( str_+at+siz, str_+at, (len_-at+1)*2 ); memmove( flg_+at+siz, flg_+at, (len_-at) ); } memmove( str_+at, buf, siz*sizeof(unicode) ); len_ += siz; } //@{ テキスト挿入(末尾に) //@} void InsertToTail( const unicode* buf, ulong siz ) { InsertAt( len_, buf, siz ); } //@{ テキスト削除(指定位置から指定サイズ) //@} void RemoveAt( ulong at, ulong siz ) { memmove( str_+at, str_+at+siz, (len_-siz-at+1)*2 ); memmove( flg_+at, flg_+at+siz, (len_-siz-at) ); len_ -= siz; } //@{ テキスト削除(指定位置から末尾まで) //@} void RemoveToTail( ulong at ) { if( at < len_ ) str_[ len_=at ] = 0x007f; } //@{ バッファにコピー(指定位置から指定サイズ) //@} ulong CopyAt( ulong at, ulong siz, unicode* buf ) { memmove( buf, str_+at, siz*sizeof(unicode) ); return siz; } //@{ バッファにコピー(指定位置から末尾まで) //@} ulong CopyToTail( ulong at, unicode* buf ) { return CopyAt( at, len_-at, buf ); } //@{ 長さ //@} ulong size() const { return len_; } //@{ テキスト //@} unicode* str() { return str_; } //@{ テキスト(const) //@} const unicode* str() const { return str_; } //@{ 解析結果 //@} uchar* flg() { return flg_; } //@{ 解析結果(const) //@} const uchar* flg() const { return flg_; } // ask bool isCmtBitReady() const { return commentBitReady_; } uchar isLineHeadCmt() const { return isLineHeadCommented_; } // for doc uchar TransitCmt( uchar start ) { isLineHeadCommented_ = start; commentBitReady_ = false; return (commentTransition_>>start)&1; } // for parser void SetTransitFlag( uchar flag ) { commentTransition_ = flag; } void CommentBitUpdated() { commentBitReady_ = true; } private: ulong alen_; ulong len_; unicode* str_; uchar* flg_; uchar isLineHeadCommented_; uchar commentTransition_; bool commentBitReady_; }; //========================================================================= //@{ // Unicodeテキスト切り分け君 // // 行単位で処理を行うことが多いので、その行毎に分ける処理を // 切り出した。getLine() するたびに、指定したポインタと整数変数へ // 先頭から順に行のデータを格納して行く。 //@} //========================================================================= class UniReader { public: //@{ 読みとり元バッファを与えて初期化 //@} UniReader( const unicode* str, ulong len, const unicode** ansstr, ulong* anslen ) : ptr_ ( str ) , end_ ( str+len ) , ans_ ( ansstr ) , aln_ ( anslen ) , empty_( false ) {} //@{ 読み終わったかどうかチェック //@} bool isEmpty() { return empty_; } //@{ 一行取得 //@} void getLine() { // 次の改行の位置を取得 const unicode *p=ptr_, *e=end_; for( ; pnext_ != &headTail_); } inline bool UnReDoChain::isModified() const { return (lastOp_ != savedPos_); } #endif // __ccdoc__ //========================================================================= //@{ // Documentクラスの実装部分 //@} //========================================================================= class DocImpl : public Object, EzLockable, Runnable { public: DocImpl( Document& theDoc ); ~DocImpl(); //@{ 操作コマンド実行 //@} void Execute( const Command& cmd ); //@{ キーワード定義切り替え //@} void SetKeyword( const unicode* defbuf, ulong siz ); //@{ イベントハンドラ登録 //@} void AddHandler( DocEvHandler* eh ); //@{ イベントハンドラ解除 //@} void DelHandler( DocEvHandler* eh ); //@{ ファイルを開く //@} void OpenFile( aptr tf ); //@{ ファイルを保存 //@} void SaveFile( TextFileW& tf ); //@{ 内容破棄 //@} void ClearAll(); //@{ アンドゥ //@] void Undo(); //@{ リドゥ //@] void Redo(); //@{ アンドゥ回数制限 //@] void SetUndoLimit( long lim ); //@{ 変更フラグをクリア //@} void ClearModifyFlag(); public: //@{ 行数 //@} ulong tln() const; //@{ 行バッファ //@} const unicode* tl( ulong i ) const; //@{ 行解析結果バッファ //@} const uchar* pl( ulong i ) const; //@{ 行文字数 //@} ulong len( ulong i ) const; //@{ 指定範囲のテキストの長さ //@} ulong getRangeLength( const DPos& stt, const DPos& end ); //@{ 指定範囲のテキスト //@} void getText( unicode* buf, const DPos& stt, const DPos& end ); //@{ 指定位置の単語の先頭を取得 //@} DPos wordStartOf( const DPos& dp ) const; //@{ 指定位置の一つ左の位置を取得 //@} DPos leftOf( const DPos& dp, bool wide=false ) const; //@{ 指定位置の一つ右の位置を取得 //@} DPos rightOf( const DPos& dp, bool wide=false ) const; //@{ アンドゥ可能? //@} bool isUndoAble() const; //@{ リドゥ可能? //@} bool isRedoAble() const; //@{ 変更済み? //@} bool isModified() const; private: Document& doc_; // 自分 aptr parser_; // 文字列解析役 gapbufobj text_; // テキストデータ mutable storage pEvHan_; // イベント通知先 UnReDoChain urdo_; // アンドゥリドゥ aptr currentOpeningFile_; private: // 変更通知 void Fire_KEYWORDCHANGE(); void Fire_MODIFYFLAGCHANGE(); void Fire_TEXTUPDATE( const DPos& s, const DPos& e, const DPos& e2, bool reparsed, bool nmlcmd ); // ヘルパー関数 bool ReParse( ulong s, ulong e ); void SetCommentBit( const Line& x ) const; void CorrectPos( DPos& pos ); void CorrectPos( DPos& stt, DPos& end ); // 挿入・削除作業 bool InsertingOperation( DPos& stt, const unicode* str, ulong len, DPos& undoend ); bool DeletingOperation( DPos& stt, DPos& end, unicode*& undobuf, ulong& undosiz ); // パラレルリード virtual void StartThread(); private: NOCOPY(DocImpl); friend class Insert; friend class Delete; friend class Replace; }; //------------------------------------------------------------------------- inline ulong DocImpl::tln() const { return text_.size(); } inline const unicode* DocImpl::tl( ulong i ) const { return text_[i].str(); } inline ulong DocImpl::len( ulong i ) const { return text_[i].size(); } inline const uchar* DocImpl::pl( ulong i ) const { const Line& x = text_[i]; if( !x.isCmtBitReady() ) SetCommentBit( x ); return x.flg(); } //========================================================================= }} // namespace editwing::doc #endif // _EDITWING_IP_DOC_H_