42c47563a2144f1733671667ab72067634c650b7
[debian/jabref.git] / src / java / net / sf / jabref / gui / FileListTableModel.java
1 package net.sf.jabref.gui;
2
3 import net.sf.jabref.Globals;
4
5 import javax.swing.table.AbstractTableModel;
6 import javax.swing.event.TableModelEvent;
7 import javax.swing.*;
8 import java.util.ArrayList;
9 import java.util.Iterator;
10
11 /**
12  * Data structure to contain a list of file links, parseable from a coded string.
13  * Doubles as a table model for the file list editor.
14 */
15 public class FileListTableModel extends AbstractTableModel {
16
17     private final ArrayList list = new ArrayList();
18
19     public FileListTableModel() {
20     }
21
22     public int getRowCount() {
23         synchronized (list) {
24             return list.size();
25         }
26     }
27
28     public int getColumnCount() {
29         return 3;
30     }
31
32     public Class getColumnClass(int columnIndex) {
33         return String.class;
34     }
35
36     public Object getValueAt(int rowIndex, int columnIndex) {
37         synchronized (list) {
38             FileListEntry entry = (FileListEntry)list.get(rowIndex);
39             switch (columnIndex) {
40                 case 0: return entry.getDescription();
41                 case 1: return entry.getLink();
42                 default: return entry.getType() != null ?
43                         entry.getType().getName() : "";
44             }
45         }
46     }
47
48     public FileListEntry getEntry(int index) {
49         synchronized (list) {
50             return (FileListEntry)list.get(index);
51         }
52     }
53
54     public void removeEntry(int index) {
55         synchronized (list) {
56             list.remove(index);
57             fireTableRowsDeleted(index, index);
58         }
59
60     }
61
62     /**
63      * Add an entry to the table model, and fire a change event. The change event
64      * is fired on the event dispatch thread.
65      * @param index The row index to insert the entry at.
66      * @param entry The entry to insert.
67      */
68     public void addEntry(final int index, final FileListEntry entry) {
69         synchronized (list) {
70             list.add(index, entry);
71             if (!SwingUtilities.isEventDispatchThread()) {
72                 SwingUtilities.invokeLater(new Runnable() {
73                     public void run() {
74                         fireTableRowsInserted(index, index);
75                     }
76                 });
77             } else
78                 fireTableRowsInserted(index, index);
79         }
80
81     }
82
83     public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
84     }
85
86     /**
87      * Set up the table contents based on the flat string representation of the file list
88      * @param value The string representation
89      */
90     public void setContent(String value) {
91         setContent(value, false);
92     }
93
94     private FileListEntry setContent(String value, boolean firstOnly) {
95         if (value == null)
96             value = "";
97         ArrayList newList = new ArrayList();
98         StringBuilder sb = new StringBuilder();
99         ArrayList thisEntry = new ArrayList();
100         boolean escaped = false;
101         for (int i=0; i<value.length(); i++) {
102             char c = value.charAt(i);
103             if (!escaped && (c == '\\')) {
104                 escaped = true;
105                 continue;
106             }
107             else if (!escaped && (c == ':')) {
108                 thisEntry.add(sb.toString());
109                 sb = new StringBuilder();
110             }
111             else if (!escaped && (c == ';')) {
112                 thisEntry.add(sb.toString());
113                 sb = new StringBuilder();
114                 if (firstOnly)
115                     return decodeEntry(thisEntry);
116                 else {
117                     newList.add(decodeEntry(thisEntry));
118                     thisEntry.clear();
119                 }
120             }
121             else sb.append(c);
122             escaped = false;
123         }
124         if (sb.length() > 0)
125             thisEntry.add(sb.toString());
126         if (thisEntry.size() > 0) {
127             if (firstOnly)
128                 return decodeEntry(thisEntry);
129             else
130                 newList.add(decodeEntry(thisEntry));
131         }
132           
133         synchronized (list) {
134             list.clear();
135             list.addAll(newList);
136         }
137         fireTableChanged(new TableModelEvent(this));
138         return null;
139     }
140
141
142     /**
143      * Convenience method for finding a label corresponding to the type of the
144      * first file link in the given field content. The difference between using
145      * this method and using setContent() on an instance of FileListTableModel
146      * is a slight optimization: with this method, parsing is discontinued after
147      * the first entry has been found.
148      * @param content The file field content, as fed to this class' setContent() method.
149      * @return A JLabel set up with no text and the icon of the first entry's file type,
150      *  or null if no entry was found.
151      */
152     public static JLabel getFirstLabel(String content) {
153         FileListTableModel tm = new FileListTableModel();
154         FileListEntry entry = tm.setContent(content, true);
155         return entry != null ? entry.getType().getIconLabel() : null;
156     }
157
158     
159     private FileListEntry decodeEntry(ArrayList contents) {
160         return new FileListEntry(getElementIfAvailable(contents, 0),
161                 getElementIfAvailable(contents, 1),
162                 Globals.prefs.getExternalFileTypeByName
163                         (getElementIfAvailable(contents, 2)));
164     }
165
166     private String getElementIfAvailable(ArrayList contents, int index) {
167         if (index < contents.size())
168             return (String)contents.get(index);
169         else return "";
170     }
171
172     /**
173      * Transform the file list shown in the table into a flat string representable
174      * as a BibTeX field:
175      * @return String representation.
176      */
177     public String getStringRepresentation() {
178         StringBuilder sb = new StringBuilder();
179         for (Iterator iterator = list.iterator(); iterator.hasNext();) {
180             FileListEntry entry = (FileListEntry) iterator.next();
181             sb.append(encodeEntry(entry));
182             if (iterator.hasNext())
183                 sb.append(';');
184         }
185         return sb.toString();
186     }
187
188     /**
189      * Transform the file list shown in the table into a HTML string representation
190      * suitable for displaying the contents in a tooltip.
191      * @return Tooltip representation.
192      */
193     public String getToolTipHTMLRepresentation() {
194         StringBuilder sb = new StringBuilder("<html>");
195         for (Iterator iterator = list.iterator(); iterator.hasNext();) {
196             FileListEntry entry = (FileListEntry) iterator.next();
197             sb.append(entry.getDescription()).append(" (").append(entry.getLink()).append(')');
198             if (iterator.hasNext())
199                 sb.append("<br>");
200         }
201         return sb.append("</html>").toString();
202     }
203
204     private String encodeEntry(FileListEntry entry) {
205         StringBuilder sb = new StringBuilder();
206         sb.append(encodeString(entry.getDescription()));
207         sb.append(':');
208         sb.append(encodeString(entry.getLink()));
209         sb.append(':');
210         sb.append(encodeString(entry.getType() != null ? entry.getType().getName() : ""));
211         return sb.toString();
212     }
213
214     private String encodeString(String s) {
215         StringBuilder sb = new StringBuilder();
216         for (int i=0; i<s.length(); i++) {
217             char c = s.charAt(i);
218             if ((c == ';') || (c == ':') || (c == '\\'))
219                 sb.append('\\');
220             sb.append(c);
221         }
222         return sb.toString();
223     }
224
225     public void print() {
226         System.out.println("----");
227         for (Iterator iterator = list.iterator(); iterator.hasNext();) {
228             FileListEntry fileListEntry = (FileListEntry) iterator.next();
229             System.out.println(fileListEntry);
230         }
231         System.out.println("----");
232     }
233
234    
235 }