effb241f33c3e9746882f7c50c60fc15a6c8806f
[debian/jabref.git] / src / java / net / sf / jabref / export / layout / LayoutEntry.java
1 /*
2  Copyright (C) 2003 Morten O. Alver
3  All programs in this directory and
4  subdirectories are published under the GNU General Public License as
5  described below.
6
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or (at
10  your option) any later version.
11
12  This program is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  General Public License for more details.
16
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20  USA
21
22  Further information about the GNU GPL is available at:
23  http://www.gnu.org/copyleft/gpl.ja.html
24
25  */
26 package net.sf.jabref.export.layout;
27
28 import java.util.ArrayList;
29 import java.util.HashMap;
30 import java.util.Map;
31 import java.util.Vector;
32
33 import net.sf.jabref.*;
34 import net.sf.jabref.export.layout.format.plugin.NameFormat;
35 import net.sf.jabref.plugin.PluginCore;
36 import net.sf.jabref.plugin.core.JabRefPlugin;
37 import net.sf.jabref.plugin.core.generated._JabRefPlugin.LayoutFormatterExtension;
38 import wsi.ra.tool.WSITools;
39 import wsi.ra.types.StringInt;
40
41 /**
42  * DOCUMENT ME!
43  * 
44  * @author $author$
45  * @version $Revision: 2488 $
46  */
47 public class LayoutEntry {
48         // ~ Instance fields
49         // ////////////////////////////////////////////////////////
50
51         private LayoutFormatter[] option;
52
53         private String text;
54
55         private LayoutEntry[] layoutEntries;
56
57         private int type;
58
59         private String classPrefix;
60
61         // ~ Constructors
62         // ///////////////////////////////////////////////////////////
63
64         public LayoutEntry(StringInt si, String classPrefix_) throws Exception {
65                 type = si.i;
66                 classPrefix = classPrefix_;
67
68                 if (si.i == LayoutHelper.IS_LAYOUT_TEXT) {
69                         text = si.s;
70                 } else if (si.i == LayoutHelper.IS_SIMPLE_FIELD) {
71                         text = si.s.trim();
72                 } else if (si.i == LayoutHelper.IS_FIELD_START) {
73                 } else if (si.i == LayoutHelper.IS_FIELD_END) {
74                 } else if (si.i == LayoutHelper.IS_OPTION_FIELD) {
75                         Vector<String> v = new Vector<String>();
76                         WSITools.tokenize(v, si.s, "\n");
77
78                         if (v.size() == 1) {
79                                 text = v.get(0);
80                         } else {
81                                 text = v.get(0).trim();
82
83                                 option = getOptionalLayout(v.get(1), classPrefix);
84                         }
85                 }
86         }
87
88         public LayoutEntry(Vector<StringInt> parsedEntries, String classPrefix_, int layoutType) throws Exception {
89                 classPrefix = classPrefix_;
90                 String blockStart = null;
91                 String blockEnd = null;
92                 StringInt si;
93                 Vector<StringInt> blockEntries = null;
94                 Vector<LayoutEntry> tmpEntries = new Vector<LayoutEntry>();
95                 LayoutEntry le;
96                 si = parsedEntries.get(0);
97                 blockStart = si.s;
98                 si = parsedEntries.get(parsedEntries.size() - 1);
99                 blockEnd = si.s;
100
101                 if (!blockStart.equals(blockEnd)) {
102                         System.err.println("Field start and end entry must be equal.");
103                 }
104
105                 type = layoutType;
106                 text = si.s;
107
108                 for (int i = 1; i < (parsedEntries.size() - 1); i++) {
109                         si = parsedEntries.get(i);
110
111                         // System.out.println("PARSED-ENTRY: "+si.s+"="+si.i);
112                         if (si.i == LayoutHelper.IS_LAYOUT_TEXT) {
113                         } else if (si.i == LayoutHelper.IS_SIMPLE_FIELD) {
114                         } else if ((si.i == LayoutHelper.IS_FIELD_START)
115                                 || (si.i == LayoutHelper.IS_GROUP_START)) {
116                                 blockEntries = new Vector<StringInt>();
117                                 blockStart = si.s;
118                         } else if ((si.i == LayoutHelper.IS_FIELD_END) || (si.i == LayoutHelper.IS_GROUP_END)) {
119                                 if (blockStart.equals(si.s)) {
120                                         blockEntries.add(si);
121                                         if (si.i == LayoutHelper.IS_GROUP_END)
122                                                 le = new LayoutEntry(blockEntries, classPrefix, LayoutHelper.IS_GROUP_START);
123                                         else
124                                                 le = new LayoutEntry(blockEntries, classPrefix, LayoutHelper.IS_FIELD_START);
125                                         tmpEntries.add(le);
126                                         blockEntries = null;
127                                 } else {
128                                         System.out.println("Nested field entries are not implemented !!!");
129                                 }
130                         } else if (si.i == LayoutHelper.IS_OPTION_FIELD) {
131                         }
132
133                         // else if (si.i == LayoutHelper.IS_OPTION_FIELD_PARAM)
134                         // {
135                         // }
136                         if (blockEntries == null) {
137                                 // System.out.println("BLOCK ADD: "+si.s+"="+si.i);
138                                 tmpEntries.add(new LayoutEntry(si, classPrefix));
139                         } else {
140                                 blockEntries.add(si);
141                         }
142                 }
143
144                 layoutEntries = new LayoutEntry[tmpEntries.size()];
145
146                 for (int i = 0; i < tmpEntries.size(); i++) {
147                         layoutEntries[i] = tmpEntries.get(i);
148
149                         // System.out.println(layoutEntries[i].text);
150                 }
151         }
152
153         public String doLayout(BibtexEntry bibtex, BibtexDatabase database) {
154
155                 switch (type) {
156                 case LayoutHelper.IS_LAYOUT_TEXT:
157                         return text;
158                 case LayoutHelper.IS_SIMPLE_FIELD:
159                         return BibtexDatabase.getResolvedField(text, bibtex, database);
160                 case LayoutHelper.IS_FIELD_START:
161                 case LayoutHelper.IS_GROUP_START: {
162                         String field = BibtexDatabase.getResolvedField(text, bibtex, database);
163
164                         if ((field == null)
165                                 || ((type == LayoutHelper.IS_GROUP_START) && (field.equalsIgnoreCase(LayoutHelper
166                                         .getCurrentGroup())))) {
167                                 return null;
168                         } else {
169                                 if (type == LayoutHelper.IS_GROUP_START) {
170                                         LayoutHelper.setCurrentGroup(field);
171                                 }
172                                 StringBuffer sb = new StringBuffer(100);
173                                 String fieldText;
174                                 boolean previousSkipped = false;
175
176                                 for (int i = 0; i < layoutEntries.length; i++) {
177                                         fieldText = layoutEntries[i].doLayout(bibtex, database);
178
179                                         if (fieldText == null) {
180                                                 if ((i + 1) < layoutEntries.length) {
181                                                         if (layoutEntries[i + 1].doLayout(bibtex, database).trim().length() == 0) {
182                                                                 i++;
183                                                                 previousSkipped = true;
184                                                                 continue;
185                                                         }
186                                                 }
187                                         } else {
188                                                 // if previous was skipped --> remove leading line
189                                                 // breaks
190                                                 if (previousSkipped) {
191                                                         int eol = 0;
192
193                                                         while ((eol < fieldText.length())
194                                                                 && ((fieldText.charAt(eol) == '\n') || (fieldText.charAt(eol) == '\r'))) {
195                                                                 eol++;
196                                                         }
197
198                                                         if (eol < fieldText.length()) {
199                                                                 sb.append(fieldText.substring(eol));
200                                                         }
201                                                 } else {
202                                                         // System.out.println("ENTRY-BLOCK: " +
203                                                         // layoutEntries[i].doLayout(bibtex));
204                                                         sb.append(fieldText);
205                                                 }
206                                         }
207
208                                         previousSkipped = false;
209                                 }
210
211                                 return sb.toString();
212                         }
213                 }
214                 case LayoutHelper.IS_FIELD_END:
215                 case LayoutHelper.IS_GROUP_END:
216                         return "";
217                 case LayoutHelper.IS_OPTION_FIELD: {
218                         String fieldEntry;
219
220                         if (text.equals("bibtextype")) {
221                                 fieldEntry = bibtex.getType().getName();
222                         } else {
223                                 // changed section begin - arudert
224                                 // resolve field (recognized by leading backslash) or text
225                                 String field = text.startsWith("\\") ? BibtexDatabase.getResolvedField(text.substring(1), bibtex, database)
226                                         : BibtexDatabase.getText(text, database);
227                                 // changed section end - arudert
228                                 if (field == null) {
229                                         fieldEntry = "";
230                                 } else {
231                                         fieldEntry = field;
232                                 }
233                         }
234
235                         // System.out.println("OPTION: "+option);
236                         if (option != null) {
237                                 for (int i = 0; i < option.length; i++) {
238                                         fieldEntry = option[i].format(fieldEntry);
239                                 }
240                         }
241
242                         return fieldEntry;
243                 }
244         case LayoutHelper.IS_ENCODING_NAME: {
245             // Printing the encoding name is not supported in entry layouts, only
246             // in begin/end layouts. This prevents breakage if some users depend
247             // on a field called "encoding". We simply return this field instead:
248             return BibtexDatabase.getResolvedField("encoding", bibtex, database);
249         }
250         default:
251                         return "";
252                 }
253         }
254
255         // added section - begin (arudert)
256         /**
257          * Do layout for general formatters (no bibtex-entry fields).
258          * 
259          * @param database
260          *            Bibtex Database
261          * @return
262          */
263         public String doLayout(BibtexDatabase database, String encoding) {
264                 if (type == LayoutHelper.IS_LAYOUT_TEXT) {
265                         return text;
266                 } else if (type == LayoutHelper.IS_SIMPLE_FIELD) {
267                         throw new UnsupportedOperationException(
268                                 "bibtex entry fields not allowed in begin or end layout");
269                 } else if ((type == LayoutHelper.IS_FIELD_START) || (type == LayoutHelper.IS_GROUP_START)) {
270                         throw new UnsupportedOperationException(
271                                 "field and group starts not allowed in begin or end layout");
272                 } else if ((type == LayoutHelper.IS_FIELD_END) || (type == LayoutHelper.IS_GROUP_END)) {
273                         throw new UnsupportedOperationException(
274                                 "field and group ends not allowed in begin or end layout");
275                 } else if (type == LayoutHelper.IS_OPTION_FIELD) {
276                         String field = BibtexDatabase.getText(text, database);
277                         if (option != null) {
278                                 for (int i = 0; i < option.length; i++) {
279                                         field = option[i].format(field);
280                                 }
281                         }
282
283                         return field;
284                 } else if (type == LayoutHelper.IS_ENCODING_NAME) {
285             // Try to translate from Java encoding name to common name:
286             String commonName = Globals.ENCODING_NAMES_LOOKUP.get(encoding);
287             return commonName != null ? commonName : encoding;
288         }
289                 return "";
290         }
291
292         // added section - end (arudert)
293
294         static Map<String, LayoutFormatter> pluginLayoutFormatter;
295         
296         public static LayoutFormatter getLayoutFormatterFromPlugins(String formatterName){
297                 if (pluginLayoutFormatter == null){
298                         pluginLayoutFormatter = new HashMap<String, LayoutFormatter>();
299                         
300                         JabRefPlugin plugin = JabRefPlugin.getInstance(PluginCore.getManager());
301                         if (plugin != null){
302                                 for (LayoutFormatterExtension e : plugin.getLayoutFormatterExtensions()){
303                                         LayoutFormatter formatter = e.getLayoutFormatter();
304                                         String name = e.getName();
305                                         if (name == null)
306                                                 name = e.getId();
307                                         
308                                         if (formatter != null){
309                                                 pluginLayoutFormatter.put(name, formatter);
310                                         }
311                                 }
312                         }
313                 }
314                 return pluginLayoutFormatter.get(formatterName);
315         }
316         
317         public static LayoutFormatter getLayoutFormatterByClassName(String className, String classPrefix)
318                 throws Exception {
319
320                 if (className.length() > 0) {
321                         try {
322                                 try {
323                                         return (LayoutFormatter) Class.forName(classPrefix + className).newInstance();
324                                 } catch (Throwable ex2) {
325                                         return (LayoutFormatter) Class.forName(className).newInstance();
326                                 }
327                         } catch (ClassNotFoundException ex) {
328                                 throw new Exception(Globals.lang("Formatter not found") + ": " + className);
329                         } catch (InstantiationException ex) {
330                                 throw new Exception(className + " can not be instantiated.");
331                         } catch (IllegalAccessException ex) {
332                                 throw new Exception(className + " can't be accessed.");
333                         }
334                 }
335                 return null;
336         }
337
338         /**
339          * Return an array of LayoutFormatters found in the given formatterName
340          * string (in order of appearance).
341          * 
342          */
343         public static LayoutFormatter[] getOptionalLayout(String formatterName,
344                         String classPrefix) throws Exception {
345
346                 ArrayList<String[]> formatterStrings = Util
347                                 .parseMethodsCalls(formatterName);
348
349                 ArrayList<LayoutFormatter> results = new ArrayList<LayoutFormatter>(
350                                 formatterStrings.size()); 
351
352                 Map<String, String> userNameFormatter = NameFormatterTab.getNameFormatters();
353
354                 for (String[] strings : formatterStrings) {
355
356                         // First load from formatters in formatter folder
357                         String className = strings[0].trim();
358             try {
359                                 LayoutFormatter f = getLayoutFormatterByClassName(className,
360                                                 classPrefix);
361                 // If this formatter accepts an argument, check if we have one, and
362                 // set it if so:
363                 if (f instanceof ParamLayoutFormatter) {
364                     if (strings.length >= 2)
365                         ((ParamLayoutFormatter)f).setArgument(strings[1]);
366                 }
367                 results.add(f);
368                                 continue;
369                         } catch (Exception e) {
370                         }
371
372                         // Then check whether this is a user defined formatter
373                         String formatterParameter = userNameFormatter
374                                         .get(className);
375
376                         if (formatterParameter != null) {
377                                 NameFormat nf = new NameFormat();
378                                 nf.setParameter(formatterParameter);
379                                 results.add(nf);
380                                 continue;
381                         }
382
383                         // Last load from plug-ins
384                         LayoutFormatter f = getLayoutFormatterFromPlugins(className);
385                         if (f != null) {
386                                 results.add(f);
387                                 continue;
388                         }
389
390                         // If not found throw exception...
391                         throw new Exception(Globals.lang("Formatter not found") + ": "
392                                         + className);
393                 }
394
395                 return results.toArray(new LayoutFormatter[] {});
396         }
397
398 }