fee690b3f24b1817b09c86dfc09faa943d447f8a
[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.Map;
30 import java.util.Vector;
31
32 import net.sf.jabref.BibtexDatabase;
33 import net.sf.jabref.BibtexEntry;
34 import net.sf.jabref.Globals;
35 import net.sf.jabref.NameFormatterTab;
36 import net.sf.jabref.Util;
37 import net.sf.jabref.export.layout.format.NameFormat;
38 import wsi.ra.tool.WSITools;
39 import wsi.ra.types.StringInt;
40
41 /**
42  * DOCUMENT ME!
43  * 
44  * @author $author$
45  * @version $Revision: 2301 $
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 v = new Vector();
76                         WSITools.tokenize(v, si.s, "\n");
77
78                         if (v.size() == 1) {
79                                 text = (String) v.get(0);
80                         } else {
81                                 text = ((String) v.get(0)).trim();
82
83                                 // try
84                                 // {
85                                 option = getOptionalLayout((String) v.get(1), classPrefix);
86                                 // }
87                                 // catch (Exception e)
88                                 // {
89                                 // e.printStackTrace();
90                                 // }
91                         }
92                 }
93
94                 // else if (si.i == LayoutHelper.IS_OPTION_FIELD_PARAM)
95                 // {
96                 // }
97         }
98
99         public LayoutEntry(Vector parsedEntries, String classPrefix_, int layoutType) throws Exception {
100                 classPrefix = classPrefix_;
101                 String blockStart = null;
102                 String blockEnd = null;
103                 StringInt si;
104                 Vector<StringInt> blockEntries = null;
105                 Vector<LayoutEntry> tmpEntries = new Vector<LayoutEntry>();
106                 LayoutEntry le;
107                 si = (StringInt) parsedEntries.get(0);
108                 blockStart = si.s;
109                 si = (StringInt) parsedEntries.get(parsedEntries.size() - 1);
110                 blockEnd = si.s;
111
112                 if (!blockStart.equals(blockEnd)) {
113                         System.err.println("Field start and end entry must be equal.");
114                 }
115
116                 type = layoutType;
117                 text = si.s;
118
119                 for (int i = 1; i < (parsedEntries.size() - 1); i++) {
120                         si = (StringInt) parsedEntries.get(i);
121
122                         // System.out.println("PARSED-ENTRY: "+si.s+"="+si.i);
123                         if (si.i == LayoutHelper.IS_LAYOUT_TEXT) {
124                         } else if (si.i == LayoutHelper.IS_SIMPLE_FIELD) {
125                         } else if ((si.i == LayoutHelper.IS_FIELD_START)
126                                 || (si.i == LayoutHelper.IS_GROUP_START)) {
127                                 blockEntries = new Vector<StringInt>();
128                                 blockStart = si.s;
129                         } else if ((si.i == LayoutHelper.IS_FIELD_END) || (si.i == LayoutHelper.IS_GROUP_END)) {
130                                 if (blockStart.equals(si.s)) {
131                                         blockEntries.add(si);
132                                         if (si.i == LayoutHelper.IS_GROUP_END)
133                                                 le = new LayoutEntry(blockEntries, classPrefix, LayoutHelper.IS_GROUP_START);
134                                         else
135                                                 le = new LayoutEntry(blockEntries, classPrefix, LayoutHelper.IS_FIELD_START);
136                                         tmpEntries.add(le);
137                                         blockEntries = null;
138                                 } else {
139                                         System.out.println("Nested field entries are not implemented !!!");
140                                 }
141                         } else if (si.i == LayoutHelper.IS_OPTION_FIELD) {
142                         }
143
144                         // else if (si.i == LayoutHelper.IS_OPTION_FIELD_PARAM)
145                         // {
146                         // }
147                         if (blockEntries == null) {
148                                 // System.out.println("BLOCK ADD: "+si.s+"="+si.i);
149                                 tmpEntries.add(new LayoutEntry(si, classPrefix));
150                         } else {
151                                 blockEntries.add(si);
152                         }
153                 }
154
155                 layoutEntries = new LayoutEntry[tmpEntries.size()];
156
157                 for (int i = 0; i < tmpEntries.size(); i++) {
158                         layoutEntries[i] = (LayoutEntry) tmpEntries.get(i);
159
160                         // System.out.println(layoutEntries[i].text);
161                 }
162         }
163
164         public String doLayout(BibtexEntry bibtex, BibtexDatabase database) {
165
166                 switch (type) {
167                 case LayoutHelper.IS_LAYOUT_TEXT:
168                         return text;
169                 case LayoutHelper.IS_SIMPLE_FIELD:
170                         return BibtexDatabase.getResolvedField(text, bibtex, database);
171                 case LayoutHelper.IS_FIELD_START:
172                 case LayoutHelper.IS_GROUP_START: {
173                         String field = BibtexDatabase.getResolvedField(text, bibtex, database);
174
175                         if ((field == null)
176                                 || ((type == LayoutHelper.IS_GROUP_START) && (field.equalsIgnoreCase(LayoutHelper
177                                         .getCurrentGroup())))) {
178                                 return null;
179                         } else {
180                                 if (type == LayoutHelper.IS_GROUP_START) {
181                                         LayoutHelper.setCurrentGroup(field);
182                                 }
183                                 StringBuffer sb = new StringBuffer(100);
184                                 String fieldText;
185                                 boolean previousSkipped = false;
186
187                                 for (int i = 0; i < layoutEntries.length; i++) {
188                                         fieldText = layoutEntries[i].doLayout(bibtex, database);
189
190                                         if (fieldText == null) {
191                                                 if ((i + 1) < layoutEntries.length) {
192                                                         if (layoutEntries[i + 1].doLayout(bibtex, database).trim().length() == 0) {
193                                                                 i++;
194                                                                 previousSkipped = true;
195                                                                 continue;
196                                                         }
197                                                 }
198                                         } else {
199                                                 // if previous was skipped --> remove leading line
200                                                 // breaks
201                                                 if (previousSkipped) {
202                                                         int eol = 0;
203
204                                                         while ((eol < fieldText.length())
205                                                                 && ((fieldText.charAt(eol) == '\n') || (fieldText.charAt(eol) == '\r'))) {
206                                                                 eol++;
207                                                         }
208
209                                                         if (eol < fieldText.length()) {
210                                                                 sb.append(fieldText.substring(eol));
211                                                         }
212                                                 } else {
213                                                         // System.out.println("ENTRY-BLOCK: " +
214                                                         // layoutEntries[i].doLayout(bibtex));
215                                                         sb.append(fieldText);
216                                                 }
217                                         }
218
219                                         previousSkipped = false;
220                                 }
221
222                                 return sb.toString();
223                         }
224                 }
225                 case LayoutHelper.IS_FIELD_END:
226                 case LayoutHelper.IS_GROUP_END:
227                         return "";
228                 case LayoutHelper.IS_OPTION_FIELD: {
229                         String fieldEntry;
230
231                         if (text.equals("bibtextype")) {
232                                 fieldEntry = bibtex.getType().getName();
233                         } else {
234                                 // changed section begin - arudert
235                                 // resolve field (recognized by leading backslash) or text
236                                 String field = text.startsWith("\\") ? BibtexDatabase.getResolvedField(text.substring(1), bibtex, database)
237                                         : BibtexDatabase.getText(text, database);
238                                 // changed section end - arudert
239                                 if (field == null) {
240                                         fieldEntry = "";
241                                 } else {
242                                         fieldEntry = field;
243                                 }
244                         }
245
246                         // System.out.println("OPTION: "+option);
247                         if (option != null) {
248                                 for (int i = 0; i < option.length; i++) {
249                                         fieldEntry = option[i].format(fieldEntry);
250                                 }
251                         }
252
253                         return fieldEntry;
254                 }
255         case LayoutHelper.IS_ENCODING_NAME: {
256             // Printing the encoding name is not supported in entry layouts, only
257             // in begin/end layouts. This prevents breakage if some users depend
258             // on a field called "encoding". We simply return this field instead:
259             return BibtexDatabase.getResolvedField("encoding", bibtex, database);
260         }
261         default:
262                         return "";
263                 }
264         }
265
266         // added section - begin (arudert)
267         /**
268          * Do layout for general formatters (no bibtex-entry fields).
269          * 
270          * @param database
271          *            Bibtex Database
272          * @return
273          */
274         public String doLayout(BibtexDatabase database, String encoding) {
275                 if (type == LayoutHelper.IS_LAYOUT_TEXT) {
276                         return text;
277                 } else if (type == LayoutHelper.IS_SIMPLE_FIELD) {
278                         throw new UnsupportedOperationException(
279                                 "bibtex entry fields not allowed in begin or end layout");
280                 } else if ((type == LayoutHelper.IS_FIELD_START) || (type == LayoutHelper.IS_GROUP_START)) {
281                         throw new UnsupportedOperationException(
282                                 "field and group starts not allowed in begin or end layout");
283                 } else if ((type == LayoutHelper.IS_FIELD_END) || (type == LayoutHelper.IS_GROUP_END)) {
284                         throw new UnsupportedOperationException(
285                                 "field and group ends not allowed in begin or end layout");
286                 } else if (type == LayoutHelper.IS_OPTION_FIELD) {
287                         String field = BibtexDatabase.getText(text, database);
288                         if (option != null) {
289                                 for (int i = 0; i < option.length; i++) {
290                                         field = option[i].format(field);
291                                 }
292                         }
293
294                         return field;
295                 } else if (type == LayoutHelper.IS_ENCODING_NAME) {
296             return encoding;
297         }
298                 return "";
299         }
300
301         // added section - end (arudert)
302
303         public static LayoutFormatter getLayoutFormatter(String className, String classPrefix)
304                 throws Exception {
305                 LayoutFormatter f = null;
306         if (className.length() > 0) {
307                         try {
308                                 try {
309                                         f = (LayoutFormatter) Class.forName(classPrefix + className).newInstance();
310                                 } catch (Throwable ex2) {
311                                         f = (LayoutFormatter) Class.forName(className).newInstance();
312                                 }
313                         } catch (ClassNotFoundException ex) {
314                                 throw new Exception(Globals.lang("Formatter not found") + ": " + className);
315                         } catch (InstantiationException ex) {
316                                 throw new Exception(className + " can not be instantiated.");
317                         } catch (IllegalAccessException ex) {
318                                 throw new Exception(className + " can't be accessed.");
319                         }
320                 }
321                 return f;
322         }
323
324         /**
325          * Return an array of LayoutFormatters found in the given formatterName
326          * string (in order of appearance).
327          * 
328          */
329         public static LayoutFormatter[] getOptionalLayout(String formatterName, String classPrefix)
330                 throws Exception {
331
332                 ArrayList formatterStrings = Util.parseMethodsCalls(formatterName);
333
334                 ArrayList<LayoutFormatter> results = new ArrayList<LayoutFormatter>(formatterStrings.size());
335
336                 Map userNameFormatter = NameFormatterTab.getNameFormatters();
337
338                 for (int i = 0; i < formatterStrings.size(); i++) {
339
340                         String[] strings = (String[]) formatterStrings.get(i);
341
342                         String className = strings[0].trim();
343
344             try {
345                                 LayoutFormatter f = getLayoutFormatter(className, classPrefix);
346                 // If this formatter accepts an argument, check if we have one, and
347                 // set it if so:
348                 if (f instanceof ParamLayoutFormatter) {
349                     if (strings.length >= 2)
350                         ((ParamLayoutFormatter)f).setArgument(strings[1]);
351                 }
352                 results.add(f);
353                         } catch (Exception e) {
354
355                                 String formatterParameter = (String) userNameFormatter.get(className);
356
357                                 if (formatterParameter == null) {
358                                         throw new Exception(Globals.lang("Formatter not found") + ": " + className);
359                                 } else {
360                                         NameFormat nf = new NameFormat();
361                                         nf.setParameter(formatterParameter);
362                                         results.add(nf);
363                                 }
364                         }
365                 }
366
367                 return (LayoutFormatter[]) results.toArray(new LayoutFormatter[] {});
368         }
369
370 }