MOSA Multi-OS Software Artists

MOSAはソフトウェア開発者を支援します

プログラマーに興味がある方なら誰でも入会いただけます。
MOSA Multi-OS Software Artists
===SINCE 1995===

  • iPhone/iPod touch アプリ紹介
  • MOSA掲示板
  • 活動履歴
  • About MOSA(English)

MOSADenバックナンバー 2006年12月発行分

  • MOSA Developer News[MOSADeN=モサ伝]第234号

    2006-12-26

    目次

    • 「「Wonderful Server Life」   第32回 田畑 英和
    • 小池邦人の「Carbon API 徒然草」
    • SqueakではじめるSmalltalk入門  第76回  鷲見 正人
    • ニュース・解説               木下 誠

    「Wonderful Server Life」  第32回  田畑 英和

      〜Leopard Server Preview編〜

     さて、2007年はいよいよLeopardがリリースされます。これまではMac OS XとMac OS X Serverが同時にリリースされていましたので、これまでと同じであればLeopardと同時にLeopard Serverもリリースされることになるでしょう。

     WWDC直後に一度Leopard Serverについては簡単にレポートしていましたが、来るべきLeopard時代に向けて、現在公開されている内容をもとにあらためてLeopard Serverについてレポートいたします。
     Leopard Serverがリリースされても、安定して稼働しているサーバはなかなかアップデートをしにくかったりもしますが、Mac OS X Serverが付属するXserveの場合はおそらく早い段階で付属するOSもLeopard Serverに移行していくものと思われます。ですので新規にサーバを構築するとなると、Leopard Serverを使い始めるのもわりと近い将来かもしれません。

    □管理ツール
     セットアップを行う「サーバアシスタント」が新しくなり、新しい管理ツールとして「Server Preferences」が導入されます。「Server Preferences」はちょうど「システム環境設定」のサーバ版のような外見をしており、次のような項目の管理を行う事ができます。

    ・アカウント
      ユーザ、グループ
    ・サービス
      カレンダー、iChat、ファイル共有、Mail、Webサイト
    ・システム
      information、Backup

     また、サーバの状態を確認するためのDashboardウィジェットが付属し、各サービスの稼働状況やディスク、ネットワーク、CPU、メモリの使用状況を一目で確認することができます。
     「ディレクトリアクセス」の改良版と思われる「Directory Utility」というツールも付属します。

    □iCal Server

     新しいサービスとしてカレンダーサーバが搭載されます。カレンダーサーバを利用することにより、ネットワーク上でカレンダーを共有することができます。iCal ServerはCalDAVという規格に基づいて開発されており、Leopardに付属するiCal 3だけでなくSunbirdやOutlookと連携することもできます。
     なおLeopard Serverに搭載されるカレンダーサーバはオープンソースによる開発がすでに開始されており、次のURLでプロジェクトの内容を参照することができます。

    http://trac.macosforge.org/projects/calendarserver

    □Wiki Server
     Leopard Serverではチームによる共同作業をサポートする機能が搭載されていますが、Wikiを使って情報の共有を行うことができます。マウス操作によるページの更新や、ページの履歴管理機能が搭載されているようですが、具体的な使い方については製品がリリースされるまで分からないかもしれません。
     また、Wiki Serverではカレンダー、メーリングリスト、ブログとの連携機能も提供されます。

    □Spotlight Server
     Tigerで導入されたメタデータ検索のSpotlightが、サーバのサービスとして提供されます。Spotlight Serverでは、クライアントにマウントされたネットワーク上のボリュームの内容を検索することができ、検索のためのインデックス作成はサーバ上で行われます。
     検索時にはアクセス権のチェックも行われ、アクセス権のないファイルが検索結果として表示されないようになっています。

    □Podcast Producer
     徐々に普及しつつあるPodcastですが、ビデオの取り込みからエンコーディング、コンテンツ配信までをまとめて行うPodcast Producerが登場します。
     撮影/録音を行ってからコンテンツを公開するまでの処理が自動化されており、クライアント上で収録したデータがLeopard Server上にアップロードされ、Webブラウザ、iTunes、iPod、携帯などに向けて配信することができます。
     エンコーディングは負荷のかかる処理ですが、Xgridを利用することにより複数のマシン上で分散してエンコーディングを実行することも可能です。

    □64bit
     サーバアプリケーションの多くが64ビット対応し、処理能力の向上と大量のデータ処理が期待できます。具体的には次のアプリケーションが64ビット対応します。

    ・64ビット対応サーバアプリケーション
      Apache、MySQL、Postfix、Cyrus、iChat Server
      QuickTime Streaming Server

    □その他
     Leopard Serverにはこの他にも様々な新機能が搭載されています。これまで長い間Apache 1.3を使っていたWebサービスはApache 2.2に切り替わり、ディレクトリサーバのOpen Directoryは、クロスドメイン認証、複製のカスケード化、AirMacのためのRADIUS認証に対応しています。

     このように非常に多くの機能がLeopard Serverに新たに搭載されます。新機能を追いかけるだけでも時間がかかりそうですが、実際にLeopard Serverがリリースされましたら、またその詳細をレポートしたと思います。

    ・Leopard Server先行プレビュー
    http://www.apple.com/jp/server/macosx/leopard/

    つづく

    小池邦人のCarbon API 徒然草(2006/12/22)

    〜 Carbonモダンアプリケーションへの道(その8) 〜

    前回は、ユニコード文字列を操作するAPIの特徴や利用方法などを取り上げてみました。その中で、Localizable.stringsの活用法を解説しましたが、そのサンプルの返す文字列中に「%1$@」といった変わった表記をみかけました。これは、どんな意味を持つのでしょうか? 今回は、こうした表記の仕組みを解説してみます。

    前回のLocalizable.stringsサンプルの一行を再度見てみます。

    VersionFormat = "%1$@ (%2$@)";     // for example, "4.0d8 (150)"

    横のコメントには”4.0d8 (150)”と記述されていますので、バージョン番号を表記するためのフォーマットであることが分かります。つまり、%1$@には”4.0d8″が、%2$@には”150″が入ることになります。もうお気づきだと思いますが、%1$@や%2$@は、文字列中に別の文字列や数値を挿入するための書式変換フォーマットです。これと同様な仕組みで有名なものは、printf()で用いられる%d(整数の引数用)や%f(浮動小数点の引数用)といった書式変換フォーマットです。

    %1や%2が引数の順番を示し、その後の$@がどんな種類の物を挿入するのかを表しています。ちなみに、$@はCore Foundation Frameworkで用いられているオブジェクトを指しており、文字列を参照するCFStringRefなどもこれに相当します。つまり、CFStringRefを渡すことでオリジナル文字列に別の文字列を挿入することなどが可能なのです。こうした書式変換フォーマットを含んだ文字列を自作アプリケーション内で活用するには、前回紹介したFCopyLocalizedString()と、以下のCFStringCreateWithFormat()を同時に用います。

    CFStringRef CFStringCreateWithFormatAndArguments (
       CFAllocatorRef  alloc,
       CFDictionaryRef formatOptions,
       CFStringRef     format,          // 書式変換フォーマット付文字列
       va_list         arguments
    );

    NULLを代入することで1番目のと2番目の引数は省略できます。先んじてCFStringRefとして定義しておいたcfstr2に”4.0d8″が、cfstr3の方には”150″が代入されているとすると、上記サンプル行のバージョン文字列を得るには以下のように記述すればOKです。これで、cfstrに目的のバージョン文字列が返ります。

    cfstr1=CFCopyLocalizedString( CFSTR( "VersionFormat" ),"" );
    cfstr=CFStringCreateWithFormatAndArguments( NULL,NULL,cfstr1,cfstr2,cfstr3 );

    文字列の代わりに整数値などを挿入する場合には、$@の代わりに$dを用います。

    PRINT_PAGE="%1$d/%2$d ページ";
    PRINT_MONTH="%1$d 月度";

    書式変換フォーマットに関する仕様は、ほとんどprintf()と同じであり、詳細についてはApple社が提供しているドキュメント「String Programming Guide for Cocoa」に詳しく載っていますので、そちらを参照してみてください。

    「String Programming Guide for Cocoa」

    http://developer.apple.com/documentation/Cocoa/Conceptual/Strings/Strings.pdf

    続いてサンプルルーチンを幾つか紹介しておきます。最初は、Cストリングスとしてキーワードを渡し、Localizable.stringsに定義されている文字列を得るルーチンです。その次は、CFStringRefをユニコード文字列に変換してから返すルーチンです。以前紹介した自作のcToCFString()やcfToUnicodeString()ルーチンを活用しています。

    OSErr getLocalCFString( char *str,CFStringRef *cfstr )
    {
        CFStringRef   cfstr1;
        short         err=1;
    
        *cfstr=NULL;
        if( ! cToCFString( str,&cfstr1 ) ) // キーワード文字列をCFStringRefに
        {
            if( *cfstr=CFCopyLocalizedString( cfstr1,"" ) ) // 文字列の読み込み
                err=noErr;
            disposeCFString( cfstr1 );
        }
        return( err );
    }
    
    OSErr getLocalUnicodeString( char *str,HFSUniStr255 *ustr )
    {
        CFStringRef   cfstr,cfstr1;
        short         err=1;
    
        ustr->length=0;
        if( ! cToCFString( str,&cfstr1 ) )  // キーワード文字列をCFStringRefに
        {
            if( cfstr=CFCopyLocalizedString( cfstr1,"" ) ) // 文字列の読み込み
            {
                err=cfToUnicodeString( cfstr,ustr ); // CFStringRefをユニコードに
                disposeCFString( cfstr );   // CFStringRefリリース自作ルーチン
            }
            disposeCFString( cfstr1 );
        }
        return( err );
    }
    


    また、文字列中に整数値(変数として)をひとつだけ挿入したい場合があります。以下の例では、1から12のどれかの整数値を挿入して「1 月度」や「12 月度」という文字列を生成したいわけです。

    PRINT_MONTH="%1$d 月度";

    こんな場合には、CFStringCreateWithFormat()に整数値をひとつだけ渡すルーチンを作成しておけば便利です。

    OSErr insertNumberUnicodeString( char *str,long val,HFSUniStr255 *ustr )
    {
        CFStringRef   cfstr,cfstr1,cfstr2;
        short         err=1;
    
        ustr->length=0;
        if( ! cToCFString( str,&cfstr1 ) )        // キーワード文字列をCFStringRefに
        {
            if( cfstr2=CFCopyLocalizedString( cfstr1,"" ) ) // 書式変換文字列を得る
            {
                if( cfstr=CFStringCreateWithFormat( NULL,NULL,cfstr2,val ) )
                {                                 // 引数で渡された整数値を挿入する
                    err=cfToUnicodeString( cfstr,ustr );    // CFStringRefをユニコードに
                    disposeCFString( cfstr );     // CFStringRefリリース自作ルーチン
                }
                disposeCFString( cfstr2 );
            }
            disposeCFString( cfstr1 );
        }
        return( err );
    }
    


    それから、先ほどの例において%1$@と%2$@に代入する文字列もLocalizable.stringsに登録されているとすると…

    VersionFormat = "%1$@ (%2$@)";

    次のようなルーチンで対応することができます。

    OSErr insertTwoCFString( char *str1,char *str2,char *str3,CFStringRef *cfstr )
    {
        CFStringRef  cfstr1,cfstr2,cfstr3;
        long         chk1,chk2;
        short        err=1;
    
        *cfstr=cfstr1=cfstr2=cfstr3=NULL;
        if( ! getLocalCFString( str1,&cfstr1 ) )   // 書式変換用文字列を得る
        {
            chk1=getLocalCFString( str2,&cfstr2 ); // ひとつめ挿入文字列を得る
            chk2=getLocalCFString( str3,&cfstr3 ); // ふたつめ挿入文字列を得る
            if( chk1==noErr && chk2==noErr )
            {
                if( *cfstr=CFStringCreateWithFormat(NULL,NULL,cfstr1,cfstr2,cfstr3))
                    err=noErr;                     // ふたつの文字列を挿入
            }
            disposeCFString( cfstr3 );  // CFStringRefリリース自作ルーチン
            disposeCFString( cfstr2 );
            disposeCFString( cfstr1 );
        }
        return( err );
    }
    


    次回は、こうして入手した文字列をウィンドウに表示したりプリントアウト(印刷)したりする状況を考えてみます。昔であれば、QuickDraw APIのDrawString()などを用いれば簡単でしたが、モダンアプリケーションではいったい何を使えば最良なのでしょうか?

    つづく

    SqueakではじめるSmalltalk入門   第76回  鷲見 正人

    本連載では、名前は知っていてもなかなか触れる機会のないSmalltalkについて、最近話題のSqueakシステムを使って紹介しています。今回は、作成中のGUIビルダをいったん完成させます。

    ▼ウィジェット削除時の処理の修正
    近々ご紹介したいと思っている、先頃リリースされた最新版のSqueak3.9での動作確認をしていたところ、うっかりミスに気付くことができましたのでこの機会に修正させてください。問題はウィジェットをレイアウトからクリックで削除するための#removeWidgetFrom:にありました。

    removeWidgetFrom: window
       | clickPoint selected |
       clickPoint := Point fromUser.
       selected := window paneMorphs
          detect: [:morph | morph bounds containsPoint: clickPoint]
          ifNone: [].
       selected
          ifNotNil: [selected delete]
    


    最後のdeleteだけでは不十分で、削除した結果をpaneMorphsに反映させるための#updatePanesFromSubmorphsをコールする必要があります。ウィジェット削除後、見えない枠変更用UIの亡霊たちに悩まされたかた、ごめんなさい(3.9ではこのUIが実体を持つように変更されたため、気が付きました…汗)。#paneMorphSatisfying:という便利メソッドも活用して次のように書き換えることにいたしましょう。

    removeWidgetFrom: window
       | clickPoint selected |
       clickPoint := Point fromUser.
       selected := window
          paneMorphSatisfying: [:morph | morph bounds containsPoint: clickPoint].
       selected ifNotNil: [
          selected delete.
          window updatePanesFromSubmorphs]
    

    ▼ウインドウを生成するためのコード出力
    仕上げには、GUIビルダ上でデザインしたGUIをコードとして出力するメニュー項目を設置します。必要な作業は二つ。ひとつは、もうお馴染みの、#addModelItemsToWindowMenu:の最後に該当記述を追加すること。メニュー項目名は「show script」、起動するメソッドは「#generateScriptOf:」としました。

    addModelItemsToWindowMenu: aMenu
       window := aMenu defaultTarget.
       aMenu addLine.
       (self class allMethodsInCategory: 'widget types') do: [:widgetSym |
          aMenu
             add: 'add ', widgetSym
             target: self
             selector: #add:to:
             argumentList: {widgetSym. window}].
       aMenu addLine.
       aMenu add: 'delete' target: self selector: #removeWidgetFrom: argument: window.
       aMenu addLine.
       aMenu add: 'show script' target: self selector: #generateScriptOf: argument: window
    

    必要なことのもうひとつは、呼び出される側の#generateScriptOf:を定義する

    generateScriptOf: window
       | sourceCodes method widgetClass sourceCode file start frame |
       sourceCodes := Dictionary new.
       (self class allMethodsInCategory: 'widget types') do: [:selector |
          method := self class compiledMethodAt: selector.
          widgetClass := method literals
             detect: [:lit | lit asString beginsWith: '#Pluggable'].
          sourceCode := method getSourceFromFile asString.
          start := sourceCode indexOf: $^.
          sourceCode := sourceCode allButFirst: start + 1.
          sourceCodes at: widgetClass value put: sourceCode].
       file := FileStream newFileNamed: 'mywindow.st'.
       [  file nextPutAll: '| model window |'; cr.
          file nextPutAll: 'model := Model new.'; cr.
          file nextPutAll: 'window := '.
          file nextPutAll: '(SystemWindow labelled: ''My Window'') model: model.'; cr.
          window paneMorphs do: [:morph |
             file nextPutAll: 'window addMorph: ('.
             file nextPutAll: (sourceCodes at: morph class).
             file nextPutAll: ') frame: ('.
             frame := morph layoutFrame.
             file nextPutAll: (
                frame leftFraction @ frame topFraction
                   corner: frame rightFraction @ frame bottomFraction) printString.
             file nextPutAll: ').'; cr].
          file nextPutAll: '^ window openInWorld']
       ensure: [file ifNotNilDo: [:f | f edit]]

    少し長めなうえ、Smalltalkならではの機能を多用(乱用?)しているので、細かな解説は次回以降としますが、大枠ではこんなことをしています。

    1. ‘widget types’に分類してあるメソッドのソースをカタログ化。
    2. 各ウィジェットからレイアウト情報を引き出す。
    3. ソースとレイアウト情報を組み合わせて加工し、スクリプトを構成。
    4. スクリプトをmywindow.stファイルに出力後、あらためてそれを表示。

    正月休みをはさんで次回まですこし間があくので、これまでの復習を兼ねて、#generateScriptOf:の読み解きにチャレンジしてみてはいかがでしょうか。ちなみに、「show script」で現われたウインドウ内のコードを選択してdo it(cmd + D)すると、完成品のウインドウが得られます。スクリプトを変更して、適切なモデルと正しく接続すれば、アプリのGUIとして機能するようになります。こちらの解説もいずれ。

    それでは、よいお年をお迎えください。

    バックナンバー:

    ニュース・解説

     今週の解説担当:木下 誠

    ———————————————————————-
    3Dアプリケーション「modo」開発者インタビュー
    ———————————————————————-

    「modo」という3Dグラフィックアプリケーションを開発している、Luxologyの開発者インタビューである、「Making modo a Great Mac App: Luxology Uses Tools, Quartz and OpenGL」が公開されています。

    Mac OS Xの強みとして、QuartzやOpenGLといったグラフィックフレームワークがあること、XcodeやSharkといった強力な開発ツールがあること、を挙げています。

    Making modo a Great Mac App: Luxology Uses Tools, Quartz and OpenGL
    http://developer.apple.com/business/macmarket/modo.html

    ———————————————————————-
    カスタムファイルシステムの、ボリュームをマウントする
    ———————————————————————-

    最近何度か登場している、カスタムのファイルシステムを作成する話題です。自分で作成したファイルシステムのボリュームを、デスクトップにマウントする方法を解説した、「QA1491: Volumes Not Showing Up On The Desktop」が公開されています。

    ファイルシステムのマウントには、適切なファイルシステムバンドルを作成する必要があります。このバンドルは、/System/Library/Filesystemsにインストールします。

    また、DiskArbitrationフレームワークを使って、ノーティフィケーションを送る必要があります。

    QA1491: Volumes Not Showing Up On The Desktop
    http://developer.apple.com/qa/qa2006/qa1491.html

    ———————————————————————-
    言語環境での並び順を取得する
    ———————————————————————-

    Mac OS Xはローカライズのシステムが非常に優れており、環境設定パネルの言語環境で使用する言語の優先順位を指定しておけば、それに対応するリソースをシステムが自動的に選択してくれます。

    でも、それとは別に、ここで指定されている言語の優先順位を調べたいときもあるでしょう。その方法を解説した、「QA1391: How can I determine the order of the languages set by the user in the Language tab of the Internation preference pane?」が公開されています。

    この順位は、ユーザデフォルトから取得することができます。Cocoaならば、NSUserDefaultsを使って、”AppleLanguages”というキーの値を調べます。Carbonならば、CFPreferencesを使います。

    QA1391: How can I determine the order of the languages set by the user
    in the Language tab of the Internation preference pane?
    http://developer.apple.com/qa/qa2006/qa1391.html

    ———————————————————————-
    Carbonアプリのスケルトン
    ———————————————————————-

    Carbonアプリケーションを作るときのスケルトンとなるサンプル、「DTSCarbonShell」が公開されています。

    DTSCarbonShell
    http://developer.apple.com/samplecode/DTSCarbonShell/index.html

     

    ◇MOSAからのお知らせと編集後記は割愛します◇

     

    MOSA Developer News   略称[MOSADeN=モサ伝]
          記事投稿受付 http://www.mosa.gr.jp/topics/mdn-toukou.html
    Apple、Mac OSは米国アップルコンピュータ社の登録商標です。またそのほかの各製品名等はそれぞれ各社の商標ならびに登録商標です。
    このメールの再配信、および掲載された記事の無断転載を禁じます。
    特定非営利活動法人MOSA  http://www.mosa.gr.jp/
    Copyright (C)2006 MOSA. All rights reserved.

  • MOSA Developer News[MOSADeN=モサ伝]第233号

    2006-12-19

    目次

    • 「Wonderful Server Life」       第31回  田畑 英和
    • 藤本裕之のプログラミング夜話 #105
    • 高橋真人の「プログラミング指南」  第103回
    • ニュース・解説                小池 邦人

    「Wonderful Server Life」  第31回  田畑 英和

      〜AFP編〜

     前回まででAFPを利用したネットワークホームの設定方法について解説してきました。今回はこれまでのまとめとして、ネットワークホームを使用するさいの挙動について解説いたします。ネットワークホームの処理の過程を理解しておくことにより、問題が発生したときのトラブルシューティングに役立ちます。

    □マウントレコードの読み込み
     クライアントコンピュータが起動すると、まずディレクトリサーバを参照して、マウントレコードを読み込みます。ディレクトリサーバを参照するためには、クライアントコンピュータはあらかじめ「ディレクトリアクセス」を使用してディレクトリサーバにバインドしておく必要があります。
     マウントレコードを読み込めばどのファイルサーバのどの領域をマウントすればよいかが決まります。ちなみに、ユーザを管理するOpen Directoryのマスターと、ネットワークホームを管理するファイルサーバを別々のマシンで運用することも可能です。サーバを分けることによって負荷を分散させることができます。

    □ユーザのログイン
     ログインウインドウで認証を行うと、あらかじめ「ディレクトリアクセス」で設定しておいたディレクトリドメインの検索順に従い、各ディレクトリ上に該当するユーザが存在するかどうかを確認します。このときユーザの確認は、必ずクライアントコンピュータ上のNetInfoで管理されているローカルディレクトリから行います。ですので同じユーザ名をもったローカルユーザとネットワークユーザが存在していた場合、ローカルディレクトリ上のローカルユーザのほうが優先されます。
     ローカルディレクトリに該当するユーザがいなければ、Open Directoryのマスターなどのネットワーク上のディレクトリドメインに該当するユーザが存在するかどうかを確認します。
     該当するユーザが存在すればユーザ認証が行われ、ユーザ認証に成功するとログイン処理が継続されます。

    □ネットワークホームのマウント
     ログイン後は直ちにネットワークホームが使用できる必要がありますので、ログイン時にネットワークホームが自動的にクライアントコンピュータ上にマウントされます。
     ログイン時にまずユーザごとに設定されたホームの情報が読み込まれます。ホームのパスとしてファイルサーバ上のネットワークホームが設定されていれば、自動的にクライアントコンピュータ上にファイルサーバ上のホームがAFPを使ってマウントされます。このときネットワークホームのマウントはログインしたユーザとしてマウントが行われ、自動的に認証が行われます。

    □トラブルシューティング
     このようにネットワークホームを使用したときには、様々な情報を読み込み、背後で自動的に処理が行われます。正しく設定が行われていないとネットワークホームが正常に機能しないことがあります。例えば、ログインウインドウで正しいユーザ名とパスワードを入力しても、ネットワークホームが正常に機能していないとログインに失敗することがあります。
     ログインに失敗した場合は、まずは問題点の切り分けを行いましょう。問題があるとすればたいていの場合、ユーザ認証に問題があるか、あるいはネットワークマウントに問題があるかのどちらかです。
     ログインウインドウからログインする場合は、ネットワークホームが機能していないとログインそのものが出来ない場合がありますが、ローカルユーザでログインしてから「Terminal」上でloginコマンドを使えば、ネットワークホームが使えなくてもネットワークユーザの認証は行えます。
     ですので、「Terminal」上で認証できた場合、おそらく問題はネットワークマウントにあるのではないかという推測ができます。ユーザ認証に問題がないことが確認できましたら、例えば手動でAFPのマウントが出来るかなどを確認して、AFPの動作を確認するようにしましょう。また、複数のユーザで動作確認を行えば、問題が特定のユーザに依存する問題なのかどうかを切り分けることができます。
     問題が発生する場合は、たいていどこかに設定ミスがあるはずですので、落ち着いて設定内容を見直しましょう。

    つづく

    藤本裕之のプログラミング夜話 #105

     承前、年の瀬で忙しいのでさくさく行こう。前回掲載したリストの解説である。まずビューオブジェクトのロードが終わった awakeFromNib でregisterForDraggedTypes: を呼んでいるのは自分がドラッグ用ペーストボードに入れたデータを自分で受け取る必要がある場合のため。今回のサンプルはこれがなくても動くんだが、例えば NSTableView におけるアイテムの順番変更などをドラッグ&ドロップで実現する場合、自分の入れたデータを自分で受け取ることが必要になる。その場合、ここでレジストしておかないと受け取れない。

    次の drawRect: でやってることはドラッグ&ドロップに直接関係ないので割愛。で、その次、mouseDown: の時点で「今ドラッグしてますフラグ」をオフにして、mouseDragged: のなかでこれがオフの時だけドラッグデータをセットする部分は私の勘違い。……つうかソースの使い回しが原因のミスであります。これについては後述。

    で、肝心カナメの mouseDragged: 。まずは「ドラッグされるデータ」として文字列 @”Data to be dragged” を用意し、次にドラッグ用ペーストボードへのリファレンスを獲得。次にこのペーストボードに対して、declareTypes: owner: を送り、これから入れるデータのタイプを申告する。このメソッドの第2パラメータ、owner: には、ここで申告したタイプのデータをこのボードに入れる責任を負うオブジェクトを……回りくどいな。このサンプルでは NSStringPboardType 1個しかデータのタイプを申告していないし、しかも次のステートメントですぐにそれをセットしているのでここは nil でも構わないんだが、そのデータを用意するオブジェクトがこのビュー自身ぢゃない場合など、ここにそのオブジェクトがどれかを申告しておいて、そいつに対して pasteboard: provideDataForType: メッセージが来るのを待ってセットするということが出来るわけ。……なんだけど、このサンプルでは簡単に文字列 @”Data to be dragged” をペーストボードにセットしてこの処理はおしまい。

    さあ次、これが結構大切、実際に画面上をドラッグされて動くイメージを作らなくちゃならない。ああ、見た目の問題ねと思うかも知れぬが、実はこれを端折ると、いくらマウスボタンを押してドラッグを始め、押したまま他のアプリケーションのウインドウの上までポインタをドラッグして行き、そこでマウスボタンを放してデータをドロップした……つもりになっても何も起きないのだ。うそだと思ったらやってみなさい。まぁサボれるとしてもサボったらユーザの顰蹙を買うことは必至だけどね。
     ではその詳細。ペーストボードに入れた文字列をデフォルトの属性で描けるだけのサイズの NSImage オブジェクトを作り、そこに描画する。ここでは描画もデフォルトの属性のままでやっているが、それっぽくしたければフォントの色をグレイにしたり半透明にしたりすることも可能。なお、サンプルでは属性を持たない NSStringPboardType しか入れてないのでこれでいいが、リッチテキスト(NSRTFPboardType)などをサポートした場合にはこのイメージにもそれなりの見た目のものを用意するべき。
     イメージができ上がったら、NSViewのdragImage: at: offset: event: pasteboard: source: slideBack: メソッドを使ってこれを……なんというのかな、「ドラッグされるイメージ」としてセットする。at: にはイメージを最初に表示する左下の座標をこのビューの座標系でセット。次の offset: はmouseDown: が発生した場所を基準にした現在のmouseの位置……なんだが、Mac OS X 10.4以降では無視されるので気にしない。event: は現在のイベント。ペーストボードも今データをセットしたペーストボード。source: にセットするのはこのドラッグ・オペレーションのコントローラ・オブジェクトで、NSDraggingSource プロトコルに適応している必要がある。具体的には最低限以下のメソッドをインプリメントしておけと……いうんだが、これ無くても別に支障がないみたいなんだけどね。

    - (unsigned int)draggingSourceOperationMaskForLocal:(BOOL)isLocal;

    とにかく、普通はビュー自身、場合によってはビューを含むウインドウをセットする。上のメソッドが何を返すべきかは NSDraggingSource プロトコルのドキュメントを参照のこと。最後の slideBack: はこのデータのドロップが拒否されたとき、つまり NSStringPboardType のデータを受け取らないオブジェクトの上でドロップされた場合にこのビューまで跳ね返されるアニメーションを行うかどうかのフラグである。
     で、さっきの「後述」部分、このメソッドを呼ぶと、これはドラッグが終わる(どっかでmouseボタンがリリースされる)まで戻ってこないので、ドラッグペーストボードにデータが入ったままこのmouseDragged:が重複して呼ばれることはない。なので、前回リストのフラグのことは忘れてくだされ。

    はぁはぁ、駆け足したがなんとか年内にここまでこぎつけたぞ。来年1月からは NSTableView に話題を絞って上にも出てきたアイテムの順番変更などのやり方を説明する予定。それではみなさま、よいお年を。
    (2006_12_14)

    高橋真人の「プログラミング指南」第103回

    プログラマのためのオブジェクト指向再入門(11)

    〜カプセル化について(2)〜

     こんにちは、高橋真人です。
     さて今回は、前回お話ししたMLTEの例でカプセル化ということについてのお話をしたいと思います。
     MLTEはかなり大きな機能のセットです。そのため、「お任せ」で使う分にはかなりラクができます。つまり、使う側は余り多くのコードを書かなくてもいろいろな機能を実現できるのです。しかし、MLTEが標準で提供しているものと違ったことをしようとすると複雑な手間を強いられることがあります。
     PowerPlantでは、多くのクラスがMac OSが提供している機能を包んだ(ラップした)形で設計されています。たとえば、LWindowというクラスは、WindowRecordという構造体をラップする形でクラスが構成されています。こうすることで、フレームワーク利用者は、WindowRecord(もしくはWindowRef)を直接扱うよりも、少ない手順でウインドウを操作することができるようになるわけです。
     さらにLWindowが提供する機能では足らない場合には、オブジェクト指向の仕組みを利用してサブクラス化することで、利用者独自の機能を追加することができます。
     ところでMLTEをラップしたLMLTEPaneは、とても簡単に使うことができます。これは、最初に言った「MLTEはラクができます」というのとはラクさの度合いが違います。
     PowerPlantが標準で用意するConstructorというGUI編集ツールを使って、部品パレットからウインドウ上にLMLTEPaneを持ってきて配置するだけで主な作業は完了。あとはコードの方にRegisterClass_(LMLTEPane);という1行を加えるだけで、表示したWindow上にちゃんとMLTEが生成されます。MLTEが備えるオプションを利用したい場合にもConstructorの設定パレットでいくつかのチェックボックスを選択する程度の手間しかかかりません。
     「MLTEはラクができます」と言っても、普通にCでMLTEを使う場合には、書かなければならないコードがそれなりにあるので、それに比べても相当に「ラクができる」と言えるでしょう。
     ところで、MLTEをカスタマイズする必要が出てきた場合、どうすればよいのでしょうか?
     Cによるアプローチの場合、MLTEの仕組みが提供する機能を適宜利用して、自分のカスタマイズの用途に合わせたコードを書いていきます。
     では、オブジェクト指向の場合はどうでしょうか?
     先ほども言いましたように、PowerPlantでは、MLTEをラップした形でLMLTEPaneというクラスが構成されています。しかし、この「ラップした仕組み」がカスタマイズの邪魔をすることがあるのです。
     今回私が取り組んだプログラムの場合、複数の写真を切り替えながらキャプションを編集する仕組みになっています。このキャプションを表示・編集する部分にMLTEを使用しているわけなのですが、ここで問題が出てきました。
     ユーザーが写真を切り替えた場合、新たに選択された写真のキャプションがMLTEの中に表示されるわけですが、内部的にはそれまで表示されていたテキストにさしかえて新しいキャプションをセットすることになります。
     すると、ユーザーが編集メニューから取り消しを選んだ場合、キャプションフィールドは以前に選択されていた写真のキャプションを表示してしまうのです。これは、MLTEが無限回数のアンドゥをサポートしているために発生する現象ですが、ユーザーからすればこの動作はちょっと不自然です。(選択されている写真も前のものに切り替わるならばまだしも)
     そんな時にどのように対処すべきか、アプローチはいくつか考えられるでしょうが、私は、写真が選択し直される場合にMLTE自体を一度消去し再度作り直すという方法を取ることにしました。(このやり方自体の是非はここでは議論しません)
     ところがMLTEというのは少しクセのあるコントロール(ボタンやフィールドなどのパーツのこと)で、生成時にしか指定のできないオプションがある上、これらのオプション値は既に生成されているMLTE自体から読み取ることができないのです。
     私の取った「新規に作り直す」というアプローチのためには、それらのオプション値をどこかから得なければなりません。MLTEのコントロールから取れないとなれば、再度リソースデータから読み出してくる必要があります。
     ところが、Constructorというツールによって作られているPowerPlantのWindowは、Windowの上に配置されているコントロールがWindow自身と共に一つの固まりとなってリソースに格納されています。
     新規にWindowを生成する場合には、そのリソースの固まりを頭から順番に読んでいき、コントロールを一つずつ生成していくようになっています(もちろん、これらは「Windowを生成する」という作業の裏側でPowerPlantが勝手にやることです)が、Window上の任意のパーツを特定して読み出すとなると話はそんなに簡単ではありません。
     パーツの数が少なければ、とりあえず全部のデータを読み出して、必要ないものは捨ててしまうというアプローチもあったのでしょうが、今回のケースではWindow上のパーツがかなりの数に上ったので、その方法は取りませんでした。
     そうなると、最初にLMLTEPaneのオブジェクトが生成される際に、リソースから読み込んできた各種設定値をどこかに保存しておけばよいということになるわけですが、あいにくLMLTEPaneはこのような機能は持っていません。
     サブクラス側から、このLMLTEPaneの初期化動作を横取りできればよいのですが、残念ながら初期化のための関数はprivate指定です(サブクラスからもアクセスができない指定。もう少しあとの回で説明します)。
     仕方ないので、サブクラスの生成関数の中で、途中まで読み出されたWindowのリソースのデータをLMLTEPaneが読み出した分だけ巻き戻して、再度読み込み直す、という回りくどいアプローチをすることで、結局実現に至ったのでした。

    少し話が複雑すぎたかもしれません。PowerPlantの経験者でもないと、ちょっと理解するのは難しかったかな?
     どういうことが言いたかったのかは、次回でまとめて説明します。

    ニュース・解説

     今週の解説担当:小池邦人

    ● Carbon ドキュメント & サンプル & SDK ナビゲーション(2006/12/15)

    【開発環境】

    アップル社から「Leopard Tech Talk」開催の案内が届きました。アップルのエンジニアやエキスパートからリリース間近のMac OS X Leopardについての最新情報と技術知識を得られる機会だそうです。大阪で1回、東京では4回開催されるのですが、登録手続きにもたついていたら、最後の開催日(2/15)しか空いていない状況になっていました。すごい人気ですね(笑)。具体的なセッションの内容は「Mac OS X “Leopard” テクノロジー概要」「グラッフィックス概要」「新しいCocoaとObjective-C 2.0の概要」「Toolsの概要」などだそうです。

    http://developer.apple.com/jp/events/techtalks/japan.html

    多分、サンフランシスコExpoの基調講演ではLeopardの新機能(WWDCでは未紹介)がデモされるでしょうから、この場においても、WWDCで入手した情報よりも「さらに新鮮な情報」が入手できると嬉しいですね。期待いたしましょう!

    【テクニカルドキュメント】

    前回から12月15日の期間中、Apple社のGuidesとReferenceサイトには幾つかのドキュメントが登録されました。しかし、そのほとんどがマイナーチェンジの改訂です。Guidesサイトに登録された以下の2つのドキュメントだけが、内容の大幅な更新がなされています。また、デベロッパ向け読み物がひとつだけ登録されています。こちらについては、前号の木下さんの記事も参考にしてください。

    「Quartz Composer Web Kit Plug-in JavaScript Reference」(PDFあり)
    「Quartz Composer Programming Guide」(PDFあり)

    http://developer.apple.com/documentation/index-rev-date.html

    「Leopard Application Technologies Overview」(読み物)
    http://developer.apple.com/leopard/overview/apptech.html

    前回から12月15日の期間中、新規テクニカルノートと新規テクニカルQ&Aがひとつずつ登録されました。両方ともAudio関連です(最近多い)。

    TN2113「Using AudioDeviceRead in Mac OS 10.4」

    http://developer.apple.com/technicalnotes/index-rev-date.html

    QA1437「Standard Audio – Parsing the kQTSCAudioPropertyID_
    CodecSpecificSettingsArray property」(初版)

    http://developer.apple.com/technicalqas/index-rev-date.html

    【サンプルソースコード】

    前回から12月15日の期間中、Apple社のSample Codeサイトには、サンプルソースコードがひとつも登録されませんでした。全体的にクリスマス休暇の影響で情報の更新が少ないです(嵐の前の静けさか?)。

    http://developer.apple.com/samplecode/index-rev-date.html

    【デベロップメント SDK】

    前回から12月15日の期間中、Apple社のSDKサイトには新しいSDKがひとつも登録されませんでした。

    http://developer.apple.com/sdk/

     ◇MOSAからのお知らせと編集後記は割愛します◇

     MOSA Developer News   略称[MOSADeN=モサ伝]
          記事投稿受付 http://www.mosa.gr.jp/topics/mdn-toukou.html
    Apple、Mac OSは米国アップルコンピュータ社の登録商標です。またそのほかの各製品名等はそれぞれ各社の商標ならびに登録商標です。
    このメールの再配信、および掲載された記事の無断転載を禁じます。
    特定非営利活動法人MOSA  http://www.mosa.gr.jp/
    Copyright (C)2006 MOSA. All rights reserved.

  • MOSA Developer News[MOSADeN=モサ伝]第232号

    2006-12-12

    目次

    • 「「Wonderful Server Life」   第30回  田畑 英和
    • 小池邦人の「Carbon API 徒然草」
    • SqueakではじめるSmalltalk入門  第75回  鷲見 正人
    • ニュース・解説               木下 誠

    「Wonderful Server Life」  第30回  田畑 英和

    ■  〜AFP編〜

     AFPサービスおよびネットワークマウントの設定が完了しましたので、あとはユーザごとにホームを設定すればいよいよネットワークホームが利用できるようになります。

    □ホームの設定
     ユーザごとのホームの設定ですが「ワークグループマネージャ」を使用します。まずツールバーから「アカウント」をクリックして画面左側にユーザのリストを表示します。次にホームの設定を行いたいユーザをユーザリストから選択してツールバーの下に並んだボタンから「ホーム」をクリックします。この「ホーム」設定画面で選択中のユーザのホームの設定を行います。
     デフォルトでは(なし)が選択されています。ネットワークマウントの設定が完了していればネットワークマウントで設定した領域がホームとして選択可能なパスのリストに追加されています。
     今回の例ですと「afp://server.example.com/Users」がネットワークマウントで設定したホームのパスになります。あとはリストからホームとして設定したいパスを選択して、画面右下の「保存」ボタンをクリックすれば、ユーザのホームの設定が完了します。

    ・ホームの設定
    http://homepage.mac.com/htabata/MXS10.3/img/WGM_Home/WGM_Home_02.png

     パスのリストの上には設定したパスが表示されますが、ネットワークホームを利用する場合には2種類のパスが設定されていることが確認できます。2種類のパスの意味はそれぞれ次のとおりです。

    ・exampleユーザの場合
    afp://server.example.com/Users/example
     クライアントからみたサーバ上のホームのパスのURL
    /Network/Servers/server.example.com/Users/example
     ホームをマウントするクライアント上でのパス

     あとは同様の手順をユーザの数だけ繰り返せばよいのですが、ユーザが複数存在した場合、いちいち1ユーザずつ設定するのは手間がかかります。そこでこんなときには画面左側のユーザリストから、ホームを設定したいユーザをすべて選択してから、ホームの設定を行います。すると複数ユーザのホームを一括して設定することができます。

    ・複数ユーザのホームの設定
    http://homepage.mac.com/htabata/MXS10.3/img/WGM_Home/WGM_Home_02.png

     このように「ワークグループマネージャ」では複数のユーザに対して設定をまとめて行えますが、ホーム以外の設定でも複数ユーザの設定をまとめて行うことができます。

    □ホームの作成
     「システム環境設定」の「アカウント」でローカルユーザを作成した場合には自動的に「/ユーザ」にホームが作成されますが、「ワークグループマネージャ」でホームの設定をしただけですと、ホームは自動的には作成されません。
     もしホームが存在しない状態で実際にネットワークユーザがクライアントコンピュータにログインしますと、その時点でホームが自動的に作成されます。ですが、あらかじめホームを作成しておくこともでき、ホームを作成するにはホームの設定画面の下にある「今すぐホームを作成」ボタンをクリックします。
     このボタンはその名前からして、クリックするとすぐホームを作成してくれそうな気がしますが、実際には画面右下の「保存」ボタンをクリックしないとホームは作成されません。作成されたホームはサーバ上の「/ユーザ」に作成されます。
     ホームの作成も、ホームを設定したときと同様に画面左側のユーザリストから複数ユーザをまとめて選択した状態で実行することができます。この場合選択していた各ユーザのホームが作成されます。
     ホームの作成は「ワークグループマネージャ」を使用するほかにもコマンドラインから実行することができます。「/usr/sbin/createhomedir」というコマンドが用意されており、例えばexampleユーザのホームを作成するには次のようにこのコマンドを使用します。

    ・コマンドラインからのホームの作成

    % createhomedir -u example

     なおこのコマンドはroot権限で実行する必要がありますので、通常はsudoコマンドを先頭につけて実行します。登録済みのすべてのユーザのホームを作成することもでき、その場合には次のように”-a”オプションを使用します。

    ・すべてのユーザのホームの作成

    % createhomedir -a

     ちなみにホームの作成ですが、「/システム/ライブラリ/User Template」に各言語ごとのホームのテンプレートが準備されており、こちらを参照することでホームの作成が実行されます。
     ホームの構成をカスタマイズすることも可能ですが、その場合はcreatehomedirコマンドを利用したシェルスクリプトなどを作成して対応するのがよいでしょう。

     さて、これでネットワークホームに関する設定がすべて完了しました。サーバ上での設定がすべて完了した後に、クライアントコンピュータを再起動してネットワークユーザとしてログインすれば、ネットワークホームが利用できるようになります。

    つづく

    SqueakではじめるSmalltalk入門   第75回  鷲見 正人

    本連載では、名前は知っていてもなかなか触れる機会のないSmalltalkについて、最近話題のSqueakシステムを使って紹介しています。

    前回は、#addFieldTo:、#addButtonTo:といった、各ウィジェットをGUIビルダのウインドウへ追加するための専用メソッドの共通部分を新しい#add:To:メソッドとしてまとめ、ウィジェット生成のほうは、ウィジェットタイプ(#fieldや#buttonといった…)を名前に持つメソッドに分担させる改変を行ないました。

    これにより、当初のテキストフィールドやプッシュボタン以外のウィジェットを扱えるようにする拡張手続きはとても簡単になりました。が、まだ相変わらず、追加したウィジェット用にメニュー項目を新設する作業は必要です。具体的には、 #addModelItemsToWindowMenu:というメソッドに、メニュー項目の追加、および、そのメニュー項目に適切なウィジェットタイプのシンボルをパラメータとして#add:to:メソッドを呼び出すよう機能の割り振りをする行を挿入しないといけません。

    そこで今回は、このメニュー構築の手続き自体も動的にしてしまい、新しく扱うウィジェットを生成するためのメソッドを定義するだけで済ませることが可能な仕組みを考えることにします。

    ▼与えられたウィジェットタイプ群からメニューを自動的に生成する
    たとえば、#fieldと#buttonという二種類のウィジェットタイプを扱えるとして、それを表わす情報が配列#(#field #button)として与えられたと想定しましょう。ここから、「add field」「add button」といったメニュー項目用の文字を生成することは#collect:を使えば簡単です。

    #(#field #button) collect: [:each | 'add ', each]   " => #('add field' 'add button') "

    なお、配列リテラル式において、要素となるシンボルの#は(対象となるシンボルがスペースなどの記号を含まないなら…)省略可能なので、こう書いても同じです。

    #(field button) collect: [:each | 'add ', each]

    #collect:は結果を集めていますが、ただブロック内の処理を繰り返すだけなら#do:を用います。このことをふまえて、#addModelItemsToWindowMenu:を次のように書き換えてみましょう。書き換えたらaccept (cmd + S)によるコンパイルもお忘れなく。

    addModelItemsToWindowMenu: aMenu
       | window |
       window := aMenu defaultTarget.
       aMenu addLine.
       #(field button) do: [:widgetSym |
          aMenu
             add: 'add ', widgetSym
             target: self
             selector: #add:to:
             argumentList: {widgetSym. window}].
       aMenu addLine.
       aMenu add: 'delete' target: self selector: #removeWidgetFrom: argument: window
    

    ウインドウメニューをプルダウンしても、これまでとの違いはまったくありませんし、項目を選択したときの動作も同じです。しかし、#(field button)のところにウィジェットタイプを書き足すだけでメニュー項目を増やすことができるようになっています。ためしに、#(field button list)と書き換えてacceptしてみてください。メニュー項目には「add list」が追加されているはずです。

    [fig.A]メニュー項目に自動的に追加された「add list」

    このメニュー項目はまだ機能しませんが(選択するとエラー)、項目リストを扱うためのウィジェットであるa PluggableListMorphを生成する次のメソッド「#list」を追加することで動作するようになります。

    list
       ^ PluggableListMorph
          on: self
          list: nil
          selected: nil
          changeSelected: nil
          menu: nil
    

    ▼扱うことができるウィジェットの種類を動的に得る
    残る問題は、#(field button list)といった配列をどうやって得るか?です。これにはSmalltalkの強力なリフレクション機能を活用することにいたします。具体的には、まず、新しい「widget types」というカテゴリを設けて、そこに#field、#button、#listというウィジェット生成用のメソッドを分類しておき、改めて「widget types」カテゴリにあるメソッド名をクラスに尋ねることで、目的の情報を得ようというもくろみです。

    システムブラウザにて、メソッドカテゴリリスト(上段右から二番目の枠)で「– all –」が選択されていることを確認してから、メソッド名リスト(右隣、上段右端の枠)から「field」を選択。そのペインのシフト黄ボタンメニュー(shiftキーを押しながら黄ボタン、あるいは、黄ボタンメニューをポップアップさせてmore…を選択)から「change category…」→「new…」を選択し、新しいカテゴリを追加するための入力欄で「widget types」とタイプして入力し「了解(s)」(英語モードならAccept)します。

    [fig.B]widget typesカテゴリの追加

    すると、メソッドカテゴリリスト(左隣の枠)に「widget types」というカテゴリが現れます。見た目では分かりませんが、一連の作業により#fieldメソッドは、このカテゴリに再分類されています。次に、メソッド名リストから「button」を選択し、同じようにシフト黄ボタンメニューから「change category…」を選択してください。今度はメニューに「widget types」が含まれているので、これを選んでおしまいです。#listについても同様に行ないます。

    メソッドカテゴリリストで「widget types」をクリックして選択し、三つのメソッドがきちんと収まっているか確認しておきましょう。もし再分類から漏れたメソッドがあるときは「– all –」を選び直して、操作を繰り返します。

    [fig.C]widget typesカテゴリに分類されたウィジェット生成用メソッド群

    以上で準備は整ったので最後の仕上げです。クラスに対して、指定したカテゴリに属するメソッド名(セレクタ)を列挙してくれるよう頼むのには、次の式を用います。

    GuiBuilder allMethodsInCategory: 'widget types'   " => #(#button #field #list) "
    

    この式を先の#addModelItemsToWindowMenu:でハードコードした配列に置き換えれば、当初の「メニュー生成までの自動化」という目的は達成できます。

    addModelItemsToWindowMenu: aMenu
       | window |
       window := aMenu defaultTarget.
       aMenu addLine.
       (self class allMethodsInCategory: 'widget types') do: [:widgetSym |
          aMenu
             add: 'add ', widgetSym
             target: self
             selector: #add:to:
             argumentList: {widgetSym. window}].
       aMenu addLine.
       aMenu add: 'delete' target: self selector: #removeWidgetFrom: argument: window
    

    ためしに、’widget types’のメソッドを別のカテゴリに再分類したり元に戻したりして、メニュー項目がきちんとその変更に追従できているか確認してみてください。

    バックナンバー:

    ニュース・解説

     今週の解説担当:木下 誠

    ———————————————————————-
    Leopard続報:アプリケーションテクノロジー
    ———————————————————————-

    Leopardの開発者向け情報を小出しに紹介している「Leopard Technology Series for Developers」。新たな項目として、「Leopard Developer Application Technologies Overview」が追加されました。今回は、サードパーティのアプリケーションで使える、Leopardの技術を紹介しています。

    取り上げられているのは、Time Machine、iChatとの統合、Calendar Store、Scripting Bridge、Core Animation、64-bitなど。Scripting Bridgeへの言及は、今回が初めてだったではないでしょうか。

    Cocoaアプリケーションの開発としてみると、PantherのCocoaバインディングや、TigerのCore Dataのような、いままでのアプリケーションの作り方をひっくり返してしまうようなものはなく、落ち着いた気分で迎えられるアップデートではないでしょうか。

    Leopard Developer Application Technologies Overview
    http://developer.apple.com/leopard/overview/apptech.html

    ———————————————————————-
    Audio ConverterのQA
    ———————————————————————-

    Audio Converterに関するQAが出ています。「QA1437: Standard Audio -Parsing the kQTSCAudioPropertyID_CodecSpecificSettingsArray 」です。

    Auido Converterでは、オーディオの変換に関する設定を行う標準ダイアログが提供されていますが、その設定をCFDictionaryの形で取り出す方法が解説されています。

    少し前に公開された「QA1390: Standard Audio – The CodecSpecificSettingsArray and MagicCookie properties」も併せて読んでください。

    QA1437: Standard Audio – Parsing the
    kQTSCAudioPropertyID_CodecSpecificSettingsArray property
    http://developer.apple.com/qa/qa2006/qa1437.html

    QA1390: Standard Audio – The CodecSpecificSettingsArray and
    MagicCookie properties
    http://developer.apple.com/qa/qa2006/qa1390.html

     

    ◇MOSAからのお知らせと編集後記は割愛します◇

     

    MOSA Developer News   略称[MOSADeN=モサ伝]
          記事投稿受付 http://www.mosa.gr.jp/topics/mdn-toukou.html
    Apple、Mac OSは米国アップルコンピュータ社の登録商標です。またそのほかの各製品名等はそれぞれ各社の商標ならびに登録商標です。
    このメールの再配信、および掲載された記事の無断転載を禁じます。
    特定非営利活動法人MOSA  http://www.mosa.gr.jp/
    Copyright (C)2006 MOSA. All rights reserved.

  • MOSA Developer News[MOSADeN=モサ伝]第231号

    2006-12-05

    目次

    • 「Wonderful Server Life」      第29回  田畑 英和
    • 藤本裕之のプログラミング夜話 #104
    • 高橋真人の「プログラミング指南」  第102回
    • ニュース・解説                小池 邦人

    「Wonderful Server Life」  第29回  田畑 英和

      〜AFP編〜

     前回新しいXserveの紹介をしましたがまずはその補足から。新型のXserveはLOM(Lights-out Management)と呼ばれる機能を搭載しています。この機能を使えばリモートからXserveの電源を入れるなどのリモート制御ができます。実際にこの機能を利用するにはLOMに対応したソフトウェアが必要になりますが、つい最近アップデートされたApple Remote Desktop v3.1はさっそくこのLOMをサポートしています。

    さて、話を元に戻してネットホームの設定方法を解説しましょう。これまでAFPサービスや共有ポイントの設定方法を解説してきました。これでAFPを使ってクライアントコンピュータからサーバ上の共有ポイントにアクセスし、ホームをクライアント上ではなくサーバ上にもつことができるようになりました。
     ですが、ネットワークホームを利用するにはさらにネットワークマウントの設定も行う必要があります。ネットワークホームを使う場合、ユーザのログイン後ただちにホームが使える必要があります。ですのでいちいちログインしてからサーバ上のホームを手動でマウントするといったことはできません。そこで自動的にサーバ上の共有ポイントをマウントする必要があるわけですが、これがネットワークマウントになります。

    ◇ネットワークマウントの設定
     ネットワークマウントの設定は「ワークグループマネージャ」を使用します。ツールバーから「共有」をクリックし、まずは画面左側に表示される共有ポイントのリストからネットワークマウントを設定したいフォルダを選択します。ネットワークホームの設定を行うには共有ポイントのリストから「Users」を選択します。つまりサーバ上の「/Users(/ユーザ)」をネットワークマウントするように設定します。
     次に右上の「ネットワークマウント」ボタンをクリックします。ネットワークマウントの設定を行うにはディレクトリの管理者として認証を行う必要があります。これはマウントレコード(ネットワークマウントの設定情報)をディレクトリサービスで管理するためです。つまり設定したマウントレコードは共有ディレクトリ(LDAP)の中に書き込まれます。共有ディレクトリに対して書き込みを行うので、ディレクトリの管理者としてまずは認証を行う必要があるわけです。
     認証を行うには「場所」ポップアップメニューの右側のカギをクリックします。「場所」のポップアップメニューですが、ここでマウントレコードを書き込む場所を選択します。OpenDirectoryとAFPサービスを同一のサーバ上で運用する場合はデフォルトの「LDAPv3/127.0.0.1」のままでかまいません。
     負荷分散のためにOpenDirectoryとAFPサービスを別々のサーバで運用する場合は、まずAFPサービスを稼働させるサーバをOpenDirectoryサーバに「ディレクトリアクセス」を使ってバインドしておきます。こうすればAFPサーバ上で「ワークグループマネージャ」を使ってネットワークマウントの設定を行うときに「場所」ポップアップメニューにOpenDirectoryのサーバがリストアップされ、マウントレコードの保存場所として選択することができます。

    適切な場所を選択したら次に「この共有ポイントのネットワークマウントを使用する」のチェックを入れます。ネットワークマウントのプロトコルを選択できますが、今回はMac同士でファイル共有を行いますので「AFP」を指定しておきます。
     「用途」は「ユーザのホームディレクトリ」を選択します。用途の選択でクライアント上のどこに共有ポイントがマウントされるかが決まります。
     以上でネットワークホームのためのネットワークマウントの設定が完了しました。最後に画面右下の「保存」ボタンをクリックするとOpenDirectory上にマウントレコードが書き込まれます。

    ・ネットワークマウントの設定
    http://homepage.mac.com/htabata/MXS10.3/img/WGM_Sharing/WGM_Mount_03.png

     ディレクトリサービスを使ってサーバにアクセスするように設定済みのクライアントは、サーバ上(OpenDirectory上)に書き込まれたマウントレコードを読み取って自動的に共有ポイントをマウントします。
     以上がネットワークマウントの設定方法です。それでは、次回は各ユーザごとのホームの設定とホームディレクトリの作成について解説します。

    つづく

    藤本裕之のプログラミング夜話 #104

     前回まではもっぱら受け身、データをドラッグ&ドロップされる側のやり方を解説してきたわけだが、普通にアプリケーションを開発していればもちろん逆の送り側、すなわちドラッグの出発点になりたい局面も生じるわけ。世の中はやはりギブ&テイクなんであって、財布を落とす不幸なひとがいるからそれを拾う幸運なひとが生じるのである。……もちろん世の中にはちょっとエレベータのボタン押すだけで15,000円も稼いぢゃう広告代理店のヒトとかそういうのもいるわけなので、イマイチ例えが説得力を欠くような気がしないでもないが、まぁ俗世間はどうか知らぬがプログラムはそうありたいもんですな、と。

    あるビューが自分自身や他のビュー、はたまた他のアプリケーションに対して提供しうるデータを持っていて、その受け渡しをドラッグ&ドロップで可能にしたいとする。既に我々はこうしたデータを受け取る術を知っているので、送り出し側がやるべきシゴトも容易に想像がつくはずだ。すなわち、ドラッグが始まったらデータをドラッグ用のペーストボードにセットしてやればいい、のである。以下にビュー上でドラッグが始まったらやみくもに「Data to be dragged」という文字列を送り出すという全く実用性のないサンプルを示す。

    @implemantation MyView
    
    - (void) awakeFromNib {  /* わしは文字列をドラッグするよ、と宣言 */
         [self registerForDraggedTypes:
               [NSArray arrayWithObject:NSStringPboardType]];
    }
    
    - (void)mouseDown:(NSEvent*)theEvent {
         _dragging = NO;          /* これはインスタンス変数 */
    }
    
    - (void)mouseDragged:(NSEvent*)theEvent {
         if(_dragging == NO){     /* まだドラッグしてなければ...     */
              NSString*      toBeDragged = @"Data to be dragged";
              NSPasteboard*  pb =
                   [NSPasteboard pasteboardWithName:NSDragPboard];
              [pb declareTypes:
                   [NSArray arrayWithObject: NSStringPboardType] owner:self];
              [pb setString:toBeDragged forType:NSStringPboardType];
    
              NSImage*  anImage =
                    [[[NSImage alloc] initWithSize:
                        [toBeDragged sizeWithAttributes:
                        [NSDictionary dictionary]]] autorelease];
              [anImage lockFocus];
              [toBeDragged drawAtPoint:NSMakePoint(0,0)
                             withAttributes:[NSDictionary dictionary]];
              [anImage unlockFocus];        /* ドラッグするイメージを作成 */
    
              [self dragImage:anImage
                   at:[self convertPoint:
                        [theEvent locationInWindow] fromView:nil]
                   offset:NSMakeSize(0,0)   /* Tiger以降は無視する */
                   event:theEvent
                   pasteboard:pb
                   source:self
                   slideBack:YES];     /* そのイメージをセットする */
    
              _dragging = YES;    /* ただいまドラッグ中 */
         }
    }
    
    /* この他、- (id)initWithFrame:frameRect: とか - (void)drawRect:とか
    必要なメソッドはちゃんと定義されてあるものとする */
    @end
    


     これしきのこと、と思えば大層なコードに見えるがクラシックシステムのときのドラッグ&ドロップのインプリメントを考えれば「ホントにこんだけでいいの?」というくらい簡単になったんである。それでは最初から解説を……と思ったが、もう所定の行数ではないか。中途半端になるのも困るので解説は次回。上のリストの再録はしないので(してたら毎回ほんの少ししか進めない)、その気のあるひとは取っておくこと。
    (2006_12_01)

    高橋真人の「プログラミング指南」第102回

    プログラマのためのオブジェクト指向再入門(10)

    〜カプセル化について(1)〜

     こんにちは、高橋真人です。
     今までクラスという仕組みを使って、「機能を持ったデータの固まり」としてのオブジェクトの片鱗を見てきました。しかし、そもそもプログラムというのは詰まるところコードの固まりであって、「それがオブジェクトというまとまりを持ったからといって、何が面白いんだ?」という疑問を持たれる方もいらっしゃることと思います。
     連載の96回では、オブジェクトを利用するメリットの一つとして「処理の詳細を隠してしまえる」というお話を少ししました。今回は、この話をもう少し広げていきたいと思います。

    最近、私が仕事で取り組んでいるものの一つにMLTEがあります。MLTEは、2000年にTextEditの制約を打ち砕く新しい技術として登場した仕組みです。TextEditには32kの壁などという有名なものから始まり、テキスト編集の仕組みとして登場してから随分経ったため、時代遅れになった部分が数多くあり、足りない部分はすべてプログラマが一つ一つ組み込んで行かなければならなかったのです。
     そんなTextEditの置き換えとして登場したMLTEの機能についてかいつまんで紹介しますと、日本語のインライン入力、テキストのドラッグアンドドロップ、複数の書体・サイズ・カラーの混在した表示などを最初からサポートし、テキスト編集はもちろんのこと、無限回数のアンドゥやリドゥなども標準で備えているのです。

    私が仕事で作っているアプリケーションの一つに、ずっとPowerPlant(*注)で作ってきたものがあります。最初のリリースは2000年で、Mac OS 9用のアプリでした。
     ユーザーの環境が徐々にOS Xに移行してきたのに合わせ、Carbon化を行い、細々とした機能追加要求などを受けてメンテナンスを続けていますが、この度少し大きなユーザーからの要求があったため、Cocoaによる作り直しも含めいろいろな対策を検討しました。
     結果として作り直しは見送ったものの、OS Xでしか使われない今となっては意味がなかったり無駄だったりする部分も少なくないため、内部設計の一部変更も含めていろいろと手を入れていたのです。
     そのアプリにはテキスト編集エリアがあって、ここはこのアプリのUIの中では中心になる部分なので、それなりにしっかりと作り込む必要があります。もともとはPowerPlantのLTextEditViewというクラスに若干の拡張を加えて実現していました。しかし、PowerPlant自体が日本語編集で抱える問題点や、私自身の拡張のやり方のまずさなどから、ちょっとしたバグも抱えていたため、この際思い切ってこれをLMLTEPaneという、PowerPlantがMLTEを使うために用意したクラスを利用することとしたのです。
     LMLTEPaneは、PowerPlantの末期に加えられたクラスです。その後間もなくPowerPlant自体のバージョンアップが止まってしまったためPowerPlantによって加えられた機能はごくわずかですが、MLTE自体が持つ高機能な仕組みはそのまま利用することができるので、開発の手間はある程度削減できると踏んだのです。
     しかし、問題がなかったわけでもありません。LTextEditViewから作った私のクラスでは、保持するテキストの長さを表示する仕組みがありました。ユーザーが文字編集するのを受けてリアルタイムで文字数を表示します。
     リアルタイムな文字数表示という場合、日本語では変換中の文字数も拾う必要があります。ユーザーによっては、一度に大量の文字を入力したままで変換作業を行う場合もあるからです。
     また、ユーザーからの追加要求として、このテキストフィールドでは改行を含むいくつかの文字が入力できないようにする必要がありました。
     これらの機能は残念ながらMLTEを「そのまま」使っているだけでは実現ができないのです。

    文字数表示に関しては、いろいろ調べて解決できました。InputMethodは、処理の途中でいくつかのCarbonイベントを発行します。よって、アプリケーションでこれらのイベントを捕まえることによって、InputMethodがまだアプリケーションに渡していない(現在変換処理中の)文字列の情報を得ることができるのです。
     しかし、もう一つの問題は難物です(「難物でした」と過去形になっていないのは、今現在でも完全解決に至っていないからです・涙)。InputMethodを介して渡ってくる文字列や、ペーストによって渡されてくる文字列に関しては、同様にCarbonイベントなどによって捕まえることができます。ところが、MLTEが提供しているドラッグアンドドロップの仕組みによって渡ってくるテキストの場合、イベントを通して捕まえることができないのです。
     さんざん調べた挙げ句に見つけた答えは、以下のようなものです。

    ・MLTEが用意しているドラッグアンドドロップのハンドラ(処理関数)をオフにする
    ・MLTEに代わって、自分でドラッグアンドドロップのハンドラを実装する

     この技術を勉強したことのある人はご存知でしょうが、ドラッグアンドドロップを実装するには、二種類の処理をしなければなりません。
     一つはモノをつかんでドラッグを始める処理。グラフィックアプリケーションであれば図形を、Finderであればアイコンを、テキスト編集ソフトであれば選択したテキスト範囲をユーザーがマウスでつかんで動かし始める時に、「ドラッグオブジェクト」を作成し、ドラッグの動作を起動する処理です。
     もう一つは、ユーザーがドラッグによって引っ張ってきたドラッグオブジェクトに反応し、マウスボタンが放されたらそれを受け入れる(または拒否する)処理。
     厳密に言えば、後者もさらに二つの処理に分けられるのですが、まあそれはよしとしましょう。
     しかし、MLTEに対して「ドラッグアンドドロップのハンドラはこっちでやるからね」と伝えるためのフラグを立てると、何故かこの二つの処理を両方ともやめてしまうのです。
     私としては、単にドラッグされてきたデータを受け入れた時にだけ(つまり拒否した場合にはいちいち知らせてくれなくていい)、それを教えてくれさえすれば充分なのに、ドラッグ関係の処理を一斉に放棄してしまうって、一体どういうことなんでしょ?
     この事実を知った時に私はショックの余り、しばらくは何も手に付きませんでした(笑)が、嘆いていても事態は何も動きませんから、ちまちまと必要な処理を組み込んで行きました。
     しかーし、Tiger上では問題なく動く処理が何故かPanther上では怪しい動作になるというバグのせいで、いまだにその回避策をめぐって右往左往を余儀なくさせられている私なのであります。(悲しいかな、未だユーザー環境も開発環境もPantherがメインであります)
     ちょっと、個人的な感情が絡んでしまったために、少し脱線してしまいました(笑)が、現実にアプリケーションを作っている人の悶々とした日常の一シーンが少しは伝わりましたでしょうか?

     「カプセル化の話をする」と言っておいて、単なる仕事の愚痴を連ねたにすぎないと思われた方も多いかもしれませんが、心配はご無用。ちゃんとこの話を元にカプセル化ということについての考察を進めてまいります。
     ただ、行数が多くなりましたので、この続きは次回に。

    注:PowerPlantは、Metrowerks社のCodeWarriorの一部として提供されていたC++言語によるアプリケーションフレームワークです。Mac OS 9の時代には多くの商用アプリケーションで利用され、Carbon対応もなされたために、Mac OS Xになってからもしばらくは使われていましたが、もともとの設計がCarbonイベントモデルではない古いイベントモデルに合わせてあったため、Mac OS X用に全面的に書き換えた新しいフレームワークであるPowerPlant Xとしてさらに発展するはずでした。
     しかし、2005年のAppleのインテルプラットホームへの移行により、MetrowerksとCodeWarriorが終焉を迎えてしまったため、実質的に入手することはできなくなってしまいました。
     ただ、今年の頭にPowerPlantとPowerPlant Xはオープンソースになったため、CodeWarriorのIDE(これは、もはや入手不可能)なしでも使うことができるようになる日が来るかもしれません。もっとも、最初からMach-OであるPowerPlant Xはまだしも、PowerPlant自体をXcode対応にさせるのは、そうそう簡単なことではないような気がしますが。

    ニュース・解説

     今週の解説担当:小池邦人

    ● Carbon ドキュメント & サンプル & SDK ナビゲーション(2006/12/01)

    【開発環境】

    使い始めてかなり時間が経つと言うのに、Xcodeのテキストエディタでソースコードを編集していると、今でも大変ストレスがたまります(涙)。テキストファイルのオープンが遅いとか、Framework APIの文字色が変えられないなどの機能的な不備も多いのですが、バグなのか仕様なのか、とにかくソースコードを編集しているとイライラする事に数多く出くわします。

    複数ファイルの検索と置換がうまくいかないケースが多々あります。検索位置がズレルのです。ソース内に日本語コメントを入れているからという噂もありますが、1ファイル内の検索と置換では問題が出ません。また、失敗したファイルを一度ファイル保存してやるとケロッと直るので、バグのような気もします?

    数値をダブルクリックすると、カンマを挟んだ隣の数値まで選択してしまいます。これは、カンマを金額の3桁区切りと判断しているのが原因だと聞いたのですが、ソースコードエディタにそんな機能必要ないですよね(笑)。引数や配列の羅列でカンマの左右にスペースを入れない作法の私としては、まことに情け無い仕様です。

    ソースコードの一部をカットする場合、行のセレクションの仕方により、前行のCR(キャリジリーターン)までカットしてしまう場合があります。これも、ソースコードの編集では余計なお世話です。複数行をマウスで選択してカットする場合には、前行のCRが消えてしまうと、後方の行が連続して表示されてしまい(インデントが消える)再度CRを入れなくてはいけなくなります。また、カット部分の先頭にCRが入っていると、ペースト後にも余分な編集が必要となります。

    まだまだ色々とあるのですが…Metrowerks CodeWarriorのテキストエディタを利用している時は、こんなにもストレスは溜まりませんでした。Apple社の技術者は平気で使っているのかな? それとも、さっさとエディタ部を差し替えているのかな? Xcode 3.0ではいくらかマシになっているのを祈りましょう。もしくは、上記問題の解決方法をご存じの方は、ぜひお教えくださいませ(エディタを代えるという手段以外で…)。

    【テクニカルドキュメント】

    前回から12月1日の期間中、Apple社のGuidesサイトとReferenceのサイトには新規登録はありませんでした。そのかわり、デベロッパ向けの読み物がひとつ登録されています。CoreGraphicsに含まれるImageIO Frameworkの各ルーチンとそのサンプルソースコードが解説されています。今まで色々な画像ファイルフォーマット(JPEGやTIFFなど)をオープンする場合には、QuickTimeのImageCompression関連のルーチンを利用していたのですが、ImageIOルーチンを利用すると各社デジタルカメラのRAW画像フォーマットもオープンできるようです。ドキュメントには、Mac OS X 10.4.8でオープン可能な画像ファイルフォーマットの一覧も掲載されています。ただし、どの画像フォーマットが読み込めるかについては、Mac OS Xのバージョンに随分と依存するようなので注意が必要かもしれません。それにしても、テクニカルノートとして登録されても良さそうな内容ですね。

    「Using the ImageIO Framework with Mac OS X 10.4 Tiger」(読み物)

    http://developer.apple.com/graphicsimaging/workingwithimageio.html

    前回から12月1日の期間中、新規テクニカルノートはひとつも登録されませんでしたが、新規テクニカルQ&Aの方は6つ登録されました。テクニカルQ&Aについては、前号で木下さんが解説されていますので、そちらも参照してみてください。

    QA1496「Configuring the Recent Searches menu for NSSearchField」(初版)
    QA1497「FSDeleteObject fails with fBsyErr, sometimes」(初版)
    QA1500「Debugging a Web Kit Plug-in in Xcode」(初版)
    QA1387「Integrating With The Connect to Server Dialog」(初版)
    QA1499「Security Framework Error Codes」(初版)
    QA1390「Standard Audio – The CodecSpecificSettings- Array and MagicCookie properties」(初版)

    http://developer.apple.com/technicalqas/index-rev-date.html

    【サンプルソースコード】

    前回から12月1日の期間中、Apple社のSample Codeサイトには、サンプルソースコードが3つ登録されました。

    「SetMouseAcclSample」(HID&Cocoa関連)(初版)
    「MovieAssembler」(FinalCutPro関連)(初版)
    「tcplognke」(Network関連)

    http://developer.apple.com/samplecode/index-rev-date.html

    【デベロップメント SDK】

    前回から12月1日の期間中、Apple社のSDKサイトには新しいSDKがひとつも登録されませんでした。

    http://developer.apple.com/sdk/

     

    ◇MOSAからのお知らせと編集後記は割愛します◇

     MOSA Developer News   略称[MOSADeN=モサ伝]
          記事投稿受付 http://www.mosa.gr.jp/topics/mdn-toukou.html
    Apple、Mac OSは米国アップルコンピュータ社の登録商標です。またそのほかの各製品名等はそれぞれ各社の商標ならびに登録商標です。
    このメールの再配信、および掲載された記事の無断転載を禁じます。
    特定非営利活動法人MOSA  http://www.mosa.gr.jp/
    Copyright (C)2006 MOSA. All rights reserved.