InDesign SDK Plugin ExtendScriptのテーブルの機能を拡張する

ExtendScriptのテーブルの機能を拡張するPluginは、これで良いのかな・・・？

~~~C++:ExtendTableScriptElement.h
/** 利用する事で起こる如何なる不具合にも責任を持てません。
	2022/09/14 更新
*/
#ifndef __ExtendTableScriptElement_h__
#define __ExtendTableScriptElement_h__

// Interface includes:
#include "IScript.h"
#include "IScriptRequestData.h"
#include "IScriptCellRef.h"
#include "ITableModel.h"
#include "ICellContent.h"
#include "ITableTextContainer.h"
#include "ITextModel.h"
#include "IFrameList.h"
#include "ITextFrameColumn.h"
#include "IMultiColumnTextFrame.h"
#include "IHierarchy.h"
#include "ITextUtils.h"
#include "IGraphicFrameData.h"

// General includes:
#include "CAlert.h"
#include "TableTypes.h" // GridArea, GridAddress

/** スクリプトエレメントを追加する為の手順（メモ）

	０、１、sdk/devtools/dolly/のdollyツールのFeaturesタブのGenerate Script Supportをチェックしてプロジェクトを作成（JAVAが必要）
		
		２、sdk/build/win/prj/のSDKSamples.slnをVisual Studio Commmunityを開く
		
		３、ソリューションに先ほど作成したプロジェクトを（既存のプロジェクトから）追加する。
		
		４、プロジェクトを開く

		５、このファイルを○○○ID.hのあるフォルダーに保存。（○○○はshort name）

		６、このファイルをプロジェクトに追加

	１、Resource Files/○○○.frの変更

		１、#include "TablesID.h" // kCellObjectScriptElement
			#include "TextScriptID.h" // kTextFrameObjectScriptElement
			を追加

		２、VersionedScriptElementInfoを変更、もしくは追加

			例
			resource VersionedScriptElementInfo(1) // 数値を重複させない事
			{
				// Contexts
				{
					kFiredrakeScriptVersion, kCoreScriptManagerBoss, kInDesignAllLanguagesFS, k_Wild,
					kFiredrakeScriptVersion, kCoreScriptManagerBoss, kInCopyAllLanguagesFS, k_Wild,
				}
	
				// Elements
				{
					Property
					{
						k○○○PropertyScriptElementCellParentTextFrame, // スクリプトエレメントID ○○○ID.h（HeaderFilesにあり）で設定
						p_CellParentTextFrame, // ScriptID ○○○ScriptingDefs.h（外部依存関係にあり）で設定
						"cell parent text frame", // ExtendScriptでの名前 「kohakuNekotarou」としたいなら「kohaku nekotarou」と入力
						"セルの親テキストフレーム", // description
						ObjectType( kTextFrameObjectScriptElement ), // プロパティのデータ型
						{} // alternate types
						kNoAttributeClass, // attribute class ID
					}

					// このプラグインのメソッドとプロパティをスクリプトに接続します。
					Provider
					{
						k○○○ScriptProviderBoss,	// provider boss ID
						{
							// 追加される側のオブジェクト
							Object{ kCellObjectScriptElement },

							// 追加するプロパティ スクリプトエレメントIDで指定
							// 
							// kReadOnly
							// 読み込み専用
							Property{ k○○○PropertyScriptElementCellParentTextFrame, kReadOnly },
						}
					}
				}
			};

	２、Heade Files/○○○ID.hのScript Element IDsを変更、もしくは追加
		例
		//Script Element IDs
		DECLARE_PMID(kScriptInfoIDSpace, k○○○PropertyScriptElementCellParentTextFrame, k○○○Prefix + 1)

	３、外部依存関係/○○○ScriptingDefs.hのScript Element IDを変更、もしくは追加（ScriptingDefs.hの値と重複しない様に）

		例
		// Property IDs
		enum ○○○ScriptProperties
		{
			// ,を忘れない事
			p_CellParentTextFrame = 'pCpt',
		};

	４、Source Files/○○○ScriptProvider.cppの変更
	
		１、#include "ExtendTableScriptElement.h"
			を追加

		２、AccessPropertyのcase部分を変更、もしくは追加
	
			例
			case p_CellParentTextFrame:
				status = ExtendTableScriptElement::CellParentTextFrame(propID, data, parent);
				break;

	５、Releaseビルド

	６、ExtendScriptで使う

		例
		// テーブルの最後のセルがあるテキストフレームを選択
		app.activeDocument.stories.firstItem().tables.firstItem().cells.lastItem().cellParentTextFrame.select();

*/
class ExtendTableScriptElement
{
public:
	/** セルの親テキストフレーム
		@param scriptID 処理するプロパティのIDを識別します。
		@param scriptRequestData スクリプト要求との間でデータをやり取りするために使用されます。。
		@param script スクリプトアーキテクチャのオブジェクトとして表示し、すべてのスクリプトクライアントで使用できるようにしたい上司に追加されます。
	*/
	 static ErrorCode CellParentTextFrame(ScriptID scriptID, IScriptRequestData* scriptRequestData, IScript* script);
};

ErrorCode ExtendTableScriptElement::CellParentTextFrame(ScriptID scriptID, IScriptRequestData* scriptRequestData, IScript* script)
{
	// virtual bool16 IScriptRequestData::IsPropertyGet() const
	// この要求がプロパティを取得する場合は kTrue を返します。
	if (scriptRequestData->IsPropertyGet())
	{
		// エラーの場合にbreakする為
		do {
			// InterfacePtr
			// インターフェイスポインターの操作を簡略化するスマートポインタークラス
			// 
			// IScriptCellRef
			// テーブル領域を記述します。
			InterfacePtr<IScriptCellRef> scriptCellRef(script, UseDefaultIID());

			// kFailure が返された場合は、アサートを取得します。
			ASSERT(scriptCellRef);
			if (scriptCellRef == nil)
			{
				break;
			}

			// ITableModel
			// テーブルモデルを公開するパブリック インターフェイス。
			//
			// virtual ITableModel* IScriptCellRef::QueryModel() const
			// このセルオブジェクトが存在するテーブルを照会する
			InterfacePtr<ITableModel> tableModel(scriptCellRef->QueryModel());
			ASSERT(tableModel);
			if (tableModel == nil)
			{
				break;
			}

			// GridArea
			// テーブルモデル内のグリッド要素の四角形を表します。
			GridArea gridarea;

			// virtual ErrorCode IScriptCellRef::GetRange(const GridArea& area)
			// このセルオブジェクトが表すセルの範囲を取得する
			scriptCellRef->GetRange(gridarea);
			if (gridarea.IsEmpty())
			{
				break;
			}

			// GridAddress
			// テーブル モデルの基になるグリッド内の要素の行と列。
			const GridAddress gridAddress(gridarea.topRow, gridarea.leftCol);

			// ICellContent
			// 不透明なラッパー内のセルの内容へのアクセスを提供します。
			//
			// virtual ICellContent* ITableModel::QueryCellContentBoss(const GridAddress& anchor) const
			// ContentBossAccessor を使用して、セルの範囲にアクセスします。
			InterfacePtr<ICellContent> cellContent(tableModel->QueryCellContentBoss(gridAddress));
			ASSERT(cellContent);
			if (cellContent == nil)
			{
				break;
			}

			// virtual ParcelKey GetNthParcelKey(int32 n) const
			ParcelKey parcelKey = cellContent->GetNthParcelKey(0);

			// virtual UID GetParcelFrameUID(ParcelKey key) const
			UID uID_TextFrameColumn = cellContent->GetParcelFrameUID(parcelKey);

			// ITableTextContainer
			// テーブルモデルとテキストモデルの間の関係を照会および操作するためのインタフェース。
			InterfacePtr<ITableTextContainer> tableTextContainer(tableModel, UseDefaultIID());
			ASSERT(tableTextContainer);
			if (tableTextContainer == nil)
			{
				break;
			}

			// ITextModel
			// テキストストーリーのメインインターフェイスです。
			//
			// virtual ITextModel* ITableTextContainer::QueryTextModel() const
			// 参照インクリメントされたインタフェースptrからテキストモデルを取得する。
			InterfacePtr<ITextModel> textModel(tableTextContainer->QueryTextModel());
			ASSERT(textModel);
			if (textModel == nil)
			{
				break;
			}

			// IFrameList
			// ITextModel のフレーム（Column）のリスト
			InterfacePtr<IFrameList> frameList(textModel->QueryFrameList());
			ASSERT(frameList);
			if (frameList == nil)
			{
				break;
			}

			// virtual int32 IFrameList::GetFrameIndex(UID frameUID) const
			// UID で指定された ITextFrameColumn の IFrameList に認識されている ITextFrame の既知のセット内のインデックスを取得します。
			int32 frameColumnIndex = frameList->GetFrameIndex(uID_TextFrameColumn);

			// ITextFrameColumn
			// テキストフレームのColumn
			//
			// virtual ITextFrameColumn* IFrameList::QueryNthFrame(int32 n)	const
			// IFrameList が保持するリスト内の特定の ITextFrameColumn にアクセスします。
			InterfacePtr<ITextFrameColumn> textFrameColumn(frameList->QueryNthFrame(frameColumnIndex));
			ASSERT(textFrameColumn);
			if (textFrameColumn == nil)
			{
				break;
			}

			// IMultiColumnTextFrame
			// 複数 Column テキストフレーム
			//
			// virtual IMultiColumnTextFrame* ITextFrameColumn::QueryMultiColumnTextFrame()	const
			// 親の複数列テキストフレームへのポイントを返します。
			InterfacePtr<IMultiColumnTextFrame> multiColumnFrame(textFrameColumn->QueryMultiColumnTextFrame());
			ASSERT(multiColumnFrame);
			if (multiColumnFrame == nil)
			{
				break;
			}

			// IHierarchy
			// 永続的なUIDベースのツリー構造が格納されます。
			//
			// ITextUtils
			// テキスト関連のコマンドを作成し、テキスト情報を収集するためのユーティリティー関数。
			//
			// virtual IHierarchy* ITextUtils::QuerySplineFromTextFrame(const IMultiColumnTextFrame* mcf) const
			// IMultiColumnTextFrames を指定すると、それに関連付けられたスプラインを返します。
			InterfacePtr<IHierarchy> hierarchy(Utils<ITextUtils>()->QuerySplineFromTextFrame(multiColumnFrame));
			ASSERT(hierarchy);
			if (hierarchy == nil)
			{
				break;
			}

			// IGraphicFrameData
			// アイテムがフレームと見なされるかどうかを示す、すべてのスプラインページアイテムのインターフェイス。
			InterfacePtr<IGraphicFrameData> graphicFrameData(hierarchy, UseDefaultIID());
			ASSERT(graphicFrameData);
			if (graphicFrameData == nil)
			{
				break;
			}
	
			InterfacePtr<IScript> script_Return(graphicFrameData, UseDefaultIID());
			ASSERT(script_Return);
			if (script_Return == nil)
			{
				break;
			}

			// ScriptData
			// スクリプトアーキテクチャでサポートされている任意のデータ型を保持できるクラスです。
			// 
			// ScriptData (IScript *object)
			// コンストラクタ
			ScriptData scriptData(script_Return);

			// virtual void AppendReturnData(const IScript* target, const ScriptID requestID, const ScriptData& returnValue)
			// 特定のターゲットの戻り値データの1つの項目を追加します。
			scriptRequestData->AppendReturnData(script, scriptID, scriptData);

			// kSuccessが返らないとスクリプトエラーが出るので注意
			return kSuccess;
		} while (false);
	}
	return kFailure;
}

#endif // __ExtendTableScriptElement_h__
~~~