当ブログに掲載しているサンプルは、すべて利用者の自己責任という形でお願いします。
ただし、明らかな不具合がある場合、ご連絡いただければ、訂正記事を出します。
また、こちらのサンプルは、別のサイト等への公開、転載は一切禁止しています。
どうしてもと言う場合は、筆者にあらかじめご連絡ください。
記事そのもののリンクについてはご自由に行っていただいてよいです。

テクてく Lotus 技術者 Slack に参加しよう!

2008年6月27日金曜日

フォームと文書の関係

フォームにはフィールドを作成することができる。
文書はフォームのフィールドに入力することで作成できる。

これらは一見すると同じもののように見えるが、当然のごとく違うものである。

フォームはフィールドを配置してある図面のようなもので、中には何もない。
文書は単なる内容を集めたものである。

文書自身は通常、表現能力を持たないためフォームの表現能力を借りて画面上に表示しているのである。

そのため、フォームが適切でないと文書が正しく表示できないことがある。

フォームには「a」「b」「c」というフィールドがあり、文書は「b」「c」「d」というフィールドに内容を持っているとする。
すると、この文書をフォームで表示した場合、「b」と「c」は正しく表示される*1が、「d」は表示できない。
また、「a」という余計なフィールドが表示される。

*1もっともフィールドの形式が適切でなければ正しく表示はできないが・・・

このとき、「a」が単なる編集可能フィールドなら大した問題ではないが、計算結果フィールドの場合、ちょっと面倒なことになる。
「a」の計算結果を表示してしまうからである。
これによって、実際の文書には存在しない「a」というフィールドがさも存在するかのように見えてしまうのである。


このことはスクリプトのNotesDatabaseクラスのCreateDocumentメソッドを使って文書を作成してみると、よく分かる。
スクリプトの場合、そのスクリプトの中でフィールドに代入しないとフィールドの値が作成されないのである。

また、文書にそのフィールドが存在するかどうかは、ビュー上で文書のプロパティを見るとわかりやすい。
ビューでは、その文書で持っているフィールドしか表示しないからである。
文書をフォーム上で表示してしまうと、文書のプロパティは「フォームのフィールドのプロパティ」+「文書の内容のプロパティ」という内容に変わってしまうのである。


余談になるが、「表示用の計算結果」もビューでは見えない。これは、「表示用の計算結果」は実体を持たないフィールドであるからだ。
そのため、文書の内容自体を表示するビュー上での文書のプロパティでは、見えないと言うことになる。


スクリプトのバックグラウンドで文書を作成すると、フィールドの属性も無視してしまう。スクリプトの中で与えた形式を属性として認識するのである。
たとえば、「c」というフィールドは数値属性であるが、スクリプトでは「文字列」を代入する。
これでも保存はできてしまうのだ。さらにそのフォームを使って文書を表示することもできる。その場合、「c」フィールドは文字列のフィールドという扱いで表示される。

ただし!そこでF9などを押して再計算をさせると、当然エラーになるので注意が必要である。

2008年6月24日火曜日

バックグラウンドで返答文書を作成する

自動で、現在の文書の返答文書を作成するサンプル。
関連するデータの登録や、主文書は変更したくないので追加で文書を作成する
という時などに利用するとよい。

-------------------------------------------------------------------------------------
Sub Click(Source As Button)
Dim session As New NotesSession
Dim db As NotesDatabase
Dim uiws As New NotesUIWorkspace
Dim uidoc As NotesUIDocument
Dim doc As NotesDocument
Dim resdoc As NotesDocument

'自文書の設定
Set db = session.CurrentDatabase
Set uidoc = uiws.CurrentDocument
Set doc = uidoc.Document

'新規に文書を作成した後、返答文書として位置づける
Set resdoc = db.CreateDocument
Call resdoc.MakeResponse( doc )

'スクリプトで文書を作成した場合、フィールドに何も設定されないので自分で設定する
resdoc.Form = "Response"
resdoc.Subject = "バックグラウンドで作成した返答文書"

'文書の保存
Call resdoc.Save( True , True )
End Sub

2008年6月19日木曜日

アップデート試験延長!

http://guylocke.blogspot.com/2008/04/blog-post_19.html
の記事で、2008/06/06にNotes8のアップデート試験を受験する!と書いたが、諸事情により延期しました。

いやぁ、そんな場合じゃないって。
まだNotes8の仕事なんかしてないから(日本IBMさん、ごめんなさい)、試験どころじゃないよ。
と言いつつ、6/27に延期したのですが。

さて、こんな状態で受験できるかわからないけど、1日も早くアップデートしないといけないからね。
LotusDay2008までには受かっていたいな。

DB中の各フォームのフィールド一覧

ノーツDBのフォームにどのようなフィールドが存在しているのかを調べる方法です。
ノーツ文書ではなく、フォームのフィールドというところがミソ。

サンプルは、現在のノーツDBの各フォームに作成されているフィールドの一覧を表示するものである。

----------------------------------------------------------------------------------------------
Sub Click(Source As Button)
Dim session As New NotesSession
Dim db As NotesDatabase
Dim title As String
Dim sbj As String

Set db = session.CurrentDatabase

'xはNotesFormクラスが返される
Forall x In db.Forms
'x.Nameはフォーム名が返される
title = x.Name
sbj = ""
i = 0
'yにはxフォームのフィールド名が入る
Forall y In x.FIelds
i = i + 1
sbj = sbj & Cstr( i ) & "." & y & Chr$(10)
End Forall
Messagebox sbj, 0, "【" & title & "】のフィールド一覧"
End Forall
End Sub

2008年6月18日水曜日

添付ファイルをディスクに保存する

ノーツ文書にファイルを添付することや、添付してあるファイルを削除するというサンプルは紹介していたが、
ローカルディスクに保存するというサンプルを提供していなかった。

下記のサンプルでいえば、
Call x.ExtractFile( res & x.Name )
がそうなのだが、変わったことが可能である。

保存する際、好きな名前で保存できるのである。
同一文書内に、同じ名前のファイルが存在している場合に、ファイル名を変更して保存できる。
という具合に使うことが可能である。





Sub Click(Source As Button)
    Dim uiws As New NotesUIWorkspace
    Dim uidoc As NotesUIDocument
    Dim doc As NotesDocument
    Dim item As Variant
    
    '現在の文書を取得する
    Set uidoc = uiws.CurrentDocument
    Set doc = uidoc.Document
    '添付ファイルがあるフィールドを取得する
    Set item = doc.GetFirstItem( "Body" )
    
    'フィールドが本当にリッチテキストかどうかを判断する(添付ファイルはリッチテキストにしかないので)
    If item.Type = RICHTEXT Then
        if doc.HasEmbdedd then
            Forall x In item.EmbeddedObjects
                'オブジェクトが添付ファイルかどうかを判断する(OLEオブジェクトとは扱いが異なるため)
                If x.Type = EMBED_ATTACHMENT Then
                    res = Inputbox ( "添付ファイルを保存するパスを入力してください。", "添付ファイルの保存箇所", "c:\" )
                    If res = "" Then
                        Messagebox "添付ファイルは保存されません。", 0 + 48, "添付ファイルの保存"
                    Else
                        'ここで添付ファイルを保存するが、どこのpathに保存するかを指定しておく必要がある
                        Call x.ExtractFile( res & x.Name )
                        Messagebox "添付ファイルは、" & res & x.Name & "に保存されました。", 0, "添付ファイルの保存"
                    End If
                End If
            End Forall
        Else
        Messagebox "文書に添付ファイルがありません。", 0, "添付ファイルの保存"
        End If
    End If
End Sub




2008年6月17日火曜日

ノーツデータベースの一覧を表示する

ディレクトリに存在するノーツDBの一覧を取得するサンプルを用意した。
カタログDBに出力していないものや「データベースを開く」ダイアログに表示しないDBも取得できる。
隠れたDBがいそうだな?と思ったら使うとよい。

---------------------------------------------------------------------------------------------------------
Sub Click(Source As Button)
'データベースの一覧の変数の定義
Dim session As New NotesSession
Dim directory As NotesDbDirectory
Dim db As NotesDatabase

'プログラム変数の定義
Dim res As String
Dim sbj As String
Dim i As Integer

'データベースの一覧を取得する場所を選択する
res = Inputbox ( "サーバー名を入力してください。" & Chr$(10) & "loaclの場合はローカルコンピュータを参照します。",_
"データベースの一覧", "local" )
'キャンセルを押した場合は処理を中断、localの場合はNULLに変換
If res = "" Then
Exit Sub
Elseif res = "local" Then
res = ""
End If
Set directory = New NotesDbDirectory( res )

i = 0
'最初のデータベースを取得する
Set db = directory.GetFirstDatabase( DATABASE )
'データベースを全部取得するまで繰り返す
Do While Not (db Is Nothing )
i = i + 1
sbj = sbj & Cstr( i ) & "." & db.Title & " ; " & db.FilePath & Chr$(10)
'dbの次のデータベースを取得する(GetFirstDatabaseとペアで使うこと)
Set db = directory.GetNextDatabase
Loop

'NULLの場合はローカルなので、「ローカルコンピュータ」を代入する
If res = "" Then
res = "ローカルコンピュータ"
End If
Messagebox sbj, 0, res & "のデータベースの一覧"
End Sub

2008年6月12日木曜日

DBオープン時のエラーハンドリング

DBをオープンするときに、エラーハンドリングを行うと思うが、DBが存在しない場合とDBにアクセスできない場合とでエラーの種類が違う。
わかりやすいのが、NotesSessionクラスのGetDatabaseメソッド。

DBが存在しない場合は、NotesDatabaseオブジェクトをNothingとして返すが、
存在していてなおかつ、アクセスできない場合は、Err4060を返すのである。
もちろん、DBが存在していてなおかつ、アクセスできる場合は、NotesDatabaseオブジェクトを返す。

2008年6月11日水曜日

区切り文字による文字列の抜き出し

特定の区切り文字で区切られた文字列であれば、その部分を抜き出すことが出来る。
サンプルは、文字列を","で区切って、その中のx番目の文字列を抜き出すというもの。
フィールドの設定を誤ってしまい、複数値フィールドにならなかったときなどのメンテナンス用に持っておくとよいだろう。

TMP := "一番目の文字列,二番目の文字列,三番目の文字列,四番目の文字列";
@Prompt([OK];"元の文字列";TMP);

TMP1 := @Prompt([OKCANCELLIST];"選択";"表示する文字列の箇所を選択してください。";"1";"1":"2":"3":"4");

REM "TMP文字列を「,」で区切った内のTMP1番目の文字列を抜き出すという関数
TMP2 := @Word(TMP;",";@TextToNumber(TMP1));

@Prompt([OK];"抜き出した文字列";TMP2)

ただし、区切り文字がデータとして存在しているような場合は注意が必要。

2008年6月5日木曜日

フォルダの作成

今回のサンプルは、Lotus Scriptでフォルダを作成するというもの。
1階層であれば、Mkdir フォルダ名で作成できるが、それでは芸がない。
ということで、複数階層のフォルダを作成するということにチャレンジしたい。
MkDirでは、上位階層のフォルダが存在しないと、下位のフォルダは作成できない。

なので、各階層ごとにフォルダが存在しているかどうかのチェックをする必要がある。
それを踏まえたサンプルである。
なお、サンプル内では省略したが、次のことにも注意しておきたい。
すでに存在しているフォルダを作成しようとすると、MkDirはエラーの75を返す。
On Errorで判断して、75の時はスキップするようにするとよいだろう。

-------------------------------------------------------------------
Sub Click(Source As Button)
Dim dirname As String
Dim ret As Integer

dirname = "c:\abcde\hijkl\"

Msgbox dirname & "のフォルダを作成します。"

'1つ目を探す
ret = Instr( dirname, "\" )

'n個目を探す
Do While ret <> 0
ret = Instr( ret+1, dirname, "\" )
If ret <> 0 Then
Mkdir Left(dirname, ret)
End If
Loop
End Sub

2008年6月4日水曜日

@Command([EditDocument])のノーツとブラウザでの利用方法の違い

@Command([EditDocument])という@コマンドがあるが、ノーツとブラウザでは書式に違いがあることに気をつけて欲しい。


@Command([EditDocument])
 この場合、文書を「編集モード」←→「読み込みモード」に切り替える。

@Command([EditDocument];"1")
 この場合、文書を「編集モード」に変更する。

@Command([EditDocument];"0")
 この場合、文書を「読み込みモード」に変更する。


というのが、ノーツ上での動作だが、
ブラウザ上では、
@Command([EditDocument])しか有効にならない。

ブラウザ上ではこのコマンドは、「文書を編集モードにする」だけのものなのであるためだ。
(であれば、"1"のオプションは有効になっても良さそうだが、しっかりとエラーになる)

※これらのコマンドをフォームアクションに登録して、DBのオプションで「Javaスクリプトを利用する」のチェックを外すとよく分かる。
 →オプションなしは表示されるが、オプションありは表示されないのである(実行できないコマンドは表示しないと言うルールがある)


※これは、オンラインヘルプに出ていない内容なので忘れがちだが、利用時には注意が必要。

2008年6月3日火曜日

グループの階層化の限界数

ノーツ/ドミノでは、グループの中にグループを作るという階層化を実現することが可能である。
さて、その階層数には限界がある。

R5/6/7ともに共通で、20階層である。
それを超えると、エラーになる。


エラーメッセージはこんな感じ。

「グループはメール送信の場合、20レベル以上の階層にすることはできません。」

2008年6月2日月曜日

ビューから編集モードで開かせない

ビューから直接編集モードで開かれては困る場合などにそれを制御する方法。

FormのQueryOpenイベントに下記のスクリプトを記述する。
ここで、Queryopenイベントに定義してある変数を利用すると簡単に書ける。

Source 現在開かれている文書
Mode 現在の文書のモード。読み取りモードなら0、編集モードなら1が入っている
Isnewdoc 現在の文書が新規文書かどうか。新規文書ならTrue、そうでなければFalseが入っている
Continue 処理を続けるかどうか。止める場合はFalseを代入すると良い

Sub Queryopen(Source As Notesuidocument, Mode As Integer, Isnewdoc As Variant, Continue As Variant)
    '新規文書でなく、編集モードで開かれた場合は確認のメッセージを表示する
    If Isnewdoc = False And Mode = 1 Then
        res = Messagebox( "編集モードで開くのですか?", 4 + 32, "スクリプトサンプル集" )
        '「いいえ」が選択された場合は、処理を中断する
        If res = 7 Then
            Continue = False
        End If
    End If
End Sub