/*! 指定行のドット位置(キャレット位置)に文字列を追加する・こっちが下位函数 @param[in] pNowDot 今のキャレットのドット位置のポインター @param[in] pdLine 対象の行番号・絶対0インデックスか @param[in] ptStr 追加したい文字列 @param[in] cchSize 文字列の文字数・ヌルターミネータ含まず @return INT 0改行無し 1〜改行した回数 */ INT DocStringAdd( PINT pNowDot, PINT pdLine, LPCTSTR ptStr, INT cchSize ) { INT i, insDot, dLn, dCrLf; assert( ptStr ); dCrLf = 0; dLn = *pdLine; insDot = *pNowDot; #ifdef DO_TRY_CATCH try{ #endif for( i = 0; cchSize > i; i++ ) { if( CC_CR == ptStr[i] && CC_LF == ptStr[i+1] ) // 改行であったら { DocInputReturn( insDot, *pdLine ); i++; // 0x0D,0x0Aだから、壱文字飛ばすのがポイント (*pdLine)++; // 改行したからFocusは次の行へ insDot = 0; // そして行の先頭である dCrLf++; // 改行した回数カウント } else if( CC_TAB == ptStr[i] ) { // タブは挿入しない } else { insDot += DocInputLetter( insDot, *pdLine, ptStr[i] ); } } #ifdef DO_TRY_CATCH } catch( exception &err ){ return (INT)ETC_MSG( err.what(), 0 ); } catch( ... ){ return (INT)ETC_MSG( ("etc error"), 0 ); } #endif #ifdef DO_TRY_CATCH try{ #endif // ここで空白チェキ・開始行から終了行までブンブンする for( i = dLn; *pdLine >= i; i++ ) { DocBadSpaceCheck( i ); } #ifdef DO_TRY_CATCH } catch( exception &err ){ return (INT)ETC_MSG( err.what(), 0 ); } catch( ... ){ return (INT)ETC_MSG( ("etc error"), 0 ); } #endif // アンドゥリドゥはここではなく呼んだほうで面倒見るほうがいい *pNowDot = insDot; return dCrLf; }
/*! ページを変更・ファイルコア函数 @param[in] dPageNum 変更したい頁番号 @return HRESULT 終了状態コード */ HRESULT DocPageChange( INT dPageNum ) { INT iPrePage; // 今の表示内容破棄とかいろいろある #ifdef DO_TRY_CATCH try{ #endif ViewSelPageAll( -1 ); // 範囲選択を破棄 iPrePage = gixFocusPage; gixFocusPage = dPageNum; // 先に変更して (*gitFileIt).dNowPage = dPageNum; // 記録 // まだ展開されてないなら DocDelayPageLoad( gitFileIt, dPageNum ); PageListViewChange( dPageNum, iPrePage ); #ifdef DO_TRY_CATCH } catch( exception &err ){ return (HRESULT)ETC_MSG( err.what(), E_UNEXPECTED ); } catch( ... ){ return (HRESULT)ETC_MSG( ("etc error") , E_UNEXPECTED ); } #endif return S_OK; }
/*! 頁を削除・ファイルコア函数 @param[in] iPage 削除する頁の番号 @param[in] iBack −1無視 0〜削除したあと移動する頁指定 @return HRESULT 終了状態コード */ HRESULT DocPageDelete( INT iPage, INT iBack ) { INT i, iNew; PAGE_ITR itPage; if( 1 >= DocNowFilePageCount( ) ) return E_ACCESSDENIED; #ifdef DO_TRY_CATCH try{ #endif // ここでバックアップを? // 街頭位置までイテレータをもっていく itPage = (*gitFileIt).vcCont.begin( ); for( i = 0; iPage > i; i++ ){ itPage++; } FREE( itPage->ptRawData ); SqnFreeAll( &(itPage->stUndoLog) ); // アンドゥログ削除 (*gitFileIt).vcCont.erase( itPage ); // さっくり削除 gixFocusPage = -1; // 頁選択無効にする PageListDelete( iPage ); if( 0 <= iBack ) // 戻り先指定 { iNew = iBack; } else { iNew = iPage - 1; // 削除したら一つ前の頁へ if( 0 > iNew ) iNew = 0; } DocPageChange( iNew ); // 削除したら頁移動 #ifdef DO_TRY_CATCH } catch( exception &err ){ return ETC_MSG( err.what(), E_FAIL ); } catch( ... ){ return ETC_MSG( ("etc error"), E_FAIL ); } #endif return S_OK; }
/*! 新しいファイル置き場を作ってフォーカスする・ファイルコア函数 @param[in] ptDmyName ダミー名を返す。NULL可。MAX_PATHであること @return LPARAM 対応するユニーク番号 */ LPARAM DocMultiFileCreate( LPTSTR ptDmyName ) { ONEFILE stFile; FILES_ITR itNew; #ifdef DO_TRY_CATCH try{ #endif ZeroMemory( stFile.atFileName, sizeof(stFile.atFileName) ); stFile.dModify = FALSE; stFile.dNowPage = 0; stFile.dUnique = gdNextNumber++; stFile.stCaret.x = 0; stFile.stCaret.y = 0; ZeroMemory( stFile.atDummyName, sizeof(stFile.atDummyName) ); StringCchPrintf( stFile.atDummyName, MAX_PATH, TEXT("%s%d.%s"), NAME_DUMMY_NAME, stFile.dUnique, NAME_DUMMY_EXT ); if( ptDmyName ){ StringCchCopy( ptDmyName, MAX_PATH, stFile.atDummyName ); } stFile.vcCont.clear( ); gltMultiFiles.push_back( stFile ); // 新規作成の準備 gixFocusPage = -1; PageListClear( ); // ページリストビューも破棄 itNew = gltMultiFiles.end( ); itNew--; // 末端に追加したからこれでおk gitFileIt = itNew; // ファイルなう #ifdef DO_TRY_CATCH } catch( exception &err ){ return ETC_MSG( err.what(), 0 ); } catch( ... ){ return ETC_MSG( ("etc error"), 0 ); } #endif return stFile.dUnique; }
/*! ページ全体を文字列で確保する・freeは呼んだ方でやる @param[in] itFile 確保するファイル @param[in] dPage 確保する頁番号 @param[in] bStyle 1ユニコードかシフトJISで、矩形かどうか @param[out] pText 確保した領域を返す・ワイド文字かマルチ文字になる・NULLだと必要バイト数を返すのみ @param[in] bCrLf 末端に改行付けるか @return 確保したバイト数・NULLターミネータ含む */ INT DocPageTextGetAlloc( FILES_ITR itFile, INT dPage, UINT bStyle, LPVOID *pText, BOOLEAN bCrLf ) { UINT_PTR iLines, iLetters, j, iSize; UINT_PTR i; UINT_PTR cchSize; LPSTR pcStr; string srString; wstring wsString; LINE_ITR itLines; #ifdef DO_TRY_CATCH try{ #endif srString.clear( ); wsString.clear( ); // デフォ的な if( 0 > dPage ){ dPage = gixFocusPage; } if( itFile->vcCont.at( dPage ).ptRawData ) // 生データ状態なら { if( bStyle & D_UNI ) // ユニコードである { wsString = wstring( itFile->vcCont.at( dPage ).ptRawData ); if( bCrLf ){ wsString += wstring( CH_CRLFW ); } } else // ShiftJISである { pcStr = SjisEncodeAlloc( itFile->vcCont.at( dPage ).ptRawData ); // ページ全体を文字列で確保 if( pcStr ) { srString = string( pcStr ); if( bCrLf ){ srString += string( CH_CRLFA ); } FREE( pcStr ); } } } else // ロード済みなら { // 全文字を頂く iLines = itFile->vcCont.at( dPage ).ltPage.size( ); for( itLines = itFile->vcCont.at( dPage ).ltPage.begin(), i = 0; itLines != itFile->vcCont.at( dPage ).ltPage.end(); itLines++, i++ ) { iLetters = itLines->vcLine.size( ); for( j = 0; iLetters > j; j++ ) { srString += string( itLines->vcLine.at( j ).acSjis ); wsString += itLines->vcLine.at( j ).cchMozi; } if( !(1 == iLines && 0 == iLetters) ) // 壱行かつ零文字は空である { if( iLines > (i+1) ) // とりあえずファイル末端改行はここでは付けない { srString += string( CH_CRLFA ); wsString += wstring( CH_CRLFW ); } } } if( bCrLf ) { srString += string( CH_CRLFA ); wsString += wstring( CH_CRLFW ); } } if( bStyle & D_UNI ) { cchSize = wsString.size( ) + 1; // NULLターミネータ iSize = cchSize * sizeof(TCHAR); // ユニコードなのでバイト数は2倍である if( pText ) { *pText = (LPTSTR)malloc( iSize ); ZeroMemory( *pText, iSize ); StringCchCopy( (LPTSTR)(*pText), cchSize, wsString.c_str( ) ); } } else { iSize = srString.size( ) + 1; // NULLターミネータ if( pText ) { *pText = (LPSTR)malloc( iSize ); ZeroMemory( *pText, iSize ); StringCchCopyA( (LPSTR)(*pText), iSize, srString.c_str( ) ); } } #ifdef DO_TRY_CATCH } catch( exception &err ){ return (INT)ETC_MSG( err.what(), 0 ); } catch( ... ){ return (INT)ETC_MSG( ("etc error") , 0 ); } #endif return (INT)iSize; }
/*! ページ追加処理・ファイルコア函数 @param[in] iAdding この指定ページの次に追加・-1で末端に追加 @return INT 新規作成したページ番号 */ INT DocPageCreate( INT iAdding ) { INT_PTR iTotal, iNext; UINT_PTR iAddPage = 0; INT i; ONELINE stLine; ONEPAGE stPage; PAGE_ITR itPage; #ifdef DO_TRY_CATCH try{ #endif ZeroONELINE( &stLine ); // 新規作成したら、壱行目が0文字な枠を作る // こっちもZeroONEPAGEとかにまとめるか ZeroMemory( stPage.atPageName, sizeof(stPage.atPageName) ); // stPage.dDotCnt = 0; stPage.dByteSz = 0; stPage.ltPage.clear( ); stPage.ltPage.push_back( stLine ); // 1頁の枠を作って stPage.dSelLineTop = -1; // 無効は−1を注意 stPage.dSelLineBottom = -1; // stPage.ptRawData = NULL; SqnInitialise( &(stPage.stUndoLog) ); // 今の頁の次に作成 iTotal = DocNowFilePageCount( ); if( 0 <= iAdding ) { iNext = iAdding + 1; // 次の頁 if( iTotal <= iNext ){ iNext = -1; } // 全頁より多いなら末端指定 } else { iNext = -1; } if( 0 > iNext ) // 末尾に追加 { (*gitFileIt).vcCont.push_back( stPage ); // ファイル構造体に追加 iAddPage = DocNowFilePageCount( ); iAddPage--; // 末端に追加したんだから、個数数えて−1したら0インデックス番号 } else { itPage = (*gitFileIt).vcCont.begin( ); for( i = 0; iNext > i; i++ ){ itPage++; } (*gitFileIt).vcCont.insert( itPage, stPage ); iAddPage = iNext; } #ifdef DO_TRY_CATCH } catch( exception &err ){ return ETC_MSG( err.what(), 0 ); } catch( ... ){ return ETC_MSG( ("etc error"), 0 ); } #endif return iAddPage; // 追加したページ番号 }
/*! 指定行のドット位置(キャレット位置)に壱文字追加する・この函数内ではアンドゥの面倒は見ない @param[in] nowDot 挿入するドット位置 @param[in] rdLine 対象の行番号・絶対0インデックスか @param[in] ch 追加したい文字 @return INT 追加した文字のドット数 */ INT DocInputLetter( INT nowDot, INT rdLine, TCHAR ch ) { INT_PTR iLetter, iCount, iLines; LETTER stLetter; LETR_ITR vcItr; LINE_ITR itLine; // アンドゥリドゥは呼んだところで #ifdef DO_TRY_CATCH try{ #endif if( 0 == ch ) { TRACE( TEXT("NULL文字が入った") ); return 0; } iLines = DocNowFilePageLineCount( ); if( iLines <= rdLine ) { TRACE( TEXT("OutOfRange 指定[%d] 行数[%d]"), rdLine, iLines ); return 0; } iLetter = DocLetterPosGetAdjust( &nowDot, rdLine, 0 ); // 今の文字位置を確認 itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); std::advance( itLine, rdLine ); // 対象行までイテレートする // 文字数確認 iCount = itLine->vcLine.size( ); // データ作成 DocLetterDataCheck( &stLetter, ch ); // 指定行のドット位置(キャレット位置)に壱文字追加するとき if( iLetter >= iCount ) // 文字数同じなら末端に追加ということ { itLine->vcLine.push_back( stLetter ); } else // そうでないなら途中に追加 { vcItr = itLine->vcLine.begin( ); vcItr += iLetter; itLine->vcLine.insert( vcItr, stLetter ); } itLine->iDotCnt += stLetter.rdWidth; itLine->iByteSz += stLetter.mzByte; (*gitFileIt).vcCont.at( gixFocusPage ).dByteSz += stLetter.mzByte; // DocBadSpaceCheck( rdLine ); 呼んだところでまとめてやる #ifdef DO_TRY_CATCH } catch( exception &err ){ return ETC_MSG( err.what(), 0 ); } catch( ... ){ return ETC_MSG( ("etc error"), 0 ); } #endif return stLetter.rdWidth; }
/*! 指定行のドット位置(キャレット位置)で改行する @param[in] nowDot 今のキャレットのドット位置 @param[in] rdLine 対象の行番号・絶対0インデックスか @return HRESULT 終了状態コード */ HRESULT DocInputReturn( INT nowDot, INT rdLine ) { INT_PTR iLetter, iLines, iCount; ONELINE stLine; LETR_ITR vcLtrItr, vcLtrEnd; LINE_ITR itLine, ltLineItr; #ifdef DO_TRY_CATCH try{ #endif iLines = DocNowFilePageLineCount( ); if( iLines <= rdLine ) return E_OUTOFMEMORY; ZeroONELINE( &stLine ); iLetter = DocLetterPosGetAdjust( &nowDot, rdLine, 0 ); // 今の文字位置を確認 // 文字数確認 itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); std::advance( itLine, rdLine ); iCount = itLine->vcLine.size( ); if( iLetter < iCount ) // もし行の途中で改行したら? { ltLineItr = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin( ); std::advance( ltLineItr, (rdLine+1) ); // 今の行の次の場所に行のデータを挿入 (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.insert( ltLineItr, stLine ); // その行の、文字データの先頭をとる ltLineItr = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin( ); std::advance( ltLineItr, (rdLine+1) ); // 追加した行まで移動 // ぶった切った場所を設定しなおして itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); std::advance( itLine, rdLine ); vcLtrItr = itLine->vcLine.begin( ); vcLtrItr += iLetter; // 今の文字位置を示した vcLtrEnd = itLine->vcLine.end( ); // 末端 // その部分を次の行にコピーする std::copy( vcLtrItr, vcLtrEnd, back_inserter(ltLineItr->vcLine) ); // 元の文字列を削除する itLine->vcLine.erase( vcLtrItr, vcLtrEnd ); // 総ドット数再計算 DocLineParamGet( rdLine, NULL, NULL ); DocLineParamGet( rdLine+1, NULL, NULL ); } else // 末端で改行した { if( (iLines - 1) == rdLine ) // EOF的なところ { (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.push_back( stLine ); } else { ltLineItr = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin( ); std::advance( ltLineItr, (rdLine+1) ); // 今の行を示した // 次の場所に行のデータを挿入 (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.insert( ltLineItr, stLine ); } } DocBadSpaceCheck( rdLine ); // ここで空白チェキ DocBadSpaceCheck( rdLine+1 ); // 空白チェキ・次の行も確認 #ifdef DO_TRY_CATCH } catch( exception &err ){ return (HRESULT)ETC_MSG( err.what(), E_UNEXPECTED ); } catch( ... ){ return (HRESULT)ETC_MSG( ("etc error") , E_UNEXPECTED ); } #endif return S_OK; }
/*! 選択されているところを全削除しちゃう @param[in] pdDot キャレットドット位置・書き換える必要がある @param[in] pdLine 行番号・書き換える必要がある @param[in] bSqSel 矩形選択してるのかどうか・D_SQUARE @param[in] bFirst アンドゥ用・これが最初のアクションか @return 非0改行あった 0壱行のみ */ INT DocSelectedDelete( PINT pdDot, PINT pdLine, UINT bSqSel, BOOLEAN bFirst ) { // UINT_PTR iLines; UINT_PTR iMozis; INT i, j, dBeginX = 0, dBeginY = 0, cbSize; INT iLct, k, bCrLf; LPTSTR ptText; LPPOINT pstPt; LETR_ITR itLtr, itEnd, itHead, itTail; LINE_ITR itLine; #ifdef DO_TRY_CATCH try{ #endif bSqSel &= D_SQUARE; // 矩形ビットだけ残す // ページ全体の行数 // iLines = DocNowFilePageLineCount( ); i = (*gitFileIt).vcCont.at( gixFocusPage ).dSelLineTop; j = (*gitFileIt).vcCont.at( gixFocusPage ).dSelLineBottom; TRACE( TEXT("範囲削除[T%d - B%d]"), i, j ); if( 0 > i ){ return 0; } // 選択範囲が無かった //アンドゥバッファリングの準備 iLct = j - i + 1; // 含まれる行なので、数えるの注意 cbSize = DocSelectTextGetAlloc( D_UNI | bSqSel, (LPVOID *)(&ptText), NULL ); pstPt = (LPPOINT)malloc( iLct * sizeof(POINT) ); ZeroMemory( pstPt, iLct * sizeof(POINT) ); k = iLct - 1; bCrLf = iLct - 1; dBeginY = i; // 選択肢のある行 itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); std::advance( itLine, j ); for( ; i <= j; j--, k--, itLine-- )//beginを超えたらアウツ! { // continueは使えない・ iMozis = itLine->vcLine.size( ); if( 0 < iMozis ) { itLtr = itLine->vcLine.begin( ); itEnd = itLine->vcLine.end( ); itHead = itEnd; itTail = itEnd; dBeginX = 0; // 最初の選択部分を検索 for( ; itLtr != itEnd; itLtr++ ) { if( CT_SELECT & itLtr->mzStyle ) { itHead = itLtr; break; } dBeginX += itLtr->rdWidth; // 意味があるのは最後のところなので、常時上書きでおk } // 選択されてない所まで検索 for( ; itLtr != itEnd; itLtr++ ) { if( !(CT_SELECT & itLtr->mzStyle) ) { itTail = itLtr; break; } } } pstPt[k].x = dBeginX; pstPt[k].y = j; if( 0 < iMozis ) { // 該当範囲を削除・末端は、該当部分の直前までが対象・末端自体は非対象 itLine->vcLine.erase( itHead, itTail ); } // 改行が含まれていたら if( CT_SELRTN & itLine->dStyle ){ DocLineCombine( j ); } DocLineParamGet( j, NULL, NULL ); // バイト数再計算 // 矩形の場合は、各行毎に面倒みないかん if( D_SQUARE & bSqSel ){ DocBadSpaceCheck( j ); } // 改行サクるとこれによりatが無効になる? // iLines = DocNowFilePageLineCount( ); // ページ全体の行数再設定? if( (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin() == itLine ) break; // 位置的に末端だったらループせずに終わる } ViewSelPageAll( -1 ); // 選択範囲無くなる // カーソル位置移動せないかん *pdDot = dBeginX; *pdLine = dBeginY; // 最終的に残っている行のチェックだけすればいい if( !(D_SQUARE & bSqSel) ){ DocBadSpaceCheck( dBeginY ); } if( bSqSel ){ SqnAppendSquare( &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog), DO_DELETE, ptText, pstPt, iLct , bFirst ); } else{ SqnAppendString( &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog), DO_DELETE, ptText, dBeginX, dBeginY, bFirst ); } FREE( ptText ); FREE( pstPt ); #ifdef DO_TRY_CATCH } catch( exception &err ){ return (INT)ETC_MSG( err.what(), 0 ); } catch( ... ){ return (INT)ETC_MSG( ("etc error"), 0 ); } #endif return bCrLf; }