001/*
002 * Copyright (c) 2009 The openGion Project.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
013 * either express or implied. See the License for the specific language
014 * governing permissions and limitations under the License.
015 */
016package org.opengion.hayabusa.taglib;
017
018import org.opengion.hayabusa.common.HybsSystem;
019import org.opengion.hayabusa.common.HybsSystemException;
020import org.opengion.fukurou.util.XHTMLTag;
021import org.opengion.fukurou.util.Attributes;
022import org.opengion.fukurou.util.ToString;                                              // 6.1.1.0 (2015/01/17)
023import org.opengion.fukurou.util.ArraySet;                                              // 6.4.3.4 (2016/03/11)
024
025import static org.opengion.fukurou.util.StringUtil.nval ;
026
027import java.io.File;
028import java.io.FileFilter;
029import java.io.Serializable;
030import java.util.Set;                                                                                   // 6.4.3.4 (2016/03/11)
031import java.util.Arrays;
032import java.util.Comparator;
033
034/**
035 * ファイルのプルダウンリストの作成するタグです。
036 *
037 * SelectタグのBODY部に指定します。
038 * 並び替えについては、このタグで指定しますが、ファイルの選別は、
039 * BODY 部に記述する fileWhere タグで指定します。
040 *
041 * @og.formSample
042 * ●形式:<og:fileOption from="…" value="[…]" ・・・ >・・・</og:fileOption>
043 * ●body:あり(EVAL_BODY_BUFFERED:BODYを評価し、{@XXXX} を解析します)
044 *
045 * ●Tag定義:
046 *   <og:fileOption
047 *       from               【TAG】ファイルの検索元となるディレクトリを指定します (初期値:FILE_URL[=filetemp/])
048 *       value              【TAG】Optionの初期値で選ばれる値を指定します
049 *       useDir             【廃止】(廃止:7.2.6.0 (2020/06/30))optionリストの作成を、ディレクトリの値で行います。
050 *       nameOnly           【TAG】ファイルの拡張子を除いた名前部分のみの値で行います。7.2.4.0 (2020/05/11)
051 *       groupDir           【TAG】optgroupを、ディレクトリの値で作成します(1レベルのみ)。
052 *       orderBy            【TAG】検索した結果を表示する表示順をファイル属性名で指定します(初期値:自然順序)
053 *       desc               【TAG】表示順を逆転するかどうか[true/false]を指定します(初期値:false)
054 *       caseKey            【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null) 6.8.0.0 (2017/06/02)
055 *       caseVal            【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null) 6.8.0.0 (2017/06/02)
056 *       caseNN             【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:判定しない) 6.8.0.0 (2017/06/02)
057 *       caseNull           【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:判定しない) 6.8.0.0 (2017/06/02)
058 *       caseIf             【TAG】指定の値が、true/TRUE文字列の場合は、このタグは使用されます(初期値:判定しない) 6.8.0.0 (2017/06/02)
059 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
060 *   >   ... Body ...
061 *   </og:fileOption>
062 *
063 * ●使用例
064 *      ・<og:fileOption val1="ABCD" val2="{@value}" >
065 *            <og:fileWhere startsWith="ABCD" ・・・ />
066 *        </og:fileOption>
067 *
068 * @og.rev 2.1.1.0 (2002/11/11) 新規作成
069 * @og.rev 4.0.0.0 (2005/01/31) 内部ロジック改定
070 * @og.group その他入力
071 *
072 * @version  4.0
073 * @author   Kazuhiko Hasegawa
074 * @since    JDK5.0,
075 */
076public class FileOptionTag extends CommonTagSupport {
077        /** このプログラムのVERSION文字列を設定します。   {@value} */
078        private static final String VERSION = "7.2.6.0 (2020/06/30)" ;
079        private static final long serialVersionUID = 726020200630L ;
080
081        private String          orderBy         ;                               // ソート項目
082//      private boolean         useDir          ;                               // 6.3.4.0 (2015/08/01) 7.2.6.0 (2020/06/30) useDIR 属性 廃止
083        private boolean         nameOnly                ;                       // 7.2.4.0 (2020/05/11)
084        private boolean         groupDir        ;                               // 6.3.4.0 (2015/08/01)
085        private boolean         desc            ;                               // 降順フラグ
086        private String      from                = HybsSystem.sys( "FILE_URL" ); // 検索起点ファイル
087        private String          selValue        ;                               // 選択済み初期値にする場合
088        private transient       FileFilter      filter  ;               // FileWhere で指定したフィルター
089
090        // 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
091        private static final Set<String> ORDER_BY_SET = new ArraySet<>( "NAME","LASTMODIFIED","FILE_LENGTH","LENGTH" );
092
093        /**
094         * デフォルトコンストラクター
095         *
096         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
097         */
098        public FileOptionTag() { super(); }             // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
099
100        /**
101         * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
102         *
103         * @og.rev 6.8.0.0 (2017/06/02) caseKey,caseVal,caseNN,caseNull 属性を追加
104         *
105         * @return      後続処理の指示( EVAL_BODY_BUFFERED )
106         */
107        @Override
108        public int doStartTag() {
109                // 6.8.0.0 (2017/06/02) caseKey,caseVal,caseNN,caseNull 属性を追加
110                return useTag() ? EVAL_BODY_BUFFERED : SKIP_BODY ;
111        }
112
113        /**
114         * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。
115         *
116         * @return      後続処理の指示(SKIP_BODY)
117         */
118        @Override
119        public int doAfterBody() {
120                return SKIP_BODY ;
121        }
122
123        /**
124         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
125         *
126         * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
127         * @og.rev 6.3.4.0 (2015/08/01) useDir 属性と、groupDir 属性 を追加します。
128         * @og.rev 6.8.0.0 (2017/06/02) caseKey,caseVal,caseNN,caseNull 属性を追加
129         *
130         * @return      後続処理の指示
131         */
132        @Override
133        public int doEndTag() {
134                debugPrint();           // 4.0.0 (2005/02/28)
135                // 6.8.0.0 (2017/06/02) caseKey,caseVal,caseNN,caseNull 属性を追加
136                if( useTag() ) {
137                        final OptionAncestorIF select = (OptionAncestorIF)findAncestorWithClass( this, OptionAncestorIF.class );
138                        if( select == null ) {
139                                final String errMsg = "<b>" + getTagName() + "タグは、SelectTag または、DatalistTag のBODY に記述する必要があります。</b>";
140                                throw new HybsSystemException( errMsg );
141                        }
142                        final Comparator<File> comp = makeComparator( orderBy,desc );
143        //              makeLabel( select,comp );
144                        makeLabel( new File( from ) , select , comp , groupDir );
145                }
146
147                return EVAL_PAGE ;
148        }
149
150        /**
151         * タグリブオブジェクトをリリースします。
152         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
153         *
154         * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
155         * @og.rev 6.3.4.0 (2015/08/01) useDir 属性と、groupDir 属性 を追加します。
156         * @og.rev 7.2.4.0 (2020/05/11) nameOnly 属性 を追加します。
157         * @og.rev 7.2.6.0 (2020/06/30) ディレクトリ処理を統一します。
158         */
159        @Override
160        protected void release2() {
161                super.release2();
162                orderBy         = null;         // ソート項目
163//              useDir          = false;        // 6.3.4.0 (2015/08/01) 7.2.6.0 (2020/06/30)
164                nameOnly        = false;        // 7.2.4.0 (2020/05/11)
165                groupDir        = false;        // 6.3.4.0 (2015/08/01)
166                desc            = false;        // 降順フラグ
167                from            = HybsSystem.sys( "FILE_URL" );
168                filter          = null;
169                selValue        = null;
170        }
171
172        /**
173         * オプションを作成します。
174         *
175         * ファイル名を "value" に、
176         * BODY属性 に登録するOptionを作成します。
177         *
178         * @og.rev 5.3.4.0 (2011/04/01) FILE_LENGTH 追加
179         *
180         * @param       orderBy ソートする属性 [NAME/LASTMODIFIED/FILE_LENGTH/LENGTH]
181         * @param       desc    並び順 [true:昇順/false:降順]
182         *
183         * @return      ファイル比較用のComparatorオブジェクト
184         */
185        private Comparator<File> makeComparator( final String orderBy,final boolean desc ) {
186                if( orderBy == null ) { return null; }
187
188                Comparator<File> comp = null ;
189
190                if( "NAME".equalsIgnoreCase( orderBy ) ) {
191                        comp = new NameComparator( desc );
192                }
193                else if( "LASTMODIFIED".equalsIgnoreCase( orderBy ) ) {
194                        comp = new ModifiedComparator( desc );
195                }
196                // "LENGTH" を残すのは、互換性のため
197                else if( "FILE_LENGTH".equalsIgnoreCase( orderBy ) || "LENGTH".equalsIgnoreCase( orderBy ) ) {
198                        comp = new LengthComparator( desc );
199                }
200
201                return comp ;
202        }
203
204        /**
205         * オプションを作成します。
206         *
207         * ファイル名を "value" と、BODY属性 に登録するOptionを作成します。
208         *
209         * @og.rev 3.8.0.9 (2005/10/17) 複数選択可能時に全選択を設定する。
210         * @og.rev 6.3.4.0 (2015/08/01) useDir 属性と、groupDir 属性 を追加します。
211         * @og.rev 6.8.0.0 (2017/06/02) フォルダ内のファイルが無い場合は、階層に加えない。
212         * @og.rev 7.2.4.0 (2020/05/11) nameOnly 属性 を追加します。
213         *
214         * @param       path    処理の開始パス名(ディレクトリ)
215         * @param       select  SelectTagオブジェクト
216         * @param       comp    並び順を指定するためのComparatorオブジェクト
217         * @param       grpDir  フォルダ階層を、optgroup タグで表すかどうか [true:階層/false:1層]
218         * @return      フォルダ内のファイルが無い場合は階層に加えないためのフラグ [true:階層/false:ファイルなし]
219         */
220        private boolean makeLabel( final File path , final OptionAncestorIF select , final Comparator<File> comp , final boolean grpDir ) {
221
222                final File[] list = path.listFiles( filter );
223
224                final boolean multipleAll = select.isMultipleAll();             // 3.8.0.9 (2005/10/17)
225                if( list != null )  {
226                        Arrays.sort( list, comp );
227                        boolean isSet = false;                                                          // 6.8.0.0 (2017/06/02)
228                        for( int i=0; i<list.length; i++ ) {
229//                              final String value = list[i].getName();
230                                String value = list[i].getName();                               // 7.2.4.0 (2020/05/11) 書き換える
231                                // 6.3.4.0 (2015/08/01) useDir 属性と、groupDir 属性 を追加
232                                if( grpDir && list[i].isDirectory() ) {
233                                        select.addOption( "<optgroup label=\"" + value + "\">" );
234                                        if( makeLabel( list[i] , select , comp , false ) ) {    // リストに追加されたかどうかを判定します。
235                                                select.addOption( "</optgroup>" );
236                                                isSet = true;                                                           // 6.8.0.0 (2017/06/02)
237                                        }
238                                        else {
239                                                select.removeLast();                                            // 6.8.0.0 (2017/06/02) リストに追加されなかった場合は、最後に追加した optgroup を削除します。
240                                        }
241
242                                        continue;
243                                }
244//                              // 7.2.6.0 (2020/06/30) useDIR 属性 廃止
245//                              else {
246//                                      // ディレクトリ時のuseDir=true と、ファイル時useDir=false でない場合( XOR )時は、処理しない。
247//                                      if( list[i].isDirectory() ^ useDir ) { continue; }
248//                              }
249
250                                // 7.2.4.0 (2020/05/11) nameOnly 属性 を追加します。
251                                if( nameOnly ) {
252                                        final int ad = value.lastIndexOf( '.' );
253                                        if( ad >= 0 ) { value = value.substring( 0,ad ); }
254                                }
255
256                                // 6.1.1.0 (2015/01/17) Attributesの連結記述
257                                final String selected = ( selValue != null && selValue.equalsIgnoreCase( value ) ) || multipleAll
258                                                                                        ? "selected" : null ;
259
260                                select.addOption(
261                                        XHTMLTag.option(
262                                                new Attributes()
263                                                        .set( "value"   , value )
264                                                        .set( "selected", selected )
265                                                        .set( "body"    , value )
266                                        )
267                                );
268                        }
269                        return isSet;   // 6.8.0.0 (2017/06/02)
270                }
271                return false;           // 6.8.0.0 (2017/06/02) フォルダ内のファイルが無い場合は、階層に加えない。
272        }
273
274        /**
275         * 【TAG】Optionの初期値で選ばれる値を指定します。
276         *
277         * @og.tag
278         * キーになるのは、ファイル属性の NAME です。(ディレクトリなしのファイル名)
279         * ここで value属性に指定した場合、このファイル名と(大文字小文字を無視して)
280         * 一致する場合に、プルダウンの初期値に表示されます。(selected 属性が設定される。)
281         *
282         * @param   val  初期値で選ばれる値
283         */
284        public void setValue( final String val ) {
285                selValue = nval( getRequestParameter( val ),selValue );
286        }
287
288        /**
289         * 【廃止】optionリストの作成を、ディレクトリの値で行います(初期値:false)。
290         *
291         * @og.tag
292         * ファイル検索で、ディレクトリ名のリストで、オプションを作成します。
293         * 初期値は、false (ファイル名でリスト) です。
294         *
295         * @og.rev 6.3.4.0 (2015/08/01) useDir 属性の追加
296         * @og.rev 7.2.6.0 (2020/06/30) ディレクトリ処理を統一します。
297         *
298         * @param       flag ディレクトリ名のリストで、オプションを作成するかどうか [true:ディレクトリ/false:ファイル]
299         */
300        public void setUseDir( final String flag ) {
301//              useDir = nval( getRequestParameter( flag ),useDir );
302        }
303
304        /**
305         * 【TAG】ファイルの拡張子を除いた名前部分のみの値で行います(初期値:false)。
306         *
307         * @og.tag
308         * ファイル検索の値を、ファイルの拡張子を取り除いた値のみで、オプションを作成します。
309         * 初期値は、false (拡張子付きファイル名でリスト) です。
310         *
311         * @og.rev 7.2.4.0 (2020/05/11) nameOnly 属性 を追加します。
312         *
313         * @param       flag ファイルの拡張子を除いた名前部分のみで、オプションを作成するかどうか [true:名前部分のみ/false:ファイル名]
314         */
315        public void setNameOnly( final String flag ) {
316                nameOnly = nval( getRequestParameter( flag ),nameOnly );
317        }
318
319        /**
320         * 【TAG】optgroupを、ディレクトリの値で作成します(1レベルのみ)(初期値:false)。
321         *
322         * @og.tag
323         * optgroupをディレクトリで作成することで、階層のメニューを作成します。
324         * 初期値は、false(通常) です。
325         *
326         * @og.rev 6.3.4.0 (2015/08/01) groupDir 属性の追加
327         *
328         * @param       flag ディレクトリで階層メニューを作成するかどうか [true:階層/false:通常]
329         */
330        public void setGroupDir( final String flag ) {
331                groupDir = nval( getRequestParameter( flag ),groupDir );
332        }
333
334        /**
335         * 【TAG】ファイルの検索元となるディレクトリを指定します
336         *              (初期値:FILE_URL[={@og.value SystemData#FILE_URL}])。
337         *
338         * @og.tag ファイルの検索元となるディレクトリを指定します。
339         * (初期値:システム定数のFILE_URL[={@og.value SystemData#FILE_URL}])。
340         *
341         * @og.rev 4.0.0.0 (2007/11/20) 指定されたディレクトリ名の最後が"\"or"/"で終わっていない場合に、"/"を付加する。
342         * @og.rev 6.4.2.1 (2016/02/05) URLの最後に、"/" を追加する処理を廃止。
343         * @og.rev 6.4.2.1 (2016/02/05) HybsSystem.url2dir に引数追加。
344         *
345         * @param       url ファイルの検索元となるディレクトリ
346         * @see         org.opengion.hayabusa.common.SystemData#FILE_URL
347         */
348        public void setFrom( final String url ) {
349                final String furl = nval( getRequestParameter( url ),null );
350                from = HybsSystem.url2dir( from,furl,"." );                     // 6.4.2.1 (2016/02/05)
351        }
352
353        /**
354         * 【TAG】検索した結果を表示する表示順をファイル属性名[null/NAME/LASTMODIFIED/FILE_LENGTH]で指定します(初期値:自然順序)。
355         *
356         * @og.tag
357         * ファイルをソートする順(Comparator)を指定します。ソートに指定できる
358         * ファイル属性名は、"NAME","LASTMODIFIED","FILE_LENGTH" の内のどれかひとつです。
359         * 何も指定しない場合は、Fileオブジェクトの自然順序でのソートになります。
360         * (※ 下位互換性のため、LENGTH も残しますが、廃止予定です。)
361         *
362         * @og.rev 3.5.6.2 (2004/07/05) 文字列の連結にStringBuilderを使用します。
363         * @og.rev 4.0.0.0 (2005/01/31) 新規ロジックで改定
364         * @og.rev 5.3.4.0 (2011/04/01) ORDER_BYリストの出力方法 見直し
365         * @og.rev 6.3.4.0 (2015/08/01) Arrays.toString から String.join に置き換え。
366         * @og.rev 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
367         *
368         * @param       ordr  ソートキー [null/NAME/LASTMODIFIED/FILE_LENGTH]
369         */
370        public void setOrderBy( final String ordr ) {
371                orderBy = nval( getRequestParameter( ordr ),orderBy );
372
373                if( orderBy != null && ! check( orderBy, ORDER_BY_SET ) ) {
374                        final String errMsg = "orderBy 属性に、下記の属性名以外の値が設定されました。" + CR
375                                                        + "orderBy=[" + orderBy + "] "                                                          + CR
376                                                        + "orderBy List=" + String.join( ", " , ORDER_BY_SET ) ;
377                        throw new HybsSystemException( errMsg );
378                }
379        }
380
381        /**
382         * 【TAG】表示順を逆転するかどうか[true/false]を指定します(初期値:false)。
383         *
384         * @og.tag
385         * orderBy 属性で指定した表示順を、逆順にするかどうかを指定できます。
386         * 初期値は、false (昇順) です。
387         *
388         * @param       flag 表示順を逆転するかどうか [true:逆順/false:昇順]
389         */
390        public void setDesc( final String flag ) {
391                desc = nval( getRequestParameter( flag ),desc );
392        }
393
394        /**
395         * FileFilterオブジェクトをセットします。
396         * これは、BODY 部に登録した、FileWhereタグによって設定された
397         * ファイルフィルターです。
398         *
399         * @param       filter  オブジェクト
400         */
401        protected void setFileFilter( final FileFilter filter ) {
402                this.filter = filter;
403        }
404
405        /**
406         * 名前順でのソート順を指定する Comparator の実体内部クラス
407         *
408         * @og.rev 6.3.9.1 (2015/11/27) 修飾子を、なし → private static final class に変更。
409         *
410         * @version  4.0
411         * @author   Kazuhiko Hasegawa
412         * @since    JDK5.0,
413         */
414        private static final class NameComparator implements Comparator<File>,Serializable {
415                private static final long serialVersionUID = 400020050131L ;    // 4.0.0.0 (2005/01/31)
416
417                private final boolean desc ;
418
419                /**
420                 * 名前順での比較を行うオブジェクトを作成します。
421                 *
422                 * @param desc 表示順逆転 [true:昇順/false:降順]
423                 */
424                public NameComparator( final boolean desc ) { this.desc = desc; }
425
426                /**
427                 * Comparator インターフェースの compare( File,File ) メソッド。
428                 *
429                 * @param o1 比較元1のファイルオブジェクト
430                 * @param o2 比較元2のファイルオブジェクト
431                 * @return      最初の引数が 2 番目の引数より小さい場合は負の整数、両方が等しい場合は 0、最初の引数が 2 番目の引数より大きい場合は正の整数
432                 */
433                public int compare( final File o1, final File o2 ) {
434                        final File f1 = desc ? o2 : o1 ;
435                        final File f2 = desc ? o1 : o2 ;
436                        return f1.getName().compareTo( f2.getName() ) ;
437                }
438        }
439
440        /**
441         * 更新日順でのソート順を指定する Comparator の実体内部クラス
442         *
443         * @og.rev 6.3.9.1 (2015/11/27) 修飾子を、なし → private static final class に変更。
444         *
445         * @version  4.0
446         * @author   Kazuhiko Hasegawa
447         * @since    JDK5.0,
448         */
449        private static final class ModifiedComparator implements Comparator<File>,Serializable {
450                private static final long serialVersionUID = 400020050131L ;    // 4.0.0.0 (2005/01/31)
451
452                private final boolean desc ;
453
454                /**
455                 * 更新日順での比較を行うオブジェクトを作成します。
456                 *
457                 * @param desc 表示順逆順 [true:昇順/false:降順]
458                 */
459                public ModifiedComparator( final boolean desc ) { this.desc = desc; }
460
461                /**
462                 * Comparator インターフェースの compare( File,File ) メソッド。
463                 *
464                 * @param o1 比較元1のファイルオブジェクト
465                 * @param o2 比較元2のファイルオブジェクト
466                 * @return      最初の引数が 2 番目の引数より小さい場合は負の整数、両方が等しい場合は 0、最初の引数が 2 番目の引数より大きい場合は正の整数
467                 */
468                public int compare( final File o1, final File o2 ) {
469                        final File f1 = desc ? o2 : o1 ;
470                        final File f2 = desc ? o1 : o2 ;
471                        return (int)( f1.lastModified() - f2.lastModified() ) ;
472                }
473        }
474
475        /**
476         * ファイルサイズ順でのソート順を指定する Comparator の実体内部クラス
477         *
478         * @og.rev 6.3.9.1 (2015/11/27) 修飾子を、なし → private static final class に変更。
479         *
480         * @version  4.0
481         * @author   Kazuhiko Hasegawa
482         * @since    JDK5.0,
483         */
484        private static final class LengthComparator implements Comparator<File>,Serializable {
485                private static final long serialVersionUID = 400020050131L ;    // 4.0.0.0 (2005/01/31)
486
487                private final boolean desc ;
488
489                /**
490                 * ファイルサイズでの比較を行うオブジェクトを作成します。
491                 *
492                 * @param desc 表示順逆順 [true:昇順/false:降順]
493                 */
494                public LengthComparator( final boolean desc ) { this.desc = desc; }
495
496                /**
497                 * Comparator インターフェースの compare( File,File ) メソッド。
498                 *
499                 * @param o1 比較元1のファイルオブジェクト
500                 * @param o2 比較元2のファイルオブジェクト
501                 * @return      最初の引数が 2 番目の引数より小さい場合は負の整数、両方が等しい場合は 0、最初の引数が 2 番目の引数より大きい場合は正の整数
502                 */
503                public int compare( final File o1, final File o2 ) {
504                        final File f1 = desc ? o2 : o1 ;
505                        final File f2 = desc ? o1 : o2 ;
506                        return (int)( f1.length() - f2.length() ) ;
507                }
508        }
509
510        /**
511         * このオブジェクトの文字列表現を返します。
512         * 基本的にデバッグ目的に使用します。
513         *
514         * @return このクラスの文字列表現
515         * @og.rtnNotNull
516         */
517        @Override
518        public String toString() {
519                return ToString.title( this.getClass().getName() )
520                                .println( "VERSION"             ,VERSION        )
521                                .println( "orderBy"             ,orderBy        )
522                                .println( "desc"                ,desc           )
523                                .println( "from"                ,from           )
524                                .println( "selValue"    ,selValue       )
525                                .println( "Other..."    ,getAttributes().getAttribute() )
526                                .fixForm().toString() ;
527        }
528}