Initialized project

This commit is contained in:
Georgy Litvinov 2021-11-17 16:23:33 +01:00
parent 072e974320
commit 11341e4b14
No known key found for this signature in database
GPG key ID: E8185E06DE0279DD
53 changed files with 2868 additions and 46 deletions

19
.classpath Normal file
View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="bin/main" path="src/main/java">
<attributes>
<attribute name="gradle_scope" value="main"/>
<attribute name="gradle_used_by_scope" value="main,test"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="bin/test" path="src/test/java">
<attributes>
<attribute name="gradle_scope" value="test"/>
<attribute name="gradle_used_by_scope" value="test"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/"/>
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
<classpathentry kind="output" path="bin/default"/>
</classpath>

View file

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<manifest:manifest>
<manifest:file-entry manifest:full-path="docSettings/" manifest:media-type="application/vnd.sun.star.basic-library"/>
<manifest:file-entry manifest:full-path="Events.xcu" manifest:media-type="application/vnd.sun.star.configuration-data"/>
</manifest:manifest>

View file

@ -1,13 +1,64 @@
apply plugin: 'java'
apply plugin: 'eclipse'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
test {
useJUnitPlatform()
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1'
compileClasspath 'org.libreoffice:jurt:5.3.2'
compileClasspath 'org.libreoffice:juh:5.3.2'
compileClasspath 'org.libreoffice:ridl:5.3.2'
compileClasspath 'org.libreoffice:unoil:5.3.2'
compileClasspath group: 'org.slf4j', name: 'slf4j-api', version: '1.7.32'
compileClasspath 'ch.qos.logback:logback-classic:1.2.6'
compileClasspath 'ch.qos.logback:logback-core:1.2.6'
compileClasspath 'org.apache.tika:tika-core:2.1.0'
}
task oxtjar(type: Jar) {
archiveName 'docsettings_oxt.jar'
manifest {
attributes("Implementation-Title": rootProject.name,
"Implementation-Version": project.version,
"RegistrationClassName" : "pro.litvinovg.docsettings.RegistrationHandler",
"Class-Path" : "jasp.jar parser.jar")
}
from('src/main/java') {
include '**/*.classes'
include 'logback.xml'
include 'pro/litvinovg/docsettings/resources/*.png'
include 'pro/litvinovg/docsettings/localizations/*.properties'
}
from (sourceSets.main.output){
include 'pro/litvinovg/**/*.class'
include 'ch/**/*'
include 'org/slf4j/**/*'
}
from {
configurations.compileClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
}
task oxt(type: Zip) {
from './'
dependsOn = [ 'oxtjar' ]
from './oxt/'
include '*'
include '*/*'
include '*/*/*'
include '*/*/*/*'
exclude 'docSettings.oxt'
exclude '.*'
exclude 'build.gradle'
exclude 'translations.ods'
exclude 'update.xml'
from ('build/libs/docsettings_oxt.jar'){
include '*'
}
archiveName 'docSettings.oxt'
}

View file

@ -1,3 +0,0 @@
Extension for document settings configuration.
For now consists of workaround for layout bug since LO 6.4
https://bugs.documentfoundation.org/show_bug.cgi?id=134782

View file

@ -1,3 +0,0 @@
Расширение исправления настроек документов
В данный момент содержит исправления для бага, возникшего с версии 6.4
https://bugs.documentfoundation.org/show_bug.cgi?id=134782

View file

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Events" script:language="StarBasic" script:moduleType="normal">Sub execOnDocumentLoad
Dim fixCompatibilityOption As Boolean
fixCompatibilityOption = true
If fixCompatibilityOption Then
Dim oDocSettings As Object
oDocSettings = ThisComponent.createInstance( &quot;com.sun.star.document.Settings&quot; )
If oDocSettings.supportsService(&quot;com.sun.star.text.DocumentSettings&quot;) Then
oDocSettings.setPropertyValue(&quot;AddParaSpacingToTableCells&quot;, false)
EndIf
EndIf
End Sub
</script:module>

View file

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE library:library PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "library.dtd">
<library:library xmlns:library="http://openoffice.org/2000/library" library:name="docSettings" library:readonly="false" library:passwordprotected="false">
</library:library>

View file

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE library:library PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "library.dtd">
<library:library xmlns:library="http://openoffice.org/2000/library" library:name="docSettings" library:readonly="false" library:passwordprotected="false">
<library:element library:name="Events"/>
</library:library>

46
oxt/Addons.xcu Normal file
View file

@ -0,0 +1,46 @@
<?xml version='1.0' encoding='UTF-8'?>
<oor:component-data oor:package="org.openoffice.Office" oor:name="Addons"
xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<node oor:name="AddonUI">
<node oor:name="Images">
<node oor:name="pro.litvinovg.docsettings.openGUIImage" oor:op="replace">
<prop oor:name="URL" oor:type="xs:string">
<value>service:pro.litvinovg.libreoffice.DocSettings?openGUI</value>
</prop>
<node oor:name="UserDefinedImages">
<prop oor:name="ImageBigURL">
<value>vnd.sun.star.extension://pro.litvinovg.libreoffice.docsettings/icons/button_icon.png</value>
</prop>
</node>
</node>
</node>
<node oor:name="OfficeToolBar">
<node oor:name="pro.litvinovg.libreoffice.docsettings.toolbar" oor:op="replace">
<prop oor:name="Title" oor:type="xs:string">
<value>Document settings panel</value>
</prop>
<prop oor:name="Docked" oor:op="fuse"><value>true</value></prop>
<node oor:name="t01" oor:op="replace">
<prop oor:name="URL" oor:type="xs:string">
<value>service:pro.litvinovg.libreoffice.DocSettings?openGUI</value>
</prop>
<prop oor:name="Target" oor:type="xs:string">
<value>_self</value>
</prop>
<prop oor:name="Context" oor:type="xs:string">
<value>com.sun.star.text.TextDocument</value>
</prop>
<prop oor:name="Title" oor:type="xs:string">
<value xml:lang="en-US">Open document settings</value>
<value xml:lang="ru-RU">Открыть настройки документа</value>
</prop>
</node>
</node>
</node>
</node>
</oor:component-data>

View file

@ -4,9 +4,9 @@ xmlns:xs="http://www.w3.org/2001/XMLSchema" oor:name="Events"
oor:package="org.openoffice.Office">
<node oor:name="ApplicationEvents">
<node oor:name="Bindings">
<node oor:name="OnLoad" oor:op="replace">
<node oor:name="OnLoadFinished" oor:op="replace">
<prop oor:name="BindingURL" oor:type="xs:string">
<value>vnd.sun.star.script:docSettings.Events.execOnDocumentLoad?language=Basic&amp;location=application</value>
<value>service:pro.litvinovg.libreoffice.DocSettings?onLoad</value>
</prop>
</node>
</node>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<manifest:manifest xmlns:manifest="http://openoffice.org/2001/manifest">
<manifest:file-entry manifest:full-path="Events.xcu" manifest:media-type="application/vnd.sun.star.configuration-data"/>
<manifest:file-entry manifest:full-path="Addons.xcu" manifest:media-type="application/vnd.sun.star.configuration-data"/>
<manifest:file-entry manifest:full-path="docsettings_oxt.jar" manifest:media-type="application/vnd.sun.star.uno-component;type=Java"/>
<manifest:file-entry manifest:full-path="WriterWindowState.xcu" manifest:media-type="application/vnd.sun.star.configuration-data"/>
</manifest:manifest>

27
oxt/WriterWindowState.xcu Normal file
View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<oor:component-data oor:package="org.openoffice.Office.UI" oor:name="WriterWindowState"
xmlns:install="http://openoffice.org/2004/installation" xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<node oor:name="UIElements">
<node oor:name="States">
<!-- Used to dock the toolbar in the first toolbar row (by default it's floating) -->
<node oor:name="private:resource/toolbar/addon_pro.litvinovg.libreoffice.docsettings.toolbar" oor:op="replace">
<prop oor:name="UIName" oor:type="xs:string">
<value xml:lang="en">Document settings</value>
<value xml:lang="ru">Настройки документа</value>
</prop>
<prop oor:name="DockPos" oor:type="xs:string">
<value>10,0</value>
</prop>
<prop oor:name="Docked" oor:type="xs:boolean">
<value>true</value>
</prop>
<prop oor:name="DockingArea" oor:type="xs:int">
<value>0</value>
</prop>
</node>
</node>
</node>
</oor:component-data>

View file

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<description xmlns="http://openoffice.org/extensions/description/2006" xmlns:dep="http://openoffice.org/extensions/description/2006" xmlns:xlink="http://www.w3.org/1999/xlink">
<identifier value="pro.litvinovg.libreoffice.docsettings"/>
<version value="0.0.3"/>
<version value="0.0.6"/>
<platform value="all"/>
<display-name>
<name lang="ru">Исправление свойств документов</name>
<name lang="en">Docement settings fix</name>
<name lang="ru">Управление настройками документов</name>
<name lang="en">Docement settings management</name>
</display-name>
<registration>
<simple-license accept-by="admin" suppress-if-required="true" suppress-on-update="true">
@ -21,6 +21,7 @@
</update-information>
<publisher>
<name lang="en" xlink:href="mailto:public@litvinovg.pro">Georgy Litvinov</name>
<name lang="ru" xlink:href="mailto:public@litvinovg.pro">Георгий Литвинов</name>
</publisher>
<release-notes>
<src lang="en" xlink:href="releasenotes.txt"/>

View file

@ -0,0 +1,2 @@
Extension for document settings configuration.
Provides a way to create setttings backups and restore from it.

View file

@ -0,0 +1,2 @@
Расширение для управления настройками документов
Предоставляет возможность создания резервных копий настроек и восстановления из них.

View file

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

BIN
oxt/icons/button_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -1,6 +1,6 @@
The author of this extension is:
Georgy Litvinov (public@litvinovg.pro)
Copyright 2020.
Copyright 2021.
This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, version 3 of the License.

View file

@ -1,6 +1,6 @@
Автор расширения:
Георгий Литвинов (public@litvinovg.pro)
Copyright 2020.
Copyright 2021.
Это расширение является свободным программным обеспечением, вы можете распространять и/или модифицировать его в соответствии с лицензией GNU Lesser General Public License версии 3.0, опубликованной Free Software Foundation.

View file

@ -1,2 +1,4 @@
0.0.6 Added settings backup and restore options
0.0.5 Removed obsoleted workaround
0.0.3 Apply only to writer documents
0.0.1 First public release with workaround for https://bugs.documentfoundation.org/show_bug.cgi?id=134782

24
src/main/java/logback.xml Normal file
View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} %-5level - %msg%n</pattern>
</encoder>
</appender>
<!-- <appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>/home/litvinovg/logs/docsettings-log.txt</file>
<append>true</append>
<encoder>
<pattern>%d{HH:mm:ss.SSS} %-5level - %msg%n</pattern>
</encoder>
</appender> -->
<root level="info">
<appender-ref ref="STDOUT" />
</root>
<!-- <root level="error">
<appender-ref ref="FILE" />
</root> -->
<!-- <root level="debug">
<appender-ref ref="FILE" />
</root> -->
</configuration>

View file

@ -0,0 +1,185 @@
package pro.litvinovg.docsettings;
import java.io.File;
import com.sun.star.awt.MessageBoxType;
import com.sun.star.awt.Point;
import com.sun.star.awt.XButton;
import com.sun.star.awt.XComboBox;
import com.sun.star.awt.XControl;
import com.sun.star.awt.XControlContainer;
import com.sun.star.awt.XControlModel;
import com.sun.star.awt.XDialog;
import com.sun.star.awt.XDialogEventHandler;
import com.sun.star.awt.XDialogProvider2;
import com.sun.star.awt.XFixedText;
import com.sun.star.awt.XListBox;
import com.sun.star.awt.XMessageBox;
import com.sun.star.awt.XMessageBoxFactory;
import com.sun.star.awt.XTextComponent;
import com.sun.star.awt.XToolkit;
import com.sun.star.awt.XWindow;
import com.sun.star.awt.XWindowPeer;
import com.sun.star.beans.PropertyVetoException;
import com.sun.star.beans.UnknownPropertyException;
import com.sun.star.beans.XPropertySet;
import com.sun.star.lang.WrappedTargetException;
import com.sun.star.uno.Exception;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.uno.XComponentContext;
public class DialogHelper {
/**
* Create a dialog from an xdl file.
*
* @param xdlFile
* The filename in the `dialog` folder
* @param context
* @return XDialog
*/
public static XDialog createDialog(String xdlFile, XComponentContext context, XDialogEventHandler handler) {
Object oDialogProvider;
try {
oDialogProvider = context.getServiceManager().createInstanceWithContext("com.sun.star.awt.DialogProvider2",
context);
XDialogProvider2 xDialogProv = (XDialogProvider2) UnoRuntime.queryInterface(XDialogProvider2.class,
oDialogProvider);
File dialogFile = FileHelper.getDialogFilePath(xdlFile, context);
return xDialogProv.createDialogWithHandler(convertToURL(context, dialogFile), handler);
} catch (Exception e) {
return null;
}
}
/** Returns a URL to be used with XDialogProvider to create a dialog */
public static String convertToURL(XComponentContext xContext, File dialogFile) {
String sURL = null;
try {
com.sun.star.ucb.XFileIdentifierConverter xFileConverter = (com.sun.star.ucb.XFileIdentifierConverter) UnoRuntime
.queryInterface(com.sun.star.ucb.XFileIdentifierConverter.class, xContext.getServiceManager()
.createInstanceWithContext("com.sun.star.ucb.FileContentProvider", xContext));
sURL = xFileConverter.getFileURLFromSystemPath("", dialogFile.getAbsolutePath());
} catch (com.sun.star.uno.Exception ex) {
return null;
}
return sURL;
}
/** Returns a button (XButton) from a dialog */
public static XButton getButton(XDialog dialog, String componentId) {
XControlContainer xDlgContainer = (XControlContainer) UnoRuntime.queryInterface(XControlContainer.class,
dialog);
Object control = xDlgContainer.getControl(componentId);
return (XButton) UnoRuntime.queryInterface(XButton.class, control);
}
/** Returns a text field (XTextComponent) from a dialog */
public static XTextComponent getEditField(XDialog dialog, String componentId) {
XControlContainer xDlgContainer = (XControlContainer) UnoRuntime.queryInterface(XControlContainer.class,
dialog);
Object control = xDlgContainer.getControl(componentId);
return (XTextComponent) UnoRuntime.queryInterface(XTextComponent.class, control);
}
/** Returns a Combo box (XComboBox) from a dialog */
public static XComboBox getCombobox(XDialog dialog, String componentId) {
XControlContainer xDlgContainer = (XControlContainer) UnoRuntime.queryInterface(XControlContainer.class,
dialog);
Object control = xDlgContainer.getControl(componentId);
return (XComboBox) UnoRuntime.queryInterface(XComboBox.class, control);
}
/** Returns a List box (XListBox) from a dialog */
public static XListBox getListBox(XDialog dialog, String componentId) {
XControlContainer xDlgContainer = (XControlContainer) UnoRuntime.queryInterface(XControlContainer.class,
dialog);
Object control = xDlgContainer.getControl(componentId);
return (XListBox) UnoRuntime.queryInterface(XListBox.class, control);
}
/** Returns a label (XFixedText) from a dialog */
public static XFixedText getLabel(XDialog dialog, String componentId) {
XControlContainer xDlgContainer = (XControlContainer) UnoRuntime.queryInterface(XControlContainer.class,
dialog);
Object control = xDlgContainer.getControl(componentId);
return (XFixedText) UnoRuntime.queryInterface(XFixedText.class, control);
}
public static void EnableButton(XDialog dialog, String componentId, boolean enable) {
XControlContainer xDlgContainer = (XControlContainer) UnoRuntime.queryInterface(XControlContainer.class,
dialog);
// retrieve the control that we want to disable or enable
XControl xControl = UnoRuntime.queryInterface(XControl.class, xDlgContainer.getControl(componentId));
XPropertySet xModelPropertySet = UnoRuntime.queryInterface(XPropertySet.class, xControl.getModel());
try {
xModelPropertySet.setPropertyValue("Enabled", Boolean.valueOf(enable));
} catch (IllegalArgumentException | UnknownPropertyException | PropertyVetoException
| WrappedTargetException e) {
return;
}
}
/** Set the focus to an input field */
public static void SetFocus(XTextComponent editField) {
XWindow xControlWindow = UnoRuntime.queryInterface(XWindow.class, editField);
xControlWindow.setFocus();
}
public static void setPosition(XDialog dialog, int posX, int posY) {
XControlModel xDialogModel = UnoRuntime.queryInterface(XControl.class, dialog).getModel();
XPropertySet xPropSet = UnoRuntime.queryInterface(XPropertySet.class, xDialogModel);
try {
xPropSet.setPropertyValue("PositionX", posX);
xPropSet.setPropertyValue("PositionY", posY);
} catch (com.sun.star.lang.IllegalArgumentException | UnknownPropertyException | PropertyVetoException
| WrappedTargetException e) {
return;
}
}
public static Point getPosition(XDialog dialog) {
int posX = 0;
int posY = 0;
XControlModel xDialogModel = UnoRuntime.queryInterface(XControl.class, dialog).getModel();
XPropertySet xPropSet = UnoRuntime.queryInterface(XPropertySet.class, xDialogModel);
try {
posX = (int) xPropSet.getPropertyValue("PositionX");
posY = (int) xPropSet.getPropertyValue("PositionY");
} catch (UnknownPropertyException | WrappedTargetException e) {
}
return new Point(posX, posY);
}
public static void showInfoMessage(XComponentContext context, XDialog dialog, String message) {
showMessageBox(context, dialog, MessageBoxType.INFOBOX, "Info", message);
}
public static void showWarningMessage(XComponentContext context, XDialog dialog, String message) {
showMessageBox(context, dialog, MessageBoxType.WARNINGBOX, "Warning", message);
}
public static void showErrorMessage(XComponentContext context, XDialog dialog, String message) {
showMessageBox(context, dialog, MessageBoxType.ERRORBOX, "Error", message);
}
public static void showMessageBox(XComponentContext context, XDialog dialog, MessageBoxType type, String sTitle, String sMessage) {
XToolkit xToolkit;
try {
xToolkit = UnoRuntime.queryInterface(XToolkit.class,
context.getServiceManager().createInstanceWithContext("com.sun.star.awt.Toolkit", context));
} catch (Exception e) {
return;
}
XMessageBoxFactory xMessageBoxFactory = UnoRuntime.queryInterface(XMessageBoxFactory.class, xToolkit);
XWindowPeer xParentWindowPeer = UnoRuntime.queryInterface(XWindowPeer.class, dialog);
XMessageBox xMessageBox = xMessageBoxFactory.createMessageBox(xParentWindowPeer, type,
com.sun.star.awt.MessageBoxButtons.BUTTONS_OK, sTitle, sMessage);
if (xMessageBox == null)
return;
xMessageBox.execute();
}
}

View file

@ -0,0 +1,121 @@
package pro.litvinovg.docsettings;
import java.awt.EventQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sun.star.lang.XSingleComponentFactory;
//import pro.litvinovg.docsettings.gui.ConfigurationWindow;
//import pro.litvinovg.docsettings.gui.ConversionExecutor;
import com.sun.star.lib.uno.helper.Factory;
import com.sun.star.lib.uno.helper.WeakBase;
import com.sun.star.registry.XRegistryKey;
import com.sun.star.uno.XComponentContext;
import pro.litvinovg.docsettings.document.ODFDocument;
import pro.litvinovg.docsettings.gui.MainWindow;
import pro.litvinovg.docsettings.settings.Backups;
import pro.litvinovg.docsettings.settings.Settings;
public final class DocSettingsExtension extends WeakBase
implements com.sun.star.lang.XServiceInfo, com.sun.star.task.XJobExecutor {
private final XComponentContext context;
private static final String m_implementationName = DocSettingsExtension.class.getName();
private static final String[] m_serviceNames = { "pro.litvinovg.libreoffice.DocSettings" };
private static final Logger logger = LoggerFactory.getLogger(DocSettingsExtension.class);
public DocSettingsExtension(XComponentContext componentContext) {
context = componentContext;
};
public static XSingleComponentFactory __getComponentFactory(String sImplementationName) {
XSingleComponentFactory xFactory = null;
if (sImplementationName.equals(m_implementationName))
xFactory = Factory.createComponentFactory(DocSettingsExtension.class, m_serviceNames);
return xFactory;
}
public static boolean __writeRegistryServiceInfo(XRegistryKey xRegistryKey) {
return Factory.writeRegistryServiceInfo(m_implementationName, m_serviceNames, xRegistryKey);
}
// com.sun.star.lang.XServiceInfo:
public String getImplementationName() {
return m_implementationName;
}
public boolean supportsService(String sService) {
int len = m_serviceNames.length;
for (int i = 0; i < len; i++) {
if (sService.equals(m_serviceNames[i]))
return true;
}
return false;
}
public String[] getSupportedServiceNames() {
return m_serviceNames;
}
// com.sun.star.task.XJobExecutor:
public void trigger(String action) {
switch (action) {
case "openGUI":
try {
MainWindow.runGUI(context);
} catch (Throwable e) {
DialogHelper.showErrorMessage(context, null, e.getLocalizedMessage());
}
break;
case "onLoad":
try {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
onLoad();
} catch (Exception e) {
DialogHelper.showErrorMessage(context, null, e.getLocalizedMessage());
}
}
});
} catch (Throwable e) {
DialogHelper.showErrorMessage(context, null, e.getLocalizedMessage());
}
break;
default:
DialogHelper.showErrorMessage(context, null, "Unknown action: " + action);
}
}
private void onLoad() {
ODFDocument document = null;
try {
document = new ODFDocument(context);
} catch (Exception e) {
logger.debug("Ops", e);
return;
}
Backups backups = new Backups();
ExtensionConfig config = ExtensionConfig.getInstance();
document.readSettings();
document.readBackups(backups);
if (!document.hasBackups(backups)) {
backups.create(document.getCurrentSettings());
document.writeBackups(backups);
return;
}
if (config.getAutoRestore()) {
Settings settings = backups.getLatest();
boolean isSettingsChanged = document.compareWithBackup(settings);
if (isSettingsChanged) {
document.restoreSettings(settings);
}
}
}
}

View file

@ -0,0 +1,41 @@
package pro.litvinovg.docsettings;
import java.util.HashMap;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ExtensionConfig {
private static final Logger logger = LoggerFactory.getLogger(ExtensionConfig.class);
private static final String AUTO_RESTORE = "autoRestore";
private static ExtensionConfig extensionSettings = null;
private Preferences storage;
public static ExtensionConfig getInstance() {
if (extensionSettings != null) {
return extensionSettings;
}
extensionSettings = new ExtensionConfig();
return extensionSettings;
}
private ExtensionConfig() {
storage = Preferences.userRoot().node(this.getClass().getName());
}
public boolean getAutoRestore() {
return storage.getBoolean(AUTO_RESTORE, false);
}
public void setAutoRestore(boolean value) {
storage.putBoolean(AUTO_RESTORE, value);
try {
storage.sync();
} catch (BackingStoreException e) {
logger.debug("Ops", e);
}
}
}

View file

@ -0,0 +1,60 @@
package pro.litvinovg.docsettings;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import com.sun.star.deployment.PackageInformationProvider;
import com.sun.star.deployment.XPackageInformationProvider;
import com.sun.star.uno.Exception;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.uno.XComponentContext;
import com.sun.star.util.XURLTransformer;
public class FileHelper {
final static String DIALOG_RESOURCES = "dialog/";
/**
* Returns a path to a dialog file
*/
public static File getDialogFilePath(String xdlFile, XComponentContext xContext) {
return getFilePath(DIALOG_RESOURCES + xdlFile, xContext);
}
/**
* Returns a file path for a file in the installed extension, or null on failure.
*/
public static File getFilePath(String file, XComponentContext xContext) {
XPackageInformationProvider xPackageInformationProvider = PackageInformationProvider.get(xContext);
String location = xPackageInformationProvider.getPackageLocation("org.libreoffice.example.starterproject");
Object oTransformer;
try {
oTransformer = xContext.getServiceManager().createInstanceWithContext("com.sun.star.util.URLTransformer", xContext);
} catch (Exception e) {
e.printStackTrace();
return null;
}
XURLTransformer xTransformer = (XURLTransformer)UnoRuntime.queryInterface(XURLTransformer.class, oTransformer);
com.sun.star.util.URL[] oURL = new com.sun.star.util.URL[1];
oURL[0] = new com.sun.star.util.URL();
oURL[0].Complete = location + "/" + file;
xTransformer.parseStrict(oURL);
URL url;
try {
url = new URL(oURL[0].Complete);
} catch (MalformedURLException e1) {
return null;
}
File f;
try {
f = new File(url.toURI());
} catch (URISyntaxException e1) {
return null;
}
return f;
}
}

View file

@ -0,0 +1,62 @@
package pro.litvinovg.docsettings;
import java.io.UnsupportedEncodingException;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
public class Localizer {
private Locale currentLocale;
private String resourceBundle = "pro.litvinovg.docsettings.localizations.docsettings";
private ResourceBundle translations;
private boolean isOld = false;
private static Localizer localizer = null;
private Localizer() {
currentLocale = Locale.getDefault();
translations = ResourceBundle.getBundle(resourceBundle, currentLocale);
this.isOld = isOldJava();
}
public static Localizer getInstance() {
if (localizer != null) {
return localizer;
}
localizer = new Localizer();
return localizer;
}
public static String get(String name) {
Localizer.getInstance();
return localizer.getTranslation(name);
}
public String getTranslation(String name) {
if (translations != null && translations.containsKey(name)) {
String translation = translations.getString(name);
if (isOld) {
try {
return new String(translation.getBytes("ISO-8859-1"), "UTF-8");
} catch(UnsupportedEncodingException e) {
e.printStackTrace();
}
} else {
return translation;
}
}
return name;
}
private boolean isOldJava() {
try {
String versionString = System.getProperty("java.class.version");
Float version = Float.parseFloat(versionString);
if (version < 53) {
return true;
}
} catch (Exception e) {
System.out.println(e.getLocalizedMessage());
}
return false;
}
}

View file

@ -0,0 +1 @@
pro.litvinovg.docsettings.DocSettingsExtension

View file

@ -0,0 +1,175 @@
/*************************************************************************
*
* The Contents of this file are made available subject to the terms of
* either of the GNU Lesser General Public License Version 2.1
*
* Sun Microsystems Inc., October, 2000
*
*
* GNU Lesser General Public License Version 2.1
* =============================================
* Copyright 2000 by Sun Microsystems, Inc.
* 901 San Antonio Road, Palo Alto, CA 94303, USA
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* The Initial Developer of the Original Code is: Sun Microsystems, Inc..
*
* Copyright: 2002 by Sun Microsystems, Inc.
*
* All Rights Reserved.
*
* Contributor(s): Cedric Bosdonnat
*
*
************************************************************************/
package pro.litvinovg.docsettings;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.lang.reflect.Method;
import java.util.ArrayList;
import com.sun.star.lang.XSingleComponentFactory;
import com.sun.star.registry.XRegistryKey;
/**
* Component main registration class.
*
* <p><strong>This class should not be modified.</strong></p>
*
* @author Cedric Bosdonnat aka. cedricbosdo
*
*/
public class RegistrationHandler {
/**
* Get a component factory for the implementations handled by this class.
*
* <p>This method calls all the methods of the same name from the classes listed
* in the <code>RegistrationHandler.classes</code> file. <strong>This method
* should not be modified.</strong></p>
*
* @param pImplementationName the name of the implementation to create.
*
* @return the factory which can create the implementation.
*/
public static XSingleComponentFactory __getComponentFactory(String sImplementationName ) {
XSingleComponentFactory xFactory = null;
Class[] classes = findServicesImplementationClasses();
int i = 0;
while (i < classes.length && xFactory == null) {
Class clazz = classes[i];
if ( sImplementationName.equals( clazz.getCanonicalName() ) ) {
try {
Class[] getTypes = new Class[]{String.class};
Method getFactoryMethod = clazz.getMethod("__getComponentFactory", getTypes);
Object o = getFactoryMethod.invoke(null, sImplementationName);
xFactory = (XSingleComponentFactory)o;
} catch (Exception e) {
// Nothing to do: skip
System.err.println("Error happened");
e.printStackTrace();
}
}
i++;
}
return xFactory;
}
/**
* Writes the services implementation informations to the UNO registry.
*
* <p>This method calls all the methods of the same name from the classes listed
* in the <code>RegistrationHandler.classes</code> file. <strong>This method
* should not be modified.</strong></p>
*
* @param pRegistryKey the root registry key where to write the informations.
*
* @return <code>true</code> if the informations have been successfully written
* to the registry key, <code>false</code> otherwise.
*/
public static boolean __writeRegistryServiceInfo(XRegistryKey xRegistryKey ) {
Class[] classes = findServicesImplementationClasses();
boolean success = true;
int i = 0;
while (i < classes.length && success) {
Class clazz = classes[i];
try {
Class[] writeTypes = new Class[]{XRegistryKey.class};
Method getFactoryMethod = clazz.getMethod("__writeRegistryServiceInfo", writeTypes);
Object o = getFactoryMethod.invoke(null, xRegistryKey);
success = success && ((Boolean)o).booleanValue();
} catch (Exception e) {
success = false;
e.printStackTrace();
}
i++;
}
return success;
}
/**
* @return all the UNO implementation classes.
*/
private static Class[] findServicesImplementationClasses() {
ArrayList<Class> classes = new ArrayList<Class>();
InputStream in = RegistrationHandler.class.getResourceAsStream("RegistrationHandler.classes");
LineNumberReader reader = new LineNumberReader(new InputStreamReader(in));
try {
String line = reader.readLine();
while (line != null) {
if (!line.equals("")) {
line = line.trim();
try {
Class clazz = Class.forName(line);
Class[] writeTypes = new Class[]{XRegistryKey.class};
Class[] getTypes = new Class[]{String.class};
Method writeRegMethod = clazz.getMethod("__writeRegistryServiceInfo", writeTypes);
Method getFactoryMethod = clazz.getMethod("__getComponentFactory", getTypes);
if (writeRegMethod != null && getFactoryMethod != null) {
classes.add(clazz);
}
} catch (Exception e) {
e.printStackTrace();
}
}
line = reader.readLine();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
reader.close();
in.close();
} catch (Exception e) {};
}
return classes.toArray(new Class[classes.size()]);
}
}

View file

@ -0,0 +1,27 @@
package pro.litvinovg.docsettings;
import java.io.File;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pro.litvinovg.docsettings.document.ODFDocument;
import pro.litvinovg.docsettings.settings.Backups;
public class StandaloneApplication {
private static final Logger logger = LoggerFactory.getLogger(StandaloneApplication.class);
public static void main(String args[]) {
if (args.length == 0 ) {
logger.debug("Error. No arguments found. Exit.");
return;
}
final String filePath = args[0];
File file = new File(filePath);
if (!file.exists()) {
logger.debug("Error. File doesn't exist. Exit.");
return;
}
}
}

View file

@ -0,0 +1,357 @@
package pro.litvinovg.docsettings.document;
import static pro.litvinovg.docsettings.settings.StorageUtils.getDocFromString;
import static pro.litvinovg.docsettings.settings.StorageUtils.getSettingsElement;
import java.awt.EventQueue;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.apache.tika.Tika;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.sun.star.beans.PropertyValue;
import com.sun.star.beans.XPropertyContainer;
import com.sun.star.beans.XPropertySet;
import com.sun.star.beans.XPropertySetInfo;
import com.sun.star.chart.TimeUnit;
import com.sun.star.document.XDocumentProperties;
import com.sun.star.document.XDocumentPropertiesSupplier;
import com.sun.star.frame.XComponentLoader;
import com.sun.star.frame.XDesktop;
import com.sun.star.frame.XDispatchHelper;
import com.sun.star.frame.XDispatchProvider;
import com.sun.star.frame.XModel;
import com.sun.star.frame.XStorable;
import com.sun.star.lang.XComponent;
import com.sun.star.lang.XMultiComponentFactory;
import com.sun.star.lang.XServiceInfo;
import com.sun.star.text.XTextDocument;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.uno.XComponentContext;
import com.sun.star.util.XModifiable;
import pro.litvinovg.docsettings.DialogHelper;
import pro.litvinovg.docsettings.Localizer;
import pro.litvinovg.docsettings.gui.MainWindow;
import pro.litvinovg.docsettings.settings.Backups;
import pro.litvinovg.docsettings.settings.ODFSetting;
import pro.litvinovg.docsettings.settings.SettingFactory;
import pro.litvinovg.docsettings.settings.Settings;
import pro.litvinovg.docsettings.settings.SettingsComparator;
public class ODFDocument {
private static final Logger logger = LoggerFactory.getLogger(ODFDocument.class);
private XComponentContext context = null;
private XDesktop xDesktop = null;
private XMultiComponentFactory multiComponentFactory = null;
private XComponent currentDocument = null;
private String fileName = "";
public static final String SETTINGS = "settings.xml";
public static final String META = "meta.xml";
private Settings currentSettings = null;
private XStorable storable = null;
private XComponentLoader loader = null;
private String url = null;
public Settings getCurrentSettings() {
if (currentSettings.getSize() == 0) {
readSettings();
}
return currentSettings;
}
private String getSettingsContent() {
return readInternalFile(SETTINGS);
}
private void setSettingsContent(String settingsContent) {
writeInternalFile(SETTINGS, settingsContent);
}
private String getMetaContent() {
return readInternalFile(META);
}
/*
* private void setMetaContent(String newMetaContent) { writeInternalFile(META,
* newMetaContent); }
*/
public ODFDocument(XComponentContext componentContext) throws Exception {
this.currentSettings = new Settings();
if (componentContext != null) {
context = componentContext;
multiComponentFactory = context.getServiceManager();
Object oDesktop = multiComponentFactory.createInstanceWithContext("com.sun.star.frame.Desktop", context);
xDesktop = UnoRuntime.queryInterface(XDesktop.class, oDesktop);
currentDocument = xDesktop.getCurrentComponent();
if (currentDocument == null) {
logger.debug("xDesktop.getCurrentComponent() returned null");
throw new Exception(Localizer.get("error_document_is_null"));
}
XModel model = UnoRuntime.queryInterface(XModel.class, currentDocument);
if (!isSupported(currentDocument, "com.sun.star.text.TextDocument")) {
throw new Exception(Localizer.get("error_document_type_is_not_supported"));
}
loader = UnoRuntime.queryInterface(XComponentLoader.class, xDesktop);
XTextDocument textDoc = UnoRuntime.queryInterface(XTextDocument.class, currentDocument);
if (textDoc == null) {
throw new Exception("Error. TextDoc is null.");
}
storable = UnoRuntime.queryInterface(XStorable.class, textDoc);
if (storable == null || storable.isReadonly()) {
throw new Exception(Localizer.get("error_document_is_ro"));
}
if (!storable.hasLocation() || storable.getLocation().isEmpty()) {
throw new Exception(Localizer.get("error_document_is_not_saved"));
}
url = model.getURL();
URI uri = new URI(url);
File file = new File(uri);
if (!file.exists()) {
throw new Exception(Localizer.get("error_document_is_null"));
}
if (!file.canRead()) {
throw new Exception(Localizer.get("error_document_is_ro"));
}
if (!"application/vnd.oasis.opendocument.text".equals(getMimeType(file))) {
throw new Exception(Localizer.get("error_document_type_is_not_supported"));
}
fileName = file.getAbsolutePath();
}
}
private String getMimeType(File file) {
Tika tika = new Tika();
InputStream is;
String mime = "";
try {
is = new FileInputStream(file);
mime = tika.detect(is);
} catch (IOException e) {
logger.debug("Ops", e);
}
return mime;
}
public void restoreSettings(Settings settings) {
closeDocument();
restoreFrom(settings);
reOpenDoc();
}
public XPropertyContainer getUserDefinedProps(){
XDocumentPropertiesSupplier docPropertiesSupplier = UnoRuntime.queryInterface(XDocumentPropertiesSupplier.class, currentDocument);
XDocumentProperties docProperties = docPropertiesSupplier.getDocumentProperties();
XPropertyContainer userDefinedProperties = docProperties.getUserDefinedProperties();
return userDefinedProperties;
}
public void readSettings() {
flushSettings();
try {
Node configSettings = getSettingsElement(getDocFromString(getSettingsContent()));
NodeList settingNodes = configSettings.getChildNodes();
for (int i = 0; i < settingNodes.getLength(); i++) {
Node settingNode = settingNodes.item(i);
ODFSetting setting = SettingFactory.create(settingNode);
currentSettings.add(setting);
}
} catch (Exception e) {
logger.debug(e.getMessage());
logger.debug("Ops!",e);
}
}
private void flushSettings() {
currentSettings.clear();
}
public void restoreFrom(Settings settings) {
String newSettingsContent;
try {
newSettingsContent = settings.toSettingsContent(getSettingsContent());
writeInternalFile(SETTINGS, newSettingsContent);
} catch (Exception e) {
logger.debug("Restore failed", e);
}
}
public void readBackups(Backups backups) {
backups.readBackupsFromMetadata(getUserDefinedProps());
}
public boolean hasBackups(Backups backups) {
return !backups.isEmpty();
}
public void writeBackups(Backups backups) {
backups.writeBackupsToMetadata(getUserDefinedProps());
}
public String getFileName() {
return fileName;
}
public void printText(String text) {
DialogHelper.showErrorMessage(context, null, text);
}
public void printFileName() {
DialogHelper.showErrorMessage(context, null, fileName);
}
private String readInternalFile(String internalFile) {
Map<String, String> env = new HashMap<>();
String result = "";
FileSystem zipfs = null;
env.put("create", "true");
Path path = Paths.get(fileName);
URI uri = URI.create("jar:" + path.toUri());
try {
zipfs = FileSystems.newFileSystem(uri, env);
Path settingsPath = zipfs.getPath(internalFile);
byte[] encoded = Files.readAllBytes(settingsPath);
result = new String(encoded, "UTF-8");
} catch (IOException e) {
logger.debug(e.getMessage());
logger.debug("Ops!",e);
e.printStackTrace();
} finally {
try {
zipfs.close();
} catch (IOException e) {
logger.debug("Ops", e);
e.printStackTrace();
}
}
return result;
}
private void writeInternalFile(String internalFile, String contents) {
Map<String, String> env = new HashMap<>();
BufferedWriter writer = null;
FileSystem zipfs = null;
env.put("create", "true");
Path path = Paths.get(fileName);
URI uri = URI.create("jar:" + path.toUri());
try {
zipfs = FileSystems.newFileSystem(uri, env);
Path internalPath = zipfs.getPath(internalFile);
writer = Files.newBufferedWriter(internalPath, StandardCharsets.UTF_8, StandardOpenOption.WRITE);
writer.write(contents);
} catch (IOException e) {
logger.debug(e.getMessage());
logger.debug("Ops!",e);
} finally {
try {
writer.close();
zipfs.close();
} catch (IOException e) {
logger.debug(e.getLocalizedMessage());
logger.debug("Ops!",e);
}
}
}
public void reOpenDoc(){
try {
XComponent doc = loader.loadComponentFromURL(url, "_default", 0, new PropertyValue[0]);
} catch (Exception e) {
System.out.println("Failed to open the document");
}
;
}
public void closeDocument() {
if (context != null) {
executedispatch("CloseDoc", new PropertyValue[0]);
} else {
logger.debug("Can't close document. No context.");
}
}
public void reloadDocument() {
if (context != null) {
executedispatch("Reload", new PropertyValue[0]);
} else {
logger.debug("Can't reload document. No context.");
}
}
private boolean isSupported(Object object, String service) {
XServiceInfo info = UnoRuntime.queryInterface(XServiceInfo.class, object);
if (info == null) {
return false;
}
return info.supportsService(service);
}
private boolean executedispatch( String cmd, PropertyValue[] props) {
XDispatchHelper helper = createInstance(XDispatchHelper.class, "com.sun.star.frame.DispatchHelper");
if (helper == null) {
logger.debug("Could not create dispatch helper for command " + cmd);
return false;
}
try {
Object oDesktop = context.getServiceManager().createInstanceWithContext("com.sun.star.frame.Desktop", context);
XDesktop xDesktop = UnoRuntime.queryInterface(XDesktop.class, oDesktop);
XDispatchProvider provider = UnoRuntime.queryInterface(XDispatchProvider.class, xDesktop.getCurrentFrame());
helper.executeDispatch(provider, ".uno:" + cmd, "", 0, props);
return true;
} catch (java.lang.Exception e) {
logger.debug("Could not dispatch '" + cmd + "':\n " + e);
}
return false;
}
private <T> T createInstance(Class<T> aType, String serviceName) {
if ((context == null)) {
logger.debug("No libreoffice context. Cant create instance of " + aType.toString());
return null;
}
T interfaceObj = null;
try {
Object o = context.getServiceManager().createInstanceWithContext(serviceName, context);
interfaceObj = UnoRuntime.queryInterface(aType, o);
} catch (Exception e) {
logger.debug("Couldn't create interface for '" + serviceName + "': " + e);
}
return interfaceObj;
}
public boolean compareWithBackup(Settings backedUpSettings) {
return SettingsComparator.isEqual(getCurrentSettings(), backedUpSettings);
}
}

View file

@ -0,0 +1,10 @@
package pro.litvinovg.docsettings.exceptions;
public class MalformedXmlException extends Exception{
private static final long serialVersionUID = 1L;
public MalformedXmlException(String message) {
super(message);
}
}

View file

@ -0,0 +1,202 @@
package pro.litvinovg.docsettings.gui;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultListModel;
import javax.swing.DefaultListSelectionModel;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.LayoutStyle.ComponentPlacement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pro.litvinovg.docsettings.ExtensionConfig;
import pro.litvinovg.docsettings.Localizer;
import pro.litvinovg.docsettings.document.ODFDocument;
import pro.litvinovg.docsettings.settings.Backups;
import pro.litvinovg.docsettings.settings.Settings;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.SwingConstants;
public class BackupPanel extends JPanel {
private ExtensionConfig config;
private ODFDocument document;
private Backups backups;
private JButton btn_close;
private JButton btn_restore;
private JButton btn_create;
private JButton btn_delete;
private JList lst_backups;
private DefaultListModel backupListModel;
private static final Logger logger = LoggerFactory.getLogger(BackupPanel.class);
private JCheckBox cb_stick_latest_backup;
private JFrame frame;
public BackupPanel(JFrame frame, ODFDocument document, Backups backups) {
this.frame = frame;
this.backups = backups;
this.config = ExtensionConfig.getInstance();
this.document = document;
initComponents();
initEvents();
}
private void initEvents() {
onCreateButtonClick();
onDeleteButtonClick();
onRestoreButtonClick();
onCloseButtonClick();
onCheckBoxClick();
}
private void initComponents() {
backupListModel = new DefaultListModel();
populateList();
lst_backups = new JList(backupListModel);
lst_backups.setSelectionMode(DefaultListSelectionModel.SINGLE_SELECTION);
JLabel lb_backups = new JLabel(Localizer.get("backup_panel_description"));
btn_delete = new JButton(Localizer.get("delete_backup_button"));
btn_create = new JButton(Localizer.get("create_backup_button"));
btn_restore = new JButton(Localizer.get("restore_button"));
btn_close = new JButton(Localizer.get("close_window_button"));
cb_stick_latest_backup = new JCheckBox(Localizer.get("stick_latest_backup_cb_label"));
cb_stick_latest_backup.setSelected(config.getAutoRestore());
cb_stick_latest_backup.setVerticalAlignment(SwingConstants.TOP);
GroupLayout groupLayout = new GroupLayout(this);
groupLayout.setHorizontalGroup(
groupLayout.createParallelGroup(Alignment.LEADING)
.addGroup(groupLayout.createSequentialGroup()
.addGap(43)
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING, false)
.addComponent(lb_backups, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(groupLayout.createSequentialGroup()
.addComponent(lst_backups, GroupLayout.PREFERRED_SIZE, 354, GroupLayout.PREFERRED_SIZE)
.addGap(26)
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING, false)
.addComponent(cb_stick_latest_backup, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(btn_close, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(btn_delete, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 269, Short.MAX_VALUE)
.addComponent(btn_create, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(btn_restore, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
.addContainerGap(288, Short.MAX_VALUE))
);
groupLayout.setVerticalGroup(
groupLayout.createParallelGroup(Alignment.LEADING)
.addGroup(groupLayout.createSequentialGroup()
.addContainerGap()
.addComponent(lb_backups, GroupLayout.PREFERRED_SIZE, 15, GroupLayout.PREFERRED_SIZE)
.addGap(14)
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
.addComponent(lst_backups, GroupLayout.PREFERRED_SIZE, 384, GroupLayout.PREFERRED_SIZE)
.addGroup(groupLayout.createSequentialGroup()
.addComponent(btn_delete)
.addGap(18)
.addComponent(btn_create)
.addGap(18)
.addComponent(btn_restore)
.addGap(33)
.addComponent(cb_stick_latest_backup, GroupLayout.PREFERRED_SIZE, 83, GroupLayout.PREFERRED_SIZE)
.addGap(132)
.addComponent(btn_close)))
.addContainerGap(74, Short.MAX_VALUE))
);
setLayout(groupLayout);
}
private void populateList() {
backupListModel.clear();
int i = 0;
for(String date : backups.getBackupTimeLabels()) {
backupListModel.add(i,date);
i++;
}
}
private void onCreateButtonClick() {
btn_create.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
if (document == null) {
return;
}
backups.create(document.getCurrentSettings());
document.writeBackups(backups);
populateList();
}
});
}
private void onDeleteButtonClick() {
btn_delete.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
if (lst_backups.isSelectionEmpty()) {
return;
}
if (document == null) {
return;
}
String selected = (String) lst_backups.getSelectedValue();
backups.removeByDateTimeLabel(selected);
document.writeBackups(backups);
populateList();
}
});
}
private void onRestoreButtonClick() {
btn_restore.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
if (lst_backups.isSelectionEmpty()) {
JOptionPane.showMessageDialog(frame, Localizer.get("no_backup_selected"));
return;
}
if (document == null) {
JOptionPane.showMessageDialog(frame, Localizer.get("error_document_not_found"));
return;
}
String selected = (String) lst_backups.getSelectedValue();
Settings backup;
try {
backup = backups.getByDateTimeLabel(selected);
document.restoreSettings(backup);
MainWindow.getSingleFrame().setVisible(false);
MainWindow.getSingleFrame().dispose();
} catch (Exception e) {
logger.debug("Restore failed", e);
JOptionPane.showMessageDialog(frame, Localizer.get("restore_failed \n" + e.getLocalizedMessage()));
}
}
});
}
private void onCloseButtonClick() {
btn_close.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
MainWindow.getSingleFrame().setVisible(false);
MainWindow.getSingleFrame().dispose();
}
});
}
private void onCheckBoxClick() {
cb_stick_latest_backup.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
config.setAutoRestore(cb_stick_latest_backup.isSelected());
}
});
}
}

View file

@ -0,0 +1,42 @@
package pro.litvinovg.docsettings.gui;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
public class ChangedSettings extends JFrame {
private JPanel contentPane;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ChangedSettings frame = new ChangedSettings();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public ChangedSettings() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
}
}

View file

@ -0,0 +1,123 @@
package pro.litvinovg.docsettings.gui;
import java.awt.EventQueue;
import java.awt.Toolkit;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import java.awt.GridLayout;
import javax.swing.JTabbedPane;
import javax.swing.UIManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sun.star.uno.XComponentContext;
import pro.litvinovg.docsettings.DialogHelper;
import pro.litvinovg.docsettings.DocSettingsExtension;
import pro.litvinovg.docsettings.ExtensionConfig;
import pro.litvinovg.docsettings.Localizer;
import pro.litvinovg.docsettings.document.ODFDocument;
import pro.litvinovg.docsettings.settings.Backups;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import javax.swing.BoxLayout;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JList;
public class MainWindow extends JFrame {
private static final long serialVersionUID = 1L;
private static JFrame frame = null;
private Localizer localizer;
private ODFDocument document;
private Backups backups;
private static final Logger logger = LoggerFactory.getLogger(MainWindow.class);
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
MainWindow window = new MainWindow();
frame = window;
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public static void runGUI(XComponentContext context) {
if (frame != null) {
frame.dispose();
}
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Throwable e) {
String message = e.getLocalizedMessage();
JOptionPane.showMessageDialog(frame, message);
}
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
MainWindow window = new MainWindow(context);
frame = window;
} catch (Throwable e) {
DialogHelper.showErrorMessage(context, null, e.getLocalizedMessage());
logger.debug("Ops", e);
}
}
});
}
public static JFrame getSingleFrame() {
return frame;
}
public MainWindow() {
backups = new Backups();
initialize();
}
public MainWindow(XComponentContext context) throws Exception {
document = new ODFDocument(context);
backups = new Backups();
document.readSettings();
document.readBackups(backups);
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
setIconImage(Toolkit.getDefaultToolkit().getImage(MainWindow.class.getResource("/pro/litvinovg/docsettings/resources/icon.png")));
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
getContentPane().setLayout(new GridLayout(1, 0, 0, 0));
localizer = Localizer.getInstance();
this.setBounds(100, 100, 750, 500);
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
this.setVisible(true);
JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
getContentPane().add(tabbedPane);
JPanel backupPanel = new BackupPanel(this, document, backups);
tabbedPane.addTab(localizer.getTranslation("backups_tab_name"), null, backupPanel, null);
//JPanel settingsPanel = new SettingsPanel(this, document);
//tabbedPane.addTab(localizer.getTranslation("settings_tab_name"), null, settingsPanel, null);
}
}

View file

@ -0,0 +1,33 @@
package pro.litvinovg.docsettings.gui;
import javax.swing.JPanel;
import pro.litvinovg.docsettings.ExtensionConfig;
import pro.litvinovg.docsettings.Localizer;
import pro.litvinovg.docsettings.document.ODFDocument;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
public class SettingsPanel extends JPanel {
private ExtensionConfig config;
private Localizer localizer;
private ODFDocument document;
private JFrame frame;
public SettingsPanel(JFrame mainWindow, ODFDocument document) {
this.frame = mainWindow;
this.document = document;
this.config = ExtensionConfig.getInstance();
this.localizer = Localizer.getInstance();
setLayout(new GridLayout(1, 0, 0, 0));
initComponents();
}
private void initComponents() {
}
}

View file

@ -0,0 +1,15 @@
close_window_button = Close
restore_button = Restore from backup
create_backup_button = Create backup
delete_backup_button = Delete backup
settings_tab_name = Settings
backups_tab_name = Backups
backup_panel_description = Manage document settings backups
no_timestamp_found_error = No backup dates found
stick_latest_backup_cb_label = Block settings
no_backup_selected = Select backup and try again
error_document_not_found = Document not found.
error_document_is_not_saved = Document is not saved. Save document before proceeding.
error_document_is_ro = Document opened in read only mode.
error_document_is_null = Document not found
error_document_type_is_not_supported = Document type is not supported.

View file

@ -0,0 +1,15 @@
close_window_button = Закрыть
restore_button = Восстановить из резервной копии
create_backup_button = Создать резервную копию
delete_backup_button = Удалить резервную копию
settings_tab_name = Настройки
backups_tab_name = Резервные копии
backup_panel_description = Управление резервными копиями настроек документов
no_timestamp_found_error = Не найдено дат резервных копий
stick_latest_backup_cb_label = Заблокировать изменение настроек
no_backup_selected = Выберите резервную копию и попробуйте снова
error_document_not_found = Ошибка. Документ не найден.
error_document_is_not_saved = Документ не сохранен. Сохраните документ и попробуйте снова.
error_document_is_ro = Документ открыт в режиме только для чтения.
error_document_is_null = Ошибка. Документ не найден.
error_document_type_is_not_supported = Тип документа не поддерживается. Сохраните документ в формате ODT.

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -0,0 +1,445 @@
package pro.litvinovg.docsettings.settings;
import static pro.litvinovg.docsettings.settings.StorageUtils.*;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TimeZone;
import java.util.TreeMap;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import com.sun.star.beans.IllegalTypeException;
import com.sun.star.beans.Property;
import com.sun.star.beans.PropertyExistException;
import com.sun.star.beans.UnknownPropertyException;
import com.sun.star.beans.XPropertyContainer;
import com.sun.star.beans.XPropertySet;
import com.sun.star.beans.XPropertySetInfo;
import com.sun.star.lang.IllegalArgumentException;
import com.sun.star.lang.WrappedTargetException;
import com.sun.star.uno.UnoRuntime;
import pro.litvinovg.docsettings.exceptions.MalformedXmlException;
public class Backups {
private static final short REMOVABLE_PROPERTY = 128;
private static final int OO_XML_MAX_LENGTH = 65535;
private static final Logger logger = LoggerFactory.getLogger(Backups.class);
private static final String BACKUP_NAME_PREFIX = "SerializedSettings-";
private TreeMap<Long,Settings> backups = null;
public Backups() {
backups = new TreeMap<Long,Settings>();
}
public void add(Long unixTimeStamp, Settings backup) {
backups.put(unixTimeStamp, backup);
}
public void clear() {
backups.clear();
}
public boolean isEmpty() {
return backups.isEmpty();
}
public void create(Settings currentSettings) {
backups.put( getUnixTime(), currentSettings);
}
public Settings getBackupByTimeStamp(Long timeStamp) {
return backups.get(timeStamp);
}
public Settings getLatest() {
return backups.lastEntry().getValue();
}
public Set<Long> getTimeStamps() {
return backups.keySet();
}
public void readBackupsFromMetadata(XPropertyContainer userDefinedProps) {
clear();
TreeMap<Long, Map<Long, String>> backupMap = getBackupMap(userDefinedProps);
Map<Long,String> serializedBackups = combineBackupStrings(backupMap);
for (Entry<Long, String> entry : serializedBackups.entrySet()) {
Long unixTimeStamp = entry.getKey();
String backupString = entry.getValue();
if (!backupString.isEmpty()) {
backupString = decodeBase64(backupString);
readBackup(unixTimeStamp, backupString);
}
}
}
public void writeBackupsToMetadata(XPropertyContainer userDefinedProps) {
cleanBackupMetadata(userDefinedProps);
for (Entry<Long, Settings> backup : backups.entrySet()) {
try {
addBackupEntries( userDefinedProps, backup);
} catch (MalformedXmlException | ParserConfigurationException | TransformerException e) {
logger.debug("Ops", e);
}
}
}
private void cleanBackupMetadata(XPropertyContainer userDefinedProps) {
XPropertySet propertySet = UnoRuntime.queryInterface(XPropertySet.class, userDefinedProps);
XPropertySetInfo propSetInfo = propertySet.getPropertySetInfo();
Property[] props = propSetInfo.getProperties();
for (int i = 0; i < props.length; i++) {
try {
String name = props[i].Name;
if (name.startsWith(BACKUP_NAME_PREFIX)) {
userDefinedProps.removeProperty(name);
}
} catch (Exception e) {
logger.debug("Ops", e);
}
}
}
private void addBackupEntries(XPropertyContainer userDefinedProps, Entry<Long, Settings> backup) throws MalformedXmlException, ParserConfigurationException, TransformerException {
String backupString = serializeSettingsXML(backup.getValue());
backupString = encodeBase64(backupString);
List<String> parts = splitByOOMaxLength(backupString);
for (int i = 0; i < parts.size();i++) {
String part = parts.get(i);
String name = formatBackupMetaName(backup.getKey(),i);
try {
userDefinedProps.addProperty(name, REMOVABLE_PROPERTY, part);
} catch (IllegalArgumentException e) {
logger.debug("Ops", e);
} catch (PropertyExistException e) {
//it is ok
logger.debug("Ops", e);
} catch (IllegalTypeException e) {
logger.debug("Ops", e);
}
}
}
private void readBackup(Long unixTimeStamp, String backupString) {
Document backupDoc;
try {
backupDoc = getDocFromString(backupString);
Element configSettings = (Element) getSettingsElement(backupDoc);
NodeList settingNodes = configSettings.getChildNodes();
Settings backup = readSettingsFromNodeList(settingNodes);
add(unixTimeStamp,backup);
} catch (ParserConfigurationException | SAXException | IOException e) {
logger.debug("Ops", e);
} catch (Exception e) {
logger.debug("Ops", e);
}
}
private TreeMap<Long, Map<Long, String>> getBackupMap(XPropertyContainer userDefinedProps) {
TreeMap<Long, Map<Long, String>> backupMap = new TreeMap<Long,Map<Long,String>>();
XPropertySet propertySet = UnoRuntime.queryInterface(XPropertySet.class, userDefinedProps);
XPropertySetInfo propSetInfo = propertySet.getPropertySetInfo();
Property[] props = propSetInfo.getProperties();
for (int i = 0; i < props.length; i++) {
try {
Property prop = props[i];
String name = prop.Name;
if (name.startsWith(BACKUP_NAME_PREFIX)) {
Long timeStamp = Long.parseLong(getTimeStampFromString(name));
Long order = Long.parseLong(getOrderFromString(name));
String stringPart = propertySet.getPropertyValue(prop.Name).toString();
Map<Long, String> backupParts = null;
if (backupMap.containsKey(timeStamp)) {
backupParts = backupMap.get(timeStamp);
} else {
backupParts = new TreeMap<Long,String>();
backupMap.put(timeStamp, backupParts);
}
backupParts.put(order, stringPart);
}
//logger.debug("Prop name "+ prop.Name + " Prop value " + propertySet.getPropertyValue(prop.Name));
} catch (UnknownPropertyException | WrappedTargetException e) {
logger.debug("Ops", e);
}
}
return backupMap;
}
public void readBackupsFromXML(String metaContent) {
clear();
try {
Document doc = getDocFromString(metaContent);
Map<Long,String> serializedBackups = getSerializedBackups(doc);
for (Entry<Long, String> entry : serializedBackups.entrySet()) {
Long unixTimeStamp = entry.getKey();
String backupString = entry.getValue();
if (!backupString.isEmpty()) {
backupString = decodeBase64(backupString);
Document backupDoc = getDocFromString(backupString);
Element configSettings = (Element) getSettingsElement(backupDoc);
NodeList settingNodes = configSettings.getChildNodes();
Settings backup = readSettingsFromNodeList(settingNodes);
add(unixTimeStamp,backup);
}
}
} catch (Exception e) {
logger.debug(e.getMessage());
logger.debug("Ops!",e);
}
}
private Settings readSettingsFromNodeList(NodeList settingNodes) throws MalformedXmlException {
Settings settings = new Settings();
for (int i = 0; i < settingNodes.getLength(); i++) {
Node settingNode = settingNodes.item(i);
ODFSetting setting = SettingFactory.create(settingNode);
settings.add(setting);
}
return settings;
}
public String getNewMetaContent(String metaContent) {
String cleanedMeta = getCleanedMetaContent(metaContent);
String newMetaContent = "";
try {
Document doc = getDocFromString(cleanedMeta);
for (Entry<Long, Settings> backup : backups.entrySet()) {
addXMLBackupEntries( doc, backup.getKey(), backup.getValue());
}
newMetaContent = serializeDoc(doc);
} catch (Exception e) {
logger.debug(e.getMessage());
logger.debug("Ops!",e);
}
return newMetaContent;
}
private void addXMLBackupEntries(Document doc, Long timeStamp, Settings settings) throws MalformedXmlException, ParserConfigurationException, TransformerException {
String backupString = serializeSettingsXML(settings);
backupString = encodeBase64(backupString);
List<String> parts = splitByOOMaxLength(backupString);
for (int i = 0; i < parts.size();i++) {
String part = parts.get(i);
addMetadataEntry(doc,timeStamp,part, i);
}
}
private void addMetadataEntry(Document doc, Long timeStamp, String string, int i) throws MalformedXmlException {
Element element = doc.createElement("meta:user-defined");
String name = formatBackupMetaName(timeStamp,i);
element.setAttribute("meta:name", name);
element.setTextContent(string);
Node metaRoot = getMetaRootElement(doc);
metaRoot.appendChild(element);
}
private String formatBackupMetaName(Long timeStamp, int i) {
String result = BACKUP_NAME_PREFIX + timeStamp.toString() + "-" + i;
return result;
}
private List<String> splitByOOMaxLength(String text) {
List<String> array = new ArrayList<String>();
int index = 0;
while (index < text.length()) {
array.add(text.substring(index, Math.min(index + OO_XML_MAX_LENGTH, text.length())));
index += OO_XML_MAX_LENGTH;
}
return array;
}
private String serializeSettingsXML(Settings settings) throws ParserConfigurationException, TransformerException {
Document doc = createNewDoc();
Element root = doc.createElementNS("urn:oasis:names:tc:opendocument:xmlns:config:1.0","config:config-item-set");
root.setAttribute("xmlns:config", "urn:oasis:names:tc:opendocument:xmlns:config:1.0");
root.setAttribute("xmlns:ooo", "http://openoffice.org/2004/office");
root.setAttribute("config:name", "ooo:configuration-settings");
doc.appendChild(root);
appendSettingNodesToDoc(settings, doc, root);
String result = serializeDoc(doc);
return result;
}
private String getCleanedMetaContent(String metaContent) {
String cleanedMetaContent = "";
try {
Document doc = getDocFromString(metaContent);
NodeList nodes = getBackupEntries(doc);
removeNodes(nodes);
cleanedMetaContent = serializeDoc(doc);
} catch (Exception e) {
logger.debug(e.getMessage());
logger.debug("Ops!",e);
}
return cleanedMetaContent;
}
private Map<Long,String> getSerializedBackups(Document doc) throws MalformedXmlException {
NodeList nodes = getBackupEntries(doc);
TreeMap<Long, Map<Long, String>> backupStringMap = sortBackupStrings(nodes);
Map<Long,String> result = combineBackupStrings(backupStringMap);
return result;
}
private NodeList getBackupEntries(Document doc) throws MalformedXmlException {
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
XPathExpression expr;
NodeList nodes;
try {
expr = xpath.compile("//*[local-name() ='user-defined'][@*[local-name() ='name' and starts-with(.,'"+ BACKUP_NAME_PREFIX + "')]]");
nodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
} catch (XPathExpressionException e) {
logger.debug(e.getLocalizedMessage());
throw new MalformedXmlException("Xpath expression failed while looking for backup entries");
}
return nodes;
}
private Map<Long, String> combineBackupStrings(TreeMap<Long, Map<Long, String>> backupMap) {
TreeMap<Long, String> result = new TreeMap<Long, String>();
for(Map.Entry<Long, Map<Long,String>> entry: backupMap.entrySet()) {
Long timeStamp = entry.getKey();
Map<Long, String> parts = entry.getValue();
String combinedString = "";
for(Map.Entry<Long, String> part: parts.entrySet()) {
String serlializedString = part.getValue();
combinedString += serlializedString;
}
result.put(timeStamp, combinedString);
}
return result;
}
private TreeMap<Long, Map<Long, String>> sortBackupStrings(NodeList nodes) throws MalformedXmlException {
TreeMap<Long, Map<Long, String>> backupMap = new TreeMap<Long,Map<Long,String>>();
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
Long timeStamp = getTimeStampFromNode(node);
Long order = getOrderFromNode(node);
String stringPart = node.getTextContent();
Map<Long, String> backupParts = null;
if (backupMap.containsKey(timeStamp)) {
backupParts = backupMap.get(timeStamp);
} else {
backupParts = new TreeMap<Long,String>();
backupMap.put(timeStamp, backupParts);
}
backupParts.put(order, stringPart);
}
return backupMap;
}
private Long getTimeStampFromNode(Node node) throws MalformedXmlException {
String name = node.getAttributes().getNamedItem("meta:name").getNodeValue();
String ts = getTimeStampFromString(name);
Long timeStamp = null;
try {
timeStamp = Long.parseLong(ts);
} catch (NumberFormatException e) {
throw new MalformedXmlException("timestamp not found for metadata backup entry " + name);
}
return timeStamp;
}
private String getTimeStampFromString(String name) {
return name.replaceAll(BACKUP_NAME_PREFIX, "").replaceAll("-[0-9]$","");
}
private Long getOrderFromNode(Node node) throws MalformedXmlException {
String name = node.getAttributes().getNamedItem("meta:name").getNodeValue();
String or = getOrderFromString(name);
Long order;
try {
order = Long.parseLong(or);
} catch (NumberFormatException e) {
throw new MalformedXmlException("order not found for metadata backup entry " + name);
}
return order;
}
private String getOrderFromString(String name) {
return name.replaceAll(BACKUP_NAME_PREFIX + "[0-9]+-", "");
}
private long getUnixTime() {
return System.currentTimeMillis() / 1000L;
}
public String[] getBackupTimeLabels() {
String[] timeLabels = new String[backups.size()];
int i = 0;
for(Long backupTime: backups.keySet()) {
timeLabels[i] = getDateTimeLabelsFromUnix(backupTime);
i++;
}
return timeLabels;
}
private String getDateTimeLabelsFromUnix(Long timeStamp){
ZoneId zoneId = TimeZone.getDefault().toZoneId();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss");
final Instant instant = Instant.ofEpochSecond(timeStamp);
LocalDateTime time = LocalDateTime.ofInstant(instant, zoneId);
return formatter.format(time);
}
private Long getUnixFromDateTimeLabels(String formattedTime){
ZoneId zoneId = TimeZone.getDefault().toZoneId();
DateTimeFormatter parseFormat = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss");
LocalDateTime time = LocalDateTime.parse(formattedTime, parseFormat);
return time.atZone(zoneId).toEpochSecond();
}
public void removeByDateTimeLabel(String dateTimeLabel) {
if (dateTimeLabel == null || dateTimeLabel.isEmpty()) {
return;
}
Long unix = getUnixFromDateTimeLabels(dateTimeLabel);
backups.remove(unix);
}
public Settings getByDateTimeLabel(String dateTimeLabel) throws Exception {
if (dateTimeLabel == null || dateTimeLabel.isEmpty()) {
throw new Exception("date time not found");
}
Long unix = getUnixFromDateTimeLabels(dateTimeLabel);
Settings result = backups.get(unix);
if (result == null) {
throw new Exception("backup not found");
}
return result;
}
}

View file

@ -0,0 +1,66 @@
package pro.litvinovg.docsettings.settings;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ComparatorResults {
private static final Logger logger = LoggerFactory.getLogger(ComparatorResults.class);
private List<ODFSetting> removedSettings = new ArrayList<ODFSetting>();
private List<ODFSetting> newSetting = new ArrayList<ODFSetting>();
private Map<ODFSetting,ODFSetting> changedSettings = new HashMap<ODFSetting,ODFSetting>();
public boolean hasChanges() {
return removedSettings.isEmpty() && newSetting.isEmpty() && changedSettings.isEmpty();
}
public void addRemovedProperty(ODFSetting setting){
removedSettings.add(setting);
}
public void addNewProperty(ODFSetting setting){
newSetting.add(setting);
}
public void addChangedProperty(ODFSetting oldSetting,ODFSetting newSetting){
changedSettings.put(oldSetting, newSetting);
}
public List<ODFSetting> getRemovedProperties() {
return removedSettings;
}
public List<ODFSetting> getAddedProperties() {
return newSetting;
}
public Map<ODFSetting, ODFSetting> getChangedProperties() {
return changedSettings;
}
public void log() {
logger.info("New settings:");
for (Iterator iterator = newSetting.iterator(); iterator.hasNext();) {
ODFSetting odfSetting = (ODFSetting) iterator.next();
logger.debug(odfSetting.getName());
}
logger.info("Removed settings:");
for (Iterator iterator = removedSettings.iterator(); iterator.hasNext();) {
ODFSetting odfSetting = (ODFSetting) iterator.next();
logger.info(odfSetting.getName());
}
logger.info("Changed settings:");
for (Entry<ODFSetting, ODFSetting> entry : changedSettings.entrySet()) {
logger.info(entry.getKey().getName() + "\nChanged from "+ entry.getKey().getValue() + " to " + entry.getValue().getValue() );
}
}
}

View file

@ -0,0 +1,11 @@
package pro.litvinovg.docsettings.settings;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
public interface ODFSetting {
public String getName();
public String getValue();
public String getType();
public void addToDocumentElement(Document doc, Node root);
}

View file

@ -0,0 +1,24 @@
package pro.litvinovg.docsettings.settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sun.star.uno.XComponentContext;
import pro.litvinovg.docsettings.DialogHelper;
public class ODFSettings {
private XComponentContext context;
private static final Logger logger = LoggerFactory.getLogger(ODFSettings.class);
public ODFSettings(XComponentContext context ) {
this.context = context;
}
public void printText(String text) {
DialogHelper.showErrorMessage(context, null, text);
}
}

View file

@ -0,0 +1,64 @@
package pro.litvinovg.docsettings.settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;
import pro.litvinovg.docsettings.exceptions.MalformedXmlException;
import static pro.litvinovg.docsettings.settings.StorageUtils.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import pro.litvinovg.docsettings.exceptions.MalformedXmlException;
public class SettingFactory {
private static final String TYPE_INT = "int";
private static final String TYPE_BASE64_BINARY = "base64Binary";
private static final String TYPE_STRING = "string";
private static final String TYPE_SHORT = "short";
private static final String TYPE_BOOLEAN = "boolean";
private static final Logger logger = LoggerFactory.getLogger(SettingFactory.class);
public static ODFSetting create(Node node) throws MalformedXmlException {
Node typeNode = node.getAttributes().getNamedItem("config:type");
if (typeNode == null) {
logger.debug("nodeType is null");
throw new MalformedXmlException("Node " + node.getNodeName() + " config:type attribute not found.");
}
String type = typeNode.getNodeValue();
if (type == null || type.isEmpty()) {
logger.debug("node type value is null or empty");
throw new MalformedXmlException("Node " + node.getNodeName() + " config:type attribute not found.");
}
if (TYPE_BOOLEAN.equals(type)||
TYPE_SHORT.equals(type)||
TYPE_STRING.equals(type)||
TYPE_BASE64_BINARY.equals(type)||
TYPE_INT.equals(type)) {
return new SimpleSetting(node);
}
logger.debug("node type not recognized");
throw new MalformedXmlException("Node " + node.getNodeName());
}
}

View file

@ -0,0 +1,78 @@
package pro.litvinovg.docsettings.settings;
import static pro.litvinovg.docsettings.settings.StorageUtils.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class Settings {
private static final Logger logger = LoggerFactory.getLogger(Settings.class);
private List<ODFSetting> settings = null;
public Settings() {
this.settings = new ArrayList<ODFSetting>();
}
public void add(ODFSetting setting) {
settings.add(setting);
}
public void remove(int index) {
settings.remove(index);
}
public void remove(ODFSetting setting) {
settings.remove(setting);
}
public int getSize() {
return settings.size();
}
public ODFSetting get(int num) {
return settings.get(num);
}
public ODFSetting getByName(String name) {
for (Iterator iterator = settings.iterator(); iterator.hasNext();) {
ODFSetting odfSetting = (ODFSetting) iterator.next();
if (name.equals(odfSetting.getName())) {
return odfSetting;
}
}
return null;
}
public void clear() {
settings.clear();
}
public boolean isEmpty() {
return settings.isEmpty();
}
public String toSettingsContent(String content) throws Exception {
Document doc = getDocFromString(content);
Node settingsContainer = getSettingsElement(doc);
NodeList settingNodes = settingsContainer.getChildNodes();
removeNodes(settingNodes);
appendSettingNodesToDoc(this, doc, settingsContainer);
String newSettingsContent = serializeDoc(doc);
return newSettingsContent;
}
public void addAll(Settings inputSettings) {
for (int i = 0; i < inputSettings.getSize(); i++) {
this.add(inputSettings.get(i));
}
}
}

View file

@ -0,0 +1,48 @@
package pro.litvinovg.docsettings.settings;
public class SettingsComparator {
private static final String RSID = "Rsid";
public static boolean isEqual(Settings currentSettings, Settings backedUpSettings) {
Settings newSettings = new Settings();
newSettings.addAll(currentSettings);
Settings oldSettings = new Settings();
oldSettings.addAll(backedUpSettings);
ComparatorResults results = compare(newSettings, oldSettings);
if (results.hasChanges()) {
results.log();
}
return !results.hasChanges();
}
private static ComparatorResults compare(Settings newSettings, Settings oldSettings) {
ComparatorResults results = new ComparatorResults();
while (!newSettings.isEmpty()) {
ODFSetting newSet = newSettings.get(0);
ODFSetting oldSet = oldSettings.getByName(newSet.getName());
if (oldSet == null) {
results.addNewProperty(newSet);
} else {
if (!(newSet.getValue()).equals(oldSet.getValue()) && !isExcluded(newSet.getName())) {
results.addChangedProperty(oldSet, newSet);
}
oldSettings.remove(oldSet);
}
newSettings.remove(newSet);
}
while (!oldSettings.isEmpty()) {
ODFSetting oldSet = oldSettings.get(0);
results.addRemovedProperty(oldSet);
}
return results;
}
private static boolean isExcluded(String name) {
if (name.equals(RSID)) {
return true;
}
return false;
}
}

View file

@ -0,0 +1,53 @@
package pro.litvinovg.docsettings.settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import pro.litvinovg.docsettings.exceptions.MalformedXmlException;
public class SimpleSetting implements ODFSetting {
private static final Logger logger = LoggerFactory.getLogger(SimpleSetting.class);
protected String name;
protected String value;
protected String type;
public SimpleSetting(Node node) throws MalformedXmlException {
this.name = getNodeName(node);
this.value = node.getTextContent();
this.type = node.getAttributes().getNamedItem("config:type").getNodeValue();
}
protected String getNodeName(Node node) throws MalformedXmlException {
Node nameAttr = node.getAttributes().getNamedItem("config:name");
if (nameAttr == null) {
logger.debug("name attribute not found while creating simple property");
throw new MalformedXmlException("Node " + node.getNodeName() + " config:name attribute not found.");
}
return nameAttr.getNodeValue();
}
@Override
public String getName() {
return name;
}
@Override
public String getValue() {
return value;
}
@Override
public String getType() {
return type;
}
@Override
public void addToDocumentElement(Document doc, Node rootElement) {
Element element = doc.createElement("config:config-item");
element.setAttribute("config:name", getName());
element.setAttribute("config:type", getType());
element.setTextContent(getValue());
rootElement.appendChild(element);
}
}

View file

@ -0,0 +1,126 @@
package pro.litvinovg.docsettings.settings;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Base64;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import pro.litvinovg.docsettings.exceptions.MalformedXmlException;
public class StorageUtils {
private static final Logger logger = LoggerFactory.getLogger(StorageUtils.class);
public static Document getDocFromString(String xmlString) throws ParserConfigurationException, SAXException, IOException {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new InputSource(new StringReader(xmlString)));
return doc;
}
public static Document createNewDoc() throws ParserConfigurationException {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.newDocument();
return doc;
}
public static String serializeDoc(Document doc) throws TransformerException {
StringWriter output = new StringWriter();
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.transform(new DOMSource(doc), new StreamResult(output));
String str = output.toString();
return str;
}
public static String printNode(Node node) throws TransformerException {
StringWriter output = new StringWriter();
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.transform(new DOMSource(node), new StreamResult(output));
String str = output.toString();
return str;
}
public static String encodeBase64(String string) {
return new String(Base64.getEncoder().encode(string.getBytes()));
}
public static String decodeBase64(String serializedMetaSettings) {
return new String(Base64.getDecoder().decode(serializedMetaSettings));
}
public static void removeNodes(NodeList nodes) {
for (int i = nodes.getLength()-1; i >= 0; i--) {
Node node = nodes.item(i);
node.getParentNode().removeChild(node);
}
}
public static void appendSettingNodesToDoc(Settings settings, Document doc, Node root) {
for(int i = 0; i< settings.getSize();i++) {
ODFSetting setting = settings.get(i);
setting.addToDocumentElement(doc,root);
}
}
public static Node getSettingsElement(Document doc) throws Exception {
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
XPathExpression expr = xpath.compile("//*[local-name() ='config-item-set'][@*[local-name() ='name' and .='ooo:configuration-settings']]");
NodeList configItems = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
Node configSettings = configItems.item(0);
if (configSettings == null) {
throw new MalformedXmlException("No configuration settings element found");
}
return configSettings;
}
public static Node getMetaRootElement(Document doc) throws MalformedXmlException {
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
XPathExpression expr;
NodeList nodes;
try {
expr = xpath.compile("//*[local-name() ='meta']");
nodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
if (nodes.getLength() == 0 ) {
throw new MalformedXmlException("Xpath expression failed while looking for main meta element");
}
} catch (XPathExpressionException e) {
logger.debug(e.getLocalizedMessage());
logger.debug("Ops!",e);
throw new MalformedXmlException("Xpath expression failed while looking for main meta element");
}
Node result = nodes.item(0);
return result;
}
}

View file

@ -0,0 +1,14 @@
package pro.litvinovg.docsettings.exceptions;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
class MalformedXmlExceptionTest {
@Test
void test() {
fail("Not yet implemented");
}
}

View file

@ -0,0 +1,14 @@
package pro.litvinovg.docsettings.processor;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
class ODFSettingsTest {
@Test
void test() {
fail("Not yet implemented");
}
}

131
testFiles/settings-old.xml Normal file
View file

@ -0,0 +1,131 @@
<?xml version="1.0" encoding="UTF-8"?>
<office:document-settings xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:ooo="http://openoffice.org/2004/office" office:version="1.3">
<office:settings>
<config:config-item-set config:name="ooo:view-settings">
<config:config-item config:name="ViewAreaTop" config:type="long">0</config:config-item>
<config:config-item config:name="ViewAreaLeft" config:type="long">0</config:config-item>
<config:config-item config:name="ViewAreaWidth" config:type="long">21625</config:config-item>
<config:config-item config:name="ViewAreaHeight" config:type="long">9213</config:config-item>
<config:config-item config:name="ShowRedlineChanges" config:type="boolean">true</config:config-item>
<config:config-item config:name="InBrowseMode" config:type="boolean">false</config:config-item>
<config:config-item-map-indexed config:name="Views">
<config:config-item-map-entry>
<config:config-item config:name="ViewId" config:type="string">view2</config:config-item>
<config:config-item config:name="ViewLeft" config:type="long">3401</config:config-item>
<config:config-item config:name="ViewTop" config:type="long">2501</config:config-item>
<config:config-item config:name="VisibleLeft" config:type="long">0</config:config-item>
<config:config-item config:name="VisibleTop" config:type="long">0</config:config-item>
<config:config-item config:name="VisibleRight" config:type="long">21624</config:config-item>
<config:config-item config:name="VisibleBottom" config:type="long">9211</config:config-item>
<config:config-item config:name="ZoomType" config:type="short">0</config:config-item>
<config:config-item config:name="ViewLayoutColumns" config:type="short">1</config:config-item>
<config:config-item config:name="ViewLayoutBookMode" config:type="boolean">false</config:config-item>
<config:config-item config:name="ZoomFactor" config:type="short">214</config:config-item>
<config:config-item config:name="IsSelectedFrame" config:type="boolean">false</config:config-item>
<config:config-item config:name="AnchoredTextOverflowLegacy" config:type="boolean">true</config:config-item>
</config:config-item-map-entry>
</config:config-item-map-indexed>
</config:config-item-set>
<config:config-item-set config:name="ooo:configuration-settings">
<config:config-item config:name="PrintPaperFromSetup" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintFaxName" config:type="string"/>
<config:config-item config:name="PrintSingleJobs" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintProspectRTL" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintProspect" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintTextPlaceholder" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintTables" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintPageBackground" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintLeftPages" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintAnnotationMode" config:type="short">0</config:config-item>
<config:config-item config:name="PrintControls" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintHiddenText" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintDrawings" config:type="boolean">true</config:config-item>
<config:config-item config:name="FrameAutowidthWithMorePara" config:type="boolean">false</config:config-item>
<config:config-item config:name="HeaderSpacingBelowLastPara" config:type="boolean">false</config:config-item>
<config:config-item config:name="ProtectFields" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintReversed" config:type="boolean">false</config:config-item>
<config:config-item config:name="ProtectBookmarks" config:type="boolean">false</config:config-item>
<config:config-item config:name="UseOldPrinterMetrics" config:type="boolean">false</config:config-item>
<config:config-item config:name="UseOldNumbering" config:type="boolean">false</config:config-item>
<config:config-item config:name="AddExternalLeading" config:type="boolean">false</config:config-item>
<config:config-item config:name="TreatSingleColumnBreakAsPageBreak" config:type="boolean">false</config:config-item>
<config:config-item config:name="IsLabelDocument" config:type="boolean">false</config:config-item>
<config:config-item config:name="RsidRoot" config:type="int">517402</config:config-item>
<config:config-item config:name="ConsiderTextWrapOnObjPos" config:type="boolean">true</config:config-item>
<config:config-item config:name="TableRowKeep" config:type="boolean">false</config:config-item>
<config:config-item config:name="TabsRelativeToIndent" config:type="boolean">true</config:config-item>
<config:config-item config:name="AddParaLineSpacingToTableCells" config:type="boolean">true</config:config-item>
<config:config-item config:name="AllowPrintJobCancel" config:type="boolean">true</config:config-item>
<config:config-item config:name="UpdateFromTemplate" config:type="boolean">true</config:config-item>
<config:config-item config:name="SaveVersionOnClose" config:type="boolean">false</config:config-item>
<config:config-item config:name="UseFormerTextWrapping" config:type="boolean">false</config:config-item>
<config:config-item config:name="ChartAutoUpdate" config:type="boolean">true</config:config-item>
<config:config-item config:name="ContinuousEndnotes" config:type="boolean">false</config:config-item>
<config:config-item config:name="AddParaTableSpacingAtStart" config:type="boolean">false</config:config-item>
<config:config-item config:name="AddParaTableSpacing" config:type="boolean">false</config:config-item>
<config:config-item config:name="AddParaSpacingToTableCells" config:type="boolean">true</config:config-item>
<config:config-item config:name="UseFormerLineSpacing" config:type="boolean">false</config:config-item>
<config:config-item config:name="OutlineLevelYieldsNumbering" config:type="boolean">false</config:config-item>
<config:config-item config:name="AlignTabStopPosition" config:type="boolean">false</config:config-item>
<config:config-item config:name="DoNotJustifyLinesWithManualBreak" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmbedOnlyUsedFonts" config:type="boolean">false</config:config-item>
<config:config-item config:name="LinkUpdateMode" config:type="short">1</config:config-item>
<config:config-item config:name="CurrentDatabaseCommandType" config:type="int">0</config:config-item>
<config:config-item config:name="CurrentDatabaseCommand" config:type="string"/>
<config:config-item config:name="CharacterCompressionType" config:type="short">0</config:config-item>
<config:config-item config:name="SmallCapsPercentage66" config:type="boolean">false</config:config-item>
<config:config-item config:name="ApplyUserData" config:type="boolean">true</config:config-item>
<config:config-item config:name="StylesNoDefault" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmbeddedDatabaseName" config:type="string"/>
<config:config-item config:name="FloattableNomargins" config:type="boolean">false</config:config-item>
<config:config-item config:name="BackgroundParaOverDrawings" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrinterName" config:type="string"/>
<config:config-item config:name="UseFormerObjectPositioning" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrinterSetup" config:type="base64Binary"/>
<config:config-item config:name="IgnoreFirstLineIndentInNumbering" config:type="boolean">false</config:config-item>
<config:config-item config:name="CollapseEmptyCellPara" config:type="boolean">true</config:config-item>
<config:config-item config:name="TabOverMargin" config:type="boolean">false</config:config-item>
<config:config-item config:name="SaveGlobalDocumentLinks" config:type="boolean">false</config:config-item>
<config:config-item config:name="CurrentDatabaseDataSource" config:type="string"/>
<config:config-item config:name="IsKernAsianPunctuation" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintEmptyPages" config:type="boolean">true</config:config-item>
<config:config-item config:name="ProtectForm" config:type="boolean">true</config:config-item>
<config:config-item config:name="AddVerticalFrameOffsets" config:type="boolean">false</config:config-item>
<config:config-item config:name="SaveThumbnail" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrinterIndependentLayout" config:type="string">high-resolution</config:config-item>
<config:config-item config:name="PrinterPaperFromSetup" config:type="boolean">false</config:config-item>
<config:config-item config:name="TabOverflow" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintGraphics" config:type="boolean">true</config:config-item>
<config:config-item config:name="PropLineSpacingShrinksFirstLine" config:type="boolean">true</config:config-item>
<config:config-item config:name="DoNotResetParaAttrsForNumFont" config:type="boolean">false</config:config-item>
<config:config-item config:name="FieldAutoUpdate" config:type="boolean">true</config:config-item>
<config:config-item config:name="IgnoreTabsAndBlanksForLineCalculation" config:type="boolean">false</config:config-item>
<config:config-item config:name="RedlineProtectionKey" config:type="base64Binary"/>
<config:config-item config:name="EmbedComplexScriptFonts" config:type="boolean">true</config:config-item>
<config:config-item config:name="LoadReadonly" config:type="boolean">false</config:config-item>
<config:config-item config:name="DoNotCaptureDrawObjsOnPage" config:type="boolean">false</config:config-item>
<config:config-item config:name="ClipAsCharacterAnchoredWriterFlyFrames" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintBlackFonts" config:type="boolean">false</config:config-item>
<config:config-item config:name="DisableOffPagePositioning" config:type="boolean">false</config:config-item>
<config:config-item config:name="SurroundTextWrapSmall" config:type="boolean">false</config:config-item>
<config:config-item config:name="UnxForceZeroExtLeading" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmbedAsianScriptFonts" config:type="boolean">true</config:config-item>
<config:config-item config:name="TabAtLeftIndentForParagraphsInList" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintRightPages" config:type="boolean">true</config:config-item>
<config:config-item config:name="Rsid" config:type="int">648908</config:config-item>
<config:config-item config:name="MathBaselineAlignment" config:type="boolean">false</config:config-item>
<config:config-item config:name="MsWordCompTrailingBlanks" config:type="boolean">true</config:config-item>
<config:config-item config:name="MsWordCompMinLineHeightByFly" config:type="boolean">false</config:config-item>
<config:config-item config:name="InvertBorderSpacing" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmbedFonts" config:type="boolean">false</config:config-item>
<config:config-item config:name="UnbreakableNumberings" config:type="boolean">false</config:config-item>
<config:config-item config:name="AddFrameOffsets" config:type="boolean">false</config:config-item>
<config:config-item config:name="ClippedPictures" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmbedLatinScriptFonts" config:type="boolean">true</config:config-item>
<config:config-item config:name="EmbedSystemFonts" config:type="boolean">false</config:config-item>
<config:config-item config:name="ApplyParagraphMarkFormatToNumbering" config:type="boolean">false</config:config-item>
<config:config-item config:name="SubtractFlysAnchoredAtFlys" config:type="boolean">true</config:config-item>
<config:config-item config:name="EmptyDbFieldHidesPara" config:type="boolean">true</config:config-item>
</config:config-item-set>
</office:settings>
</office:document-settings>

131
testFiles/settings.xml Normal file
View file

@ -0,0 +1,131 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<office:document-settings xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:xlink="http://www.w3.org/1999/xlink" office:version="1.3">
<office:settings>
<config:config-item-set config:name="ooo:view-settings">
<config:config-item config:name="ViewAreaTop" config:type="long">0</config:config-item>
<config:config-item config:name="ViewAreaLeft" config:type="long">0</config:config-item>
<config:config-item config:name="ViewAreaWidth" config:type="long">21625</config:config-item>
<config:config-item config:name="ViewAreaHeight" config:type="long">9213</config:config-item>
<config:config-item config:name="ShowRedlineChanges" config:type="boolean">true</config:config-item>
<config:config-item config:name="InBrowseMode" config:type="boolean">false</config:config-item>
<config:config-item-map-indexed config:name="Views">
<config:config-item-map-entry>
<config:config-item config:name="ViewId" config:type="string">view2</config:config-item>
<config:config-item config:name="ViewLeft" config:type="long">3401</config:config-item>
<config:config-item config:name="ViewTop" config:type="long">2501</config:config-item>
<config:config-item config:name="VisibleLeft" config:type="long">0</config:config-item>
<config:config-item config:name="VisibleTop" config:type="long">0</config:config-item>
<config:config-item config:name="VisibleRight" config:type="long">21624</config:config-item>
<config:config-item config:name="VisibleBottom" config:type="long">9211</config:config-item>
<config:config-item config:name="ZoomType" config:type="short">0</config:config-item>
<config:config-item config:name="ViewLayoutColumns" config:type="short">1</config:config-item>
<config:config-item config:name="ViewLayoutBookMode" config:type="boolean">false</config:config-item>
<config:config-item config:name="ZoomFactor" config:type="short">214</config:config-item>
<config:config-item config:name="IsSelectedFrame" config:type="boolean">false</config:config-item>
<config:config-item config:name="AnchoredTextOverflowLegacy" config:type="boolean">true</config:config-item>
</config:config-item-map-entry>
</config:config-item-map-indexed>
</config:config-item-set>
<config:config-item-set config:name="ooo:configuration-settings">
<config:config-item config:name="PrintPaperFromSetup" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintFaxName" config:type="string"/>
<config:config-item config:name="PrintSingleJobs" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintProspectRTL" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintProspect" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintTextPlaceholder" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintTables" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintPageBackground" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintLeftPages" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintAnnotationMode" config:type="short">0</config:config-item>
<config:config-item config:name="PrintControls" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintHiddenText" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintDrawings" config:type="boolean">true</config:config-item>
<config:config-item config:name="FrameAutowidthWithMorePara" config:type="boolean">false</config:config-item>
<config:config-item config:name="HeaderSpacingBelowLastPara" config:type="boolean">false</config:config-item>
<config:config-item config:name="ProtectFields" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintReversed" config:type="boolean">false</config:config-item>
<config:config-item config:name="ProtectBookmarks" config:type="boolean">false</config:config-item>
<config:config-item config:name="UseOldPrinterMetrics" config:type="boolean">false</config:config-item>
<config:config-item config:name="UseOldNumbering" config:type="boolean">false</config:config-item>
<config:config-item config:name="AddExternalLeading" config:type="boolean">true</config:config-item>
<config:config-item config:name="TreatSingleColumnBreakAsPageBreak" config:type="boolean">false</config:config-item>
<config:config-item config:name="IsLabelDocument" config:type="boolean">false</config:config-item>
<config:config-item config:name="RsidRoot" config:type="int">517402</config:config-item>
<config:config-item config:name="ConsiderTextWrapOnObjPos" config:type="boolean">false</config:config-item>
<config:config-item config:name="TableRowKeep" config:type="boolean">false</config:config-item>
<config:config-item config:name="TabsRelativeToIndent" config:type="boolean">true</config:config-item>
<config:config-item config:name="AddParaLineSpacingToTableCells" config:type="boolean">false</config:config-item>
<config:config-item config:name="AllowPrintJobCancel" config:type="boolean">true</config:config-item>
<config:config-item config:name="UpdateFromTemplate" config:type="boolean">true</config:config-item>
<config:config-item config:name="SaveVersionOnClose" config:type="boolean">false</config:config-item>
<config:config-item config:name="UseFormerTextWrapping" config:type="boolean">false</config:config-item>
<config:config-item config:name="ChartAutoUpdate" config:type="boolean">true</config:config-item>
<config:config-item config:name="ContinuousEndnotes" config:type="boolean">false</config:config-item>
<config:config-item config:name="AddParaTableSpacingAtStart" config:type="boolean">true</config:config-item>
<config:config-item config:name="AddParaTableSpacing" config:type="boolean">true</config:config-item>
<config:config-item config:name="AddParaSpacingToTableCells" config:type="boolean">false</config:config-item>
<config:config-item config:name="UseFormerLineSpacing" config:type="boolean">false</config:config-item>
<config:config-item config:name="OutlineLevelYieldsNumbering" config:type="boolean">false</config:config-item>
<config:config-item config:name="AlignTabStopPosition" config:type="boolean">true</config:config-item>
<config:config-item config:name="DoNotJustifyLinesWithManualBreak" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmbedOnlyUsedFonts" config:type="boolean">false</config:config-item>
<config:config-item config:name="LinkUpdateMode" config:type="short">1</config:config-item>
<config:config-item config:name="CurrentDatabaseCommandType" config:type="int">0</config:config-item>
<config:config-item config:name="CurrentDatabaseCommand" config:type="string"/>
<config:config-item config:name="CharacterCompressionType" config:type="short">0</config:config-item>
<config:config-item config:name="SmallCapsPercentage66" config:type="boolean">false</config:config-item>
<config:config-item config:name="ApplyUserData" config:type="boolean">true</config:config-item>
<config:config-item config:name="StylesNoDefault" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmbeddedDatabaseName" config:type="string"/>
<config:config-item config:name="FloattableNomargins" config:type="boolean">false</config:config-item>
<config:config-item config:name="BackgroundParaOverDrawings" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrinterName" config:type="string"/>
<config:config-item config:name="UseFormerObjectPositioning" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrinterSetup" config:type="base64Binary"/>
<config:config-item config:name="IgnoreFirstLineIndentInNumbering" config:type="boolean">false</config:config-item>
<config:config-item config:name="CollapseEmptyCellPara" config:type="boolean">true</config:config-item>
<config:config-item config:name="TabOverMargin" config:type="boolean">false</config:config-item>
<config:config-item config:name="SaveGlobalDocumentLinks" config:type="boolean">false</config:config-item>
<config:config-item config:name="CurrentDatabaseDataSource" config:type="string"/>
<config:config-item config:name="IsKernAsianPunctuation" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintEmptyPages" config:type="boolean">true</config:config-item>
<config:config-item config:name="ProtectForm" config:type="boolean">false</config:config-item>
<config:config-item config:name="AddVerticalFrameOffsets" config:type="boolean">false</config:config-item>
<config:config-item config:name="SaveThumbnail" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrinterIndependentLayout" config:type="string">high-resolution</config:config-item>
<config:config-item config:name="PrinterPaperFromSetup" config:type="boolean">false</config:config-item>
<config:config-item config:name="TabOverflow" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintGraphics" config:type="boolean">true</config:config-item>
<config:config-item config:name="PropLineSpacingShrinksFirstLine" config:type="boolean">true</config:config-item>
<config:config-item config:name="DoNotResetParaAttrsForNumFont" config:type="boolean">false</config:config-item>
<config:config-item config:name="FieldAutoUpdate" config:type="boolean">true</config:config-item>
<config:config-item config:name="IgnoreTabsAndBlanksForLineCalculation" config:type="boolean">false</config:config-item>
<config:config-item config:name="RedlineProtectionKey" config:type="base64Binary"/>
<config:config-item config:name="EmbedComplexScriptFonts" config:type="boolean">true</config:config-item>
<config:config-item config:name="LoadReadonly" config:type="boolean">false</config:config-item>
<config:config-item config:name="DoNotCaptureDrawObjsOnPage" config:type="boolean">false</config:config-item>
<config:config-item config:name="ClipAsCharacterAnchoredWriterFlyFrames" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintBlackFonts" config:type="boolean">false</config:config-item>
<config:config-item config:name="DisableOffPagePositioning" config:type="boolean">false</config:config-item>
<config:config-item config:name="SurroundTextWrapSmall" config:type="boolean">false</config:config-item>
<config:config-item config:name="UnxForceZeroExtLeading" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmbedAsianScriptFonts" config:type="boolean">true</config:config-item>
<config:config-item config:name="TabAtLeftIndentForParagraphsInList" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintRightPages" config:type="boolean">true</config:config-item>
<config:config-item config:name="Rsid" config:type="int">639374</config:config-item>
<config:config-item config:name="MathBaselineAlignment" config:type="boolean">false</config:config-item>
<config:config-item config:name="MsWordCompTrailingBlanks" config:type="boolean">false</config:config-item>
<config:config-item config:name="MsWordCompMinLineHeightByFly" config:type="boolean">false</config:config-item>
<config:config-item config:name="InvertBorderSpacing" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmbedFonts" config:type="boolean">false</config:config-item>
<config:config-item config:name="UnbreakableNumberings" config:type="boolean">false</config:config-item>
<config:config-item config:name="AddFrameOffsets" config:type="boolean">false</config:config-item>
<config:config-item config:name="ClippedPictures" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmbedLatinScriptFonts" config:type="boolean">true</config:config-item>
<config:config-item config:name="EmbedSystemFonts" config:type="boolean">false</config:config-item>
<config:config-item config:name="ApplyParagraphMarkFormatToNumbering" config:type="boolean">false</config:config-item>
<config:config-item config:name="SubtractFlysAnchoredAtFlys" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmptyDbFieldHidesPara" config:type="boolean">false</config:config-item>
</config:config-item-set>
</office:settings>
</office:document-settings>

Binary file not shown.

BIN
testFiles/testFile.odt Normal file

Binary file not shown.