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     */
016    package org.opengion.hayabusa.report2;
017    
018    import java.io.File;
019    import java.util.Map;
020    import java.util.HashMap;
021    import java.util.Locale;
022    
023    import org.opengion.fukurou.util.FileUtil;
024    import org.opengion.fukurou.util.StringUtil;
025    import org.opengion.hayabusa.common.HybsSystem;
026    import org.opengion.hayabusa.common.HybsSystemException;
027    
028    import com.sun.star.beans.PropertyValue;
029    import com.sun.star.frame.XComponentLoader;
030    import com.sun.star.frame.XController;
031    import com.sun.star.frame.XDispatchHelper;
032    import com.sun.star.frame.XDispatchProvider;
033    import com.sun.star.frame.XModel;
034    import com.sun.star.frame.XStorable;
035    import com.sun.star.io.IOException;
036    import com.sun.star.lang.EventObject;
037    import com.sun.star.lang.IllegalArgumentException;
038    import com.sun.star.lang.XComponent;
039    import com.sun.star.uno.Exception;
040    import com.sun.star.uno.UnoRuntime;
041    import com.sun.star.util.CloseVetoException;
042    import com.sun.star.util.XCloseable;
043    import com.sun.star.view.PrintJobEvent;
044    import com.sun.star.view.PrintableState;
045    import com.sun.star.view.XPrintJobBroadcaster;
046    import com.sun.star.view.XPrintJobListener;
047    import com.sun.star.view.XPrintable;
048    
049    /**
050     * OpenOfficeを利用して様?な形式?ファイルを読み込み、?力?印刷を行うための変換クラスです?
051     *
052     * 変換を行うことのできる入出力?フォーマット以下?通りです?
053     *
054     * [対応フォーマッ?
055     *  入力[Calc(ODS)   ,Excel(XLS)     ] -> 出力[Calc(ODS)   ,Excel(XLS)     ,PDF]
056     *  入力[Writer(ODT) ,Word(DOC)      ] -> 出力[Writer(ODT) ,Word(DOC)      ,PDF]
057     *  入力[Impress(ODP),PowerPoint(PPT)] -> 出力[Impress(ODP),PowerPoint(PPT),PDF]
058     *  入力[ * 上記?全て               ] -> 印刷
059     *
060     * 変換を行うには、以下?2通りの方法があります?
061     * (1)簡易的な変換メソ?を利用する場?
062     *   {@link #convert(String, String)}を利用して、変換を行います?
063     *   こ?場合?出力形式?、?力ファイルの拡張子に従って自動的に決定されます?
064     *   こ?ため、印刷処?どを行う場合??2)の方法で出力して下さ??
065     * (2)段階的に書くメソ?を呼び出して変換する場?
066     *   オブジェクトを生?した後?{@link #open()}?(?変換メソ?)、{@link #clone()}?
067     *   ?に呼び出して変換を行います?
068     *   こ?場合?出力形式?、それに対応するメソ?を呼び出ることで決定されます?
069     *
070     *   また?変換を行うための、各種メソ?は、例外としてThrowableを投げるように定義されて?す?
071     *   こ?クラスを利用する場合?、このThrowableをcatchし?catch句で、?{@link #close( boolean )}に?
072     *   "true"(エラー発生時のクローズ処?を指定して、終???行って下さ??
073     *   (これを行わな??合?OpenOfficeの不要なプロセスが残ってしま?能性がありま?
074     *
075     * また?出力ファイルが既に存在する場合?出力ファイルは?削除された後?処?れます?
076     * なお?入力ファイルと出力ファイルが同じ?合?何も処?れません?例外も発行されません)
077     *
078     * 入力ファイルを?カンマ区?で??した?合??の入力ファイルを?ージして出力します?
079     * ※1 現状は、ファイルのマ?ジは、?力ファイルがExcelまた?Calcの場合?み対応して?す?
080     *
081     * @og.group 帳票シス?
082     *
083     * @version  4.0
084     * @author   Hiroki.Nakamura
085     * @since    JDK1.6
086     */
087    public class DocConverter_OOO {
088    
089            final private boolean                   isOnline;                       // オンライン処?ど?(オンライン処??場合?プロセスはファクトリクラス経由で生?されま?
090            final private String[]                  mergeFile;
091    
092            private String                                  inputName;
093            private String                                  origName;
094    
095    //      private XComponent                              doc;
096            private XComponent                              xComp;                          // 5.1.8.0 (2010/07/01) メソ?と重なる変数名?変更
097            private SOfficeProcess                  soffice;
098    
099            // 入力?出力?拡張子とこれに対応するフィルター?
100    //      static final private HashMap<String,String> filterMap     = new HashMap<String,String>();
101            static final private Map<String,String> filterMap = new HashMap<String,String>();
102            static {
103                    filterMap.put( "ods_ods", "calc8" );
104                    filterMap.put( "xls_ods", "calc8" );
105                    filterMap.put( "ods_xls", "MS Excel 97" );
106                    filterMap.put( "xls_xls", "MS Excel 97" );
107                    filterMap.put( "ods_pdf", "calc_pdf_Export" );
108                    filterMap.put( "xls_pdf", "calc_pdf_Export" );
109                    filterMap.put( "odt_odt", "writer8" );
110                    filterMap.put( "doc_odt", "writer8" );
111                    filterMap.put( "odt_doc", "MS Word 97" );
112                    filterMap.put( "doc_doc", "MS Word 97" );
113                    filterMap.put( "odt_pdf", "writer_pdf_Export" );
114                    filterMap.put( "doc_pdf", "writer_pdf_Export" );
115                    filterMap.put( "odp_odp", "impress8" );
116                    filterMap.put( "ppt_odp", "impress8" );
117                    filterMap.put( "odp_ppt", "MS PowerPoint 97" );
118                    filterMap.put( "ppt_ppt", "MS PowerPoint 97" );
119                    filterMap.put( "odp_pdf", "impress_pdf_Export" );
120                    filterMap.put( "ppt_pdf", "impress_pdf_Export" );
121            };
122    
123            /**
124             * コンストラクタです?
125             *
126             * #DocConverter(input, true)と同じです?
127             *
128             * @param input ファイル?(カンマ区?)
129             * @see #DocConverter_OOO(String[])
130             */
131            public DocConverter_OOO( final String input ) {
132                    this( StringUtil.csv2Array( input ), true );
133            }
134    
135            /**
136             * コンストラクタです?
137             *
138             * #DocConverter(input, true)と同じです?
139             *
140             * @param input ファイル?(配?)
141             * @see #DocConverter_OOO(String[], boolean)
142             */
143            public DocConverter_OOO( final String input[] ) {
144                    this( input, true );
145            }
146    
147            /**
148             * コンストラクタです?
149             *
150             * isOnline(isOl)がtrueに?された場合?soffice.binのプロセスをファクトリークラス経由で生?し?
151             * キャ?ュします?
152             * ?、シス?リソースが読み込まれな??、バ?ファイルから起動した?合?、この方法?
153             * 利用できな?め?isOnlineをfalseに?する?があります?
154             *
155             * @param input ファイル?(配?)
156             * @param isOl オンライン(Web環?の使用)かど?
157             */
158            public DocConverter_OOO( final String input[], final boolean isOl ) {
159                    if( input == null || input.length == 0 || input[0].length() == 0 ) {
160                            throw new HybsSystemException( "入力ファイルが指定されて?せん? );
161                    }
162                    File inFile = new File( input[0] );
163                    if( !inFile.exists() ) {
164                            throw new HybsSystemException( "入力ファイルが存在しません?file=" + input[0] + "]" );
165                    }
166                    isOnline = isOl;
167                    inputName = input[0];
168                    origName = input[0];
169    
170                    if( input.length == 1 ) {
171                            mergeFile = null;
172                    }
173                    else {
174                            if( !"xls".equals( getSuffix( input[0] ) ) && !"ods".equals( getSuffix( input[0] ) ) ) {
175                                    throw new HybsSystemException( "ファイルのマ?ジを行う場合?入力ファイルは、Excelまた?Cacl形式である?があります?" );
176                            }
177    
178                            mergeFile = new String[input.length-1];
179                            for( int i=0; i<mergeFile.length; i++ ) {
180                                    if( input[i+1].length() == 0 || !( new File( input[i+1] ) ).exists() ) {
181                                            throw new HybsSystemException( "マ?ジファイルが指定されて??、また?存在しません?file=" + input[i+1] + "]" );
182                                    }
183                                    if( inputName.equals( input[i] + 1 ) ) {
184                                            throw new HybsSystemException( "マ?ジファイルに入力ファイルと同じファイルが指定されてます?[file=" + input[i+1] + "]" );
185                                    }
186                                    if( !"xls".equals( getSuffix( input[i+1] ) ) && !"ods".equals( getSuffix( input[i+1] ) ) ) {
187                                            throw new HybsSystemException( "ファイルのマ?ジを行う場合?マ?ジファイルは、Excelまた?Cacl形式である?があります?" );
188                                    }
189                                    mergeFile[i] = input[i+1];
190                            }
191                    }
192            }
193    
194            /**
195             * SOficeのコンポ?ネントを起動します?
196             *
197             * 正常に処?終?た?合??close()を発行し、終???行って下さ??
198             * また?例外が発生した?合??close(true)を発行し、終???行って下さ??
199             *
200             * @og.rev 5.1.7.0 (2010/06/01) マ?ジ処??
201             *
202             * @throws Throwable
203             * @see #close()
204             * @see #close(boolean)
205             */
206            public void open() throws Throwable {
207                    // プロセスの取?
208                    if( soffice == null ) {
209                            if( isOnline ) {
210                                    soffice = ProcessFactory.newInstance();
211                            }
212                            else {
213                                    soffice = new SOfficeProcess( "docconverter.class" );
214                                    soffice.bootstrap();
215                            }
216    
217                            // マ?ジする場合?、?ージ対象のファイルをテンポラリにコピ?する(readOnly回避のため)
218                            // ?プレー?無?として上げると、シートコピ?先として特定できなくなるた?
219                            if( mergeFile != null ) {
220                                    File origFile = new File( origName );
221                                    inputName = soffice.getTempPath() + System.currentTimeMillis() + "_" + origFile.getName();
222                                    FileUtil.copy( origFile, new File( inputName ) );
223                            }
224                    }
225    
226    //              PropertyValue[] calcProps = new PropertyValue[1];
227    //              calcProps[0] = new PropertyValue();
228    //              calcProps[0].Name = "Hidden";
229    //              calcProps[0].Value = true;
230    //
231    //              String url = "file:///" + inputName.replace( '\\', '/' );
232    //
233    //              @SuppressWarnings("cast")       // OpenOffice 3.2 での冗長なキャスト警告?抑止。キャストをはずすと、旧3.1 では、エラーになる?
234    //              XComponentLoader cloader = (XComponentLoader) UnoRuntime.queryInterface( XComponentLoader.class, soffice.getDesktop() );
235    //              try {
236    //                      doc = cloader.loadComponentFromURL( url, "_default", 0, calcProps );
237    //              }
238    //              catch( IOException ex ) {
239    //                      throw new HybsSystemException( "OpenOfficeの立ち上げ時にエラーが発生しました(入出力エラー)?, ex );
240    //              }
241    //              catch( IllegalArgumentException ex ) {
242    //                      throw new HybsSystemException( "OpenOfficeの立ち上げ時にエラーが発生しました(パラメーター不正)?, ex );
243    //              }
244    
245                    // 5.1.7.0 (2010/06/01) マ?ジ処??
246                    xComp = getComponent( inputName, ( mergeFile == null ? true : false ), false );
247    
248                    if( mergeFile != null ) {
249                            for( int i=0; i<mergeFile.length; i++ ) {
250                                    merge( mergeFile[i] );
251                            }
252                    }
253            }
254    
255            /**
256             * ドキュメントコンポ?ネントを取得します?
257             *
258             * @param       input                   ファイル?
259             * @param       isHidden                ?属?[true/false]
260             * @param       isAsTemplate    OpenOffice上?Template属?[true/false]
261             *
262             * @return      ドキュメントコンポ?ネン?
263             */
264            @SuppressWarnings("cast")       // OpenOffice 3.2 での冗長なキャスト警告?抑止。キャストをはずすと、旧3.1 では、エラーになる?
265            private XComponent getComponent( final String input, final boolean isHidden, final boolean isAsTemplate ) {
266                    PropertyValue[] calcProps = new PropertyValue[2];
267                    calcProps[0] = new PropertyValue();
268                    calcProps[0].Name = "Hidden";
269                    calcProps[0].Value = isHidden;
270                    calcProps[1] = new PropertyValue();
271                    calcProps[1].Name = "AsTemplate";
272                    calcProps[1].Value = isAsTemplate;
273    
274                    String url = "file:///" + input.replace( '\\', '/' );
275    
276                    XComponent rtnDoc;
277                    XComponentLoader cloader = (XComponentLoader) UnoRuntime.queryInterface( XComponentLoader.class, soffice.getDesktop() );
278                    try {
279                            rtnDoc = cloader.loadComponentFromURL( url, "_blank", 0, calcProps );
280                    }
281                    catch( IOException ex ) {
282                            throw new HybsSystemException( "OpenOfficeの立ち上げ時にエラーが発生しました(入出力エラー)?, ex );
283                    }
284                    catch( IllegalArgumentException ex ) {
285                            throw new HybsSystemException( "OpenOfficeの立ち上げ時にエラーが発生しました(パラメーター不正)?, ex );
286                    }
287                    return rtnDoc;
288            }
289    
290            /**
291             * ドキュメン?xls,ods)のマ?ジを行います?
292             *
293             * @param mergeInputName マ?ジ対象のファイル?
294             */
295            @SuppressWarnings("cast")       // OpenOffice 3.2 での冗長なキャスト警告?抑止。キャストをはずすと、旧3.1 では、エラーになる?
296            private void merge( final String mergeInputName ) {
297                    // マ?ジする副ファイルは、テンプレー?無?として上げ?readOnly回避のため)
298                    XComponent subDoc = getComponent( mergeInputName, false, true );
299    
300                    XDispatchProvider dispatchProvider
301                            = (XDispatchProvider)UnoRuntime.queryInterface( XDispatchProvider.class
302                                    ,((XController)UnoRuntime.queryInterface( XController.class
303                                            ,((XModel)UnoRuntime.queryInterface( XModel.class
304                                                    ,subDoc
305                                            )).getCurrentController()
306                                    )).getFrame()
307                            );
308    
309                    XDispatchHelper xDispatchHelper = soffice.getDispatcher();
310                    xDispatchHelper.executeDispatch(dispatchProvider, ".uno:TableSelectAll", "", 0, new PropertyValue[0]);
311    
312                    String title = ( new File( inputName ).getName() );
313                    title = ( title ).substring( 0, title.indexOf( '.' ) );
314    
315                    PropertyValue[] moveProps = new PropertyValue[3];
316                    moveProps[0] = new PropertyValue();
317                    moveProps[0].Name = "DocName";
318                    moveProps[0].Value = title;
319                    moveProps[1] = new PropertyValue();
320                    moveProps[1].Name = "Index";
321                    moveProps[1].Value = 32767;
322                    moveProps[2] = new PropertyValue();
323                    moveProps[2].Name = "Copy";
324                    moveProps[2].Value = true;
325                    xDispatchHelper.executeDispatch(dispatchProvider, ".uno:Move", "", 0, moveProps);
326    
327                    // シートリンク方式?場合?、CalcをHiddenの状態で実行できるが?画像などのオブジェクトがリンクされな?め?
328                    // 採用見?り??
329    //              XSpreadsheets mainSp = ( (XSpreadsheetDocument)UnoRuntime.queryInterface( XSpreadsheetDocument.class, xComp ) ).getSheets();
330    //              String[] mainSheetNames = mainSp.getElementNames();
331    //
332    //              XSpreadsheets subSp = ( (XSpreadsheetDocument)UnoRuntime.queryInterface( XSpreadsheetDocument.class, subDoc ) ).getSheets();
333    //              String[] subSheetNames = subSp.getElementNames();
334    //              for( int i=0; i<1; i++ ) {
335    //                      XSpreadsheet newSp = insertSheet( mainSp, subSheetNames[i], 0, (short)(mainSheetNames.length + i) );
336    //                      XSheetLinkable mainLink = (XSheetLinkable) UnoRuntime.queryInterface( XSheetLinkable.class, newSp );
337    //                      mainLink.link( "file:///" + mergeInputName.replace( '\\', '/' ), subSheetNames[i], "", "", com.sun.star.sheet.SheetLinkMode.NORMAL );
338    //                      mainLink.setLinkMode( com.sun.star.sheet.SheetLinkMode.NONE );
339    //              }
340    
341                    closeComponent( subDoc );
342            }
343    
344    //      /**
345    //       * スプレ?シートオブジェクトに対して、シートを新規に追?ます?
346    //       * 追?るシート名が既に存在する場合?シート名のサフィ?スとして1,2...の連番を付加します?
347    //       *
348    //       * @param sheets
349    //       * @param sheetName
350    //       * @param suffix
351    //       * @param index
352    //       * @return 追?ート?シートオブジェク?
353    //       */
354    //      private XSpreadsheet insertSheet( final XSpreadsheets sheets, final String sheetName, final int suffix, final short index ) {
355    //              String sn = sheetName + ( suffix == 0 ? "" : String.valueOf( suffix ) );
356    //              try {
357    //                      sheets.insertNewByName( sn, index );
358    //              }
359    //              catch ( com.sun.star.uno.RuntimeException ex ) {
360    //                      if( suffix < 256 ) {
361    //                              return insertSheet( sheets, sheetName, suffix+1, index );
362    //                      }
363    //                      else {
364    //                              throw new HybsSystemException( "シート?追?失敗しました", ex );
365    //                      }
366    //              }
367    //
368    //              XSpreadsheet insSheet = null;
369    //              try {
370    //                      insSheet = (XSpreadsheet)UnoRuntime.queryInterface( XSpreadsheet.class, sheets.getByName( sn ) );
371    //              }
372    //              catch( NoSuchElementException ex ) {
373    //                      throw new HybsSystemException( "追?たシートにアクセスできません?, ex );
374    //              }
375    //              catch( WrappedTargetException ex ) {
376    //                      throw new HybsSystemException( "追?たシートにアクセスできません?, ex );
377    //              }
378    //              return insSheet;
379    //      }
380    
381            /**
382             * Calcコンポ?ネントをクローズします?
383             *
384             * こ?クローズ処??、??正常終?た?合に呼び出しする?があります?
385             * 例外が発生した?合??close(true)を発行し、終???行って下さ??
386             *
387             * こ?メソ?は#close(false)と同じです?
388             *
389             * @throws Throwable
390             * @see #close(boolean)
391             */
392            public void close() throws Throwable  {
393                    close( false );
394            }
395    
396            /**
397             * Calcコンポ?ネントをクローズします?
398             *
399             * 引数のisErrがtrueの場合?こ?変換オブジェクトで生?された?ロセスは強制?破?れます?
400             * falseの場合?、?ロセスは、ファクトリクラスを経由して、キャ?ュに戻されます?
401             * (バッチ???場合?、いずれの場合も、?ロセスは強制?破?れま?
402             *
403             * 起動から変換、クローズまでの書く??例外が発生した?合??close(true)を発行し、終???行って下さ??
404             *
405             * #close(false)は#close()と同じであるため??常利用することはありません?
406             *
407             * @og.rev 4.2.4.1 (2008/07/07 ) 終???60回で終わるよ?修正
408             * @og.rev 4.3.0.0 (2008/07/15 ) ↑?6秒しか?て?かった?で?0秒?ように修正
409             *
410             * @param       isErr   trueの場合?こ?変換オブジェクトで生?された?ロセスは強制?破?れます?
411             */
412            @SuppressWarnings("cast")       // OpenOffice 3.2 での冗長なキャスト警告?抑止。キャストをはずすと、旧3.1 では、エラーになる?
413            public void close( final boolean isErr ) {
414                    if( xComp != null ) {
415                            closeComponent( xComp );
416                    }
417    
418                    if( soffice != null ) {
419                            if( isOnline ) {
420                                    if( isErr ) {
421                                            ProcessFactory.remove( soffice );
422                                    }
423                                    else {
424                                            ProcessFactory.release( soffice );
425                                    }
426                            }
427                            else {
428                                    soffice.close();
429                            }
430                    }
431    
432                    // マ?ジした場合?、テンポラリにコピ?したファイルを削除
433                    if( mergeFile != null ) {
434                            if( ! ( new File( inputName ) ).delete() ) {
435                                    System.err.println( "?ポラリにコピ?したファイルを削除できませんでした?" + inputName + "]" );
436                            }
437                    }
438            }
439    
440            /**
441             * ドキュメントコンポ?ネントをクローズします?
442             *
443             * @param comp ドキュメントコンポ?ネン?
444             */
445            @SuppressWarnings("cast")       // OpenOffice 3.2 での冗長なキャスト警告?抑止。キャストをはずすと、旧3.1 では、エラーになる?
446            private void closeComponent( final XComponent comp ) {
447                    XCloseable closeable = null;
448                    for( int i = 0;; ++i ) {
449                            try {
450                                    closeable = (XCloseable) UnoRuntime.queryInterface( XCloseable.class, comp );
451                                    closeable.close( true );
452                                    break;
453                            }
454                            catch( CloseVetoException ex ) {
455                                    // 4.2.4.1 (2008/07/07 )
456                                    // 4.3.4.4 (2009/01/01)
457                                    if( i == 600 ) { throw new HybsSystemException( "sofficeプロセスに接続できません?, ex ); }
458                                    try {
459                                            Thread.sleep( 100 );
460                                    }
461                                    catch( InterruptedException ex2 ) {
462    //                                      throw new HybsSystemException( ex2 );
463                                    }
464                            }
465                    }
466            }
467    
468            /**
469             * 印刷を行います?
470             *
471             * 正常に処?終?た?合??close()を発行し、終???行って下さ??
472             * また?例外が発生した?合??close(true)を発行し、終???行って下さ??
473             *
474             * @og.rev 4.3.0.0 (2008/07/16) スプ?ルが終わるまでwaitし?さらにプリンタ発行?状況を監視し、正常終?ど?を判断
475             * @og.rev 4.3.7.3 (2009/06/22) 存在しな??リンターを指定した?合?エラーハンドリングを追?
476             * @og.rev 5.1.2.0 (2010/01/01) CentOS等?、OS_INFOがLinux UNKNOWNとなるため?判定条件を変更
477             *
478             * @param       printer プリンター?
479             * @throws Throwable
480             */
481            public void print( final String printer ) throws Throwable {
482                    if( xComp == null ) { throw new HybsSystemException( "初めに?open()を実行して下さ? ); }
483    
484                    if( printer == null || printer.length() == 0 ) {
485                            throw new HybsSystemException( "プリンターが指定されて?せん? );
486                    }
487    
488                    @SuppressWarnings("cast")       // OpenOffice 3.2 での冗長なキャスト警告?抑止。キャストをはずすと、旧3.1 では、エラーになる?
489                    XPrintable xprintable = (XPrintable) UnoRuntime.queryInterface( XPrintable.class, xComp );
490                    @SuppressWarnings("cast")       // OpenOffice 3.2 での冗長なキャスト警告?抑止。キャストをはずすと、旧3.1 では、エラーになる?
491                    XPrintJobBroadcaster selection = (XPrintJobBroadcaster) UnoRuntime.queryInterface(XPrintJobBroadcaster.class, xprintable);
492                    MyPrintJobListener listener = new MyPrintJobListener ();
493                    selection.addPrintJobListener( listener );
494    
495                    PropertyValue[] tmpProps = new PropertyValue[1];
496                    tmpProps[0] = new PropertyValue();
497                    tmpProps[0].Name = "Name";
498                    // 5.1.2.0 (2010/01/01) CentOS等?、OS_INFOがLinux UNKNOWNとなるため?判定条件を変更
499                    // OSがLinuxの場合?、?リンタ名称の前後に"<",">"を付加
500    //              tmpProps[0].Value = "Linux".equals( HybsSystem.sys( "OS_INFO" ) ) ? "<" + printer + ">" : printer;
501                    tmpProps[0].Value = "LINUX".indexOf( HybsSystem.sys( "OS_INFO" ).toUpperCase( Locale.JAPAN ) ) >= 0 ? "<" + printer + ">" : printer;
502    
503                    // 4.3.4.4 (2009/01/01)
504                    try {
505                            xprintable.setPrinter( tmpProps );
506                    }
507                    catch ( IllegalArgumentException ex ) {
508                            throw new HybsSystemException( "印刷時にエラーが発生しました?, ex );
509                    }
510    
511                    // 4.3.7.3 (2009/06/22) 存在しな??リンタを指定した?合?、PropertyValueに
512                    // ?ォルト?リンターが?るため?引数の値と合?して?かで正しく設定されたかを確?
513                    String curPrinter = null;
514                    PropertyValue[] chkProps = xprintable.getPrinter();
515                    for( int i=0; i<chkProps.length; i++ ) {
516                            if( "Name".equals( chkProps[i].Name) ) {
517                                    curPrinter = (String)chkProps[i].Value;
518                                    break;
519                            }
520                    }
521                    if( !(printer.equalsIgnoreCase( curPrinter ) ) ) {
522                            String errMsg = "プリンター[" + printer + "]を発行?に?できませんでした? + HybsSystem.CR
523                                                            + "存在しな??リンタ名が?されて?可能性があります?";
524                            throw new HybsSystemException( errMsg );
525                    }
526    
527                    // 4.3.0.0 (2008/07/16)
528                    PropertyValue[] printProps = new PropertyValue[1];
529                    printProps[0] = new PropertyValue();
530                    printProps[0].Name = "Wait";
531                    printProps[0].Value = true;
532    
533                    // 4.3.4.4 (2009/01/01)
534                    try {
535                            xprintable.print( printProps );
536                    }
537                    catch ( IllegalArgumentException ex ) {
538                            throw new HybsSystemException( "印刷時にエラーが発生しました?, ex );
539                    }
540    
541                    // 4.3.0.0 (2008/07/16)
542                    if( listener.getStatus() == null
543                                    || ( listener.getStatus() != PrintableState.JOB_COMPLETED && listener.getStatus() != PrintableState.JOB_SPOOLED ) ){
544                            throw new HybsSystemException ( "Error Occured while spooling print job. Check Spooler-Service!!!");
545                    }
546            }
547    
548            /**
549             * プリンタジョブ?状況を監視するリスナ?です?
550             *
551             * @author Hiroki.Nakamura
552             */
553            private static class MyPrintJobListener implements XPrintJobListener {
554                    private PrintableState status = null;
555    
556                    @Override
557                    public void printJobEvent( final PrintJobEvent event ) {
558                            status = event.State;
559                    }
560    
561                    @Override
562                    public void disposing( final EventObject event ) {
563                            // 何もありません?PMD エラー回避)
564                    }
565    
566                    public PrintableState getStatus() {
567                            return status;
568                    }
569            }
570    
571            /**
572             * PDF出力を行います?
573             *
574             * 入力形式で未対応?場?形式?入力ファイルの拡張子で判別)、例外が発行されます?
575             *
576             * 正常に処?終?た?合??close()を発行し、終???行って下さ??
577             * また?例外が発生した?合??close(true)を発行し、終???行って下さ??
578             *
579             * @param       outputName      出力ファイル?
580             * @param       pdfPasswd       PDFパスワー?
581             * @throws Throwable
582             */
583            public void pdf( final String outputName, final String pdfPasswd ) throws Throwable  {
584                    savePdf( outputName, getFilterName( getSuffix( inputName ), "pdf" ), pdfPasswd );
585            }
586    
587            /**
588             * Calc(ods)出力を行います?
589             *
590             * 入力形式で未対応?場?形式?入力ファイルの拡張子で判別)、例外が発行されます?
591             *
592             * 正常に処?終?た?合??close()を発行し、終???行って下さ??
593             * また?例外が発生した?合??close(true)を発行し、終???行って下さ??
594             *
595             * @param       outputName      出力ファイル?
596             * @throws Throwable
597             */
598            public void ods( final String outputName ) throws Throwable  {
599                    saveDoc( outputName, getFilterName( getSuffix( inputName ), "ods" ) );
600            }
601    
602            /**
603             * Excel(xls)出力を行います?
604             *
605             * 入力形式で未対応?場?形式?入力ファイルの拡張子で判別)、例外が発行されます?
606             *
607             * 正常に処?終?た?合??close()を発行し、終???行って下さ??
608             * また?例外が発生した?合??close(true)を発行し、終???行って下さ??
609             *
610             * @param       outputName      出力ファイル?
611             * @throws Throwable
612             */
613            public void xls( final String outputName ) throws Throwable {
614                    saveDoc( outputName, getFilterName( getSuffix( inputName ), "xls" ) );
615            }
616    
617            /**
618             * Writer(ods)出力を行います?
619             *
620             * 入力形式で未対応?場?形式?入力ファイルの拡張子で判別)、例外が発行されます?
621             *
622             * 正常に処?終?た?合??close()を発行し、終???行って下さ??
623             * また?例外が発生した?合??close(true)を発行し、終???行って下さ??
624             *
625             * @param       outputName      出力ファイル?
626             * @throws Throwable
627             */
628            public void odt( final String outputName ) throws Throwable {
629                    saveDoc( outputName, getFilterName( getSuffix( inputName ), "odt" ) );
630            }
631    
632            /**
633             * Word(doc)出力を行います?
634             *
635             * 入力形式で未対応?場?形式?入力ファイルの拡張子で判別)、例外が発行されます?
636             *
637             * 正常に処?終?た?合??close()を発行し、終???行って下さ??
638             * また?例外が発生した?合??close(true)を発行し、終???行って下さ??
639             *
640             * @param       outputName      出力ファイル?
641             * @throws Throwable
642             */
643            public void doc( final String outputName ) throws Throwable {
644                    saveDoc( outputName, getFilterName( getSuffix( inputName ), "doc" ) );
645            }
646    
647            /**
648             * Impress(odp)出力を行います?
649             *
650             * 入力形式で未対応?場?形式?入力ファイルの拡張子で判別)、例外が発行されます?
651             *
652             * 正常に処?終?た?合??close()を発行し、終???行って下さ??
653             * また?例外が発生した?合??close(true)を発行し、終???行って下さ??
654             *
655             * @param       outputName      出力ファイル?
656             * @throws Throwable
657             */
658            public void odp( final String outputName ) throws Throwable {
659                    saveDoc( outputName, getFilterName( getSuffix( inputName ), "odp" ) );
660            }
661    
662            /**
663             * PowerPoint(ppt)出力を行います?
664             *
665             * 入力形式で未対応?場?形式?入力ファイルの拡張子で判別)、例外が発行されます?
666             *
667             * 正常に処?終?た?合??close()を発行し、終???行って下さ??
668             * また?例外が発生した?合??close(true)を発行し、終???行って下さ??
669             *
670             * @param       outputName      出力ファイル?
671             * @throws Throwable
672             */
673            public void ppt( final String outputName ) throws Throwable {
674                    saveDoc( outputName, getFilterName( getSuffix( inputName ), "ppt" ) );
675            }
676    
677            /**
678             * 出力ファイルから出力形式を自動判別し?変換を行います?
679             *
680             * 入出力形式で未対応?場?形式?入出力ファイルの拡張子で判別)、例外が発行されます?
681             *
682             * 正常に処?終?た?合??close()を発行し、終???行って下さ??
683             * また?例外が発生した?合??close(true)を発行し、終???行って下さ??
684             *
685             * @param       outputName      出力ファイル?
686             * @throws Throwable
687             */
688            public void auto( final String outputName ) throws Throwable {
689                    String outSuffix = getSuffix( outputName );
690                    if( "pdf".equalsIgnoreCase( outSuffix ) ) {
691                            savePdf( outputName, getFilterName( getSuffix( inputName ), outSuffix ), null );
692                    }
693                    else {
694                            saveDoc( outputName, getFilterName( getSuffix( inputName ), outSuffix ) );
695                    }
696            }
697    
698            /**
699             * フィルター名を?して、各種ファイル形式に出力を行います?
700             *
701             * @param       outputName      出力ファイル?
702             * @param       filter          フィルター?
703             */
704            private void saveDoc(  final String outputName, final String filter ) {
705                    if( xComp == null ) { throw new HybsSystemException( "初めに?open()を実行して下さ? ); }
706                    if( !checkOutput( outputName ) ){ return; }
707    
708                    PropertyValue[] storeProps = new PropertyValue[1];
709                    storeProps[0] = new PropertyValue();
710                    storeProps[0].Name = "FilterName";
711                    storeProps[0].Value = filter;
712    
713                    String url = "file:///" + outputName.replace( '\\', '/' );
714                    @SuppressWarnings("cast")       // OpenOffice 3.2 での冗長なキャスト警告?抑止。キャストをはずすと、旧3.1 では、エラーになる?
715                    XStorable xstorable = (XStorable) UnoRuntime.queryInterface( XStorable.class, xComp );
716                    try {
717                            xstorable.storeAsURL( url, storeProps );
718                    }
719                    catch ( Throwable th ) {
720                            throw new HybsSystemException( "ファイルへの変換時にエラーが発生しました?filter=" + filter + "]", th );
721                    }
722            }
723    
724            /**
725             * フィルターを指定してPDF出力を行います?
726             *
727             * @param       outputName      出力ファイル?
728             * @param       filter          フィルター?
729             * @param       pdfPasswd       PDFパスワー?
730             */
731            private void savePdf( final String outputName, final String filter, final String pdfPasswd ) {
732                    if( xComp == null ) { throw new HybsSystemException( "初めに?open()を実行して下さ? ); }
733                    if( !checkOutput( outputName ) ){ return; }
734    
735                    PropertyValue[] storeProps;
736                    if( pdfPasswd == null || pdfPasswd.length() == 0 ) {
737                            storeProps = new PropertyValue[1];
738                            storeProps[0] = new PropertyValue();
739                            storeProps[0].Name = "FilterName";
740                            storeProps[0].Value = filter;
741                    }
742                    // 帳票要求テーブルでPDFパスワードが設定されて?場?
743                    else {
744                            PropertyValue[] filterProps = new PropertyValue[2];
745                            filterProps[0] = new PropertyValue();
746                            filterProps[0].Name = "EncryptFile";
747                            filterProps[0].Value = true;
748                            filterProps[1] = new PropertyValue();
749                            filterProps[1].Name = "DocumentOpenPassword";
750                            filterProps[1].Value = pdfPasswd;
751    
752                            storeProps = new PropertyValue[2];
753                            storeProps[0] = new PropertyValue();
754                            storeProps[0].Name = "FilterName";
755                            storeProps[0].Value = "calc_pdf_Export";
756                            storeProps[1] = new PropertyValue();
757                            storeProps[1].Name = "FilterData";
758                            storeProps[1].Value = filterProps;
759                    }
760    
761                    String url = "file:///" + outputName.replace( '\\', '/' );
762                    @SuppressWarnings("cast")       // OpenOffice 3.2 での冗長なキャスト警告?抑止。キャストをはずすと、旧3.1 では、エラーになる?
763                    XStorable xstorable = (XStorable) UnoRuntime.queryInterface( XStorable.class, xComp );
764                    try {
765                            xstorable.storeToURL( url, storeProps );
766                    }
767                    catch ( Throwable th ) {
768                            throw new HybsSystemException( "PDFファイルへの変換時にエラーが発生しました?filter=" + filter + "]", th );
769                    }
770            }
771    
772            /**
773             * 出力ファイルのチェ?を行います?
774             *
775             * @param       outputName      出力ファイル?
776             *
777             * @return      処?象かど?(入力ファイルと出力ファイルが同じ?合?、falseが返りま?
778             */
779            private boolean checkOutput( final String outputName ) {
780                    if( outputName == null || outputName.length() == 0 ) {
781                            throw new HybsSystemException( "出力ファイルが指定されて?せん? );
782                    }
783    
784                    File inFile = new File( inputName );
785                    File outFile = new File( outputName );
786    
787                    if( outFile.exists() ) {
788                            if( inFile.getAbsoluteFile().equals( outFile.getAbsoluteFile() ) ) {
789                                    // 入力と出力が同じファイルの場合な何もしな?
790                                    return false;
791                            }
792                            else if( !outFile.delete() ) {
793                                    throw new HybsSystemException( "出力?の既存ファイルが削除できません?file=" + outputName + "]" );
794                            }
795                    }
796                    return true;
797            }
798    
799            /**
800             * 入出力?形?拡張?からフィルター名を取得します?
801             *
802             * @param       inSuffix        入力拡張?
803             * @param       outSuffix       出力拡張?
804             *
805             * @return      フィルター?
806             */
807            private static String getFilterName( final String inSuffix, final String outSuffix ) {
808                    String filterName = filterMap.get( inSuffix + "_" + outSuffix );
809                    if( filterName == null ) {
810                            String errMsg = "入力形式?出力形式?、以下?対応表に基づき?設定して下さ??" + HybsSystem.CR
811                                                            + "入力[Calc(ods)   ,Excel(xls)     ] -> 出力[Calc(ods)   ,Excel(xls)     ,PDF]" + HybsSystem.CR
812                                                            + "入力[Writer(odt) ,Word(doc)      ] -> 出力[Writer(odt) ,Word(doc)      ,PDF]" + HybsSystem.CR
813                                                            + "入力[Impress(odp),PowerPoint(ppt)] -> 出力[Impress(odp),PowerPoint(ppt),PDF]" + HybsSystem.CR;
814                            throw new HybsSystemException( errMsg );
815                    }
816                    return filterName;
817            }
818    
819            /**
820             * ファイル名から拡張?小文?を求めます?
821             *
822             * @param       fileName        ファイル?
823             *
824             * @return      拡張?小文?
825             */
826            private static String getSuffix( final String fileName ) {
827                    String suffix = null;
828                    if( fileName != null ) {
829    //                      int sufIdx = fileName.lastIndexOf( "." );
830                            int sufIdx = fileName.lastIndexOf( '.' );
831                            if( sufIdx >= 0 ) {
832                                    suffix = fileName.substring( sufIdx + 1 ).toLowerCase( Locale.JAPAN );
833                            }
834                    }
835                    return suffix;
836            }
837    
838            /**
839             * ドキュメント?変換を行うための簡易メソ?です?
840             *
841             * 変換方法?、?力ファイルの拡張子により自動的に決定されます?
842             *
843             * @param       inputFile       入力ファイル?
844             * @param       outputFile      出力ファイル?
845             * @see #convert(String[], String, boolean)
846             */
847            public static final void convert( final String inputFile, final String outputFile ) {
848                    convert( StringUtil.csv2Array( inputFile ), outputFile );
849            }
850    
851            /**
852             * ドキュメント?変換を行うための簡易メソ?です?
853             *
854             * 変換方法?、?力ファイルの拡張子により自動的に決定されます?
855             *
856             * @param       inputFile       入力ファイル名??
857             * @param       outputFile      出力ファイル?
858             * @see #convert(String[], String, boolean)
859             */
860            public static final void convert( final String[] inputFile, final String outputFile ) {
861                    convert( inputFile, outputFile, true );
862            }
863    
864            /**
865             * ドキュメント?変換を行うための簡易メソ?です?
866             *
867             * 変換方法?、?力ファイルの拡張子により自動的に決定されます?
868             *
869             * isOnlineがtrueに?された場合?soffice.binのプロセスをファクトリークラス経由で生?し?
870             * キャ?ュします?
871             * ?、シス?リソースが読み込まれな??、バ?ファイルから起動した?合?、この方法?
872             * 利用できな?め?isOnlineをfalseに?する?があります?
873             *
874             * @param       inputFile       入力ファイル名??
875             * @param       outputFile      出力ファイル?
876             * @param       isOnline        オンライン(Web環?の使用)かど?
877             */
878            public static final void convert( final String inputFile[], final String outputFile, final boolean isOnline ) {
879                    DocConverter_OOO dc = new DocConverter_OOO( inputFile, isOnline );
880                    try {
881                            dc.open();
882                            dc.auto( outputFile );
883                            dc.close();
884                    }
885                    catch ( Throwable th ) {
886                            dc.close( true );
887                            throw new HybsSystemException( th );
888                    }
889            }
890    
891            /**
892             * ドキュメント?変換を行います?
893             *
894             * 変換方法?、?力ファイルの拡張子により自動的に決定されます?
895             *
896             * @og.rev 4.3.1.1 (2008/08/23) mkdirs の戻り?判?
897             *
898             * @param       args    コマンド引数配?
899             * @throws Exception
900             */
901            public static void main( final String[] args ) throws Exception {
902                    if( args.length < 2 ) {
903                            System.out.println( "usage : OdsConverter [inputFile or inputDir] [outputDir]" );
904                            return;
905                    }
906    
907                    File input = new File( args[0] );
908                    File output = new File( args[1] );
909    
910                    // 4.3.1.1 (2008/08/23) mkdirs の戻り?判?
911                    if( output.mkdirs() ) {
912                            System.err.println( args[1] + " の ?レクトリ作?に失敗しました? );
913                    }
914    
915                    if( input.isDirectory() ) {
916                            File[] inputFiles = input.listFiles();
917                            for( int i = 0; i<inputFiles.length; i++ ) {
918                                    String inputFile = inputFiles[i].getAbsolutePath();
919                                    String outputFile = output.getAbsolutePath() + File.separator + inputFiles[i].getName().replace( ".xls", ".ods" );
920                                    convert( StringUtil.csv2Array( inputFile ), outputFile, false );
921                            }
922                    }
923                    else {
924                            String inputFile = input.getAbsolutePath();
925                            String outputFile = output.getAbsolutePath() + File.separator + input.getName().replace( ".xls", ".ods" );
926                            convert( StringUtil.csv2Array( inputFile ), outputFile, false );
927                    }
928            }
929    }