initial commit

master
李岩峰 5 years ago
parent d2f34333b7
commit b3a74388fe

51
.gitignore vendored

@ -1,13 +1,42 @@
# ---> Maven
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
.mvn/wrapper/maven-wrapper.jar
!.mvn/wrapper/maven-wrapper.jar
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
nbproject/private/
build/
nbbuild/
dist/
nbdist/
.nb-gradle/
/*.iml
**/target/
.classpath
.project
**/.settings
**/build/
**/.externalToolBuilders/
*.iml
**/.idea/
**/disconf
**/rpc.properties
/producer/tmp
/.temfile
.temfile
convertedFile/
jodconverter-web/src/main/cache/
jodconverter-web/src/main/file/

@ -0,0 +1,4 @@
{
"java.configuration.updateBuildConfiguration": "automatic",
"git.ignoreLimitWarning": true
}

@ -0,0 +1,34 @@
FROM centos:centos7.6.1810
MAINTAINER chenjh "842761733@qq.com"
ADD jodconverter-web/target/kkFileView-*.tar.gz /opt/
COPY fonts/* /usr/share/fonts/chienes/
RUN yum install -y kde-l10n-Chinese &&\
yum install -y glibc-common &&\
yum install -y fontconfig &&\
yum install -y mkfontscale &&\
localedef -c -f UTF-8 -i zh_CN zh_CN.utf8 &&\
echo "LANG=zh_CN.UTF-8" > /etc/locale.conf &&\
source /etc/locale.conf &&\
export LANG=zh_CN.UTF-8 &&\
LANG="zh_CN.UTF-8" &&\
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime &&\
yum install -y java-1.8.0-openjdk.x86_64 &&\
yum install -y wget &&\
yum install -y libXext.x86_64 &&\
yum groupinstall -y "X Window System" &&\
cd /tmp &&\
wget https://kkfileview.keking.cn/Apache_OpenOffice_4.1.6_Linux_x86-64_install-rpm_zh-CN.tar.gz -cO openoffice_rpm.tar.gz &&\
tar zxf /tmp/openoffice_rpm.tar.gz &&\
cd /tmp/zh-CN/RPMS &&\
rpm -Uvih *.rpm &&\
rpm -Uvih desktop-integration/openoffice4.1.6-redhat-menus-4.1.6-9790.noarch.rpm &&\
rm -f /tmp/openoffice_rpm.tar.gz &&\
rm -rf /tmp/zh-CN &&\
cd /usr/share/fonts/chienes &&\
mkfontscale &&\
mkfontdir &&\
fc-cache -fv
ENV LANG zh_CN.UTF-8
ENV LC_ALL zh_CN.UTF-8
ENV KKFILEVIEW_BIN_FOLDER /opt/kkFileView-2.2.0-SNAPSHOT/bin
ENTRYPOINT ["java","-Dfile.encoding=UTF-8","-Dsun.java2d.cmm=sun.java2d.cmm.kcms.KcmsServiceProvider","-Dspring.config.location=/opt/kkFileView-2.2.0-SNAPSHOT/config/application.properties","-jar","/opt/kkFileView-2.2.0-SNAPSHOT/bin/kkFileView-2.2.0-SNAPSHOT.jar"]

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

@ -0,0 +1,102 @@
# file-online-preview
[![GitHub license](https://img.shields.io/github/license/kekingcn/kkFileView.svg?style=flat-square)](https://github.com/kekingcn/kkFileView/blob/master/LICENSE)
### Introduction
This kekingcn kkFileView project is intended to be a solution for previewing documents online. At present,there are some similar paid products in the industry.
Such as 【[永中office](http://dcs.yozosoft.com/)】,【[office365](http://www.officeweb365.com/)】,【[idocv](https://www.idocv.com/)】, etc...
It is an open source implementation and released under the Apache License version 2.0. Finally,It is aimed to feedback the community after obtaining the consent of company executives,
special thanks to the supports of @唐老大 and the contributions of @端木详笑.
### Features
- Build with the popular frame spring boot
- Easy to build and deploy
- Basically support online preview of mainstream office documents, such as Doc, docx, Excel, PDF, TXT, zip, rar, pictures, etc
- REST API
- Abstract file preview interface so that it is easy to extend more file extensions and develop this project on your own
### Live demo
> Please treat public service kindly, or this would stop at any time.
URLhttp://file.keking.cn/
### Documentation
1. 中文文档https://gitee.com/kekingcn/file-online-preview/blob/master/README.md
1. English documenthttps://github.com/kekingcn/kkFileView/blob/master/README.en.md
### Contact us && Join us
> We will answer everyone's questions in use of this project.
And please Google or Baidu first before asking a question, so that we can solve it efficiently.
Cherish life away from ineffective communication.
![输入图片说明](https://gitee.com/uploads/images/2017/1219/173717_934cb068_492218.png "屏幕截图.png")
QQ group613025121
### Pictures for some samples
> Excel
![输入图片说明](https://gitee.com/uploads/images/2017/1213/093051_cd55b3ec_492218.png "屏幕截图.png")
> doc
![输入图片说明](https://gitee.com/uploads/images/2017/1213/092350_5b2ecbe5_492218.png "屏幕截图.png")
> zip,rar
![输入图片说明](https://gitee.com/uploads/images/2017/1213/093806_46cede06_492218.png "屏幕截图.png")
> png,jpeg,jpg,etc., support for zooming with mouse scroll, rotation, inversion,etc.
![输入图片说明](https://gitee.com/uploads/images/2017/1213/094335_657a6f60_492218.png "屏幕截图.png")
Considering space issues, the pictures of other types of documents will not be shown here.You can deploy it by yourself if you are interested in our project.There is a way to deploy it as below.
### Quick Start
> Technology stack
- Spring boot [spring boot Development Reference Guide](http://www.kailing.pub/PdfReader/web/viewer.html?file=springboot)
- Freemarker
- Redisson
- Jodconverter
> Dependencies
- Redis(Optional, Unnecessary by default)
- OpenOffice or LibreOffice(Integrated on Windows, will be installed automatically on Linux, need to be manually installed on Mac OS)
1. First step`git pull https://github.com/kekingcn/file-online-preview.git`
2. Third stepRun the main method of FilePreviewApplication.java.After starting,visit `http://localhost:8012/`.
If everything is ok,you will see the picture below.
![输入图片说明](https://gitee.com/uploads/images/2017/1213/100221_ea15202e_492218.png "屏幕截图.png")
### Changelog
> June 18th 2019
1. Support automatic cleaning of cache and preview files
2. Support http/https stream url file preview
3. Support FTP url file preview
4. Add Docker build
> April 8th 2019
1. Cache and queue implementations abstract, providing JDK and REDIS implementations (REDIS becomes optional dependencies)
2. Provides zip and tar.gz packages, and provides a one-click startup script
> January 17th 2018
1. Refined the project directory, abstract file preview interface, Easy to extend more file extensions and depoly this project on your own
1. Added English documentation (@幻幻Fate@汝辉) contribution
1. Support for more image file extensions
1. Fixed the issue that image carousel in zip file will always start from the first
> January 12th 2018
1. Support for multiple images preview
1. Support for images rotation preview in rar/zip
> January 2nd 2018
1. Fixed gibberish issue when preview a txt document caused by the file encoding problem
1. Fixed the issue that some module dependencies can not be found
1. Add a spring boot profile, and support for Multi-environment configuration
1. Add `pdf.js` to preview the documents such as doc,etc.,support for generating doc headlines as pdf menusupport for mobile preview
### Register Usage
If this project is helpful for you, please register on 'https://gitee.com/kekingcn/file-online-preview/issues/IGSBV',
If this project helps you to economize the service charge for preview of documents, as well as you are willing to support us, click 【donate】 below to donate a cup of coffee, we would appreciate it.

@ -1,3 +1,9 @@
# fileview
# file-online-preview
此项目为文件文档在线预览项目解决方案
## 构建
```
mvn clean package
```
文档在线预览

@ -0,0 +1,160 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.keking</groupId>
<artifactId>jodconverter-core</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<repositories>
<repository>
<!-- required for org.hyperic:sigar -->
<id>jboss-public-repository-group</id>
<url>https://repository.jboss.org/nexus/content/groups/public-jboss/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.openoffice</groupId>
<artifactId>juh</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>org.openoffice</groupId>
<artifactId>ridl</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>org.openoffice</groupId>
<artifactId>unoil</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<!-- for the command line tool -->
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.1</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.hyperic</groupId>
<artifactId>sigar</artifactId>
<version>1.6.5.132</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20190722</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.0.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 要将源码放上去,需要加入这个插件 -->
<plugin>
<artifactId>maven-source-plugin</artifactId>
<version>2.1</version>
<configuration>
<attach>true</attach>
</configuration>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.7.2</version>
<configuration>
<!-- don't run tests in parallel -->
<perCoreThreadCount>false</perCoreThreadCount>
<threadCount>1</threadCount>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<archive>
<manifest>
<mainClass>org.artofsolving.jodconverter.cli.Convert</mainClass>
<addClasspath>true</addClasspath>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-5</version>
<configuration>
<descriptors>
<descriptor>src/main/assembly/dist.xml</descriptor>
</descriptors>
</configuration>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.7</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>2.4</version>
</plugin>
</plugins>
</reporting>
<!-- distribute目录 -->
<distributionManagement>
<repository>
<id>repo</id>
<name>User Project Releases</name>
<url>http://192.168.1.204:8081/nexus/content/repositories/releases</url>
</repository>
<snapshotRepository>
<id>repo</id>
<name>User Project SNAPSHOTS</name>
<url>http://192.168.1.204:8081/nexus/content/repositories/snapshots</url>
</snapshotRepository>
</distributionManagement>
</project>

@ -0,0 +1,37 @@
<assembly>
<id>dist</id>
<formats>
<format>zip</format>
</formats>
<dependencySets>
<dependencySet>
<outputDirectory>lib</outputDirectory>
<excludes>
<exclude>org.hyperic:sigar</exclude>
</excludes>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<includes>
<include>LICENSE.txt</include>
<include>README.txt</include>
</includes>
</fileSet>
<fileSet>
<directory>target</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>${project.artifactId}-${project.version}-javadoc.jar</include>
<include>${project.artifactId}-${project.version}-sources.jar</include>
</includes>
</fileSet>
<fileSet>
<directory>src/main/resources</directory>
<outputDirectory>/conf</outputDirectory>
<includes>
<include>document-formats.js</include>
</includes>
</fileSet>
</fileSets>
</assembly>

@ -0,0 +1,125 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter;
import static org.artofsolving.jodconverter.office.OfficeUtils.SERVICE_DESKTOP;
import static org.artofsolving.jodconverter.office.OfficeUtils.cast;
import static org.artofsolving.jodconverter.office.OfficeUtils.toUnoProperties;
import static org.artofsolving.jodconverter.office.OfficeUtils.toUrl;
import java.io.File;
import java.util.Map;
import org.artofsolving.jodconverter.office.OfficeContext;
import org.artofsolving.jodconverter.office.OfficeException;
import org.artofsolving.jodconverter.office.OfficeTask;
import com.sun.star.frame.XComponentLoader;
import com.sun.star.frame.XStorable;
import com.sun.star.io.IOException;
import com.sun.star.lang.IllegalArgumentException;
import com.sun.star.lang.XComponent;
import com.sun.star.task.ErrorCodeIOException;
import com.sun.star.util.CloseVetoException;
import com.sun.star.util.XCloseable;
public abstract class AbstractConversionTask implements OfficeTask {
private final File inputFile;
private final File outputFile;
public AbstractConversionTask(File inputFile, File outputFile) {
this.inputFile = inputFile;
this.outputFile = outputFile;
}
protected abstract Map<String,?> getLoadProperties(File inputFile);
protected abstract Map<String,?> getStoreProperties(File outputFile, XComponent document);
public void execute(OfficeContext context) throws OfficeException {
XComponent document = null;
try {
document = loadDocument(context, inputFile);
modifyDocument(document);
storeDocument(document, outputFile);
} catch (OfficeException officeException) {
throw officeException;
} catch (Exception exception) {
throw new OfficeException("conversion failed", exception);
} finally {
if (document != null) {
XCloseable closeable = cast(XCloseable.class, document);
if (closeable != null) {
try {
closeable.close(true);
} catch (CloseVetoException closeVetoException) {
// whoever raised the veto should close the document
}
} else {
document.dispose();
}
}
}
}
private XComponent loadDocument(OfficeContext context, File inputFile) throws OfficeException {
if (!inputFile.exists()) {
throw new OfficeException("input document not found");
}
XComponentLoader loader = cast(XComponentLoader.class, context.getService(SERVICE_DESKTOP));
Map<String,?> loadProperties = getLoadProperties(inputFile);
XComponent document = null;
try {
document = loader.loadComponentFromURL(toUrl(inputFile), "_blank", 0, toUnoProperties(loadProperties));
} catch (IllegalArgumentException illegalArgumentException) {
throw new OfficeException("could not load document: " + inputFile.getName(), illegalArgumentException);
} catch (ErrorCodeIOException errorCodeIOException) {
throw new OfficeException("could not load document: " + inputFile.getName() + "; errorCode: " + errorCodeIOException.ErrCode, errorCodeIOException);
} catch (IOException ioException) {
throw new OfficeException("could not load document: " + inputFile.getName(), ioException);
}
if (document == null) {
throw new OfficeException("could not load document: " + inputFile.getName());
}
return document;
}
/**
* Override to modify the document after it has been loaded and before it gets
* saved in the new format.
* <p>
* Does nothing by default.
*
* @param document
* @throws OfficeException
*/
protected void modifyDocument(XComponent document) throws OfficeException {
// noop
}
private void storeDocument(XComponent document, File outputFile) throws OfficeException {
Map<String,?> storeProperties = getStoreProperties(outputFile, document);
if (storeProperties == null) {
throw new OfficeException("unsupported conversion");
}
try {
cast(XStorable.class, document).storeToURL(toUrl(outputFile), toUnoProperties(storeProperties));
} catch (ErrorCodeIOException errorCodeIOException) {
throw new OfficeException("could not store document: " + outputFile.getName() + "; errorCode: " + errorCodeIOException.ErrCode, errorCodeIOException);
} catch (IOException ioException) {
throw new OfficeException("could not store document: " + outputFile.getName(), ioException);
}
}
}

@ -0,0 +1,75 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.io.FilenameUtils;
import org.artofsolving.jodconverter.document.DefaultDocumentFormatRegistry;
import org.artofsolving.jodconverter.document.DocumentFormat;
import org.artofsolving.jodconverter.document.DocumentFormatRegistry;
import org.artofsolving.jodconverter.office.OfficeException;
import org.artofsolving.jodconverter.office.OfficeManager;
import com.sun.star.document.UpdateDocMode;
public class OfficeDocumentConverter {
private final OfficeManager officeManager;
private final DocumentFormatRegistry formatRegistry;
private Map<String,?> defaultLoadProperties = createDefaultLoadProperties();
public OfficeDocumentConverter(OfficeManager officeManager) {
this(officeManager, new DefaultDocumentFormatRegistry());
}
public OfficeDocumentConverter(OfficeManager officeManager, DocumentFormatRegistry formatRegistry) {
this.officeManager = officeManager;
this.formatRegistry = formatRegistry;
}
private Map<String,Object> createDefaultLoadProperties() {
Map<String,Object> loadProperties = new HashMap<String,Object>();
loadProperties.put("Hidden", true);
loadProperties.put("ReadOnly", true);
loadProperties.put("UpdateDocMode", UpdateDocMode.QUIET_UPDATE);
return loadProperties;
}
public void setDefaultLoadProperties(Map<String, ?> defaultLoadProperties) {
this.defaultLoadProperties = defaultLoadProperties;
}
public DocumentFormatRegistry getFormatRegistry() {
return formatRegistry;
}
public void convert(File inputFile, File outputFile) throws OfficeException {
String outputExtension = FilenameUtils.getExtension(outputFile.getName());
DocumentFormat outputFormat = formatRegistry.getFormatByExtension(outputExtension);
convert(inputFile, outputFile, outputFormat);
}
public void convert(File inputFile, File outputFile, DocumentFormat outputFormat) throws OfficeException {
String inputExtension = FilenameUtils.getExtension(inputFile.getName());
DocumentFormat inputFormat = formatRegistry.getFormatByExtension(inputExtension);
StandardConversionTask conversionTask = new StandardConversionTask(inputFile, outputFile, outputFormat);
conversionTask.setDefaultLoadProperties(defaultLoadProperties);
conversionTask.setInputFormat(inputFormat);
officeManager.execute(conversionTask);
}
}

@ -0,0 +1,47 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter;
import static org.artofsolving.jodconverter.office.OfficeUtils.*;
import org.artofsolving.jodconverter.document.DocumentFamily;
import org.artofsolving.jodconverter.office.OfficeException;
import com.sun.star.lang.XComponent;
import com.sun.star.lang.XServiceInfo;
class OfficeDocumentUtils {
private OfficeDocumentUtils() {
throw new AssertionError("utility class must not be instantiated");
}
public static DocumentFamily getDocumentFamily(XComponent document) throws OfficeException {
XServiceInfo serviceInfo = cast(XServiceInfo.class, document);
if (serviceInfo.supportsService("com.sun.star.text.GenericTextDocument")) {
// NOTE: a GenericTextDocument is either a TextDocument, a WebDocument, or a GlobalDocument
// but this further distinction doesn't seem to matter for conversions
return DocumentFamily.TEXT;
} else if (serviceInfo.supportsService("com.sun.star.sheet.SpreadsheetDocument")) {
return DocumentFamily.SPREADSHEET;
} else if (serviceInfo.supportsService("com.sun.star.presentation.PresentationDocument")) {
return DocumentFamily.PRESENTATION;
} else if (serviceInfo.supportsService("com.sun.star.drawing.DrawingDocument")) {
return DocumentFamily.DRAWING;
} else {
throw new OfficeException("document of unknown family: " + serviceInfo.getImplementationName());
}
}
}

@ -0,0 +1,74 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter;
import static org.artofsolving.jodconverter.office.OfficeUtils.cast;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import org.artofsolving.jodconverter.document.DocumentFamily;
import org.artofsolving.jodconverter.document.DocumentFormat;
import org.artofsolving.jodconverter.office.OfficeException;
import com.sun.star.lang.XComponent;
import com.sun.star.util.XRefreshable;
public class StandardConversionTask extends AbstractConversionTask {
private final DocumentFormat outputFormat;
private Map<String,?> defaultLoadProperties;
private DocumentFormat inputFormat;
public StandardConversionTask(File inputFile, File outputFile, DocumentFormat outputFormat) {
super(inputFile, outputFile);
this.outputFormat = outputFormat;
}
public void setDefaultLoadProperties(Map<String, ?> defaultLoadProperties) {
this.defaultLoadProperties = defaultLoadProperties;
}
public void setInputFormat(DocumentFormat inputFormat) {
this.inputFormat = inputFormat;
}
@Override
protected void modifyDocument(XComponent document) throws OfficeException {
XRefreshable refreshable = cast(XRefreshable.class, document);
if (refreshable != null) {
refreshable.refresh();
}
}
@Override
protected Map<String,?> getLoadProperties(File inputFile) {
Map<String,Object> loadProperties = new HashMap<String,Object>();
if (defaultLoadProperties != null) {
loadProperties.putAll(defaultLoadProperties);
}
if (inputFormat != null && inputFormat.getLoadProperties() != null) {
loadProperties.putAll(inputFormat.getLoadProperties());
}
return loadProperties;
}
@Override
protected Map<String,?> getStoreProperties(File outputFile, XComponent document) {
DocumentFamily family = OfficeDocumentUtils.getDocumentFamily(document);
return outputFormat.getStoreProperties(family);
}
}

@ -0,0 +1,126 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.cli;
import java.io.File;
import java.io.IOException;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.artofsolving.jodconverter.OfficeDocumentConverter;
import org.artofsolving.jodconverter.document.DefaultDocumentFormatRegistry;
import org.artofsolving.jodconverter.document.DocumentFormatRegistry;
import org.artofsolving.jodconverter.document.JsonDocumentFormatRegistry;
import org.artofsolving.jodconverter.office.OfficeManager;
import org.artofsolving.jodconverter.office.DefaultOfficeManagerConfiguration;
import org.json.JSONException;
/**
* Command line interface executable.
*/
public class Convert {
public static final int STATUS_OK = 0;
public static final int STATUS_MISSING_INPUT_FILE = 1;
public static final int STATUS_INVALID_ARGUMENTS = 255;
private static final Option OPTION_OUTPUT_FORMAT = new Option("o", "output-format", true, "output format (e.g. pdf)");
private static final Option OPTION_PORT = new Option("p", "port", true, "office socket port (optional; defaults to 2002)");
private static final Option OPTION_REGISTRY = new Option("r", "registry", true, "document formats registry configuration file (optional)");
private static final Option OPTION_TIMEOUT = new Option("t", "timeout", true, "maximum conversion time in seconds (optional; defaults to 120)");
private static final Option OPTION_USER_PROFILE = new Option("u", "user-profile", true, "use settings from the given user installation dir (optional)");
private static final Options OPTIONS = initOptions();
private static final int DEFAULT_OFFICE_PORT = 2002;
private static Options initOptions() {
Options options = new Options();
options.addOption(OPTION_OUTPUT_FORMAT);
options.addOption(OPTION_PORT);
options.addOption(OPTION_REGISTRY);
options.addOption(OPTION_TIMEOUT);
options.addOption(OPTION_USER_PROFILE);
return options;
}
public static void main(String[] arguments) throws ParseException, JSONException, IOException {
CommandLineParser commandLineParser = new PosixParser();
CommandLine commandLine = commandLineParser.parse(OPTIONS, arguments);
String outputFormat = null;
if (commandLine.hasOption(OPTION_OUTPUT_FORMAT.getOpt())) {
outputFormat = commandLine.getOptionValue(OPTION_OUTPUT_FORMAT.getOpt());
}
int port = DEFAULT_OFFICE_PORT;
if (commandLine.hasOption(OPTION_PORT.getOpt())) {
port = Integer.parseInt(commandLine.getOptionValue(OPTION_PORT.getOpt()));
}
String[] fileNames = commandLine.getArgs();
if ((outputFormat == null && fileNames.length != 2) || fileNames.length < 1) {
String syntax = "java -jar jodconverter-core.jar [options] input-file output-file\n"
+ "or [options] -o output-format input-file [input-file...]";
HelpFormatter helpFormatter = new HelpFormatter();
helpFormatter.printHelp(syntax, OPTIONS);
System.exit(STATUS_INVALID_ARGUMENTS);
}
DocumentFormatRegistry registry;
if (commandLine.hasOption(OPTION_REGISTRY.getOpt())) {
File registryFile = new File(commandLine.getOptionValue(OPTION_REGISTRY.getOpt()));
registry = new JsonDocumentFormatRegistry(FileUtils.readFileToString(registryFile));
} else {
registry = new DefaultDocumentFormatRegistry();
}
DefaultOfficeManagerConfiguration configuration = new DefaultOfficeManagerConfiguration();
configuration.setPortNumber(port);
if (commandLine.hasOption(OPTION_TIMEOUT.getOpt())) {
int timeout = Integer.parseInt(commandLine.getOptionValue(OPTION_TIMEOUT.getOpt()));
configuration.setTaskExecutionTimeout(timeout * 1000);
}
if (commandLine.hasOption(OPTION_USER_PROFILE.getOpt())) {
String templateProfileDir = commandLine.getOptionValue(OPTION_USER_PROFILE.getOpt());
configuration.setTemplateProfileDir(new File(templateProfileDir));
}
OfficeManager officeManager = configuration.buildOfficeManager();
officeManager.start();
OfficeDocumentConverter converter = new OfficeDocumentConverter(officeManager, registry);
try {
if (outputFormat == null) {
File inputFile = new File(fileNames[0]);
File outputFile = new File(fileNames[1]);
converter.convert(inputFile, outputFile);
} else {
for (int i = 0; i < fileNames.length; i++) {
File inputFile = new File(fileNames[i]);
String outputName = FilenameUtils.getBaseName(fileNames[i]) + "." + outputFormat;
File outputFile = new File(FilenameUtils.getFullPath(fileNames[i]) + outputName);
converter.convert(inputFile, outputFile);
}
}
} finally {
officeManager.stop();
}
}
}

@ -0,0 +1,157 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.document;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
public class DefaultDocumentFormatRegistry extends SimpleDocumentFormatRegistry {
public DefaultDocumentFormatRegistry() {
DocumentFormat pdf = new DocumentFormat("Portable Document Format", "pdf", "application/pdf");
pdf.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "writer_pdf_Export"));
pdf.setStoreProperties(DocumentFamily.SPREADSHEET, Collections.singletonMap("FilterName", "calc_pdf_Export"));
pdf.setStoreProperties(DocumentFamily.PRESENTATION, Collections.singletonMap("FilterName", "impress_pdf_Export"));
pdf.setStoreProperties(DocumentFamily.DRAWING, Collections.singletonMap("FilterName", "draw_pdf_Export"));
addFormat(pdf);
DocumentFormat swf = new DocumentFormat("Macromedia Flash", "swf", "application/x-shockwave-flash");
swf.setStoreProperties(DocumentFamily.PRESENTATION, Collections.singletonMap("FilterName", "impress_flash_Export"));
swf.setStoreProperties(DocumentFamily.DRAWING, Collections.singletonMap("FilterName", "draw_flash_Export"));
addFormat(swf);
// disabled because it's not always available
//DocumentFormat xhtml = new DocumentFormat("XHTML", "xhtml", "application/xhtml+xml");
//xhtml.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "XHTML Writer File"));
//xhtml.setStoreProperties(DocumentFamily.SPREADSHEET, Collections.singletonMap("FilterName", "XHTML Calc File"));
//xhtml.setStoreProperties(DocumentFamily.PRESENTATION, Collections.singletonMap("FilterName", "XHTML Impress File"));
//addFormat(xhtml);
DocumentFormat html = new DocumentFormat("HTML", "html", "text/html");
// HTML is treated as Text when supplied as input, but as an output it is also
// available for exporting Spreadsheet and Presentation formats
html.setInputFamily(DocumentFamily.TEXT);
html.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "HTML (StarWriter)"));
html.setStoreProperties(DocumentFamily.SPREADSHEET, Collections.singletonMap("FilterName", "HTML (StarCalc)"));
html.setStoreProperties(DocumentFamily.PRESENTATION, Collections.singletonMap("FilterName", "impress_html_Export"));
addFormat(html);
DocumentFormat odt = new DocumentFormat("OpenDocument Text", "odt", "application/vnd.oasis.opendocument.text");
odt.setInputFamily(DocumentFamily.TEXT);
odt.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "writer8"));
addFormat(odt);
DocumentFormat sxw = new DocumentFormat("OpenOffice.org 1.0 Text Document", "sxw", "application/vnd.sun.xml.writer");
sxw.setInputFamily(DocumentFamily.TEXT);
sxw.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "StarOffice XML (Writer)"));
addFormat(sxw);
DocumentFormat doc = new DocumentFormat("Microsoft Word", "doc", "application/msword");
doc.setInputFamily(DocumentFamily.TEXT);
doc.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "MS Word 97"));
addFormat(doc);
DocumentFormat docx = new DocumentFormat("Microsoft Word 2007 XML", "docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
docx.setInputFamily(DocumentFamily.TEXT);
addFormat(docx);
DocumentFormat rtf = new DocumentFormat("Rich Text Format", "rtf", "text/rtf");
rtf.setInputFamily(DocumentFamily.TEXT);
rtf.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "Rich Text Format"));
addFormat(rtf);
DocumentFormat wpd = new DocumentFormat("WordPerfect", "wpd", "application/wordperfect");
wpd.setInputFamily(DocumentFamily.TEXT);
addFormat(wpd);
DocumentFormat txt = new DocumentFormat("Plain Text", "txt", "text/plain");
txt.setInputFamily(DocumentFamily.TEXT);
Map<String,Object> txtLoadAndStoreProperties = new LinkedHashMap<String,Object>();
txtLoadAndStoreProperties.put("FilterName", "Text (encoded)");
txtLoadAndStoreProperties.put("FilterOptions", "utf8");
txt.setLoadProperties(txtLoadAndStoreProperties);
txt.setStoreProperties(DocumentFamily.TEXT, txtLoadAndStoreProperties);
addFormat(txt);
DocumentFormat wikitext = new DocumentFormat("MediaWiki wikitext", "wiki", "text/x-wiki");
wikitext.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "MediaWiki"));
//addFormat(wikitext);
DocumentFormat ods = new DocumentFormat("OpenDocument Spreadsheet", "ods", "application/vnd.oasis.opendocument.spreadsheet");
ods.setInputFamily(DocumentFamily.SPREADSHEET);
ods.setStoreProperties(DocumentFamily.SPREADSHEET, Collections.singletonMap("FilterName", "calc8"));
addFormat(ods);
DocumentFormat sxc = new DocumentFormat("OpenOffice.org 1.0 Spreadsheet", "sxc", "application/vnd.sun.xml.calc");
sxc.setInputFamily(DocumentFamily.SPREADSHEET);
sxc.setStoreProperties(DocumentFamily.SPREADSHEET, Collections.singletonMap("FilterName", "StarOffice XML (Calc)"));
addFormat(sxc);
DocumentFormat xls = new DocumentFormat("Microsoft Excel", "xls", "application/vnd.ms-excel");
xls.setInputFamily(DocumentFamily.SPREADSHEET);
xls.setStoreProperties(DocumentFamily.SPREADSHEET, Collections.singletonMap("FilterName", "MS Excel 97"));
addFormat(xls);
DocumentFormat xlsx = new DocumentFormat("Microsoft Excel 2007 XML", "xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
xlsx.setInputFamily(DocumentFamily.SPREADSHEET);
addFormat(xlsx);
DocumentFormat csv = new DocumentFormat("Comma Separated Values", "csv", "text/csv");
csv.setInputFamily(DocumentFamily.SPREADSHEET);
Map<String,Object> csvLoadAndStoreProperties = new LinkedHashMap<String,Object>();
csvLoadAndStoreProperties.put("FilterName", "Text - txt - csv (StarCalc)");
csvLoadAndStoreProperties.put("FilterOptions", "44,34,0"); // Field Separator: ','; Text Delimiter: '"'
csv.setLoadProperties(csvLoadAndStoreProperties);
csv.setStoreProperties(DocumentFamily.SPREADSHEET, csvLoadAndStoreProperties);
addFormat(csv);
DocumentFormat tsv = new DocumentFormat("Tab Separated Values", "tsv", "text/tab-separated-values");
tsv.setInputFamily(DocumentFamily.SPREADSHEET);
Map<String,Object> tsvLoadAndStoreProperties = new LinkedHashMap<String,Object>();
tsvLoadAndStoreProperties.put("FilterName", "Text - txt - csv (StarCalc)");
tsvLoadAndStoreProperties.put("FilterOptions", "9,34,0"); // Field Separator: '\t'; Text Delimiter: '"'
tsv.setLoadProperties(tsvLoadAndStoreProperties);
tsv.setStoreProperties(DocumentFamily.SPREADSHEET, tsvLoadAndStoreProperties);
addFormat(tsv);
DocumentFormat odp = new DocumentFormat("OpenDocument Presentation", "odp", "application/vnd.oasis.opendocument.presentation");
odp.setInputFamily(DocumentFamily.PRESENTATION);
odp.setStoreProperties(DocumentFamily.PRESENTATION, Collections.singletonMap("FilterName", "impress8"));
addFormat(odp);
DocumentFormat sxi = new DocumentFormat("OpenOffice.org 1.0 Presentation", "sxi", "application/vnd.sun.xml.impress");
sxi.setInputFamily(DocumentFamily.PRESENTATION);
sxi.setStoreProperties(DocumentFamily.PRESENTATION, Collections.singletonMap("FilterName", "StarOffice XML (Impress)"));
addFormat(sxi);
DocumentFormat ppt = new DocumentFormat("Microsoft PowerPoint", "ppt", "application/vnd.ms-powerpoint");
ppt.setInputFamily(DocumentFamily.PRESENTATION);
ppt.setStoreProperties(DocumentFamily.PRESENTATION, Collections.singletonMap("FilterName", "MS PowerPoint 97"));
addFormat(ppt);
DocumentFormat pptx = new DocumentFormat("Microsoft PowerPoint 2007 XML", "pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation");
pptx.setInputFamily(DocumentFamily.PRESENTATION);
addFormat(pptx);
DocumentFormat odg = new DocumentFormat("OpenDocument Drawing", "odg", "application/vnd.oasis.opendocument.graphics");
odg.setInputFamily(DocumentFamily.DRAWING);
odg.setStoreProperties(DocumentFamily.DRAWING, Collections.singletonMap("FilterName", "draw8"));
addFormat(odg);
DocumentFormat svg = new DocumentFormat("Scalable Vector Graphics", "svg", "image/svg+xml");
svg.setStoreProperties(DocumentFamily.DRAWING, Collections.singletonMap("FilterName", "draw_svg_Export"));
addFormat(svg);
}
}

@ -0,0 +1,19 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.document;
public enum DocumentFamily {
TEXT, SPREADSHEET, PRESENTATION, DRAWING
}

@ -0,0 +1,99 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.document;
import java.util.HashMap;
import java.util.Map;
public class DocumentFormat {
private String name;
private String extension;
private String mediaType;
private DocumentFamily inputFamily;
private Map<String,?> loadProperties;
private Map<DocumentFamily,Map<String,?>> storePropertiesByFamily;
public DocumentFormat() {
// default
}
public DocumentFormat(String name, String extension, String mediaType) {
this.name = name;
this.extension = extension;
this.mediaType = mediaType;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getExtension() {
return extension;
}
public void setExtension(String extension) {
this.extension = extension;
}
public String getMediaType() {
return mediaType;
}
public void setMediaType(String mediaType) {
this.mediaType = mediaType;
}
public DocumentFamily getInputFamily() {
return inputFamily;
}
public void setInputFamily(DocumentFamily documentFamily) {
this.inputFamily = documentFamily;
}
public Map<String, ?> getLoadProperties() {
return loadProperties;
}
public void setLoadProperties(Map<String,?> loadProperties) {
this.loadProperties = loadProperties;
}
public Map<DocumentFamily, Map<String, ?>> getStorePropertiesByFamily() {
return storePropertiesByFamily;
}
public void setStorePropertiesByFamily(Map<DocumentFamily, Map<String,?>> storePropertiesByFamily) {
this.storePropertiesByFamily = storePropertiesByFamily;
}
public void setStoreProperties(DocumentFamily family, Map<String,?> storeProperties) {
if (storePropertiesByFamily == null) {
storePropertiesByFamily = new HashMap<DocumentFamily,Map<String,?>>();
}
storePropertiesByFamily.put(family, storeProperties);
}
public Map<String,?> getStoreProperties(DocumentFamily family) {
if (storePropertiesByFamily == null) {
return null;
}
return storePropertiesByFamily.get(family);
}
}

@ -0,0 +1,25 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.document;
import java.util.Set;
public interface DocumentFormatRegistry {
public DocumentFormat getFormatByExtension(String extension);
public DocumentFormat getFormatByMediaType(String mediaType);
public Set<DocumentFormat> getOutputFormats(DocumentFamily family);
}

@ -0,0 +1,73 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.document;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.io.IOUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class JsonDocumentFormatRegistry extends SimpleDocumentFormatRegistry {
public JsonDocumentFormatRegistry(InputStream input) throws JSONException, IOException {
readJsonArray(IOUtils.toString(input));
}
public JsonDocumentFormatRegistry(String source) throws JSONException {
readJsonArray(source);
}
private void readJsonArray(String source) throws JSONException {
JSONArray array = new JSONArray(source);
for (int i = 0; i < array.length(); i++) {
JSONObject jsonFormat = array.getJSONObject(i);
DocumentFormat format = new DocumentFormat();
format.setName(jsonFormat.getString("name"));
format.setExtension(jsonFormat.getString("extension"));
format.setMediaType(jsonFormat.getString("mediaType"));
if (jsonFormat.has("inputFamily")) {
format.setInputFamily(DocumentFamily.valueOf(jsonFormat.getString("inputFamily")));
}
if (jsonFormat.has("loadProperties")) {
format.setLoadProperties(toJavaMap(jsonFormat.getJSONObject("loadProperties")));
}
if (jsonFormat.has("storePropertiesByFamily")) {
JSONObject jsonStorePropertiesByFamily = jsonFormat.getJSONObject("storePropertiesByFamily");
for (String key : JSONObject.getNames(jsonStorePropertiesByFamily)) {
Map<String,?> storeProperties = toJavaMap(jsonStorePropertiesByFamily.getJSONObject(key));
format.setStoreProperties(DocumentFamily.valueOf(key), storeProperties);
}
}
addFormat(format);
}
}
private Map<String,?> toJavaMap(JSONObject jsonMap) throws JSONException {
Map<String,Object> map = new HashMap<String,Object>();
for (String key : JSONObject.getNames(jsonMap)) {
Object value = jsonMap.get(key);
if (value instanceof JSONObject) {
map.put(key, toJavaMap((JSONObject) value));
} else {
map.put(key, value);
}
}
return map;
}
}

@ -0,0 +1,65 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.document;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class SimpleDocumentFormatRegistry implements DocumentFormatRegistry {
private List<DocumentFormat> documentFormats = new ArrayList<DocumentFormat>();
public void addFormat(DocumentFormat documentFormat) {
documentFormats.add(documentFormat);
}
public DocumentFormat getFormatByExtension(String extension) {
if (extension == null) {
return null;
}
String lowerExtension = extension.toLowerCase();
//TODO keep a documentByExtension map instead
for (DocumentFormat format : documentFormats) {
if (format.getExtension().equals(lowerExtension)) {
return format;
}
}
return null;
}
public DocumentFormat getFormatByMediaType(String mediaType) {
if (mediaType == null) {
return null;
}
//TODO keep a documentByMediaType map instead
for (DocumentFormat format : documentFormats) {
if (format.getMediaType().equals(mediaType)) {
return format;
}
}
return null;
}
public Set<DocumentFormat> getOutputFormats(DocumentFamily family) {
Set<DocumentFormat> formats = new HashSet<DocumentFormat>();
for (DocumentFormat format : documentFormats) {
if (format.getStoreProperties(family) != null) {
formats.add(format);
}
}
return formats;
}
}

@ -0,0 +1,223 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.office;
import java.io.File;
import org.artofsolving.jodconverter.process.ProcessManager;
import org.artofsolving.jodconverter.process.PureJavaProcessManager;
import org.artofsolving.jodconverter.process.LinuxProcessManager;
import org.artofsolving.jodconverter.process.SigarProcessManager;
import org.artofsolving.jodconverter.util.PlatformUtils;
public class DefaultOfficeManagerConfiguration {
public static final long DEFAULT_RETRY_TIMEOUT = 120000L;
private File officeHome = OfficeUtils.getDefaultOfficeHome();
private OfficeConnectionProtocol connectionProtocol = OfficeConnectionProtocol.SOCKET;
private int[] portNumbers = new int[] { 2002 };
private String[] pipeNames = new String[] { "office" };
private String[] runAsArgs = null;
private File templateProfileDir = null;
private File workDir = new File(System.getProperty("java.io.tmpdir"));
private long taskQueueTimeout = 30000L; // 30 seconds
private long taskExecutionTimeout = 120000L; // 2 minutes
private int maxTasksPerProcess = 200;
private long retryTimeout = DEFAULT_RETRY_TIMEOUT;
private ProcessManager processManager = null; // lazily initialised
public DefaultOfficeManagerConfiguration setOfficeHome(String officeHome) throws NullPointerException, IllegalArgumentException {
checkArgumentNotNull("officeHome", officeHome);
return setOfficeHome(new File(officeHome));
}
public DefaultOfficeManagerConfiguration setOfficeHome(File officeHome) throws NullPointerException, IllegalArgumentException {
checkArgumentNotNull("officeHome", officeHome);
checkArgument("officeHome", officeHome.isDirectory(), "must exist and be a directory");
this.officeHome = officeHome;
return this;
}
public DefaultOfficeManagerConfiguration setConnectionProtocol(OfficeConnectionProtocol connectionProtocol) throws NullPointerException {
checkArgumentNotNull("connectionProtocol", connectionProtocol);
this.connectionProtocol = connectionProtocol;
return this;
}
public DefaultOfficeManagerConfiguration setPortNumber(int portNumber) {
this.portNumbers = new int[] { portNumber };
return this;
}
public DefaultOfficeManagerConfiguration setPortNumbers(int... portNumbers) throws NullPointerException, IllegalArgumentException {
checkArgumentNotNull("portNumbers", portNumbers);
checkArgument("portNumbers", portNumbers.length > 0, "must not be empty");
this.portNumbers = portNumbers;
return this;
}
public DefaultOfficeManagerConfiguration setPipeName(String pipeName) throws NullPointerException {
checkArgumentNotNull("pipeName", pipeName);
this.pipeNames = new String[] { pipeName };
return this;
}
public DefaultOfficeManagerConfiguration setPipeNames(String... pipeNames) throws NullPointerException, IllegalArgumentException {
checkArgumentNotNull("pipeNames", pipeNames);
checkArgument("pipeNames", pipeNames.length > 0, "must not be empty");
this.pipeNames = pipeNames;
return this;
}
public DefaultOfficeManagerConfiguration setRunAsArgs(String... runAsArgs) {
this.runAsArgs = runAsArgs;
return this;
}
public DefaultOfficeManagerConfiguration setTemplateProfileDir(File templateProfileDir) throws IllegalArgumentException {
if (templateProfileDir != null) {
checkArgument("templateProfileDir", templateProfileDir.isDirectory(), "must exist and be a directory");
}
this.templateProfileDir = templateProfileDir;
return this;
}
/**
* Sets the directory where temporary office profiles will be created.
* <p>
* Defaults to the system temporary directory as specified by the <code>java.io.tmpdir</code> system property.
*
* @param workDir
* @return
*/
public DefaultOfficeManagerConfiguration setWorkDir(File workDir) {
checkArgumentNotNull("workDir", workDir);
this.workDir = workDir;
return this;
}
public DefaultOfficeManagerConfiguration setTaskQueueTimeout(long taskQueueTimeout) {
this.taskQueueTimeout = taskQueueTimeout;
return this;
}
public DefaultOfficeManagerConfiguration setTaskExecutionTimeout(long taskExecutionTimeout) {
this.taskExecutionTimeout = taskExecutionTimeout;
return this;
}
public DefaultOfficeManagerConfiguration setMaxTasksPerProcess(int maxTasksPerProcess) {
this.maxTasksPerProcess = maxTasksPerProcess;
return this;
}
/**
* Provide a specific {@link ProcessManager} implementation
* <p>
* The default is to use {@link SigarProcessManager} if sigar.jar is
* available in the classpath, otherwise {@link LinuxProcessManager}
* on Linux and {@link PureJavaProcessManager} on other platforms.
*
* @param processManager
* @return
* @throws NullPointerException
*/
public DefaultOfficeManagerConfiguration setProcessManager(ProcessManager processManager) throws NullPointerException {
checkArgumentNotNull("processManager", processManager);
this.processManager = processManager;
return this;
}
/**
* Retry timeout set in milliseconds. Used for retrying office process calls.
* If not set, it defaults to 2 minutes
*
* @param retryTimeout in milliseconds
* @return
*/
public DefaultOfficeManagerConfiguration setRetryTimeout(long retryTimeout) {
this.retryTimeout = retryTimeout;
return this;
}
public OfficeManager buildOfficeManager() throws IllegalStateException {
if (officeHome == null) {
throw new IllegalStateException("officeHome not set and could not be auto-detected");
} else if (!officeHome.isDirectory()) {
throw new IllegalStateException("officeHome doesn't exist or is not a directory: " + officeHome);
} else if (!OfficeUtils.getOfficeExecutable(officeHome).isFile()) {
throw new IllegalStateException("invalid officeHome: it doesn't contain soffice.bin: " + officeHome);
}
if (templateProfileDir != null && !isValidProfileDir(templateProfileDir)) {
throw new IllegalStateException("templateProfileDir doesn't appear to contain a user profile: " + templateProfileDir);
}
if (!workDir.isDirectory()) {
throw new IllegalStateException("workDir doesn't exist or is not a directory: " + workDir);
}
if (processManager == null) {
processManager = findBestProcessManager();
}
int numInstances = connectionProtocol == OfficeConnectionProtocol.PIPE ? pipeNames.length : portNumbers.length;
UnoUrl[] unoUrls = new UnoUrl[numInstances];
for (int i = 0; i < numInstances; i++) {
unoUrls[i] = (connectionProtocol == OfficeConnectionProtocol.PIPE) ? UnoUrl.pipe(pipeNames[i]) : UnoUrl.socket(portNumbers[i]);
}
return new ProcessPoolOfficeManager(officeHome, unoUrls, runAsArgs, templateProfileDir, workDir, retryTimeout, taskQueueTimeout, taskExecutionTimeout, maxTasksPerProcess, processManager);
}
private ProcessManager findBestProcessManager() {
if (isSigarAvailable()) {
return new SigarProcessManager();
} else if (PlatformUtils.isLinux()) {
LinuxProcessManager processManager = new LinuxProcessManager();
if (runAsArgs != null) {
processManager.setRunAsArgs(runAsArgs);
}
return processManager;
} else {
// NOTE: UnixProcessManager can't be trusted to work on Solaris
// because of the 80-char limit on ps output there
return new PureJavaProcessManager();
}
}
private boolean isSigarAvailable() {
try {
Class.forName("org.hyperic.sigar.Sigar", false, getClass().getClassLoader());
return true;
} catch (ClassNotFoundException classNotFoundException) {
return false;
}
}
private void checkArgumentNotNull(String argName, Object argValue) throws NullPointerException {
if (argValue == null) {
throw new NullPointerException(argName + " must not be null");
}
}
private void checkArgument(String argName, boolean condition, String message) throws IllegalArgumentException {
if (!condition) {
throw new IllegalArgumentException(argName + " " + message);
}
}
private boolean isValidProfileDir(File profileDir) {
return new File(profileDir, "user").isDirectory();
}
}

@ -0,0 +1,86 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.office;
import java.net.ConnectException;
/**
* {@link OfficeManager} implementation that connects to an external Office process.
* <p>
* The external Office process needs to be started manually, e.g. from the command line with
*
* <pre>
* soffice -accept="socket,host=127.0.0.1,port=2002;urp;"
* </pre>
* <p>
* Since this implementation does not manage the Office process, it does not support auto-restarting the process if it exits unexpectedly.
* <p>
* It will however auto-reconnect to the external process if the latter is manually restarted.
* <p>
* This {@link OfficeManager} implementation basically provides the same behaviour as JODConverter 2.x, including using <em>synchronized</em> blocks for serialising office
* operations.
*/
class ExternalOfficeManager implements OfficeManager {
private final OfficeConnection connection;
private final boolean connectOnStart;
/**
* @param unoUrl
* @param connectOnStart
* should a connection be attempted on {@link #start()}? Default is <em>true</em>. If <em>false</em>, a connection will only be attempted the first time an
* {@link OfficeTask} is executed.
*/
public ExternalOfficeManager(UnoUrl unoUrl, boolean connectOnStart) {
connection = new OfficeConnection(unoUrl);
this.connectOnStart = connectOnStart;
}
public void start() throws OfficeException {
if (connectOnStart) {
synchronized (connection) {
connect();
}
}
}
public void stop() {
synchronized (connection) {
if (connection.isConnected()) {
connection.disconnect();
}
}
}
public void execute(OfficeTask task) throws OfficeException {
synchronized (connection) {
if (!connection.isConnected()) {
connect();
}
task.execute(connection);
}
}
private void connect() {
try {
connection.connect();
} catch (ConnectException connectException) {
throw new OfficeException("could not connect to external office process", connectException);
}
}
public boolean isRunning() {
return connection.isConnected();
}
}

@ -0,0 +1,47 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.office;
public class ExternalOfficeManagerConfiguration {
private OfficeConnectionProtocol connectionProtocol = OfficeConnectionProtocol.SOCKET;
private int portNumber = 2002;
private String pipeName = "office";
private boolean connectOnStart = true;
public ExternalOfficeManagerConfiguration setConnectionProtocol(OfficeConnectionProtocol connectionProtocol) {
this.connectionProtocol = connectionProtocol;
return this;
}
public ExternalOfficeManagerConfiguration setPortNumber(int portNumber) {
this.portNumber = portNumber;
return this;
}
public ExternalOfficeManagerConfiguration setPipeName(String pipeName) {
this.pipeName = pipeName;
return this;
}
public ExternalOfficeManagerConfiguration setConnectOnStart(boolean connectOnStart) {
this.connectOnStart = connectOnStart;
return this;
}
public OfficeManager buildOfficeManager() {
UnoUrl unoUrl = connectionProtocol == OfficeConnectionProtocol.SOCKET ? UnoUrl.socket(portNumber) : UnoUrl.pipe(pipeName);
return new ExternalOfficeManager(unoUrl, connectOnStart);
}
}

@ -0,0 +1,176 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.office;
import java.net.ConnectException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sun.star.frame.XDesktop;
import com.sun.star.lang.DisposedException;
class ManagedOfficeProcess {
private static final Integer EXIT_CODE_NEW_INSTALLATION = Integer.valueOf(81);
private final ManagedOfficeProcessSettings settings;
private final OfficeProcess process;
private final OfficeConnection connection;
private ExecutorService executor = Executors.newSingleThreadExecutor(new NamedThreadFactory("OfficeProcessThread"));
private final Logger logger = Logger.getLogger(getClass().getName());
public ManagedOfficeProcess(ManagedOfficeProcessSettings settings) throws OfficeException {
this.settings = settings;
process = new OfficeProcess(settings.getOfficeHome(), settings.getUnoUrl(), settings.getRunAsArgs(), settings.getTemplateProfileDir(), settings.getWorkDir(), settings
.getProcessManager());
connection = new OfficeConnection(settings.getUnoUrl());
}
public OfficeConnection getConnection() {
return connection;
}
public void startAndWait() throws OfficeException {
Future<?> future = executor.submit(new Runnable() {
public void run() {
doStartProcessAndConnect();
}
});
try {
future.get();
} catch (Exception exception) {
throw new OfficeException("failed to start and connect", exception);
}
}
public void stopAndWait() throws OfficeException {
Future<?> future = executor.submit(new Runnable() {
public void run() {
doStopProcess();
}
});
try {
future.get();
} catch (Exception exception) {
throw new OfficeException("failed to start and connect", exception);
}
}
public void restartAndWait() {
Future<?> future = executor.submit(new Runnable() {
public void run() {
doStopProcess();
doStartProcessAndConnect();
}
});
try {
future.get();
} catch (Exception exception) {
throw new OfficeException("failed to restart", exception);
}
}
public void restartDueToTaskTimeout() {
executor.execute(new Runnable() {
public void run() {
doTerminateProcess();
// will cause unexpected disconnection and subsequent restart
}
});
}
public void restartDueToLostConnection() {
executor.execute(new Runnable() {
public void run() {
try {
doEnsureProcessExited();
doStartProcessAndConnect();
} catch (OfficeException officeException) {
logger.log(Level.SEVERE, "could not restart process", officeException);
}
}
});
}
private void doStartProcessAndConnect() throws OfficeException {
try {
process.start();
new Retryable() {
protected void attempt() throws TemporaryException, Exception {
try {
connection.connect();
} catch (ConnectException connectException) {
Integer exitCode = process.getExitCode();
if (exitCode == null) {
// process is running; retry later
throw new TemporaryException(connectException);
} else if (exitCode.equals(EXIT_CODE_NEW_INSTALLATION)) {
// restart and retry later
// see http://code.google.com/p/jodconverter/issues/detail?id=84
logger.log(Level.WARNING, "office process died with exit code 81; restarting it");
process.start(true);
throw new TemporaryException(connectException);
} else {
throw new OfficeException("office process died with exit code " + exitCode);
}
}
}
}.execute(settings.getRetryInterval(), settings.getRetryTimeout());
} catch (Exception exception) {
throw new OfficeException("could not establish connection", exception);
}
}
private void doStopProcess() {
try {
XDesktop desktop = OfficeUtils.cast(XDesktop.class, connection.getService(OfficeUtils.SERVICE_DESKTOP));
desktop.terminate();
} catch (DisposedException disposedException) {
// expected
} catch (Exception exception) {
// in case we can't get hold of the desktop
doTerminateProcess();
}
doEnsureProcessExited();
}
private void doEnsureProcessExited() throws OfficeException {
try {
int exitCode = process.getExitCode(settings.getRetryInterval(), settings.getRetryTimeout());
logger.info("process exited with code " + exitCode);
} catch (RetryTimeoutException retryTimeoutException) {
doTerminateProcess();
}
process.deleteProfileDir();
}
private void doTerminateProcess() throws OfficeException {
try {
int exitCode = process.forciblyTerminate(settings.getRetryInterval(), settings.getRetryTimeout());
logger.info("process forcibly terminated with code " + exitCode);
} catch (Exception exception) {
throw new OfficeException("could not terminate process", exception);
}
}
boolean isConnected() {
return connection.isConnected();
}
}

@ -0,0 +1,97 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.office;
import java.io.File;
import org.artofsolving.jodconverter.process.ProcessManager;
import org.artofsolving.jodconverter.process.PureJavaProcessManager;
class ManagedOfficeProcessSettings {
public static final long DEFAULT_RETRY_INTERVAL = 250L;
private final UnoUrl unoUrl;
private File officeHome = OfficeUtils.getDefaultOfficeHome();
private String[] runAsArgs;
private File templateProfileDir;
private File workDir = new File(System.getProperty("java.io.tmpdir"));
private ProcessManager processManager = new PureJavaProcessManager();
private long retryTimeout = DefaultOfficeManagerConfiguration.DEFAULT_RETRY_TIMEOUT;
private long retryInterval = DEFAULT_RETRY_INTERVAL;
public ManagedOfficeProcessSettings(UnoUrl unoUrl) {
this.unoUrl = unoUrl;
}
public UnoUrl getUnoUrl() {
return unoUrl;
}
public File getOfficeHome() {
return officeHome;
}
public void setOfficeHome(File officeHome) {
this.officeHome = officeHome;
}
public String[] getRunAsArgs() {
return runAsArgs;
}
public void setRunAsArgs(String[] runAsArgs) {
this.runAsArgs = runAsArgs;
}
public File getTemplateProfileDir() {
return templateProfileDir;
}
public void setTemplateProfileDir(File templateProfileDir) {
this.templateProfileDir = templateProfileDir;
}
public File getWorkDir() {
return workDir;
}
public void setWorkDir(File workDir) {
this.workDir = workDir;
}
public ProcessManager getProcessManager() {
return processManager;
}
public void setProcessManager(ProcessManager processManager) {
this.processManager = processManager;
}
public long getRetryTimeout() {
return retryTimeout;
}
public void setRetryTimeout(long retryTimeout) {
this.retryTimeout = retryTimeout;
}
public long getRetryInterval() {
return retryInterval;
}
public void setRetryInterval(long retryInterval) {
this.retryInterval = retryInterval;
}
}

@ -0,0 +1,43 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.office;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
/**
* A {@link ThreadFactory} that allows for custom thread names
*/
class NamedThreadFactory implements ThreadFactory {
private static final AtomicInteger threadIndex = new AtomicInteger(0);
private final String baseName;
private final boolean daemon;
public NamedThreadFactory(String baseName) {
this(baseName, true);
}
public NamedThreadFactory(String baseName, boolean daemon) {
this.baseName = baseName;
this.daemon = daemon;
}
public Thread newThread(Runnable runnable) {
Thread thread = new Thread(runnable, baseName + "-" + threadIndex.getAndIncrement());
thread.setDaemon(daemon);
return thread;
}
}

@ -0,0 +1,117 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.office;
import java.net.ConnectException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
import com.sun.star.beans.XPropertySet;
import com.sun.star.bridge.XBridge;
import com.sun.star.bridge.XBridgeFactory;
import com.sun.star.comp.helper.Bootstrap;
import com.sun.star.connection.NoConnectException;
import com.sun.star.connection.XConnection;
import com.sun.star.connection.XConnector;
import com.sun.star.lang.EventObject;
import com.sun.star.lang.XComponent;
import com.sun.star.lang.XEventListener;
import com.sun.star.lang.XMultiComponentFactory;
import com.sun.star.uno.XComponentContext;
class OfficeConnection implements OfficeContext {
private static AtomicInteger bridgeIndex = new AtomicInteger();
private final UnoUrl unoUrl;
private XComponent bridgeComponent;
private XMultiComponentFactory serviceManager;
private XComponentContext componentContext;
private final List<OfficeConnectionEventListener> connectionEventListeners = new ArrayList<OfficeConnectionEventListener>();
private volatile boolean connected = false;
private XEventListener bridgeListener = new XEventListener() {
public void disposing(EventObject event) {
if (connected) {
connected = false;
logger.info(String.format("disconnected: '%s'", unoUrl));
OfficeConnectionEvent connectionEvent = new OfficeConnectionEvent(OfficeConnection.this);
for (OfficeConnectionEventListener listener : connectionEventListeners) {
listener.disconnected(connectionEvent);
}
}
// else we tried to connect to a server that doesn't speak URP
}
};
private final Logger logger = Logger.getLogger(getClass().getName());
public OfficeConnection(UnoUrl unoUrl) {
this.unoUrl = unoUrl;
}
public void addConnectionEventListener(OfficeConnectionEventListener connectionEventListener) {
connectionEventListeners.add(connectionEventListener);
}
public void connect() throws ConnectException {
logger.fine(String.format("connecting with connectString '%s'", unoUrl));
try {
XComponentContext localContext = Bootstrap.createInitialComponentContext(null);
XMultiComponentFactory localServiceManager = localContext.getServiceManager();
XConnector connector = OfficeUtils.cast(XConnector.class, localServiceManager.createInstanceWithContext("com.sun.star.connection.Connector", localContext));
XConnection connection = connector.connect(unoUrl.getConnectString());
XBridgeFactory bridgeFactory = OfficeUtils.cast(XBridgeFactory.class, localServiceManager.createInstanceWithContext("com.sun.star.bridge.BridgeFactory", localContext));
String bridgeName = "jodconverter_" + bridgeIndex.getAndIncrement();
XBridge bridge = bridgeFactory.createBridge(bridgeName, "urp", connection, null);
bridgeComponent = OfficeUtils.cast(XComponent.class, bridge);
bridgeComponent.addEventListener(bridgeListener);
serviceManager = OfficeUtils.cast(XMultiComponentFactory.class, bridge.getInstance("StarOffice.ServiceManager"));
XPropertySet properties = OfficeUtils.cast(XPropertySet.class, serviceManager);
componentContext = OfficeUtils.cast(XComponentContext.class, properties.getPropertyValue("DefaultContext"));
connected = true;
logger.info(String.format("connected: '%s'", unoUrl));
OfficeConnectionEvent connectionEvent = new OfficeConnectionEvent(this);
for (OfficeConnectionEventListener listener : connectionEventListeners) {
listener.connected(connectionEvent);
}
} catch (NoConnectException connectException) {
throw new ConnectException(String.format("connection failed: '%s'; %s", unoUrl, connectException.getMessage()));
} catch (Exception exception) {
throw new OfficeException("connection failed: "+ unoUrl, exception);
}
}
public boolean isConnected() {
return connected;
}
public synchronized void disconnect() {
logger.fine(String.format("disconnecting: '%s'", unoUrl));
bridgeComponent.dispose();
}
public Object getService(String serviceName) {
try {
return serviceManager.createInstanceWithContext(serviceName, componentContext);
} catch (Exception exception) {
throw new OfficeException(String.format("failed to obtain service '%s'", serviceName), exception);
}
}
}

@ -0,0 +1,25 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.office;
import java.util.EventObject;
class OfficeConnectionEvent extends EventObject {
private static final long serialVersionUID = 2060652797570876077L;
public OfficeConnectionEvent(OfficeConnection source) {
super(source);
}
}

@ -0,0 +1,23 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.office;
import java.util.EventListener;
interface OfficeConnectionEventListener extends EventListener {
void connected(OfficeConnectionEvent event);
void disconnected(OfficeConnectionEvent event);
}

@ -0,0 +1,15 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.office;
public enum OfficeConnectionProtocol { PIPE, SOCKET }

@ -0,0 +1,19 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.office;
public interface OfficeContext {
Object getService(String serviceName);
}

@ -0,0 +1,26 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.office;
public class OfficeException extends RuntimeException {
private static final long serialVersionUID = 1L;
public OfficeException(String message) {
super(message);
}
public OfficeException(String message, Throwable cause) {
super(message, cause);
}
}

@ -0,0 +1,30 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.office;
/**
* An OfficeManager knows how to execute {@link OfficeTask}s.
* <p>
* An OfficeManager implementation will typically manage one or more
* {@link OfficeConnection}s.
*/
public interface OfficeManager {
void execute(OfficeTask task) throws OfficeException;
void start() throws OfficeException;
void stop() throws OfficeException;
boolean isRunning();
}

@ -0,0 +1,209 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.office;
import static org.artofsolving.jodconverter.process.ProcessManager.PID_NOT_FOUND;
import static org.artofsolving.jodconverter.process.ProcessManager.PID_UNKNOWN;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import org.apache.commons.io.FileUtils;
import org.artofsolving.jodconverter.process.ProcessManager;
import org.artofsolving.jodconverter.process.ProcessQuery;
import org.artofsolving.jodconverter.util.PlatformUtils;
class OfficeProcess {
private final File officeHome;
private final UnoUrl unoUrl;
private final String[] runAsArgs;
private final File templateProfileDir;
private final File instanceProfileDir;
private final ProcessManager processManager;
private Process process;
private long pid = PID_UNKNOWN;
private final Logger logger = Logger.getLogger(getClass().getName());
public OfficeProcess(File officeHome, UnoUrl unoUrl, String[] runAsArgs, File templateProfileDir, File workDir, ProcessManager processManager) {
this.officeHome = officeHome;
this.unoUrl = unoUrl;
this.runAsArgs = runAsArgs;
this.templateProfileDir = templateProfileDir;
this.instanceProfileDir = getInstanceProfileDir(workDir, unoUrl);
this.processManager = processManager;
}
public void start() throws IOException {
start(false);
}
public void start(boolean restart) throws IOException {
ProcessQuery processQuery = new ProcessQuery("soffice.bin", unoUrl.getAcceptString());
long existingPid = processManager.findPid(processQuery);
if (!(existingPid == PID_NOT_FOUND || existingPid == PID_UNKNOWN)) {
throw new IllegalStateException(String.format("a process with acceptString '%s' is already running; pid %d",
unoUrl.getAcceptString(), existingPid));
}
if (!restart) {
prepareInstanceProfileDir();
}
List<String> command = new ArrayList<String>();
File executable = OfficeUtils.getOfficeExecutable(officeHome);
if (runAsArgs != null) {
command.addAll(Arrays.asList(runAsArgs));
}
command.add(executable.getAbsolutePath());
command.add("-accept=" + unoUrl.getAcceptString() + ";urp;");
command.add("-env:UserInstallation=" + OfficeUtils.toUrl(instanceProfileDir));
command.add("-headless");
command.add("-nocrashreport");
command.add("-nodefault");
command.add("-nofirststartwizard");
command.add("-nolockcheck");
command.add("-nologo");
command.add("-norestore");
ProcessBuilder processBuilder = new ProcessBuilder(command);
if (PlatformUtils.isWindows()) {
addBasisAndUrePaths(processBuilder);
}
logger.info(String.format("starting process with acceptString '%s' and profileDir '%s'", unoUrl, instanceProfileDir));
process = processBuilder.start();
pid = processManager.findPid(processQuery);
if (pid == PID_NOT_FOUND) {
throw new IllegalStateException(String.format("process with acceptString '%s' started but its pid could not be found",
unoUrl.getAcceptString()));
}
logger.info("started process" + (pid != PID_UNKNOWN ? "; pid = " + pid : ""));
}
private File getInstanceProfileDir(File workDir, UnoUrl unoUrl) {
String dirName = ".jodconverter_" + unoUrl.getAcceptString().replace(',', '_').replace('=', '-');
return new File(workDir, dirName);
}
private void prepareInstanceProfileDir() throws OfficeException {
if (instanceProfileDir.exists()) {
logger.warning(String.format("profile dir '%s' already exists; deleting", instanceProfileDir));
deleteProfileDir();
}
if (templateProfileDir != null) {
try {
FileUtils.copyDirectory(templateProfileDir, instanceProfileDir);
} catch (IOException ioException) {
throw new OfficeException("failed to create profileDir", ioException);
}
}
}
public void deleteProfileDir() {
if (instanceProfileDir != null) {
try {
FileUtils.deleteDirectory(instanceProfileDir);
} catch (IOException ioException) {
File oldProfileDir = new File(instanceProfileDir.getParentFile(), instanceProfileDir.getName() + ".old." + System.currentTimeMillis());
if (instanceProfileDir.renameTo(oldProfileDir)) {
logger.warning("could not delete profileDir: " + ioException.getMessage() + "; renamed it to " + oldProfileDir);
} else {
logger.severe("could not delete profileDir: " + ioException.getMessage());
}
}
}
}
private void addBasisAndUrePaths(ProcessBuilder processBuilder) throws IOException {
// see http://wiki.services.openoffice.org/wiki/ODF_Toolkit/Efforts/Three-Layer_OOo
File basisLink = new File(officeHome, "basis-link");
if (!basisLink.isFile()) {
logger.fine("no %OFFICE_HOME%/basis-link found; assuming it's OOo 2.x and we don't need to append URE and Basic paths");
return;
}
String basisLinkText = FileUtils.readFileToString(basisLink).trim();
File basisHome = new File(officeHome, basisLinkText);
File basisProgram = new File(basisHome, "program");
File ureLink = new File(basisHome, "ure-link");
String ureLinkText = FileUtils.readFileToString(ureLink).trim();
File ureHome = new File(basisHome, ureLinkText);
File ureBin = new File(ureHome, "bin");
Map<String,String> environment = processBuilder.environment();
// Windows environment variables are case insensitive but Java maps are not :-/
// so let's make sure we modify the existing key
String pathKey = "PATH";
for (String key : environment.keySet()) {
if ("PATH".equalsIgnoreCase(key)) {
pathKey = key;
}
}
String path = environment.get(pathKey) + ";" + ureBin.getAbsolutePath() + ";" + basisProgram.getAbsolutePath();
logger.fine(String.format("setting %s to \"%s\"", pathKey, path));
environment.put(pathKey, path);
}
public boolean isRunning() {
if (process == null) {
return false;
}
return getExitCode() == null;
}
private class ExitCodeRetryable extends Retryable {
private int exitCode;
protected void attempt() throws TemporaryException, Exception {
try {
exitCode = process.exitValue();
} catch (IllegalThreadStateException illegalThreadStateException) {
throw new TemporaryException(illegalThreadStateException);
}
}
public int getExitCode() {
return exitCode;
}
}
public Integer getExitCode() {
try {
return process.exitValue();
} catch (IllegalThreadStateException exception) {
return null;
}
}
public int getExitCode(long retryInterval, long retryTimeout) throws RetryTimeoutException {
try {
ExitCodeRetryable retryable = new ExitCodeRetryable();
retryable.execute(retryInterval, retryTimeout);
return retryable.getExitCode();
} catch (RetryTimeoutException retryTimeoutException) {
throw retryTimeoutException;
} catch (Exception exception) {
throw new OfficeException("could not get process exit code", exception);
}
}
public int forciblyTerminate(long retryInterval, long retryTimeout) throws IOException, RetryTimeoutException {
logger.info(String.format("trying to forcibly terminate process: '" + unoUrl + "'" + (pid != PID_UNKNOWN ? " (pid " + pid + ")" : "")));
processManager.kill(process, pid);
return getExitCode(retryInterval, retryTimeout);
}
}

@ -0,0 +1,19 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.office;
public interface OfficeTask {
void execute(OfficeContext context) throws OfficeException;
}

@ -0,0 +1,183 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.office;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import org.artofsolving.jodconverter.util.PlatformUtils;
import com.sun.star.beans.PropertyValue;
import com.sun.star.uno.UnoRuntime;
public class OfficeUtils {
public static final String SERVICE_DESKTOP = "com.sun.star.frame.Desktop";
public static final String OFFICE_HOME_KEY = "office.home";
public static final String DEFAULT_OFFICE_HOME_VALUE = "default";
private OfficeUtils() {
throw new AssertionError("utility class must not be instantiated");
}
public static <T> T cast(Class<T> type, Object object) {
return (T) UnoRuntime.queryInterface(type, object);
}
public static PropertyValue property(String name, Object value) {
PropertyValue propertyValue = new PropertyValue();
propertyValue.Name = name;
propertyValue.Value = value;
return propertyValue;
}
@SuppressWarnings("unchecked")
public static PropertyValue[] toUnoProperties(Map<String,?> properties) {
PropertyValue[] propertyValues = new PropertyValue[properties.size()];
int i = 0;
for (Map.Entry<String,?> entry : properties.entrySet()) {
Object value = entry.getValue();
if (value instanceof Map) {
Map<String,Object> subProperties = (Map<String,Object>) value;
value = toUnoProperties(subProperties);
}
propertyValues[i++] = property((String) entry.getKey(), value);
}
return propertyValues;
}
public static String toUrl(File file) {
String path = file.toURI().getRawPath();
String url = path.startsWith("//") ? "file:" + path : "file://" + path;
return url.endsWith("/") ? url.substring(0, url.length() - 1) : url;
}
public static File getDefaultOfficeHome() {
Properties properties = new Properties();
String customizedConfigPath = getCustomizedConfigPath();
try {
BufferedReader bufferedReader = new BufferedReader(new FileReader(customizedConfigPath));
properties.load(bufferedReader);
restorePropertiesFromEnvFormat(properties);
} catch (Exception e) {}
String officeHome = properties.getProperty(OFFICE_HOME_KEY);
if (officeHome != null && !DEFAULT_OFFICE_HOME_VALUE.equals(officeHome)) {
return new File(officeHome);
}
if (PlatformUtils.isWindows()) {
// %ProgramFiles(x86)% on 64-bit machines; %ProgramFiles% on 32-bit ones
String homePath = OfficeUtils.getHomePath();
String programFiles = System.getenv("ProgramFiles(x86)");
if (programFiles == null) {
programFiles = System.getenv("ProgramFiles");
}
return findOfficeHome(
programFiles + File.separator + "OpenOffice 4",
programFiles + File.separator + "LibreOffice 4",
homePath + File.separator + "office"
);
} else if (PlatformUtils.isMac()) {
return findOfficeHome(
"/Applications/OpenOffice.org.app/Contents",
"/Applications/OpenOffice.app/Contents",
"/Applications/LibreOffice.app/Contents"
);
} else {
// Linux or other *nix variants
return findOfficeHome(
"/opt/openoffice.org3",
"/opt/openoffice",
"/opt/libreoffice",
"/opt/openoffice4",
"/usr/lib/openoffice",
"/usr/lib/libreoffice"
);
}
}
private static File findOfficeHome(String... knownPaths) {
for (String path : knownPaths) {
File home = new File(path);
if (getOfficeExecutable(home).isFile()) {
return home;
}
}
return null;
}
public static File getOfficeExecutable(File officeHome) {
if (PlatformUtils.isMac()) {
return new File(officeHome, "MacOS/soffice");
} else {
return new File(officeHome, "program/soffice.bin");
}
}
public static String getHomePath() {
String userDir = System.getenv("KKFILEVIEW_BIN_FOLDER");
if (userDir == null) {
userDir = System.getProperty("user.dir");
}
if (userDir.endsWith("bin")) {
userDir = userDir.substring(0, userDir.length() - 4);
} else {
String separator = File.separator;
if (userDir.contains("jodconverter-web")) {
userDir = userDir + separator + "src" + separator + "main";
} else {
userDir = userDir + separator + "jodconverter-web" + separator + "src" + separator + "main";
}
}
return userDir;
}
public static String getCustomizedConfigPath() {
String homePath = OfficeUtils.getHomePath();
String separator = java.io.File.separator;
String configFilePath = homePath + separator + "config" + separator + "application.properties";
return configFilePath;
}
/**
* SpringBoot application.properties
* @param properties
*/
public synchronized static void restorePropertiesFromEnvFormat(Properties properties) {
Iterator<Map.Entry<Object, Object>> iterator = properties.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<Object, Object> entry = iterator.next();
String key = entry.getKey().toString();
String value = entry.getValue().toString();
if (value.trim().startsWith("${") && value.trim().endsWith("}")) {
int beginIndex = value.indexOf(":");
if (beginIndex < 0) {
beginIndex = value.length() - 1;
}
int endIndex = value.length() - 1;
String envKey = value.substring(2, beginIndex);
String envValue = System.getenv(envKey);
if (envValue == null || "".equals(envValue.trim())) {
value = value.substring(beginIndex + 1, endIndex);
} else {
value = envValue;
}
properties.setProperty(key, value);
}
}
}
}

@ -0,0 +1,110 @@
//
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.office;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;
class PooledOfficeManager implements OfficeManager {
private final PooledOfficeManagerSettings settings;
private final ManagedOfficeProcess managedOfficeProcess;
private final SuspendableThreadPoolExecutor taskExecutor;
private volatile boolean stopping = false;
private int taskCount;
private Future<?> currentTask;
private final Logger logger = Logger.getLogger(getClass().getName());
private OfficeConnectionEventListener connectionEventListener = new OfficeConnectionEventListener() {
public void connected(OfficeConnectionEvent event) {
taskCount = 0;
taskExecutor.setAvailable(true);
}
public void disconnected(OfficeConnectionEvent event) {
taskExecutor.setAvailable(false);
if (stopping) {
// expected
stopping = false;
} else {
logger.warning("connection lost unexpectedly; attempting restart");
if (currentTask != null) {
currentTask.cancel(true);
}
managedOfficeProcess.restartDueToLostConnection();
}
}
};
public PooledOfficeManager(UnoUrl unoUrl) {
this(new PooledOfficeManagerSettings(unoUrl));
}
public PooledOfficeManager(PooledOfficeManagerSettings settings) {
this.settings = settings;
managedOfficeProcess = new ManagedOfficeProcess(settings);
managedOfficeProcess.getConnection().addConnectionEventListener(connectionEventListener);
taskExecutor = new SuspendableThreadPoolExecutor(new NamedThreadFactory("OfficeTaskThread"));
}
public void execute(final OfficeTask task) throws OfficeException {
Future<?> futureTask = taskExecutor.submit(new Runnable() {
public void run() {
if (settings.getMaxTasksPerProcess() > 0 && ++taskCount == settings.getMaxTasksPerProcess() + 1) {
logger.info(String.format("reached limit of %d maxTasksPerProcess: restarting", settings.getMaxTasksPerProcess()));
taskExecutor.setAvailable(false);
stopping = true;
managedOfficeProcess.restartAndWait();
//FIXME taskCount will be 0 rather than 1 at this point
}
task.execute(managedOfficeProcess.getConnection());
}
});
currentTask = futureTask;
try {
futureTask.get(settings.getTaskExecutionTimeout(), TimeUnit.MILLISECONDS);
} catch (TimeoutException timeoutException) {
managedOfficeProcess.restartDueToTaskTimeout();
throw new OfficeException("task did not complete within timeout", timeoutException);
} catch (ExecutionException executionException) {
if (executionException.getCause() instanceof OfficeException) {
throw (OfficeException) executionException.getCause();
} else {
throw new OfficeException("task failed", executionException.getCause());
}
} catch (Exception exception) {
throw new OfficeException("task failed", exception);
}
}
public void start() throws OfficeException {
managedOfficeProcess.startAndWait();
}
public void stop() throws OfficeException {
taskExecutor.setAvailable(false);
stopping = true;
taskExecutor.shutdownNow();
managedOfficeProcess.stopAndWait();
}
public boolean isRunning() {
return managedOfficeProcess.isConnected();
}
}

@ -0,0 +1,43 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.office;
class PooledOfficeManagerSettings extends ManagedOfficeProcessSettings {
public static final long DEFAULT_TASK_EXECUTION_TIMEOUT = 120000L;
public static final int DEFAULT_MAX_TASKS_PER_PROCESS = 200;
private long taskExecutionTimeout = DEFAULT_TASK_EXECUTION_TIMEOUT;
private int maxTasksPerProcess = DEFAULT_MAX_TASKS_PER_PROCESS;
public PooledOfficeManagerSettings(UnoUrl unoUrl) {
super(unoUrl);
}
public long getTaskExecutionTimeout() {
return taskExecutionTimeout;
}
public void setTaskExecutionTimeout(long taskExecutionTimeout) {
this.taskExecutionTimeout = taskExecutionTimeout;
}
public int getMaxTasksPerProcess() {
return maxTasksPerProcess;
}
public void setMaxTasksPerProcess(int maxTasksPerProcess) {
this.maxTasksPerProcess = maxTasksPerProcess;
}
}

@ -0,0 +1,110 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.office;
import java.io.File;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import org.artofsolving.jodconverter.process.ProcessManager;
class ProcessPoolOfficeManager implements OfficeManager {
private final BlockingQueue<PooledOfficeManager> pool;
private final PooledOfficeManager[] pooledManagers;
private final long taskQueueTimeout;
private volatile boolean running = false;
private final Logger logger = Logger.getLogger(ProcessPoolOfficeManager.class.getName());
public ProcessPoolOfficeManager(File officeHome, UnoUrl[] unoUrls, String[] runAsArgs, File templateProfileDir, File workDir,
long retryTimeout, long taskQueueTimeout, long taskExecutionTimeout, int maxTasksPerProcess,
ProcessManager processManager) {
this.taskQueueTimeout = taskQueueTimeout;
pool = new ArrayBlockingQueue<PooledOfficeManager>(unoUrls.length);
pooledManagers = new PooledOfficeManager[unoUrls.length];
for (int i = 0; i < unoUrls.length; i++) {
PooledOfficeManagerSettings settings = new PooledOfficeManagerSettings(unoUrls[i]);
settings.setRunAsArgs(runAsArgs);
settings.setTemplateProfileDir(templateProfileDir);
settings.setWorkDir(workDir);
settings.setOfficeHome(officeHome);
settings.setRetryTimeout(retryTimeout);
settings.setTaskExecutionTimeout(taskExecutionTimeout);
settings.setMaxTasksPerProcess(maxTasksPerProcess);
settings.setProcessManager(processManager);
pooledManagers[i] = new PooledOfficeManager(settings);
}
logger.info("ProcessManager implementation is " + processManager.getClass().getSimpleName());
}
public synchronized void start() throws OfficeException {
for (int i = 0; i < pooledManagers.length; i++) {
pooledManagers[i].start();
releaseManager(pooledManagers[i]);
}
running = true;
}
public void execute(OfficeTask task) throws IllegalStateException, OfficeException {
if (!running) {
throw new IllegalStateException("this OfficeManager is currently stopped");
}
PooledOfficeManager manager = null;
try {
manager = acquireManager();
if (manager == null) {
throw new OfficeException("no office manager available");
}
manager.execute(task);
} finally {
if (manager != null) {
releaseManager(manager);
}
}
}
public synchronized void stop() throws OfficeException {
running = false;
logger.info("stopping");
pool.clear();
for (int i = 0; i < pooledManagers.length; i++) {
pooledManagers[i].stop();
}
logger.info("stopped");
}
private PooledOfficeManager acquireManager() {
try {
return pool.poll(taskQueueTimeout, TimeUnit.MILLISECONDS);
} catch (InterruptedException interruptedException) {
throw new OfficeException("interrupted", interruptedException);
}
}
private void releaseManager(PooledOfficeManager manager) {
try {
pool.put(manager);
} catch (InterruptedException interruptedException) {
throw new OfficeException("interrupted", interruptedException);
}
}
public boolean isRunning() {
return running;
}
}

@ -0,0 +1,23 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.office;
class RetryTimeoutException extends Exception {
private static final long serialVersionUID = -3704437769955257514L;
public RetryTimeoutException(Throwable cause) {
super(cause);
}
}

@ -0,0 +1,55 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.office;
abstract class Retryable {
/**
* @throws TemporaryException for an error condition that can be temporary - i.e. retrying later could be successful
* @throws Exception for all other error conditions
*/
protected abstract void attempt() throws TemporaryException, Exception;
public void execute(long interval, long timeout) throws RetryTimeoutException, Exception {
execute(0L, interval, timeout);
}
public void execute(long delay, long interval, long timeout) throws RetryTimeoutException, Exception {
long start = System.currentTimeMillis();
if (delay > 0L) {
sleep(delay);
}
while (true) {
try {
attempt();
return;
} catch (TemporaryException temporaryException) {
if (System.currentTimeMillis() - start < timeout) {
sleep(interval);
// continue
} else {
throw new RetryTimeoutException(temporaryException.getCause());
}
}
}
}
private void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException interruptedException) {
// continue
}
}
}

@ -0,0 +1,59 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.office;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
class SuspendableThreadPoolExecutor extends ThreadPoolExecutor {
private boolean available = false;
private ReentrantLock suspendLock = new ReentrantLock();
private Condition availableCondition = suspendLock.newCondition();
public SuspendableThreadPoolExecutor(ThreadFactory threadFactory) {
super(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory);
}
@Override
protected void beforeExecute(Thread thread, Runnable task) {
super.beforeExecute(thread, task);
suspendLock.lock();
try {
while (!available) {
availableCondition.await();
}
} catch (InterruptedException interruptedException) {
thread.interrupt();
} finally {
suspendLock.unlock();
}
}
public void setAvailable(boolean available) {
suspendLock.lock();
try {
this.available = available;
if (available) {
availableCondition.signalAll();
}
} finally {
suspendLock.unlock();
}
}
}

@ -0,0 +1,32 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.office;
import java.math.BigDecimal;
/**
* Represents an error condition that can be temporary, i.e. that could go
* away by simply retrying the same operation after an interval.
*/
class TemporaryException extends Exception {
private static final long serialVersionUID = 7237380113208327295L;
public TemporaryException(Throwable cause) {
super(cause);
}
public static void main(String[] args) {
System.out.println(new BigDecimal("7412611111110.99"));
}
}

@ -0,0 +1,62 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.office;
/**
* Encapsulates the UNO Interprocess Connection type and parameters.
* <p>
* OpenOffice.org supports two connection types: TCP sockets and named pipes.
* Named pipes are marginally faster and do not take up a TCP port, but they
* require native libraries, which means setting <em>java.library.path</em>
* when starting Java. E.g. on Linux
* <pre>
* java -Djava.library.path=/opt/openoffice.org/ure/lib ...
* </pre>
* <p>
* See <a href="http://wiki.services.openoffice.org/wiki/Documentation/DevGuide/ProUNO/Opening_a_Connection">Opening a Connection</a>
* in the OpenOffice.org Developer's Guide for more details.
*/
class UnoUrl {
private final String acceptString;
private final String connectString;
private UnoUrl(String acceptString, String connectString) {
this.acceptString = acceptString;
this.connectString = connectString;
}
public static UnoUrl socket(int port) {
String socketString = "socket,host=127.0.0.1,port=" + port;
return new UnoUrl(socketString, socketString + ",tcpNoDelay=1");
}
public static UnoUrl pipe(String pipeName) {
String pipeString = "pipe,name=" + pipeName;
return new UnoUrl(pipeString, pipeString);
}
public String getAcceptString() {
return acceptString;
}
public String getConnectString() {
return connectString;
}
@Override
public String toString() {
return connectString;
}
}

@ -0,0 +1,82 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.process;
import java.io.IOException;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.io.IOUtils;
/**
* {@link ProcessManager} implementation for Linux. Uses the <tt>ps</tt>
* and <tt>kill</tt> commands.
* <p>
* Should Work on Solaris too, except that the command line string
* returned by <tt>ps</tt> there is limited to 80 characters and this affects
* {@link #findPid(String)}.
*/
public class LinuxProcessManager implements ProcessManager {
private static final Pattern PS_OUTPUT_LINE = Pattern.compile("^\\s*(\\d+)\\s+(.*)$");
private String[] runAsArgs;
public void setRunAsArgs(String... runAsArgs) {
this.runAsArgs = runAsArgs;
}
protected String[] psCommand() {
return new String[] { "/bin/ps", "-e", "-o", "pid,args" };
}
public long findPid(ProcessQuery query) throws IOException {
String regex = Pattern.quote(query.getCommand()) + ".*" + Pattern.quote(query.getArgument());
Pattern commandPattern = Pattern.compile(regex);
for (String line : execute(psCommand())) {
Matcher lineMatcher = PS_OUTPUT_LINE.matcher(line);
if (lineMatcher.matches()) {
String command = lineMatcher.group(2);
Matcher commandMatcher = commandPattern.matcher(command);
if (commandMatcher.find()) {
return Long.parseLong(lineMatcher.group(1));
}
}
}
return PID_NOT_FOUND;
}
public void kill(Process process, long pid) throws IOException {
if (pid <= 0) {
throw new IllegalArgumentException("invalid pid: " + pid);
}
execute("/bin/kill", "-KILL", Long.toString(pid));
}
private List<String> execute(String... args) throws IOException {
String[] command;
if (runAsArgs != null) {
command = new String[runAsArgs.length + args.length];
System.arraycopy(runAsArgs, 0, command, 0, runAsArgs.length);
System.arraycopy(args, 0, command, runAsArgs.length, args.length);
} else {
command = args;
}
Process process = new ProcessBuilder(command).start();
@SuppressWarnings("unchecked")
List<String> lines = IOUtils.readLines(process.getInputStream());
return lines;
}
}

@ -0,0 +1,32 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.process;
import java.io.IOException;
public interface ProcessManager {
public static final long PID_NOT_FOUND = -2;
public static final long PID_UNKNOWN = -1;
void kill(Process process, long pid) throws IOException;
/**
* @param query
* @return the pid if found, {@link #PID_NOT_FOUND} if not,
* or {@link #PID_UNKNOWN} if this implementation is unable to find out
* @throws IOException
*/
long findPid(ProcessQuery query) throws IOException;
}

@ -0,0 +1,33 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.process;
public class ProcessQuery {
private final String command;
private final String argument;
public ProcessQuery(String command, String argument) {
this.command = command;
this.argument = argument;
}
public String getCommand() {
return command;
}
public String getArgument() {
return argument;
}
}

@ -0,0 +1,25 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.process;
public class PureJavaProcessManager implements ProcessManager {
public long findPid(ProcessQuery query) {
return PID_UNKNOWN;
}
public void kill(Process process, long pid) {
process.destroy();
}
}

@ -0,0 +1,71 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.process;
import java.io.IOException;
import org.hyperic.sigar.Sigar;
import org.hyperic.sigar.SigarException;
import org.hyperic.sigar.ptql.ProcessFinder;
/**
* {@link ProcessManager} implementation that uses the SIGAR library.
* <p>
* Requires the sigar.jar in the classpath and the appropriate system-specific
* native library (e.g. <tt>libsigar-x86-linux.so</tt> on Linux x86) available
* in the <em>java.library.path</em>.
* <p>
* See the <a href="http://support.hyperic.com/display/SIGAR">SIGAR site</a>
* for documentation and downloads.
*/
public class SigarProcessManager implements ProcessManager {
public long findPid(ProcessQuery query) throws IOException {
Sigar sigar = new Sigar();
try {
long[] pids = ProcessFinder.find(sigar, "State.Name.eq=" + query.getCommand());
for (int i = 0; i < pids.length; i++) {
String[] arguments = sigar.getProcArgs(pids[i]);
if (arguments != null && argumentMatches(arguments, query.getArgument())) {
return pids[i];
}
}
return PID_NOT_FOUND;
} catch (SigarException sigarException) {
throw new IOException("findPid failed", sigarException);
} finally {
sigar.close();
}
}
public void kill(Process process, long pid) throws IOException {
Sigar sigar = new Sigar();
try {
sigar.kill(pid, Sigar.getSigNum("KILL"));
} catch (SigarException sigarException) {
throw new IOException("kill failed", sigarException);
} finally {
sigar.close();
}
}
private boolean argumentMatches(String[] arguments, String expected) {
for (String argument : arguments) {
if (argument.contains(expected)) {
return true;
}
}
return false;
}
}

@ -0,0 +1,35 @@
//
// JODConverter - Java OpenDocument Converter
// Copyright 2004-2012 Mirko Nasato and contributors
//
// JODConverter is Open Source software, you can redistribute it and/or
// modify it under either (at your option) of the following licenses
//
// 1. The GNU Lesser General Public License v3 (or later)
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
// 2. The Apache License, Version 2.0
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
//
package org.artofsolving.jodconverter.util;
public class PlatformUtils {
private static final String OS_NAME = System.getProperty("os.name").toLowerCase();
private PlatformUtils() {
throw new AssertionError("utility class must not be instantiated");
}
public static boolean isLinux() {
return OS_NAME.startsWith("linux");
}
public static boolean isMac() {
return OS_NAME.startsWith("mac");
}
public static boolean isWindows() {
return OS_NAME.startsWith("windows");
}
}

@ -0,0 +1,188 @@
[
{
"name": "Portable Document Format",
"extension": "pdf",
"mediaType": "application/pdf",
"storePropertiesByFamily": {
"DRAWING": {"FilterName": "draw_pdf_Export"},
"SPREADSHEET": {"FilterName": "calc_pdf_Export"},
"PRESENTATION": {"FilterName": "impress_pdf_Export"},
"TEXT": {"FilterName": "writer_pdf_Export"}
}
},
{
"name": "Macromedia Flash",
"extension": "swf",
"mediaType": "application/x-shockwave-flash",
"storePropertiesByFamily": {
"DRAWING": {"FilterName": "draw_flash_Export"},
"PRESENTATION": {"FilterName": "impress_flash_Export"}
}
},
{
"name": "HTML",
"extension": "html",
"mediaType": "text/html",
"inputFamily": "TEXT",
"storePropertiesByFamily": {
"SPREADSHEET": {"FilterName": "HTML (StarCalc)"},
"PRESENTATION": {"FilterName": "impress_html_Export"},
"TEXT": {"FilterName": "HTML (StarWriter)"}
}
},
{
"name": "OpenDocument Text",
"extension": "odt",
"mediaType": "application/vnd.oasis.opendocument.text",
"inputFamily": "TEXT",
"storePropertiesByFamily": {"TEXT": {"FilterName": "writer8"}}
},
{
"name": "OpenOffice.org 1.0 Text Document",
"extension": "sxw",
"mediaType": "application/vnd.sun.xml.writer",
"inputFamily": "TEXT",
"storePropertiesByFamily": {"TEXT": {"FilterName": "StarOffice XML (Writer)"}}
},
{
"name": "Microsoft Word",
"extension": "doc",
"mediaType": "application/msword",
"inputFamily": "TEXT",
"storePropertiesByFamily": {"TEXT": {"FilterName": "MS Word 97"}}
},
{
"name": "Microsoft Word 2007 XML",
"extension": "docx",
"mediaType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"inputFamily": "TEXT"
},
{
"name": "Rich Text Format",
"extension": "rtf",
"mediaType": "text/rtf",
"inputFamily": "TEXT",
"storePropertiesByFamily": {"TEXT": {"FilterName": "Rich Text Format"}}
},
{
"name": "WordPerfect",
"extension": "wpd",
"mediaType": "application/wordperfect",
"inputFamily": "TEXT"
},
{
"name": "Plain Text",
"extension": "txt",
"mediaType": "text/plain",
"inputFamily": "TEXT",
"loadProperties": {
"FilterName": "Text (encoded)",
"FilterOptions": "utf8"
},
"storePropertiesByFamily": {"TEXT": {
"FilterName": "Text (encoded)",
"FilterOptions": "utf8"
}}
},
{
"name": "MediaWiki wikitext",
"extension": "wiki",
"mediaType": "text/x-wiki",
"storePropertiesByFamily": {"TEXT": {"FilterName": "MediaWiki"}}
},
{
"name": "OpenDocument Spreadsheet",
"extension": "ods",
"mediaType": "application/vnd.oasis.opendocument.spreadsheet",
"inputFamily": "SPREADSHEET",
"storePropertiesByFamily": {"SPREADSHEET": {"FilterName": "calc8"}}
},
{
"name": "OpenOffice.org 1.0 Spreadsheet",
"extension": "sxc",
"mediaType": "application/vnd.sun.xml.calc",
"inputFamily": "SPREADSHEET",
"storePropertiesByFamily": {"SPREADSHEET": {"FilterName": "StarOffice XML (Calc)"}}
},
{
"name": "Microsoft Excel",
"extension": "xls",
"mediaType": "application/vnd.ms-excel",
"inputFamily": "SPREADSHEET",
"storePropertiesByFamily": {"SPREADSHEET": {"FilterName": "MS Excel 97"}}
},
{
"name": "Microsoft Excel 2007 XML",
"extension": "xlsx",
"mediaType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"inputFamily": "SPREADSHEET"
},
{
"name": "Comma Separated Values",
"extension": "csv",
"mediaType": "text/csv",
"inputFamily": "SPREADSHEET",
"loadProperties": {
"FilterName": "Text - txt - csv (StarCalc)",
"FilterOptions": "44,34,0"
},
"storePropertiesByFamily": {"SPREADSHEET": {
"FilterName": "Text - txt - csv (StarCalc)",
"FilterOptions": "44,34,0"
}}
},
{
"name": "Tab Separated Values",
"extension": "tsv",
"mediaType": "text/tab-separated-values",
"inputFamily": "SPREADSHEET",
"loadProperties": {
"FilterName": "Text - txt - csv (StarCalc)",
"FilterOptions": "9,34,0"
},
"storePropertiesByFamily": {"SPREADSHEET": {
"FilterName": "Text - txt - csv (StarCalc)",
"FilterOptions": "9,34,0"
}}
},
{
"name": "OpenDocument Presentation",
"extension": "odp",
"mediaType": "application/vnd.oasis.opendocument.presentation",
"inputFamily": "PRESENTATION",
"storePropertiesByFamily": {"PRESENTATION": {"FilterName": "impress8"}}
},
{
"name": "OpenOffice.org 1.0 Presentation",
"extension": "sxi",
"mediaType": "application/vnd.sun.xml.impress",
"inputFamily": "PRESENTATION",
"storePropertiesByFamily": {"PRESENTATION": {"FilterName": "StarOffice XML (Impress)"}}
},
{
"name": "Microsoft PowerPoint",
"extension": "ppt",
"mediaType": "application/vnd.ms-powerpoint",
"inputFamily": "PRESENTATION",
"storePropertiesByFamily": {"PRESENTATION": {"FilterName": "MS PowerPoint 97"}}
},
{
"name": "Microsoft PowerPoint 2007 XML",
"extension": "pptx",
"mediaType": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
"inputFamily": "PRESENTATION"
},
{
"name": "OpenDocument Drawing",
"extension": "odg",
"mediaType": "application/vnd.oasis.opendocument.graphics",
"inputFamily": "DRAWING",
"storePropertiesByFamily": {"DRAWING": {"FilterName": "draw8"}}
},
{
"name": "Scalable Vector Graphics",
"extension": "svg",
"mediaType": "image/svg+xml",
"storePropertiesByFamily": {"DRAWING": {"FilterName": "draw_svg_Export"}}
}
]

@ -0,0 +1,58 @@
#######################################不可动态配置,需要重启生效#######################################
server.port = ${KK_SERVER_PORT:8012}
server.context-path = ${KK_CONTEXT_PATH:/}
spring.http.encoding.charset = utf8
## Freemarker 配置
spring.freemarker.template-loader-path = classpath:/web/
spring.freemarker.cache = false
spring.freemarker.charset = UTF-8
spring.freemarker.check-template-location = true
spring.freemarker.content-type = text/html
spring.freemarker.expose-request-attributes = true
spring.freemarker.expose-session-attributes = true
spring.freemarker.request-context-attribute = request
spring.freemarker.suffix = .ftl
server.tomcat.uri-encoding = UTF-8
#文件上传限制
spring.http.multipart.max-request-size=100MB
spring.http.multipart.max-file-size=100MB
#文件资源路径默认为打包根路径下的file目录下
#file.dir = D:\\kkFileview\\
file.dir = ${KK_FILE_DIR:default}
#openoffice home路径
#office.home = C:\\Program Files (x86)\\OpenOffice 4
office.home = ${KK_OFFICE_HOME:default}
#缓存实现类型不配默认为内嵌RocksDB(type = default)实现可配置为redis(type = redis)实现需要配置spring.redisson.address等参数和 JDK 内置对象实现type = jdk,
cache.type = ${KK_CACHE_TYPE:jdk}
#redis连接只有当cache.type = redis时才有用
spring.redisson.address = ${KK_SPRING_REDISSON_ADDRESS:127.0.0.1:6379}
spring.redisson.password = ${KK_SPRING_REDISSON_PASSWORD:123456}
#缓存是否自动清理 true 为开启,注释掉或其他值都为关闭
cache.clean.enabled = ${KK_CACHE_CLEAN_ENABLED:true}
#缓存自动清理时间cache.clean.enabled = true时才有用cron表达式基于Quartz cron
cache.clean.cron = ${KK_CACHE_CLEAN_CRON:0 0 3 * * ?}
#######################################可在运行时动态配置#######################################
#提供预览服务的地址默认从请求url读如果使用nginx等反向代理需要手动设置
#base.url = https://file.keking.cn
base.url = ${KK_BASE_URL:default}
#是否启用缓存
cache.enabled = ${KK_CACHE_ENABLED:true}
#文本类型,默认如下,可自定义添加
simText = ${KK_SIMTEXT:txt,html,htm,asp,jsp,xml,json,properties,md,gitignore,,java,py,c,cpp,sql,sh,bat,m,bas,prg,cmd}
#多媒体类型,默认如下,可自定义添加
media = ${KK_MEDIA:mp3,wav,mp4,flv}
#office类型文档(word ppt)样式,默认为图片(image)可配置为pdf预览时也有按钮切换
office.preview.type = ${KK_OFFICE_PREVIEW_TYPE:image}
#预览源为FTP时 FTP用户名可在ftp url后面加参数ftp.username=ftpuser指定不指定默认用配置的
ftp.username = ${KK_FTP_USERNAME:ftpuser}
#预览源为FTP时 FTP密码可在ftp url后面加参数ftp.password=123456指定不指定默认用配置的
ftp.password = ${KK_FTP_PASSWORD:123456}
#预览源为FTP时, FTP连接默认ControlEncoding(根据FTP服务器操作系统选择Linux一般为UTF-8Windows一般为GBK)可在ftp url后面加参数ftp.control.encoding=UTF-8指定不指定默认用配置的
ftp.control.encoding = ${KK_FTP_CONTROL_ENCODING:UTF-8}

@ -0,0 +1,63 @@
C:\Users\lyf\Documents\fileview\file-online-preview\jodconverter-web\target
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.2.RELEASE)
2020-03-31 17:21:06.323 INFO 14272 --- [ main] cn.keking.FilePreviewApplication : Starting FilePreviewApplication v2.2.0-SNAPSHOT on DESKTOP-RKVHFJ0 with PID 14272 (C:\Users\lyf\Documents\fileview\file-online-preview\jodconverter-web\target\kkFileView-2.2.0-SNAPSHOT.jar started by lyf in C:\Users\lyf\Documents\fileview\file-online-preview\jodconverter-web\target)
2020-03-31 17:21:06.326 INFO 14272 --- [ main] cn.keking.FilePreviewApplication : No active profile set, falling back to default profiles: default
2020-03-31 17:21:07.524 INFO 14272 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8012 (http)
2020-03-31 17:21:07.535 INFO 14272 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2020-03-31 17:21:07.535 INFO 14272 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.29]
2020-03-31 17:21:07.602 INFO 14272 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2020-03-31 17:21:07.602 INFO 14272 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1236 ms
2020-03-31 17:21:07.649 WARN 14272 --- [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'converterUtils': Invocation of init method failed; nested exception is java.lang.NullPointerException
2020-03-31 17:21:07.651 INFO 14272 --- [ main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
2020-03-31 17:21:07.660 INFO 14272 --- [ main] ConditionEvaluationReportLoggingListener :
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-03-31 17:21:07.663 ERROR 14272 --- [ main] o.s.boot.SpringApplication : Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'converterUtils': Invocation of init method failed; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:160) ~[spring-beans-5.2.2.RELEASE.jar!/:5.2.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:416) ~[spring-beans-5.2.2.RELEASE.jar!/:5.2.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1788) ~[spring-beans-5.2.2.RELEASE.jar!/:5.2.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:595) ~[spring-beans-5.2.2.RELEASE.jar!/:5.2.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.2.RELEASE.jar!/:5.2.2.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.2.RELEASE.jar!/:5.2.2.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.2.2.RELEASE.jar!/:5.2.2.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.2.RELEASE.jar!/:5.2.2.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.2.RELEASE.jar!/:5.2.2.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:879) ~[spring-beans-5.2.2.RELEASE.jar!/:5.2.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878) ~[spring-context-5.2.2.RELEASE.jar!/:5.2.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550) ~[spring-context-5.2.2.RELEASE.jar!/:5.2.2.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141) ~[spring-boot-2.2.2.RELEASE.jar!/:2.2.2.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747) [spring-boot-2.2.2.RELEASE.jar!/:2.2.2.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) [spring-boot-2.2.2.RELEASE.jar!/:2.2.2.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) [spring-boot-2.2.2.RELEASE.jar!/:2.2.2.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) [spring-boot-2.2.2.RELEASE.jar!/:2.2.2.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215) [spring-boot-2.2.2.RELEASE.jar!/:2.2.2.RELEASE]
at cn.keking.FilePreviewApplication.main(FilePreviewApplication.java:16) [classes!/:2.2.0-SNAPSHOT]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_212]
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_212]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_212]
at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_212]
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48) [kkFileView-2.2.0-SNAPSHOT.jar:2.2.0-SNAPSHOT]
at org.springframework.boot.loader.Launcher.launch(Launcher.java:87) [kkFileView-2.2.0-SNAPSHOT.jar:2.2.0-SNAPSHOT]
at org.springframework.boot.loader.Launcher.launch(Launcher.java:51) [kkFileView-2.2.0-SNAPSHOT.jar:2.2.0-SNAPSHOT]
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:52) [kkFileView-2.2.0-SNAPSHOT.jar:2.2.0-SNAPSHOT]
Caused by: java.lang.NullPointerException: null
at cn.keking.utils.ConverterUtils.initOfficeManager(ConverterUtils.java:43) ~[classes!/:2.2.0-SNAPSHOT]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_212]
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_212]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_212]
at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_212]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:389) ~[spring-beans-5.2.2.RELEASE.jar!/:5.2.2.RELEASE]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:333) ~[spring-beans-5.2.2.RELEASE.jar!/:5.2.2.RELEASE]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:157) ~[spring-beans-5.2.2.RELEASE.jar!/:5.2.2.RELEASE]
... 26 common frames omitted

@ -0,0 +1,54 @@
<!--***********************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
***********************************************************-->
<xsl:stylesheet version="1.0" encoding="UTF-8"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:office="http://openoffice.org/2000/office"
xmlns:style="http://openoffice.org/2000/style"
xmlns:table="http://openoffice.org/2000/table"
xmlns:draw="http://openoffice.org/2000/drawing"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:meta="http://openoffice.org/2000/meta"
xmlns:number="http://openoffice.org/2000/datastyle"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:chart="http://openoffice.org/2000/chart"
xmlns:help="http://openoffice.org/2000/help"
xmlns:index="http://sun.com/2000/XMLSearch"
xmlns:text="http://openoffice.org/2000/text">
<xsl:param name="Language" select="'en-US'"/>
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="/">
<xsl:apply-templates select="//title" mode="include"/>
<xsl:apply-templates select="//paragraph[@role='heading']" mode="include"/>
</xsl:template>
<xsl:template match="*" mode="include">
<xsl:value-of select="."/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="*"/>
</xsl:stylesheet>

@ -0,0 +1,124 @@
<!--***********************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
***********************************************************-->
<xsl:stylesheet version="1.0" encoding="UTF-8"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:office="http://openoffice.org/2000/office"
xmlns:style="http://openoffice.org/2000/style"
xmlns:table="http://openoffice.org/2000/table"
xmlns:draw="http://openoffice.org/2000/drawing"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:meta="http://openoffice.org/2000/meta"
xmlns:number="http://openoffice.org/2000/datastyle"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:chart="http://openoffice.org/2000/chart"
xmlns:help="http://openoffice.org/2000/help"
xmlns:index="http://sun.com/2000/XMLSearch"
xmlns:text="http://openoffice.org/2000/text">
<xsl:param name="Language" select="'en-US'"/>
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="helpdocument|body">
<xsl:choose>
<xsl:when test="meta/topic[@indexer='exclude']"/>
<xsl:otherwise>
<xsl:apply-templates/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="title">
<xsl:value-of select="."/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="table">
<xsl:apply-templates/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="tablecell">
<xsl:apply-templates/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="tablerow">
<xsl:apply-templates/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="list">
<xsl:apply-templates/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="listitem">
<xsl:apply-templates/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="item">
<xsl:apply-templates/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="emph">
<xsl:apply-templates/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="paragraph">
<xsl:value-of select="."/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="section">
<xsl:apply-templates/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="bookmark">
<xsl:apply-templates/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="bookmark_value">
<xsl:apply-templates/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="link">
<xsl:apply-templates/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="ahelp[@visibility='visible']">
<xsl:value-of select="."/>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="*"/>
</xsl:stylesheet>

@ -0,0 +1,960 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--***********************************************************************
This is the main transformation style sheet for transforming.
Only use with OOo 2.0
Owner: fpe@openoffice.org
=========================================================================
Changes Log
May 24 2004 Created
Aug 24 2004 Fixed for help2 CWS
Aug 27 2004 Added css link, fixed missing embed-mode for variable
Removed width/height for images
Sep 03 2004 Modularized xsl, added some embedded modes
Oct 08 2004 Fixed bug wrong mode "embedded" for links
Added embedded modes for embed and embedvar (for cascaded embeds)
Added <p> tags around falsely embedded pars and vars
Dec 08 2004 #i38483#, fixed wrong handling of web links
#i37377#, fixed missing usage of Database parameter for switching
Jan 04 2005 #i38905#, fixed buggy branding replacement template
Mar 17 2005 #i43972#, added language info to image URL, evaluate Language parameter
evaluate new localize attribute in images
May 10 2005 #i48785#, fixed wrong setting of distrib variable
Aug 16 2005 workaround for #i53365#
Aug 19 2005 fixed missing list processing in embedded sections
Aug 19 2005 #i53535#, fixed wrong handling of Database parameter
Oct 17 2006 #i70462#, disabled sorting to avoid output of error messages to console
Jun 15 2009 #i101799#, fixed wrong handling of http URLs with anchors
***********************************************************************//-->
<!--***********************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
***********************************************************-->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" method="html"/>
<!--
############################
# Variables and Parameters #
############################
//-->
<!-- General Usage -->
<xsl:variable name="am" select="'&amp;'"/>
<xsl:variable name="sl" select="'/'"/>
<xsl:variable name="qt" select="'&quot;'"/>
<!-- generic Icon alt text -->
<xsl:variable name="alttext" select="'text/shared/00/icon_alt.xhp'"/>
<!-- For calculating pixel sizes -->
<xsl:variable name="dpi" select="'96'"/>
<xsl:variable name="dpcm" select="'38'"/>
<!-- Product brand variables used in the help files -->
<xsl:variable name="brand1" select="'$[officename]'"/>
<xsl:variable name="brand2" select="'$[officeversion]'"/>
<xsl:variable name="brand3" select="'%PRODUCTNAME'"/>
<xsl:variable name="brand4" select="'%PRODUCTVERSION'"/>
<!-- meta data variables from the help file -->
<xsl:variable name="filename" select="/helpdocument/meta/topic/filename"/>
<xsl:variable name="topic_id" select="/helpdocument/meta/topic/@id"/>
<xsl:variable name="topic_status" select="/helpdocument/meta/topic/@status"/>
<xsl:variable name="title" select="/helpdocument/meta/topic/title"/>
<xsl:variable name="doclang" select="/helpdocument/meta/topic/title/@xml-lang"/>
<!-- Module and the corresponding switching values-->
<xsl:param name="Database" select="'swriter'"/>
<xsl:variable name="module" select="$Database"/>
<xsl:variable name="appl">
<xsl:choose>
<xsl:when test="$module = 'swriter'"><xsl:value-of select="'WRITER'"/></xsl:when>
<xsl:when test="$module = 'scalc'"><xsl:value-of select="'CALC'"/></xsl:when>
<xsl:when test="$module = 'sdraw'"><xsl:value-of select="'DRAW'"/></xsl:when>
<xsl:when test="$module = 'simpress'"><xsl:value-of select="'IMPRESS'"/></xsl:when>
<xsl:when test="$module = 'schart'"><xsl:value-of select="'CHART'"/></xsl:when>
<xsl:when test="$module = 'sbasic'"><xsl:value-of select="'BASIC'"/></xsl:when>
<xsl:when test="$module = 'smath'"><xsl:value-of select="'MATH'"/></xsl:when>
</xsl:choose>
</xsl:variable>
<!-- the other parameters given by the help caller -->
<xsl:param name="System" select="'WIN'"/>
<xsl:param name="productname" select="'Office'"/>
<xsl:param name="productversion" select="''"/>
<xsl:variable name="pversion">
<xsl:value-of select="translate($productversion,' ','')"/>
</xsl:variable>
<!-- this is were the images are -->
<xsl:param name="imgrepos" select="''"/>
<xsl:param name="Id" />
<!-- (lame) distinction between OS and Commercial -->
<xsl:param name="distrib">
<xsl:choose>
<xsl:when test="starts-with($productname,'OpenOffice')">
<xsl:value-of select="'OpenSource'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'COMMERCIAL'"/>
</xsl:otherwise>
</xsl:choose>
</xsl:param>
<xsl:param name="Language" select="'en-US'"/>
<xsl:variable name="lang" select="$Language"/>
<xsl:param name="ExtensionId" select="''"/>
<xsl:param name="ExtensionPath" select="''"/>
<!-- parts of help and image urls -->
<xsl:variable name="help_url_prefix" select="'vnd.sun.star.help://'"/>
<xsl:variable name="img_url_prefix" select="concat('vnd.sun.star.zip://',$imgrepos,'/')"/>
<xsl:variable name="urlpost" select="concat('?Language=',$lang,$am,'System=',$System,$am,'UseDB=no')"/>
<xsl:variable name="urlpre" select="$help_url_prefix" />
<xsl:variable name="linkprefix" select="$urlpre"/>
<xsl:variable name="linkpostfix" select="$urlpost"/>
<xsl:variable name="css" select="'default.css'"/>
<!-- images for notes, tips and warnings -->
<xsl:variable name="note_img" select="concat($img_url_prefix,'res/helpimg/note.png')"/>
<xsl:variable name="tip_img" select="concat($img_url_prefix,'res/helpimg/tip.png')"/>
<xsl:variable name="warning_img" select="concat($img_url_prefix,'res/helpimg/warning.png')"/>
<!--
#############
# Templates #
#############
//-->
<!-- Create the document skeleton -->
<xsl:template match="/">
<xsl:variable name="csslink" select="concat($urlpre,'/',$urlpost)"/>
<html>
<head>
<title><xsl:value-of select="$title"/></title>
<link href="{$csslink}" rel="Stylesheet" type="text/css" /> <!-- stylesheet link -->
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
</head>
<body lang="{$lang}">
<xsl:apply-templates select="/helpdocument/body"/>
</body>
</html>
</xsl:template>
<!-- AHELP -->
<xsl:template match="ahelp">
<xsl:if test="not(@visibility='hidden')"><span class="avis"><xsl:apply-templates /></span></xsl:if>
</xsl:template>
<!-- ALT -->
<xsl:template match="alt"/>
<!-- BOOKMARK -->
<xsl:template match="bookmark">
<a name="{@id}"></a>
<xsl:choose>
<xsl:when test="starts-with(@branch,'hid')" />
<xsl:otherwise><xsl:apply-templates /></xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="bookmark" mode="embedded" />
<!-- BOOKMARK_VALUE -->
<xsl:template match="bookmark_value" />
<!-- BR -->
<xsl:template match="br"><br /></xsl:template>
<!-- CAPTION -->
<xsl:template match="caption" />
<!-- CASE -->
<xsl:template match="case"><xsl:call-template name="insertcase" /></xsl:template>
<xsl:template match="case" mode="embedded">
<xsl:call-template name="insertcase">
<xsl:with-param name="embedded" select="'yes'"/>
</xsl:call-template>
</xsl:template>
<!-- CASEINLINE -->
<xsl:template match="caseinline"><xsl:call-template name="insertcase" /></xsl:template>
<xsl:template match="caseinline" mode="embedded">
<xsl:call-template name="insertcase">
<xsl:with-param name="embedded" select="'yes'"/>
</xsl:call-template>
</xsl:template>
<!-- COMMENT -->
<xsl:template match="comment" />
<xsl:template match="comment" mode="embedded"/>
<!-- CREATED -->
<xsl:template match="created" />
<!-- DEFAULT -->
<xsl:template match="default"><xsl:call-template name="insertdefault" /></xsl:template>
<xsl:template match="default" mode="embedded">
<xsl:call-template name="insertdefault">
<xsl:with-param name="embedded" select="'yes'"/>
</xsl:call-template>
</xsl:template>
<!-- DEFAULTINLINE -->
<xsl:template match="defaultinline"><xsl:call-template name="insertdefault" /></xsl:template>
<xsl:template match="defaultinline" mode="embedded">
<xsl:call-template name="insertdefault">
<xsl:with-param name="embedded" select="'yes'"/>
</xsl:call-template>
</xsl:template>
<!-- EMBED -->
<xsl:template match="embed"><xsl:call-template name="resolveembed"/></xsl:template>
<xsl:template match="embed" mode="embedded"><xsl:call-template name="resolveembed"/></xsl:template>
<!-- EMBEDVAR -->
<xsl:template match="embedvar"><xsl:call-template name="resolveembedvar"/></xsl:template>
<xsl:template match="embedvar" mode="embedded"><xsl:call-template name="resolveembedvar"/></xsl:template>
<!-- EMPH -->
<xsl:template match="emph">
<span class="emph"><xsl:apply-templates /></span>
</xsl:template>
<xsl:template match="emph" mode="embedded">
<span class="emph"><xsl:apply-templates /></span>
</xsl:template>
<!-- FILENAME -->
<xsl:template match="filename" />
<!-- HISTORY -->
<xsl:template match="history" />
<!-- IMAGE -->
<xsl:template match="image"><xsl:call-template name="insertimage"/></xsl:template>
<xsl:template match="image" mode="embedded"><xsl:call-template name="insertimage"/></xsl:template>
<!-- ITEM -->
<xsl:template match="item"><span class="{@type}"><xsl:apply-templates /></span></xsl:template>
<xsl:template match="item" mode="embedded"><span class="{@type}"><xsl:apply-templates /></span></xsl:template>
<!-- LASTEDITED -->
<xsl:template match="lastedited" />
<!-- LINK -->
<xsl:template match="link">
<xsl:choose> <!-- don't insert the heading link to itself -->
<xsl:when test="(concat('/',@href) = /helpdocument/meta/topic/filename) or (@href = /helpdocument/meta/topic/filename)">
<xsl:apply-templates />
</xsl:when>
<xsl:when test="contains(child::embedvar/@href,'/00/00000004.xhp#wie')"> <!-- special treatment of howtoget links -->
<xsl:call-template name="insert_howtoget">
<xsl:with-param name="linkhref" select="@href"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="createlink" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="link" mode="embedded">
<xsl:call-template name="createlink"/>
</xsl:template>
<!-- LIST -->
<xsl:template match="list">
<xsl:choose>
<xsl:when test="@type='ordered'">
<ol>
<xsl:if test="@startwith">
<xsl:attribute name="start"><xsl:value-of select="@startwith"/></xsl:attribute>
</xsl:if>
<xsl:apply-templates />
</ol>
</xsl:when>
<xsl:otherwise>
<ul><xsl:apply-templates /></ul>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="list" mode="embedded">
<xsl:choose>
<xsl:when test="@type='ordered'">
<ol>
<xsl:if test="@startwith">
<xsl:attribute name="start"><xsl:value-of select="@startwith"/></xsl:attribute>
</xsl:if>
<xsl:apply-templates mode="embedded"/>
</ol>
</xsl:when>
<xsl:otherwise>
<ul><xsl:apply-templates mode="embedded"/></ul>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- LISTITEM -->
<xsl:template match="listitem">
<li><xsl:apply-templates /></li>
</xsl:template>
<xsl:template match="listitem" mode="embedded">
<li><xsl:apply-templates mode="embedded"/></li>
</xsl:template>
<!-- META, SEE HEADER -->
<xsl:template match="meta" />
<!-- OBJECT (UNUSED) -->
<xsl:template match="object" />
<!-- PARAGRAPH -->
<xsl:template match="paragraph">
<xsl:choose>
<xsl:when test="@role='heading'">
<xsl:call-template name="insertheading">
<xsl:with-param name="level" select="@level"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="contains(' note warning tip ',@role)">
<xsl:call-template name="insertnote">
<xsl:with-param name="type" select="@role" />
</xsl:call-template>
</xsl:when>
<xsl:when test="contains(descendant::embedvar/@href,'/00/00000004.xhp#wie')"> <!-- special treatment of howtoget links -->
<xsl:apply-templates />
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="insertpara" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="paragraph" mode="embedded">
<xsl:choose>
<xsl:when test="@role='heading'"> <!-- increase the level of headings that are embedded -->
<!--
The internal sablotron processor does not seem to support the number function.
Therefore, we need a workaround for
<xsl:variable name="level"><xsl:value-of select="number(@level)+1"/></xsl:variable>
-->
<xsl:variable name="newlevel">
<xsl:choose>
<xsl:when test="@level='1'"><xsl:value-of select="'2'"/></xsl:when>
<xsl:when test="@level='2'"><xsl:value-of select="'2'"/></xsl:when>
<xsl:when test="@level='3'"><xsl:value-of select="'3'"/></xsl:when>
<xsl:when test="@level='4'"><xsl:value-of select="'4'"/></xsl:when>
<xsl:when test="@level='5'"><xsl:value-of select="'5'"/></xsl:when>
</xsl:choose>
</xsl:variable>
<xsl:call-template name="insertheading">
<xsl:with-param name="level" select="$newlevel"/>
<xsl:with-param name="embedded" select="'yes'"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="contains(' note warning tip ',@role)">
<xsl:call-template name="insertnote">
<xsl:with-param name="type" select="@role" />
</xsl:call-template>
</xsl:when>
<xsl:when test="contains(descendant::embedvar/@href,'/00/00000004.xhp#wie')"> <!-- special treatment of howtoget links -->
<xsl:apply-templates />
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="insertpara" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- SECTION -->
<xsl:template match="section">
<a name="{@id}"></a>
<xsl:choose>
<xsl:when test="@id='relatedtopics'">
<div class="relatedtopics">
<xsl:variable name="href"><xsl:value-of select="concat($urlpre,'shared/text/shared/00/00000004.xhp',$urlpost)"/></xsl:variable>
<xsl:variable name="anchor"><xsl:value-of select="'related'"/></xsl:variable>
<xsl:variable name="doc" select="document($href)"/>
<p class="related">
<xsl:apply-templates select="$doc//variable[@id=$anchor]"/>
</p>
<div class="relatedbody">
<xsl:apply-templates />
</div>
</div>
</xsl:when>
<xsl:when test="@id='howtoget'">
<xsl:call-template name="insert_howtoget" />
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- SECTION -->
<xsl:template match="section" mode="embedded">
<a name="{@id}"></a>
<xsl:apply-templates mode="embedded"/>
</xsl:template>
<!-- SORT -->
<xsl:template match="sort" >
<xsl:apply-templates><xsl:sort select="descendant::paragraph"/></xsl:apply-templates>
</xsl:template>
<xsl:template match="sort" mode="embedded">
<xsl:apply-templates><xsl:sort select="descendant::paragraph"/></xsl:apply-templates>
</xsl:template>
<!-- SWITCH -->
<xsl:template match="switch"><xsl:apply-templates /></xsl:template>
<xsl:template match="switch" mode="embedded"><xsl:apply-templates /></xsl:template>
<!-- SWITCHINLINE -->
<xsl:template match="switchinline"><xsl:apply-templates /></xsl:template>
<xsl:template match="switchinline" mode="embedded"><xsl:apply-templates mode="embedded"/></xsl:template>
<!-- TABLE -->
<xsl:template match="table"><xsl:call-template name="inserttable"/></xsl:template>
<xsl:template match="table" mode="embedded"><xsl:call-template name="inserttable"/></xsl:template>
<!-- TABLECELL -->
<xsl:template match="tablecell"><td valign="top"><xsl:apply-templates /></td></xsl:template>
<xsl:template match="tablecell" mode="icontable"><td valign="top"><xsl:apply-templates/></td></xsl:template>
<xsl:template match="tablecell" mode="embedded"><td valign="top"><xsl:apply-templates mode="embedded"/></td></xsl:template>
<!-- TABLEROW -->
<xsl:template match="tablerow"><tr><xsl:apply-templates /></tr></xsl:template>
<xsl:template match="tablerow" mode="icontable"><tr><xsl:apply-templates mode="icontable"/></tr></xsl:template>
<xsl:template match="tablerow" mode="embedded"><tr><xsl:apply-templates mode="embedded"/></tr></xsl:template>
<!-- TITLE -->
<xsl:template match="title"/>
<!-- TOPIC -->
<xsl:template match="topic"/>
<!-- VARIABLE -->
<xsl:template match="variable"><a name="{@id}"></a><xsl:apply-templates /></xsl:template>
<xsl:template match="variable" mode="embedded"><a name="{@id}"></a><xsl:apply-templates mode="embedded"/></xsl:template>
<xsl:template match="text()">
<xsl:call-template name="brand">
<xsl:with-param name="string"><xsl:value-of select="."/></xsl:with-param>
</xsl:call-template>
</xsl:template>
<xsl:template match="text()" mode="embedded">
<xsl:call-template name="brand">
<xsl:with-param name="string"><xsl:value-of select="."/></xsl:with-param>
</xsl:call-template>
</xsl:template>
<!-- In case of missing help files -->
<xsl:template match="help-id-missing"><xsl:value-of select="$Id"/></xsl:template>
<!--
###################
# NAMED TEMPLATES #
###################
//-->
<!-- Branding -->
<xsl:template name="brand" >
<xsl:param name="string"/>
<xsl:choose>
<xsl:when test="contains($string,$brand1)">
<xsl:variable name="newstr">
<xsl:value-of select="substring-before($string,$brand1)"/>
<xsl:value-of select="$productname"/>
<xsl:value-of select="substring-after($string,$brand1)"/>
</xsl:variable>
<xsl:call-template name="brand">
<xsl:with-param name="string" select="$newstr"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="contains($string,$brand2)">
<xsl:variable name="newstr">
<xsl:value-of select="substring-before($string,$brand2)"/>
<xsl:value-of select="$pversion"/>
<xsl:value-of select="substring-after($string,$brand2)"/>
</xsl:variable>
<xsl:call-template name="brand">
<xsl:with-param name="string" select="$newstr"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="contains($string,$brand3)">
<xsl:variable name="newstr">
<xsl:value-of select="substring-before($string,$brand3)"/>
<xsl:value-of select="$productname"/>
<xsl:value-of select="substring-after($string,$brand3)"/>
</xsl:variable>
<xsl:call-template name="brand">
<xsl:with-param name="string" select="$newstr"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="contains($string,$brand4)">
<xsl:variable name="newstr">
<xsl:value-of select="substring-before($string,$brand4)"/>
<xsl:value-of select="$pversion"/>
<xsl:value-of select="substring-after($string,$brand4)"/>
</xsl:variable>
<xsl:call-template name="brand">
<xsl:with-param name="string" select="$newstr"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$string"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- Insert Paragraph -->
<xsl:template name="insertpara">
<xsl:variable name="role">
<xsl:choose>
<xsl:when test="ancestor::table">
<xsl:value-of select="concat(@role,'intable')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="@role"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<p class="{$role}"><xsl:apply-templates /></p>
</xsl:template>
<!-- Insert "How to get Link" -->
<xsl:template name="insert_howtoget">
<xsl:param name="linkhref" />
<xsl:variable name="archive" select="'shared'"/>
<xsl:variable name="tmp_href"><xsl:value-of select="concat($urlpre,'shared/text/shared/00/00000004.xhp',$urlpost)"/></xsl:variable>
<xsl:variable name="tmp_doc" select="document($tmp_href)"/>
<table class="howtoget" width="100%" border="1" cellpadding="3" cellspacing="0">
<tr>
<td>
<p class="howtogetheader"><xsl:apply-templates select="$tmp_doc//variable[@id='wie']"/></p>
<div class="howtogetbody">
<xsl:choose>
<xsl:when test="$linkhref = ''"> <!-- new style -->
<xsl:apply-templates/>
</xsl:when>
<xsl:otherwise> <!-- old style -->
<xsl:variable name="archive1"><xsl:value-of select="concat(substring-before(substring-after($linkhref,'text/'),'/'),'/')"/></xsl:variable>
<xsl:variable name="href"><xsl:value-of select="concat($urlpre,$archive1,substring-before($linkhref,'#'),$urlpost)"/></xsl:variable>
<xsl:variable name="anc"><xsl:value-of select="substring-after($linkhref,'#')"/></xsl:variable>
<xsl:variable name="docum" select="document($href)"/>
<xsl:call-template name="insertembed">
<xsl:with-param name="doc" select="$docum" />
<xsl:with-param name="anchor" select="$anc" />
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</div>
</td>
</tr>
</table>
<br/>
</xsl:template>
<!-- Create a link -->
<xsl:template name="createlink">
<xsl:variable name="archive"><xsl:value-of select="concat(substring-before(substring-after(@href,'text/'),'/'),'/')"/></xsl:variable>
<xsl:variable name="dbpostfix"><xsl:call-template name="createDBpostfix"><xsl:with-param name="archive" select="$archive"/></xsl:call-template></xsl:variable>
<xsl:choose>
<xsl:when test="starts-with(@href,'http://') or starts-with(@href,'https://')"> <!-- web links -->
<a href="{@href}"><xsl:apply-templates /></a>
</xsl:when>
<xsl:when test="contains(@href,'#')">
<xsl:variable name="anchor"><xsl:value-of select="concat('#',substring-after(@href,'#'))"/></xsl:variable>
<xsl:variable name="href"><xsl:value-of select="concat($linkprefix,$archive,substring-before(@href,'#'),$linkpostfix,$dbpostfix,$anchor)"/></xsl:variable>
<a href="{$href}"><xsl:apply-templates /></a>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="href"><xsl:value-of select="concat($linkprefix,$archive,@href,$linkpostfix,$dbpostfix)"/></xsl:variable>
<a href="{$href}"><xsl:apply-templates /></a>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- Insert Note, Warning, or Tip -->
<xsl:template name="insertnote">
<xsl:param name="type" /> <!-- note, tip, or warning -->
<xsl:variable name="imgsrc">
<xsl:choose>
<xsl:when test="$type='note'"><xsl:value-of select="$note_img"/></xsl:when>
<xsl:when test="$type='tip'"><xsl:value-of select="$tip_img"/></xsl:when>
<xsl:when test="$type='warning'"><xsl:value-of select="$warning_img"/></xsl:when>
</xsl:choose>
</xsl:variable>
<xsl:variable name="dbpostfix"><xsl:call-template name="createDBpostfix"><xsl:with-param name="archive" select="'shared'"/></xsl:call-template></xsl:variable>
<xsl:variable name="alt">
<xsl:variable name="href"><xsl:value-of select="concat($urlpre,'shared/',$alttext,$urlpost,$dbpostfix)"/></xsl:variable>
<xsl:variable name="anchor"><xsl:value-of select="concat('alt_',$type)"/></xsl:variable>
<xsl:variable name="doc" select="document($href)"/>
<xsl:apply-templates select="$doc//variable[@id=$anchor]" mode="embedded"/>
</xsl:variable>
<div class="{$type}">
<table border="0" class="{$type}" cellspacing="0" cellpadding="5">
<tr>
<td><img src="{$imgsrc}" alt="{$alt}" title="{$alt}"/></td>
<td><xsl:apply-templates /></td>
</tr>
</table>
</div>
<br/>
</xsl:template>
<!-- Insert a heading -->
<xsl:template name="insertheading">
<xsl:param name="level" />
<xsl:param name="embedded" />
<xsl:text disable-output-escaping="yes">&lt;h</xsl:text><xsl:value-of select="$level"/><xsl:text disable-output-escaping="yes">&gt;</xsl:text>
<xsl:choose>
<xsl:when test="$embedded = 'yes'">
<xsl:apply-templates mode="embedded"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates />
</xsl:otherwise>
</xsl:choose>
<xsl:text disable-output-escaping="yes">&lt;/h</xsl:text><xsl:value-of select="$level"/><xsl:text disable-output-escaping="yes">&gt;</xsl:text>
</xsl:template>
<!-- Evaluate a case or caseinline switch -->
<xsl:template name="insertcase">
<xsl:param name="embedded" />
<xsl:choose>
<xsl:when test="parent::switch[@select='sys'] or parent::switchinline[@select='sys']">
<xsl:if test="@select = $System">
<xsl:choose>
<xsl:when test="$embedded = 'yes'">
<xsl:apply-templates mode="embedded"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates />
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:when>
<xsl:when test="parent::switch[@select='appl'] or parent::switchinline[@select='appl']">
<xsl:if test="@select = $appl">
<xsl:choose>
<xsl:when test="$embedded = 'yes'">
<xsl:apply-templates mode="embedded"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates />
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:when>
<xsl:when test="parent::switch[@select='distrib'] or parent::switchinline[@select='distrib']">
<xsl:if test="@select = $distrib">
<xsl:choose>
<xsl:when test="$embedded = 'yes'">
<xsl:apply-templates mode="embedded"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates />
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:when>
</xsl:choose>
</xsl:template>
<!-- Evaluate a default or defaultinline switch -->
<xsl:template name="insertdefault">
<xsl:param name="embedded" />
<xsl:choose>
<xsl:when test="parent::switch[@select='sys'] or parent::switchinline[@select='sys']">
<xsl:if test="not(../child::case[@select=$System]) and not(../child::caseinline[@select=$System])">
<xsl:choose>
<xsl:when test="$embedded = 'yes'">
<xsl:apply-templates mode="embedded"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates />
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:when>
<xsl:when test="parent::switch[@select='appl'] or parent::switchinline[@select='appl']">
<xsl:if test="not(../child::case[@select=$appl]) and not(../child::caseinline[@select=$appl])">
<xsl:choose>
<xsl:when test="$embedded = 'yes'">
<xsl:apply-templates mode="embedded"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates />
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:when>
<xsl:when test="parent::switch[@select='distrib'] or parent::switchinline[@select='distrib']">
<xsl:if test="not(../child::case[@select=$distrib]) and not(../child::caseinline[@select=$distrib])">
<xsl:choose>
<xsl:when test="$embedded = 'yes'">
<xsl:apply-templates mode="embedded"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates />
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:when>
</xsl:choose>
</xsl:template>
<!-- evaluate embeds -->
<xsl:template name="insertembed">
<xsl:param name="doc" />
<xsl:param name="anchor" />
<!-- different embed targets (also falsely used embed instead embedvar) -->
<xsl:choose>
<xsl:when test="$doc//section[@id=$anchor]"> <!-- first test for a section of that name -->
<xsl:apply-templates select="$doc//section[@id=$anchor]" mode="embedded"/>
</xsl:when>
<xsl:when test="$doc//paragraph[@id=$anchor]"> <!-- then test for a para of that name -->
<p class="embedded">
<xsl:apply-templates select="$doc//paragraph[@id=$anchor]" mode="embedded"/>
</p>
</xsl:when>
<xsl:when test="$doc//variable[@id=$anchor]"> <!-- then test for a variable of that name -->
<p class="embedded">
<xsl:apply-templates select="$doc//variable[@id=$anchor]" mode="embedded"/>
</p>
</xsl:when>
<xsl:otherwise> <!-- then give up -->
<p class="bug">D'oh! You found a bug (<xsl:value-of select="@href"/> not found).</p>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- Insert an image -->
<xsl:template name="insertimage">
<xsl:variable name="fpath">
<xsl:call-template name="getfpath">
<xsl:with-param name="s"><xsl:value-of select="@src"/></xsl:with-param>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="fname">
<xsl:call-template name="getfname">
<xsl:with-param name="s"><xsl:value-of select="@src"/></xsl:with-param>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="src">
<xsl:choose>
<xsl:when test="not($ExtensionId='') and starts-with(@src,$ExtensionId)">
<xsl:value-of select="concat($ExtensionPath,'/',@src)"/>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="(@localize='true') and not($lang='en-US')">
<xsl:value-of select="concat($img_url_prefix,$fpath,$lang,'/',$fname)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat($img_url_prefix,$fpath,$fname)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<!--<xsl:variable name="src"><xsl:value-of select="concat($img_url_prefix,@src)"/></xsl:variable>-->
<xsl:variable name="alt"><xsl:value-of select="./alt"/></xsl:variable>
<xsl:variable name="width" select="''"/> <!-- Images don't all have the correct size -->
<xsl:variable name="height" select="''"/><!-- Image don't all have the correct size -->
<img src="{$src}" alt="{$alt}" title="{$alt}">
<xsl:if test="not($width='')"><xsl:attribute name="width"><xsl:value-of select="$width"/></xsl:attribute></xsl:if>
<xsl:if test="not($height='')"><xsl:attribute name="height"><xsl:value-of select="$height"/></xsl:attribute></xsl:if>
</img>
</xsl:template>
<!-- Insert a Table -->
<xsl:template name="inserttable">
<xsl:variable name="imgsrc"> <!-- see if we are in an image table -->
<xsl:value-of select="tablerow/tablecell[1]/paragraph[1]/image/@src"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="count(descendant::tablecell)=1">
<table border="0" class="onecell" cellpadding="0" cellspacing="0">
<xsl:apply-templates />
</table>
</xsl:when>
<xsl:when test="descendant::tablecell[1]/descendant::image">
<table border="0" class="icontable" cellpadding="5" cellspacing="0">
<xsl:apply-templates mode="icontable"/>
</table>
</xsl:when>
<xsl:when test="@class='wide'">
<table border="1" class="{@class}" cellpadding="0" cellspacing="0" width="100%" >
<xsl:apply-templates />
</table>
</xsl:when>
<xsl:when test="not(@class='')">
<table border="1" class="{@class}" cellpadding="0" cellspacing="0" >
<xsl:apply-templates />
</table>
</xsl:when>
<xsl:otherwise>
<table border="1" class="border" cellpadding="0" cellspacing="0" >
<xsl:apply-templates />
</table>
</xsl:otherwise>
</xsl:choose>
<br/>
</xsl:template>
<xsl:template name="resolveembed">
<div class="embedded">
<xsl:variable name="archive"><xsl:value-of select="concat(substring-before(substring-after(@href,'text/'),'/'),'/')"/></xsl:variable>
<xsl:variable name="dbpostfix"><xsl:call-template name="createDBpostfix"><xsl:with-param name="archive" select="$archive"/></xsl:call-template></xsl:variable>
<xsl:variable name="href"><xsl:value-of select="concat($urlpre,$archive,substring-before(@href,'#'),$urlpost,$dbpostfix)"/></xsl:variable>
<xsl:variable name="anc"><xsl:value-of select="substring-after(@href,'#')"/></xsl:variable>
<xsl:variable name="docum" select="document($href)"/>
<xsl:call-template name="insertembed">
<xsl:with-param name="doc" select="$docum" />
<xsl:with-param name="anchor" select="$anc" />
</xsl:call-template>
</div>
</xsl:template>
<xsl:template name="resolveembedvar">
<xsl:if test="not(@href='text/shared/00/00000004.xhp#wie')"> <!-- special treatment if howtoget links -->
<xsl:variable name="archive"><xsl:value-of select="concat(substring-before(substring-after(@href,'text/'),'/'),'/')"/></xsl:variable>
<xsl:variable name="dbpostfix"><xsl:call-template name="createDBpostfix"><xsl:with-param name="archive" select="$archive"/></xsl:call-template></xsl:variable>
<xsl:variable name="href"><xsl:value-of select="concat($urlpre,$archive,substring-before(@href,'#'),$urlpost,$dbpostfix)"/></xsl:variable>
<xsl:variable name="anchor"><xsl:value-of select="substring-after(@href,'#')"/></xsl:variable>
<xsl:variable name="doc" select="document($href)"/>
<xsl:choose>
<xsl:when test="$doc//variable[@id=$anchor]"> <!-- test for a variable of that name -->
<xsl:apply-templates select="$doc//variable[@id=$anchor]" mode="embedded"/>
</xsl:when>
<xsl:otherwise> <!-- or give up -->
<span class="bug">[<xsl:value-of select="@href"/> not found].</span>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
<!-- Apply -->
<xsl:template name="apply">
<xsl:param name="embedded" />
<xsl:choose>
<xsl:when test="$embedded = 'yes'">
<xsl:apply-templates mode="embedded"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="getfpath">
<xsl:param name="s"/>
<xsl:param name="p"/>
<xsl:choose>
<xsl:when test="contains($s,'/')">
<xsl:call-template name="getfpath">
<xsl:with-param name="p"><xsl:value-of select="concat($p,substring-before($s,'/'),'/')"/></xsl:with-param>
<xsl:with-param name="s"><xsl:value-of select="substring-after($s,'/')"/></xsl:with-param>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$p"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="getfname">
<xsl:param name="s"/>
<xsl:choose>
<xsl:when test="contains($s,'/')">
<xsl:call-template name="getfname">
<xsl:with-param name="s"><xsl:value-of select="substring-after($s,'/')"/></xsl:with-param>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$s"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="createDBpostfix">
<xsl:param name="archive"/>
<xsl:variable name="newDB">
<xsl:choose>
<xsl:when test="(substring($archive,1,6) = 'shared')"><xsl:value-of select="$Database"/></xsl:when>
<xsl:otherwise><xsl:value-of select="substring-before($archive,'/')"/></xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:value-of select="concat($am,'DbPAR=',$newDB)"/>
</xsl:template>
</xsl:stylesheet>

@ -0,0 +1,94 @@
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
/*
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ OPENOFFICE.ORG 2.0 HELP +
+ DEFAULT STYLESHEET +
+ CHINESE SIMPL +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ LAST CHANGES: 24-MAR-2005 +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*/
body, p, h1, h2, h3, h4, h5, h6, .listitem, .listitemintable, .tablecontent, .tablecontentintable
{ font-family: ,"MSung Light SC",SimSun,FZSongYi,FZShuSong,NSimSun,"Andale Sans UI","Arial Unicode MS","Lucida Sans Unicode",Song; }
.code, .codeintable, .example, .exampleintable, .literal, .literalintable, .path, .pathintable
{ font-family: ,"MSung Light SC",Cumberland,Courier New,Courier,"Lucida Sans Typewriter","Lucida Typewriter",Monaco,Monospaced; margin-top: 1pt; margin-bottom: 1pt;}
.acronym
{ font-weight: bold; }
.related
{ font-weight: bold; margin-top:20pt; border-top: 1px solid black;}
.emph, .menuitem, .keycode
{ font-weight: bold; }
.tablehead, .tableheadintable
{ font-weight: bold; margin-top: 0px;}
.howtogetheader
{ font-weight: bold; border: 1px solid #999999; background: #FFFFFF; padding: 3px;}
h1, h2, h3, h4, h5, h6
{ margin-bottom: 5pt; }
p, td
{ font-size: 10pt; }
h1
{ font-size: 18pt; border-bottom: 1px solid black; padding-bottom: 6px; margin-bottom: 6px;}
h2
{ font-size: 14pt; }
h3
{ font-size: 12pt; }
h4, h5, h6
{ font-size: 10pt; }
.relatedtopics
{ font-weight: normal; }
.relatedbody
{ margin-top: 2px; margin-bottom: 2px; margin-left: 5px; }
.howtoget
{ background:#EEEEEE;}
.howtogetbody
{ background:#EEEEEE;}
.wide
{ width: 100%; }
.topalign
{ vertical-align: top; border: 1px;}
.bug
{ color: red; border: 1px solid red;}
.debug
{ border: 1px solid black; padding: 3px; display: none;}

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--***********************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
***********************************************************-->
<helpdocument version="1.0">
<meta>
<topic id="textshared05err_htmlxml" indexer="exclude" status="PUBLISH">
<title id="tit" xml-lang="zh-CN">未找到帮助页面</title>
<filename>/text/shared/05/err_html.xhp</filename>
</topic>
<history>
<created date="2003-10-31T00:00:00">Sun Microsystems, Inc.</created>
<lastedited date="2005-01-11T11:07:13">converted from old format - fpe
FPE: Updated</lastedited>
</history>
</meta>
<body>
<paragraph role="heading" id="hd_id3146957" xml-lang="zh-CN" level="1" l10n="U" oldref="1">帮助页面未能找到。</paragraph>
<paragraph role="paragraph" id="par_id3147088" xml-lang="zh-CN" l10n="U" oldref="2">很遗憾,您所选择的帮助页面未能找到。以下数据可能对界定错误有所帮助:</paragraph>
<paragraph role="paragraph" id="par_id3143268" xml-lang="zh-CN" l10n="U" oldref="3">帮助 ID<emph><help-id-missing/></emph></paragraph>
<paragraph role="paragraph" id="par_idN10681" xml-lang="zh-CN" l10n="NEW">可以使用安装应用程序来安装缺少的帮助模块。</paragraph>
<paragraph role="paragraph" id="par_id3150541" xml-lang="zh-CN" l10n="U" oldref="16">单击<image id="img_id3148946" src="res/sc06301.png" width="0.222inch" height="0.222inch"><alt id="alt_id3148946">图标</alt></image><emph>上一步</emph>可返回上一页面。</paragraph>
</body>
</helpdocument>

@ -0,0 +1,114 @@
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
/*
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ OPENOFFICE.ORG 2.0 HELP +
+ HIGH CONTRAST #1 STYLESHEET +
+ CHINESE SIMPL +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ LAST CHANGES: 24-MAR-2005 +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*/
body, p, h1, h2, h3, h4, h5, h6, .listitem, .listitemintable, .tablecontent, .tablecontentintable
{ font-family: ,"MSung Light SC",SimSun,FZSongYi,FZShuSong,NSimSun,"Andale Sans UI","Arial Unicode MS","Lucida Sans Unicode",Song; }
.code, .codeintable, .example, .exampleintable, .literal, .literalintable, .path, .pathintable
{ font-family: ,"MSung Light SC",Cumberland,Courier New,Courier,"Lucida Sans Typewriter","Lucida Typewriter",Monaco,Monospaced; margin-top: 1pt; margin-bottom: 1pt;}
.acronym
{ font-weight: bold; }
.related
{ font-weight: bold; margin-top:20pt; border-top: 1px solid black;}
.emph, .menuitem, .keycode
{ font-weight: bold; }
.tablehead, .tableheadintable
{ font-weight: bold; margin-top: 0px;}
.howtogetheader
{ font-weight: bold; padding: 3px;}
h1, h2, h3, h4, h5, h6
{ margin-bottom: 5pt; }
p, td
{ font-size: 10pt; }
h1
{ font-size: 18pt; border-bottom: 1px solid black; padding-bottom: 6px; margin-bottom: 6px;}
h2
{ font-size: 14pt; }
h3
{ font-size: 12pt; }
h4, h5, h6
{ font-size: 10pt; }
.relatedtopics
{ font-weight: normal; }
.relatedbody
{ margin-top: 2px; margin-bottom: 2px; margin-left: 5px; }
.wide
{ width: 100%; }
.topalign
{ vertical-align: top; border: 1px;}
.bug
{ color: red; border: 1px solid red;}
.debug
{ border: 1px solid black; padding: 3px; display: none;}
/* HIGH CONTRAST SPECIFIC SETTINGS */
body, p, h1, h2, h3, h4, h5, h6, .listitem, .listitemintable, .tablecontent, .tablecontentintable
{ background: #000000; color: #FFFF00;}
.related
{ border-top: 1px solid #FFFF00; }
.howtogetheader
{border: 1px solid #EFEFEF; background: #000000;}
h1
{ border-bottom: 1px solid #FFFF00; ]
.howtoget
{ background:#000000;}
.howtogetbody
{ background:#000000;}
.debug
{ border: 1px solid red; padding: 3px; display: none;}
a
{ color: #FFFF00; }

@ -0,0 +1,114 @@
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
/*
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ OPENOFFICE.ORG 2.0 HELP +
+ HIGH CONTRAST #2 STYLESHEET +
+ CHINESE SIMPL +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ LAST CHANGES: 24-MAR-2005 +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*/
body, p, h1, h2, h3, h4, h5, h6, .listitem, .listitemintable, .tablecontent, .tablecontentintable
{ font-family: ,"MSung Light SC",SimSun,FZSongYi,FZShuSong,NSimSun,"Andale Sans UI","Arial Unicode MS","Lucida Sans Unicode",Song; }
.code, .codeintable, .example, .exampleintable, .literal, .literalintable, .path, .pathintable
{ font-family: ,"MSung Light SC",Cumberland,Courier New,Courier,"Lucida Sans Typewriter","Lucida Typewriter",Monaco,Monospaced; margin-top: 1pt; margin-bottom: 1pt;}
.acronym
{ font-weight: bold; }
.related
{ font-weight: bold; margin-top:20pt; border-top: 1px solid black;}
.emph, .menuitem, .keycode
{ font-weight: bold; }
.tablehead, .tableheadintable
{ font-weight: bold; margin-top: 0px;}
.howtogetheader
{ font-weight: bold; padding: 3px;}
h1, h2, h3, h4, h5, h6
{ margin-bottom: 5pt; }
p, td
{ font-size: 10pt; }
h1
{ font-size: 18pt; border-bottom: 1px solid black; padding-bottom: 6px; margin-bottom: 6px;}
h2
{ font-size: 14pt; }
h3
{ font-size: 12pt; }
h4, h5, h6
{ font-size: 10pt; }
.relatedtopics
{ font-weight: normal; }
.relatedbody
{ margin-top: 2px; margin-bottom: 2px; margin-left: 5px; }
.wide
{ width: 100%; }
.topalign
{ vertical-align: top; border: 1px;}
.bug
{ color: red; border: 1px solid red;}
.debug
{ border: 1px solid black; padding: 3px; display: none;}
/* HIGH CONTRAST SPECIFIC SETTINGS */
body, p, h1, h2, h3, h4, h5, h6, .listitem, .listitemintable, .tablecontent, .tablecontentintable
{ background: #000000; color: #00FF00;}
.related
{ border-top: 1px solid #00FF00; }
.howtogetheader
{border: 1px solid #EFEFEF; background: #000000;}
h1
{ border-bottom: 1px solid #00FF00; ]
.howtoget
{ background:#000000;}
.howtogetbody
{ background:#000000;}
.debug
{ border: 1px solid red; padding: 3px; display: none;}
a
{ color: #00FF00; }

@ -0,0 +1,114 @@
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
/*
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ OPENOFFICE.ORG 2.0 HELP +
+ HIGH CONTRAST BLACK STYLESHEET +
+ CHINESE SIMPL +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ LAST CHANGES: 24-MAR-2005 +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*/
body, p, h1, h2, h3, h4, h5, h6, .listitem, .listitemintable, .tablecontent, .tablecontentintable
{ font-family: ,"MSung Light SC",SimSun,FZSongYi,FZShuSong,NSimSun,"Andale Sans UI","Arial Unicode MS","Lucida Sans Unicode",Song; }
.code, .codeintable, .example, .exampleintable, .literal, .literalintable, .path, .pathintable
{ font-family: ,"MSung Light SC",Cumberland,Courier New,Courier,"Lucida Sans Typewriter","Lucida Typewriter",Monaco,Monospaced; margin-top: 1pt; margin-bottom: 1pt;}
.acronym
{ font-weight: bold; }
.related
{ font-weight: bold; margin-top:20pt; border-top: 1px solid black;}
.emph, .menuitem, .keycode
{ font-weight: bold; }
.tablehead, .tableheadintable
{ font-weight: bold; margin-top: 0px;}
.howtogetheader
{ font-weight: bold; padding: 3px;}
h1, h2, h3, h4, h5, h6
{ margin-bottom: 5pt; }
p, td
{ font-size: 10pt; }
h1
{ font-size: 18pt; border-bottom: 1px solid black; padding-bottom: 6px; margin-bottom: 6px;}
h2
{ font-size: 14pt; }
h3
{ font-size: 12pt; }
h4, h5, h6
{ font-size: 10pt; }
.relatedtopics
{ font-weight: normal; }
.relatedbody
{ margin-top: 2px; margin-bottom: 2px; margin-left: 5px; }
.wide
{ width: 100%; }
.topalign
{ vertical-align: top; border: 1px;}
.bug
{ color: red; border: 1px solid red;}
.debug
{ border: 1px solid black; padding: 3px; display: none;}
/* HIGH CONTRAST SPECIFIC SETTINGS */
body, p, h1, h2, h3, h4, h5, h6, .listitem, .listitemintable, .tablecontent, .tablecontentintable
{ background: #000000; color: #FFFFFF;}
.related
{ border-top: 1px solid #FFFFFF; }
.howtogetheader
{border: 1px solid #FFFFFF; background: #000000;}
h1
{ border-bottom: 1px solid #FFFFFF; ]
.howtoget
{ background:#000000;}
.howtogetbody
{ background:#000000;}
.debug
{ border: 1px solid red; padding: 3px; display: none;}
a
{ color: #FFFFFF; }

@ -0,0 +1,114 @@
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
/*
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ OPENOFFICE.ORG 2.0 HELP +
+ HIGH CONTRAST WHITE STYLESHEET +
+ CHINESE SIMPL +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ LAST CHANGES: 24-MAR-2005 +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*/
body, p, h1, h2, h3, h4, h5, h6, .listitem, .listitemintable, .tablecontent, .tablecontentintable
{ font-family: ,"MSung Light SC",SimSun,FZSongYi,FZShuSong,NSimSun,"Andale Sans UI","Arial Unicode MS","Lucida Sans Unicode",Song; }
.code, .codeintable, .example, .exampleintable, .literal, .literalintable, .path, .pathintable
{ font-family: ,"MSung Light SC",Cumberland,Courier New,Courier,"Lucida Sans Typewriter","Lucida Typewriter",Monaco,Monospaced; margin-top: 1pt; margin-bottom: 1pt;}
.acronym
{ font-weight: bold; }
.related
{ font-weight: bold; margin-top:20pt; border-top: 1px solid black;}
.emph, .menuitem, .keycode
{ font-weight: bold; }
.tablehead, .tableheadintable
{ font-weight: bold; margin-top: 0px;}
.howtogetheader
{ font-weight: bold; padding: 3px;}
h1, h2, h3, h4, h5, h6
{ margin-bottom: 5pt; }
p, td
{ font-size: 10pt; }
h1
{ font-size: 18pt; border-bottom: 1px solid black; padding-bottom: 6px; margin-bottom: 6px;}
h2
{ font-size: 14pt; }
h3
{ font-size: 12pt; }
h4, h5, h6
{ font-size: 10pt; }
.relatedtopics
{ font-weight: normal; }
.relatedbody
{ margin-top: 2px; margin-bottom: 2px; margin-left: 5px; }
.wide
{ width: 100%; }
.topalign
{ vertical-align: top; border: 1px;}
.bug
{ color: red; border: 1px solid red;}
.debug
{ border: 1px solid black; padding: 3px; display: none;}
/* HIGH CONTRAST SPECIFIC SETTINGS */
body, p, h1, h2, h3, h4, h5, h6, .listitem, .listitemintable, .tablecontent, .tablecontentintable
{ background: #FFFFFF; color: #000000;}
.related
{ border-top: 1px solid #000000; }
.howtogetheader
{border: 1px solid #000000; background: #FFFFFF;}
h1
{ border-bottom: 1px solid #000000; ]
.howtoget
{ background:#FFFFFF;}
.howtogetbody
{ background:#FFFFFF;}
.debug
{ border: 1px solid red; padding: 3px; display: none;}
a
{ color: #000000; }

@ -0,0 +1,30 @@
###############################################################
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
###############################################################
Title=%PRODUCTNAME Basic
Language=zh-CN
Order=7
Start=text%2Fsbasic%2Fshared%2Fmain0601.xhp
Heading=headingheading
Program=BASIC
07.07.04 00:00:00

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,265 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--***********************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
***********************************************************-->
<tree_view version="24-Aug-2004">
<help_section application="sbasic" id="07" title="宏和编程">
<node id="0701" title="一般信息和用户界面的使用">
<topic id="sbasic/text/sbasic/shared/main0601.xhp">%PRODUCTNAME Basic 帮助</topic>
<topic id="sbasic/text/sbasic/shared/01000000.xhp">使用 %PRODUCTNAME Basic 编程</topic>
<topic id="sbasic/text/sbasic/shared/00000002.xhp">%PRODUCTNAME Basic 词汇表</topic>
<topic id="sbasic/text/sbasic/shared/01010210.xhp">Basics</topic>
<topic id="sbasic/text/sbasic/shared/01020000.xhp">语法</topic>
<topic id="sbasic/text/sbasic/shared/01050000.xhp">%PRODUCTNAME Basic IDE</topic>
<topic id="sbasic/text/sbasic/shared/01030100.xhp">IDE 概况</topic>
<topic id="sbasic/text/sbasic/shared/01030200.xhp">Basic 编辑器</topic>
<topic id="sbasic/text/sbasic/shared/01050100.xhp">监视窗口</topic>
<topic id="sbasic/text/sbasic/shared/main0211.xhp">宏工具栏</topic>
<topic id="sbasic/text/sbasic/shared/05060700.xhp">宏</topic>
</node>
<node id="0702" title="命令引用">
<topic id="sbasic/text/sbasic/shared/01020300.xhp">使用过程和函数</topic>
<topic id="sbasic/text/sbasic/shared/01020500.xhp">程序库、模块和对话框</topic>
<node id="070202" title="运行时函数、语句和运算符">
<topic id="sbasic/text/sbasic/shared/03010000.xhp">屏幕 I/O 函数</topic>
<topic id="sbasic/text/sbasic/shared/03020000.xhp">文件 I/O 函数</topic>
<topic id="sbasic/text/sbasic/shared/03030000.xhp">日期和时间函数</topic>
<topic id="sbasic/text/sbasic/shared/03050000.xhp">错误处理函数</topic>
<topic id="sbasic/text/sbasic/shared/03060000.xhp">逻辑运算符</topic>
<topic id="sbasic/text/sbasic/shared/03070000.xhp">数学运算符</topic>
<topic id="sbasic/text/sbasic/shared/03080000.xhp">数字函数</topic>
<topic id="sbasic/text/sbasic/shared/03090000.xhp">控制程序的执行</topic>
<topic id="sbasic/text/sbasic/shared/03100000.xhp">变量</topic>
<topic id="sbasic/text/sbasic/shared/03110000.xhp">比较运算符</topic>
<topic id="sbasic/text/sbasic/shared/03120000.xhp">字符串</topic>
<topic id="sbasic/text/sbasic/shared/03130000.xhp">其他命令</topic>
</node>
<node id="070201" title="函数、语句和运算符的字母顺序列表">
<topic id="sbasic/text/sbasic/shared/03080601.xhp">Abs 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03060100.xhp">AND 运算符 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03104200.xhp">Array 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03120101.xhp">Asc 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03080101.xhp">Atn 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03130100.xhp">Beep 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03010301.xhp">Blue 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03100100.xhp">CBool 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03120105.xhp">CByte 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03030108.xhp">CDateFromIso 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03030107.xhp">CdateToIso 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03100300.xhp">CDate 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03100400.xhp">CDbl 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03100500.xhp">CInt 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03100600.xhp">CLng 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03100900.xhp">CSng 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03101000.xhp">CStr 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03090401.xhp">Call 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03020401.xhp">ChDir 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03020402.xhp">ChDrive 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03090402.xhp">Choose 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03120102.xhp">Chr 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03020101.xhp">Close 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03110100.xhp">比较运算符 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03100700.xhp">Const 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03120313.xhp">ConvertFromURL 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03120312.xhp">ConvertToURL 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03080102.xhp">Cos 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03131800.xhp">CreateUnoDialog 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03132000.xhp">CreateUnoListener 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03131600.xhp">CreateUnoService 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03131500.xhp">CreateUnoStruct 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03020403.xhp">CurDir 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03030101.xhp">DateSerial 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03030102.xhp">DateValue 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03030301.xhp">Date 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03030103.xhp">Day 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03090403.xhp">Declare 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03101100.xhp">DefBool 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03101300.xhp">DefDate 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03101400.xhp">DefDbl 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03101500.xhp">DefInt 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03101600.xhp">DefLng 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03101700.xhp">DefObj 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03102000.xhp">DefVar 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03104300.xhp">DimArray 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03102100.xhp">Dim 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03020404.xhp">Dir 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03090201.xhp">Do...Loop 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03110100.xhp">比较运算符 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03090404.xhp">End 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03130800.xhp">Environ 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03020301.xhp">Eof 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03104600.xhp">EqualUnoObjects 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03060200.xhp">Eqv 运算符 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03050100.xhp">Erl 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03050200.xhp">Err 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03050300.xhp">Error 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03050000.xhp">错误处理函数</topic>
<topic id="sbasic/text/sbasic/shared/03090412.xhp">Exit 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03080201.xhp">Exp 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03020405.xhp">FileAttr 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03020406.xhp">FileCopy 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03020407.xhp">FileDateTime 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03020415.xhp">FileExists 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03020408.xhp">FileLen 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03103800.xhp">FindObject 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03103900.xhp">FindPropertyObject 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03080501.xhp">Fix 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03090202.xhp">For...Next 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03120301.xhp">Format 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03020102.xhp">FreeFile 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03090405.xhp">FreeLibrary 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03090406.xhp">Function 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03090400.xhp">其他语句</topic>
<topic id="sbasic/text/sbasic/shared/03080300.xhp">生成随机数</topic>
<topic id="sbasic/text/sbasic/shared/03020409.xhp">GetAttr 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03131700.xhp">GetProcessServiceManager 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03131000.xhp">GetSolarVersion 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03130700.xhp">GetSystemTicks 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03020201.xhp">Get 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03131900.xhp">GlobalScope [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03090301.xhp">GoSub...Return 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03090302.xhp">GoTo 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03010302.xhp">Green 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03104400.xhp">HasUnoInterfaces 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03080801.xhp">Hex 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03030201.xhp">Hour 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03090103.xhp">IIf 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03090101.xhp">If...Then...Else 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03060300.xhp">隐含运算符 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03120401.xhp">InStr 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03010201.xhp">InputBox 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03020202.xhp">Input# 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03080502.xhp">Int 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03102200.xhp">IsArray 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03102300.xhp">IsDate 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03102400.xhp">IsEmpty 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03104000.xhp">IsMissing 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03102600.xhp">IsNull 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03102700.xhp">IsNumeric 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03102800.xhp">IsObject 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03104500.xhp">IsUnoStruct 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03120315.xhp">Join 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03020410.xhp">Kill 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03102900.xhp">LBound 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03120302.xhp">LCase 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03120304.xhp">LSet 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03120305.xhp">LTrim 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03120303.xhp">Left 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03120402.xhp">Len 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03103100.xhp">Let 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03020203.xhp">Line Input # 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03020302.xhp">Loc 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03020303.xhp">Lof 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03080202.xhp">Log 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03120306.xhp">Mid 函数、Mid 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03030202.xhp">Minute 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03020411.xhp">MkDir 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03070600.xhp">Mod 运算符 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03030104.xhp">Month 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03010102.xhp">MsgBox 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03010101.xhp">MsgBox 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03020412.xhp">Name 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03060400.xhp">"Not"运算符 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03030203.xhp">Now 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03080000.xhp">数字函数</topic>
<topic id="sbasic/text/sbasic/shared/03080802.xhp">Oct 函数 [运行时间]</topic>
<topic id="sbasic/text/sbasic/shared/03050500.xhp">On Error GoTo ...Resume 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03090303.xhp">On...GoSub 语句On...GoTo 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03020103.xhp">Open 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03103200.xhp">Option Base 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03103300.xhp">Option Explicit 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03104100.xhp">Optional在函数语句中[运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03060500.xhp">Or 运算符 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03010103.xhp">Print 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03103400.xhp">Public 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03020204.xhp">Put 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03010304.xhp">QBColor 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03010305.xhp">RGB 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03120308.xhp">RSet 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03120309.xhp">RTrim 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03080301.xhp">Randomize 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03102101.xhp">ReDim 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03010303.xhp">Red 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03090407.xhp">Rem 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03020104.xhp">Reset 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03120307.xhp">Right 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03020413.xhp">RmDir 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03080302.xhp">Rnd 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03030204.xhp">Second 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03020304.xhp">Seek 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03020305.xhp">Seek 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03090102.xhp">Select...Case 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03020414.xhp">SetAttr 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03103700.xhp">Set 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03080701.xhp">Sgn 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03130500.xhp">Shell 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03080103.xhp">Sin 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03120201.xhp">Space 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03120314.xhp">Split 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03080401.xhp">Sqr 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03080400.xhp">计算平方根</topic>
<topic id="sbasic/text/sbasic/shared/03103500.xhp">Static 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03090408.xhp">Stop 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03120403.xhp">StrComp 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03120103.xhp">Str 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03120202.xhp">String 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03090409.xhp">Sub 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03090410.xhp">Switch 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03080104.xhp">Tan 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03030205.xhp">TimeSerial 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03030206.xhp">TimeValue 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03030302.xhp">Time 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03030303.xhp">Timer 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03080100.xhp">三角函数</topic>
<topic id="sbasic/text/sbasic/shared/03120311.xhp">Trim 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03131300.xhp">TwipsPerPixelX 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03131400.xhp">TwipsPerPixelY 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03103600.xhp">TypeName 函数; VarType 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03103000.xhp">UBound 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03120310.xhp">UCase 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03120104.xhp">Val 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03130600.xhp">Wait 语句 [运行时间]</topic>
<topic id="sbasic/text/sbasic/shared/03030105.xhp">WeekDay 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03090203.xhp">While...Wend 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03090411.xhp">With 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03020205.xhp">Write 语句 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03060600.xhp">Xor 运算符 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03030106.xhp">Year 函数 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03070100.xhp">"-" 运算符 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03070200.xhp">"*" 运算符 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03070300.xhp">"+" 运算符 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03070400.xhp">"/" 运算符 [运行时]</topic>
<topic id="sbasic/text/sbasic/shared/03070500.xhp">"^" 运算符 [运行时]</topic>
</node>
</node>
<node id="0703" title="指南">
<topic id="sbasic/text/sbasic/guide/control_properties.xhp">修改对话框编辑器中控件的属性</topic>
<topic id="sbasic/text/sbasic/guide/insert_control.xhp">在对话框编辑器中创建控件</topic>
<topic id="sbasic/text/sbasic/guide/sample_code.xhp">对话框编辑器中控件的编程示例</topic>
<topic id="sbasic/text/sbasic/guide/show_dialog.xhp">通过程序代码打开对话框</topic>
<topic id="sbasic/text/sbasic/guide/create_dialog.xhp">创建 Basic 对话框</topic>
<topic id="sbasic/text/sbasic/shared/01030400.xhp">管理库和模块</topic>
<topic id="sbasic/text/sbasic/shared/01020100.xhp">使用变量</topic>
<topic id="sbasic/text/sbasic/shared/01020200.xhp">使用对象</topic>
<topic id="sbasic/text/sbasic/shared/01030300.xhp">调试 Basic 程序</topic>
<topic id="sbasic/text/sbasic/shared/01040000.xhp">事件驱动的宏</topic>
</node>
</help_section>
</tree_view>

@ -0,0 +1,30 @@
###############################################################
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
###############################################################
Title=%PRODUCTNAME Calc
Language=zh-CN
Order=3
Start=text%2Fscalc%2Fmain0000.xhp
Heading=headingheading
Program=CALC
07.07.04 00:00:00

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,190 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--***********************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
***********************************************************-->
<tree_view version="24-Aug-2004">
<help_section application="scalc" id="08" title="电子表格">
<node id="0801" title="一般信息和用户界面的使用">
<topic id="scalc/text/scalc/main0000.xhp">欢迎使用 %PRODUCTNAME Calc 帮助</topic>
<topic id="scalc/text/scalc/main0503.xhp">%PRODUCTNAME Calc 功能</topic>
<topic id="scalc/text/scalc/guide/keyboard.xhp">快捷键(%PRODUCTNAME Calc 辅助功能)</topic>
<topic id="scalc/text/scalc/04/01020000.xhp">电子表格的快捷键</topic>
<topic id="scalc/text/scalc/05/02140000.xhp">%PRODUCTNAME Calc 中的错误代码</topic>
<topic id="scalc/text/scalc/01/04060112.xhp">%PRODUCTNAME Calc 中用于编程的加载宏</topic>
<topic id="scalc/text/scalc/guide/main.xhp">%PRODUCTNAME Calc 使用说明</topic>
</node>
<node id="0802" title="命令和菜单引用">
<node id="080201" title="菜单">
<topic id="scalc/text/scalc/main0100.xhp">菜单</topic>
<topic id="scalc/text/scalc/main0101.xhp">文件</topic>
<topic id="scalc/text/scalc/main0102.xhp">编辑</topic>
<topic id="scalc/text/scalc/main0103.xhp">视图</topic>
<topic id="scalc/text/scalc/main0104.xhp">插入</topic>
<topic id="scalc/text/scalc/main0105.xhp">格式</topic>
<topic id="scalc/text/scalc/main0106.xhp">工具</topic>
<topic id="scalc/text/scalc/main0107.xhp">窗口</topic>
<topic id="scalc/text/scalc/main0112.xhp">数据</topic>
</node>
<node id="080202" title="工具栏">
<topic id="scalc/text/scalc/main0200.xhp">工具栏</topic>
<topic id="scalc/text/scalc/main0202.xhp">格式栏</topic>
<topic id="scalc/text/scalc/main0203.xhp">绘图对象属性栏</topic>
<topic id="scalc/text/scalc/main0205.xhp">文字格式栏</topic>
<topic id="scalc/text/scalc/main0206.xhp">公式栏</topic>
<topic id="scalc/text/scalc/main0208.xhp">状态栏</topic>
<topic id="scalc/text/scalc/main0210.xhp">打印预览栏</topic>
<topic id="scalc/text/scalc/main0214.xhp">图片栏</topic>
<topic id="scalc/text/scalc/main0218.xhp">工具栏</topic>
<topic id="shared/text/shared/main0201.xhp">标准栏</topic>
<topic id="shared/text/shared/main0209.xhp">超链接地址栏</topic>
<topic id="shared/text/shared/main0212.xhp">表格数据栏</topic>
<topic id="shared/text/shared/main0213.xhp">窗体导航栏</topic>
<topic id="shared/text/shared/main0214.xhp">查询设计栏</topic>
<topic id="shared/text/shared/main0226.xhp">窗体设计工具栏</topic>
</node>
</node>
<node id="0803" title="函数类型和运算符">
<topic id="scalc/text/scalc/01/04060000.xhp">函数向导</topic>
<topic id="scalc/text/scalc/01/04060100.xhp">函数(按类别)</topic>
<topic id="scalc/text/scalc/01/04060101.xhp">数据库函数</topic>
<topic id="scalc/text/scalc/01/04060102.xhp">日期和时间函数</topic>
<topic id="scalc/text/scalc/01/04060103.xhp">财务函数第一部分</topic>
<topic id="scalc/text/scalc/01/04060119.xhp">财务函数第二部分</topic>
<topic id="scalc/text/scalc/01/04060118.xhp">金融函数第三部分</topic>
<topic id="scalc/text/scalc/01/04060104.xhp">信息函数</topic>
<topic id="scalc/text/scalc/01/04060105.xhp">逻辑函数</topic>
<topic id="scalc/text/scalc/01/04060106.xhp">数学函数</topic>
<topic id="scalc/text/scalc/01/04060107.xhp">矩阵函数</topic>
<topic id="scalc/text/scalc/01/04060108.xhp">统计函数</topic>
<topic id="scalc/text/scalc/01/04060181.xhp">统计函数第一部分</topic>
<topic id="scalc/text/scalc/01/04060182.xhp">统计函数第二部分</topic>
<topic id="scalc/text/scalc/01/04060183.xhp">统计函数第三部分</topic>
<topic id="scalc/text/scalc/01/04060184.xhp">统计函数第四部分</topic>
<topic id="scalc/text/scalc/01/04060185.xhp">统计函数第五部分</topic>
<topic id="scalc/text/scalc/01/04060109.xhp">电子表格函数</topic>
<topic id="scalc/text/scalc/01/04060110.xhp">文字函数</topic>
<topic id="scalc/text/scalc/01/04060111.xhp">加载宏函数</topic>
<topic id="scalc/text/scalc/01/04060115.xhp">加载宏函数,分析函数列表第一部分</topic>
<topic id="scalc/text/scalc/01/04060116.xhp">加载宏函数,分析函数列表第二部分</topic>
<topic id="scalc/text/scalc/01/04060199.xhp">%PRODUCTNAME Calc 中的运算符</topic>
<topic id="scalc/text/scalc/guide/userdefined_function.xhp">自定义函数</topic>
</node>
<node id="0804" title="加载、保存、导入和导出">
<topic id="scalc/text/scalc/guide/webquery.xhp">在表格中插入外部数据 (WebQuery)</topic>
<topic id="scalc/text/scalc/guide/html_doc.xhp">将工作表以 HTML 格式保存和打开</topic>
<topic id="scalc/text/scalc/guide/csv_formula.xhp">导入和导出文本文件</topic>
</node>
<node id="0805" title="格式化">
<topic id="scalc/text/scalc/guide/text_rotate.xhp">旋转文字</topic>
<topic id="scalc/text/scalc/guide/text_wrap.xhp">写入多行文字</topic>
<topic id="scalc/text/scalc/guide/text_numbers.xhp">将数字格式化为文本</topic>
<topic id="scalc/text/scalc/guide/super_subscript.xhp">文字上标/下标</topic>
<topic id="scalc/text/scalc/guide/row_height.xhp">改变行高或列宽</topic>
<topic id="scalc/text/scalc/guide/cellstyle_conditional.xhp">应用条件格式</topic>
<topic id="scalc/text/scalc/guide/cellstyle_minusvalue.xhp">突出显示负数</topic>
<topic id="scalc/text/scalc/guide/cellstyle_by_formula.xhp">根据公式指定的格式</topic>
<topic id="scalc/text/scalc/guide/integer_leading_zero.xhp">输入带前置零的数字</topic>
<topic id="scalc/text/scalc/guide/format_table.xhp">格式化电子表格</topic>
<topic id="scalc/text/scalc/guide/format_value.xhp">格式化带小数的数字</topic>
<topic id="scalc/text/scalc/guide/value_with_name.xhp">命名单元格</topic>
<topic id="scalc/text/scalc/guide/table_rotate.xhp">旋转表格(转置)</topic>
<topic id="scalc/text/scalc/guide/rename_table.xhp">重命名工作表</topic>
<topic id="scalc/text/scalc/guide/year2000.xhp">19xx/20xx 年</topic>
<topic id="scalc/text/scalc/guide/rounding_numbers.xhp">使用四舍五入的数字</topic>
<topic id="scalc/text/scalc/guide/currency_format.xhp">采用货币格式的单元格</topic>
<topic id="scalc/text/scalc/guide/autoformat.xhp">对表格使用自动套用格式</topic>
<topic id="scalc/text/scalc/guide/note_insert.xhp">插入和编辑批注</topic>
<topic id="scalc/text/scalc/guide/design.xhp">选择工作表主题</topic>
<topic id="scalc/text/scalc/guide/fraction_enter.xhp">输入分数</topic>
</node>
<node id="0806" title="筛选和排序">
<topic id="scalc/text/scalc/guide/filters.xhp">应用筛选</topic>
<topic id="scalc/text/scalc/guide/specialfilter.xhp">筛选:应用高级筛选</topic>
<!-- removed scalc/text/scalc/guide/standardfilter.xhp -->
<topic id="scalc/text/scalc/guide/autofilter.xhp">应用自动筛选</topic>
<topic id="scalc/text/scalc/guide/sorted_list.xhp">应用排序列表</topic>
</node>
<node id="0807" title="打印">
<topic id="scalc/text/scalc/guide/print_title_row.xhp">在每一页上打印行或列</topic>
<topic id="scalc/text/scalc/guide/print_landscape.xhp">横向打印工作表</topic>
<topic id="scalc/text/scalc/guide/print_details.xhp">打印工作表详细资料</topic>
<topic id="scalc/text/scalc/guide/print_exact.xhp">定义打印的页数</topic>
</node>
<node id="0808" title="数据区域">
<topic id="scalc/text/scalc/guide/database_define.xhp">定义数据库区域</topic>
<topic id="scalc/text/scalc/guide/database_filter.xhp">过滤单元格范围</topic>
<!-- removed scalc/text/scalc/guide/database_group.xhp -->
<topic id="scalc/text/scalc/guide/database_sort.xhp">数据排序 </topic>
</node>
<node id="0809" title="数据透视表">
<topic id="scalc/text/scalc/guide/datapilot.xhp">数据透视表</topic>
<topic id="scalc/text/scalc/guide/datapilot_createtable.xhp">创建数据透视表</topic>
<topic id="scalc/text/scalc/guide/datapilot_deletetable.xhp">删除数据透视表</topic>
<topic id="scalc/text/scalc/guide/datapilot_edittable.xhp">编辑数据透视表</topic>
<topic id="scalc/text/scalc/guide/datapilot_filtertable.xhp">筛选数据透视表</topic>
<topic id="scalc/text/scalc/guide/datapilot_tipps.xhp">选择数据透视表输出范围</topic>
<topic id="scalc/text/scalc/guide/datapilot_updatetable.xhp">更新数据透视表</topic>
</node>
<node id="0810" title="方案">
<topic id="scalc/text/scalc/guide/scenario.xhp">使用方案</topic>
</node>
<node id="0811" title="引用">
<topic id="scalc/text/scalc/guide/relativ_absolut_ref.xhp">地址和引用,绝对和相对</topic>
<topic id="scalc/text/scalc/guide/cellreferences.xhp">引用其他文档中的单元格</topic>
<topic id="scalc/text/scalc/guide/cellreferences_url.xhp">引用其他工作表和参考 URL</topic>
<topic id="scalc/text/scalc/guide/cellreference_dragdrop.xhp">通过拖放来引用单元格</topic>
<topic id="scalc/text/scalc/guide/address_auto.xhp">寻址时识别名称</topic>
</node>
<node id="0812" title="查看、选择和复制">
<topic id="scalc/text/scalc/guide/table_view.xhp">修改表格视图</topic>
<topic id="scalc/text/scalc/guide/formula_value.xhp">显示公式或数值</topic>
<topic id="scalc/text/scalc/guide/line_fix.xhp">行或列作为标题固定</topic>
<topic id="scalc/text/scalc/guide/multi_tables.xhp">浏览工作表标签</topic>
<topic id="scalc/text/scalc/guide/edit_multitables.xhp">复制到多个工作表</topic>
<topic id="scalc/text/scalc/guide/cellcopy.xhp">仅复制可见单元格</topic>
<topic id="scalc/text/scalc/guide/mark_cells.xhp">选择多个单元格</topic>
</node>
<node id="0813" title="公式和计算">
<topic id="scalc/text/scalc/guide/formulas.xhp">通过公式计算</topic>
<topic id="scalc/text/scalc/guide/formula_copy.xhp">复制公式</topic>
<topic id="scalc/text/scalc/guide/formula_enter.xhp">输入公式</topic>
<topic id="scalc/text/scalc/guide/formula_value.xhp">显示公式或数值</topic>
<topic id="scalc/text/scalc/guide/calculate.xhp">电子表格中的计算</topic>
<topic id="scalc/text/scalc/guide/calc_date.xhp">使用日期和时间进行计算</topic>
<topic id="scalc/text/scalc/guide/calc_series.xhp">自动计算序列</topic>
<topic id="scalc/text/scalc/guide/calc_timevalues.xhp">计算时差</topic>
<topic id="scalc/text/scalc/guide/matrixformula.xhp">输入矩阵公式</topic>
</node>
<node id="0814" title="保护">
<topic id="scalc/text/scalc/guide/cell_protect.xhp">保护单元格不被修改</topic>
<topic id="scalc/text/scalc/guide/cell_unprotect.xhp">取消单元格保护</topic>
</node>
<node id="0815" title="其他">
<!-- removed scalc/text/scalc/guide/autofill.xhp -->
<topic id="scalc/text/scalc/guide/auto_off.xhp">停用自动修改</topic>
<topic id="scalc/text/scalc/guide/consolidate.xhp">合并计算数据</topic>
<topic id="scalc/text/scalc/guide/goalseek.xhp">应用单变量求解</topic>
<topic id="scalc/text/scalc/guide/multioperation.xhp">应用多重计算</topic>
<topic id="scalc/text/scalc/guide/multitables.xhp">应用多个工作表</topic>
<topic id="scalc/text/scalc/guide/validity.xhp">单元格内容的有效性</topic>
</node>
</help_section>
</tree_view>

@ -0,0 +1,30 @@
###############################################################
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
###############################################################
Title=%PRODUCTNAME Chart
Language=zh-CN
Order=4
Start=text%2Fschart%2Fmain0000.xhp
Heading=headingheading
Program=CHART
07.07.04 00:00:00

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--***********************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
***********************************************************-->
<tree_view version="24-Aug-2004">
<help_section application="scalc" id="05" title="图表和图解">
<node id="0501" title="一般信息">
<topic id="schart/text/schart/main0000.xhp">%PRODUCTNAME 中的图表</topic>
<topic id="schart/text/schart/main0503.xhp">%PRODUCTNAME 图表功能</topic>
<topic id="schart/text/schart/04/01020000.xhp">图表的快捷键</topic>
</node>
</help_section>
</tree_view>

@ -0,0 +1,30 @@
###############################################################
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
###############################################################
Title=%PRODUCTNAME Base
Language=zh-CN
Order=7
Start=text%2Fshared%2Fexplorer%2Fdatabase%2Fmain.xhp
Heading=headingheading
Program=DATABASE
07.07.04 00:00:00

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save