From 2ee62d4a36fd178dd35d77911a50963fc3433751 Mon Sep 17 00:00:00 2001 From: gregor herrmann Date: Sun, 16 May 2010 15:39:36 +0000 Subject: [PATCH 1/1] [svn-upgrade] Integrating new upstream version, jabref-plugin-oo (0.7.4+ds) --- CHANGELOG | 131 ++++ OOPlugin.html | 269 +++++++ build.xml | 66 ++ example_style_file.jstyle | 53 ++ net/sf/jabref/oo/OOBibBase.java | 1181 ++++++++++++++++++++++++++++++ net/sf/jabref/oo/OOBibStyle.java | 840 +++++++++++++++++++++ net/sf/jabref/oo/OOUtil.java | 285 +++++++ plugin.xml | 32 + 8 files changed, 2857 insertions(+) create mode 100755 CHANGELOG create mode 100755 OOPlugin.html create mode 100755 build.xml create mode 100755 example_style_file.jstyle create mode 100755 net/sf/jabref/oo/OOBibBase.java create mode 100755 net/sf/jabref/oo/OOBibStyle.java create mode 100755 net/sf/jabref/oo/OOUtil.java create mode 100755 plugin.xml diff --git a/CHANGELOG b/CHANGELOG new file mode 100755 index 0000000..aac2787 --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,131 @@ + +0.7.4: + - Added optional citation property "AuthorLastSeparatorInText" which, if present, + overrides "AuthorLastSeparator" for in-text author-year citations. + - Added citation property "MultiCiteChronological". For author-year citations, this + property can be set to false instead of true to get alphabetical sorting of entries + within the same citation. + - Fixed bug: for normal characters, CharEscapementHeight was set to 0 instead of 100. +0.7.3: + - Changed order of formatting operations in order to fix the problem that formatting + of the first part of a reference list entry gets lost. + - Added tag to indicate small caps in reference list. + - Modified parsing of style file so boolean properties can be parsed even if extra + white space is included, e.g. "true ". + - Fixed bug in "MaxAuthorsFirst" handling: if two citations can be grouped, but one of + them has appeared earlier, this should prevent grouping if the difference between + "MaxAuthorsFirst" and "MaxAuthors" has bearing on the citations in question. +0.7.2: + - Added option "MaxAuthorsFirst" to control how many authors can be shown the first + time a citation appears before "et al" is used. "MaxAuthors" controls the following + appearances. +0.7.1: + - The preformatter is now preferentially run after instead of before formatters called + from the layout specification. This solves the problems of e.g. organization author + names wrapped in braces (e.g. {World Bank}), where the braces have no effect as long + as the preprocessor is run first. This feature depends on a change introduced in + JabRef 2.6, and if older versions are used, the preprocessor will be run first as before. + - Fixed problem with repeated citations in numbered citations. + - Fixed problem with paragraph format not affecting the entire bibliography entries. +0.7: + - All BibTeX fields are now run through a formatter that translates LaTeX character + sequences and \textit{} and \textbf{} commands before insertion into OO. +0.6: + - Improved behaviour when the document references BibTeX keys not found in the + BibTeX database. Citation is now marked as undefined, and the remaining + bibliography gets created as normal. + - Added settings popup menu, and option for whether to automatically sync + bibliography when inserting new citations. +0.5: + - Fixed bug in Merge citations feature - citations would be lost when combined + citations have same year. + - Fixed problem with connection on Mac. +0.4: + - Added optional citation properties BracketBeforeInList and BracketAfterInList that override + BracketBefore and BracketAfter for the numbering of the reference list. + - Added support for and tags in reference layouts, for superscript and + subscript, respectively. + - Added "SubscriptCitations" property that gives subscripted citation markers. +0.3: + - Some changes to the interface. + - Added property MinimumGroupingCount the determines how many consecutive numbers are + required for grouping in a citation marker (e.g. [1-3] or[2;5-8]). + - Fixed bug in properties parsing - empty strings are no longer ignored and replaced by + default values. +0.2.1: + - Fixed bug in sorting of reference list. +0.2: + - Citation markers are now set to language [None] to prevent spell checker from underlining + names. + - Fixed sorting of citations in table cells and footnotes. + - Added option for superscripted citation markers. +0.1.9: + - Added support for citations in table cells and footnotes. Currently sorting by position + fails if there are such citations. + - Added properties for setting bold/italic formatting on citation markers. +0.1.2: + - Added button for inserting invisible citations (without text in the citation marker), + which can be used to insert an entry into the reference list without citing it. + - When citations are merged, they are now sorted chronologically (oldest first). +0.1.1: + - It is now possible to connect again after OpenOffice has been shut down and started + again. + - Added property ReferenceHeaderParagraphFormat in style file to control the paragraph + format of the bibliography header. + - Added error message for the case that OpenOffice has been shut down after connection. + - Fixed bug in handling of von particles in citation markers. +0.1: + - Added functionality to choose which Writer document to connect to - selector is shown + both when connecting, and when using the new "Select Writer document" button. + - Improved appearance of the OpenOffice panel. + - A space is now inserted after newly inserted citations, in order to alleviate problem + with new text becoming part of the citation marker. + - Some improvements to cursor placement after inserting citation. + +0.0.9 (2008-10-19): + - Streamlined connection process by adding button that attempts to find the necessary + paths automatically. + - Made adaptations to connect to OpenOffice.org 3.x, due to changed library locations. + - Fixed bug: plugin tries to connect even if user cancels the connect dialog. + +0.0.8 (2008-09-03): + - No changes, but packaged with JabRef 2.4. + +0.0.7 (2008-02-20): + - Added interface for selecting style. You can set up a list of single files and directories + that will be scanned to build a list of styles (directories can be scanned recursively). + - Fixed problem with layouts starting with a tag such as "" would disable bold/italics + formatting for the entire entry. + - Added property "ReferenceParagraphFormat" that determines what paragraph format is used + for the reference list (default value is "Default"). + +0.0.6 (2008-02-12): + - "Test" button in this version autocombines citations that are separated by spaces only. + - Number citation markers now give citations in ascending order (instead of chronologically, + as with author-year citations), and group consecutive entries (e.g. [1-3; 6]). + +0.0.5 (2008-02-06): + - Fixed bug in author-year citations with names like "Van der Waal". Von-particles are + now included in the citations. + +0.0.4 (2008-01-09): + - When synchronizing bibliography, the style file is now automatically reloaded if it has + been modified since the last read. + - Cleaned out some obsolete code. + +0.0.3 (2007-12-22): + - Reworked the entire plugin to bypass OpenOffice.org's built-in bibliography functions. + This makes it possible to solve the open issues in previous versions, and add support + for multiple citations, and uniquefier letters and formatting within fields in the + bibliography. + - The bibliography is now formatted using standard JabRef layout, including formatters. + - A new formatter FormatChars is added, which translates LaTeX commands for bold and italic + into the and markup used by this plugin. This lets the formatting carry into + the bibliography in OO where appropriate. + +0.0.2 (2007-12-04): + - Fixed bug that prevented the "editor" field from being exported. + - Missing fields are now populated from crossreferenced entry where available. + +0.0.1 (2007-12-01): + - First version. diff --git a/OOPlugin.html b/OOPlugin.html new file mode 100755 index 0000000..dabb3ea --- /dev/null +++ b/OOPlugin.html @@ -0,0 +1,269 @@ +

OpenOffice plugin for JabRef

+ +

Introduction

+ +

JabRef is an open source BibTeX bibliography + manager. +

This plugin offers an interface for inserting citations and formatting a Bibliography in an + OpenOffice writer document from JabRef.

+ + +

How to use the plugin

+ +

The plugin can be used with JabRef 2.4 or newer. If your JabRef version doesn't + have a plugin manager (versions 2.4.x), you need to put the plugin jar file + in a directory named plugins below the directory where the JabRef + jar file is installed (typically under C:\Program files\Jabref 2.x + if you are running under Windows). The plugin should be loaded next time you + start JabRef, and an item named OpenOffice.org panel should appear in + JabRef's Plugins menu. +

The plugin should work with OpenOffice versions 2.4.x and 3.x, provided it + is installed with Java support (this is usually the case on Windows, while in + some Linux distributions you need to install a separate package named + openoffice.org-java-common or something similar).

+ +

Updates:

+ 2010-05-11: Version 0.7.4: Added option to sort alphabetically for citations with multiple entries.
+ 2010-03-04: Version 0.7.3: Added support for <smallcaps> tag to indicate small caps in reference list. Several bug fixes.
+ 2010-02-02: Version 0.7.2: Added MaxAuthorsFirst property to override MaxAuthors the first time each citation appears.
+ 2009-10-07: Version 0.7.1: Several important bug fixes.
+ 2009-08-26: Version 0.7: BibTeX fields are now preprocessed to handle LaTeX \textit and \textbf commands and + character sequences. NOTE: it is no longer necessary to run FormatChars on fields.
+ 2009-08-23: Version 0.6: Improved handling of undefined BibTeX keys. Added option to not sync automatically when adding citation.
+ 2009-08-05: Version 0.5: Fixed connection problem on Mac. Fixed bug in merge function.
+ 2009-06-03: Version 0.4: Added support for superscript/subscript tags in reference list, subscripted citations + and different brackets for numbering in the reference list.
+ 2009-05-17: Version 0.3: Added MinimumGroupingCount property. Some GUI changes.
+ 2009-04-02: Version 0.2.1: Fixed bug in sorting of reference list.
+ 2009-03-01: Version 0.2: Better sorting of citations in captions, tables and footnotes.
+ 2009-02-25: Version 0.1.9: Added support for bold/italic citation markers, and for citations in table cells and footnotes.
+ 2008-12-21: Version 0.1.2: Added invisible citations. Merged citations are now sorted.
+ 2008-11-19: Version 0.1.1: Improved handling of OpenOffice shutdown and reconnect.
+ 2008-10-25: Version 0.1: User interface improvements. Can now select which Writer document to work with.
+ 2008-10-19: Version 0.0.9: Enabled connection to OpenOffice.org 3. Streamlined connection process.
+ 2008-09-03: Version 0.0.8: No major changes, but packaged with JabRef 2.4.
+ 2008-02-20: Version 0.0.7: New interface for style selection. Styles can now specify paragraph format.
+ 2008-02-13: Version 0.0.6: Sorting and grouping of number citation markers.
+ 2008-02-06: Version 0.0.5: Modified style file format. Fixed bug in handling names with elements like "van der".
+ 2008-01-09: Version 0.0.4: Style file is now automatically reloaded if modified.
+ 2007-12-17: Version 0.0.3: From this version, we bypass OO's built-in bibliographic system.
+ 2007-12-04: Version 0.0.2
+ 2007-12-01: Version 0.0.1
+ +

Downloads:

+

The plugin.

+

Plugin source code. The source code tree includes four + OpenOffice.org jars and JabRef 2.5. The plugin is built using + an included Ant build file.

+

Example style file

+ +

The plugin is distributed under the terms of the GNU + General Public License, + version 2 or later.

+ +

Using the OpenOffice interface

+ +

To communicate with OpenOffice, the OO plugin must first connect to a running OpenOffice + instance. You need to start OpenOffice and enter your document before connecting from + JabRef. The plugin needs to know the location of your OpenOffice executable (soffice.exe on + Windows, and soffice on other platforms), and the directory where several OpenOffice + jar files reside. If you connect by clicking the Connect button, the plugin will try to + automatically determine these locations. If this does not work, you need to connect using the + Manual connect button, which will open a window asking you for the needed locations.

+ +

After the connection has been established, you can insert citations by selecting one or more + entries in JabRef and using the Push to OpenOffice button in the dropdown menu of JabRef's + toolbar, or by using the appropriate button in the OpenOffice plugin panel in the side pane. This + will insert citations for the selected entries at the current cursor position in the OpenOffice + document, and update the bibliography to contain the full reference.

+ +

Note: JabRef does not use OpenOffice's built-in bibliography system, because of the + limitations of that system. A document containing citations inserted from JabRef will + not generally be compatible with other reference managers such as Bibus and Zotero.

+ +

Two different types of citations + can be inserted - either a citation in parenthesis, "(Author 2007)", or an in-text citation, + "Author (2007)". This distinction is only meaningful if author-year citations are used instead of + numbered citations, but the distinction will be preserved if you switch between the two styles.

+ +

If you modify entries in JabRef after inserting their citations into OpenOffice, you will + need to synchronize the bibliography. The Sync OO bibliography button will update all + entries of the bibliography, provided their BibTeX keys have not been altered (JabRef encodes the + BibTeX key into the reference name for each citation to keep track of which BibTeX key + the original JabRef entry has).

+ +

The style file

+ + You need to select a style file before connecting to OpenOffice - an external file which is selected + using a standard file dialog. The style file defines the + format of citations and the format of the bibliography. You can use standard JabRef export + formatters to process entry fields before they are sent to OpenOffice. + Through the style file, the intention is to give as much flexibility in citation styles as possible. + +

Here is an example style file:

+
+NAME
+Example style file for JabRef-oo plugin.
+
+JOURNALS
+Journal name 1
+Journal name 2
+
+PROPERTIES
+Title=References
+IsSortByPosition=false
+IsNumberEntries=false
+ReferenceParagraphFormat=Default
+ReferenceHeaderParagraphFormat=Heading 1
+
+CITATION
+AuthorField=author/editor
+YearField=year
+MaxAuthors=3
+MaxAuthorsFirst=6
+AuthorSeparator=,
+AuthorLastSeparator= &
+EtAlString= et al.
+YearSeparator=
+InTextYearSeparator=
+BracketBefore=[
+BracketAfter=]
+BracketBeforeInList=[
+BracketAfterInList=]
+CitationSeparator=;
+UniquefierSeparator=,
+GroupedNumbersSeparator=-
+MinimumGroupingCount=3
+FormatCitations=false
+ItalicCitations=false
+BoldCitations=false
+SuperscriptCitations=false
+SubscriptCitations=false
+
+
+LAYOUT
+article=\format[AuthorLastFirst,AuthorAbbreviator,AuthorAndsReplacer]{\author} (<b>\year\uniq). <i>\title, \journal \volume\begin{pages} : \format[FormatPagesForHTML]{\pages}\end{pages}.
+
+book=\format[AuthorLastFirst,AuthorAbbreviator,AuthorAndsReplacer]{\author}\begin{editor}\format[AuthorLastFirst,AuthorAbbreviator,AuthorAndsReplacer]{\editor} (Ed.)\end{editor}, <b>\year\uniq. <i>\title. \publisher, \address.
+
+incollection=\format[AuthorLastFirst,AuthorAbbreviator,AuthorAndsReplacer]{\author} (<b>\year\uniq). <i>\title. In: \format[AuthorLastFirst,AuthorAbbreviator,AuthorAndsReplacer]{\editor} (Ed.), <i>\booktitle, \publisher.
+
+inbook=\format[AuthorLastFirst,AuthorAbbreviator,AuthorAndsReplacer]{\author} (<b>\year\uniq). <i>\chapter. In: \format[AuthorLastFirst,AuthorAbbreviator,AuthorAndsReplacer]{\editor} (Ed.), <i>\title, \publisher.
+
+phdthesis=\format[AuthorLastFirst,AuthorAbbreviator,AuthorAndsReplacer]{\author} (<b>\year\uniq). <i>\title, \school.
+
+default=\format[AuthorLastFirst,AuthorAbbreviator,AuthorAndsReplacer]{\author} (<b>\year\uniq). <i>\title, \journal \volume\begin{pages} : \format[FormatPagesForHTML]{\pages}\end{pages}.
+
+
+ +

(Note that the layout for each entry type must be constrained to a single line in the style file - above, the lines are broken up to improve readability.)

+
+ +

The PROPERTIES section describes global properties for the bibliography: +

  • Title: determines the header text for the bibliography.
+
  • IsSortByPosition: determines how the bibliography is sorted. If true, the entries + will be sorted according to the order in which they are cited. If false, the entries will be + sorted alphabetically by authors.
+
  • IsNumberEntries: determines the type of citations to use. If true, number + citations will be used. The citation numbers will be included in the bibliography as well. + If false, author-year citations will be used.
+

+ +

The CITATION section describes the format of the citation markers inserted into the text. + If numbered entries are used, only the BracketBefore and BracketAfter properties + are relevant - they define which characters the citation number is wrapped in. The citation is composed + as follows:
+ [BracketBefore][Number][BracketAfter]
+ where [Number] is the number of the citation, determined according to the ordering of the bibliography and/or + the position of the citation in the text. If a citation refers to several entries, these will be separated + by the string given in the property CitationSeparator (for instance, if CitationSeparator=;, + the citation could look like [2;4;6]). If two or more of the entries have a series of consecutive + numbers, the numbers can be grouped (for instance [2-4] for 2, 3 and 4 or [2;5-7] for + 2, 5, 6 and 7). The property GroupedNumbersSeparator (default -) determines which string separates the first and last + of the grouped numbers. The integer property MinimumGroupingCount (default 3) determines what number of + consecutive numbers are required before entries are grouped. If MinimumGroupingCount=3, the numbers + 2 and 3 will not be grouped, while 2, 3, 4 will be. If MinimumGroupingCount=0, no grouping will be + done regardless of the number of consecutive numbers. +

+

If numbered entries are not used, author-year citations will be created based on the citation properties. + A parenthesis citation is composed as follows:
+ [BracketBefore][Author][YearSeparator][Year][BracketAfter]
+ where [Author] is the result of looking up the field or fields given in the AuthorField property, + and formatting a list of authors. The list can contain up to MaxAuthors names - if more are present, + the list will be composed as the first author plus the text specified in the property EtAlString. + If several, slash-separated, fields are given in the AuthorField property, they will be looked up + successively if the first field is empty for the given BibTeX entry. In the example above, the "author" field will + be used, but if empty, the "editor" field will be used as a backup. +

The names in the author list will be separated by the text given by the AuthorSeparator + property, except for the last two names, which will be separated by the text given by AuthorLastSeparator. + If the property AuthorLastSeparatorInText is given, it overrides the former for citations of the in-text + type. This makes it possible to get citations like (Olsen & Jensen, 2008) and Olsen and Jensen (2008) + for the same style. +

+

[Year] is the result of looking up the field or fields given in the [YearField] property.

+ An in-text citation is composed as follows:
+ [Author][InTextYearSeparator][BracketBefore][Year][BracketAfter]
+ where [Author] and [Year] are resolved in exactly the same way as for the parenthesis citations. +

+

If two different cited sources have the same authors and publication year, and author-year citations are used, + their markers will need modification in order to be distinguishable. This is done automatically by appending a + letter after the year for + each of the publications; 'a' for the first cited reference, 'b' for the next, and so on. + For instance, if the author "Olsen" has two cited papers from 2005, the citation markers will be modified to + (Olsen, 2005a) and (Olsen, 2005b). In the bibliography + layout, the placement of the "uniquefier" letter is indicated explicitly by inserting the virtual field + uniq.

+

If several entries that have been "uniquefied" are cited together, they will be grouped in the citation + marker. For instance, of the two entries in the example above are cited together, the citation marker will + be (Olsen, 2005a, b) rather than Olsen, 2005a; Olsen, 2005b). The grouped uniquefier + letters (a and b in our example) will be separated by the string specified by the UniquefierSeparator + property. +

+

The property FormatCitations determines whether the citation markers should be formatted with + regards to italics, boldness, superscript and subscript. If FormatCitations is false, no such formatting + will be done. If true, the citations will be italicized or not depending on the ItalicCitations property, set to bold + or not depending on the BoldCitations property, and similar for the SuperscriptCitations and + SubscriptCitations properties.

+

The LAYOUT section describes how the bibliography entry for each entry type in JabRef + should appear. Each line should start with either the name of a BibTeX entry type, or the word + default, followed by a '='. The default layout will be used for all + entry types for which an explicit layout hasn't been given.

+

The remainder of each line defines the layout, with normal text and spaces appearing literally + in the bibliography entry. Information from the BibTeX entry is inserted by adding \field markers + with the appropriate field name (e.g. \author for inserting the author names). Formatting + information for the field can be included here, following JabRef's standard export layout syntax. + Refer to JabRef's documentation on custom export filters + for more information about which formatters are available.

+

If author-year citations are used, you have to explicitly specify the position of the "uniquefier" letter + that is added to distinguish similar-looking citations. This is done by including a marker for the virtual field + uniq, typically right after the year (as shown in the example style file). The uniq + field is automatically set correctly for each entry before its reference text is laid out. +

+

To indicate formatting in the bibliography, you can use the HTML-like tag pairs <b> </b>, + <i> </i>, <sup> </sup> and <sub> </sub> to specify bold text, + italic text, superscript and subscript, respectively.

+

If you are using numbered citations, the number for each entry will be automatically inserted at the start + of each entry in the reference list. By default, the numbers will be enclosed in the same brackets defined for + citations. The optional citation properties BracketBeforeInList and + BracketAfterInList override BracketBefore and BracketAfter if set. These + can be used if you want different types of brackets (or no brackets) in the reference list. Note that these need + not be brackets as such - they can be any combination of characters.

+ +

Known issues

+ +
    +
  • Make sure to save your Writer document in OpenDocument format + (odt). Saving to Word format will lose your reference marks.
  • +
  • There is currently no support for footnote based citations.
  • +
  • The cursor may be poorly positioned after inserting a citation.
  • +
  • Copy-pasting the example style file directly from this page can give an unparseable + file. To avoid this, instead download the example file from the link in the download section.
  • +
+ +

Contact

+ +If you have tested this plugin, and want to give your feedback, or if you +want to contribute to the development of the plugin, please contact me at the +e-mail address mortenalver at users.sourceforge.net. + + diff --git a/build.xml b/build.xml new file mode 100755 index 0000000..712e5cb --- /dev/null +++ b/build.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example_style_file.jstyle b/example_style_file.jstyle new file mode 100755 index 0000000..7208ba8 --- /dev/null +++ b/example_style_file.jstyle @@ -0,0 +1,53 @@ +NAME +Example style file for JabRef-oo plugin. + +JOURNALS +Journal name 1 +Journal name 2 + +PROPERTIES +Title=References +IsSortByPosition=false +IsNumberEntries=false +ReferenceParagraphFormat=Text body +ReferenceHeaderParagraphFormat=Heading 2 + +CITATION +AuthorField=author/editor +YearField=year +MaxAuthors=2 +MaxAuthorsFirst=6 +AuthorSeparator=, +AuthorLastSeparator= & +AuthorLastSeparatorInText= & +EtAlString= et al. +YearSeparator= +InTextYearSeparator= +BracketBefore=[ +BracketAfter=] +BracketBeforeInList=[ +BracketAfterInList=] +CitationSeparator=; +UniquefierSeparator=, +GroupedNumbersSeparator=- +MinimumGroupingCount=3 +FormatCitations=false +ItalicCitations=false +BoldCitations=false +SuperscriptCitations=false +SubscriptCitations=false +MultiCiteChronological=true + +LAYOUT +article=\format[AuthorLastFirst,AuthorAbbreviator,AuthorAndsReplacer]{\author} (\year\uniq). \title, \journal \volume\begin{pages} : \format[FormatPagesForHTML]{\pages}\end{pages}. + +book=\format[AuthorLastFirst,AuthorAbbreviator,AuthorAndsReplacer]{\author}\begin{editor}\format[AuthorLastFirst,AuthorAbbreviator,AuthorAndsReplacer]{\editor} (Ed.)\end{editor}, \year\uniq. \title. \publisher, \address. + +incollection=\format[AuthorLastFirst,AuthorAbbreviator,AuthorAndsReplacer]{\author} (\year\uniq). \title. In: \format[AuthorLastFirst,AuthorAbbreviator,AuthorAndsReplacer]{\editor} (Ed.), \booktitle, \publisher. + +inbook=\format[AuthorLastFirst,AuthorAbbreviator,AuthorAndsReplacer]{\author} (\year\uniq). \chapter. In: \format[AuthorLastFirst,AuthorAbbreviator,AuthorAndsReplacer]{\editor} (Ed.), \title, \publisher. + +phdthesis=\format[AuthorLastFirst,AuthorAbbreviator,AuthorAndsReplacer]{\author} (\year\uniq). \title, \school. + +default=\format[AuthorLastFirst,AuthorAbbreviator,AuthorAndsReplacer]{\author} (\year\uniq). \title, \journal \volume\begin{pages} : \format[FormatPagesForHTML]{\pages}\end{pages}. + diff --git a/net/sf/jabref/oo/OOBibBase.java b/net/sf/jabref/oo/OOBibBase.java new file mode 100755 index 0000000..6fbc11d --- /dev/null +++ b/net/sf/jabref/oo/OOBibBase.java @@ -0,0 +1,1181 @@ +package net.sf.jabref.oo; + +import com.sun.star.awt.Point; +import com.sun.star.awt.XWindow; +import com.sun.star.beans.XPropertySet; +import com.sun.star.beans.PropertyValue; +import com.sun.star.comp.helper.Bootstrap; +import com.sun.star.container.*; +import com.sun.star.frame.*; +import com.sun.star.lang.*; +import com.sun.star.lang.Locale; +import com.sun.star.text.*; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XComponentContext; +import net.sf.jabref.*; +import net.sf.jabref.export.layout.Layout; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import classes.net.sf.jabref.oo.ComparableMark; + +/** + * Class for manipulating the Bibliography of the currently start document in OpenOffice. + */ +public class OOBibBase { + + final static String BIB_SECTION_NAME = "JR_bib"; + final static String BIB_SECTION_END_NAME = "JR_bib_end"; + final static String BIB_CITATION = "JR_cite"; + final Pattern citePattern = Pattern.compile(BIB_CITATION+"\\d*_(\\d*)_(.*)"); + + final static int + AUTHORYEAR_PAR = 1, + AUTHORYEAR_INTEXT = 2, + INVISIBLE_CIT = 3; + + final static String DEFAULT_CONNECTION_STRING = "uno:socket,host=localhost,port=2002;urp;StarOffice.ServiceManager"; + final String[] BIB_TYPES = new String[] { "ARTICLE", "BOOK", "BOOKLET", "CONFERENCE", + "INBOOK", "INCOLLECTION", "INPROCEEDINGS", "JOURNAL", "MANUAL", "MASTERTHESIS", + "MISC", "PHDTHESIS", "PROCEEDINGS", "TECHREPORT", "UNPUBLISHED", "EMAIL", "WWW", + "CUSTOM1", "CUSTOM2", "CUSTOM3", "CUSTOM4", "CUSTOM5" }; + + + private XMultiServiceFactory mxDocFactory = null; + private XTextDocument mxDoc = null; + private XText text = null; + private XDesktop xDesktop = null; + XTextViewCursorSupplier xViewCursorSupplier = null; + XComponent xCurrentComponent = null; + XComponentLoader xComponentLoader = null; + private boolean atEnd; + private AlphanumericComparator entryComparator = new AlphanumericComparator(); + private YearComparator yearComparator = new YearComparator(); + + private HashMap uniquefiers = new HashMap(); + + private String[] sortedReferenceMarks = null; + + public OOBibBase(String pathToOO, boolean atEnd) throws Exception { + this.atEnd = atEnd; + xDesktop = simpleBootstrap(pathToOO);//getDesktop(); + try { + selectDocument(); + } catch (Exception ex) { + // Could not find a writer document? + return; + } + + } + + public boolean isConnectedToDocument() { + return xCurrentComponent != null; + } + + public String getCurrentDocumentTitle() { + if (mxDoc != null) { + try { + return String.valueOf(OOUtil.getProperty + (mxDoc.getCurrentController().getFrame(), "Title")); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + else + return null; + } + + public void selectDocument() throws Exception { + List ls = getTextDocuments(); + XTextDocument selected = null; + if (ls.size() == 0) { + // No text documents found. + throw new Exception("No Writer documents found"); + } + else if (ls.size() > 1) { + selected = OOUtil.selectComponent(null, xDesktop, ls); + } + else + selected = ls.get(0); + + if (selected == null) { + return; + } + xCurrentComponent = (XComponent) UnoRuntime.queryInterface( + XComponent.class, selected); + mxDoc = selected; + + com.sun.star.text.XDocumentIndexesSupplier indexesSupp = (com.sun.star.text.XDocumentIndexesSupplier) UnoRuntime.queryInterface( + com.sun.star.text.XDocumentIndexesSupplier.class, xCurrentComponent); + + XModel xModel = (XModel) UnoRuntime.queryInterface(XModel.class, xCurrentComponent); + XController xController = xModel.getCurrentController(); + xViewCursorSupplier = + (com.sun.star.text.XTextViewCursorSupplier) UnoRuntime.queryInterface( + com.sun.star.text.XTextViewCursorSupplier.class, xController); + + // get a reference to the body text of the document + text = mxDoc.getText(); + + // Access the text document's multi service factory: + mxDocFactory = (XMultiServiceFactory) UnoRuntime.queryInterface(XMultiServiceFactory.class, mxDoc); + + } + + public XDesktop simpleBootstrap(String pathToExecutable) throws Exception { + + + ClassLoader loader = ClassLoader.getSystemClassLoader(); + if (loader instanceof URLClassLoader) { + URLClassLoader cl = (URLClassLoader) loader; + Class sysclass = URLClassLoader.class; + try { + + Method method = sysclass.getDeclaredMethod("addURL", new Class[]{URL.class}); + method.setAccessible(true); + + method.invoke(cl, new Object[]{new File(pathToExecutable).toURI().toURL()}); + } catch (Throwable t) { + t.printStackTrace(); + throw new IOException("Error, could not add URL to system classloader"); + } + } else { + System.out.println("Error occured, URLClassLoader expected but " + + loader.getClass() + " received. Could not continue."); + } + + //Get the office component context: + XComponentContext xContext = Bootstrap.bootstrap(); + + //Get the office service manager: + XMultiComponentFactory xServiceManager = xContext.getServiceManager(); + + //Create the desktop, which is the root frame of the + //hierarchy of frames that contain viewable components: + Object desktop = xServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", xContext); + + XDesktop xD = (XDesktop) UnoRuntime.queryInterface(XDesktop.class, desktop); + + xComponentLoader = (XComponentLoader)UnoRuntime.queryInterface( + XComponentLoader.class, desktop); + + return xD; + + } + + public List getTextDocuments() throws Exception { + List res = new ArrayList(); + XEnumerationAccess enumA = xDesktop.getComponents(); + XEnumeration e = enumA.createEnumeration(); + + // TODO: http://api.openoffice.org/docs/DevelopersGuide/OfficeDev/OfficeDev.xhtml#1_1_3_2_1_2_Frame_Hierarchies + + while (e.hasMoreElements()) { + Object o = e.nextElement(); + XComponent comp = (XComponent) UnoRuntime.queryInterface(XComponent.class, o); + XTextDocument doc = (XTextDocument) UnoRuntime.queryInterface( + XTextDocument.class, comp); + if (doc != null) { + res.add(doc); + } + } + return res; + } + + + public void updateSortedReferenceMarks() throws Exception { + XReferenceMarksSupplier supplier = (XReferenceMarksSupplier) UnoRuntime.queryInterface( + XReferenceMarksSupplier.class, xCurrentComponent); + XNameAccess nameAccess = supplier.getReferenceMarks(); + String[] names; + sortedReferenceMarks = getSortedReferenceMarks(nameAccess); + } + + /** + * This method inserts a cite marker in the text for the given BibtexEntry, + * and may refresh the bibliography. + * @param entries The entries to cite. + * @param database The database the entry belongs to. + * @param style The bibliography style we are using. + * @param inParenthesis Indicates whether it is an in-text citation or a citation in parenthesis. + * This is not relevant if numbered citations are used. + * @param withText Indicates whether this should be a normal citation (true) or an empty + * (invisible) citation (false). + * @param sync Indicates whether the reference list should be refreshed. + * @throws Exception + */ + public void insertEntry(BibtexEntry[] entries, BibtexDatabase database, OOBibStyle style, + boolean inParenthesis, boolean withText, boolean sync) throws Exception { + + try { + XTextViewCursor xViewCursor = xViewCursorSupplier.getViewCursor(); + + if (entries.length > 1) { + if (style.getBooleanCitProperty("MultiCiteChronological")) + Arrays.sort(entries, yearComparator); + else + Arrays.sort(entries, entryComparator); + } + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < entries.length; i++) { + BibtexEntry entry = entries[i]; + if (i > 0) + sb.append(","); + sb.append(entry.getCiteKey()); + } + String keyString = sb.toString(); + // Insert bookmark: + String bName = getUniqueReferenceMarkName(keyString, + withText ? (inParenthesis ? AUTHORYEAR_PAR : AUTHORYEAR_INTEXT) : INVISIBLE_CIT); + //XTextContent content = insertBookMark(bName, xViewCursor); + + + String citeText = style.isNumberEntries() ? "-" : style.getCitationMarker(entries, database, inParenthesis, null, null); + + //System.out.println(text+" / "+xViewCursor.getText()); + xViewCursor.getText().insertString(xViewCursor, " ", false); + xViewCursor.goLeft((short)1,false); + insertReferenceMark(bName, citeText, xViewCursor, withText, style); + //xViewCursor.collapseToEnd(); + + xViewCursor.collapseToEnd(); + xViewCursor.goRight((short)1,false); + + XTextRange position = xViewCursor.getEnd(); + + if (sync) { + // To account for numbering and for uniqiefiers, we must refresh the cite markers: + updateSortedReferenceMarks(); + refreshCiteMarkers(database, style); + + // Insert it at the current position: + rebuildBibTextSection(database, style); + } + + // Go back to the relevant position: + try { + xViewCursor.gotoRange(position, false); + } catch (Exception ex) { + System.out.println("Catch"); + ex.printStackTrace(); + } + } catch (DisposedException ex) { + // We need to catch this one here because the OOTestPanel class is + // loaded before connection, and therefore cannot directly reference + // or catch a DisposedException (which is in a OO jar file). + throw new ConnectionLostException(ex.getMessage()); + } + } + + /** + * Refresh all cite markers in the document. + * @param database The database to get entries from. + * @param style The bibliography style to use. + * @return A list of those referenced BibTeX keys that could not be resolved. + * @throws UndefinedParagraphFormatException + * @throws Exception + */ + public List refreshCiteMarkers(BibtexDatabase database, OOBibStyle style) throws + UndefinedParagraphFormatException, Exception { + try { + return refreshCiteMarkersInternal(database, style); + } catch (DisposedException ex) { + // We need to catch this one here because the OOTestPanel class is + // loaded before connection, and therefore cannot directly reference + // or catch a DisposedException (which is in a OO jar file). + throw new ConnectionLostException(ex.getMessage()); + } + } + + private List refreshCiteMarkersInternal(BibtexDatabase database, OOBibStyle style) throws + UndefinedParagraphFormatException, Exception { + + List cited = findCitedKeys(); + List entries = findCitedEntries(database, cited); + + XReferenceMarksSupplier supplier = (XReferenceMarksSupplier) UnoRuntime.queryInterface( + XReferenceMarksSupplier.class, xCurrentComponent); + XNameAccess nameAccess = supplier.getReferenceMarks(); + + String[] names; + if (style.isSortByPosition()) { + // We need to sort the reference marks according to their order of appearance: + /*if (sortedReferenceMarks == null) + updateSortedReferenceMarks();*/ + names = sortedReferenceMarks; + } + else if (style.isNumberEntries()) { + // We need to sort the reference marks according to the sorting of the bibliographic + // entries: + Collections.sort(entries, entryComparator); + // Rebuild the list of cited keys according to the sort order: + cited.clear(); + for (Iterator iterator = entries.iterator(); iterator.hasNext();) { + BibtexEntry entry = iterator.next(); + cited.add(entry.getCiteKey()); + } + names = nameAccess.getElementNames(); + } + else { + /*if (sortedReferenceMarks == null) + updateSortedReferenceMarks();*/ + names = sortedReferenceMarks; + } + + HashMap numbers = new HashMap(); + //HashMap 1) { + if (style.getBooleanCitProperty("MultiCiteChronological")) + Arrays.sort(cEntries, yearComparator); + else + Arrays.sort(cEntries, entryComparator); + // Update key list to match the new sorting: + for (int j = 0; j < cEntries.length; j++) { + bibtexKeys[i][j] = cEntries[j].getCiteKey(); + } + } + /*System.out.println(style.getBooleanCitProperty("MultiCiteChronological")); + for (int j = 0; j < cEntries.length; j++) { + BibtexEntry cEntry = cEntries[j]; + System.out.println(cEntry.getCiteKey()); + } */ + + citationMarker = style.getCitationMarker(cEntries, database, type == AUTHORYEAR_PAR, null, null); + // We need "normalized" (in parenthesis) markers for uniqueness checking purposes: + for (int j=0; j> refKeys = new HashMap>(); + HashMap> refNums = new HashMap>(); + for (int i = 0; i < citMarkers.length; i++) { + String[] markers = normCitMarkers[i]; // compare normalized markers, since the actual markers can be different + for (int j=0; j l = new ArrayList(1); + l.add(bibtexKeys[i][j]); + refKeys.put(marker, l); + List l2 = new ArrayList(1); + l2.add(i); + refNums.put(marker, l2); + } + else { + // Ok, we have seen this exact marker before. + if (!refKeys.get(marker).contains(bibtexKeys[i][j])) { + // ... but not for this entry. + refKeys.get(marker).add(bibtexKeys[i][j]); + refNums.get(marker).add(i); + } + } + } + } + // Go through the collected lists and see where we need to uniquefy: + for (String marker : refKeys.keySet()) { + List keys = refKeys.get(marker); + if (keys.size() > 1) { + // This marker appears for more than one unique entry: + int uniq = 'a'; + for (String key : keys) { + // Update the map of uniquefiers for the benefit of both the following generation of new + // citation markers, and for the method that builds the bibliography: + uniquefiers.put(key, String.valueOf((char)uniq)); + uniq++; + } + } + } + + // Finally, go through all citation markers, and update those referring to entries in our current list: + int maxAuthorsFirst = style.getIntCitProperty("MaxAuthorsFirst"); + HashSet seenBefore = new HashSet(); + for (int j = 0; j < bibtexKeys.length; j++) { + boolean needsChange = false; + int[] firstLimAuthors = new int[bibtexKeys[j].length]; + String[] uniquif = new String[bibtexKeys[j].length]; + BibtexEntry[] cEntries = new BibtexEntry[bibtexKeys[j].length]; + for (int k=0; k 0) { + if (!seenBefore.contains(bibtexKeys[j][k])) { + firstLimAuthors[k] = maxAuthorsFirst; + } + seenBefore.add(bibtexKeys[j][k]); + } + String uniq = uniquefiers.get(bibtexKeys[j][k]); + if ((uniq != null) && (uniq.length() >= 0)) { + needsChange = true; + cEntries[k] = OOUtil.createAdaptedEntry(database.getEntryByKey(bibtexKeys[j][k])); + uniquif[k] = uniq; + } + else if (firstLimAuthors[k] > 0) { + needsChange = true; + cEntries[k] = OOUtil.createAdaptedEntry(database.getEntryByKey(bibtexKeys[j][k])); + uniquif[k] = ""; + } + else { + cEntries[k] = OOUtil.createAdaptedEntry(database.getEntryByKey(bibtexKeys[j][k])); + uniquif[k] = ""; + } + } + if (needsChange) + citMarkers[j] = style.getCitationMarker(cEntries, database, types[j] == AUTHORYEAR_PAR, + uniquif, firstLimAuthors); + } + } + + // Refresh all reference marks with the citation markers we computed: + boolean hadBibSection = getBookmarkRange(BIB_SECTION_NAME) != null; + for (int i = 0; i < names.length; i++) { + Object o = nameAccess.getByName(names[i]); + XTextContent bm = (XTextContent) UnoRuntime.queryInterface + (XTextContent.class, o); + + XTextCursor cursor = bm.getAnchor().getText().createTextCursorByRange(bm.getAnchor()); + text.removeTextContent(bm); + insertReferenceMark(names[i], citMarkers[i], cursor, types[i] != INVISIBLE_CIT, style); + if (hadBibSection && (getBookmarkRange(BIB_SECTION_NAME) == null)) { + // We have overwritten the marker for the start of the reference list. + // We need to add it again. + cursor.collapseToEnd(); + OOUtil.insertParagraphBreak(text, cursor); + insertBookMark(BIB_SECTION_NAME, cursor); + /* The following is for resetting the paragraph format, but should probably + not be done. + + XParagraphCursor parCursor = + (XParagraphCursor)UnoRuntime.queryInterface( + java.lang.Class.forName("com.sun.star.text.XParagraphCursor"), cursor); + parCursor.gotoPreviousParagraph(false); + parCursor.gotoStartOfParagraph(false); + parCursor.gotoEndOfParagraph(true); + XPropertySet props = (XPropertySet) UnoRuntime.queryInterface( + XPropertySet.class, parCursor); + + try { + props.setPropertyValue("ParaStyleName", "Default"); + } catch (com.sun.star.lang.IllegalArgumentException ex) { + throw new UndefinedParagraphFormatException("Default"); + } + */ + + } + } + + ArrayList unresolvedKeys = new ArrayList(); + for (BibtexEntry entry : entries) { + if (entry instanceof UndefinedBibtexEntry) { + String key = ((UndefinedBibtexEntry)entry).getKey(); + if (!unresolvedKeys.contains(key)) + unresolvedKeys.add(key); + } + } + return unresolvedKeys; + } + + public String[] getSortedReferenceMarks(final XNameAccess nameAccess) throws Exception { + /* + PropertyValue[] props = new PropertyValue[2]; + + props[0] = new PropertyValue(); + props[0].Name = "Model"; + + props[0].Value = mxDoc.getCurrentController().getModel(); + props[1] = new PropertyValue(); + props[1].Name = "Hidden"; + props[1].Value = true; + + // argument xModel wins over URL. + System.out.println("her"); + XComponent comp = xComponentLoader.loadComponentFromURL("private:factory/swriter", + "_blank", 0, props); + System.out.println("her2"); + + XTextDocument newDoc = (XTextDocument)UnoRuntime.queryInterface( + XTextDocument.class, comp); + System.out.println("newDoc = "+newDoc); + + // Controller of the hidden frame + XController xController = newDoc.getCurrentController(); + + XFrame xFrame = xController.getFrame(); + XWindow xContainerWindow = xFrame.getContainerWindow(); + XWindow xComponentWindow = xFrame.getComponentWindow(); + + xContainerWindow.setVisible(true); + xComponentWindow.setFocus(); + xContainerWindow.setVisible(false); + */ + XTextViewCursorSupplier css = (XTextViewCursorSupplier)UnoRuntime.queryInterface( + XTextViewCursorSupplier.class, mxDoc.getCurrentController()); + + XTextViewCursor tvc = css.getViewCursor(); + XTextRange initialPos = tvc.getStart(); + String[] names = nameAccess.getElementNames(); + Point[] positions = new Point[names.length]; + for (int i = 0; i < names.length; i++) { + String name = names[i]; + XTextContent tc = (XTextContent) UnoRuntime.queryInterface + (XTextContent.class, nameAccess.getByName(name)); + XTextRange r = tc.getAnchor(); + // Check if we are inside a footnote: + if (UnoRuntime.queryInterface(XFootnote.class, r.getText()) != null) { + // Find the linking footnote marker: + XFootnote footer = (XFootnote)UnoRuntime.queryInterface(XFootnote.class, r.getText()); + // The footnote's anchor gives the correct position in the text: + r = footer.getAnchor(); + } + + positions[i] = findPosition(tvc, r); + } + TreeSet set = new TreeSet(); + for (int i = 0; i < positions.length; i++) { + set.add(new ComparableMark(names[i], positions[i])); + } + int i=0; + for (Iterator iterator = set.iterator(); iterator.hasNext();) { + ComparableMark mark = iterator.next(); + //System.out.println(mark.getPosition().X+" -- "+mark.getPosition().Y+" : "+mark.getName()); + names[i++] = mark.getName(); + } + tvc.gotoRange(initialPos, false); + //xFrame.dispose(); + + return names; + + /*final XTextRangeCompare compare = (XTextRangeCompare) UnoRuntime.queryInterface + (XTextRangeCompare.class, text); + Arrays.sort(names, new Comparator() { + public int compare(String o1, String o2) { + try { + XTextRange r1 = ((XTextContent) UnoRuntime.queryInterface + (XTextContent.class, nameAccess.getByName(o1))).getAnchor(); + XTextRange r2 = ((XTextContent) UnoRuntime.queryInterface + (XTextContent.class, nameAccess.getByName(o2))).getAnchor(); + + try { + return compare.compareRegionStarts(r2, r1); + } catch (com.sun.star.lang.IllegalArgumentException ex) { + // problem comparing reference marks in different areas (text, table, etc.) + return 0; + } + } catch (Exception ex) { + ex.printStackTrace(); + return 0; + } + } + }); + return names;*/ + } + + public void rebuildBibTextSection(BibtexDatabase database, OOBibStyle style) + throws Exception { + List cited = findCitedKeys(); + List entries = findCitedEntries(database, cited); + + String[] names = sortedReferenceMarks; + if (style.isSortByPosition()) { + // We need to sort the entries according to their order of appearance: + entries = getSortedEntriesFromSortedRefMarks(names, database, entries); + } + else { + Collections.sort(entries, entryComparator); + } + + clearBibTextSectionContent(); + populateBibTextSection(database, entries, style); + } + + + + public String getUniqueReferenceMarkName(String bibtexKey, int type) { + XReferenceMarksSupplier supplier = (XReferenceMarksSupplier) UnoRuntime.queryInterface( + XReferenceMarksSupplier.class, xCurrentComponent); + XNameAccess xNamedRefMarks = supplier.getReferenceMarks(); + int i=0; + String name = BIB_CITATION+"_"+type+"_"+bibtexKey; + while (xNamedRefMarks.hasByName(name)) { + name = BIB_CITATION+i+"_"+type+"_"+bibtexKey; + i++; + } + return name; + } + + public List findCitedEntries(BibtexDatabase database, List keys) { + List entries = new ArrayList(); + for (String key : keys) { + BibtexEntry entry = database.getEntryByKey(key); + + if (entry != null) + entries.add(OOUtil.createAdaptedEntry(entry)); + else { + entries.add(new UndefinedBibtexEntry(key)); + } + } + return entries; + } + + public List findCitedKeys() throws com.sun.star.container.NoSuchElementException, WrappedTargetException { + + XReferenceMarksSupplier supplier = (XReferenceMarksSupplier) UnoRuntime.queryInterface( + XReferenceMarksSupplier.class, xCurrentComponent); + XNameAccess xNamedMarks = supplier.getReferenceMarks(); + String[] names = xNamedMarks.getElementNames(); + ArrayList keys = new ArrayList(); + for (int i = 0; i < names.length; i++) { + Object bookmark = xNamedMarks.getByName(names[i]); + XTextContent xTextContent = (XTextContent) UnoRuntime.queryInterface( + XTextContent.class, bookmark); + + String name = names[i]; + List newKeys = parseRefMarkName(name); + for (String key : newKeys) + if (!keys.contains(key)) + keys.add(key); + } + + return keys; + } + + public List getSortedEntriesFromSortedRefMarks(String[] names, + BibtexDatabase database, List entries) + throws BibtexEntryNotFoundException { + + List newList = new ArrayList(); + HashMap adaptedEntries = new HashMap(); + for (int i = 0; i < names.length; i++) { + Matcher m = citePattern.matcher(names[i]); + if (m.find()) { + String[] keys = m.group(2).split(","); + for (int j = 0; j < keys.length; j++) { + BibtexEntry origEntry = database.getEntryByKey(keys[j]); + if (origEntry == null) { + System.out.println("Bibtex key not found : '"+keys[j]+"'"); + System.out.println("Problem with reference mark: '"+names[i]+"'"); + newList.add(new UndefinedBibtexEntry(keys[j])); + //throw new BibtexEntryNotFoundException(keys[j], ""); + } else { + BibtexEntry entry = adaptedEntries.get(origEntry); + if (entry == null) { + entry = OOUtil.createAdaptedEntry(origEntry); + adaptedEntries.put(origEntry, entry); + } + if (!newList.contains(entry)) { + newList.add(entry); + } + } + } + } + } + + return newList; + } + + public Point findPosition(XTextViewCursor cursor, XTextRange range) { + cursor.gotoRange(range, false); + return cursor.getPosition(); + } + + /** + * Extract the list of bibtex keys from a reference mark name. + * @param name The reference mark name. + * @return The list of bibtex keys encoded in the name. + */ + public List parseRefMarkName(String name) { + ArrayList keys = new ArrayList(); + Matcher m = citePattern.matcher(name); + if (m.find()) { + String[] keystring = m.group(2).split(","); + for (int j = 0; j < keystring.length; j++) { + if (!keys.contains(keystring[j])) + keys.add(keystring[j]); + } + } + return keys; + } + + /** + * Resolve the bibtex key from a citation reference marker name, and look up + * the index of the key in a list of keys. + * @param citRefName The name of the ReferenceMark representing the citation. + * @param keys A List of bibtex keys representing the entries in the bibliography. + * @return the indices of the cited keys, -1 if a key is not found. Returns null if the ref name + * could not be resolved as a citation. + */ + public int[] findCitedEntryIndex(String citRefName, List keys) { + Matcher m = citePattern.matcher(citRefName); + if (m.find()) { + String[] keyStrings = m.group(2).split(","); + int[] res = new int[keyStrings.length]; + for (int i=0; i entries, + OOBibStyle style, String parFormat) + throws UndefinedParagraphFormatException, Exception { + // If we don't have numbered entries, we need to sort the entries before adding them: + if (!style.isSortByPosition()) + Collections.sort(entries, entryComparator); + int number = 1; + for (BibtexEntry entry : entries) { + if (entry instanceof UndefinedBibtexEntry) + continue; + OOUtil.insertParagraphBreak(text, cursor); + if (style.isNumberEntries()) { + int minGroupingCount = style.getIntCitProperty("MinimumGroupingCount"); + OOUtil.insertTextAtCurrentLocation(text, cursor, + style.getNumCitationMarker(new int[] {number++}, minGroupingCount, true)+" ", + false, false, false, false, false, false); + } + Layout layout = style.getReferenceFormat(entry.getType().getName()); + try { + layout.setPostFormatter(OOUtil.postformatter); + } catch (NoSuchMethodError ex) { + + } + OOUtil.insertFullReferenceAtCurrentLocation(text, cursor, layout, parFormat, entry, database, + uniquefiers.get(entry.getCiteKey())); + } + + } + + public void insertFullReferenceAtViewCursor(BibtexDatabase database, List entries, + OOBibStyle style, String parFormat) throws Exception { + XTextViewCursor xViewCursor = xViewCursorSupplier.getViewCursor(); + insertFullReferenceAtCursor(xViewCursor, database, entries, style, parFormat); + } + + + public void insertMarkedUpTextAtViewCursor(String lText, String parFormat) throws Exception { + XTextViewCursor xViewCursor = xViewCursorSupplier.getViewCursor(); + XTextCursor cursor = text.createTextCursorByRange(xViewCursor.getEnd()); + OOUtil.insertOOFormattedTextAtCurrentLocation(text,cursor, lText, parFormat); + + } + + /** + * This method creates and inserts an XTextSection named as determined by the + * string BIB_SECTION_NAME. + * @param end true to indicate that the section should be put at the end of the document, + * false to indicate that it should be put at the cursor position. + * @return true if the bibliography already existed, false otherwise.. + * @throws Exception + */ + public boolean createBibTextSection(boolean end) throws Exception { + // Check if there already is a bookmarked section: + XBookmarksSupplier bSupp = (XBookmarksSupplier) UnoRuntime.queryInterface( + XBookmarksSupplier.class, mxDoc); + if (bSupp.getBookmarks().hasByName(BIB_SECTION_NAME)) { + System.out.println("Found existing JabRef bookmark"); + return true; + } + XTextCursor mxDocCursor = text.createTextCursor(); + if (end) + mxDocCursor.gotoEnd(false); + OOUtil.insertParagraphBreak(text, mxDocCursor); + insertBookMark(BIB_SECTION_NAME, mxDocCursor); + return false; + } + + public void clearBibTextSectionContent() throws Exception { + // Get a range comparator: + XTextRangeCompare compare = (XTextRangeCompare) UnoRuntime.queryInterface + (XTextRangeCompare.class, text); + // Find the bookmarks for the bibliography: + XTextRange range = getBookmarkRange(BIB_SECTION_NAME); + if (range == null) + createBibTextSection(atEnd); + XTextRange rangeEnd = getBookmarkRange(BIB_SECTION_END_NAME); + if (rangeEnd == null) { + // No end bookmark. This means that there is no bibliography. + return; + } + // Get a paragraph cursor at the start of the bibliography: + //System.out.println("text="+text+" range="+range); + XTextCursor mxDocCursor = text.createTextCursorByRange(range.getEnd()); + mxDocCursor.goRight((short)1, true); + boolean couldExpand = true; + while (couldExpand && (compare.compareRegionEnds(mxDocCursor, rangeEnd) > 0)) { + couldExpand = mxDocCursor.goRight((short)1, true); + } + // Finally, clear the bibliography: + mxDocCursor.setString(""); + mxDocCursor.collapseToStart(); + removeBookMark(BIB_SECTION_END_NAME); + // If we lost the start bookmark, recreate it: + if (getBookmarkRange(BIB_SECTION_NAME) == null) + insertBookMark(BIB_SECTION_NAME, mxDocCursor); + } + + public void populateBibTextSection(BibtexDatabase database, List entries, + OOBibStyle style) + throws UndefinedParagraphFormatException, Exception { + XTextRange range = getBookmarkRange(BIB_SECTION_NAME); + XTextCursor cursor = text.createTextCursorByRange(range.getEnd()); + OOUtil.insertTextAtCurrentLocation(text, cursor, (String)style.getProperty("Title"), + (String)style.getProperty("ReferenceHeaderParagraphFormat")); + insertFullReferenceAtCursor(cursor, database, entries, style, + (String)style.getProperty("ReferenceParagraphFormat")); + insertBookMark(BIB_SECTION_END_NAME, cursor); + } + + public XTextContent insertBookMark(String name, XTextCursor position) throws Exception { + Object bookmark = mxDocFactory.createInstance("com.sun.star.text.Bookmark"); + // name the bookmark + XNamed xNamed = (XNamed) UnoRuntime.queryInterface( + XNamed.class, bookmark); + xNamed.setName(name); + // get XTextContent interface + XTextContent xTextContent = (XTextContent) UnoRuntime.queryInterface( + XTextContent.class, bookmark); + // insert bookmark at the end of the document + // instead of mxDocText.getEnd you could use a text cursor's XTextRange interface or any XTextRange + text.insertTextContent(position, xTextContent, true); + position.collapseToEnd(); + return xTextContent; + } + + public void insertReferenceMark(String name, String citText, XTextCursor position, boolean withText, + OOBibStyle style) + throws Exception { + Object bookmark = mxDocFactory.createInstance("com.sun.star.text.ReferenceMark"); + // Name the reference + XNamed xNamed = (XNamed) UnoRuntime.queryInterface( + XNamed.class, bookmark); + xNamed.setName(name); + // get XTextContent interface + if (true) { + + XTextContent xTextContent = (XTextContent) UnoRuntime.queryInterface( + XTextContent.class, bookmark); + if (withText) { + position.setString(citText); + XPropertySet xCursorProps = (XPropertySet) UnoRuntime.queryInterface( + XPropertySet.class, position); + // Set language to [None]: + xCursorProps.setPropertyValue("CharLocale", new Locale("zxx", "", "")); + + // See if we should format the citation marker or not: + if (style.isFormatCitations()) { + + if (style.getBooleanCitProperty("SuperscriptCitations")) { + xCursorProps.setPropertyValue("CharEscapement", + (byte)101); + xCursorProps.setPropertyValue("CharEscapementHeight", + (byte)58); + } + else if (style.getBooleanCitProperty("SubscriptCitations")) { + xCursorProps.setPropertyValue("CharEscapement", + (byte)-101); + xCursorProps.setPropertyValue("CharEscapementHeight", + (byte)58); + } + else { + xCursorProps.setPropertyValue("CharEscapement", + (byte)0); + xCursorProps.setPropertyValue("CharEscapementHeight", + (byte)0); + } + + xCursorProps.setPropertyValue("CharPosture", + style.isItalicCitations() ? com.sun.star.awt.FontSlant.ITALIC : + com.sun.star.awt.FontSlant.NONE); + xCursorProps.setPropertyValue("CharWeight", + style.isBoldCitations() ? com.sun.star.awt.FontWeight.BOLD : + com.sun.star.awt.FontWeight.NORMAL); + + } + } + else + position.setString(""); + + + position.getText().insertTextContent(position, xTextContent, true); + } + position.collapseToEnd(); + + } + + public void testFootnote() throws Exception { + XTextViewCursor xViewCursor = xViewCursorSupplier.getViewCursor(); + insertFootnote("jabbes", "Cite text", xViewCursor); + } + + public void insertFootnote(String name, String citText, XTextCursor position) throws Exception { + XFootnote xFootnote = (XFootnote) UnoRuntime.queryInterface( XFootnote.class, + mxDocFactory.createInstance("com.sun.star.text.Footnote")); + xFootnote.setLabel(""); + XPropertySet props = (XPropertySet)UnoRuntime.queryInterface(XPropertySet.class, xFootnote); + props.setPropertyValue("ReferenceId", name); // doesn't work: short data type + System.out.println(props.getPropertyValue("ReferenceId")); + XTextContent xContent = (XTextContent)UnoRuntime.queryInterface( + XTextContent.class, xFootnote); + text.insertTextContent (position, xContent, false); + XSimpleText xSimple = (XSimpleText)UnoRuntime.queryInterface(XSimpleText.class, xFootnote); + XTextRange xRange = (XTextRange)UnoRuntime.queryInterface(XTextRange.class, xSimple.createTextCursor()); + xSimple.insertString (xRange, citText, false); + } + + public void removeBookMark(String name) throws Exception { + XBookmarksSupplier xBookmarksSupplier = (XBookmarksSupplier) UnoRuntime.queryInterface( + XBookmarksSupplier.class, xCurrentComponent); + if (xBookmarksSupplier.getBookmarks().hasByName(name)) { + Object o = xBookmarksSupplier.getBookmarks().getByName(name); + XTextContent bm = (XTextContent) UnoRuntime.queryInterface( + XTextContent.class, o); + text.removeTextContent(bm); + } + } + + public void removeReferenceMark(String name) throws Exception { + XReferenceMarksSupplier xSupplier = (XReferenceMarksSupplier) UnoRuntime.queryInterface( + XReferenceMarksSupplier.class, xCurrentComponent); + if (xSupplier.getReferenceMarks().hasByName(name)) { + Object o = xSupplier.getReferenceMarks().getByName(name); + XTextContent bm = (XTextContent) UnoRuntime.queryInterface( + XTextContent.class, o); + text.removeTextContent(bm); + } + } + + /** + * Get the XTextRange corresponding to the named bookmark. + * @param name The name of the bookmark to find. + * @return The XTextRange for the bookmark. + * @throws Exception + */ + public XTextRange getBookmarkRange(String name) throws Exception { + // query XBookmarksSupplier from document model and get bookmarks collection + XBookmarksSupplier xBookmarksSupplier = (XBookmarksSupplier) UnoRuntime.queryInterface( + XBookmarksSupplier.class, xCurrentComponent); + XNameAccess xNamedBookmarks = xBookmarksSupplier.getBookmarks(); + + // retrieve bookmark by name + //System.out.println("Name="+name+" : "+xNamedBookmarks.hasByName(name)); + if (!xNamedBookmarks.hasByName(name)) + return null; + Object foundBookmark = xNamedBookmarks.getByName(name); + XTextContent xFoundBookmark = (XTextContent) UnoRuntime.queryInterface( + XTextContent.class, foundBookmark); + return xFoundBookmark.getAnchor(); + } + + public void printBookmarkNames() throws Exception { + XBookmarksSupplier xBookmarksSupplier = (XBookmarksSupplier) UnoRuntime.queryInterface( + XBookmarksSupplier.class, xCurrentComponent); + XNameAccess xNamedBookmarks = xBookmarksSupplier.getBookmarks(); + String[] names = xNamedBookmarks.getElementNames(); + for (int i = 0; i < names.length; i++) { + System.out.println(i+". "+names[i]); + } + } + + + /** + * Focus the active OO document. + */ + public void setFocus() { + xDesktop.getCurrentFrame().getContainerWindow().setFocus(); + } + + + public void combineCiteMarkers(BibtexDatabase database, OOBibStyle style) throws Exception { + XReferenceMarksSupplier supplier = (XReferenceMarksSupplier) UnoRuntime.queryInterface( + XReferenceMarksSupplier.class, xCurrentComponent); + XNameAccess nameAccess = supplier.getReferenceMarks(); + // TODO: doesn't work for citations in footnotes/tables + String[] names = getSortedReferenceMarks(nameAccess); + + + final XTextRangeCompare compare = (XTextRangeCompare) UnoRuntime.queryInterface + (XTextRangeCompare.class, text); + + int piv = 0; + boolean madeModifications = false; + while (piv < names.length-1) { + XTextRange r1 = ((XTextContent) UnoRuntime.queryInterface + (XTextContent.class, nameAccess.getByName(names[piv]))).getAnchor().getEnd(); + XTextRange r2 = ((XTextContent) UnoRuntime.queryInterface + (XTextContent.class, + nameAccess.getByName(names[piv+1]))).getAnchor().getStart(); + if (r1.getText() != r2.getText()) { + piv++; + continue; + } + XTextCursor mxDocCursor = r1.getText().createTextCursorByRange(r1); + mxDocCursor.goRight((short)1, true); + boolean couldExpand = true; + while (couldExpand && (compare.compareRegionEnds(mxDocCursor, r2) > 0)) { + couldExpand = mxDocCursor.goRight((short)1, true); + } + String text = mxDocCursor.getString(); + // Check if the string contains no line breaks and only whitespace: + if ((text.indexOf('\n') == -1) && (text.trim().length() == 0)) { + List keys = parseRefMarkName(names[piv]); + keys.addAll(parseRefMarkName(names[piv+1])); + removeReferenceMark(names[piv]); + removeReferenceMark(names[piv+1]); + ArrayList entries = new ArrayList(); + for (String key : keys) { + entries.add(OOUtil.createAdaptedEntry(database.getEntryByKey(key))); + } + Collections.sort(entries, new FieldComparator("year")); + StringBuilder sb = new StringBuilder(); + int i=0; + for (BibtexEntry entry : entries) { + if (i > 0) + sb.append(","); + sb.append(entry.getCiteKey()); + i++; + } + String keyString = sb.toString(); + boolean inParenthesis = true; + // Insert bookmark: + String bName = getUniqueReferenceMarkName(keyString, + inParenthesis ? AUTHORYEAR_PAR : AUTHORYEAR_INTEXT); + insertReferenceMark(bName, "tmp", mxDocCursor, true, style); + names[piv+1] = bName; + madeModifications = true; + } + piv++; + } + if (madeModifications) { + updateSortedReferenceMarks(); + refreshCiteMarkers(database, style); + } + + + } + + public void testFrameHandling() throws Exception { + + XController oldController = mxDoc.getCurrentController(); + PropertyValue[] props = new PropertyValue[2]; + + props[0] = new PropertyValue(); + props[0].Name = "Model"; + + props[0].Value = mxDoc.getCurrentController().getModel(); + props[1] = new PropertyValue(); + props[1].Name = "Hidden"; + props[1].Value = true; + + // argument xModel wins over URL. + System.out.println("her"); + XComponent comp = xComponentLoader.loadComponentFromURL("private:factory/swriter", + "_blank", 0, props); + System.out.println("her2"); + + XTextDocument newDoc = (XTextDocument)UnoRuntime.queryInterface( + XTextDocument.class, comp); + System.out.println("newDoc = "+newDoc); + + // Controller of the hidden frame + XController xController = newDoc.getCurrentController(); + + XFrame xFrame = xController.getFrame(); + XWindow xContainerWindow = xFrame.getContainerWindow(); + XWindow xComponentWindow = xFrame.getComponentWindow(); + + //xContainerWindow.setVisible(true); + //xComponentWindow.setFocus(); + //xContainerWindow.setVisible(false); + xFrame.dispose(); + } +} diff --git a/net/sf/jabref/oo/OOBibStyle.java b/net/sf/jabref/oo/OOBibStyle.java new file mode 100755 index 0000000..3cf8b4d --- /dev/null +++ b/net/sf/jabref/oo/OOBibStyle.java @@ -0,0 +1,840 @@ +package net.sf.jabref.oo; + +import net.sf.jabref.AuthorList; +import net.sf.jabref.BibtexDatabase; +import net.sf.jabref.BibtexEntry; +import net.sf.jabref.Globals; +import net.sf.jabref.export.layout.Layout; +import net.sf.jabref.export.layout.LayoutFormatter; +import net.sf.jabref.export.layout.LayoutHelper; +import net.sf.jabref.export.layout.format.RemoveLatexCommands; + +import java.io.*; +import java.util.*; +import java.util.regex.Pattern; + +/** + * This class embodies a bibliography formatting for OpenOffice, which is composed + * of the following elements: + * + * 1) Each OO bib entry type must have a formatting. A formatting is an array of elements, each + * of which is either a piece of constant text, an entry field value, or a tab. Each element has + * a character format associated with it. + * + * 2) Many field values (e.g. author) need to be formatted before input to OpenOffice. The style + * has the responsibility of formatting all field values. Formatting is handled by 0-n + * JabRef LayoutFormatter classes. + * + * 3) If the entries are not numbered, a citation marker must be produced for each entry. This + * operation is performed for each JabRef BibtexEntry. + */ +public class OOBibStyle implements Comparable { + + public static final String UNDEFINED_CITATION_MARKER = "??"; + String name = null; + SortedSet journals = new TreeSet(); + + Layout defaultBibLayout; + // formatters mapped from field names. Each field can have no mapping, or a set of formatters: + HashMap formatters = new HashMap(); + // 0-n formatters applied to all fields before field-speficic formatters: + LayoutFormatter[] allBeforeFormat, allAfterFormat; + // reference layout mapped from entry type number: + HashMap bibLayout = new HashMap(); + + HashMap properties = new HashMap(); + HashMap citProperties = new HashMap(); + + Pattern numPattern = Pattern.compile("-?\\d+"); + + boolean valid = false; + + List juks = new ArrayList(); + + final static int NONE = 0, LAYOUT = 1, PROPERTIES=2, CITATION=3, NAME=4, JOURNALS=5; + final static String LAYOUT_MRK = "LAYOUT", + PROPERTIES_MARK = "PROPERTIES", + CITATION_MARK = "CITATION", + NAME_MARK = "NAME", + JOURNALS_MARK = "JOURNALS", + DEFAULT_MARK = "default"; + private File styleFile = null; + private static long styleFileModificationTime = Long.MIN_VALUE; + private String COMBINED_ENTRIES_SEPARATOR = "-"; + + public OOBibStyle(File styleFile) throws Exception { + this(new FileReader(styleFile)); + this.styleFile = styleFile; + styleFileModificationTime = (styleFile).lastModified(); + } + + public OOBibStyle(Reader in) throws Exception { + + // Set default property values: + properties.put("Title", "Bibliography"); + properties.put("SortAlgorithm", "alphanumeric"); + properties.put("IsSortByPosition", Boolean.FALSE); + properties.put("IsNumberEntries", Boolean.FALSE); + properties.put("BracketBefore", "["); + properties.put("BracketAfter", "]"); + properties.put("ReferenceParagraphFormat", "Default"); + properties.put("ReferenceHeaderParagraphFormat", "Heading 1"); + + // Set default properties for the citation marker: + citProperties.put("AuthorField", "author/editor"); + citProperties.put("YearField", "year"); + citProperties.put("MaxAuthors", 3); + citProperties.put("MaxAuthorsFirst", -1); + citProperties.put("AuthorSeparator", ", "); + citProperties.put("AuthorLastSeparator", " & "); + citProperties.put("AuthorLastSeparatorInText", null); + citProperties.put("EtAlString", " et al."); + citProperties.put("YearSeparator", ", "); + citProperties.put("InTextYearSeparator", " "); + citProperties.put("BracketBefore", "("); + citProperties.put("BracketAfter", ")"); + citProperties.put("CitationSeparator", "; "); + citProperties.put("GroupedNumbersSeparator", "-"); + citProperties.put("MinimumGroupingCount", 3); + citProperties.put("FormatCitations", Boolean.FALSE); + citProperties.put("ItalicCitations", Boolean.FALSE); + citProperties.put("BoldCitations", Boolean.FALSE); + citProperties.put("SuperscriptCitations", Boolean.FALSE); + citProperties.put("SubscriptCitations", Boolean.FALSE); + citProperties.put("MultiCiteChronological", Boolean.TRUE); + + initialize(in); + + + } + + public String getName() { + return name; + } + + public File getFile() { + return styleFile; + } + + public Set getJournals() { + return Collections.unmodifiableSet(journals); + } + + private void initialize(Reader in) throws IOException { + name = null; + readFormatFile(in); + allBeforeFormat = new LayoutFormatter[] {new RemoveLatexCommands()}; + } + + /** + * If this style was initialized from a file on disk, reload the style + * if the file has been modified since it was read. + * @throws Exception + */ + public void ensureUpToDate() throws Exception { + if (!isUpToDate()) + reload(); + } + + /** + * If this style was initialized from a file on disk, reload the style + * information. + * @throws Exception + */ + public void reload() throws Exception { + if (styleFile != null) { + styleFileModificationTime = (styleFile).lastModified(); + initialize(new FileReader(styleFile)); + } + } + + /** + * If this style was initialized from a file on disk, check whether the file + * is unmodified since initialization. + * @return true if the file has not been modified, false otherwise. + */ + public boolean isUpToDate() { + if (styleFile != null) { + return styleFile.lastModified() == styleFileModificationTime; + } + else return true; + } + + private void readFormatFile(Reader in) throws IOException { + + // First read all the contents of the file: + StringBuffer sb = new StringBuffer(); + int c; + while ((c = in.read()) != -1) { + sb.append((char)c); + } + // Break into separate lines: + String[] lines = sb.toString().split("\n"); + int mode = NONE; + + for (int i = 0; i < lines.length; i++) { + String line = lines[i]; + // Check for empty line or comment: + if ((line.trim().length() == 0) || (line.charAt(0) == '#')) + continue; + // Check if we should change mode: + if (line.equals(NAME_MARK)) { + mode = NAME; + continue; + } + else if (line.equals(LAYOUT_MRK)) { + mode = LAYOUT; + continue; + } + else if (line.equals(PROPERTIES_MARK)) { + mode = PROPERTIES; + continue; + } + else if (line.equals(CITATION_MARK)) { + mode = CITATION; + continue; + } + else if (line.equals(JOURNALS_MARK)) { + mode = JOURNALS; + continue; + } + + switch (mode) { + case NAME: + if (line.trim().length() > 0) + name = line.trim(); + case LAYOUT: + handleStructureLine(line); + break; + case PROPERTIES: + handlePropertiesLine(line, properties); + break; + case CITATION: + handlePropertiesLine(line, citProperties); + break; + case JOURNALS: + handleJournalsLine(line); + } + + } + + // Set validity boolean based on whether we found anything interesting + // in the file: + if (mode != NONE) + valid = true; + + } + + /** + * After initalizing this style from a file, this method can be used to check + * whether the file appeared to be a proper style file. + * @return true if the file could be parsed as a style file, false otherwise. + */ + public boolean isValid() { + return valid; + } + + + /** + * Parse a line providing bibliography structure information for an entry type. + * @param line The string containing the structure description. + * @throws IOException + */ + private void handleStructureLine(String line) throws IOException { + int index = line.indexOf("="); + if ((index > 0) && (index < line.length()-1)) { + String formatString = line.substring(index+1); + //System.out.println("'"+line.substring(0, index)+"' : '"+formatString+"'"); + boolean setDefault = line.substring(0, index).equals(DEFAULT_MARK); + String type = line.substring(0, index); + Short typeS; + try { + /*typeS = new Short(Short.parseShort(type)); + OOBibFormatParser parser = new OOBibFormatParser(new StringReader(formatString)); + PropertyValue[][] layout = parser.parse();*/ + Layout layout = new LayoutHelper(new StringReader(formatString)). + getLayoutFromText(Globals.FORMATTER_PACKAGE); + if (setDefault) + defaultBibLayout = layout; + else + bibLayout.put(type.toLowerCase(), layout); + + } catch (Exception ex) { + ex.printStackTrace(); + + } + } + } + + + /** + * Parse a line providing a property name and value. + * @param line The line containing the formatter names. + * @throws IOException + */ + private void handlePropertiesLine(String line, HashMap map) throws IOException { + int index = line.indexOf("="); + if ((index > 0) && (index <= line.length()-1)) { + String propertyName = line.substring(0, index).trim(); + String value = line.substring(index+1); + Object toSet = value; + if (numPattern.matcher(value).matches()) { + toSet = Integer.parseInt(value); + } + else if (value.toLowerCase().trim().equals("true")) + toSet = Boolean.TRUE; + else if (value.toLowerCase().trim().equals("false")) + toSet = Boolean.FALSE; + map.put(propertyName, toSet); + } + } + + /** + * Parse a line providing a journal name for which this style is valid. + * @param line + * @throws IOException + */ + private void handleJournalsLine(String line) throws IOException { + if (line.trim().length() > 0) + journals.add(line.trim()); + } + + public Layout getReferenceFormat(String type) { + Layout l = bibLayout.get(type.toLowerCase()); + if (l != null) + return l; + else + return defaultBibLayout; + } + + /** + * Get the array of elements composing the reference for a given entry type. + * @param bibType The OO type number. + * @return The format definition. + + public PropertyValue[][] getReferenceFormat(short bibType) { + Object o = bibLayout.get(new Short(bibType)); + if (o != null) + return (PropertyValue[][])o; + else + return defaultBibLayout; + }*/ + + /** + * Format the given field value based on the rules of this bib style. + * @param field The name of the field. + * @param content The unformatted field content. + * @return The formatted field value. + */ + public String formatField(String field, String content) { + if (allBeforeFormat != null) + for (int i = 0; i < allBeforeFormat.length; i++) { + LayoutFormatter formatter = allBeforeFormat[i]; + content = formatter.format(content); + } + + Object o = formatters.get(field); + if (o == null) + return content; + LayoutFormatter[] form = (LayoutFormatter[])o; + for (int i = 0; i < form.length; i++) { + LayoutFormatter formatter = form[i]; + content = formatter.format(content); + } + + if (allAfterFormat != null) + for (int i = 0; i < allAfterFormat.length; i++) { + LayoutFormatter formatter = allAfterFormat[i]; + content = formatter.format(content); + } + + return content; + } + + /** + * Format a number-based citation marker for the given number. + * @param number The citation numbers. + * @return The text for the citation. + */ + public String getNumCitationMarker(int[] number, int minGroupingCount, boolean inList) { + String bracketBefore = (String)citProperties.get("BracketBefore"); + if (inList && (citProperties.get("BracketBeforeInList")!=null)) { + bracketBefore = (String)citProperties.get("BracketBeforeInList"); + } + String bracketAfter = (String)citProperties.get("BracketAfter"); + if (inList && (citProperties.get("BracketAfterInList")!=null)) { + bracketAfter = (String)citProperties.get("BracketAfterInList"); + } + // Sort the numbers: + int[] lNum = new int[number.length]; + for (int i = 0; i < lNum.length; i++) { + lNum[i] = number[i]; + + } + //Arrays.copyOf(number, number.length); + Arrays.sort(lNum); + StringBuilder sb = new StringBuilder(bracketBefore); + int combineFrom = -1, written = 0; + for (int i = 0; i < lNum.length; i++) { + int i1 = lNum[i]; + if (combineFrom < 0) { + // Check if next entry is the next in the ref list: + if ((i < lNum.length-1) && (lNum[i+1] == i1+1)) + combineFrom = i1; + else { + // Add single entry: + if (i>0) + sb.append((String)citProperties.get("CitationSeparator")); + sb.append(lNum[i] > 0 ? String.valueOf(lNum[i]) : UNDEFINED_CITATION_MARKER); + written++; + } + } else { + // We are building a list of combined entries. + // Check if it ends here: + if ((i == lNum.length-1) || (lNum[i+1] != i1+1)) { + if (written>0) + sb.append((String)citProperties.get("CitationSeparator")); + if ((minGroupingCount > 0) && (i1+1-combineFrom >= minGroupingCount)) { + sb.append(combineFrom); + sb.append((String)citProperties.get("GroupedNumbersSeparator")); + sb.append(i1); + written++; + } + else { + // Either we should never group, or there aren't enough + // entries in this case to group. Output all: + for (int jj=combineFrom; jj<=i1; jj++) { + sb.append(jj); + if (jj < i1) + sb.append((String)citProperties.get("CitationSeparator")); + written++; + } + } + combineFrom = -1; + + } + // If it doesn't end here, just keep iterating. + } + + } + sb.append(bracketAfter); + return sb.toString(); + } + + /** + * Format the marker for the in-text citation according to this bib style. + * + * @param entry The JabRef BibtexEntry providing the data. + * @param inParenthesis Signals whether a parenthesized citation or an in-text citation is wanted. + * @param uniquefier String to add behind the year in case it's needed to separate similar + * entries. + * @return The formatted citation. + */ + public String getCitationMarker(BibtexEntry entry, BibtexDatabase database, boolean inParenthesis, + String uniquefier, int unlimAuthors) { + return getCitationMarker(new BibtexEntry[] {entry}, database, inParenthesis, new String[] {uniquefier}, + new int[] {unlimAuthors}); + } + + /** + * Format the marker for the in-text citation according to this bib style. Uniquefier letters are added as + * provided by the uniquefiers argument. If successive entries within the citation are uniquefied from each other, + * this method will perform a grouping of these entries. + * + * @param entries The array of JabRef BibtexEntry providing the data. + * @param inParenthesis Signals whether a parenthesized citation or an in-text citation is wanted. + * @param uniquefiers Strings to add behind the year for each entry in case it's needed to separate similar + * entries. + * @param unlimAuthors Boolean for each entry. If true, we should not use "et al" formatting regardless + * of the number of authors. Can be null to indicate that no entries should have unlimited names. + * @return The formatted citation. + */ + public String getCitationMarker(BibtexEntry[] entries, BibtexDatabase database, boolean inParenthesis, + String[] uniquefiers, int[] unlimAuthors) { + + // Look for groups of uniquefied entries that should be combined in the output. + // E.g. (Olsen, 2005a, b) should be output instead of (Olsen, 2005a; Olsen, 2005b). + int piv = -1; + String tmpMarker = null; + if (uniquefiers != null) { + for (int i = 0; i < uniquefiers.length; i++) { + + if ((uniquefiers[i] != null) && (uniquefiers[i].length() > 0)) { + String authorField = (String)citProperties.get("AuthorField"); + int maxAuthors = (Integer)citProperties.get("MaxAuthors"); + if (piv == -1) { + piv = i; + tmpMarker = getAuthorYearParenthesisMarker(new BibtexEntry[] {entries[i]}, database, + authorField, + (String)citProperties.get("YearField"), + maxAuthors, + (String)citProperties.get("AuthorSeparator"), + (String)citProperties.get("AuthorLastSeparator"), + (String)citProperties.get("EtAlString"), + (String)citProperties.get("YearSeparator"), + (String)citProperties.get("BracketBefore"), + (String)citProperties.get("BracketAfter"), + (String)citProperties.get("CitationSeparator"), null, unlimAuthors); + //System.out.println("piv="+piv+" tmpMarker='"+tmpMarker+"'"); + } + else { + // See if this entry can go into a group with the previous one: + String thisMarker = getAuthorYearParenthesisMarker(new BibtexEntry[] {entries[i]}, database, + authorField, + (String)citProperties.get("YearField"), + maxAuthors, + (String)citProperties.get("AuthorSeparator"), + (String)citProperties.get("AuthorLastSeparator"), + (String)citProperties.get("EtAlString"), + (String)citProperties.get("YearSeparator"), + (String)citProperties.get("BracketBefore"), + (String)citProperties.get("BracketAfter"), + (String)citProperties.get("CitationSeparator"), null, unlimAuthors); + + String author = getCitationMarkerField(entries[i], database, + authorField); + AuthorList al = AuthorList.getAuthorList(author); + //System.out.println("i="+i+" thisMarker='"+thisMarker+"'"); + int prevALim = i > 0 ? unlimAuthors[i-1] : unlimAuthors[0]; + if (!thisMarker.equals(tmpMarker) || + ((al.size() > maxAuthors) && (unlimAuthors[i] != prevALim))) { + // No match. Update piv to exclude the previous entry. But first check if the + // previous entry was part of a group: + if ((piv > -1) && (i > piv+1)) { + // Do the grouping: + group(entries, uniquefiers, piv, i-1, (String)citProperties.get("UniquefierSeparator")); + } + tmpMarker = thisMarker; + piv = i; + } + } + } + else { + // This entry has no uniquefier. + // Check if we just passed a group of more than one entry with uniquefier: + if ((piv > -1) && (i > piv+1)) { + // Do the grouping: + group(entries, uniquefiers, piv, i-1, (String)citProperties.get("UniquefierSeparator")); + } + + piv = -1; + } + + } + // Finished with the loop. See if the last entries form a group: + if (piv >= 0) { + // Do the grouping: + group(entries, uniquefiers, piv, uniquefiers.length-1, (String)citProperties.get("UniquefierSeparator")); + } + } + + if (inParenthesis) + return getAuthorYearParenthesisMarker(entries, database, + (String)citProperties.get("AuthorField"), + (String)citProperties.get("YearField"), + (Integer)citProperties.get("MaxAuthors"), + (String)citProperties.get("AuthorSeparator"), + (String)citProperties.get("AuthorLastSeparator"), + (String)citProperties.get("EtAlString"), + (String)citProperties.get("YearSeparator"), + (String)citProperties.get("BracketBefore"), + (String)citProperties.get("BracketAfter"), + (String)citProperties.get("CitationSeparator"), + uniquefiers, unlimAuthors); + else { + String authorLastSeparator = (String)citProperties.get("AuthorLastSeparator"); + String alsInText = (String)citProperties.get("AuthorLastSeparatorInText"); + if (alsInText != null) + authorLastSeparator = alsInText; + return getAuthorYearInTextMarker(entries, database, + (String)citProperties.get("AuthorField"), + (String)citProperties.get("YearField"), + (Integer)citProperties.get("MaxAuthors"), + (String)citProperties.get("AuthorSeparator"), + authorLastSeparator, + (String)citProperties.get("EtAlString"), + (String)citProperties.get("InTextYearSeparator"), + (String)citProperties.get("BracketBefore"), + (String)citProperties.get("BracketAfter"), + (String)citProperties.get("CitationSeparator"), + uniquefiers, unlimAuthors); + } + } + + /** + * Modify entry and uniqiefier arrays to facilitate a grouped presentation of uniqiefied entries. + * @param entries The entry array. + * @param uniquefiers The uniquefier array. + * @param from The first index to group (inclusive) + * @param to The last index to group (inclusive) + * @param separator The separator for the uniquefier letters. + */ + private void group(BibtexEntry[] entries, String[] uniquefiers, int from, int to, String separator) { + StringBuilder sb = new StringBuilder(uniquefiers[from]); + for (int i=from+1; i<=to; i++) { + sb.append(separator); + sb.append(uniquefiers[i]); + entries[i] = null; + } + uniquefiers[from] = sb.toString(); + } + + /** + * This method produces (Author, year) style citation strings in many different forms. + * + * @param entries The array of BibtexEntry to get fields from. + * @param authorField The bibtex field providing author names, e.g. "author" or "editor". + * @param yearField The bibtex field providing the year, e.g. "year". + * @param maxA The maximum number of authors to write out in full without using etal. Set to + * -1 to always write out all authors. + * @param authorSep The String to add between author names except the last two, e.g. ", ". + * @param andString The String to add between the two last author names, e.g. " & ". + * @param etAlString The String to represent authors that are not mentioned, e.g. " et al." + * @param yearSep The String to separate authors from year, e.g. "; ". + * @param startBrace The opening parenthesis. + * @param endBrace The closing parenthesis. + * @param citationSeparator The String to separate citations from each other. + * @param uniquifiers Optional parameter to separate similar citations. Elements can be null if not needed. + * @return The formatted citation. + */ + public String getAuthorYearParenthesisMarker(BibtexEntry[] entries, BibtexDatabase database, + String authorField, String yearField, + int maxA, String authorSep, + String andString, String etAlString, String yearSep, + String startBrace, String endBrace, String citationSeparator, + String[] uniquifiers, int[] unlimAuthors) { + + + StringBuffer sb = new StringBuffer(startBrace); + for (int j=0; j 0 ? unlimA : maxA; + + BibtexEntry entry = entries[j]; + + // Check if this entry has been nulled due to grouping with the previous entry(ies): + if (entry == null) + continue; + + if (j > 0) + sb.append(citationSeparator); + + String author = getCitationMarkerField(entry, database, authorField); + + if (author != null) { + AuthorList al = AuthorList.getAuthorList(author); + sb.append(getAuthorLastName(al, 0)); + + if ((al.size() > 1) && ((al.size() <= maxAuthors) || (maxAuthors < 0))) { + int i=1; + while (i < al.size()-1) { + sb.append(authorSep); + sb.append(getAuthorLastName(al, i)); + i++; + } + sb.append(andString); + sb.append(getAuthorLastName(al, al.size()-1)); + } else if (al.size() > maxAuthors) { + sb.append(etAlString); + } + sb.append(yearSep); + } + String year = getCitationMarkerField(entry, database, yearField); + if (year != null) + sb.append(year); + if ((uniquifiers != null) && (uniquifiers[j] != null)) + sb.append(uniquifiers[j]); + } + sb.append(endBrace); + return sb.toString(); + + } + + /** + * This method produces "Author (year)" style citation strings in many different forms. + * + * @param entries The array of BibtexEntry to get fields from. + * @param authorField The bibtex field providing author names, e.g. "author" or "editor". + * @param yearField The bibtex field providing the year, e.g. "year". + * @param maxA The maximum number of authors to write out in full without using etal. Set to + * -1 to always write out all authors. + * @param authorSep The String to add between author names except the last two, e.g. ", ". + * @param andString The String to add between the two last author names, e.g. " & ". + * @param etAlString The String to represent authors that are not mentioned, e.g. " et al." + * @param yearSep The String to separate authors from year, e.g. "; ". + * @param startBrace The opening parenthesis. + * @param endBrace The closing parenthesis. + * @param uniquefiers Optional parameters to separate similar citations. Can be null if not needed. + * @return The formatted citation. + */ + public String getAuthorYearInTextMarker(BibtexEntry[] entries, BibtexDatabase database, String authorField, + String yearField, int maxA, String authorSep, + String andString, String etAlString, String yearSep, + String startBrace, String endBrace, String citationSeparator, + String[] uniquefiers, int[] unlimAuthors) { + StringBuffer sb = new StringBuffer(); + for (int i=0; i 0 ? unlimA : maxA; + + // Check if this entry has been nulled due to grouping with the previous entry(ies): + if (entries[i] == null) + continue; + + if (i > 0) + sb.append(citationSeparator); + String author = getCitationMarkerField(entries[i], database, authorField); + if (author != null) { + AuthorList al = AuthorList.getAuthorList(author); + if (al.size() > 0) + sb.append(getAuthorLastName(al, 0)); + if ((al.size() > 1) && ((al.size() <= maxAuthors) || (maxAuthors < 0))) { + int j=1; + while (j < al.size()-1) { + sb.append(authorSep); + sb.append(getAuthorLastName(al, j)); + j++; + } + sb.append(andString); + sb.append(getAuthorLastName(al, al.size()-1)); + } else if (al.size() > maxAuthors) { + sb.append(etAlString); + } + sb.append(yearSep); + } + sb.append(startBrace); + String year = getCitationMarkerField(entries[i], database, yearField); + if (year != null) + sb.append(year); + if ((uniquefiers != null) && (uniquefiers[i] != null)) + sb.append(uniquefiers[i]); + sb.append(endBrace); + } + return sb.toString(); + + } + + /** + * This method looks up a field for en entry in a database. Any number of backup fields can be used + * if the primary field is empty. + * @param entry The entry. + * @param database The database the entry belongs to. + * @param field The field, or succession of fields, to look up. If backup fields are needed, separate + * field names by /. E.g. to use "author" with "editor" as backup, specify "author/editor". + * @return The resolved field content, or an empty string if the field(s) were empty. + */ + public String getCitationMarkerField(BibtexEntry entry, BibtexDatabase database, String field) { + String[] fields = field.split("/"); + for (int i = 0; i < fields.length; i++) { + String s = fields[i]; + String content = BibtexDatabase.getResolvedField(s, entry, database); + if ((content != null) && (content.trim().length() > 0)) + return content; + } + // No luck? Return an empty string: + return ""; + } + + /** + * Look up the nth author and return the proper last name for citation markers. + * @param al The author list. + * @param number The number of the author to return. + * @return The author name, or an empty String if inapplicable. + */ + public String getAuthorLastName(AuthorList al, int number) { + StringBuilder sb = new StringBuilder(); + + if (al.size() > number) { + AuthorList.Author a = al.getAuthor(number); + if ((a.getVon() != null) && a.getVon().length() > 0) { + String von = a.getVon(); + sb.append(von); + /*sb.append(von.substring(0, 1).toUpperCase()); + if (von.length() > 1) + sb.append(von.substring(1));*/ + sb.append(' '); + } + sb.append(a.getLast()); + } + + return sb.toString(); + } + + /** + * Convenience method for checking the property for whether we use number citations or + * author-year citations. + * @return true if we use numbered citations, false otherwise. + */ + public boolean isNumberEntries() { + return (Boolean)getProperty("IsNumberEntries"); + } + + /** + * Convenience method for checking the property for whether we sort the bibliography + * according to their order of appearance in the text. + * @return true to sort by appearance, false to sort alphabetically. + */ + public boolean isSortByPosition() { + return (Boolean)getProperty("IsSortByPosition"); + } + + /** + * Convenience method for checking whether citation markers should be italicised. + * Will only be relevant if isFormatCitations() returns true. + * @return true to indicate that citations should be in italics. + */ + public boolean isItalicCitations() { + return (Boolean)citProperties.get("ItalicCitations"); + } + + /** + * Convenience method for checking whether citation markers should be bold. + * Will only be relevant if isFormatCitations() returns true. + * @return true to indicate that citations should be in bold. + */ + public boolean isBoldCitations() { + return (Boolean)citProperties.get("BoldCitations"); + } + + /** + * Convenience method for checking whether citation markers formatted + * according to the results of the isItalicCitations() and + * isBoldCitations() methods. + * @return true to indicate that citations should be in italics. + */ + public boolean isFormatCitations() { + return (Boolean)citProperties.get("FormatCitations"); + } + + /** + * Get boolean property. + * @param key The property key + * @return the value + */ + public boolean getBooleanCitProperty(String key) { + return (Boolean)citProperties.get(key); + } + + public int getIntCitProperty(String key) { + return (Integer)citProperties.get(key); + } + /** + * Get a style property. + * @param name The property name. + * @return The property value, or null if it doesn't exist. + */ + public Object getProperty(String name) { + return properties.get(name); + } + + public int compareTo(Object o) { + OOBibStyle other = (OOBibStyle)o; + return getName().compareTo(other.getName()); + } + + public boolean equals(Object o) { + return styleFile.equals(((OOBibStyle)o).styleFile); + } +} diff --git a/net/sf/jabref/oo/OOUtil.java b/net/sf/jabref/oo/OOUtil.java new file mode 100755 index 0000000..c2ca2e5 --- /dev/null +++ b/net/sf/jabref/oo/OOUtil.java @@ -0,0 +1,285 @@ +package net.sf.jabref.oo; + +import com.sun.star.beans.XPropertySet; +import com.sun.star.beans.Property; +import com.sun.star.text.*; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.frame.XDesktop; +import net.sf.jabref.BibtexDatabase; +import net.sf.jabref.BibtexEntry; +import net.sf.jabref.Globals; +import net.sf.jabref.BibtexFields; +import net.sf.jabref.export.layout.Layout; + +import javax.swing.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.List; +import java.util.Iterator; + +/** + * Utility methods for processing OO Writer documents. + */ +public class OOUtil { + + + static Pattern htmlTag = Pattern.compile(""); + + static OOPreFormatter postformatter = new OOPreFormatter(); + + /** + * Insert a reference, formatted using a Layout, at the position of a given cursor. + * @param text The text to insert in. + * @param cursor The cursor giving the insert location. + * @param layout The Layout to format the reference with. + * @param parStyle The name of the paragraph style to use. + * @param entry The entry to insert. + * @param database The database the entry belongs to. + * @param uniquefier Uniqiefier letter, if any, to append to the entry's year. + * @throws Exception + */ + public static void insertFullReferenceAtCurrentLocation(XText text, XTextCursor cursor, + Layout layout, String parStyle, BibtexEntry entry, BibtexDatabase database, String uniquefier) + throws UndefinedParagraphFormatException, Exception { + + final String UNIQUEFIER_FIELD = "uniq"; + + // Backup the value of the uniq field, just in case the entry already has it: + String oldUniqVal = (String)entry.getField(UNIQUEFIER_FIELD); + + // Set the uniq field with the supplied uniquefier: + entry.setField(UNIQUEFIER_FIELD, uniquefier); + + // Do the layout for this entry: + String lText = layout.doLayout(entry, database); + + // Afterwards, reset the old value: + entry.setField(UNIQUEFIER_FIELD, oldUniqVal); + + // Insert the formatted text: + insertOOFormattedTextAtCurrentLocation(text, cursor, lText, parStyle); + } + + /** + * Insert a text with formatting indicated by HTML-like tags, into a text at + * the position given by a cursor. + * @param text The text to insert in. + * @param cursor The cursor giving the insert location. + * @param lText The marked-up text to insert. + * @param parStyle The name of the paragraph style to use. + * @throws Exception + */ + public static void insertOOFormattedTextAtCurrentLocation(XText text, XTextCursor cursor, + String lText, String parStyle) throws UndefinedParagraphFormatException, Exception { + + XParagraphCursor parCursor = (XParagraphCursor)UnoRuntime.queryInterface( + XParagraphCursor.class, cursor); + XPropertySet props = (XPropertySet) UnoRuntime.queryInterface( + XPropertySet.class, parCursor); + + try { + props.setPropertyValue("ParaStyleName", parStyle); + } catch (com.sun.star.lang.IllegalArgumentException ex) { + throw new UndefinedParagraphFormatException(parStyle); + } + + // We need to extract formatting. Use a simple regexp search iteration: + int piv = 0; + int italic = 0, bold = 0, sup = 0, sub = 0, mono = 0, smallCaps = 0; + //insertTextAtCurrentLocation(text, cursor, "_", + // false, false, false, false, false, false); + //cursor.goLeft((short)1, true); + Matcher m = htmlTag.matcher(lText); + while (m.find()) { + String ss = lText.substring(piv, m.start()); + if (ss.length() > 0) { + insertTextAtCurrentLocation(text, cursor, ss, (bold % 2) > 0, (italic % 2) > 0, + mono > 0, smallCaps > 0, sup > 0, sub > 0); + } + String tag = m.group(); + // Handle tags: + if (tag.equals("")) + bold++; + else if (tag.equals("")) + bold--; + else if (tag.equals("") || tag.equals("")) + italic++; + else if (tag.equals("") || tag.equals("")) + italic--; + else if (tag.equals("")) + mono = 0; + else if (tag.equals("")) + mono = 1; + else if (tag.equals("
")) + smallCaps = 0; + else if (tag.equals("")) + smallCaps = 1; + else if (tag.equals("")) + sup = 0; + else if (tag.equals("")) + sup = 1; + else if (tag.equals("")) + sub = 0; + else if (tag.equals("")) + sub = 1; + + piv = m.end(); + + } + + if (piv < lText.length()) + insertTextAtCurrentLocation(text, cursor,lText.substring(piv), + (bold % 2) > 0, (italic % 2) > 0, mono > 0, smallCaps > 0, sup > 0, sub > 0); + + + + cursor.collapseToEnd(); + } + + public static void insertParagraphBreak(XText text, XTextCursor cursor) throws Exception { + text.insertControlCharacter(cursor, ControlCharacter.PARAGRAPH_BREAK, true); + cursor.collapseToEnd(); + } + + public static void insertTextAtCurrentLocation(XText text, XTextCursor cursor, String string, + boolean bold, boolean italic, boolean monospace, boolean smallCaps, boolean superscript, + boolean subscript) throws Exception { + text.insertString(cursor, string, true); + // Access the property set of the cursor, and set the currently selected text + // (which is the string we just inserted) to be bold + XPropertySet xCursorProps = (XPropertySet) UnoRuntime.queryInterface( + XPropertySet.class, cursor); + if (bold) + xCursorProps.setPropertyValue("CharWeight", + new Float(com.sun.star.awt.FontWeight.BOLD)); + else + xCursorProps.setPropertyValue("CharWeight", + new Float(com.sun.star.awt.FontWeight.NORMAL)); + + if (italic) + xCursorProps.setPropertyValue("CharPosture", + com.sun.star.awt.FontSlant.ITALIC); + else + xCursorProps.setPropertyValue("CharPosture", + com.sun.star.awt.FontSlant.NONE); + + if (smallCaps) { + xCursorProps.setPropertyValue("CharCaseMap", + com.sun.star.style.CaseMap.SMALLCAPS); + } + else { + xCursorProps.setPropertyValue("CharCaseMap", + com.sun.star.style.CaseMap.NONE); + } + + // TODO: the tag doesn't work + /* + if (monospace) { + xCursorProps.setPropertyValue("CharFontPitch", + com.sun.star.awt.FontPitch.FIXED); + } + else { + xCursorProps.setPropertyValue("CharFontPitch", + com.sun.star.awt.FontPitch.VARIABLE); + } */ + if (subscript) { + xCursorProps.setPropertyValue("CharEscapement", + (byte)-101); + xCursorProps.setPropertyValue("CharEscapementHeight", + (byte)58); + } + else if (superscript) { + xCursorProps.setPropertyValue("CharEscapement", + (byte)101); + xCursorProps.setPropertyValue("CharEscapementHeight", + (byte)58); + } + else { + xCursorProps.setPropertyValue("CharEscapement", + (byte)0); + xCursorProps.setPropertyValue("CharEscapementHeight", + (byte)100); + } + + cursor.collapseToEnd(); + + } + + public static void insertTextAtCurrentLocation(XText text, XTextCursor cursor, String string, + String parStyle) throws Exception { + text.insertString(cursor, string, true); + XParagraphCursor parCursor = (XParagraphCursor)UnoRuntime.queryInterface( + XParagraphCursor.class, cursor); + // Access the property set of the cursor, and set the currently selected text + // (which is the string we just inserted) to be bold + XPropertySet props = (XPropertySet) UnoRuntime.queryInterface( + XPropertySet.class, parCursor); + try { + props.setPropertyValue("ParaStyleName", parStyle); + } catch (com.sun.star.lang.IllegalArgumentException ex) { + throw new UndefinedParagraphFormatException(parStyle); + } + cursor.collapseToEnd(); + + } + + + + public static Object getProperty(Object o, String property) throws Exception { + XPropertySet props = (XPropertySet) UnoRuntime.queryInterface( + XPropertySet.class, o); + return props.getPropertyValue(property); + } + + public static void listProperties(Object o) throws Exception { + XPropertySet props = (XPropertySet) UnoRuntime.queryInterface( + XPropertySet.class, o); + Property[] pr = props.getPropertySetInfo().getProperties(); + for (int i = 0; i < pr.length; i++) { + Property property1 = pr[i]; + System.out.println(property1.Name+" : "+props.getPropertyValue(property1.Name)); + } + } + + public static XTextDocument selectComponent(JFrame parent, XDesktop xDesktop, List list) throws Exception { + String[] values = new String[list.size()]; + int ii=0; + for (Iterator iterator = list.iterator(); iterator.hasNext();) { + XTextDocument doc = iterator.next(); + values[ii++] = String.valueOf(getProperty(doc.getCurrentController().getFrame(), "Title")); + } + JList sel = new JList(values); + sel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + sel.setSelectedIndex(0); + int ans = JOptionPane.showConfirmDialog(parent, new JScrollPane(sel), Globals.lang("Select document"), + JOptionPane.OK_CANCEL_OPTION); + if (ans == JOptionPane.OK_OPTION) { + return list.get(sel.getSelectedIndex()); + } + else return null; + } + + /** + * Make a cloned BibtexEntry and do the necessary preprocessing for use by the plugin. + * If the running JabRef version doesn't support post-processing in Layout, this + * preprocessing includes running the OOPreFormatter formatter for all fields except the + * BibTeX key. + * @param entry the original entry + * @return the cloned and processed entry + */ + public static BibtexEntry createAdaptedEntry(BibtexEntry entry) { + if (entry == null) + return null; + BibtexEntry e = (BibtexEntry)entry.clone(); + for (String field : e.getAllFields()) { + if (field.equals(BibtexFields.KEY_FIELD)) + continue; + String value = e.getField(field); + // If the running JabRef version doesn't support post-processing in Layout, + // preprocess fields instead: + if (!OOTestPanel.postLayoutSupported && (value != null)) + e.setField(field, postformatter.format(value)); + } + return e; + } +} diff --git a/plugin.xml b/plugin.xml new file mode 100755 index 0000000..5f967c6 --- /dev/null +++ b/plugin.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- 2.30.2