a3475c2afcafd6563091e77d883bc1bafba66817
[debian/jabref.git] / src / java / net / sf / jabref / BibtexFields.java
1 /*
2  Copyright (C) 2006 Raik Nagel <kiar@users.sourceforge.net>
3  All rights reserved.
4
5  Redistribution and use in source and binary forms, with or without
6  modification, are permitted provided that the following conditions are met:
7
8  * Redistributions of source code must retain the above copyright notice,
9   this list of conditions and the following disclaimer.
10  * Redistributions in binary form must reproduce the above copyright notice,
11   this list of conditions and the following disclaimer in the documentation
12   and/or other materials provided with the distribution.
13  * Neither the name of the author nor the names of its contributors may be
14   used to endorse or promote products derived from this software without
15   specific prior written permission.
16
17  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 // created by : r.nagel 19.04.2006
31 //
32 // function : Handling of bibtex fields.
33 //            All bibtex-field related stuff should be placed here!
34 //            Because we can export these informations into additional
35 //            config files -> simple extension and definition of new fields....
36 //
37 // todo     : - handling of identically fields with different names
38 //              e.g. LCCN = lib-congress
39 //            - group id for each fields, e.g. standard, jurabib, bio....
40 //            - add a additional properties functionality into the
41 //              BibtexSingleField class
42 //
43 // modified : r.nagel 25.04.2006
44 //            export/import of some definition from/to a xml file
45
46 package net.sf.jabref ;
47
48 import java.util.* ;
49 import net.sf.jabref.util.*;
50 import org.w3c.dom.Element;
51 import org.w3c.dom.NodeList;
52
53 public class BibtexFields
54 {
55   public static final String KEY_FIELD = "bibtexkey" ;
56
57   // some internal fields
58   public static final String
59       SEARCH = "__search",
60       GROUPSEARCH = "__groupsearch",
61       MARKED = "__markedentry",
62       OWNER = "owner",
63       TIMESTAMP = "timestamp", // it's also definied at the JabRefPreferences class
64       ENTRYTYPE = "entrytype",
65
66       // Using this when I have no database open or when I read
67       // non bibtex file formats (used by the ImportFormatReader.java)
68       DEFAULT_BIBTEXENTRY_ID = "__ID" ;
69
70   public static final String[] DEFAULT_INSPECTION_FIELDS = new String[]
71           {"author", "title", "year", KEY_FIELD};
72
73
74   // singleton instance
75   private static final BibtexFields runtime = new BibtexFields() ;
76
77   // contains all bibtex-field objects (BibtexSingleField)
78   private HashMap fieldSet = null ;
79
80   // contains all known (and public) bibtex fieldnames
81   private Object[] PUBLIC_FIELDS = null ;
82
83   private BibtexFields()
84   {
85     fieldSet = new HashMap() ;
86     BibtexSingleField dummy = null ;
87
88     // FIRST: all standard fields
89     // These are the fields that BibTex might want to treat, so these
90     // must conform to BibTex rules.
91     add( new BibtexSingleField( "address", true, GUIGlobals.SMALL_W  ) ) ;
92     // An annotation. It is not used by the standard bibliography styles,
93     // but may be used by others that produce an annotated bibliography.
94     // http://www.ecst.csuchico.edu/~jacobsd/bib/formats/bibtex.html
95     add( new BibtexSingleField( "annote", true, GUIGlobals.LARGE_W  ) ) ;
96     add( new BibtexSingleField( "author", true, GUIGlobals.MEDIUM_W, 280 ) ) ;
97     add( new BibtexSingleField( "booktitle", true, 175 ) ) ;
98     add( new BibtexSingleField( "chapter", true, GUIGlobals.SMALL_W  ) ) ;
99     add( new BibtexSingleField( "crossref", true, GUIGlobals.SMALL_W ) ) ;
100     add( new BibtexSingleField( "edition", true, GUIGlobals.SMALL_W  ) ) ;
101     add( new BibtexSingleField( "editor", true, GUIGlobals.MEDIUM_W, 280  ) ) ;
102     add( new BibtexSingleField( "howpublished", true, GUIGlobals.MEDIUM_W  ) ) ;
103     add( new BibtexSingleField( "institution", true, GUIGlobals.MEDIUM_W  ) ) ;
104
105     dummy = new BibtexSingleField( "journal", true, GUIGlobals.SMALL_W ) ;
106     dummy.setExtras("journalNames");
107     add(dummy) ;
108     add( new BibtexSingleField( "key", true ) ) ;
109     add( new BibtexSingleField( "month", true, GUIGlobals.SMALL_W ) ) ;
110     add( new BibtexSingleField( "note", true, GUIGlobals.MEDIUM_W  ) ) ;
111     add( new BibtexSingleField( "number", true, GUIGlobals.SMALL_W, 60  ) ) ;
112     add( new BibtexSingleField( "organization", true, GUIGlobals.MEDIUM_W  ) ) ;
113     add( new BibtexSingleField( "pages", true, GUIGlobals.SMALL_W ) ) ;
114     add( new BibtexSingleField( "publisher", true, GUIGlobals.MEDIUM_W  ) ) ;
115     add( new BibtexSingleField( "school", true, GUIGlobals.MEDIUM_W  ) ) ;
116     add( new BibtexSingleField( "series", true, GUIGlobals.SMALL_W  ) ) ;
117     add( new BibtexSingleField( "title", true, 400 ) ) ;
118     add( new BibtexSingleField( "type", true, GUIGlobals.SMALL_W  ) ) ;
119     add( new BibtexSingleField( "volume", true, GUIGlobals.SMALL_W, 60  ) ) ;
120     add( new BibtexSingleField( "year", true, GUIGlobals.SMALL_W, 60 ) ) ;
121
122     // some semi-standard fields
123     dummy = new BibtexSingleField( KEY_FIELD, true ) ;
124     dummy.setPrivate();
125     add( dummy ) ;
126
127     dummy = new BibtexSingleField( "doi", true, GUIGlobals.SMALL_W ) ;
128     dummy.setExtras("external");
129     add(dummy) ;
130     add( new BibtexSingleField( "eid", true, GUIGlobals.SMALL_W  ) ) ;
131
132     dummy = new BibtexSingleField( "date", true ) ;
133     dummy.setPrivate();
134     add( dummy ) ;
135
136
137     // additional fields ------------------------------------------------------
138     dummy =  new BibtexSingleField( "citeseercitationcount", false,
139                                                  GUIGlobals.SMALL_W, 75) ;
140     dummy.setAlternativeDisplayName("Popularity") ;
141     add(dummy) ;
142     add( new BibtexSingleField( "location", false ) ) ;
143     add( new BibtexSingleField( "abstract", false, GUIGlobals.LARGE_W, 400  ) ) ;
144
145     dummy =  new BibtexSingleField( "url", false, GUIGlobals.SMALL_W) ;
146     dummy.setExtras("external");
147     add(dummy) ;
148
149     dummy = new BibtexSingleField( "citeseerurl", false, GUIGlobals.SMALL_W ) ;
150     dummy.setExtras("external");
151     add(dummy) ;
152
153     dummy = new BibtexSingleField( "pdf", false, GUIGlobals.SMALL_W ) ;
154     dummy.setExtras("browseDoc");
155     add(dummy) ;
156
157     dummy = new BibtexSingleField( "ps", false, GUIGlobals.SMALL_W ) ;
158     dummy.setExtras("browseDocZip");
159     add(dummy) ;
160     add( new BibtexSingleField( "comment", false, GUIGlobals.MEDIUM_W  ) ) ;
161     add( new BibtexSingleField( "keywords", false, GUIGlobals.SMALL_W  ) ) ;
162     //FIELD_EXTRAS.put("keywords", "selector");
163
164
165     dummy = new BibtexSingleField(GUIGlobals.FILE_FIELD, false);
166     dummy.setEditorType(GUIGlobals.FILE_LIST_EDITOR);
167     add(dummy);
168
169
170     add( new BibtexSingleField( "search", false, 75 ) ) ;
171
172
173     // some internal fields ----------------------------------------------
174     dummy = new BibtexSingleField( GUIGlobals.NUMBER_COL, false, 32  ) ;
175     dummy.setPrivate() ;
176     dummy.setWriteable(false);
177     dummy.setDisplayable(false);
178     add( dummy ) ;
179
180     dummy = new BibtexSingleField( OWNER, false, GUIGlobals.SMALL_W ) ;
181     dummy.setExtras("setOwner");
182     dummy.setPrivate();
183     add(dummy) ;
184
185     dummy = new BibtexSingleField( TIMESTAMP, false, GUIGlobals.SMALL_W ) ;
186     dummy.setExtras("datepicker");
187     dummy.setPrivate();
188     add(dummy) ;
189
190     dummy =  new BibtexSingleField( ENTRYTYPE, false, 75 ) ;
191     dummy.setPrivate();
192     add(dummy) ;
193
194     dummy =  new BibtexSingleField( SEARCH, false) ;
195     dummy.setPrivate();
196     dummy.setWriteable(false);
197     dummy.setDisplayable(false);
198     add(dummy) ;
199
200     dummy =  new BibtexSingleField( GROUPSEARCH, false) ;
201     dummy.setPrivate();
202     dummy.setWriteable(false);
203     dummy.setDisplayable(false);
204     add(dummy) ;
205
206     dummy =  new BibtexSingleField( MARKED, false) ;
207     dummy.setPrivate();
208     dummy.setWriteable(true); // This field must be written to file!
209     dummy.setDisplayable(false);
210     add(dummy) ;
211
212      // read external field definitions
213     readXML( Globals.additionalFields ) ;
214
215     // collect all public fields for the PUBLIC_FIELDS array
216     Vector pFields = new Vector( fieldSet.size()) ;
217     for(Iterator iter = fieldSet.values().iterator(); iter.hasNext() ; )
218     {
219       BibtexSingleField sField = (BibtexSingleField) iter.next() ;
220       if (sField.isPublic() )
221       {
222         pFields.add( sField.getFieldName() );
223         // or export the complet BibtexSingleField ?
224         // BibtexSingleField.toString() { return fieldname ; }
225       }
226     }
227
228     PUBLIC_FIELDS = pFields.toArray() ;
229     // sort the entries
230     java.util.Arrays.sort( PUBLIC_FIELDS );
231   }
232
233
234   /** insert a field into the internal list */
235   private void add( BibtexSingleField field )
236   {
237     // field == null check
238     String key = field.name ;
239     fieldSet.put( key, field ) ;
240   }
241
242   /** read a xml definiton file and put only NEW fields into the field list */
243   private void readXML( String resName )
244   {
245     TXMLReader reader = new TXMLReader(resName) ;
246     if (reader.isReady() )
247     {
248       // get a list of all fields
249       NodeList fieldNodes = reader.getNodes("field") ;
250
251       int tagsCount = fieldNodes.getLength() ;
252       for (int t = 0 ; t < tagsCount ; t++)
253       {
254         Element entry = (Element) fieldNodes.item(t) ;
255         String fName = reader.readStringAttribute(entry, "name", null) ;
256         if (fName != null)  // something found ?
257         {
258           fName = fName.toLowerCase() ;
259           BibtexSingleField dummy = (BibtexSingleField) fieldSet.get( fName ) ;
260           if (dummy == null)  // unknown field
261           {
262             dummy = new BibtexSingleField(reader, entry) ;
263             fieldSet.put(fName, dummy) ;
264           }
265         }
266       }
267     }
268   }
269
270   // --------------------------------------------------------------------------
271   //  the "static area"
272   // --------------------------------------------------------------------------
273   private static final BibtexSingleField getField( String name )
274   {
275     if (name != null)
276     {
277       return (BibtexSingleField) runtime.fieldSet.get(name.toLowerCase()) ;
278     }
279
280     return null ;
281   }
282
283   public static String getFieldExtras( String name )
284   {
285     BibtexSingleField sField = getField( name ) ;
286     if (sField != null)
287     {
288       return sField.getExtras() ;
289     }
290     return null ;
291   }
292
293
294   public static int getEditorType(String name) {
295     BibtexSingleField sField = getField( name ) ;
296     if (sField != null)
297     {
298       return sField.getEditorType();
299     }
300     return GUIGlobals.STANDARD_EDITOR;      
301   }
302
303   public static double getFieldWeight( String name )
304   {
305     BibtexSingleField sField = getField( name ) ;
306     if (sField != null)
307     {
308       return sField.getWeight() ;
309     }
310     return GUIGlobals.DEFAULT_FIELD_WEIGHT ;
311   }
312
313   public static void setFieldWeight( String fieldName, double weight )
314   {
315     BibtexSingleField sField = getField( fieldName ) ;
316     if (sField != null)
317     {
318       sField.setWeight( weight ) ;
319     }
320   }
321
322   public static int getFieldLength( String name )
323   {
324     BibtexSingleField sField = getField( name ) ;
325     if (sField != null)
326     {
327       return sField.getLength() ;
328     }
329     return GUIGlobals.DEFAULT_FIELD_LENGTH ;
330   }
331
332   // returns an alternative name for the given fieldname
333   public static String getFieldDisplayName( String fieldName )
334   {
335     BibtexSingleField sField = getField( fieldName ) ;
336     if (sField != null)
337     {
338       return sField.getAlternativeDisplayName() ;
339     }
340     return null ;
341   }
342
343   public static boolean isWriteableField( String field )
344   {
345     BibtexSingleField sField = getField( field ) ;
346     if (sField != null)
347     {
348       return sField.isWriteable() ;
349     }
350     return true ;
351   }
352
353   public static boolean isDisplayableField( String field )
354   {
355     BibtexSingleField sField = getField( field ) ;
356     if (sField != null)
357     {
358       return sField.isDisplayable() ;
359     }
360     return true ;
361   }
362
363   /**
364    * Returns true if the given field is a standard Bibtex field.
365    *
366    * @param field a <code>String</code> value
367    * @return a <code>boolean</code> value
368    */
369   public static boolean isStandardField( String field )
370   {
371     BibtexSingleField sField = getField( field ) ;
372     if (sField != null)
373     {
374       return sField.isStandard() ;
375     }
376     return false ;
377   }
378
379   /** returns an string-array with all fieldnames */
380   public static Object[] getAllFieldNames()
381   {
382     return runtime.PUBLIC_FIELDS ;
383   }
384
385   /** returns the fieldname of the entry at index t */
386   public static String getFieldName( int t )
387   {
388     return  (String) runtime.PUBLIC_FIELDS[t] ;
389   }
390
391   /** returns the number of available fields */
392   public static int numberOfPublicFields()
393   {
394     return runtime.PUBLIC_FIELDS.length ;
395   }
396
397   /*
398      public static int getPreferredFieldLength(String name) {
399      int l = DEFAULT_FIELD_LENGTH;
400      Object o = fieldLength.get(name.toLowerCase());
401      if (o != null)
402      l = ((Integer)o).intValue();
403      return l;
404      }*/
405
406
407   // --------------------------------------------------------------------------
408   // a container class for all properties of a bibtex-field
409   // --------------------------------------------------------------------------
410   private class BibtexSingleField
411   {
412     private static final int
413         STANDARD       = 0x01,  // it is a standard bibtex-field
414         PRIVATE        = 0x02,  // internal use, e.g. owner, timestamp
415         DISPLAYABLE    = 0x04,  // These fields cannot be shown inside the source editor panel
416         WRITEABLE      = 0x08 ; // These fields will not be saved to the .bib file.
417
418     // the fieldname
419     private String name ;
420
421     // contains the standard, privat, displayable, writable infos
422     // default is: not standard, public, displayable and writable
423     private int flag = DISPLAYABLE | WRITEABLE ;
424
425     private int length = GUIGlobals.DEFAULT_FIELD_LENGTH ;
426     private double weight = GUIGlobals.DEFAULT_FIELD_WEIGHT ;
427
428     private int editorType = GUIGlobals.STANDARD_EDITOR;
429
430     // a alternative displayname, e.g. used for
431     // "citeseercitationcount"="Popularity"
432     private String alternativeDisplayName = null ;
433
434     // the extras data
435     // fieldExtras contains mappings to tell the EntryEditor to add a specific
436     // function to this field, for instance a "browse" button for the "pdf" field.
437     private String extras = null ;
438
439     // a comma separated list of alternative bibtex-fieldnames, e.g.
440     // "LCCN" is the same like "lib-congress"
441     // private String otherNames = null ;
442
443     // a Hashmap for a lot of additional "not standard" properties
444     // todo: add the handling in a key=value manner
445     // private HashMap props = new HashMap() ;
446
447     // some constructors ;-)
448     public BibtexSingleField( String fieldName )
449     {
450       name = fieldName ;
451     }
452
453     public BibtexSingleField( String fieldName, boolean pStandard )
454     {
455       name = fieldName ;
456       setFlag( pStandard, STANDARD) ;
457     }
458
459     public BibtexSingleField( String fieldName, boolean pStandard, double pWeight)
460     {
461       name = fieldName ;
462       setFlag( pStandard, STANDARD) ;
463       weight = pWeight ;
464     }
465
466     public BibtexSingleField( String fieldName, boolean pStandard, int pLength)
467     {
468       name = fieldName ;
469       setFlag( pStandard, STANDARD) ;
470       length = pLength ;
471     }
472
473     public BibtexSingleField( String fieldName, boolean pStandard,
474                               double pWeight, int pLength)
475     {
476       name = fieldName ;
477       setFlag( pStandard, STANDARD) ;
478       weight = pWeight ;
479       length = pLength ;
480     }
481
482     /** the constructor reads all neccessary data from the xml file */
483     public BibtexSingleField( TXMLReader reader, Element node)
484     {
485       // default is: not standard, public, displayable and writable
486       flag = DISPLAYABLE | WRITEABLE ;
487
488       name = reader.readStringAttribute(node, "name", "field") ;
489       name = name.toLowerCase() ;
490
491       // read the weight
492       String wStr = reader.readStringAttribute(node, "weight", null) ;
493       if (wStr != null)
494       {
495         int hCode = wStr.toLowerCase().hashCode() ;
496         if (hCode == "small".hashCode())
497         {
498           weight = GUIGlobals.SMALL_W ;
499         }
500         else if (hCode == "medium".hashCode())
501         {
502           weight = GUIGlobals.MEDIUM_W ;
503         }
504         else if (hCode == "large".hashCode())
505         {
506           weight = GUIGlobals.LARGE_W ;
507         }
508         else // try to convert to a double value
509         {
510           try
511           {
512             weight = Double.parseDouble(wStr) ;
513             if ((weight < 0.0) || (weight > GUIGlobals.MAX_FIELD_WEIGHT))
514             {
515               weight = GUIGlobals.DEFAULT_FIELD_WEIGHT ;
516             }
517           }
518           catch (Exception e)
519           {
520             weight = GUIGlobals.DEFAULT_FIELD_WEIGHT ;
521           }
522         }
523       }
524       length = reader.readIntegerAttribute( node, "length", GUIGlobals.DEFAULT_FIELD_LENGTH ) ;
525
526       extras = reader.readStringAttribute(node, "extras", null) ;
527     }
528
529     // -----------------------------------------------------------------------
530     // -----------------------------------------------------------------------
531
532     private void setFlag( boolean onOff, int flagID)
533     {
534       if (onOff)  // set the flag
535       {
536         flag = flag | flagID ;
537       }
538       else // unset the flag,
539       {
540         flag = flag & ( 0xff ^ flagID ) ;
541       }
542     }
543
544     private boolean isSet( int flagID )
545     {
546       if ( (flag & flagID) == flagID)
547         return true ;
548
549       return false ;
550     }
551
552     // -----------------------------------------------------------------------
553     public boolean isStandard()
554     {
555       return isSet( STANDARD ) ;
556     }
557
558     public void setPrivate()
559     {
560       flag = flag | PRIVATE ;
561     }
562
563     public boolean isPrivate()
564     {
565       return isSet( PRIVATE ) ;
566     }
567
568     public void setPublic()
569     {
570       setFlag( false, PRIVATE ) ;
571     }
572
573     public boolean isPublic()
574     {
575       return !isSet( PRIVATE ) ;
576     }
577
578     public void setDisplayable(boolean value)
579     {
580       setFlag( value, DISPLAYABLE ) ;
581     }
582
583     public boolean isDisplayable()
584     {
585       return isSet(DISPLAYABLE) ;
586     }
587
588
589     public void setWriteable(boolean value)
590     {
591       setFlag( value, WRITEABLE ) ;
592     }
593
594     public boolean isWriteable()
595     {
596       return isSet( WRITEABLE ) ;
597     }
598
599     // -----------------------------------------------------------------------
600     public void setAlternativeDisplayName( String aName)
601     {
602       alternativeDisplayName = aName ;
603     }
604
605     public String getAlternativeDisplayName()
606     {
607       return alternativeDisplayName ;
608     }
609     // -----------------------------------------------------------------------
610
611     public void setExtras( String pExtras)
612     {
613       extras = pExtras ;
614     }
615
616     // fieldExtras contains mappings to tell the EntryEditor to add a specific
617     // function to this field, for instance a "browse" button for the "pdf" field.
618     public String getExtras()
619     {
620       return extras ;
621     }
622
623     public void setEditorType(int type) {
624         editorType = type;
625     }
626
627     public int getEditorType() {
628         return editorType;
629     }
630     // -----------------------------------------------------------------------
631
632     public void setWeight( double value )
633     {
634       this.weight = value ;
635     }
636
637     public double getWeight()
638     {
639       return this.weight ;
640     }
641
642     // -----------------------------------------------------------------------
643     public int getLength()
644     {
645       return this.length ;
646     }
647
648     // -----------------------------------------------------------------------
649
650     public String getFieldName()
651     {
652       return name ;
653     }
654
655   }
656 }