    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.report2;
    017
    018import java.io.File;
    019import java.util.Map;
    020import java.util.HashMap;
    021import java.util.Locale;
    022// import java.util.List;                                                                               // 8.0.3.0 (2021/12/17) 【保留】
    023import java.nio.file.Files;                                                                             // 8.1.0.3 (2022/01/21)
    024import java.nio.file.Paths;                                                                             // 8.1.0.3 (2022/01/21)
    025import java.nio.file.Path;                                                                              // 8.1.0.3 (2022/01/21)
    026import java.nio.file.StandardCopyOption;                                                // 8.1.0.3 (2022/01/21)
    027
    028// import org.opengion.fukurou.system.HybsConst;                                // 8.0.1.0 (2021/10/29)
    029// import org.opengion.fukurou.model.ExcelModel;                                // 8.0.3.0 (2021/12/17)【保留】
    030import org.opengion.fukurou.util.FileUtil;
    031import org.opengion.fukurou.util.StringUtil;
    032import org.opengion.hayabusa.common.HybsSystem;
    033import org.opengion.hayabusa.common.HybsSystemException;
    034import static org.opengion.fukurou.system.HybsConst.CR ;                // 6.1.0.0 (2014/12/26)
    035// import static org.opengion.fukurou.system.HybsConst.FS ;             // 8.0.3.0 (2021/12/17)
    036
    037import com.sun.star.beans.PropertyValue;
    038import com.sun.star.frame.XComponentLoader;
    039import com.sun.star.frame.XController;
    040import com.sun.star.frame.XDispatchHelper;
    041import com.sun.star.frame.XDispatchProvider;
    042import com.sun.star.frame.XModel;
    043import com.sun.star.frame.XStorable;
    044import com.sun.star.io.IOException;
    045import com.sun.star.lang.EventObject;
    046import com.sun.star.lang.IllegalArgumentException;
    047import com.sun.star.lang.XComponent;
    048import com.sun.star.uno.UnoRuntime;
    049import com.sun.star.util.CloseVetoException;
    050import com.sun.star.util.XCloseable;
    051import com.sun.star.view.PrintJobEvent;
    052import com.sun.star.view.PrintableState;
    053import com.sun.star.view.XPrintJobBroadcaster;
    054import com.sun.star.view.XPrintJobListener;
    055import com.sun.star.view.XPrintable;
    056
    057import com.sun.star.sheet.XCalculatable;                                                // 8.1.1.2 (2022/02/25)
    058
    059/**
    060 * OpenOfficeを利用して様々な形式のﾌｧｲﾙを読み込み､出力･印刷を行うための変換ｸﾗｽです｡
    061 *
    062 * 変換を行うことのできる入出力のﾌｫｰﾏｯﾄ以下の通りです｡
    063 *
    064 * [対応ﾌｫｰﾏｯﾄ]
    065 *  入力[Calc(ods)   ,Excel(xls)     ] ⇒ 出力[Calc(ods)   ,Excel(xls,xlsx)      ,PDF]
    066 *  入力[Writer(odt) ,Word(doc)      ] ⇒ 出力[Writer(odt) ,Word(doc,docx)       ,PDF]
    067 *  入力[Impress(odp),PowerPoint(ppt)] ⇒ 出力[Impress(odp),PowerPoint(ppt,pptx) ,PDF]
    068 *  入力[ * 上記の全て               ] ⇒ 印刷
    069 *
    070 * ※ xlsx,docx,pptx は､MS 2007形式の為､LibreOffice のみ利用できます｡
    071 *
    072 * 変換を行うには､以下の2通りの方法があります｡
    073 * <del>
    074 * (1)簡易的な変換ﾒｿｯﾄﾞを利用する場合
    075 *   #convert(String, String)を利用して､変換を行います｡
    076 *   この場合､出力形式は､出力ﾌｧｲﾙの拡張子に従って自動的に決定されます｡
    077 *   このため､印刷処理などを行う場合は､(2)の方法で出力して下さい｡
    078 * </del>
    079 * (2)段階的に各ﾒｿｯﾄﾞを呼び出して変換する場合
    080 *   ｵﾌﾞｼﾞｪｸﾄを生成した後､{@link #open()}､#(各種変換ﾒｿｯﾄﾞ)､{@link #clone()}を
    081 *   順番に呼び出して変換を行います｡
    082 *   この場合､出力形式は､それに対応するﾒｿｯﾄﾞを呼び出すことで決定されます｡
    083 *
    084 *   また､変換を行うための､各種ﾒｿｯﾄﾞは､例外としてThrowableを投げるように定義されています｡
    085 *   このｸﾗｽを利用する場合は､このThrowableをcatchし､catch句で､必ず{@link #close( boolean )}に､
    086 *   "true"(ｴﾗｰ発生時のｸﾛｰｽﾞ処理)を指定して､終了処理を行って下さい｡
    087 *   (これを行わない場合､OpenOfficeの不要なﾌﾟﾛｾｽが残ってしまう可能性があります)
    088 *
    089 * また､出力ﾌｧｲﾙが既に存在する場合､出力ﾌｧｲﾙは一旦削除された後､処理されます｡
    090 * なお､入力ﾌｧｲﾙと出力ﾌｧｲﾙが同じ場合､何も処理されません｡(例外も発行されません)
    091 *
    092 * 入力ﾌｧｲﾙを､CSV形式で複数指定した場合､複数の入力ﾌｧｲﾙをﾏｰｼﾞして出力します｡
    093 * ※1 現状は､ﾌｧｲﾙのﾏｰｼﾞは､入力ﾌｧｲﾙがExcelまたはCalcの場合のみ対応しています｡
    094 *
    095 * ※ DocConverter は､ｸﾗｳﾄﾞ対応されていません｡変換時はﾛｰｶﾙﾌｧｲﾙ間で行ってください｡
    096 *
    097 * @og.group 帳票ｼｽﾃﾑ
    098 *
    099 * @version  4.0
    100 * @author   Hiroki.Nakamura
    101 * @since    JDK1.6
    102 */
    103public class DocConverter_OOO {
    104//      // XLSX は、LibreOffice のみ実行可能なので、その判定用に使用する。
    105//      private static final String OFFICE_HOME = HybsConst.getenv( "OFFICE_HOME","NULL" );     // 8.0.1.0 (2021/10/29) 環境変数から取得
    106
    107        private final boolean                   isOnline;                       // ｵﾝﾗｲﾝ処理かどうか(ｵﾝﾗｲﾝ処理の場合､ﾌﾟﾛｾｽはﾌｧｸﾄﾘｸﾗｽ経由で生成されます)
    108        private final String[]                  mergeFile;
    109
    110        private String                                  inputName;
    111        private String                                  origName;
    112
    113        private XComponent                              xComp;                          // 5.1.8.0 (2010/07/01) ﾒｿｯﾄﾞと重なる変数名の変更
    114        private SOfficeProcess                  soffice;
    115
    116        // 入力､出力の拡張子とこれに対応するﾌｨﾙﾀｰ名
    117        // share¥registry¥calc.xcd 形式のﾌｧｲﾙ <node oor:name="****" 部分？
    118
    119        /** staticｲﾆｼｬﾗｲｻﾞ後､読み取り専用にするので､ConcurrentHashMap を使用しません｡ */
    120        private static final Map<String,String> FILTER_MAP      = new HashMap<>();              // 6.4.1.1 (2016/01/16) filterMap → FILTER_MAP refactoring
    121        static {
    122                // 8.1.0.3 (2022/01/21) ﾌｧｲﾙの拡張子が同じ場合は、copyで対応する。
    123        //      FILTER_MAP.put( "ods_ods", "calc8" );
    124                FILTER_MAP.put( "xls_ods", "calc8" );
    125                FILTER_MAP.put( "ods_xls", "MS Excel 97" );
    126        //      FILTER_MAP.put( "xls_xls", "MS Excel 97" );
    127                FILTER_MAP.put( "ods_pdf", "calc_pdf_Export" );
    128                FILTER_MAP.put( "xls_pdf", "calc_pdf_Export" );
    129        //      FILTER_MAP.put( "odt_odt", "writer8" );
    130                FILTER_MAP.put( "doc_odt", "writer8" );
    131                FILTER_MAP.put( "odt_doc", "MS Word 97" );
    132        //      FILTER_MAP.put( "doc_doc", "MS Word 97" );
    133                FILTER_MAP.put( "odt_pdf", "writer_pdf_Export" );
    134                FILTER_MAP.put( "doc_pdf", "writer_pdf_Export" );
    135        //      FILTER_MAP.put( "odp_odp", "impress8" );
    136                FILTER_MAP.put( "ppt_odp", "impress8" );
    137                FILTER_MAP.put( "odp_ppt", "MS PowerPoint 97" );
    138        //      FILTER_MAP.put( "ppt_ppt", "MS PowerPoint 97" );
    139                FILTER_MAP.put( "odp_pdf", "impress_pdf_Export" );
    140                FILTER_MAP.put( "ppt_pdf", "impress_pdf_Export" );
    141
    142//              if( OFFICE_HOME.contains( "LibreOffice" ) ) {                                           // 8.0.1.0 (2021/10/29) LibreOffice の時のみ使用可能
    143        //              FILTER_MAP.put( "ods_xlsx", "Calc MS Excel 2007 XML" );                 // 8.0.1.0 (2021/10/29)
    144        //              FILTER_MAP.put( "xls_xlsx", "Calc MS Excel 2007 XML" );                 // 8.0.1.0 (2021/10/29)
    145
    146                        FILTER_MAP.put( "ods_xlsx", "Calc Office Open XML" );                   // 8.0.1.0 (2021/10/29)
    147                        FILTER_MAP.put( "xls_xlsx", "Calc Office Open XML" );                   // 8.0.1.0 (2021/10/29)
    148
    149                        // share¥registry¥writer.xcd
    150                        FILTER_MAP.put( "odt_docx", "MS Word 2007 XML" );                               // 8.0.1.0 (2021/10/29)
    151                        FILTER_MAP.put( "doc_docx", "MS Word 2007 XML" );                               // 8.0.1.0 (2021/10/29)
    152                        // ※ writer_MS_Word_2007 は､failed: 0x81a(Error Area:Io Class:Parameter Code:26)
    153
    154                        // share¥registry¥impress.xcd
    155                        FILTER_MAP.put( "odp_pptx", "Impress MS PowerPoint 2007 XML" ); // 8.0.1.0 (2021/10/29)
    156                        FILTER_MAP.put( "ppt_pptx", "Impress MS PowerPoint 2007 XML" ); // 8.0.1.0 (2021/10/29)
    157                        // ※ MS PowerPoint 2007 XML は､failed: 0x81a(Error Area:Io Class:Parameter Code:26)
    158                        // ※ Office Open XML Presentation は､failed: 0x81a(Error Area:Io Class:Parameter Code:26)
    159//              }
    160        };
    161
    162        /**
    163         * ｺﾝｽﾄﾗｸﾀです｡
    164         *
    165         * #DocConverter(input, true)と同じです｡
    166         *
    167         * @param input ﾌｧｲﾙ一覧(CSV形式)
    168         * @see #DocConverter_OOO(String[])
    169         */
    170        public DocConverter_OOO( final String input ) {
    171                this( StringUtil.csv2Array( input ), true );
    172        }
    173
    174        /**
    175         * ｺﾝｽﾄﾗｸﾀです｡
    176         *
    177         * #DocConverter(input, true)と同じです｡
    178         *
    179         * @param input ﾌｧｲﾙ一覧(配列)
    180         * @see #DocConverter_OOO(String[], boolean)
    181         */
    182        public DocConverter_OOO( final String input[] ) {
    183                this( input, true );
    184        }
    185
    186        /**
    187         * ｺﾝｽﾄﾗｸﾀです｡
    188         *
    189         * isOnline(isOl)がtrueに指定された場合､soffice.binのﾌﾟﾛｾｽをﾌｧｸﾄﾘｰｸﾗｽ経由で生成し､
    190         * ｷｬｯｼｭします｡
    191         * 但し､ｼｽﾃﾑﾘｿｰｽが読み込まれないような､ﾊﾞｯﾁﾌｧｲﾙから起動した場合は､この方法は
    192         * 利用できないため､isOnlineをfalseに指定する必要があります｡
    193         *
    194         * @param input ﾌｧｲﾙ一覧(配列)
    195         * @param isOl ｵﾝﾗｲﾝ(Web環境での使用)かどうか
    196         */
    197        public DocConverter_OOO( final String input[], final boolean isOl ) {
    198                if( input == null || input.length == 0 || input[0].isEmpty() ) {
    199                        throw new HybsSystemException( "入力ﾌｧｲﾙが指定されていません｡" );
    200                }
    201                origName = input[0];
    202                final File inFile = new File( origName );
    203                if( !inFile.exists() ) {
    204                        throw new HybsSystemException( "入力ﾌｧｲﾙが存在しません｡[file=" + input[0] + "]" );
    205                }
    206                isOnline  = isOl;
    207                inputName = origName;
    208//              origName  = input[0];
    209
    210                if( input.length == 1 ) {
    211                        mergeFile = null;
    212                }
    213                else {
    214                        if( !"xls".equals( getSuffix( origName ) ) && !"ods".equals( getSuffix( origName ) ) ) {
    215                                throw new HybsSystemException( "ﾌｧｲﾙのﾏｰｼﾞを行う場合､入力ﾌｧｲﾙは､ExcelまたはCacl形式である必要があります｡" );
    216                        }
    217
    218                        mergeFile = new String[input.length-1];
    219                        for( int i=0; i<mergeFile.length; i++ ) {
    220                                final String mrgFile = input[i+1];
    221                                if( mrgFile.isEmpty() || !( new File( mrgFile ) ).exists() ) {
    222                                        throw new HybsSystemException( "ﾏｰｼﾞﾌｧｲﾙが指定されていないか､または存在しません｡[file=" + mrgFile + "]" );
    223                                }
    224                                if( inputName.equals( mrgFile ) ) {
    225                                        throw new HybsSystemException( "ﾏｰｼﾞﾌｧｲﾙに入力ﾌｧｲﾙと同じﾌｧｲﾙが指定されてます｡[file=" + mrgFile + "]" );
    226                                }
    227                                if( !"xls".equals( getSuffix( mrgFile ) ) && !"ods".equals( getSuffix( mrgFile ) ) ) {
    228                                        throw new HybsSystemException( "ﾌｧｲﾙのﾏｰｼﾞを行う場合､ﾏｰｼﾞﾌｧｲﾙは､ExcelまたはCacl形式である必要があります｡" );
    229                                }
    230                                mergeFile[i] = mrgFile;
    231                        }
    232                }
    233        }
    234
    235        /**
    236         * SOficeのｺﾝﾎﾟｰﾈﾝﾄを起動します｡
    237         *
    238         * 正常に処理が終了した場合は､#close()を発行し､終了処理を行って下さい｡
    239         * また､例外が発生した場合は､#close(true)を発行し､終了処理を行って下さい｡
    240         *
    241         * @og.rev 5.1.7.0 (2010/06/01) ﾏｰｼﾞ処理対応
    242         *
    243         * @throws Throwable 何らかのｴﾗｰが発生した場合｡
    244         * @see #close()
    245         * @see #close(boolean)
    246         */
    247        public void open() throws Throwable {
    248                // ﾌﾟﾛｾｽの取得
    249                if( soffice == null ) {
    250                        if( isOnline ) {
    251                                soffice = ProcessFactory.newInstance();
    252                        }
    253                        else {
    254                                soffice = new SOfficeProcess( "docconverter.class" );
    255                                soffice.bootstrap();
    256                        }
    257
    258                        // ﾏｰｼﾞする場合は､ﾏｰｼﾞ対象のﾌｧｲﾙをﾃﾝﾎﾟﾗﾘにｺﾋﾟｰする(readOnly回避のため)
    259                        // ﾃﾝﾌﾟﾚｰﾄ(無題)として上げると､ｼｰﾄｺﾋﾟｰ先として特定できなくなるため
    260                        if( mergeFile != null ) {
    261                                final File origFile = new File( origName );
    262                                inputName = soffice.getTempPath() + System.currentTimeMillis() + "_" + origFile.getName();
    263                                FileUtil.copy( origFile, new File( inputName ) );
    264                        }
    265                }
    266
    267                // 5.1.7.0 (2010/06/01) ﾏｰｼﾞ処理対応
    268                xComp = getComponent( inputName, ( mergeFile == null ? true : false ), false );
    269
    270                if( mergeFile != null ) {
    271                        for( int i=0; i<mergeFile.length; i++ ) {
    272                                merge( mergeFile[i] );
    273                        }
    274                }
    275        }
    276
    277        /**
    278         * ﾄﾞｷｭﾒﾝﾄｺﾝﾎﾟｰﾈﾝﾄを取得します｡
    279         *
    280         * @param       input                   ﾌｧｲﾙ名
    281         * @param       isHidden                隠し属性[true/false]
    282         * @param       isAsTemplate    OpenOffice上のTemplate属性[true/false]
    283         *
    284         * @og.rev 8.1.0.2 (2022/01/14) odsﾌｫｰﾏｯﾄｴﾗｰ時には、rtnDoc が null になる
    285         * @og.rev 8.1.1.2 (2022/02/25) calcの計算式がLibreOfficeで実行されない対応
    286         *
    287         * @return      ﾄﾞｷｭﾒﾝﾄｺﾝﾎﾟｰﾈﾝﾄ
    288         */
    289//      @SuppressWarnings("cast")       // OpenOffice 3.2 での冗長なｷｬｽﾄ警告の抑止｡ｷｬｽﾄをはずすと､旧3.1 では､ｴﾗｰになる｡
    290        private XComponent getComponent( final String input, final boolean isHidden, final boolean isAsTemplate ) {
    291                final PropertyValue[] calcProps = new PropertyValue[2];
    292                calcProps[0] = new PropertyValue();
    293                calcProps[0].Name = "Hidden";
    294                calcProps[0].Value = isHidden;
    295                calcProps[1] = new PropertyValue();
    296                calcProps[1].Name = "AsTemplate";
    297                calcProps[1].Value = isAsTemplate;
    298
    299                final String url = "file:///" + input.replace( '\\', '/' );
    300
    301                XComponent rtnDoc;
    302//              final XComponentLoader cloader = (XComponentLoader) UnoRuntime.queryInterface( XComponentLoader.class, soffice.getDesktop() );
    303                final XComponentLoader cloader = UnoRuntime.queryInterface( XComponentLoader.class, soffice.getDesktop() );
    304                try {
    305                        rtnDoc = cloader.loadComponentFromURL( url, "_blank", 0, calcProps );
    306
    307                        // 8.1.1.2 (2022/02/25) calcの計算式がLibreOfficeで実行されない対応
    308                        final XCalculatable calc = UnoRuntime.queryInterface(XCalculatable.class,rtnDoc);
    309                //      calc.enableAutomaticCalculation(true);
    310                        calc.calculateAll();
    311                }
    312                catch( final IOException ex ) {
    313                        throw new HybsSystemException( "OpenOfficeの立ち上げ時にｴﾗｰが発生しました(入出力ｴﾗｰ)｡", ex );
    314                }
    315                catch( final IllegalArgumentException ex ) {
    316                        throw new HybsSystemException( "OpenOfficeの立ち上げ時にｴﾗｰが発生しました(ﾊﾟﾗﾒｰﾀｰ不正)｡", ex );
    317                }
    318
    319                // 8.1.0.2 (2022/01/14)
    320                if( rtnDoc == null ) {
    321                        final String errMsg = "OpenOffice[" + input + "]ﾌｧｲﾙが不正です｡" + CR
    322                                                                + "印刷範囲設定や、ﾃﾞｰﾀにCTRL文字等が含まれていないかご確認ください｡";
    323                        throw new HybsSystemException( errMsg );
    324                }
    325
    326                return rtnDoc;
    327        }
    328
    329        /**
    330         * ﾄﾞｷｭﾒﾝﾄ(xls,ods)のﾏｰｼﾞを行います｡
    331         *
    332         * @param mergeInputName ﾏｰｼﾞ対象のﾌｧｲﾙ名
    333         */
    334//      @SuppressWarnings("cast")       // OpenOffice 3.2 での冗長なｷｬｽﾄ警告の抑止｡ｷｬｽﾄをはずすと､旧3.1 では､ｴﾗｰになる｡
    335        private void merge( final String mergeInputName ) {
    336                // ﾏｰｼﾞする副ﾌｧｲﾙは､ﾃﾝﾌﾟﾚｰﾄ(無題)として上げる(readOnly回避のため)
    337                final XComponent subDoc = getComponent( mergeInputName, false, true );
    338
    339                final XDispatchProvider dispatchProvider
    340//                      = (XDispatchProvider)UnoRuntime.queryInterface( XDispatchProvider.class
    341                        = UnoRuntime.queryInterface( XDispatchProvider.class
    342//                              ,((XController)UnoRuntime.queryInterface( XController.class
    343                                ,(UnoRuntime.queryInterface( XController.class
    344//                                      ,((XModel)UnoRuntime.queryInterface( XModel.class
    345                                        ,(UnoRuntime.queryInterface( XModel.class
    346                                                ,subDoc
    347                                        )).getCurrentController()
    348                                )).getFrame()
    349                        );
    350
    351                final XDispatchHelper xDispatchHelper = soffice.getDispatcher();
    352                xDispatchHelper.executeDispatch(dispatchProvider, ".uno:TableSelectAll", "", 0, new PropertyValue[0]);
    353
    354                String title = new File( inputName ).getName() ;
    355                title = title.substring( 0, title.indexOf( '.' ) );
    356
    357                final PropertyValue[] moveProps = new PropertyValue[3];
    358                moveProps[0] = new PropertyValue();
    359                moveProps[0].Name = "DocName";
    360                moveProps[0].Value = title;
    361                moveProps[1] = new PropertyValue();
    362                moveProps[1].Name = "Index";
    363                moveProps[1].Value = 32767;
    364                moveProps[2] = new PropertyValue();
    365                moveProps[2].Name = "Copy";
    366                moveProps[2].Value = true;
    367                xDispatchHelper.executeDispatch(dispatchProvider, ".uno:Move", "", 0, moveProps);
    368
    369                closeComponent( subDoc );
    370        }
    371
    372        /**
    373         * Calcｺﾝﾎﾟｰﾈﾝﾄをｸﾛｰｽﾞします｡
    374         *
    375         * このｸﾛｰｽﾞ処理は､処理が正常終了した場合に呼び出しする必要があります｡
    376         * 例外が発生した場合は､#close(true)を発行し､終了処理を行って下さい｡
    377         *
    378         * このﾒｿｯﾄﾞは#close(false)と同じです｡
    379         *
    380         * @throws Throwable 何らかのｴﾗｰが発生した場合｡
    381         * @see #close(boolean)
    382         */
    383        public void close() throws Throwable {
    384                close( false );
    385        }
    386
    387        /**
    388         * Calcｺﾝﾎﾟｰﾈﾝﾄをｸﾛｰｽﾞします｡
    389         *
    390         * 引数のisErrがtrueの場合､この変換ｵﾌﾞｼﾞｪｸﾄで生成されたﾌﾟﾛｾｽは強制的に破棄されます｡
    391         * falseの場合は､ﾌﾟﾛｾｽは､ﾌｧｸﾄﾘｸﾗｽを経由して､ｷｬｯｼｭに戻されます｡
    392         * (ﾊﾞｯﾁ処理の場合は､いずれの場合も､ﾌﾟﾛｾｽは強制的に破棄されます)
    393         *
    394         * 起動から変換､ｸﾛｰｽﾞまでの書く処理で例外が発生した場合は､#close(true)を発行し､終了処理を行って下さい｡
    395         *
    396         * #close(false)は#close()と同じであるため､通常利用することはありません｡
    397         *
    398         * @og.rev 4.2.4.1 (2008/07/07 ) 終了処理を60回で終わるように修正
    399         * @og.rev 4.3.0.0 (2008/07/15 ) ↑は6秒しか待っていなかったので､60秒待つように修正
    400         *
    401         * @param       isErr   trueの場合､この変換ｵﾌﾞｼﾞｪｸﾄで生成されたﾌﾟﾛｾｽは強制的に破棄されます｡
    402         */
    403//      @SuppressWarnings("cast")       // OpenOffice 3.2 での冗長なｷｬｽﾄ警告の抑止｡ｷｬｽﾄをはずすと､旧3.1 では､ｴﾗｰになる｡
    404        public void close( final boolean isErr ) {
    405                if( xComp != null ) {
    406                        closeComponent( xComp );
    407                }
    408
    409                if( soffice != null ) {
    410                        if( isOnline ) {
    411                                if( isErr ) {
    412                                        ProcessFactory.remove( soffice );
    413                                }
    414                                else {
    415                                        ProcessFactory.release( soffice );
    416                                }
    417                        }
    418                        else {
    419                                soffice.close();
    420                        }
    421                }
    422
    423                // ﾏｰｼﾞした場合は､ﾃﾝﾎﾟﾗﾘにｺﾋﾟｰしたﾌｧｲﾙを削除
    424                // 6.0.0.1 (2014/04/25) These nested if statements could be combined
    425                if( mergeFile != null && ! ( new File( inputName ) ).delete() ) {
    426                        System.err.println( "ﾃﾝﾎﾟﾗﾘにｺﾋﾟｰしたﾌｧｲﾙを削除できませんでした｡[" + inputName + "]" );
    427                }
    428        }
    429
    430        /**
    431         * ﾄﾞｷｭﾒﾝﾄｺﾝﾎﾟｰﾈﾝﾄをｸﾛｰｽﾞします｡
    432         *
    433         * @param comp ﾄﾞｷｭﾒﾝﾄｺﾝﾎﾟｰﾈﾝﾄ
    434         */
    435//      @SuppressWarnings("cast")       // OpenOffice 3.2 での冗長なｷｬｽﾄ警告の抑止｡ｷｬｽﾄをはずすと､旧3.1 では､ｴﾗｰになる｡
    436        private void closeComponent( final XComponent comp ) {
    437                XCloseable closeable = null;
    438                for( int i=0;; ++i ) {
    439                        try {
    440//                              closeable = (XCloseable) UnoRuntime.queryInterface( XCloseable.class, comp );
    441                                closeable = UnoRuntime.queryInterface( XCloseable.class, comp );
    442                                closeable.close( true );
    443                                break;
    444                        }
    445                        catch( final CloseVetoException ex ) {
    446                                // 4.2.4.1 (2008/07/07 )
    447                                // 4.3.4.4 (2009/01/01)
    448                                if( i == 600 ) { throw new HybsSystemException( "sofficeﾌﾟﾛｾｽに接続できません｡", ex ); }
    449                                try {
    450                                        Thread.sleep( 100 );
    451                                }
    452                                catch( final InterruptedException ex2 ) {
    453                        //              throw new HybsSystemException( ex2 );
    454                                }
    455                        }
    456                }
    457        }
    458
    459        /**
    460         * 印刷を行います｡
    461         *
    462         * 正常に処理が終了した場合は､#close()を発行し､終了処理を行って下さい｡
    463         * また､例外が発生した場合は､#close(true)を発行し､終了処理を行って下さい｡
    464         *
    465         * @og.rev 4.3.0.0 (2008/07/16) ｽﾌﾟｰﾙが終わるまでwaitし､さらにﾌﾟﾘﾝﾀ発行の状況を監視し､正常終了かどうかを判断
    466         * @og.rev 4.3.7.3 (2009/06/22) 存在しないﾌﾟﾘﾝﾀｰを指定した場合のｴﾗｰﾊﾝﾄﾞﾘﾝｸﾞを追加
    467         * @og.rev 5.1.2.0 (2010/01/01) CentOS等は､OS_INFOがLinux UNKNOWNとなるため､判定条件を変更
    468         *
    469         * @param       printer ﾌﾟﾘﾝﾀｰ名
    470         * @throws Throwable 何らかのｴﾗｰが発生した場合｡
    471         */
    472        public void print( final String printer ) throws Throwable {
    473                if( printer == null || printer.isEmpty() ) {
    474                        throw new HybsSystemException( "ﾌﾟﾘﾝﾀｰが指定されていません｡" );
    475                }
    476
    477        //      if( xComp == null ) { throw new HybsSystemException( "初めに､#open()を実行して下さい(1)" ); }
    478//              @SuppressWarnings("cast")       // OpenOffice 3.2 での冗長なｷｬｽﾄ警告の抑止｡ｷｬｽﾄをはずすと､旧3.1 では､ｴﾗｰになる｡
    479//              final XPrintable xprintable = (XPrintable) UnoRuntime.queryInterface( XPrintable.class, xComp );
    480                final XPrintable xprintable = UnoRuntime.queryInterface( XPrintable.class, xComp );
    481//              @SuppressWarnings("cast")       // OpenOffice 3.2 での冗長なｷｬｽﾄ警告の抑止｡ｷｬｽﾄをはずすと､旧3.1 では､ｴﾗｰになる｡
    482//              final XPrintJobBroadcaster selection = (XPrintJobBroadcaster) UnoRuntime.queryInterface(XPrintJobBroadcaster.class, xprintable);
    483                final XPrintJobBroadcaster selection = UnoRuntime.queryInterface(XPrintJobBroadcaster.class, xprintable);
    484                final MyPrintJobListener listener = new MyPrintJobListener();
    485                selection.addPrintJobListener( listener );
    486
    487                final PropertyValue[] tmpProps = new PropertyValue[1];
    488                tmpProps[0] = new PropertyValue();
    489                tmpProps[0].Name = "Name";
    490                // 5.1.2.0 (2010/01/01) CentOS等は､OS_INFOがLinux UNKNOWNとなるため､判定条件を変更
    491                // OSがLinuxの場合は､ﾌﾟﾘﾝﾀ名称の前後に"<",">"を付加
    492                tmpProps[0].Value = "LINUX".indexOf( HybsSystem.sys( "OS_INFO" ).toUpperCase( Locale.JAPAN ) ) >= 0 ? "<" + printer + ">" : printer;
    493
    494                // 4.3.4.4 (2009/01/01)
    495                try {
    496                        xprintable.setPrinter( tmpProps );
    497                }
    498                catch( final IllegalArgumentException ex ) {
    499                        throw new HybsSystemException( "印刷時にｴﾗｰが発生しました｡", ex );
    500                }
    501
    502                // 4.3.7.3 (2009/06/22) 存在しないﾌﾟﾘﾝﾀを指定した場合は､PropertyValueに
    503                // ﾃﾞﾌｫﾙﾄﾌﾟﾘﾝﾀｰが入るため､引数の値と合致しているかで正しく設定されたかを確認
    504                String curPrinter = null;
    505                for( final PropertyValue chkProp : xprintable.getPrinter() ) {
    506                        if( "Name".equals( chkProp.Name) ) {
    507                                curPrinter = (String)chkProp.Value;
    508                                break;
    509                        }
    510                }
    511
    512//              final PropertyValue[] chkProps = xprintable.getPrinter();
    513//              for( int i=0; i<chkProps.length; i++ ) {
    514//                      if( "Name".equals( chkProps[i].Name) ) {
    515//                              curPrinter = (String)chkProps[i].Value;
    516//                              break;
    517//                      }
    518//              }
    519                if( !(printer.equalsIgnoreCase( curPrinter ) ) ) {
    520                        final String errMsg = "ﾌﾟﾘﾝﾀｰ[" + printer + "]を発行先に指定できませんでした｡" + CR
    521                                                        + "存在しないﾌﾟﾘﾝﾀ名が指定されている可能性があります｡";
    522                        throw new HybsSystemException( errMsg );
    523                }
    524
    525                // 4.3.0.0 (2008/07/16)
    526                final PropertyValue[] printProps = new PropertyValue[1];
    527                printProps[0] = new PropertyValue();
    528                printProps[0].Name = "Wait";
    529                printProps[0].Value = true;
    530
    531                // 4.3.4.4 (2009/01/01)
    532                try {
    533                        xprintable.print( printProps );
    534                }
    535                catch( final IllegalArgumentException ex ) {
    536                        throw new HybsSystemException( "印刷時にｴﾗｰが発生しました｡", ex );
    537                }
    538
    539                // 4.3.0.0 (2008/07/16)
    540                // 6.9.7.0 (2018/05/14) PMD Useless parentheses.
    541//              if( listener.getStatus() == null
    542//                              || listener.getStatus() != PrintableState.JOB_COMPLETED && listener.getStatus() != PrintableState.JOB_SPOOLED ) {
    543                if( listener.isError() ) {
    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 final class MyPrintJobListener implements XPrintJobListener {
    554                private PrintableState status   ;
    555
    556                /**
    557                 * PrintJobEventのｽﾃｰﾀｽを内部変数にｾｯﾄします｡
    558                 *
    559                 * @param       event   PrintJobEventｵﾌﾞｼﾞｪｸﾄ
    560                 */
    561                @Override
    562                public void printJobEvent( final PrintJobEvent event ) {
    563                        status = event.State;
    564                }
    565
    566                /**
    567                 * EventObjectの処理を実施します｡(ここでは何も行いません｡)
    568                 *
    569                 * @param       event   EventObjectｵﾌﾞｼﾞｪｸﾄ
    570                 */
    571                @Override
    572                public void disposing( final EventObject event ) {
    573                        // 何もありません｡(PMD ｴﾗｰ回避)
    574                }
    575
    576//              /**
    577//               * PrintableStateｵﾌﾞｼﾞｪｸﾄを返します｡
    578//               *
    579//               * @og.rev 8.0.3.0 (2021/12/17) Delete
    580//               *
    581//               * @return      PrintableStateｵﾌﾞｼﾞｪｸﾄ
    582//               */
    583//              public PrintableState getStatus() {
    584//                      return status;
    585//              }
    586
    587                /**
    588                 * PrintableStateｵﾌﾞｼﾞｪｸﾄの状態を返します｡
    589                 *
    590                 * statusが nullか､COMPLETEDでなく､SPOOLEDでない場合にｴﾗｰと判断します｡
    591                 *
    592                 * @return      ｴﾗｰの場合､true
    593                 */
    594                public boolean isError() {
    595                        return status == null || status != PrintableState.JOB_COMPLETED && status != PrintableState.JOB_SPOOLED ;
    596                }
    597        }
    598
    599        /**
    600         * Calc(ods)出力を行います｡
    601         *
    602         * 入力形式で未対応の場合(形式は入力ﾌｧｲﾙの拡張子で判別)､例外が発行されます｡
    603         *
    604         * 正常に処理が終了した場合は､#close()を発行し､終了処理を行って下さい｡
    605         * また､例外が発生した場合は､#close(true)を発行し､終了処理を行って下さい｡
    606         *
    607         * @param       outputName      出力ﾌｧｲﾙ名
    608         * @throws Throwable 何らかのｴﾗｰが発生した場合｡
    609         */
    610//      public void ods( final String outputName ) throws Throwable {
    611//      //      saveDoc( outputName, getFilterName( getSuffix( inputName ), "ods" ) );
    612//              saveDoc( outputName, getFilterName( inputName, "ods" ) );
    613//      }
    614
    615//      /**
    616//       * Excel(xls)出力を行います｡
    617//       *
    618//       * 入力形式で未対応の場合(形式は入力ﾌｧｲﾙの拡張子で判別)､例外が発行されます｡
    619//       *
    620//       * 正常に処理が終了した場合は､#close()を発行し､終了処理を行って下さい｡
    621//       * また､例外が発生した場合は､#close(true)を発行し､終了処理を行って下さい｡
    622//       *
    623//       * @param       outputName      出力ﾌｧｲﾙ名
    624//       * @throws Throwable 何らかのｴﾗｰが発生した場合｡
    625//       */
    626//      public void xls( final String outputName ) throws Throwable {
    627//      //      saveDoc( outputName, getFilterName( getSuffix( inputName ), "xls" ) );
    628//              saveDoc( outputName, getFilterName( inputName, "xls" ) );
    629//      }
    630
    631//      /**
    632//       * Writer(ods)出力を行います｡
    633//       *
    634//       * 入力形式で未対応の場合(形式は入力ﾌｧｲﾙの拡張子で判別)､例外が発行されます｡
    635//       *
    636//       * 正常に処理が終了した場合は､#close()を発行し､終了処理を行って下さい｡
    637//       * また､例外が発生した場合は､#close(true)を発行し､終了処理を行って下さい｡
    638//       *
    639//       * @param       outputName      出力ﾌｧｲﾙ名
    640//       * @throws Throwable 何らかのｴﾗｰが発生した場合｡
    641//       */
    642//      public void odt( final String outputName ) throws Throwable {
    643//      //      saveDoc( outputName, getFilterName( getSuffix( inputName ), "odt" ) );
    644//              saveDoc( outputName, getFilterName( inputName, "odt" ) );
    645//      }
    646
    647//      /**
    648//       * Word(doc)出力を行います｡
    649//       *
    650//       * 入力形式で未対応の場合(形式は入力ﾌｧｲﾙの拡張子で判別)､例外が発行されます｡
    651//       *
    652//       * 正常に処理が終了した場合は､#close()を発行し､終了処理を行って下さい｡
    653//       * また､例外が発生した場合は､#close(true)を発行し､終了処理を行って下さい｡
    654//       *
    655//       * @param       outputName      出力ﾌｧｲﾙ名
    656//       * @throws Throwable 何らかのｴﾗｰが発生した場合｡
    657//       */
    658//      public void doc( final String outputName ) throws Throwable {
    659//      //      saveDoc( outputName, getFilterName( getSuffix( inputName ), "doc" ) );
    660//              saveDoc( outputName, getFilterName( inputName, "doc" ) );
    661//      }
    662
    663//      /**
    664//       * Impress(odp)出力を行います｡
    665//       *
    666//       * 入力形式で未対応の場合(形式は入力ﾌｧｲﾙの拡張子で判別)､例外が発行されます｡
    667//       *
    668//       * 正常に処理が終了した場合は､#close()を発行し､終了処理を行って下さい｡
    669//       * また､例外が発生した場合は､#close(true)を発行し､終了処理を行って下さい｡
    670//       *
    671//       * @param       outputName      出力ﾌｧｲﾙ名
    672//       * @throws Throwable 何らかのｴﾗｰが発生した場合｡
    673//       */
    674//      public void odp( final String outputName ) throws Throwable {
    675//      //      saveDoc( outputName, getFilterName( getSuffix( inputName ), "odp" ) );
    676//              saveDoc( outputName, getFilterName( inputName, "odp" ) );
    677//      }
    678
    679//      /**
    680//       * PowerPoint(ppt)出力を行います｡
    681//       *
    682//       * 入力形式で未対応の場合(形式は入力ﾌｧｲﾙの拡張子で判別)､例外が発行されます｡
    683//       *
    684//       * 正常に処理が終了した場合は､#close()を発行し､終了処理を行って下さい｡
    685//       * また､例外が発生した場合は､#close(true)を発行し､終了処理を行って下さい｡
    686//       *
    687//       * @param       outputName      出力ﾌｧｲﾙ名
    688//       * @throws Throwable 何らかのｴﾗｰが発生した場合｡
    689//       */
    690//      public void ppt( final String outputName ) throws Throwable {
    691//      //      saveDoc( outputName, getFilterName( getSuffix( inputName ), "ppt" ) );
    692//              saveDoc( outputName, getFilterName( inputName, "ppt" ) );
    693//      }
    694
    695        /**
    696         * PDF出力を行います｡
    697         *
    698         * 入力形式で未対応の場合(形式は入力ﾌｧｲﾙの拡張子で判別)､例外が発行されます｡
    699         *
    700         * 正常に処理が終了した場合は､#close()を発行し､終了処理を行って下さい｡
    701         * また､例外が発生した場合は､#close(true)を発行し､終了処理を行って下さい｡
    702         *
    703         * @og.rev 8.1.0.3 (2022/01/21) checkOutputﾒｿｯﾄﾞは呼出元で判定する。
    704         *
    705         * @param       outputName      出力ﾌｧｲﾙ名
    706         * @param       pdfPasswd       PDFﾊﾟｽﾜｰﾄﾞ
    707         * @throws Throwable 何らかのｴﾗｰが発生した場合｡
    708         */
    709        public void pdf( final String outputName, final String pdfPasswd ) throws Throwable {
    710                if( !checkOutput( outputName ) ){ return; }                     // 8.1.0.3 (2022/01/21)
    711
    712        //      savePdf( outputName, getFilterName( getSuffix( inputName ), "pdf" ), pdfPasswd );
    713                savePdf( outputName, getFilterName( inputName, "pdf" ), pdfPasswd );
    714        }
    715
    716        //      /**
    717        //       * 【保留】Excel2007(xlsx)出力を行います｡
    718        //       *
    719        //       * 入力形式で未対応の場合(形式は入力ﾌｧｲﾙの拡張子で判別)､例外が発行されます｡
    720        //       *
    721        //       * 正常に処理が終了した場合は､#close()を発行し､終了処理を行って下さい｡
    722        //       * また､例外が発生した場合は､#close(true)を発行し､終了処理を行って下さい｡
    723        //       *
    724        //       * @og.rev 8.0.3.0 (2021/12/17) ods→xlsx変換時のｼｰﾄ毎の行数
    725        //       *
    726        //       * @param       outputName      出力ﾌｧｲﾙ名
    727        //       * @param       sheetRows       ｼｰﾄ毎の行数List
    728        //       * @throws Throwable 何らかのｴﾗｰが発生した場合｡
    729        //       */
    730        //      public void xlsx( final String outputName,final List<Integer> sheetRows ) throws Throwable {
    731        //              saveDoc( outputName, getFilterName( inputName, "xlsx" ) );
    732        //
    733        //              // 余分な行やｶﾗﾑを除去(ただし、ものすごく遅い)
    734        //              final File outputFile = new File( outputName );
    735        //              final ExcelModel excel = new ExcelModel( outputFile , true );
    736        //              excel.activeWorkbook( sheetRows );
    737        //              excel.saveFile( outputFile );
    738        //      }
    739
    740        /**
    741         * 出力ﾌｧｲﾙから出力形式を自動判別し､変換を行います｡
    742         *
    743         * 入出力形式で未対応の場合(形式は入出力ﾌｧｲﾙの拡張子で判別)､例外が発行されます｡
    744         *
    745         * 正常に処理が終了した場合は､#close()を発行し､終了処理を行って下さい｡
    746         * また､例外が発生した場合は､#close(true)を発行し､終了処理を行って下さい｡
    747         *
    748         * @og.rev 8.1.0.3 (2022/01/21) checkOutputﾒｿｯﾄﾞは呼出元で判定する。
    749         *
    750         * @param       outputName      出力ﾌｧｲﾙ名
    751         * @throws Throwable 何らかのｴﾗｰが発生した場合｡
    752         */
    753        public void auto( final String outputName ) throws Throwable {
    754                if( !checkOutput( outputName ) ){ return; }                     // 8.1.0.3 (2022/01/21)
    755
    756                final String outSuffix = getSuffix( outputName );
    757                if( "pdf".equalsIgnoreCase( outSuffix ) ) {
    758//                      savePdf( outputName, getFilterName( getSuffix( inputName ), outSuffix ), null );
    759                        savePdf( outputName, getFilterName( inputName, outSuffix ), null );
    760                }
    761                else {
    762//                      saveDoc( outputName, getFilterName( getSuffix( inputName ), outSuffix ) );
    763                        saveDoc( outputName, getFilterName( inputName, outSuffix ) );
    764                }
    765        }
    766
    767        /**
    768         * ﾌｨﾙﾀｰ名を指定して､各種ﾌｧｲﾙ形式に出力を行います｡
    769         *
    770         * @og.rev 8.1.0.3 (2022/01/21) checkOutputﾒｿｯﾄﾞは呼出元で判定する。
    771         *
    772         * @param       outputName      出力ﾌｧｲﾙ名
    773         * @param       filter          ﾌｨﾙﾀｰ名
    774         */
    775        private void saveDoc( final String outputName, final String filter ) {
    776//              if( !checkOutput( outputName ) ){ return; }
    777
    778                final PropertyValue[] storeProps = new PropertyValue[1];
    779                storeProps[0] = new PropertyValue();
    780                storeProps[0].Name = "FilterName";
    781                storeProps[0].Value = filter;
    782
    783                final String url = "file:///" + outputName.replace( '\\', '/' );
    784        //      if( xComp == null ) { throw new HybsSystemException( "初めに､#open()を実行して下さい(2)" ); }
    785//              @SuppressWarnings("cast")       // OpenOffice 3.2 での冗長なｷｬｽﾄ警告の抑止｡ｷｬｽﾄをはずすと､旧3.1 では､ｴﾗｰになる｡
    786//              final XStorable xstorable = (XStorable) UnoRuntime.queryInterface( XStorable.class, xComp );
    787                final XStorable xstorable = UnoRuntime.queryInterface( XStorable.class, xComp );
    788                try {
    789                        xstorable.storeAsURL( url, storeProps );
    790                }
    791                catch( final Throwable th ) {
    792                        throw new HybsSystemException( "ﾌｧｲﾙへの変換時にｴﾗｰが発生しました｡[filter=" + filter + "]", th );
    793                }
    794        }
    795
    796        /**
    797         * ﾌｨﾙﾀｰを指定してPDF出力を行います｡
    798         *
    799         * @og.rev 8.1.0.3 (2022/01/21) checkOutputﾒｿｯﾄﾞは呼出元で判定する。
    800         *
    801         * @param       outputName      出力ﾌｧｲﾙ名
    802         * @param       filter          ﾌｨﾙﾀｰ名
    803         * @param       pdfPasswd       PDFﾊﾟｽﾜｰﾄﾞ
    804         */
    805        private void savePdf( final String outputName, final String filter, final String pdfPasswd ) {
    806//              if( !checkOutput( outputName ) ){ return; }
    807
    808                final PropertyValue[] storeProps;
    809                if( pdfPasswd == null || pdfPasswd.isEmpty() ) {
    810                        storeProps = new PropertyValue[1];
    811                        storeProps[0] = new PropertyValue();
    812                        storeProps[0].Name = "FilterName";
    813                        storeProps[0].Value = filter;
    814                }
    815                // 帳票要求ﾃｰﾌﾞﾙでPDFﾊﾟｽﾜｰﾄﾞが設定されている場合
    816                else {
    817                        final PropertyValue[] filterProps = new PropertyValue[2];
    818                        filterProps[0] = new PropertyValue();
    819                        filterProps[0].Name = "EncryptFile";
    820                        filterProps[0].Value = true;
    821                        filterProps[1] = new PropertyValue();
    822                        filterProps[1].Name = "DocumentOpenPassword";
    823                        filterProps[1].Value = pdfPasswd;
    824
    825                        storeProps = new PropertyValue[2];
    826                        storeProps[0] = new PropertyValue();
    827                        storeProps[0].Name = "FilterName";
    828                        storeProps[0].Value = "calc_pdf_Export";
    829                        storeProps[1] = new PropertyValue();
    830                        storeProps[1].Name = "FilterData";
    831                        storeProps[1].Value = filterProps;
    832                }
    833
    834                final String url = "file:///" + outputName.replace( '\\', '/' );
    835        //      if( xComp == null ) { throw new HybsSystemException( "初めに､#open()を実行して下さい(3)" ); }
    836//              @SuppressWarnings("cast")       // OpenOffice 3.2 での冗長なｷｬｽﾄ警告の抑止｡ｷｬｽﾄをはずすと､旧3.1 では､ｴﾗｰになる｡
    837//              final XStorable xstorable = (XStorable) UnoRuntime.queryInterface( XStorable.class, xComp );
    838                final XStorable xstorable = UnoRuntime.queryInterface( XStorable.class, xComp );
    839                try {
    840                        xstorable.storeToURL( url, storeProps );
    841                }
    842                catch( final Throwable th ) {
    843                        final String err = "PDFﾌｧｲﾙへの変換時にｴﾗｰが発生しました｡[filter=" + filter + "]"
    844                                                        + " URL=" + url + " , storeProps=" + storeProps + " , xComp=" + xComp ;
    845
    846//                      throw new HybsSystemException( "PDFﾌｧｲﾙへの変換時にｴﾗｰが発生しました｡[filter=" + filter + "]", th );
    847                        throw new HybsSystemException( err, th );
    848                }
    849        }
    850
    851        /**
    852         * 出力ﾌｧｲﾙのﾁｪｯｸを行います｡
    853         *
    854         * @og.rev 8.1.0.3 (2022/01/21) ﾌｧｲﾙの拡張子が同じ場合は、copyで対応する。
    855         *
    856         * @param       outputName      出力ﾌｧｲﾙ名
    857         *
    858         * @return      処理対象かどうか(入力ﾌｧｲﾙと出力ﾌｧｲﾙが同じ場合は､falseが返ります)
    859         */
    860        private boolean checkOutput( final String outputName ) {
    861                if( outputName == null || outputName.isEmpty() ) {
    862                        throw new HybsSystemException( "出力ﾌｧｲﾙが指定されていません｡" );
    863                }
    864
    865                try {
    866                        // 8.1.0.3 (2022/01/21) 出力ﾌｧｲﾙがあれば、無条件削除
    867                        final Path outPath = Paths.get( outputName );
    868                        if( Files.exists( outPath ) ) { Files.delete( outPath ); }
    869//                      if( Files.exists( outPath ) && !Files.deleteIfExists( outPath ) ) {
    870//                              throw new HybsSystemException( "出力先の既存ﾌｧｲﾙが削除できません｡[file=" + outputName + "]" );
    871//                      }
    872
    873                        // 8.1.0.3 (2022/01/21) 拡張子が同じなら、copyする。
    874                        if( getSuffix( inputName ).equals( getSuffix( outputName ) ) ) {
    875                                final Path inPath = Paths.get( inputName );
    876                                Files.copy( inPath , outPath , StandardCopyOption.REPLACE_EXISTING );
    877                                return false;
    878                        }
    879                }
    880//              catch( final IOException ex ) {         // 意味不明なｴﾗｰが出る。
    881                catch( final Throwable ex ) {
    882                        throw new HybsSystemException( "ﾌｧｲﾙｺﾋﾟｰが失敗しました｡[in=" + inputName + "],out=" + outputName + "]" ,ex );
    883                }
    884
    885                return true;
    886
    887//              if( outFile.exists() ) {
    888//                      if( inFile.getAbsoluteFile().equals( outFile.getAbsoluteFile() ) ) {
    889//                              // 入力と出力が同じﾌｧｲﾙの場合な何もしない
    890//                              return false;
    891//                      }
    892//                      else if( !outFile.delete() ) {
    893//                              throw new HybsSystemException( "出力先の既存ﾌｧｲﾙが削除できません｡[file=" + outputName + "]" );
    894//                      }
    895//              }
    896//              return true;
    897        }
    898
    899        /**
    900         * 入出力の形式(拡張子)からﾌｨﾙﾀｰ名を取得します｡
    901         *
    902         * 入力ﾌｧｲﾙ名からｻﾌｨｯｸｽを取り出して､FILTER_MAP からﾌｨﾙﾀｰ名を取り出します｡
    903         *
    904         * @og.rev 8.0.1.0 (2021/10/29) ﾒｯｾｰｼﾞ修正
    905         *
    906//       * @param       inSuffix        入力拡張子
    907         * @param       inputName       入力ﾌｧｲﾙ名
    908         * @param       outSuffix       出力拡張子
    909         *
    910         * @return      ﾌｨﾙﾀｰ名
    911         */
    912//      private static String getFilterName( final String inSuffix, final String outSuffix ) {
    913        private static String getFilterName( final String inputName, final String outSuffix ) {
    914                final String inSuffix = getSuffix( inputName );
    915
    916                final String filterName = FILTER_MAP.get( inSuffix + "_" + outSuffix );
    917                if( filterName == null ) {
    918                        final String errMsg = "入力ﾌｧｲﾙ=[" + inputName + "] , 出力形式=[" + outSuffix + "]" + CR
    919                                                        + "入力形式､出力形式は､以下の対応表に基づき､設定して下さい｡" + CR
    920                                                        + "入力[Calc(ods)   ,Excel(xls)     ] ⇒ 出力[Calc(ods)   ,Excel(xls,xlsx)     ,PDF]" + CR
    921                                                        + "入力[Writer(odt) ,Word(doc)      ] ⇒ 出力[Writer(odt) ,Word(doc,docx)      ,PDF]" + CR
    922                                                        + "入力[Impress(odp),PowerPoint(ppt)] ⇒ 出力[Impress(odp),PowerPoint(ppt,pptx),PDF]" + CR
    923                                                        + "xlsx,docx,pptx は､MS 2007形式の為､LibreOffice のみ利用できます｡" + CR ;
    924                        throw new HybsSystemException( errMsg );
    925                }
    926                return filterName;
    927        }
    928
    929        /**
    930         * ﾌｧｲﾙ名から拡張子(小文字)を求めます｡
    931         *
    932         * @param       fileName        ﾌｧｲﾙ名
    933         *
    934         * @return      拡張子(小文字)…存在しない場合は、空文字列
    935         */
    936        private static String getSuffix( final String fileName ) {
    937//              String suffix = null;
    938                String suffix = "";
    939                if( fileName != null ) {
    940                        final int sufIdx = fileName.lastIndexOf( '.' );
    941                        if( sufIdx >= 0 ) {
    942                                suffix = fileName.substring( sufIdx + 1 ).toLowerCase( Locale.JAPAN );
    943                        }
    944                }
    945                return suffix;
    946        }
    947
    948//      /**
    949//       * ﾄﾞｷｭﾒﾝﾄの変換を行うための簡易ﾒｿｯﾄﾞです｡
    950//       *
    951//       * 変換方法は､出力ﾌｧｲﾙの拡張子により自動的に決定されます｡
    952//       *
    953//       * @og.rev 8.0.3.0 (2021/12/17) ﾌｧｲﾙ連結の簡易ﾒｿｯﾄﾞは、使用しません。
    954//       *
    955//       * @param       inputFile       入力ﾌｧｲﾙ名
    956//       * @param       outputFile      出力ﾌｧｲﾙ名
    957//       * @see #convert(String[], String, boolean)
    958//       */
    959//      public static final void convert( final String inputFile, final String outputFile ) {
    960////            convert( StringUtil.csv2Array( inputFile ), outputFile );
    961//              convert( StringUtil.csv2Array( inputFile ), outputFile, true ); // 8.0.3.0 (2021/12/17)
    962//      }
    963
    964//      /**
    965//       * ﾄﾞｷｭﾒﾝﾄの変換を行うための簡易ﾒｿｯﾄﾞです｡
    966//       *
    967//       * 変換方法は､出力ﾌｧｲﾙの拡張子により自動的に決定されます｡
    968//       *
    969//       * @og.rev 8.0.3.0 (2021/12/17) ﾌｧｲﾙ連結の簡易ﾒｿｯﾄﾞは、使用しません。
    970//       *
    971//       * @param       inputFile       入力ﾌｧｲﾙ名配列
    972//       * @param       outputFile      出力ﾌｧｲﾙ名
    973//       * @see #convert(String[], String, boolean)
    974//       */
    975//      public static final void convert( final String[] inputFile, final String outputFile ) {
    976//              convert( inputFile, outputFile, true );
    977//      }
    978
    979        /**
    980         * ﾄﾞｷｭﾒﾝﾄの変換を行うための簡易ﾒｿｯﾄﾞです｡
    981         *
    982         * 変換方法は､出力ﾌｧｲﾙの拡張子により自動的に決定されます｡
    983         *
    984         * isOnlineがtrueに指定された場合､soffice.binのﾌﾟﾛｾｽをﾌｧｸﾄﾘｰｸﾗｽ経由で生成し､
    985         * ｷｬｯｼｭします｡
    986         * 但し､ｼｽﾃﾑﾘｿｰｽが読み込まれないような､ﾊﾞｯﾁﾌｧｲﾙから起動した場合は､この方法は
    987         * 利用できないため､isOnlineをfalseに指定する必要があります｡
    988         *
    989         * @og.rev 8.0.3.0 (2021/12/17) ﾌｧｲﾙ連結の簡易ﾒｿｯﾄﾞは、使用しません。
    990         *
    991         * @param       inputFile       入力ﾌｧｲﾙ名配列
    992         * @param       outputFile      出力ﾌｧｲﾙ名
    993         * @param       isOnline        ｵﾝﾗｲﾝ(Web環境での使用)かどうか
    994         */
    995        public static final void convert( final String inputFile[], final String outputFile, final boolean isOnline ) {
    996                final DocConverter_OOO dc = new DocConverter_OOO( inputFile, isOnline );
    997                try {
    998                        dc.open();
    999                        dc.auto( outputFile );
    1000                        dc.close();
    1001                }
    1002                catch( final Throwable th ) {
    1003                        dc.close( true );
    1004                        throw new HybsSystemException( th );
    1005                }
    1006        }
    1007
    1008        /**
    1009         * ﾄﾞｷｭﾒﾝﾄの変換を行います｡
    1010         *
    1011         * 変換方法は､出力ﾌｧｲﾙの拡張子により自動的に決定されます｡
    1012         *
    1013         * @og.rev 4.3.1.1 (2008/08/23) mkdirs の戻り値判定
    1014         * @og.rev 6.3.9.1 (2015/11/27) A method/constructor shouldnt explicitly throw java.lang.Exception(PMD)｡
    1015         * @og.rev 8.0.3.0 (2021/12/17) ﾌｧｲﾙ連結の簡易ﾒｿｯﾄﾞは、使用しません。
    1016         *
    1017         * @param       args    ｺﾏﾝﾄﾞ引数配列
    1018         */
    1019        public static void main( final String[] args ) {
    1020                if( args.length < 2 ) {
    1021                        System.out.println( "usage : OdsConverter [inputFile] [outputFile]" );
    1022                        return;
    1023                }
    1024
    1025                DocConverter_OOO.convert( new String[] {args[0]}, args[1], false );
    1026
    1027//              final File input  = new File( args[0] );
    1028//              final File output = new File( args[1] );
    1029//
    1030//              // 4.3.1.1 (2008/08/23) mkdirs の戻り値判定
    1031//              if( outPath.mkdirs() ) {
    1032//                      System.err.println( args[1] + " の ﾃﾞｨﾚｸﾄﾘ作成に失敗しました｡" );
    1033//              }
    1034//
    1035//              final String absPath = output.getAbsolutePath() + FS ;          // 8.0.3.0 (2021/12/17)
    1036//              if( input.isDirectory() ) {
    1037//                      final File[] inputFiles = input.listFiles();
    1038//                      // 6.3.9.0 (2015/11/06) null になっている可能性があるﾒｿｯﾄﾞの戻り値を利用している(findbugs)
    1039//                      if( inputFiles != null ) {
    1040//                              for( final File file : inputFiles ) {
    1041//                                      final String inputFile = file.getAbsolutePath();
    1042////                                    final String outputFile = output.getAbsolutePath() + File.separator + file.getName().replace( ".xls", ".ods" );
    1043//                                      final String outputFile = absPath + file.getName().replace( ".xls", ".ods" );
    1044//                                      convert( StringUtil.csv2Array( inputFile ), outputFile, false );
    1045//                              }
    1046//                      }
    1047//              }
    1048//              else {
    1049//                      final String inputFile = input.getAbsolutePath();
    1050////                    final String outputFile = output.getAbsolutePath() + File.separator + input.getName().replace( ".xls", ".ods" );
    1051//                      final String outputFile = absPath + input.getName().replace( ".xls", ".ods" );
    1052//                      convert( StringUtil.csv2Array( inputFile ), outputFile, false );
    1053//              }
    1054        }
    1055}