/src/enoa/handler/DocumentHandler.java
Java | 617 lines | 415 code | 52 blank | 150 comment | 94 complexity | ac89f902ab03e5cf3619223e91613da2 MD5 | raw file
Possible License(s): LGPL-3.0, Apache-2.0, GPL-3.0, GPL-2.0, AGPL-3.0, JSON, BSD-3-Clause
1/* 2 * This file is part of YaBS. 3 * 4 * YaBS is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * YaBS is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with YaBS. If not, see <http://www.gnu.org/licenses/>. 16 */ 17package enoa.handler; 18 19import ag.ion.bion.officelayer.document.DocumentDescriptor; 20import ag.ion.bion.officelayer.document.DocumentException; 21import ag.ion.bion.officelayer.document.IDocument; 22import ag.ion.bion.officelayer.filter.*; 23import ag.ion.bion.officelayer.form.IFormComponent; 24import ag.ion.bion.officelayer.text.ITextCursor; 25import ag.ion.bion.officelayer.text.ITextDocument; 26import ag.ion.bion.officelayer.text.ITextField; 27import ag.ion.bion.officelayer.text.ITextFieldService; 28import ag.ion.bion.officelayer.text.IVariableTextFieldMaster; 29import ag.ion.bion.officelayer.text.TextException; 30import ag.ion.noa.NOAException; 31import ag.ion.noa.filter.OpenDocumentFilter; 32import com.sun.star.awt.XTextComponent; 33import com.sun.star.beans.PropertyValue; 34import com.sun.star.beans.XPropertySet; 35import com.sun.star.form.XFormComponent; 36import com.sun.star.frame.XStorable; 37import com.sun.star.io.IOException; 38import com.sun.star.uno.UnoRuntime; 39import enoa.connection.NoaConnection; 40import enoa.connection.URLAdapter; 41import java.io.File; 42import java.io.FileFilter; 43import java.io.FileInputStream; 44import java.io.FileNotFoundException; 45import java.io.FileOutputStream; 46import java.io.InputStream; 47import java.net.MalformedURLException; 48import java.net.UnknownHostException; 49import java.util.ArrayList; 50import java.util.Arrays; 51import java.util.HashMap; 52import java.util.Iterator; 53import java.util.List; 54import javax.swing.table.TableModel; 55import mpv5.db.objects.Template; 56import mpv5.db.objects.User; 57import mpv5.globals.GlobalSettings; 58import mpv5.logging.Log; 59import org.jopendocument.util.StringInputStream; 60 61/** 62 * This class OpenOffice Documents IO 63 */ 64public class DocumentHandler { 65 66 /** 67 * All known OO file extensions 68 */ 69 public static final String EXTENSION = ".*ott$|.*sxw$|.*doc$|.*xls$|.*odt$|.*ods$|.*pps$|.*odt$|.*ppt$|.*odp$"; 70 /** 71 * A FileFilter looking for OO files 72 */ 73 public static FileFilter OFFICE_FILE_FILTER = new FileFilter() { 74 75 @Override 76 public boolean accept(File pathname) { 77 return pathname.getName().matches(EXTENSION); 78 } 79 }; 80 private final NoaConnection connection; 81 private final DocumentDescriptor descriptor; 82 private IDocument document; 83 private ITextFieldService textFieldService; 84 private ITextField[] placeholders; 85 private TableHandler tablehandler; 86 private File file; 87 88 /** 89 * Creates a new (hidden) Document Handler on top of the given connection 90 * @param connection The OO connection to use 91 */ 92 public DocumentHandler(NoaConnection connection) { 93 if (connection != null) { 94 this.connection = connection; 95 descriptor = DocumentDescriptor.DEFAULT_HIDDEN; 96 } else { 97 throw new NullPointerException("Connection cannot be null"); 98 } 99 } 100 101 /** 102 * Load an existing document into the Document Handler 103 * @param file The file to load 104 * @param asTemplate If true, the file is treatened as template (.ott) 105 * @throws Exception Any error thrown 106 */ 107 public void loadDocument(File file, boolean asTemplate) throws Exception { 108 if (!OFFICE_FILE_FILTER.accept(file)) { 109 throw new UnsupportedOperationException("The file extension must match: " + EXTENSION); 110 } 111 if (asTemplate) { 112 descriptor.setAsTemplate(asTemplate); 113 } 114 this.file = file; 115 descriptor.setHidden(true); 116 clear(); 117 } 118 119 /** 120 * Creates a new, empty text document (.odt) 121 * @throws Exception 122 */ 123 public void newTextDocument() throws Exception { 124 IDocument d = connection.getDocumentService().constructNewDocument(IDocument.WRITER, descriptor); 125 document = (ITextDocument) d; 126 } 127 128 /** 129 * Save the given document to the physical location of the given file. 130 * @param file 131 * @throws DocumentException 132 */ 133 public synchronized void saveAs(File file) throws DocumentException { 134 135 if (file.exists()) { 136 file.delete(); 137 } 138 139 document.reformat(); 140 document.update(); 141 142 if (file.getName().split("\\.").length < 2) { 143 throw new UnsupportedOperationException("The file must have an extension: " + file); 144 } 145 146 IFilter filter = null; 147 String extension = file.getName().substring(file.getName().lastIndexOf("."), file.getName().length()); 148 if (extension.equalsIgnoreCase(".pdf")) { 149 filter = PDFFilter.FILTER; 150 } else if (extension.equalsIgnoreCase(".doc")) { 151 filter = MSOffice97Filter.FILTER; 152 } else if (extension.equalsIgnoreCase(".txt")) { 153 filter = TextFilter.FILTER; 154 } else if (extension.equalsIgnoreCase(".odt")) { 155 filter = OpenDocumentFilter.FILTER; 156 } else if (extension.equalsIgnoreCase(".html")) { 157 filter = HTMLFilter.FILTER; 158 } 159 160 161 if (filter != null) { 162 try { 163 Log.Debug(this, "Exporting to: " + file); 164 document.getPersistenceService().export(new FileOutputStream(file), filter); 165 166 } catch (Exception ex) { 167 Log.Debug(ex); 168 } 169 } else { 170 throw new UnsupportedOperationException("File extension not supported: " + extension); 171 } 172 } 173 174 /** 175 * Close the underlying doc 176 */ 177 public void close() { 178 document.close(); 179 } 180 181 /** 182 * Fill the Form Fields of the template with values 183 * @param data 184 * @throws Exception 185 * @throws NOAException 186 * @deprecated slow :-/ 187 */ 188 public synchronized void fillFormFields(HashMap<String, Object> data) throws Exception, NOAException { 189 Log.Debug(this, "Looking for form fields in: " + document); 190 IFormComponent[] formComponents = document.getFormService().getFormComponents(); 191 Iterator<String> keys = data.keySet().iterator(); 192 String key = null; 193 while (keys.hasNext()) { 194 195 // get column name 196 key = keys.next(); 197// Log.Debug(this, "Found key: " + key + " [" + data.get(key) + "]"); 198 for (int i = 0; i < formComponents.length; i++) { 199 200 XFormComponent xFormComponent = formComponents[i].getXFormComponent(); 201 XTextComponent xTextComponent = formComponents[i].getXTextComponent(); 202 XPropertySet propertySet = UnoRuntime.queryInterface(XPropertySet.class, 203 xFormComponent); 204 205 if (propertySet != null && propertySet.getPropertySetInfo().hasPropertyByName("Name")) { 206 String n = propertySet.getPropertyValue("Name").toString(); 207// Log.Debug(this, "Found form field: " + n); 208 if (n.equalsIgnoreCase(key) || key.endsWith(n)) { 209 Log.Debug(this, "Form field matches key: " + key + " [" + data.get(key) + "]"); 210 xTextComponent.setText(String.valueOf(data.get(key))); 211 } 212 } 213 } 214// textDocument.getTextFieldService().refresh(); 215 } 216 } 217 218 /** 219 * Fill the Placeholder Fields of the template with values 220 * @param data 221 * @throws Exception 222 * @throws NOAException 223 */ 224 public synchronized void fillPlaceholderFields(HashMap<String, Object> data) throws Exception, NOAException { 225 Log.Debug(this, "Looking for placeholder fields in: " + document); 226 Iterator<String> keys = data.keySet().iterator(); 227 String key = null; 228 String[] placehrepr = new String[0]; 229 List<ITextField> fields = new ArrayList<ITextField>(); 230 if (textFieldService == null || placeholders == null) { 231 textFieldService = ((ITextDocument) document).getTextFieldService(); 232 placeholders = textFieldService.getPlaceholderFields(); 233 placehrepr = new String[placeholders.length]; 234 for (int i = 0; i < placeholders.length; i++) { 235 placehrepr[i] = placeholders[i].getDisplayText(); 236 fields.add(placeholders[i]); 237 } 238 Log.Debug(this, "Got: " + Arrays.asList(placehrepr)); 239 } 240 InputStream is = null; 241 ITextCursor cursor; 242 243 244 while (keys.hasNext()) { 245 key = keys.next(); 246 try { 247 for (int i = 0; i < placehrepr.length; i++) { 248 String placeholderDisplayText = placehrepr[i]; 249// Log.Debug(this, "Check placeholder key: " + placeholderDisplayText); 250 if (placeholderDisplayText.equalsIgnoreCase(key) || placeholderDisplayText.equalsIgnoreCase("<" + key + ">") 251 || placeholderDisplayText.equalsIgnoreCase("<RTF." + key + ">")) { 252 Log.Debug(this, "Found placeholder key: " + key + " [" + data.get(key) + "]"); 253 if (placeholderDisplayText.startsWith("<RTF.") || placeholderDisplayText.startsWith("<rtf.")) { 254 is = new StringInputStream(((String) data.get(key)).replace("`", 255 "'")); 256 cursor = placeholders[i].getTextDocument(). 257 getViewCursorService(). 258 getViewCursor(). 259 getTextCursorFromStart(); 260 cursor.gotoRange(placeholders[i].getTextRange(), 261 false); 262 cursor.insertDocument(is, 263 RTFFilter.FILTER); 264// placeholders[i].getTextRange(). 265// setText(""); 266 } else { 267 placeholders[i].getTextRange().setText(String.valueOf(data.get(key))); 268 } 269 } 270 } 271 } catch (java.lang.Exception ex) { 272 Log.Debug(ex); 273 } 274 } 275 if (!GlobalSettings.getBooleanProperty("org.openyabs.exportproperty.blankunusedfields.disable")) { 276 for (int i = 0; i < fields.size(); i++) { 277 try { 278 ITextField xTextComponent = fields.get(i); 279 if (xTextComponent.getXTextContent().getAnchor() != null) { 280 if (Log.isDebugging()) { 281 Log.Debug(this, "Filling unspecified field: " + xTextComponent.getDisplayText()); 282 } 283 xTextComponent.getTextRange().setText(""); 284 } 285 } catch (Throwable ex) { 286 Log.Debug(this, ex.getLocalizedMessage()); 287 } 288 } 289 } 290 } 291 292 /** 293 * Fill the Variable Text Fields of the template with values 294 * @param data 295 * @throws Exception 296 * @throws NOAException 297 * @deprecated slow :_/ 298 */ 299 public synchronized void fillTextVariableFields(HashMap<String, Object> data) throws Exception, NOAException { 300 Log.Debug(this, "Looking for variable fields in: " + document); 301 Iterator<String> keys = data.keySet().iterator(); 302 String key = null; 303 IVariableTextFieldMaster x; 304 305 while (keys.hasNext()) { 306 // get column name 307 key = keys.next(); 308 if (textFieldService == null) { 309 textFieldService = ((ITextDocument) document).getTextFieldService(); 310 } 311 x = textFieldService.getVariableTextFieldMaster(key); 312 313 if (x != null) { 314 ITextField[] variables = x.getVariableTextFields(); 315 for (int i = 0; i < variables.length; i++) { 316 XPropertySet xPropertySetField = (XPropertySet) UnoRuntime.queryInterface(XPropertySet.class, variables[i].getXTextContent()); 317 if (xPropertySetField.getPropertyValue("CurrentPresentation").toString().equalsIgnoreCase(key)) { 318 Log.Debug(this, "Found variable key: " + key + " [" + data.get(key) + "]"); 319 xPropertySetField.setPropertyValue("Content", data.get(key)); 320 } 321 } 322 } 323 } 324 } 325 326 /** 327 * Export a file to another format/file. Supported target formats: 328 * <li>pdf (pdf/a) 329 * <li>odt 330 * <li>txt 331 * @param source The file to export 332 * @param target The target file 333 * @return The target file 334 * @throws DocumentException 335 */ 336 public File export(File source, File target) throws DocumentException { 337 if (target.getName().split("\\.").length < 2) { 338 throw new UnsupportedOperationException("The file must have an extension: " + target); 339 } 340 341 IFilter filter = null; 342 String extension = target.getName().substring(target.getName().lastIndexOf("."), target.getName().length()); 343 if (extension.equalsIgnoreCase(".pdf")) { 344 if (User.getCurrentUser().getProperties().hasProperty("pdftype") 345 && User.getCurrentUser().getProperties().getProperty("pdftype").equalsIgnoreCase("pdf/a")) { 346 try { 347 return exportPDFA(source, target); 348 } catch (Exception ex) { 349 Log.Debug(ex); 350 } 351 } else { 352 filter = PDFFilter.FILTER; 353 } 354 } else if (extension.equalsIgnoreCase(".doc")) { 355 filter = MSOffice97Filter.FILTER; 356 } else if (extension.equalsIgnoreCase(".txt")) { 357 filter = TextFilter.FILTER; 358 } else if (extension.equalsIgnoreCase(".odt")) { 359 filter = OpenDocumentFilter.FILTER; 360 } else if (extension.equalsIgnoreCase(".html")) { 361 filter = HTMLFilter.FILTER; 362 } 363 364 if (filter != null) { 365 connection.getDocumentService().loadDocument(source.getAbsolutePath()).getPersistenceService().export(target.getPath(), filter); 366 } else { 367 throw new UnsupportedOperationException("File extension not supported: " + extension); 368 } 369 370 return target; 371 } 372 373 private File exportPDFA(File source, File target) throws DocumentException, MalformedURLException, FileNotFoundException, IOException, UnknownHostException { 374 375 IDocument doc = connection.getDocumentService().loadDocument(new FileInputStream(source), descriptor); 376 377 PDFFilter pdfFilter = (PDFFilter) PDFFilter.FILTER; 378 /*PDFFilterProperties pdfFilterProperties = pdfFilter.getPDFFilterProperties(); 379 pdfFilterProperties.setPdfVersion(1); 380 doc.getPersistenceService().export(url, pdfFilter);*/ 381 382 PropertyValue[] filterData = new PropertyValue[1]; 383 filterData[0] = new PropertyValue(); 384 filterData[0].Name = "SelectPdfVersion"; 385 filterData[0].Value = new Integer(1); //0: normal 1.4, 1: PDF/A 386 387 String filterDefinition = pdfFilter.getFilterDefinition(doc); 388 PropertyValue[] properties = new PropertyValue[2]; 389 properties[0] = new PropertyValue(); 390 properties[0].Name = "FilterName"; //$NON-NLS-1$ 391 properties[0].Value = filterDefinition; 392 properties[1] = new PropertyValue(); 393 properties[1].Name = "FilterData"; 394 properties[1].Value = filterData; 395 396 397 String url = URLAdapter.adaptURL(target.getPath()); 398 399 XStorable xStorable = (XStorable) UnoRuntime.queryInterface(XStorable.class, 400 doc.getXComponent()); 401 xStorable.storeToURL(url, properties); 402 403 return target; 404 } 405 406 /** 407 * Print the document directly 408 */ 409 public void print() { 410 try { 411 document.getPrintService().print(); 412 } catch (DocumentException ex) { 413 Log.Debug(ex); 414 } 415 } 416 417 /** 418 * Fill the tables in the document 419 * @param data 420 */ 421 public synchronized void fillTables(HashMap<String, Object> data) { 422 fillTables(data, null); 423 } 424 425 /** 426 * Fills the tables in an .odt file 427 * @param data 428 * @param template 429 */ 430 public void fillTables(HashMap<String, Object> data, Template template) { 431 HashMap<String, TableModel> models = template.getTables(); 432 433 Log.Debug(this, "Looking for tables in: " + document); 434 435 try { 436 for (Iterator<String> it = models.keySet().iterator(); it.hasNext();) { 437 String key = it.next(); 438 TableModel m = models.get(key); 439 Log.Debug(this, "Table: " + key); 440 if (tablehandler == null) { 441 if (key.contains(".")) { 442 key = key.substring(key.lastIndexOf(".") + 1); 443 } 444 Log.Debug(this, "Table identifier: " + key); 445 tablehandler = new TableHandler((ITextDocument) document, key); 446 } 447 for (int j = 0; j < m.getRowCount(); j++) { 448 String[] strings = new String[m.getColumnCount()]; 449 for (int k = 0; k < strings.length; k++) { 450 if (m.getValueAt(j, k) != null) { 451 strings[k] = String.valueOf(m.getValueAt(j, k)); 452 } 453 } 454 doRow(template, strings, j); 455 } 456 } 457 } catch (Exception e) { 458 Log.Debug(e); 459 } 460 461 try { 462 for (Iterator<String> it = data.keySet().iterator(); it.hasNext();) { 463 String key = it.next(); 464 if (key.contains(TableHandler.KEY_TABLE)) {//Table found 465 Log.Debug(this, "Table: " + key); 466 @SuppressWarnings("unchecked") 467 List<String[]> value = (List<String[]>) data.get(key); 468 if (tablehandler == null) { 469 if (key.contains(".")) { 470 key = key.substring(key.lastIndexOf(".") + 1); 471 } 472 Log.Debug(this, "Table identifier: " + key); 473 tablehandler = new TableHandler((ITextDocument) document, key); 474 } 475 for (int i = 0; i < value.size(); i++) { 476 String[] strings = value.get(i); 477 doRow(template, strings, i); 478 } 479 } 480 } 481 } catch (Exception textException) { 482 Log.Debug(this, textException); 483 } 484 485 486 } 487 public static final String linkstartidentifier = "[url]"; 488 public static final String linkendidentifier = "[/url]"; 489 490 /** 491 * Reset the doc 492 * @throws DocumentException 493 */ 494 public void clear() throws DocumentException { 495 try { 496 Log.Debug(this, "Trying to load: " + URLAdapter.adaptURL(file.getPath())); 497// document = connection.getDocumentService().loadDocument(file.getPath().replace("\\", "/"), descriptor); 498 document = connection.getDocumentService().loadDocument(new FileInputStream(file), descriptor); 499 } catch (Exception ex) { 500 Log.Debug(ex); 501 } 502 textFieldService = null; 503 placeholders = null; 504 tablehandler = null; 505 } 506 507 /** 508 * Set the images 509 * @param data 510 */ 511 public void setImages(HashMap<String, Object> data) { 512// XTextGraphicObjectsSupplier graphicObjSupplier = (XTextGraphicObjectsSupplier) UnoRuntime.queryInterface(XTextGraphicObjectsSupplier.class, 513// document.getXTextDocument()); 514// XNameAccess nameAccess = graphicObjSupplier.getGraphicObjects(); 515// String[] names = nameAccess.getElementNames(); 516// for (int i = 0; i < names.length; i++) { 517// try { 518// Any xImageAny = (Any) nameAccess.getByName(names[i]); 519// Object xImageObject = xImageAny.getObject(); 520// XTextContent xImage = (XTextContent) xImageObject; 521// XServiceInfo xInfo = (XServiceInfo) UnoRuntime.queryInterface(XServiceInfo.class, xImage); 522// if (xInfo.supportsService("com.sun.star.text.TextGraphicObject")) { 523// try { 524// XPropertySet xPropSet = (XPropertySet) UnoRuntime.queryInterface(XPropertySet.class, 525// xImage); 526// String name = xPropSet.getPropertyValue("LinkDisplayName").toString(); 527// String graphicURL = xPropSet.getPropertyValue("GraphicURL").toString(); 528// //only ones that are not embedded 529// if (graphicURL.indexOf("vnd.sun.") == -1) { 530// XMultiServiceFactory multiServiceFactory = (XMultiServiceFactory) UnoRuntime.queryInterface(XMultiServiceFactory.class, 531// textDocument.getXTextDocument()); 532// XNameContainer xBitmapContainer = (XNameContainer) UnoRuntime.queryInterface(XNameContainer.class, 533// multiServiceFactory.createInstance("com.sun.star.drawing.BitmapTable")); 534// if (!xBitmapContainer.hasByName(name)) { 535// xBitmapContainer.insertByName(name, graphicURL); 536// String newGraphicURL = xBitmapContainer.getByName(name).toString(); 537// xPropSet.setPropertyValue("GraphicURL", newGraphicURL); 538// } 539// } 540// } catch (UnknownPropertyException ex) { 541// Logger.getLogger(DocumentHandler.class.getName()).log(Level.SEVERE, null, ex); 542// } catch (WrappedTargetException ex) { 543// Logger.getLogger(DocumentHandler.class.getName()).log(Level.SEVERE, null, ex); 544// } 545// } 546// } catch (NoSuchElementException ex) { 547// Logger.getLogger(DocumentHandler.class.getName()).log(Level.SEVERE, null, ex); 548// } catch (WrappedTargetException ex) { 549// Logger.getLogger(DocumentHandler.class.getName()).log(Level.SEVERE, null, ex); 550// } 551// } 552 } 553 554 private String[] refactorRow(Template template, String[] possibleCols) { 555 String format = template.__getFormat(); 556 int[] intcols; 557 try { 558 String[] cols = format.split(","); 559 intcols = new int[cols.length]; 560 for (int i = 0; i < intcols.length; i++) { 561 String string = cols[i]; 562 intcols[i] = Integer.valueOf(string).intValue(); 563 } 564 } catch (Exception ex) { 565 Log.Debug(this, "An error occured, using default format now. " + ex.getMessage()); 566 intcols = new int[possibleCols.length]; 567 for (int i = 0; i < intcols.length; i++) { 568 intcols[i] = i + 1; 569 } 570 } 571 String[] form = new String[intcols.length]; 572 for (int i = 0; i < intcols.length; i++) { 573 try { 574 form[i] = possibleCols[intcols[i] - 1]; 575 } catch (Exception e) { 576 // Log.Debug(this, "Too much columns in the format definition: " + e); 577 } 578 } 579 580 return form; 581 } 582 583 private void doRow(Template template, String[] strings, int row) { 584 if (template != null) { 585 strings = refactorRow(template, strings); 586 } 587 if (Log.getLoglevel() == Log.LOGLEVEL_DEBUG) { 588 Log.Debug(this, Arrays.asList(strings).toString()); 589 } 590 for (int j = 0; j < strings.length; j++) { 591 String cellValue = strings[j]; 592 if (cellValue == null) { 593 cellValue = ""; 594 } 595 cellValue = cellValue.replaceAll("\\<.*?\\>", "");//remove html/xml tags 596 if (!cellValue.contains("://")) {//lets say its a valid url 597 try { 598 tablehandler.setValueAt(cellValue, j, row); 599 } catch (TextException ex) { 600 Log.Debug(ex); 601 } 602 } else { 603 try { 604 String linkname = "Link"; 605 if (cellValue.contains("@")) { 606 String link1 = cellValue.split("@")[1]; 607 linkname = cellValue.split("@")[0]; 608 cellValue = link1; 609 } 610 tablehandler.setHyperlinkAt(linkname, cellValue, j, row); 611 } catch (Exception ex) { 612 Log.Debug(ex); 613 } 614 } 615 } 616 } 617}