IllustratorとSQLとCS SDKと

Creative Suite SDKを利用しはじめて変わった事。
1.ExtendScriptの遅さに辟易しはじめた。
2.幾つかのExternalObjectプロジェクトが廃止の憂き目にあった。
3.テストの為に繁茂にCSアプリケーションを再起動するようになった。
4.多少のコードの不味さが気にならなくなった。適当なコードでもそこそこ高速に動作しますし、メモリのマネジメントもExtendScriptよりは安定しているようですので手抜きしまくりな訳です。
特に2はMySQLコネクタやローレベルのソケット接続等が完全に停止しました。MySQL使いたければフロントエンドにrailsやPHP使った方が効率良いような気がしますしね。
と言う訳なのですが、ローカルで使う分にはSQLiteが取り回しがラクチンで良いようです。
今回はそのSQLiteとIllustratorで何かしてみましょう。

<?xml version=”1.0″ encoding=”utf-8″?>
<mx:WindowedApplication xmlns:mx=”http://www.adobe.com/2006/mxml&#8221; layout=”vertical”>
    <mx:Script>
        <![CDATA[
            import mx.events.DataGridEventReason;
            import mx.events.DataGridEvent;
            import mx.events.ItemClickEvent;
            import mx.collections.ArrayCollection;
            import flash.data.SQLResult;
            import flash.data.SQLStatement;
            import flash.filesystem.File;
            import flash.data.SQLConnection;
            import mx.events.FlexEvent;
            import com.adobe.csawlib.illustrator.Illustrator;
            import com.adobe.illustrator.*;

            private var conn:SQLConnection;
            private var stm:SQLStatement;

            [Bindable] private var dp:ArrayCollection = new ArrayCollection();

            private function readDB():void
            {
                message.text += “Start processing…\n”;
                var tgDB:File = File.desktopDirectory.resolvePath(DBName.text + “.db”);
                conn = new SQLConnection();
                conn.addEventListener(SQLEvent.OPEN, connOpen);
                conn.addEventListener(SQLErrorEvent.ERROR, connErr);
                conn.open(tgDB);
            }

            private function connOpen(event:SQLEvent):void
            {
                stm = new SQLStatement();
                stm.sqlConnection = conn;
                stm.text = “CREATE TABLE IF NOT EXISTS ” + DBName.text + ” (“+
                    ” no INTEGER PRIMARY KEY NOT NULL,”+
                    ” Title TEXT,”+
                    ” mail TEXT,”+
                    ” cell TEXT,”+
                    ” psName TEXT”+”)”;
                stm.addEventListener(SQLEvent.RESULT, stmCreRslt);
                stm.addEventListener(SQLErrorEvent.ERROR,stmErr);
                stm.execute();
            }

            private function stmCreRslt(event:SQLEvent):void
            {
                message.text += “Connect database…\n”;
                getData();
            }

            private function getData():void
            {
                stm = new SQLStatement();
                stm.sqlConnection =  conn;
                stm.text = “SELECT no, psName, mail, Title, cell FROM ” + DBName.text;
                stm.addEventListener(SQLEvent.RESULT, getDatRslt);
                stm.addEventListener(SQLErrorEvent.ERROR, stmErr);
                stm.execute();
            }

            private function getDatRslt(event:SQLEvent):void
            {
                message.text += “update DataGrid.\n”;
                var result:SQLResult = stm.getResult();
                if (result.data==null) return;
                dp = new ArrayCollection(result.data);
            }

            private function insBtnClick(event:Event):void
            {
                stm = new SQLStatement();
                stm.sqlConnection = conn;
                stm.text = “INSERT INTO ” + DBName.text + ” (no, psName, mail, Title, cell)”
                    + ” VALUES (Null,” + “‘” + psName.text + “‘,” + “‘” + mail.text + “‘,”
                    + “‘” + Title.text +”‘,” + “‘”+ cell.text + “‘)”;
                stm.addEventListener(SQLEvent.RESULT, stmInsRslt);
                stm.addEventListener(SQLErrorEvent.ERROR, stmErr);
                stm.execute();
            }

            private function stmInsRslt(event:SQLEvent):void
            {
                message.text += “insert a record…\n”;
                getData();
            }

            private function delBtnClick(event:Event):void
            {
                var item:Object = datGrid.selectedItem;
                var no:int = item.no;
                stm = new SQLStatement();
                stm.sqlConnection = conn;
                stm.text = “DELETE FROM ” + DBName.text + ” WHERE no=” + no;
                stm.addEventListener(SQLEvent.RESULT, stmDelRslt);
                stm.addEventListener(SQLErrorEvent.ERROR, stmErr);
                stm.execute();
            }

            private function stmDelRslt(event:SQLEvent):void
            {
                message.text += “delete target record finished…\n”;
                getData();
            }

            private function datGridEdit(event:DataGridEvent):void
            {
                if (event.dataField==”no”) event.preventDefault();
            }

            private function datGridEditEnd(event:DataGridEvent):void
            {
                if (event.reason==DataGridEventReason.CANCELLED) return;
                var datGrid:DataGrid = event.currentTarget as DataGrid;
                var item:Object = event.itemRenderer.data;
                var dataField:String = event.dataField;   
                var itemEditor:Object = datGrid.itemEditorInstance;
                if (itemEditor.text==item[dataField]) return;
                stm = new SQLStatement();
                stm.sqlConnection = conn;
                stm.text = “UPDATE ” + DBName.text + ” SET ” + dataField +” = :”
                    + dataField + ” WHERE no = :no”;
                stm.parameters[“:no”] = item.no;
                stm.parameters[“:”+dataField] = itemEditor.text;
                stm.addEventListener(SQLEvent.RESULT, stmUpdateRslt);
                stm.addEventListener(SQLErrorEvent.ERROR, stmErr);
                stm.execute();
            }

            private function editClick(event:Event):void
            {
                var app:com.adobe.illustrator.Application = Illustrator.app;
                var doc:Document = app.activeDocument;
                var layer:Layer = doc.layers.index(1);
                var item:Object = datGrid.selectedItem;
                var txFrm:TextFrames = layer.textFrames;
                message.text += “CREATE a DOCUMENT.\n”;
                txFrm.index(0).contents = item.cell;
                txFrm.index(1).contents = item.mail;
                txFrm.index(2).contents = item.Title;
                txFrm.index(3).contents = item.psName;
                var svFile:File = File.desktopDirectory.resolvePath(item.psName+”.ai”);
                doc.saveAs(svFile);
            }

            private function stmUpdateRslt(event:SQLEvent):void
            {
                message.text += “update target record finished.\n”;
                getData();
            }

            private function stmErr(event:SQLErrorEvent):void
            {
                message.text += event.error.message + “\n”;
            }

            private function connErr(event:SQLEvent):void
            {
                message.text += “Could not connect Database\n”;
            }
        ]]>
    </mx:Script>
        <mx:TabNavigator width=”100%” height=”100%” top=”0″ left=”0″>
            <mx:VBox label=”Data View” width=”100%” height=”100%”>
                <mx:Label text=”Data View” />
                <mx:VBox height=”100%” paddingLeft=”5″>
                    <mx:HBox width=”100%” paddingLeft=”5″>
                        <mx:TextInput id=”psName” text=”Name” width=”50%”/>
                        <mx:TextInput id=”mail” text=”Mail” width=”50%”/>
                    </mx:H
Box>
                    <mx:HBox width=”100%”>
                        <mx:TextInput id=”Title” text=”Title” width=”40%”/>
                        <mx:TextInput id=”cell” text=”Cell” width=”40%”/>
                    </mx:HBox>
                    <mx:HBox width=”100%”>
                        <mx:Button id=”insBtn” label=”insert” click=”insBtnClick(event)” />
                        <mx:Button id=”delBtn” label=”delete” click=”delBtnClick(event)” />
                        <mx:Button id=”editBtn” label=”edit” click=”editClick(event)” />
                    </mx:HBox>
                    <mx:DataGrid id=”datGrid” width=”100%” height=”100%” dataProvider=”{dp}”
                        editable=”true” itemEditBeginning=”datGridEdit(event)”
                        itemEditEnd=”datGridEditEnd(event)”>
                        <mx:columns>
                            <mx:DataGridColumn width=”30″ dataField=”no” headerText=”No” />
                            <mx:DataGridColumn width=”120″ dataField=”psName” headerText=”name” />
                            <mx:DataGridColumn width=”130″ dataField=”mail” headerText=”mail” />
                            <mx:DataGridColumn width=”70″ dataField=”Title” headerText=”title” />
                            <mx:DataGridColumn width=”100″ dataField=”cell” headerText=”cell” />
                        </mx:columns>
                    </mx:DataGrid>
                </mx:VBox>
            </mx:VBox>
            <mx:VBox label=”set DB Name” width=”100%” height=”100%”>
                <mx:Label text=”Database Name” />
                <mx:VBox paddingLeft=”5″>
                    <mx:HBox>
                        <mx:TextInput id=”DBName” text=”database1″ />
                        <mx:Button id=”dbApply” label=”apply” click=”readDB()”/>
                        </mx:HBox>
                        <mx:TextArea id=”message” width=”290″ height=”320″ />
                    </mx:VBox>
            </mx:VBox>
        </mx:TabNavigator>
</mx:WindowedApplication>

まあ、非同期で無駄にイベント待ちが多いので山の様にイベントリスナ設定してファンクション書きまくっていますが、ひとつずつ見てみればそう複雑なものではありません。

まずはインターフェースから見てみましょう。

    <mx:TabNavigator width=”100%” height=”100%” top=”0″ left=”0″>
            <mx:VBox label=”Data View” width=”100%” height=”100%”>
                <mx:VBox height=”100%” paddingLeft=”5″>
                    <mx:HBox width=”100%” paddingLeft=”5″>
                        <mx:TextInput id=”psName” text=”Name” width=”50%”/>
                        <mx:TextInput id=”mail” text=”Mail” width=”50%”/>
                    </mx:HBox>
                    <mx:HBox width=”100%”>
                        <mx:TextInput id=”Title” text=”Title” width=”40%”/>
                        <mx:TextInput id=”cell” text=”Cell” width=”40%”/>
                    </mx:HBox>
                    <mx:HBox width=”100%”>
                        <mx:Button id=”insBtn” label=”insert” click=”insBtnClick(event)” />
                        <mx:Button id=”delBtn” label=”delete” click=”delBtnClick(event)” />
                        <mx:Button id=”editBtn” label=”edit” click=”editClick(event)” />
                    </mx:HBox>
                    <mx:DataGrid id=”datGrid” width=”100%” height=”100%” dataProvider=”{dp}”
                        editable=”true” itemEditBeginning=”datGridEdit(event)”
                        itemEditEnd=”datGridEditEnd(event)”>
                        <mx:columns>
                            <mx:DataGridColumn width=”30″ dataField=”no” headerText=”No” />
                            <mx:DataGridColumn width=”120″ dataField=”psName” headerText=”name” />
                            <mx:DataGridColumn width=”130″ dataField=”mail” headerText=”mail” />
                            <mx:DataGridColumn width=”70″ dataField=”Title” headerText=”title” />
                            <mx:DataGridColumn width=”100″ dataField=”cell” headerText=”cell” />
                        </mx:columns>
                    </mx:DataGrid>
                </mx:VBox>
            </mx:VBox>
            <mx:VBox label=”set DB Name” width=”100%” height=”100%”>
                <mx:VBox paddingLeft=”5″>
                    <mx:HBox>
                        <mx:TextInput id=”DBName” text=”database1″ />
                        <mx:Button id=”dbApply” label=”apply” click=”readDB()”/>
                        </mx:HBox>
                        <mx:TextArea id=”message” width=”290″ height=”320″ />
                    </mx:VBox>
            </mx:VBox>
        </mx:TabNavigator>

mx:TabNavigatorというのがいきなり出てきます。文字通りタブをコントロールするコンテナです。各タブの内容は内包するmx:VBoxコンテナが相当します。

では単純な構成の2番目のタブを見てみましょう。

        <mx:VBox label=”set DB Name” width=”100%” height=”100%”>
                <mx:VBox paddingLeft=”5″>
                    <mx:HBox>
                        <mx:TextInput id=”DBName” text=”database1″ />
                        <mx:Button id=”dbApply” label=”apply” click=”readDB()”/>
                        </mx:HBox>
                        <mx:TextArea id=”message” width=”290″ height=”320″ />
                    </mx:VBox>
            </mx:VBox>

db2.png

一行目のlabelがタブに表示されるラベルになります。単純にオブジェクトが3つ縦並びです。続いて1番目のタブです。

            <mx:VBox label=”Data View” width=”100%” height=”100%”>
                <mx:VBox height=”100%” paddingLeft=”5″>
                    <mx:HBox width=”100%” paddingLeft=”5″>
                        <mx:TextInput id=”psName” text=”Name” width=”50%”/>
                        <mx:TextInput id=”mail” text=”Mail” width=”50%”/>
                    </mx:HBox>
                    <mx:HBox width=”100%”>
                        <mx:TextInput id=”Title” text=”Title” width=”40%”/>
                        <mx:TextInput id=”cell” text=”Cell” width=”40%”/>
                    </mx:HBox>
                    <mx:HBox width=”100%”>
                        <mx:Button id=”insBtn” label=”insert” click=”insBtnClick(event)” />
                        <mx:Button id=”delBtn” label=”delete” click=”delBtnClick(event)” />
                        <mx:Button id=”editBtn” label=”edit” click=”editClick(event)” />
                    </mx:HBox>
                    <mx:DataGrid id=”datGrid” width=”100%” height=”100%” dataProvider=”{dp}”
                        editable=”true” itemEditBeginning=”datGridEdit(event)”
                        itemEditEnd=”datGridEditEnd(event)”>
                        <mx:columns>
                            <mx:DataGridColumn width=”30″ dataField=”no” headerText=”No” />
                            <mx:DataGridColumn width=”120″ dataField=”psName” headerText=”name” />
                            <mx:DataGridColumn width=”130″ dataField=”mail” headerText=”mail” />
                            <mx:DataGridColumn width=”70″ dataField=”Title” headerText=”title” />
                            <mx:DataGridColumn width=”100″ dataField=”cell” headerText=”cell” />
                        </mx:columns>
                    </mx:DataGrid>
                </mx:VBox>
            </mx:VBox>

db1.png

かなりややこしい事になっています。肝心なのはbindableに駆動されるDataGridです。バインドされているのはSQLステートメントの返り値のarrayObjectです。データフィールドが連想配列状態ですのでdataField名で引っ掛けていきます。
注意するべきは、「タブの中身は表示された時にオンデマンドでオブジェクトとして生成される」と言う事です。ですからオブジェクトとして生成される前にスクリプトからアクセス出来るようなコーディングはコンパイルエラーになります。
次にimportが必要なライブラリです。

            import mx.events.DataGridEventReason;
            import mx.events.DataGridEvent;
            import mx.events.ItemClickEvent;
            import flash.data.SQLResult;
            import flash.data.SQLStatement;
            import flash.data.SQLConnection;
            import flash.filesystem.File;
            import mx.collections.ArrayCollection;
            import mx.events.FlexEvent;
            import com.adobe.csawlib.illustrator.Illustrator;
            import com.adobe.illustrator.*;

細かく書いているのでたくさんあるようですが、ワイルドカードを使えばもう少しシンプルに記述する事も可能です。
グローバルとして設定するバリアブルは

            private var conn:SQLConnection;
            private var stm:SQLStatement;

            [Bindable] private var dp:ArrayCollection = new ArrayCollection();

SQLステートメントとコネクション及び返り値が設定されています。

以下の流れはパターン的なものですが、基本コネクションにステートメントつっこんで返り値をイベントリスナで拾うと言う感じです。

            private function readDB():void
            {
                message.text += “Start processing…\n”;
                var tgDB:File = File.desktopDirectory.resolvePath(DBName.text + “.db”);
                conn = new SQLConnection();
                conn.addEventListener(SQLEvent.OPEN, connOpen);
                conn.addEventListener(SQLErrorEvent.ERROR, connErr);
                conn.open(tgDB);
            }

最初のモノはデータベース自身のオープン処理です。いつものごとくmessage.textへログを記録するのは動作的なものを確認する為ですので削ってしまっても問題ありません。データベース自体はデスクトップに配置してあります。ファイルオブジェクトを取得した後SQLコネクションをはります。
結果は正常に処理出来た場合のOPENとエラーのERRORの2種類のリスナを設定しておきます。
実際にコネクションを開くのはopenメソッドです。

            private function connOpen(event:SQLEvent):void
            {
                stm = new SQLStatement();
                stm.sqlConnection = conn;
                stm.text = “CREATE TABLE IF NOT EXISTS ” + DBName.text + ” (“+
                    ” no INTEGER PRIMARY KEY NOT NULL,”+
                    ” Title TEXT,”+
                    ” mail TEXT,”+
                    ” cell TEXT,”+
                    ” psName TEXT”+”)”;
                stm.addEventListener(SQLEvent.RESULT, stmCreRslt);
                stm.addEventListener(SQLErrorEvent.ERROR,stmErr);
                stm.execute();
            }

正常にオープン出来た場合、SQLステートメントを実行します。
上記のステートメントはデータベースが存在しない場合は新規に作成する為のものです。実際にSQLiteにステートメントをスローするのはexecuteメソッドの部分。ここでもクエリの返り値を拾うRESULTイベントとエラーに対処する為のリスナを設定します。

            private function stmCreRslt(event:SQLEvent):void
            {
                message.text += “Connect database…\n”;
                getData();
            }

前のイベントはデータベースの生成又は既存のデータベースにコネクト出来た場合のものですので、ここまででデータベースとのコネクションが正常に構成出来た事になります。つながったらデータを取得します。ここでは単純にgetDataファンクションをコールします。

            private function getData():void
            {
                stm = new SQLStatement();
                stm.sqlConnection =  conn;
                stm.text = “SELECT no, psName, mail, Title, cell FROM ” + DBName.text;
                stm.addEventListener(SQLEvent.RESULT, getDatRslt);
                stm.addEventListener(SQLErrorEvent.ERROR, stmErr);
                stm.execute();
            }

構成は単純です。クエリを構成してイベントリスナを設定してステートメントの実行を行うです。

            private function getDatRslt(event:SQLEvent):void
            {
                message.text += “update DataGrid.\n”;
                var result:SQLResult = stm.getResult();
                if (result.data==null) return;
                dp = new ArrayCollection(result.data);
            }

ここで初めて返り値を拾います。返り値はArrayCollectionです。そのままデータプロパイダに設定したdpにつっこみます。dpはバインダブルですので勝手にDataGridが更新されます。

            private function insBtnClick(event:Event):void
            {
                stm = new SQLStatement();
                stm.sqlConnection = conn;
                stm.text = “INSERT INTO ” + DBName.text + ” (no, psName, mail, Title, cell)”
                    + ” VALUES (Null,” + “‘” + psName.text + “‘,” + “‘” + mail.text + “‘,”
                    + “‘” + Title.text +”‘,” + “‘”+ cell.text + “‘)”;
                stm.addEventListener(SQLEvent.RESULT, stmInsRslt);
                stm.addEventListener(SQLErrorEvent.ERROR, stmErr);
                stm.execute();
            }

こちらのファンクションはデータフィルドに入力されたものをデータベースにストアする為のものです。テキストフィールドのデータを参照しながらクエリを構成してステートメントを実行します。

            private function delBtnClick(event:Event):void
            {
                var item:Object = datGrid.selectedItem;
                var no:int = item.no;
                stm = new SQLStatement();
                stm.sqlConnection = conn;
                stm.text = “DELETE FROM ” + DBName.text + ” WHERE no=” + no;
                stm.addEventListener(SQLEvent.RESULT, stmDelRslt);
                stm.addEventListener(SQLErrorEvent.ERROR, stmErr);
                stm.execute();
            }

データをストアする事もあれば削除する事もあるはずですので削除用ファンクションも用意します。データグリッド上で選択された行のNoの項目をキーに削除用のクエリを構成します。

            private function datGridEdit(event:DataGridEvent):void
            {
                if (event.dataField==”no”) event.preventDefault();
            }

            private function datGridEditEnd(event:DataGridEvent):void
            {
                if (event.reason==DataGridEventReason.CANCELLED) return;
                var datGrid:DataGrid = event.currentTarget as DataGrid;
                var item:Object = event.itemRenderer.data;
                var dataField:String = event.dataField;    
                var itemEditor:Object = datGrid.itemEditorInstance;
                if (itemEditor.text==item[dataField]) return;
                stm = new SQLStatement();
                stm.sqlConnection = conn;
                stm.text = “UPDATE ” + DBName.text + ” SET ” + dataField +” = :”
                    + dataField + ” WHERE no = :no”;
                stm.parameters[“:no”] = item.no;
                stm.parameters[“:”+dataField] = itemEditor.text;
                stm.addEventListener(SQLEvent.RESULT, stmUpdateRslt);
                stm.addEventListener(SQLErrorEvent.ERROR, stmErr);
                stm.execute();
            }

当然のごとくデータのアップデートも必要です。幸いな事にデータグリッドには更新用の各種機能が実装されています。しかし、キーとなるNoが編集されるのは都合がよろしくありません。こちらは編集自体をキャンセルし、デフォルトから変更出来ない様にしておきます。
編集が終了した時点でイベントを拾えますのでそこにリスナを引っ掛けて処理します。Noをキーにして変更された項目をアップデートするクエリを構成しステートメントを実行します。
毎度まいどなので省略していますが、ステートメントの実行を行った場合、最終的にはgetData()が行われますのでデータベースよりデータプロバイダへデータのリロードが実行される事になっています。

            private function editClick(event:Event):void
            {
                var app:com.adobe.illustrator.Application = Illustrator.app;
                var doc:Document = app.activeDocument;
                var layer:Layer = doc.layers.index(1);
                var item:Object = datGrid.selectedItem;
                var txFrm:TextFrames = layer.textFrames;
                message.text += “CREATE a DOCUMENT.\n”;
                txFrm.index(0).contents = item.cell;
                txFrm.index(1).contents = item.mail;
                txFrm.index(2).contents = item.Title;
                txFrm.index(3).contents = item.psName;
                var svFile:File = File.desktopDirectory.resolvePath(item.psName+”.ai”);
                doc.saveAs(svFile);
            }

はい、ここでやっとAIのオブジェクトを触ります。ターゲットはapp.activeDocumentつまり開いているドキュメントだよって事です。この辺はESTKとほとんど差異がなかったりします。サンプルとなるベースデータを見れば分かりますが、variableとなるデータはひとつのレイヤーに隔離してあります。データ自体はデータグリッド上で選択しているrowのものを拾います。flash系のものはセキュリティの関係でアクセス出来るディレクトリが制限されていますのでデータを置いたり書き出す先はもっぱらデスクトップにしています。この例でも生成データはデスクトップに保存する事になります。

その他ファンクションは幾つか存在しますがエラー処理ですので解説はしません。
それで、動作イメージは

db3.png

2番目のタブでデータベースを選び読み込みます。

db4.png

1番目のタブに戻るとデータが読み込まれています。

db5.png

テキストフィールドに入力してinsertボタンを押すとデータベースに追加されます。

db6.png

では、テンプレートを開いてみます。

db7.png

データグリッドを選択状態にしてeditボタンをクリックでバリアブルが更新され、ファイルがデスクトップに保存されます。

応用ですが、流用データ上の値組データからテキストを抜き出して新しいテンプレートに移し替えるとかの処理をしたい時に、必要なものを片っ端からデータベースに集めて、配置した新しいテンプレートに連続で貼付ける処理とか結構便利です。

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google フォト

Google アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中