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}