KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > ca > directory > jxplorer > viewer > HTMLTemplateDisplay


1 package com.ca.directory.jxplorer.viewer;
2
3 import com.ca.commons.cbutil.*;
4 import com.ca.commons.naming.*;
5 import com.ca.directory.jxplorer.*;
6 import com.ca.directory.jxplorer.tree.SmartTree;
7
8 import javax.naming.NamingEnumeration JavaDoc;
9 import javax.naming.NamingException JavaDoc;
10 import javax.naming.directory.Attribute JavaDoc;
11 import javax.naming.directory.Attributes JavaDoc;
12 import javax.swing.*;
13 import javax.swing.event.HyperlinkEvent JavaDoc;
14 import javax.swing.event.HyperlinkListener JavaDoc;
15 import java.awt.*;
16 import java.awt.event.ActionEvent JavaDoc;
17 import java.awt.event.ActionListener JavaDoc;
18 import java.io.*;
19 import java.net.*;
20 import java.util.*;
21 import java.util.logging.Logger JavaDoc;
22 import java.util.logging.Level JavaDoc;
23 import java.util.zip.ZipException JavaDoc;
24
25 /**
26  * Display Template handles the insertion of attribute values into
27  * an HTML template, in order to display filtered information to
28  * the user in an attractive manner.<p>
29  *
30  * It also implements a simple web browser for viewing help links
31  * etc.<p>
32  *
33  * Form submission is done in the @MyHTMLEditorKit class.
34  */

35
36
37 /* IMPLEMENTATION NOTES....
38  *
39  * This is a large class, and should probably be broken up - an MVC model maybe, but
40  * at least separate the functionality families.
41  *
42  * It is currently doing three separate things.
43  * A) Operating the Template Display GUI
44  * B) Keeping track of the html templates on disk, and indexing them by object class
45  * C) Parsing the html text and doing tricks (many of which may not be necessary, since they were often
46  * work arounds for buggy sun code in the good 'ol days).
47  */

48
49 public class HTMLTemplateDisplay extends JPanel
50         implements DataSink, PluggableEditor
51 {
52     JScrollPane scrollDisplay;
53
54     DataSource currentDataSource = null;
55
56     JEditorPane editor;
57     JViewport viewport; // was CBViewport
58
JTextArea bloop;
59
60     String JavaDoc baseText; // the original text, formatted for html but without attribute values
61
StringBuffer JavaDoc htmlText; // the display text, including attributes...
62
// String baseURL; // the base file URL of the template directory location
63
// String localURL; //TE: the path to the users working dir. Used to store the temporary templates extracted from a zip/jar.
64
// URL base = null; // the same base file URL, as a url.
65

66     Component display; // a display panel used for user error messages.
67

68     public static final String JavaDoc DEFAULTTEXT = "<html><head><title>Default Template</title></head><body> <dxtemplate:get-all-attributes> <br> </body></html>";
69     public static final String JavaDoc ATTRIBTAG = "<dxtemplate:";
70     public static String JavaDoc NOVALUEFOUND;
71     public static final String JavaDoc JPEGEXTENSION = ".jpg"; //TE: the extenion of the temporary jpegPhotos stored locally.
72
public static final String JavaDoc DOCEXTENSION = ".doc"; //TE: the extenion of the temporary documents stored locally.
73
public static final String JavaDoc XLSEXTENSION = ".xls"; //TE: the extenion of the temporary spreadsheets stored locally.
74
public static final String JavaDoc WAVEXTENSION = ".wav"; //TE: the extenion of the temporary wav files stored locally.
75
public static final String JavaDoc AVIEXTENSION = ".avi"; //TE: the extenion of the temporary avi files stored locally.
76
public static final String JavaDoc MIDEXTENSION = ".mid"; //TE: the extenion of the temporary mid files stored locally.
77

78     public static final String JavaDoc startFile = "start"; // the initially displayed html page
79

80     public static final int MAX_LEGAL_VALUE_LENGTH = 500;
81     public static final String JavaDoc ILLEGAL_VALUE = "[ATTRIBUTE TOO LARGE TO DISPLAY]";
82
83     public static final String JavaDoc DEFAULT = "defaulttemplate"; // name for default templates...
84

85     Properties myProperties; // contains info about default urls and file locations.
86

87     JToolBar toolBar; // the toolbar containing the list of allowed templates
88

89     /*
90      * A bunch of variables are needed to keep track of all the available html templates,
91      * and the users state when viewing a particular template combination.
92      */

93
94     // The combo box the user uses to select a display template
95
CBJComboBox viewTemplates;
96
97     // The position in the combo box for a particular 'object class set signature' (i.e. what the user last
98
// viewed for a particular object class set). Keyed by object class signature.
99
Hashtable viewTemplatesPos = new Hashtable(); // hashtable of most-recently-used templates
100

101     // All available templates (as File objects, keyed by lower case object class. Defaults keyed by empty string "").
102
Hashtable templates = new Hashtable(100);
103
104     // the 'object class signature' (the object classes for a particular entry concatenated to a unique key)
105
String JavaDoc oldObjectClassesSignature = "";
106
107     // the base directory for all the html templates
108
File baseTemplateDir;
109
110     // the base directory for any plugin html templates
111
File pluginTemplateDirectory = null;
112
113 // String currentLDAPObjectClass = ""; // the current object class being viewed
114
DXEntry currentEntry = null; // the current entry being displayed.
115
// (we need to remember this, because the display template changes)
116
static String JavaDoc currentTemplateName = ""; // the name of the currently selected template...
117

118     public static String JavaDoc NODATA; // no data html page - not static, 'cause of internationalisation requirements...
119

120     public boolean showHTMLErrors = true; // for debugging html forms.
121

122     protected MyHyperlinkListener hyperlinkListener;
123     protected MyHTMLEditorKit htmlEditorKit;
124
125     protected boolean settingUpTemplates = false; // utility variable to disable combo box action listener during combo box setup.
126

127     Vector currentBinaryAttributes = new Vector(0); // used by MyHTMLEditorKit to flag special data...
128

129     CBResourceLoader resourceLoader = null; // used to load HTML templates from zip/jar files.
130

131     protected String JavaDoc currentDN; //TE: part of the name of the temporary files that are created for jpegPhoto & audio attributes (i.e. the dn of the entry).
132

133     SmartTree smartTree = null;
134
135     private static Logger JavaDoc log = Logger.getLogger(HTMLTemplateDisplay.class.getName());
136
137     /**
138      * Default Constructor for HTMLTemplateDisplay
139      */

140
141     public HTMLTemplateDisplay(Component owner, Properties props, CBResourceLoader resourceLoader)
142     {
143         commonConstructorCode(owner, props, resourceLoader);
144         setToDefault();
145     }
146
147     protected void setToDefault()
148     {
149         htmlText = new StringBuffer JavaDoc(DEFAULTTEXT);
150         baseText = new String JavaDoc(DEFAULTTEXT);
151     }
152
153     /**
154      * <p>A bunch of vaguely hacky code to add hyperlink-like functionality to the html display</p>
155      */

156     class MyHyperlinkListener implements HyperlinkListener JavaDoc
157     {
158         public void hyperlinkUpdate(final HyperlinkEvent JavaDoc e)
159         {
160             if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED)
161             {
162                 SwingUtilities.invokeLater(new Runnable JavaDoc()
163                 {
164                     public void run()
165                     {
166                         String JavaDoc desc = e.getDescription();
167
168                         if (desc.toLowerCase().startsWith("dn:")) // el hack especial
169
{
170                             String JavaDoc dn = desc.substring(desc.indexOf(":") + 1);
171
172                             if (smartTree != null)
173                             {
174                                 smartTree.readAndExpandDN(new DN(dn));
175                             }
176                         }
177                         else if (desc.toLowerCase().startsWith(".." + File.separator + "temp" + File.separator + "audio" + File.separator) || desc.toLowerCase().startsWith(".." + File.separator + ".." + File.separator + "temp" + File.separator + "audio" + File.separator)) //TE: audio handler.
178
{//TE: launches audio files...
179
if (!System.getProperty("os.name").equalsIgnoreCase("SunOS")) //TE: Check if the operating system is Sun if so don't attempt to play the audio file.
180
{
181                                 String JavaDoc path = CBCache.getAudioDirPath();
182                                 String JavaDoc audioFilePath = desc.substring(desc.indexOf("temp", desc.lastIndexOf("\"")));
183                                 String JavaDoc audioFileName = audioFilePath.substring(audioFilePath.lastIndexOf("\\"));
184                                 String JavaDoc extension = audioFileName.substring(audioFileName.indexOf("."));
185
186                                 if (extension.equalsIgnoreCase(".xxx"))
187                                     CBUtility.error(CBIntText.get("Unable to play unknown audio file type"));
188                                 else
189                                     CBLauncher.launchProgram(extension, path + audioFileName);
190                             }
191                         }
192                         else if (desc.toLowerCase().startsWith(".." + File.separator + "temp" + File.separator) || desc.toLowerCase().startsWith(".." + File.separator + ".." + File.separator + "temp" + File.separator)) //TE: audio handler.
193
{//TE: currently launches odDocumentDOC/odSpreadSheetXLS/odMusicMID/odSoundWAV/odMovieAVI files with .doc extension...
194
if (!System.getProperty("os.name").equalsIgnoreCase("SunOS")) //TE: Check if the operating system is Sun if so don't attempt to launch the document.
195
{
196                                 String JavaDoc path = CBCache.getDirPath();
197                                 String JavaDoc filePath = desc.substring(desc.indexOf("temp", desc.lastIndexOf("\"")));
198                                 String JavaDoc fileName = filePath.substring(filePath.indexOf("\\"));
199                                 String JavaDoc extension = fileName.substring(fileName.indexOf("."));
200
201                                 CBLauncher.launchProgram(extension, path + fileName);
202                             }
203                         }
204                         else if (!System.getProperty("os.name").equalsIgnoreCase("SunOS") && desc.toLowerCase().startsWith("mailto")) //TE: spawn default mail client (windows only).
205
{//TE: launches email client...
206
launchClient(desc);
207                         }
208                         else
209                         {
210                             URL url = e.getURL();
211
212 // XXX
213
// Have had no end of trouble trying to do string matching of paths (shame there sin't a decent OO way of doing it with File
214
// objects!). As a result have switched everything to using 'canonical paths'... hopefully that will work :-). - CB
215
// XXX
216

217
218 //CB - base no longer used? if (base != null && url.getProtocol().equals("file")) // possibly this is another template...
219
if (url.getProtocol().equals("file")) // possibly this is another template...
220
{
221
222                                 String JavaDoc fullFileName = "";
223                                 String JavaDoc baseTemplateDirPath = "";
224                                 String JavaDoc pluginTemplateDirectoryPath = "";
225                                 try
226                                 {
227                                 // Assume this is a template, and attempt to obtain template name from url...
228
fullFileName = new File(URLDecoder.decode(url.getFile(), "UTF-8")).getCanonicalPath(); // wierd processing to get standard file separators ('/' or '\') (needed for matching below)
229
baseTemplateDirPath = baseTemplateDir.getCanonicalPath();
230                                     if (pluginTemplateDirectory != null)
231                                         pluginTemplateDirectoryPath = pluginTemplateDirectory.getCanonicalPath();
232                                 }
233                                 catch (IOException e) // not expected...
234
{
235                                     log.log(Level.WARNING, "Exception trying to access HTML file urls " + url.getFile().toString(), e);
236                                 }
237                                 String JavaDoc fileName = "";
238
239                                 if (fullFileName.startsWith(baseTemplateDirPath))
240                                 {
241                                     fileName = fullFileName.substring(baseTemplateDirPath.length());
242                                 }
243 //TODO: this needs to be tested -> do urls between plugin templates work...
244
else if (pluginTemplateDirectory!=null && fullFileName.startsWith(pluginTemplateDirectoryPath))
245                                 {
246                                     fileName = fullFileName.substring(pluginTemplateDirectoryPath.length());
247                                 }
248
249                                 if (fileName.startsWith(File.separator))
250                                     fileName = fileName.substring(1);
251
252                                 fileName = (new File(fileName)).toString();
253
254                                 if (templateExists(fileName))
255                                 {
256                                     setNewTemplate(fileName);
257                                 }
258                                 else
259                                 {
260                                     openPage(url);
261                                 }
262                             }
263                             else
264                             { //TE: if the user has set (via advanced options) to launch URLs in a browser...
265
if ((JXplorer.getProperty("option.url.handling")).equalsIgnoreCase("Launch"))
266                                     launchClient(desc);
267 //TE: otherwise open it in JXplorer...
268
else
269                                     openPage(url);
270                             }
271                         }
272                     }
273                 });
274             }
275         }
276     };
277
278
279
280     /**
281      * Recreates the editor, and sets the text.
282      * @param htmlText the Text (possibly html) to display
283      */

284
285     public void setEditorText(String JavaDoc htmlText)
286     {
287         //System.out.println("-----------\n" + htmlText + "\n----------------\n");
288

289         Dimension current = null;
290         if (editor != null) // reuse editor to avoid memory leak.
291
// TODO: figure out what the JEditorPane doco means about recreating the document
292
{
293             try
294             {
295                 editor.setText(htmlText);
296             }
297             catch (Exception JavaDoc e) // can Sun write code? No, no I don't think they can. If the editor screws up internally, make it again.
298
{
299                 recreateEditor(current, htmlText);
300             }
301         }
302         else
303         {
304             recreateEditor(current, htmlText);
305         }
306         editor.validate();
307
308         // TODO: figure out a way of being able to reuse the viewport without getting exceptions.
309
// In Java 1.5 exceptions are thrown more than not when reusing the viewport.
310
// Now we will recreated it each time :-S
311
try
312         {
313             viewport.setView(editor);
314         }
315         catch (ArrayIndexOutOfBoundsException JavaDoc e) // XXX sun stuff sometimes throws an exception, claiming the viewport has no existing child??
316
{
317             viewport = new JViewport();
318             viewport.setView(editor);
319             scrollDisplay.setViewport(viewport);
320         }
321     }
322
323     /**
324      * The Swing editor is a fragile beast, and must be frequently executed because deep inside it is as
325      * buggy a piece of crap as Sun ever wrote.
326      * @param current
327      * @param htmlText
328      */

329     private void recreateEditor(Dimension current, String JavaDoc htmlText)
330     {
331         editor = getNewEditor();
332         if (current == null) // this occasionally happens. *shrug*
333
{
334             //System.out.println("CURRENT IS NULL???");
335
current = new Dimension (400,400);
336         }
337         editor.setSize(current);
338         editor.setText(htmlText);
339     }
340
341
342     /**
343      * As advised in the doco, it is apparently better to re-create an
344      * editor pane every time, rather than reuse the old one. Phenomenal.
345      *
346      * Sept '04 - this method causes a memory leak, so calling repeatedly
347      * is not advised. The doco actually advises recreating the document
348      * object, however for our purposes we can probably accept the performance
349      * hit of tearing down the old document and rebuilding it. Seems to fix
350      * the memory leak anyway :-).
351      */

352
353     protected JEditorPane getNewEditor()
354     {
355         // this fixes the memory leak, but removes the point of the method -
356
// better not to call it at all.
357
//if (editor != null) { return editor; }
358

359         //System.out.println("Getting new editor");
360

361         JEditorPane newEditor = new JEditorPane();
362
363         newEditor.setEditorKitForContentType("text/html", htmlEditorKit);
364         newEditor.addHyperlinkListener(hyperlinkListener);
365         newEditor.setEditable(false);
366         newEditor.setMinimumSize(new Dimension(400, 400));
367         newEditor.setContentType("text/html");
368
369         return newEditor;
370
371     }
372
373     /**
374      * <p>This code is run by both constructors. It sets up the GUI and the template lists, and other
375      * housekeeping tasks.</p>
376      * @param owner
377      * @param props
378      * @param resourceLoader
379      */

380     private void commonConstructorCode(Component owner, Properties props, CBResourceLoader resourceLoader)
381     {
382         initMyProperties(props);
383
384         this.resourceLoader = resourceLoader;
385
386         setupTemplateLists();
387
388 /*
389         baseURL = JXplorer.getFileURL(myProperties.getProperty("dir.templates"));
390         try
391         {
392             base = new URL(baseURL);
393         }
394         catch (MalformedURLException e)
395         {
396             log.warning(" unable to parse file url: " + baseURL + "\n ( error was: " + e + " )");
397         }
398
399         localURL = myProperties.getProperty("dir.local"); //TE: gets the path of the users local dir.
400 */

401         initGUI(owner);
402
403         setStartPage();
404
405
406
407     }
408
409     /**
410      * <p>This searches the template directories at start up, and builds up a list
411      * of available templates, keyed by lowercase object class.</p>
412      */

413     private void setupTemplateLists()
414     {
415         try
416         {
417             // unpack any plugin templates (sets 'pluginTemplateDirectory')
418
initZipTemplates();
419
420             // Find the root of the /template directory tree
421
baseTemplateDir = getBaseTemplateDirectory();
422             String JavaDoc baseTemplate = baseTemplateDir.getCanonicalPath();
423
424             // get the list of default html templates that can be used for all object classes
425
String JavaDoc[] defaultTemplates = CBUtility.readFilteredDirectory(baseTemplate, new String JavaDoc[]{"html", "htm"});
426
427             addToGlobalTemplateList(defaultTemplates, DEFAULT);
428
429             // do the same for the plugin templates (if any)
430
if (pluginTemplateDirectory != null)
431             {
432
433                 defaultTemplates = CBUtility.readFilteredDirectory(pluginTemplateDirectory.getCanonicalPath(), new String JavaDoc[]{"html", "htm"});
434                 addToGlobalTemplateList(defaultTemplates, "");
435             }
436
437             if (defaultTemplates == null || defaultTemplates.length == 0)
438                 log.warning("Warning - can't find any default html templates in " + baseTemplate);
439
440             // get the list of object class directories (e.g. /person, /organizationalUnit etc.)
441
String JavaDoc[] objectClassFolders = getAllTemplateSubDirectories(baseTemplateDir);
442             addIndividualObjectClassTemplates(objectClassFolders, baseTemplate);
443
444             // do the same for the plugin templates (if any)
445
if (pluginTemplateDirectory != null)
446             {
447                 objectClassFolders = getAllTemplateSubDirectories(pluginTemplateDirectory);
448                 addIndividualObjectClassTemplates(objectClassFolders, pluginTemplateDirectory.toString());
449             }
450
451             //printTemplates();
452
}
453         catch (FileNotFoundException e)
454         {
455             log.warning("Error initialising HTML Template: " + e.toString());
456         }
457         catch (IOException e2)
458         {
459             log.warning("Error initialising HTML Template file paths: " + e2.toString());
460         }
461     }
462 /*
463     private void printTemplates()
464     {
465             System.out.println("***PRINTING TEMPLATES VARIABLE***");
466             Enumeration bloop = templates.keys();
467             while (bloop.hasMoreElements())
468             {
469                 String key = (String)bloop.nextElement();
470                 System.out.println("hashtable: " + key);
471                 File[] files = (File[]) templates.get(key);
472                 if (files == null)
473                     System.out.println(" NULL !");
474                 else
475                     for (int i=0; i<files.length; i++)
476                         System.out.println(" -> " + files[i].toString());
477             }
478     }
479 */

480     private void addIndividualObjectClassTemplates(String JavaDoc[] objectClassFolders, String JavaDoc baseTemplate)
481     {
482         // search the discovered object class directories, adding their html templates to the global hash.
483
for (int i = 0; i < objectClassFolders.length; i++)
484         {
485             String JavaDoc folderName = baseTemplate + File.separator + objectClassFolders[i];
486             String JavaDoc objectClass = objectClassFolders[i];
487             String JavaDoc[] ocTemplates = CBUtility.readFilteredDirectory(folderName, new String JavaDoc[]{"html", "htm"});
488             addToGlobalTemplateList(ocTemplates, objectClass);
489         }
490     }
491
492     /**
493      * <p>Adds a directory of html files (with paths relative to baseTemplateDir) to the global hash, keyed by lower case object class.</p>
494      * @param fileNames the individual file names
495      * @param folderName the name of the folder, in mixed case, which is also the object class to key by.
496      */

497     private void addToGlobalTemplateList(String JavaDoc[] fileNames, String JavaDoc folderName)
498     {
499         if (fileNames == null) // there may not be any templates at all...
500
return;
501
502         String JavaDoc objectClass = folderName.toLowerCase();
503
504         File[] fileList = new File[fileNames.length];
505         for (int i = 0; i < fileNames.length; i++)
506         {
507             if (DEFAULT.equals(folderName))
508                 fileList[i] = new File(fileNames[i]);
509             else
510                 fileList[i] = new File(folderName, fileNames[i]);
511         }
512
513         // add the array of files to the hashtable, keyed by lowercase object class.
514
templates.put(objectClass, fileList);
515     }
516
517     /**
518      * <p>CONSTRUCTOR METHOD: returns all sub directories under the template directory</p>
519      * <p>These correspond to the various object classes.</p>
520      * @param baseTemplateDir
521      * @return
522      */

523     private String JavaDoc[] getAllTemplateSubDirectories(File baseTemplateDir)
524     {
525         String JavaDoc[] childDirectories = baseTemplateDir.list(new FilenameFilter()
526         {
527             public boolean accept(File dir, String JavaDoc name)
528             {
529                 File candidate = new File(dir, name);
530                 return candidate.isDirectory();
531             }
532         });
533
534         return childDirectories;
535     }
536
537     /**
538      * <p>CONSTRUCTOR METHOD: This finds the root of the /templates directory tree, where the
539      * html file templates are stored. (It is also where any templates
540      * in .zip resource files are kept.)</p>
541      * @return the file location of /templates (usually [jxplorer home]/templates )
542      * @throws FileNotFoundException
543      */

544     private File getBaseTemplateDirectory()
545             throws FileNotFoundException
546     {
547         File baseTemplateDir = new File(myProperties.getProperty("dir.templates"));
548         if (!baseTemplateDir.exists())
549         {
550             log.warning("can't find html template directory " + baseTemplateDir + " - trying to find /templates directory");
551             baseTemplateDir = new File(JXplorer.localDir + "templates" + File.separator);
552             if (!baseTemplateDir.exists())
553             {
554                 throw new FileNotFoundException("ERROR - Cannot find backup /template directory in " + baseTemplateDir);
555             }
556         }
557         return baseTemplateDir;
558     }
559
560     /**
561      * <p>Gets any resourses from a zip/jar file depending on the object class of the entry.
562      * For example, if the oc is person, this checks the zip/jar file for resources in
563      * templates/oc/. It then extracts these files and puts them in a temporary dir of the
564      * same path within the plugins dir. For example, jxplorer/plugins/templates/oc/Main.html .
565      *
566      * <p>This is Trudi code, that has been kidnapped by Chris and mungified...
567      * It now unpacks permanently, and only does the writing if needed (checks the
568      * date stamps).</p>
569      */

570     private void initZipTemplates()
571     {
572         String JavaDoc[] zipTemplates = null; //TE: stores the names of any resourses found in the zip/jar file.
573

574         File pluginDirectory = new File(JXplorer.getProperty("dir.plugins"));
575         if (!pluginDirectory.exists())
576             pluginDirectory.mkdirs();
577
578         //zipTemplates = resourceLoader.getPrefixedResources("templates/"+className+"/");//+File.separator);// doesn't wk w file.sep??????
579

580         // read all plugin files with the prefix 'templates/'
581

582         zipTemplates = resourceLoader.getPrefixedResources("templates/");
583
584         if (zipTemplates.length == 0)
585             return; // nothing to do!
586

587         pluginTemplateDirectory = new File(pluginDirectory, "templates/");
588
589         // unpack them to the plugins directory.
590

591         int prefixSize = "templates/".length();
592
593         for (int i = 0; i < zipTemplates.length; i++)
594         {
595             // get the template name as a string and as a (potential) file.
596
String JavaDoc templateName = zipTemplates[i];
597
598             if (templateName.length() > prefixSize)
599             {
600                 String JavaDoc templateRelativeFileName = CBParse.replaceAllChar(new StringBuffer JavaDoc(templateName), '/', File.separator);
601
602                 File pluginTemplateFile = new File(pluginDirectory + File.separator + templateRelativeFileName);
603
604                 try
605                 {
606                     // See if we need to unpack this template file because it doesn't already exist, or is newer than
607
// the cached version.
608
if ((pluginTemplateFile.exists() == false) ||
609                             (pluginTemplateFile.lastModified() < resourceLoader.getLastModified(templateName)))
610                     {
611                         if (templateRelativeFileName.endsWith(File.separator)) // it's a directory - just make it!
612
{
613                             pluginTemplateFile.mkdirs();
614                         }
615                         else
616                         {
617                             if (!pluginTemplateFile.getParentFile().exists())
618                                 pluginTemplateFile.getParentFile().mkdirs();
619
620                             byte[] b = resourceLoader.getResource(templateName); //TE: read the resource into a byte array.
621

622                             try
623                             {
624                                 FileOutputStream output = new FileOutputStream(pluginTemplateFile);
625                                 output.write(b);
626                                 output.close();
627                             }
628                             catch (java.io.IOException JavaDoc e)
629                             {
630                                 CBUtility.error("Problem writing unpacked plugin template file: " + pluginTemplateFile + " to disk \n ", e);
631                             }
632                         }
633                     }
634                 }
635                 catch (ZipException JavaDoc e)
636                 {
637                     CBUtility.error("Problem accessing plugin zip file: " + e);
638                 }
639             }
640         }
641 /*XXX NEEDED???
642         if (zipTemplates!=null)
643         { //TE: add any templates to the combo box...
644             for(int j=0;j<zipTemplates.length;j++)
645             {
646                 if (zipTemplates[j].endsWith(".html") || zipTemplates[j].endsWith(".htm"))
647                 {
648                     templateNames.add(zipTemplates[j].substring(10)); //TE: cut the prefix 'templates/' off the name of the HTML template for normal oc display handling.
649                 }
650             }
651         }
652 */

653     }
654
655     /**
656      * CONSTRUCTOR METHOD: Finds and sets up the start page displayed when JX first loads. This can be localised.
657      * XXX
658      * XXX URL MAGIC: This will fail on pathalogical urls, since Sun's file URL Loader can't cope with special
659      * XXX characters in file names (e.g. '#', '@' etc). We go to insane lengths to handle this in the
660      * XXX template stuff by loading the html text manually via a file reader, and then massaging the
661      * XXX html - but I can't be bothered doing it for this one special case.
662      * XXX
663      */

664     private void setStartPage()
665     {
666
667         if (editor == null) editor = getNewEditor();
668
669
670         String JavaDoc htmldocs = myProperties.getProperty("dir.htmldocs", JXplorer.localDir + "htmldocs" + File.separator);
671         try
672         {
673             final String JavaDoc language = Locale.getDefault().getLanguage();
674             File localeSpecificStartFile = new File(htmldocs + startFile + "_" + language + ".html");
675             if (localeSpecificStartFile.exists() == false)
676             {
677                 log.warning("unable to find locale specific start file: " + localeSpecificStartFile);
678                 localeSpecificStartFile = new File(htmldocs + startFile + ".html");
679                 if (localeSpecificStartFile.exists() == false)
680                 {
681                     log.warning("unable to find locale specific start file: " + localeSpecificStartFile);
682                     editor.setText("<html><head><title>JXplorer Start Screen</title></head>" +
683                                    "<body><h2><font face=\"arial\">Welcome to JXplorer...</font></h2><p>" +
684                                    "<font face=\"arial\">This panel will display the results of your directory browsing and searches.</font></p>" +
685                                    "<p><font face=\"arial\">If you need any assistance, use the help option on the menu bar above.</font></p>" +
686                                    "</body></html>");
687                     validate(); // necessary?
688
return;
689                 }
690             }
691             openPage(localeSpecificStartFile.toURL());
692             validate(); // necessary?
693
}
694         catch (IOException e)
695         {
696             log.warning("unable to open welcome page. " + e);
697         }
698     }
699
700     /**
701      * <p>CONSTRUCTOR METHOD: Sets up the GUI components; the combo box and the display pane.</p>
702      * @param owner the parent GUI to initialise from.
703      */

704     private void initGUI(Component owner)
705     {
706         setLayout(new BorderLayout());
707         NODATA = "<html><head><title>" + CBIntText.get("No Data") + "</title></head><body><h2><font face=\"arial\">" + CBIntText.get("Select an entry to view data") + "</font></h2></body></html>";
708         NOVALUEFOUND = "<i>" + CBIntText.get("No Value Found") + "</i>";
709         viewport = new JViewport(); // was CBViewport
710
scrollDisplay = new JScrollPane();
711         initToolBar();
712         add(toolBar, BorderLayout.NORTH);
713         add(scrollDisplay);
714         htmlEditorKit = new MyHTMLEditorKit(this);
715         hyperlinkListener = new MyHyperlinkListener();
716         editor = getNewEditor();
717         viewport.setView(editor);
718         scrollDisplay.setViewport(viewport);
719         display = owner;
720     }
721
722     private void initMyProperties(Properties props)
723     {
724         if (props == null)
725         {
726             CBUtility.error("unable to find html templates", new Exception JavaDoc("Null properties list passed to HTML template display - unable to use templates..."));
727             myProperties = new Properties();
728         }
729         else
730             myProperties = props;
731     }
732
733     /**
734      * Checks whether a particular candidate string corresponds to the name of a template
735      * in the viewTemplates combo box.
736      * @return whether it exists.
737      */

738
739     protected boolean templateExists(String JavaDoc candidate)
740     {
741 /*
742         if (candidate.endsWith(".htm")) // trim .htm?
743             candidate = candidate.substring(0, candidate.length()-4); // extension to match
744         else if(candidate.endsWith(".html")) // with template names
745             candidate = candidate.substring(0, candidate.length()-5);
746 */

747
748
749         for (int i = 0; i < viewTemplates.getItemCount(); i++)
750         {
751             String JavaDoc name = (String JavaDoc) viewTemplates.getItemAt(i);
752             if (name.equalsIgnoreCase(candidate)) return true; // CASE SENSITIVE CODE
753
}
754         return false;
755     }
756
757     /**
758      * Sets up the initial tool bar. The toolbar should have different numbers of
759      * components visible, depending on the users privileges and whether
760      * or not they're actively editing the page...
761      */

762
763     public void initToolBar()
764     {
765         toolBar = new JToolBar();
766         String JavaDoc[] errorMessage = {CBIntText.get("no templates found")};
767         String JavaDoc[] templates = readTemplateNames(new String JavaDoc[]{});
768         if (templates == null || templates.length == 0)
769             templates = errorMessage;
770
771         viewTemplates = new CBJComboBox(templates);
772         viewTemplates.setEditable(false);
773         viewTemplates.setAlignmentY(Component.TOP_ALIGNMENT);
774
775         viewTemplates.setToolTipText(CBIntText.get("Select a template to view attributes with"));
776
777         toolBar.add(viewTemplates);
778
779         /*
780          * Add Action Listeners to the different Tool Bar Components
781          */

782         viewTemplates.addActionListener(new ActionListener JavaDoc()
783         {
784             public void actionPerformed(ActionEvent JavaDoc e)
785             {
786                 if (settingUpTemplates == true) return; // ignore 'changes' that are simply adding options to combo box.
787

788                 if ((e == null) || (e.getSource() == null)) return; // sanity check
789
if (viewTemplates.getSelectedItem() == null) return; // sanity check
790

791                 String JavaDoc templateName = viewTemplates.getSelectedItem().toString();
792                 if (templateName.equalsIgnoreCase(currentTemplateName)) return; // nothing *really* happened // CASE SENSITIVE CODE
793

794                 setNewTemplate(templateName);
795
796                 repaint();
797             }
798         });
799
800     }
801
802
803     public void setNewTemplate(String JavaDoc templateName)
804     {
805         String JavaDoc current = (String JavaDoc) viewTemplates.getSelectedItem();
806         if (templateName.equalsIgnoreCase(current) == false) // CASE SENSITIVE CODE
807
{
808             viewTemplates.setSelectedItem(templateName);
809         }
810         currentTemplateName = templateName;
811
812         openNewTemplate(templateName);
813         displayEntry(currentEntry, currentDataSource); // same old data, different template
814
}
815
816
817     /**
818      * Adds an array of files to the templateNames list (which eventually turns
819      * into the displayed combo box).
820      */

821
822     private void addFileListToTemplateNames(ArrayList templateNames, File[] fileList)
823     {
824         if (fileList == null)
825         {
826             return;
827         }
828
829         for (int i = 0; i < fileList.length; i++)
830         {
831             templateNames.add(fileList[i].toString());
832         }
833     }
834
835     /**
836      * Creates the set of html template names corresponding to a given set of objectClassNames.
837      */

838
839     public String JavaDoc[] readTemplateNames(String JavaDoc[] objectClassNames)
840     {
841         //printTemplates();
842

843         // This is the list of available templates that will be displayed in the combo box.
844
ArrayList templateNames = new ArrayList();
845
846         // Always add in the defaults...
847
addFileListToTemplateNames(templateNames, (File[]) templates.get(DEFAULT));
848
849         // Now find the templates for each known object class, and store those.
850
for (int classNo = 0; classNo < objectClassNames.length; classNo++)
851         {
852             String JavaDoc className = objectClassNames[classNo].toLowerCase();
853             addFileListToTemplateNames(templateNames, (File[]) templates.get(className));
854         }
855
856         // dump the stored names into a string array
857
String JavaDoc[] templates = (String JavaDoc[]) templateNames.toArray(new String JavaDoc[templateNames.size()]);
858
859         Arrays.sort(templates);
860
861         return templates;
862     }
863
864
865     /**
866      * Try to open a new template. Try both ".html" and ".htm"
867      * extensions if necessary. Start in subdirectory (for object
868      * class specific templates) and then try the default template
869      * directory for general templates.
870      */

871
872     public boolean openNewTemplate(String JavaDoc templateName)
873     {
874         // Try to open the template file in the normal templates directory
875
File templateFile = new File(baseTemplateDir, templateName);
876         if (templateFile.exists() == false)
877         {
878             //... if that fails, try to find it in the plugin directory...
879
templateFile = new File(pluginTemplateDirectory, templateName);
880             if (templateFile.exists() == false)
881                 return CBUtility.error(display, CBIntText.get("Can't find html template! ") + templateName);
882         }
883
884         try
885         {
886             htmlText = new StringBuffer JavaDoc(CBUtility.readTextFile(templateFile));
887
888             // parse file and set paths correctly
889
htmlText = parseNewTemplate(htmlText, templateFile.toURI().toURL());
890             baseText = htmlText.toString(); // set the base template text.
891
}
892         catch (IOException e)
893         {
894             return CBUtility.error(display, CBIntText.get("Can't read html template! ") + templateFile.getAbsolutePath());
895         }
896         return true;
897
898 /*
899         if (subdir == null) subdir = "";
900         if (subdir.length() > 0)
901             if (subdir.endsWith("/") == false)
902                 subdir += "/";
903
904         if (baseURL == null) baseURL = "";
905         if (baseURL.length() > 0)
906             if (baseURL.endsWith("/") == false)
907                 baseURL += "/";
908
909         URL url;
910
911         String baseTemplatePath = myProperties.getProperty("dir.templates");
912
913         String fileName = baseTemplatePath + templateURL; //TE: gets the path & name of each template that is displayed. I.e when a tab is clicked.
914
915         File template = new File(fileName);
916
917         try
918         {
919             htmlText = new StringBuffer(CBUtility.readTextFile(template));
920
921             url = new URL(baseURL + subdir + templateURL);
922
923             // parse file and set paths correctly
924             htmlText = parseNewTemplate(htmlText, url);
925             baseText = htmlText.toString(); // set the base template text.
926         }
927         catch (Exception e)
928         {
929             try
930             {
931 */

932                 /**
933                  * Probably not a politically correct way to find out if there are any plugin templates..
934                  * ..but that is what this is doing. If JX can't find a template in the normal JX dir,
935                  * then this checks the plugins dir for a (temporary) template dir. If the template still
936                  * can't be found then it displays the error message.
937                  *
938                  * The template is added to the combo box without the 'templates' prefix i.e: templates/person/whatever.html
939                  * so that normal picking up of the templates can occur in respect of object class. In other words if
940                  * there is a plugins dir of 'person' as well as the default one, JX will display the template that is
941                  * is first in ASCII order.
942                  *
943                  * This assumes that the user places any templates in a zip/jar file in the following dir format...
944                  * templates/"objectclass name"/"template name.html". (replacing names in commars).
945                  */

946 /*
947                 String temp = new String(resourceLoader.getResource("templates/" + templateURL)); //TE: read the html template from the zip/jar file.
948
949                 templateURL = "temp" + File.separator + templateURL; //TE: add the prefix so the HTML file can be found in the zip/jar file.
950
951                 htmlText = new StringBuffer(temp);
952                 //TODO: get Trudi to explain how this works?
953                 url = new URL(JXplorer.getFileURL(localURL) + templateURL); //TE: point to the templates dir in the plugins dir rather than the one in JX.
954
955                 // parse file and set paths correctly
956                 htmlText = parseNewTemplate(htmlText, url); //TE: parse as normal.
957                 baseText = htmlText.toString(); //TE: important to set this so JX knows where to find any images etc that are referenced by the HTML template.
958             }
959             catch (Exception ee)
960             {
961                 return CBUtility.error(display, CBIntText.get("Can't find html template! ") + fileName, e);
962             }
963         }
964
965         return true;
966 */

967     }
968
969
970     /* Pre-parses the html file, doing hack workarounds to make images
971      * work under broken Java 1.2.0 swing.
972      *
973      * All this could be done more aesthetically using the HTMLEditorKit...
974      * But we're on a deadline, and it doesn't seem to work properly; so
975      * we'll hack it by hand for the time being... Especially since the
976      * *(&^ swing HTMLDocument documentBase property doesn't seem to
977      * work for generated documents (i.e. you can't set it!) so we need
978      * to stick in fully qualified base refs to things like images etc...
979      */

980
981     public StringBuffer JavaDoc parseNewTemplate(StringBuffer JavaDoc templateText, URL url)
982     {
983         // XXX DANGER WILL ROBINSON
984
// XXX INCREDIBLY SCREWED SUN URL HANDLING
985
// XXX file:// HIGHLY UNRELIABLE
986
//
987
// bottom code is carefully hacked to produce a base url reference
988
// that may work on solaris under jre 1.3 as well as normal NT.
989
// This can be very easily messed up (for example by naively using
990
// suns URL class as a constructor). Be carefull.
991

992         String JavaDoc baseTagURL = url.getPath();
993
994         // note - force use of 'file://' prefix. URL constructed version would only
995
// have file: prefix, ommitting double slash. While both versions may work,
996
// it seems to be variable...
997

998         //XXX should we be trying to do something clever with the File.toURL() method here?
999

1000        baseTagURL = "file://" + baseTagURL.substring(0, baseTagURL.lastIndexOf('/') + 1);
1001
1002        int headPos = templateText.toString().indexOf("<head>");
1003
1004        String JavaDoc baseTag = "\n<base HREF=\"" + baseTagURL + "\">\n";
1005
1006        templateText.insert(headPos + 7, baseTag); //TE: was templateText.insert(headPos+6, baseTag); ??? html = <html <base href...> >
1007
// System.out.println(templateText);
1008
return templateText;
1009    }
1010
1011    /**
1012     * Returns a template file given the root path and name of the file.
1013     *
1014     * @param fileNameAndPath the name and path, but <b>not</b> the extension,
1015     * of the template file
1016     *
1017     * @return the File object found. This may be null, or may not exist; these
1018     * conditions must be checked for.
1019     */

1020
1021    public File getTemplateFile(String JavaDoc fileNameAndPath)
1022    {
1023        String JavaDoc fileName = fileNameAndPath + ".html";
1024        File templateFile = new File(fileName);
1025        if (templateFile.exists() == false) // check file exists, try '.htm' ext. if not
1026
templateFile = new File(fileNameAndPath + ".htm");
1027        return templateFile;
1028    }
1029
1030
1031    public String JavaDoc[] getObjectClasses(DXAttributes atts)
1032    {
1033        try
1034        {
1035            Attribute JavaDoc a = atts.getAllObjectClasses();
1036
1037            if (a == null) return new String JavaDoc[]{};
1038
1039            DXNamingEnumeration en = new DXNamingEnumeration(a.getAll());
1040            en.sort(); // alphabetacize.
1041

1042            String JavaDoc[] ret = en.toStringArray();
1043
1044            return ret;
1045        }
1046        catch (NamingException JavaDoc e)
1047        {
1048            log.warning("unable to read object classes in AttributeDisplay: " + e.toString());
1049        }
1050        return null;
1051    }
1052
1053    /**
1054     * Concatenates a string array of alphabetically ordered object Classes into
1055     * one long string, providing a unique String for this combination of classes.
1056     *
1057     */

1058
1059    public String JavaDoc getObjectClassSignature(String JavaDoc[] objectClasses)
1060    {
1061        String JavaDoc ret = "";
1062        if (objectClasses == null) return "";
1063        for (int i = 0; i < objectClasses.length; i++)
1064            ret += objectClasses[i];
1065        return ret;
1066    }
1067
1068
1069    /**
1070     * Checks if the list of object classes has changed. If it has,
1071     * reset the 'oldClassSignature' and return true, otherwise return
1072     * false.
1073     */

1074
1075    public boolean objectClassesChanged(String JavaDoc classesSignature)
1076    {
1077        return !((oldObjectClassesSignature != null) && (oldObjectClassesSignature.equals(classesSignature)));
1078    }
1079
1080
1081    public void displayEntry(DXEntry entry, DataSource formDataSource)
1082    {
1083        if (entry == null || entry.size() == 0)
1084        {
1085            setEditorText(NODATA);
1086            return;
1087        }
1088
1089        currentDataSource = formDataSource; // used by form submission handler in MyHTMLEditorKit.
1090

1091        currentEntry = entry;
1092
1093        String JavaDoc[] objectClasses = getObjectClasses(entry);
1094        if (objectClasses == null)
1095        {
1096            log.warning("unable to find any object classes for " + entry.getDN().toString());
1097            setEditorText(NODATA);
1098            return;
1099        }
1100
1101        setupTemplates(objectClasses, entry); // change templates if necessary...
1102

1103
1104        if (entry == null)
1105        {
1106            CBUtility.error(this, CBIntText.get("Error. No data for this node!"), null);
1107            setEditorText(NODATA);
1108            return;
1109        }
1110        displayData(entry);
1111    }
1112
1113    /**
1114     * Takes a list of object classes, and if the object classes to display have
1115     * changed modifies the list of available templates to display only appropriate
1116     * templates.
1117     */

1118    void setupTemplates(String JavaDoc[] objectClasses, DXEntry entry)
1119    {
1120        String JavaDoc objectClassesSignature = getObjectClassSignature(objectClasses);
1121
1122        // change the template viewing combo box to a new set of templates, if objectClass has changed
1123
if (objectClassesChanged(objectClassesSignature))
1124        {
1125            // remember the current menu position for later
1126
viewTemplatesPos.put(oldObjectClassesSignature, new Integer JavaDoc(viewTemplates.getSelectedIndex()));
1127            oldObjectClassesSignature = objectClassesSignature;
1128
1129            // disable combo box action listener using flag
1130
settingUpTemplates = true;
1131
1132            // clear all existing combo box templates
1133
viewTemplates.removeAllItems();
1134
1135            // read the list of new templates for the particular object classes this entry has.
1136
String JavaDoc[] templates = readTemplateNames(objectClasses);
1137
1138            if ((templates == null) || (templates.length == 0))
1139            // make sure that we found some! (We *should* find at least the default templates)
1140
log.warning("No templates found for objectClasses " + objectClassesSignature);
1141            else
1142            {
1143                // load the combo box with the listed templates, in the order we got them from readTemplateNames
1144
for (int i = 0; i < templates.length; i++)
1145                    viewTemplates.addItem(templates[i]);
1146
1147
1148                if (viewTemplatesPos.containsKey(objectClassesSignature))
1149                {
1150                    // If we've viewed this object class set before, try to use the same template as last time.
1151
int indexPos = ((Integer JavaDoc) viewTemplatesPos.get(objectClassesSignature)).intValue();
1152                    if (indexPos < templates.length)
1153                        viewTemplates.setSelectedIndex(indexPos);
1154                }
1155                else
1156                {
1157                    // if we *haven't* viewed this object class set before...
1158
// ... set the combo box to show the first option ('all') by default
1159
viewTemplates.setSelectedIndex(0);
1160
1161                    // ... and try to set the view to the most specific available template
1162
attemptToSetOCSpecificTemplate(entry, templates);
1163                }
1164                String JavaDoc templateName = viewTemplates.getSelectedItem().toString();
1165                openNewTemplate(templateName);
1166            }
1167            settingUpTemplates = false; // re-enable combo box action listener
1168
}
1169    }
1170
1171    /**
1172     * This attempts to match a list of template names with the deepest possible
1173     * object class.
1174     */

1175
1176    protected void attemptToSetOCSpecificTemplate(DXAttributes entry, String JavaDoc[] templates)
1177    {
1178        //String baseOC = ((DXAttributes)entry).getBaseObjectClass();
1179
Vector ocs = (entry).getOrderedOCs();
1180
1181        for (int i = 0; i < ocs.size(); i++)
1182        {
1183            String JavaDoc oc = ((String JavaDoc) ocs.get(i)).toLowerCase();
1184            for (int j = 0; j < templates.length; j++)
1185            {
1186                String JavaDoc template = templates[j].toLowerCase();
1187                if (template.startsWith(oc))
1188                {
1189                    settingUpTemplates = true;
1190                    viewTemplates.setSelectedIndex(j);
1191                    settingUpTemplates = false;
1192                    return;
1193                }
1194            }
1195        }
1196    }
1197
1198
1199    /**
1200     * Checks if the HTML page has any custom tags such as...
1201     * <p><dxtemplate:get-all-attributes style="list"/></p>
1202     * <p><dxtemplate:get-attribute name="cn" style="list"/></p>
1203     * if so it enters the data. If the tag is 'get-all-attributes', all
1204     * the attributes are included in the page. If the tag is 'get-attribute', the
1205     * specific attribute is displayed.
1206     * This method also kicks off the handling of inserting form data.
1207     * @param entry the entry that we are trying to display.
1208     */

1209
1210    protected void displayData(DXEntry entry)
1211    {
1212        if (entry == null)
1213        {
1214            setEditorText(NODATA);
1215            return;
1216        }
1217
1218        int tagstart = 0; // the start of the ATTRIBTAG html tag
1219
int tagend; // the end of the ATTRIBTAG html tag
1220

1221        //int htmlTagLen = ATTRIBTAG.length();
1222

1223        htmlText = new StringBuffer JavaDoc(baseText);
1224
1225        // check if doco is XHTML, and try to convert to HTML 3.2 by replacing all end tags '/>' with '>'
1226
htmlText = parseXHTML(htmlText);
1227
1228
1229        mediaCheck(entry, "jpegPhoto"); //TE: checks for jpegPhoto and creates temporary file that can be later displayed in a template.
1230
mediaCheck(entry, "audio"); //TE: checks for audio and creates temporary file that can be later displayed in a template.
1231
mediaCheck(entry, "odDocumentDOC"); //TE: checks for odDocumentDOC and creates temporary file that can be later displayed in a template.
1232
mediaCheck(entry, "odSpreadSheetXLS"); //TE: checks for odSpreadSheetXLS and creates temporary file that can be later displayed in a template.
1233
mediaCheck(entry, "odMusicMID"); //TE: checks for odMusicMID and creates temporary file that can be later displayed in a template.
1234
mediaCheck(entry, "odSoundWAV"); //TE: checks for odSoundWAV and creates temporary file that can be later displayed in a template.
1235
mediaCheck(entry, "odMovieAVI"); //TE: checks for odMovieAVI and creates temporary file that can be later displayed in a template.
1236

1237
1238        tagstart = htmlText.indexOf(ATTRIBTAG, tagstart);
1239        while (tagstart >= 0)
1240        {
1241            tagend = htmlText.indexOf(">", tagstart);
1242            String JavaDoc tempTag = htmlText.substring(tagstart, tagend);
1243
1244            String JavaDoc attName = "";
1245            if (tempTag.indexOf("get-all-attributes") > 0) //TE: splat all attribute values onto the page.
1246
attName = "all";
1247            else //TE: get the name of the specific attribute to splat. The next line is basically just getting the attribute name between the quotes e.g. 'cn' from name="cn".
1248
attName = tempTag.substring(tempTag.indexOf("name=\"") + 6, tempTag.indexOf("\"", tempTag.indexOf("name=\"") + 6));
1249
1250            String JavaDoc modifier = null;
1251
1252            if (tempTag.indexOf("style=\"") > 0) //TE: get the name of the specific attribute to splat. The next line is basically just getting the style of display from between the quotes e.g. 'list' from style="list".
1253
modifier = tempTag.substring(tempTag.indexOf("style=\"") + 7, tempTag.indexOf("\"", tempTag.indexOf("style=\"") + 7));
1254
1255            htmlText.delete(tagstart, tagend + 1); //TE: remove the tag, we don't need it anymore.
1256
if (attName.equalsIgnoreCase("all")) //TE: make new tags for all the attributes and splat them into where the old tag use to be.
1257
htmlText.insert(tagstart, formattedAllAttributes(currentEntry, modifier));
1258            else //TE: make a new tag for the attribute specified and splat it into where the old tag use to be.
1259
htmlText.insert(tagstart, formattedAttribute(attName, currentEntry, modifier)); //TE: splat certain attributes.
1260

1261            //TE: moves the position to the beginning of the next custom tag, if there is one and...
1262
//TE: breaks the loop if there are no more tags i.e. tagstart would =-1.
1263
tagstart = htmlText.indexOf(ATTRIBTAG, tagstart);
1264
1265        }
1266        if ((htmlText == null) || (htmlText.length() == 0))
1267        {
1268            log.warning("HTMLTemplateDisplay:displayNodeData - bad html String " + ((htmlText == null) ? " (is null!)" : ""));
1269            setEditorText(NODATA);
1270            return;
1271        }
1272
1273        String JavaDoc htmlString = htmlText.toString().trim();
1274
1275        htmlString = insertFormData(htmlString, entry);
1276
1277
1278        try
1279        {
1280            setEditorText(htmlString);
1281        }
1282        catch (EmptyStackException e) // the amazingly buggy HTML editor has done it again...
1283
{
1284            log.warning("Another Bug in Sun HTML Component: " + e);
1285        }
1286
1287        scrollDisplay.getVerticalScrollBar().setValue(0); //TE: sets the scroll bar back to the top.
1288
viewport.setViewPosition(new Point(0, 0)); //TE: sets the view back to the top.
1289
}
1290
1291
1292    /**
1293     * Checks if there is any jpegPhoto, audio or odDocumentDOC attributes in the entry if so creates temporary files for them
1294     * only if there isn't any already. Gets the byte[] of the jpegPhoto, audio or odDocumentDOC attributes of the entry being
1295     * displayed. Makes a temp directory called 'temp'. Lists all files in the directory, if there are
1296     * any temp files for the jpegPhoto, audio or odDocumentDOC attributes in question it does not recreate them. Otherwise, if
1297     * there isn't any temp files for the entry, it goes ahead and makes them. The temp files are named
1298     * as followed: dn+unique number+.jpg. The temp files and directory are removed when the JX exists.
1299     * @param entry the entry that is to be displayed.
1300     * @param type the type of media being checked for (jpegPhoto, audio or odDocumentDOC).
1301     */

1302
1303    protected void mediaCheck(DXEntry entry, String JavaDoc type)
1304    {
1305        DXAttribute attribute = null;
1306        attribute = (DXAttribute) entry.get(type);
1307
1308        if (attribute == null)
1309            return;
1310
1311        currentDN = entry.getDN().toString(); //TE: the name of the dn becomes the main part of the temporary jpegPhoto or audio file.
1312
currentDN = Integer.toString(currentDN.hashCode()); //TE: make a hash code of it.
1313

1314        int size = attribute.size(); //TE: the amount of jpegPhoto or audio attributes in the entry.
1315

1316        if (attribute != null)
1317        {
1318            CBCache.createCache(entry.getDN().toString(), entry, type, size); //TE: creates a cache for the jpegPhoto or audio file.
1319
}
1320    }
1321
1322
1323
1324    /**
1325     * Changes XHTML into standard HTML for display.
1326     * (Currently all this involves is changing any string '/&gt;' into '&gt;').
1327     */

1328    // (Currently all this involves is changing any string '/>' into '>').
1329

1330    static public StringBuffer JavaDoc parseXHTML(StringBuffer JavaDoc html)
1331    {
1332        return CBParse.replaceAllBufferString(html, "/>", ">");
1333    }
1334
1335    /**
1336     * This method looks for form elements, and fills in the initial form values based on
1337     * the entry data received. It is fairly picky about white space - it prefers there to
1338     * be minimal whitespace in the form html. Also, there is minimal form validation; an
1339     * incorrect form will cause all sorts of mess.<p>
1340     * Note that if <i>anything</i> is wrong with the form, this will simply fail with
1341     * an exception (probably a substring exception).
1342     *
1343     */

1344
1345    // XXX This should be rewritten to correctly use the HTML Document object model, but I don't
1346
// XXX have time right now to work out how to do that :-) - CB
1347

1348    protected String JavaDoc insertFormData(String JavaDoc htmlString, DXEntry entry)
1349    {
1350        if (htmlString.indexOf("<form") < 0)
1351        {
1352            if (currentBinaryAttributes.size() > 0)
1353                currentBinaryAttributes.clear();
1354            return htmlString; // no forms today.
1355
}
1356
1357        try
1358        {
1359            htmlString = insertFormInputData(htmlString, entry);
1360            htmlString = insertFormSelectData(htmlString, entry);
1361            htmlString = insertFormTextAreaData(htmlString, entry);
1362            htmlString = insertFormImageData(htmlString, entry); //TE: inserts jpegPhotos into the html template.
1363
htmlString = insertFormAudioData(htmlString, entry); //TE: inserts a link (or links) to temporary audio files which should be played by the systems default player depending on the extension of the file.
1364
}
1365        catch (Exception JavaDoc e) // usually simply that the value can't be found.
1366
{
1367            if (showHTMLErrors)
1368            {
1369                log.warning("Error parsing form html for value insertion in HTMLTemplateDisplay. \n " + e);
1370                e.printStackTrace();
1371            }
1372        }
1373
1374        return htmlString;
1375    }
1376
1377    // XXX This should be rewritten to correctly use the HTML Document object model,
1378
protected String JavaDoc getTagValue(String JavaDoc tagName, String JavaDoc tag)
1379    {
1380        tag = tag.toLowerCase();
1381        tagName = tagName.toLowerCase();
1382        try
1383        {
1384            int start = tag.indexOf(tagName) + tagName.length();
1385            start = tag.indexOf("\"", start) + 1;
1386            if (start < 0) return null;
1387            int end = tag.indexOf("\"", start);
1388            if (end < 0) return null;
1389            String JavaDoc val = tag.substring(start, end);
1390            return val.trim();
1391        }
1392        catch (Exception JavaDoc e)
1393        {
1394            if (showHTMLErrors)
1395                log.warning("error parsing: " + tagName + "\n " + e);
1396            return null;
1397        }
1398    }
1399
1400
1401
1402    /**
1403     * Goes through the html template, checking for any field tags of text type for example:
1404     * <p>
1405     * &#60tr&#62
1406     * &#60th align="right" width="200"&#62Common Name:&#60/th&#62
1407     * &#60td width="230"&#62&#60input type="text" name="cn" value=""/&#62&#60/td&#62
1408     * &#60/tr&#62
1409     * <p>
1410     * If one is found, it checks the name and gets (in this example) the cn value from the entry and inserts
1411     * it into the value part of the tag (for example value="Trudi"). If the attribute is multivalued, the
1412     * input tag (&#60input type="text" name="cn" value=""/&#62) is copied and reused until all of the attribute
1413     * values are inserted. For layout, a &#60/br&#62 is added to the end of multivalued attribute tags. The tag
1414     * is then inserted back into the html template and returned.
1415     * @param htmlString the actual html file that is to be displayed.
1416     * @param entry the current entry that the html file is trying to display.
1417     * @return the updated html file (updated with the values of the text fields that are to be displayed).
1418     */

1419
1420    // XXX This should be rewritten to correctly use the HTML Document object model,
1421
protected String JavaDoc insertFormInputData(String JavaDoc htmlString, DXEntry entry)
1422    {
1423        int tagStart,tagEnd,pos = 0;
1424        StringBuffer JavaDoc multiValuedTag = new StringBuffer JavaDoc(0);
1425
1426        while ((pos = htmlString.indexOf("<input", pos)) >= 0)
1427        {
1428            tagStart = pos;
1429            tagEnd = htmlString.indexOf(">", pos);
1430
1431            String JavaDoc tag = htmlString.substring(tagStart, tagEnd + 1);
1432
1433            String JavaDoc type = getTagValue("type", tag);
1434            String JavaDoc name = getTagValue("name", tag);
1435
1436            DXAttribute attribute = null;
1437            attribute = (DXAttribute) entry.get(name); //TE: get the attribute values that are being processed.
1438

1439            int size = 0;
1440
1441            if (attribute != null)
1442                size = attribute.size(); //TE: get the number of values the attribute has so we can tell if it is multivalued.
1443

1444            if ("text".equalsIgnoreCase(type) && name != null && attribute != null) //TE: if the input type is 'text', and the input name is not null, and the attribute is not null.
1445
{
1446                if (size == 1) //TE: was attribute.size() -> throws a null pointer exception.
1447
tag = insertFormValue(tag, entry, name); //TE: if there is only one value process it normally.
1448
else if (size > 1) //TE: multivalued.
1449
{
1450                    for (int i = 0; i < size; i++)
1451                    { //TE: make a new tag for each attribute value (only used for multivalued attributes),
1452
// for example: <input type="text" name="telephoneNumber" value="9727 8941"/><br/>.
1453
// Then append the tag to a string buffer.
1454
multiValuedTag.append(new String JavaDoc(insertFormValue(tag, entry, name, i) + "<br>"));
1455                    }
1456                    tag = multiValuedTag.toString();
1457                    multiValuedTag.setLength(0);
1458                }
1459            }
1460            else if ("hidden".equalsIgnoreCase(type) && name != null)
1461                tag = insertFormValue(tag, entry, name);
1462            else if ("password".equalsIgnoreCase(type) && name != null && attribute != null)
1463            {
1464                if (attribute.size() == 1)
1465                    tag = insertFormValue(tag, entry, name);
1466                else if (attribute.size() > 1)
1467                {
1468                    for (int i = 0; i < size; i++)
1469                    { //TE: make a new tag for each password value (only used for multivalued attributes),
1470
// for example: <input type="text" name="userPassword" value="*****"/><br/>.
1471
// Then append the tag to a string buffer.
1472
multiValuedTag.append(new String JavaDoc(insertFormValue(tag, entry, name, i) + "<br>"));
1473                    }
1474                    tag = multiValuedTag.toString();
1475                    multiValuedTag.setLength(0);
1476                }
1477            }
1478            pos = tagStart + tag.length(); // reset pos because tag may have grown larger and may now contains multiple html tags.
1479
htmlString = htmlString.substring(0, tagStart) + tag + htmlString.substring(tagEnd + 1); //TE: insert the tag into the htmlString.
1480
}
1481        return htmlString;
1482    }
1483
1484    // XXX This should be rewritten to correctly use the HTML Document object model,
1485
protected String JavaDoc insertFormSelectData(String JavaDoc htmlString, DXEntry entry)
1486    {
1487        int tagStart,tagEnd,pos = 0;
1488        while ((pos = htmlString.indexOf("<select", pos)) >= 0)
1489        {
1490            tagStart = pos;
1491            tagEnd = htmlString.indexOf("</select>", pos);
1492
1493            String JavaDoc tag = htmlString.substring(tagStart, tagEnd);
1494
1495            String JavaDoc name = getTagValue("name", tag);
1496
1497            if (name != null)
1498            {
1499                try
1500                {
1501                    Attribute JavaDoc a = entry.get(name);
1502                    if (a == null) return htmlString; // no pre-existing value, so nothing to do.
1503
if (a.get() == null) return htmlString; // no pre-existing value, so nothing to do.
1504

1505                    String JavaDoc entryValue = ((String JavaDoc) a.get()).toLowerCase();
1506
1507                    String JavaDoc lowerCaseTag = tag.toLowerCase();
1508                    int valPos = lowerCaseTag.indexOf(entryValue);
1509                    int valTag = lowerCaseTag.lastIndexOf("value", valPos); //XXX should this be " value" ??
1510
if (valTag > -1 && valTag > valPos - 9) // make sure we're not picking up the wrong value!
1511
{ //TE: was (valTag > valPos-9) but was throwing a exception each time a page loaded.
1512
tag = tag.substring(0, valTag - 1) + " selected " + tag.substring(valTag);
1513                        htmlString = htmlString.substring(0, tagStart) + tag + htmlString.substring(tagEnd);
1514                    }
1515                }
1516                catch (Exception JavaDoc e)
1517                {
1518                    if (showHTMLErrors)
1519                    {
1520                        e.printStackTrace();
1521                        log.warning("Error getting value for " + name + " value :\n " + e); // not a terminal error.
1522
}
1523                }
1524            }
1525
1526            pos = tagEnd;
1527        }
1528        return htmlString;
1529    }
1530
1531
1532
1533    /**
1534     * Goes through the html template, checking for any text area tags for example:
1535     * <p>
1536     * &#60tr&#62
1537     * &#60th align="right" valign="top" width="200"&#62Address:&#60/th&#62
1538     * &#60td width="230"&#62&#60textarea name="postalAddress" rows="4"&#62&#60/textarea&#62&#60/td&#62
1539     * &#60/tr&#62
1540     * <p>
1541     * If one is found, it checks the name and gets (in this example) the postalAddress value from the entry and inserts
1542     * it into the value part of the tag (for example value="21 Jump Street"). If the attribute is multivalued, the
1543     * input tag (&#60textarea name="postalAddress" rows="4"&#62&#60/textarea&#62) is copied and reused until all of the attribute
1544     * values are inserted. For layout, a &#60/br&#62 is added to the end of multivalued attribute tags. The tag
1545     * is then inserted back into the html template and returned.
1546     * @param htmlString the actual html file that is to be displayed.
1547     * @param entry the current entry that the html file is trying to display.
1548     * @return the updated html file (updated with the values of the text fields that are to be displayed).
1549     */

1550
1551    // XXX This should be rewritten to correctly use the HTML Document object model,
1552
protected String JavaDoc insertFormTextAreaData(String JavaDoc htmlString, DXEntry entry)
1553    {
1554        int tagStart,tagEnd,pos = 0;
1555        while ((pos = htmlString.indexOf("<textarea", pos)) >= 0)
1556        {
1557            tagStart = pos;
1558            tagEnd = htmlString.indexOf(">", pos);
1559            String JavaDoc tag = htmlString.substring(tagStart, tagEnd);
1560
1561            String JavaDoc name = getTagValue("name", tag);
1562
1563            DXAttribute attribute = null;
1564            attribute = (DXAttribute) entry.get(name); //TE: get the attribute values that are being processed.
1565

1566            int size = 0;
1567
1568            if (attribute != null)
1569                size = attribute.size(); //TE: get the number of values the attribute has so we can tell if it is multivalued.
1570

1571            int nextTag = htmlString.indexOf("</textarea>", tagEnd);
1572
1573            if (nextTag > 0)
1574            {
1575                String JavaDoc betweenTagText = htmlString.substring(tagEnd + 1, nextTag);
1576                if (betweenTagText.trim().length() == 0) // i.e. nothing but white space
1577
{
1578                    if (size == 1)
1579                    {
1580                        String JavaDoc text = getAttValue(name, entry);
1581                        if (text != null && attribute != null) //&& name.toLowerCase().indexOf("address")>0 //TE: removed this to allow any attribute to use a text area.
1582
{
1583                            //Only replace '$' in address fields..
1584
if (name.toLowerCase().indexOf("address") > 0)
1585                                text = text.replace('$', '\n');
1586
1587                            htmlString = htmlString.substring(0, tagEnd + 1) + text + htmlString.substring(nextTag);
1588                        }
1589                    }
1590                    else if (size > 1) //TE: multivalued.
1591
{
1592                        String JavaDoc text;
1593                        String JavaDoc textAreaStartTag = htmlString.substring(tagStart, tagEnd + 1); //TE: <textarea name="postalAddress" rows="4">
1594
String JavaDoc textAreaEndTag = htmlString.substring(tagEnd + 1, htmlString.indexOf(">", tagEnd + 1) + 1); //TE: </textarea>
1595

1596                        StringBuffer JavaDoc multiValuedTag = new StringBuffer JavaDoc();
1597                        for (int i = 0; i < size; i++)
1598                        { //TE: make a new tag for each attribute value (only used for multivalued attributes),
1599
// for example: <textarea name="postalAddress" rows="4">21 Jump Street \nJump Haven</textarea><br/>.
1600
// Then append the tag to a string buffer.
1601
text = getAttValue(name, entry, i);
1602                            text = text.replace('$', '\n');
1603                            multiValuedTag.append(new String JavaDoc(textAreaStartTag + text + textAreaEndTag + "<br>")); //TE: <textarea name="postalAddress" rows="4">21 Jump Street</textarea>
1604
}
1605
1606                        String JavaDoc multiTag = multiValuedTag.toString();
1607                        htmlString = htmlString.substring(0, tagStart) + multiTag + htmlString.substring(nextTag);
1608                    }
1609                }
1610            }
1611            pos = tagEnd;
1612        }
1613        return htmlString;
1614    }
1615
1616
1617    /**
1618     * Inserts jpegPhoto values into the html file/template. It searches the html file (which is the parameter:
1619     * "htmlString") for the jpegPhoto tag (or flag): "Image N/A". If there is one or more audio values in the
1620     * entry it removes the whole tag (or flag) "Image N/A", and makes a string buffer containing the new tags of all of
1621     * the jpegPhoto attributes that pertain to the current entry.
1622     * <p>
1623     * For example:
1624     * &#60br/&#62&#60img SRC="..\..\temp\cn=Allison MOODY,o=DEMOCORP,c=AU0.jpg" border="1" /&#62
1625     * &#60br/&#62&#60img SRC="..\..\temp\cn=Allison MOODY,o=DEMOCORP,c=AU1.jpg" border="1" /&#62
1626     * &#60br/&#62&#60img SRC="..\..\temp\cn=Allison MOODY,o=DEMOCORP,c=AU2.jpg" border="1" /&#62
1627     * <p>
1628     * It gets the names of the files from searching the temp directory for names that begin with the DN of the current
1629     * entry and end in '.jpg'. The string buffer is inserted in the place of the removed image tag (the last "&#62" is removed), and then returned.
1630     * <p>
1631     * The html files/templates reside in jxplorer>templates>inetOrgPerson (inetOrgPerson being the only object class that
1632     * contains the jpegPhoto attribute that we provide templates for) whereas the temp directory resides in the jxplorer
1633     * directory. This is why the image tag needs "..\..\temp\".
1634     * @param htmlString the actual html file that is to be displayed & that the jpegPhoto image is to be set.
1635     * @param entry the current entry that the html file is trying to display.
1636     * @return the updated html file (updated with the names and locations of the images that are to be displayed).
1637     */

1638
1639    protected String JavaDoc insertFormImageData(String JavaDoc htmlString, DXEntry entry)
1640    {
1641        int tagStart,tagEnd,pos = 0;
1642
1643        DXAttribute attribute = null;
1644        attribute = (DXAttribute) entry.get("jpegPhoto"); //TE: gets the jpegPhoto attributes of the current entry.
1645

1646        while ((pos = htmlString.indexOf("Image N/A", pos)) >= 0)
1647        {
1648            tagStart = pos;
1649            tagEnd = htmlString.indexOf("<", pos);
1650
1651            String JavaDoc tag = htmlString.substring(tagStart, tagEnd); //TE: tag = e.g. Image N/A.
1652

1653            if ("Image N/A".equalsIgnoreCase(tag) && tag != null && attribute != null)
1654            {
1655                if (attribute.size() != 0)
1656                {
1657                    int tagPos = htmlString.indexOf(tag); //TE: gets the position of the image tag.
1658

1659                    String JavaDoc htmlCopyStart = htmlString.substring(0, tagPos); //TE: makes a substring of the beginning of the htmlString, up to where the image tag starts.
1660
String JavaDoc htmlCopyEnd = htmlString.substring(htmlString.indexOf("<", tagPos)); //TE: makes a substring of the end of the htmlString, from the end of the image tag to the end of the htmlString.
1661

1662                    File fileDir = CBCache.getCacheDirectory(); //TE: get the temp directory.
1663
String JavaDoc[] allFiles = fileDir.list(); //TE: get the files in the temp directory.
1664

1665                    String JavaDoc[] currentFiles = new String JavaDoc[allFiles.length];
1666
1667                    StringBuffer JavaDoc imageTags = new StringBuffer JavaDoc();
1668
1669                    int x = 0; //TE: used as a separate counter by the "currentFiles" array.
1670

1671                    for (int i = 0; i < allFiles.length; i++)
1672                    {
1673                        //TE: checks all of the files in the temp directory. If any begin with the DN of the current
1674
// entry and end with ".jpg", they are added to a new string buffer of image tags.
1675
if (allFiles[i].startsWith(currentDN) && allFiles[i].endsWith(JPEGEXTENSION))
1676                        {
1677                            currentFiles[x] = allFiles[i].toString();
1678
1679                            imageTags.append(new String JavaDoc("<img SRC=\".." + File.separator + ".." + File.separator + "temp" + File.separator + currentFiles[x] + "\" border=\"1\"><br>")); //TE: the new image tag.
1680
x++;
1681                        }
1682                    }
1683                    htmlString = htmlCopyStart + imageTags.toString() + htmlCopyEnd; //TE: the htmlString with the image tags updated.
1684
}
1685            }
1686            pos = tagEnd;
1687        }
1688        return htmlString;
1689    }
1690
1691
1692    /**
1693     * Inserts audio hyperlinks into the html file/template. It searches the html file (which is the parameter:
1694     * "htmlString") for the audio tag (or flag): "Audio N/A". If there is one or more audio values in the
1695     * entry it removes the whole tag (or flag) "Audio N/A", and makes a string buffer containing the new tags of all of
1696     * the audio attributes that pertain to the current entry.
1697     * <p>
1698     * For example:
1699     * &#60a HREF="..\..\temp\cn=Allison MOODY,o=DEMOCORP,c=AU0.wav"&#62Sound File&#60a/&#62&#60br/&#62
1700     * &#60a HREF="..\..\temp\cn=Allison MOODY,o=DEMOCORP,c=AU1.wav"&#62Sound File&#60a/&#62&#60br/&#62
1701     * &#60a HREF="..\..\temp\cn=Allison MOODY,o=DEMOCORP,c=AU2.wav"&#62Sound File&#60a/&#62&#60br/&#62
1702     * <p>
1703     * It gets the names of the files from searching the temp directory for names that begin with the DN of the current
1704     * entry & that don't end in '.jpg'. The string buffer is inserted in the place of the removed audio tag , and then returned.
1705     * <p>
1706     * The html files/templates reside in jxplorer>templates>inetOrgPerson (inetOrgPerson being the only object class that
1707     * contains the audio attribute that we provide templates for) whereas the temp directory resides in the jxplorer
1708     * directory. This is why the image tag needs "..\..\temp\".
1709     * @param htmlString the actual html file that the audio hyperlinks need to be inserted into.
1710     * @param entry the current entry that the html file is trying to display.
1711     * @return the updated html file (updated with the names and locations of the audio files that are to be hyperlinked to).
1712     */

1713
1714    protected String JavaDoc insertFormAudioData(String JavaDoc htmlString, DXEntry entry)
1715    {
1716        int tagStart,tagEnd,pos = 0;
1717
1718        DXAttribute attribute = null;
1719        attribute = (DXAttribute) entry.get("audio"); //TE: gets the audio attributes of the current entry.
1720

1721        while ((pos = htmlString.indexOf("Audio N/A", pos)) >= 0)
1722        {
1723            tagStart = pos;
1724            tagEnd = htmlString.indexOf("<", pos);
1725
1726            String JavaDoc tag = htmlString.substring(tagStart, tagEnd); //TE: tag = e.g. 'Audio N/A'.
1727

1728            if ("Audio N/A".equalsIgnoreCase(tag) && tag != null && attribute != null)
1729            {
1730                if (attribute.size() != 0)
1731                {
1732                    int tagPos = htmlString.indexOf(tag); //TE: gets the position of the audio tag.
1733

1734                    String JavaDoc htmlCopyStart = htmlString.substring(0, tagPos); //TE: makes a substring of the beginning of the htmlString, up to where the audio tag starts.
1735
String JavaDoc htmlCopyEnd = htmlString.substring(htmlString.indexOf("<", tagPos)); //TE: makes a substring of the end of the htmlString, from the end of the audio tag to the end of the htmlString.
1736

1737                    File fileDir = CBCache.getAudioCacheDirectory(); //TE: get the temp directory.
1738
String JavaDoc[] allFiles = fileDir.list(); //TE: get the files in the temp directory.
1739

1740                    String JavaDoc[] currentFiles = new String JavaDoc[allFiles.length];
1741
1742                    StringBuffer JavaDoc audioTags = new StringBuffer JavaDoc();
1743
1744                    int x = 0; //TE: used as a separate counter by the "currentFiles" array.
1745

1746                    for (int i = 0; i < allFiles.length; i++)
1747                    {
1748                        //TE: checks all of the files in the temp directory. If any begin with the DN of the current
1749
// entry and don't end with ".jpg", they are added to a new string buffer of audio tags.
1750
if (allFiles[i].startsWith(currentDN) && !allFiles[i].endsWith(JPEGEXTENSION))
1751                        {
1752                            currentFiles[x] = allFiles[i].toString();
1753
1754                            audioTags.append(new String JavaDoc("<a HREF=\"" + ".." + File.separator + ".." + File.separator + "temp" + File.separator + "audio" + File.separator + currentFiles[x] + "\">Sound File</a><br>")); //TE: the new image tag.
1755
x++;
1756                        }
1757                    }
1758                    htmlString = htmlCopyStart + audioTags.toString() + htmlCopyEnd; //TE: the htmlString with the audio tags updated.
1759
}
1760            }
1761            pos = tagEnd;
1762        }
1763        return htmlString;
1764    }
1765
1766
1767    /**
1768     * Inserts the attribute value into the tag.
1769     * @param tag the html tag that the value needs to be inserted into e.g. &#60input type="text" name="cn" value=""/&#62.
1770     * @param entry the current entry (or the entry that needs to be displayed).
1771     * @param name the name of the attribute (e.g. 'cn').
1772     * @return the tag with the value inserted.
1773     */

1774
1775    protected String JavaDoc insertFormValue(String JavaDoc tag, DXEntry entry, String JavaDoc name)
1776    {
1777        String JavaDoc newTag = insertFormValue(tag, entry, name, 0); //TE: not a multivalued attribute therefore get attribute at position 0.
1778
return newTag;
1779    }
1780
1781
1782    /**
1783     * Inserts the attribute value into the tag.
1784     * @param tag the html tag that the value needs to be inserted into e.g. &#60input type="text" name="cn" value=""/&#62.
1785     * @param entry the current entry (or the entry that needs to be displayed).
1786     * @param name the name of the attribute (e.g. 'cn').
1787     * @param position the position of the value to be inserted (an attribute may be multivalued).
1788     * @return the tag with the value inserted.
1789     */

1790
1791    // XXX This should be rewritten to correctly use the HTML Document object model,
1792
protected String JavaDoc insertFormValue(String JavaDoc tag, DXEntry entry, String JavaDoc name, int position)
1793    {
1794        String JavaDoc val = getTagValue(" value", tag);
1795
1796        if (val == null) return tag; // no value tag - nothing to do.
1797
if (val.trim().length() > 0) return tag; // value preset - don't change it!
1798

1799        // o.k., we have an empty value. Let's fill it in.
1800

1801        int pos = tag.indexOf(" value");
1802        pos = tag.indexOf("\"", pos) + 1;
1803        int end = tag.indexOf("\"", pos);
1804
1805        String JavaDoc entryValue = getAttValue(name, entry, position); //TE: get the attribute's value at the specified position.
1806
if (entryValue != null)
1807            tag = tag.substring(0, pos) + entryValue + tag.substring(end);
1808
1809        return tag;
1810    }
1811
1812
1813    /**
1814     * Get the value of an attribute corresponding to a particular name.
1815     * @param name the name of the attribute(e.g. 'cn').
1816     * @param entry the current entry (or the entry that needs to be displayed).
1817     * @return the attribute value (e.g. 'frank').
1818     */

1819
1820    protected String JavaDoc getAttValue(String JavaDoc name, DXEntry entry)
1821    {
1822        String JavaDoc newTag = getAttValue(name, entry, 0); //TE: not a multivalued attribute therefore get attribute at position 0.
1823
return checkLength(newTag);
1824    }
1825
1826    /**
1827     * Returns ILLEGAL_VALUE if MAX_LEGAL_VALUE_LENGTH is exceeded.
1828     * @param checkString a string which may be excessively long
1829     * @return the checkString, or an error string if it was too long.
1830     */

1831
1832    private String JavaDoc checkLength(String JavaDoc checkString)
1833    {
1834        return (checkString.length() > MAX_LEGAL_VALUE_LENGTH) ? ILLEGAL_VALUE : checkString;
1835    }
1836
1837
1838    /**
1839     * <p>Get the value of an attribute corresponding to a particular name.</p>
1840     *
1841     * <p>For simplicity elsewhere in the code (!) we make sure that for naming
1842     * attributes the first
1843     * value (in position 0) is *always* the naming value.</p>
1844     *
1845     * @param name the actual attribute name (e.g. 'cn').
1846     * @param entry the current entry (or the entry that needs to be displayed).
1847     * @param position the position of the value to be inserted (an attribute may be multivalued).
1848     * @return the attribute value (e.g. 'frank').
1849     */

1850
1851    protected String JavaDoc getAttValue(String JavaDoc name, DXEntry entry, int position)
1852    {
1853        int numberValues; // how many values the attribute has.
1854

1855        if (name == null) return "No name given in HTMLTemplateDisplay.getAttValue()";
1856
1857
1858        try
1859        {
1860            Attribute JavaDoc a = entry.get(name);
1861            if (a == null) return null; // no pre-existing value, so nothing to do.
1862
numberValues = a.size();
1863            if (numberValues == 0 || a.get() == null) return null; // no pre-existing value, so nothing to do.
1864
if (numberValues <= position) return null; // can't do that.
1865

1866            Object JavaDoc attValue = a.get(position); //TE: get the attribute value at the specified position.
1867

1868            // XXX WARNING - HERE BE MAGIC
1869
/*
1870             * We want to ensure that the naming value is always the first displayed.
1871             * So we check if it is a naming attribute, and whether it is multi valued.
1872             * If it is, we swap the naming value with whatever is in position 0.
1873             */

1874
1875            if (numberValues > 1)
1876            {
1877                boolean namingMagic = false; // whether we're playing silly buggers with multi-valued naming values
1878

1879                String JavaDoc namingValue = null;
1880
1881                /*
1882                 * See if we've got a naming value to worry about.
1883                 */

1884
1885                String JavaDoc[] namingTypes = entry.getRDN().getAtts();
1886                if (namingTypes != null)
1887                {
1888                    for (int i = 0; i < namingTypes.length; i++)
1889                        if (namingTypes[i].equalsIgnoreCase(name))
1890                        {
1891                            namingMagic = true;
1892                            namingValue = entry.getRDN().getRawVals()[i];
1893                        }
1894                }
1895
1896                /*
1897                 * If we do, swap 0 for the naming value, and visa versa.
1898                 */

1899
1900                if (namingMagic)
1901                {
1902                    if (position == 0)
1903                    {
1904                        return checkLength(namingValue);
1905                    }
1906                    else if (attValue.equals(namingValue))
1907                    {
1908                        return checkLength((String JavaDoc) a.get(0));
1909                    }
1910                }
1911
1912            }
1913
1914            if (attValue instanceof String JavaDoc)
1915            {
1916                return checkLength((String JavaDoc) attValue);
1917            }
1918            else
1919            {
1920                if (attValue instanceof byte[])
1921                {
1922                    currentBinaryAttributes.add(name);
1923                    //return "[Binary Data]";
1924
return CBBase64.binaryToString((byte[]) attValue);
1925                }
1926            }
1927            return "Unable to get Att Value for " + name + "!";
1928
1929        }
1930        catch (NamingException JavaDoc e)
1931        {
1932            if (showHTMLErrors)
1933                log.warning("Form Value Error getting value for " + name + " value :\n " + e); // not a terminal error.
1934
return "";
1935        }
1936    }
1937
1938
1939    /**
1940     * This takes a attribute type name and the complete attribute list, as
1941     * well as an optional modifier, and returns the formatted html necessary
1942     * to display the attribute in the html text.
1943     *
1944     * @param attType the type of the attribute being formatted
1945     * @param attributes a list of all available attributes
1946     * @param modifier one of list|table|plain, or a null value
1947     * (which is equivalent to list) that sets the html list display
1948     * type
1949     * @return formatted html text displaying the attribute
1950     */

1951
1952    public String JavaDoc formattedAttribute(String JavaDoc attType, Attributes JavaDoc attributes, String JavaDoc modifier)
1953    {
1954        Attribute JavaDoc theAttribute = attributes.get(attType);
1955        //TE: Return null values as a blank string...was 'No Value Found' changed to satisfy bug 2712.
1956
if (theAttribute == null)
1957        {
1958            log.warning("can't find attribute: '" + attType + "'");
1959            return "";
1960        } // TEMP
1961

1962        return formattedAttribute(theAttribute, modifier);
1963    }
1964
1965    /**
1966     * This takes a attribute type name and the complete attribute list, as
1967     * well as an optional modifier, and returns the formatted html necessary
1968     * to display the attribute in the html text.
1969     *
1970     * @param theAttribute the attribute to format into an HTML fragment
1971     * @param modifier one of list|table|plain, or a null value
1972     * (which is equivalent to list) that sets the html list display
1973     * type
1974     * @return formatted html text displaying the attribute
1975     */

1976
1977    public String JavaDoc formattedAttribute(Attribute JavaDoc theAttribute, String JavaDoc modifier)
1978    {
1979//TODO - Adjust for non-string Values...
1980

1981        try
1982        {
1983            if (theAttribute == null) return NOVALUEFOUND;
1984
1985            String JavaDoc syntaxOID = "";
1986            if (theAttribute instanceof DXAttribute)
1987                syntaxOID = ((DXAttribute) theAttribute).getSyntaxOID();
1988
1989            // Return single values as raw strings...
1990
if (theAttribute.size() == 1)
1991            {
1992                Object JavaDoc o = theAttribute.get();
1993                if (o == null)
1994                    return NOVALUEFOUND;
1995                else if (o instanceof String JavaDoc)
1996                {
1997                    if ("1.3.6.1.4.1.1466.115.121.1.12".equals(syntaxOID))
1998                        return "<a HREF=\"dn:" + o.toString() + "\">" + o.toString() + "</a>"; //TE: dn hyperlink for text.html.
1999
else if ("1.3.6.1.4.1.1466.115.121.1.26".equalsIgnoreCase(syntaxOID))
2000                        return "<a HREF=\"mailto:" + o.toString() + "\">" + o.toString() + "</a>"; //TE: email hyperlink for text.html
2001
else if ((((String JavaDoc) o).toLowerCase()).startsWith("http://"))
2002                        return "<a HREF=\"" + o + "\">" + o + "</a>"; //TE: URL hyperlink
2003
else
2004                        return CBParse.toHTML(syntaxParse(o.toString(), syntaxOID));
2005                }
2006// else if (!"1.3.6.1.4.1.1466.115.121.1.4".equals(syntaxOID)) //TE: why did I put this in?
2007
// {
2008
// return CBIntText.get("(Binary Value)");
2009
// }
2010
}
2011            NamingEnumeration JavaDoc values = theAttribute.getAll();
2012            if (values == null) return NOVALUEFOUND;
2013
2014            // it's a list of values; use the list formatting method...
2015

2016            return formattedListAttribute(values, modifier, syntaxOID, theAttribute.getID());
2017        }
2018        catch (NamingException JavaDoc e)
2019        {
2020            return "<i>" + CBIntText.get("Error: exception reading value") + "</i>";
2021        }
2022    }
2023
2024    public String JavaDoc syntaxParse(String JavaDoc s, String JavaDoc syntaxOID)
2025    {
2026        if (!("".equals(syntaxOID)))
2027        {
2028            if ("1.3.6.1.4.1.1466.115.121.1.41".equals(syntaxOID)) // 'Postal Address'
2029
s = s.replace('$', '\n');
2030        }
2031        return s;
2032    }
2033
2034
2035/*
2036   public String formattedAttribute( Object[] attlist, String modifier )
2037    {
2038        // Return null values as 'No Value Found' string
2039        if ((attlist==null ) || (attlist.length == 0)) return "<i>No Value Found</i>";
2040
2041        // Return single values as raw strings...
2042        if (attlist.length == 1) return CBUtility.toHTML(attlist[0].toString());
2043
2044        // it's a list of values; use the list formatting method...
2045        return formattedListAttribute( attlist, modifier);
2046    }
2047*/

2048
2049
2050    /**
2051     * Takes a list of attribute values, and formats them as an
2052     * html list, possibly of a type specified by the modifier.
2053     * @param attlist a list of objects to display.
2054     * @param modifier one of list|table|plain, or a null value
2055     * (which is equivalent to list) that sets the html list display
2056     * type.
2057     * @param syntaxOID eg 1.3.6.1.4.1.1466.155.121.1.41 for postalAddress.
2058     * @param syntaxID eg postalAddress.
2059     * @return the html text necessary to display th elist of values.
2060     */

2061
2062    public String JavaDoc formattedListAttribute(NamingEnumeration JavaDoc attlist, String JavaDoc modifier, String JavaDoc syntaxOID, String JavaDoc syntaxID)
2063    {
2064        String JavaDoc listStart = "";
2065        String JavaDoc listEnd = "";
2066        String JavaDoc itemStart = "";
2067        String JavaDoc itemEnd = "";
2068
2069        if ((modifier == null) || (modifier.equalsIgnoreCase("list")))
2070        {
2071            listStart = "<ul>\n";
2072            listEnd = "</ul>\n";
2073            itemStart = "<li>";
2074            itemEnd = "</li>";
2075        }
2076        else if (modifier.equalsIgnoreCase("table"))
2077        {
2078            listStart = "<table>\n";
2079            listEnd = "</table>\n";
2080            itemStart = "<tr><td valign=top>";
2081            itemEnd = "</td></tr>";
2082        }
2083        else if (modifier.equalsIgnoreCase("plain"))
2084        {
2085            itemEnd = "\n";
2086        }
2087        else
2088        {
2089        }
2090
2091        return formattedListWithModifiers(attlist, listStart, listEnd, itemStart, itemEnd, syntaxOID, syntaxID);
2092    }
2093
2094
2095    /**
2096     * used by formattedListAttribute to format a list, using the
2097     * parameters as formatting text to produce html.
2098     * @param attlist a list of objects to display.
2099     * @param listStart could be the unordered list or table tag.
2100     * @param listEnd could be the unordered list or table (end) tag.
2101     * @param itemStart could be a list item or a row tag.
2102     * @param itemEnd could be a list item tag or a row (end) tag
2103     * @param syntaxOID eg 1.3.6.1.4.1.1466.155.121.1.41 for postalAddress.
2104     * @param syntaxID eg postalAddress.
2105     * @return the formatted list with the modifiers.
2106     */

2107
2108    private String JavaDoc formattedListWithModifiers(NamingEnumeration JavaDoc attlist, String JavaDoc listStart, String JavaDoc listEnd, String JavaDoc itemStart, String JavaDoc itemEnd, String JavaDoc syntaxOID, String JavaDoc syntaxID)
2109    {
2110        if (attlist == null) return NOVALUEFOUND;
2111
2112        if (syntaxOID != null)
2113        {
2114            if (syntaxOID.equalsIgnoreCase("1.3.6.1.4.1.1466.115.121.1.28")) //TE: special handling for jpegPhoto.
2115
return new String JavaDoc(getMediaTags(listStart, listEnd, itemStart, itemEnd, "jpegPhoto")); //TE: returns the all jpegPhoto tags (all included in the same string).
2116
else if (syntaxOID.equalsIgnoreCase("1.3.6.1.4.1.1466.115.121.1.4")) //TE: special handling for audio.
2117
return new String JavaDoc(getMediaTags(listStart, listEnd, itemStart, itemEnd, "audio")); //TE: returns the all audio tags (all included in the same string).
2118
}
2119
2120        if (syntaxID.equalsIgnoreCase("odDocumentDOC")) //TE: special handling for odDocumentDOC.
2121
return new String JavaDoc(getMediaTags(listStart, listEnd, itemStart, itemEnd, "odDocumentDOC")); //TE: returns the all odDocumentDOC tags (all included in the same string).
2122
if (syntaxID.equalsIgnoreCase("odSpreadSheetXLS")) //TE: special handling for odSpreadSheetXLS.
2123
return new String JavaDoc(getMediaTags(listStart, listEnd, itemStart, itemEnd, "odSpreadSheetXLS")); //TE: returns the all odSpreadSheetXLS tags (all included in the same string).
2124
if (syntaxID.equalsIgnoreCase("odMusicMID")) //TE: special handling for odSpreadSheetXLS.
2125
return new String JavaDoc(getMediaTags(listStart, listEnd, itemStart, itemEnd, "odMusicMID")); //TE: returns the all odSpreadSheetXLS tags (all included in the same string).
2126
if (syntaxID.equalsIgnoreCase("odMovieAVI")) //TE: special handling for odSpreadSheetXLS.
2127
return new String JavaDoc(getMediaTags(listStart, listEnd, itemStart, itemEnd, "odMovieAVI")); //TE: returns the all odSpreadSheetXLS tags (all included in the same string).
2128
if (syntaxID.equalsIgnoreCase("odSoundWAV")) //TE: special handling for odSpreadSheetXLS.
2129
return new String JavaDoc(getMediaTags(listStart, listEnd, itemStart, itemEnd, "odSoundWAV")); //TE: returns the all odSpreadSheetXLS tags (all included in the same string).
2130

2131        StringBuffer JavaDoc formattedList = new StringBuffer JavaDoc();
2132        while (attlist.hasMoreElements())
2133        {
2134            Object JavaDoc temp = attlist.nextElement();
2135
2136            String JavaDoc value = "";
2137            if (temp != null) value = (temp instanceof String JavaDoc) ? temp.toString() : "(Binary Value)";
2138
2139            /*
2140             * Active Directory hack - sometimes AD doesn't publish schema, leading us to mis-identify
2141             * large binary values as strings. It seems the second
2142             */

2143             if (value.length()>2 && (value.charAt(0) == 0 || value.charAt(1) == 0)) // real strings never have '0s' in them.
2144
value = "(Binary Data in String)";
2145
2146            if (syntaxOID != null && syntaxOID.equalsIgnoreCase("1.3.6.1.4.1.1466.115.121.1.12")) //TE: DN tag <a HREF="dn:...">dn...</a>.
2147
formattedList.append(itemStart + "<a HREF=\"dn:" + value + "\">" + value + "</a>" + itemEnd);
2148            else if (syntaxOID != null && syntaxOID.equalsIgnoreCase("1.3.6.1.4.1.1466.115.121.1.26"))
2149                formattedList.append(itemStart + "<a HREF=\"mailto:" + value + "\">" + value + "</a>" + itemEnd); //TE: email tag <a HREF="mailto:whoever@whereever.com">whoever@whereever.com</a>.
2150
else if ((value.toLowerCase()).startsWith("http://"))
2151                formattedList.append(itemStart + "<a HREF=\"" + value + "\">" + value + "</a>" + itemEnd); //TE: email tag <a HREF="url">url name</a>.
2152
else
2153                formattedList.append(itemStart + CBParse.toHTML(syntaxParse(value, syntaxOID)) + itemEnd);
2154        }
2155        return new String JavaDoc(listStart + formattedList.toString() + listEnd);
2156    }
2157
2158
2159    /**
2160     * Returns a string representation of all HTML code need to display all of the jpegPhoto or audio
2161     * attributes in the template. Lists all the files in the temp directory. Checks if any
2162     * pertain to the entry that is to be displayed (checks that it starts with the dn of the entry
2163     * and ends with '.jpg', or for audio checks that it doesn't end in ',jpg'). If so, appends
2164     * the html code to a string buffer which is returned as a string.
2165     * @param listStart the start tag for the display type (bullet or table).
2166     * @param listEnd the end tag for the display type.
2167     * @param itemStart the start tag for the display inserts.
2168     * @param itemEnd the end tag for the display inserts.
2169     * @return the whole html code for displaying the jpeg photos within the display.
2170     */

2171
2172    public String JavaDoc getMediaTags(String JavaDoc listStart, String JavaDoc listEnd, String JavaDoc itemStart, String JavaDoc itemEnd, String JavaDoc type)
2173    {
2174        StringBuffer JavaDoc htmlStringBuffer = new StringBuffer JavaDoc();
2175
2176        File fileDir = type.equalsIgnoreCase("audio") ? CBCache.getAudioCacheDirectory() : CBCache.getCacheDirectory(); //TE: get the temp directory.
2177

2178        String JavaDoc[] allFiles = fileDir.list(); //TE: get the files in the temp directory.
2179
String JavaDoc fileName;
2180
2181        for (int i = 0; i < allFiles.length; i++)
2182        {
2183            if (type.equalsIgnoreCase("audio") && allFiles[i].startsWith(currentDN) && !allFiles[i].endsWith(JPEGEXTENSION)) //TE: if the files are temp audio files for the entry, create html for it...
2184
{ //TE: i.e <ul><li><a HREF="..\temp\cn=turtle food,ou=Administration,ou=Corporate,o=DemoCorp,c=AU1.wav">audio</a></li></ul>
2185
fileName = allFiles[i].toString();
2186                htmlStringBuffer.append(new String JavaDoc(listStart + itemStart + "<a HREF=" + "\".." + File.separator + "temp" + File.separator + "audio" + File.separator + fileName + "\" + >audio</a>" + itemEnd + listEnd));
2187            }
2188            else if (type.equalsIgnoreCase("jpegPhoto") && allFiles[i].startsWith(currentDN) && allFiles[i].endsWith(JPEGEXTENSION)) //TE: if the files are temp jpeg files for the entry, create html for it...
2189
{ //TE: i.e <ul><li><img SRC="..\temp\cn=turtle food,ou=Administration,ou=Corporate,o=DemoCorp,c=AU1.jpg" border="1"></li></ul>
2190
fileName = allFiles[i].toString();
2191                htmlStringBuffer.append(new String JavaDoc(listStart + itemStart + "<img SRC=" + "\".." + File.separator + "temp" + File.separator + fileName + "\" " + "border=\"1\">" + itemEnd + listEnd));
2192            }
2193            else if (type.equalsIgnoreCase("odDocumentDOC") && allFiles[i].startsWith(currentDN) && allFiles[i].endsWith(DOCEXTENSION)) //TE: if the files are temp odDocumentDOC files for the entry, create html for it...
2194
{ //TE: i.e <ul><li><a HREF="..\temp\cn=turtle food,ou=Administration,ou=Corporate,o=DemoCorp,c=AU1.doc">audio</a></li></ul>
2195
fileName = allFiles[i].toString();
2196                htmlStringBuffer.append(new String JavaDoc(listStart + itemStart + "<a HREF=" + "\".." + File.separator + "temp" + File.separator + fileName + "\" + >document</a>" + itemEnd + listEnd));
2197            }
2198            else if (type.equalsIgnoreCase("odSpreadSheetXLS") && allFiles[i].startsWith(currentDN) && allFiles[i].endsWith(XLSEXTENSION)) //TE: if the files are temp odSpreadSheetXLS files for the entry, create html for it...
2199
{ //TE: i.e <ul><li><a HREF="..\temp\cn=turtle food,ou=Administration,ou=Corporate,o=DemoCorp,c=AU1.doc">audio</a></li></ul>
2200
fileName = allFiles[i].toString();
2201                htmlStringBuffer.append(new String JavaDoc(listStart + itemStart + "<a HREF=" + "\".." + File.separator + "temp" + File.separator + fileName + "\" + >spreadsheet</a>" + itemEnd + listEnd));
2202            }
2203            else if (type.equalsIgnoreCase("odMusicMID") && allFiles[i].startsWith(currentDN) && allFiles[i].endsWith(MIDEXTENSION)) //TE: if the files are temp odMusicMID files for the entry, create html for it...
2204
{ //TE: i.e <ul><li><a HREF="..\temp\cn=turtle food,ou=Administration,ou=Corporate,o=DemoCorp,c=AU1.mid">audio</a></li></ul>
2205
fileName = allFiles[i].toString();
2206                htmlStringBuffer.append(new String JavaDoc(listStart + itemStart + "<a HREF=" + "\".." + File.separator + "temp" + File.separator + fileName + "\" + >audio</a>" + itemEnd + listEnd));
2207            }
2208            else if (type.equalsIgnoreCase("odSoundWAV") && allFiles[i].startsWith(currentDN) && allFiles[i].endsWith(WAVEXTENSION)) //TE: if the files are temp odSoundWAV files for the entry, create html for it...
2209
{ //TE: i.e <ul><li><a HREF="..\temp\cn=turtle food,ou=Administration,ou=Corporate,o=DemoCorp,c=AU1.wav">audio</a></li></ul>
2210
fileName = allFiles[i].toString();
2211                htmlStringBuffer.append(new String JavaDoc(listStart + itemStart + "<a HREF=" + "\".." + File.separator + "temp" + File.separator + fileName + "\" + >audio</a>" + itemEnd + listEnd));
2212            }
2213            else if (type.equalsIgnoreCase("odMovieAVI") && allFiles[i].startsWith(currentDN) && allFiles[i].endsWith(AVIEXTENSION)) //TE: if the files are temp odMovieAVI files for the entry, create html for it...
2214
{ //TE: i.e <ul><li><a HREF="..\temp\cn=turtle food,ou=Administration,ou=Corporate,o=DemoCorp,c=AU1.avi">movie</a></li></ul>
2215
fileName = allFiles[i].toString();
2216                htmlStringBuffer.append(new String JavaDoc(listStart + itemStart + "<a HREF=" + "\".." + File.separator + "temp" + File.separator + fileName + "\" + >movie</a>" + itemEnd + listEnd));
2217            }
2218        }
2219        return htmlStringBuffer.toString();
2220    }
2221
2222
2223
2224    /*
2225     * returns all non-null attribute values, formatted in a sane manner according to
2226     * the optional modifier paramater
2227     * @param attributes a list of all attributes to display
2228     * @param modifier one of list|table|plain, or a null value
2229     * (which is equivalent to list) that sets the html list display
2230     * type
2231     * @return the html text necessary to display the list of values.
2232     */

2233
2234    public String JavaDoc formattedAllAttributes(DXEntry attributes, String JavaDoc modifier)
2235    {
2236
2237//TODO modify code so that the NamingExceptions that may be handled by the
2238
// NamingEnumeration are sensibly handled and displayed (currently they are
2239
// ignored).
2240

2241        if (modifier == null) modifier = "list"; // list is default option.
2242

2243        NamingEnumeration JavaDoc attributeList;
2244
2245        attributeList = attributes.getAllNonNull();
2246
2247        StringBuffer JavaDoc list = new StringBuffer JavaDoc("");
2248
2249        if (modifier.equalsIgnoreCase("list")) list.append("<table>");
2250
2251        try
2252        {
2253            while (attributeList.hasMore())
2254            {
2255                Attribute JavaDoc theAttribute = (Attribute JavaDoc) attributeList.next();
2256
2257                String JavaDoc syntaxOID = (theAttribute instanceof DXAttribute) ? ((DXAttribute) theAttribute).getSyntaxOID() : "";
2258
2259                if (modifier.equalsIgnoreCase("list")) //TE: Simple.html.
2260
{
2261                    list.append("<tr>" + theAttribute.getID() + "</td><td valign=top>");
2262                    list.append(formattedListAttribute(theAttribute.getAll(), modifier, syntaxOID, theAttribute.getID()) + "</tr>\n");
2263// list.append("</td></tr><tr valign=top colspan=\"2\"><hr></tr>\n");
2264
}
2265                else if (modifier.equalsIgnoreCase("table")) //TE: Table
2266
{
2267                    list.append(formattedListAttribute(theAttribute.getAll(), modifier, syntaxOID, theAttribute.getID()));
2268                }
2269                else //TE: Text.html
2270
{
2271                    list.append(theAttribute.getID() + ":\n" + formattedAttribute(theAttribute, "plain") + "\n\n");
2272                }
2273            }
2274
2275            if (modifier.equalsIgnoreCase("list")) list.append("</table>");
2276        }
2277        catch (NamingException JavaDoc e)
2278        {
2279            log.warning("naming exception in formattedAllAttributes() " + e);
2280        }
2281
2282        return list.toString();
2283    }
2284
2285
2286    /**
2287     * Convenience wrapper for openPage, that prefixes parameter URL
2288     * with the local URL directory path.
2289     *
2290     * @param localURL the URL to convert to a fully defined path
2291     */

2292/*
2293    public boolean openLocalURL(String localURL)
2294    {
2295        if (localURL.startsWith("http:")) // don't mess with existing defined URLs
2296            return openPage(localURL);
2297        else
2298            return openPage(JXplorer.fileURLPrefix + myProperties.getProperty("dir.local") + localURL);
2299    }
2300*/

2301    /**
2302     * Convenience wrapper for openPage, that prefixes parameter URL
2303     * with the document URL directory path.
2304     * D:\abcdefghijklmnopqrstuvwxyz ` ; ' ^ $ # @ % & ( )\a test with lots of spaces\dist\htmldocs
2305     * D:\abcdefghijklmnopqrstuvwxyz ` ; ' ^ $ # @ % & ( )\a test with lots of spaces\dist\htmldocs\start.html
2306     * @param docURL the URL to convert to a fully defined path
2307     */

2308
2309    public boolean openDocumentURL(String JavaDoc docURL)
2310    {
2311        if (docURL.startsWith("http:")) // don't mess with urls that are already properly defined
2312
return openPage(docURL);
2313        else
2314        {
2315            File document = new File(myProperties.getProperty("dir.htmldocs") + docURL);
2316            try
2317            {
2318                return openPage(document.toURL());
2319            }
2320            catch (MalformedURLException e)
2321            {
2322                log.warning("Bad URL '" + document.toString() + "'\n" + e);
2323                return false;
2324            }
2325        }
2326            //return openPage(JXplorer.fileURLPrefix + myProperties.getProperty("dir.htmldocs") + docURL);
2327
}
2328
2329
2330    /**
2331     * Tricky method that launches the users default mail client or Browser. Does this
2332     * by creating a bat file (which is deleted on JX exit) called 'temp.bat'.
2333     * It then writes something like 'start mailto:whoever@whereever.com' or a url to this file
2334     * It then uses the runtime class to run this bat file which should launch the default
2335     * mail client (on windows only).
2336     * @param desc email address for example 'mailto:whoever@wherever.com'.
2337     */

2338
2339    public void launchClient(String JavaDoc desc)
2340    {
2341        try
2342        {
2343            File file = new File("temp.bat"); //TE: make a bat file in the working directory.
2344
file.deleteOnExit(); //TE: deletes the temporary file when JX is shut down.
2345

2346            FileWriter output = new FileWriter(file);
2347            output.write("start " + desc); //TE: write 'start mailto:whoever@whereever.com" to the bat file.
2348
output.close();
2349
2350            Runtime JavaDoc r = Runtime.getRuntime();
2351            r.exec("temp.bat"); //TE: run the bat file.
2352
}
2353        catch (Exception JavaDoc e)
2354        {
2355            CBUtility.error("Error launching default mail client " + e);
2356        }
2357    }
2358
2359
2360    /**
2361     * identical in intent to openPage(URL) (see). This
2362     * version takes a string form of the URL instead.
2363     *
2364     * @param urlString the string form of the url to be opened.
2365     * @return whether the new page loading was successfull.
2366     */

2367    public boolean openPage(String JavaDoc urlString)
2368    {
2369        if (urlString == null) return false;
2370
2371        if (urlString.toLowerCase().startsWith("dn:")) // 'hyperlinked' dn: tags jump browser to appropriate entry when pressed.
2372
{
2373            String JavaDoc dn = urlString.substring(3);
2374            if (dn.startsWith("/")) dn = dn.substring(1);
2375            if (dn.startsWith("/")) dn = dn.substring(1);
2376            DN linkDN = new DN(dn);
2377            if (linkDN.size() > 0)
2378            {
2379                currentDataSource.getEntry(linkDN);
2380            }
2381
2382            return true;
2383        }
2384        else
2385        {
2386
2387            try
2388            {
2389                URL url = new URL(urlString);
2390                return openPage(url);
2391            }
2392            catch (MalformedURLException e)
2393            {
2394                log.warning("Bad URL '" + urlString + "'\n" + e);
2395                return false;
2396            }
2397        }
2398    }
2399
2400    /**
2401     * this opens a page for viewing. It handles all errors internally. If
2402     * it is unable to open a page, it will attempt to restore the current
2403     * page.
2404     *
2405     *
2406     * @param url the location of the page (help file, template etc.) to be opened
2407     * @return whether the new page loading was successfull.
2408     */

2409    public boolean openPage(URL url)
2410    {
2411        if (url == null) return false;
2412        URL original = editor.getPage();
2413
2414
2415        try
2416        {
2417            setEditor(url);
2418
2419            return true;
2420        }
2421        catch (IOException e) // catch normal 'can't find this' exceptions
2422
{
2423            e.printStackTrace();
2424            JOptionPane.showMessageDialog(this, CBIntText.get("Can't follow link ") + url.toString(),
2425                    CBIntText.get("Invalid URL"), JOptionPane.ERROR_MESSAGE);
2426            log.warning("unable to follow url " + url.toString() + "\n" + e);
2427            try
2428            {
2429                if (original != null)
2430                    editor.setPage(original); // XXX this reuses the same editor, and hence might be error-prone.
2431
else
2432                    setToDefault();
2433            } // Return to Original
2434
catch (Exception JavaDoc e3)
2435            {
2436                log.warning("fnord: " + e3);
2437                setToDefault();
2438            }
2439            return false;
2440        }
2441        catch (Exception JavaDoc e2) // some screwy stuff in swing html handling... try to catch that too.
2442
{
2443            log.warning("Wierd Java exception thrown on setPage in AttributeDisplay\n" + e2);
2444            try
2445            {
2446                if (original != null)
2447                    editor.setPage(original); // XXX this reuses the same editor, and hence might be error-prone.
2448
else
2449                    setToDefault();
2450            } // Return to Original
2451
catch (Exception JavaDoc e3)
2452            {
2453                setToDefault();
2454            }
2455            return false;
2456        }
2457    }
2458
2459    /**
2460     * Sets the editor to display the particular (html only, no DNs...) url.
2461     * @param url the url of the local file/web page to display
2462     */

2463
2464    protected void setEditor(URL url) throws IOException
2465    {
2466        if (editor == null) editor = getNewEditor();
2467        editor.setPage(url); // XXX this reuses the same editor, and hence might be error-prone.
2468
validate();
2469    }
2470
2471
2472    public JComponent getDisplayComponent()
2473    {
2474        return this;
2475    }
2476
2477    public String JavaDoc toString()
2478    {
2479        return htmlText.toString();
2480    }
2481
2482    public String JavaDoc getName()
2483    {
2484        return CBIntText.get("HTML View");
2485    }
2486
2487    public ImageIcon getIcon()
2488    {
2489        return new ImageIcon("images" + File.separator + "html.gif");
2490    } //TE: returns an icon.
2491

2492    public String JavaDoc getToolTip()
2493    {
2494        return CBIntText.get("The HTML View is used to view and edit the data in purpose constructed HTML templates.");
2495    } //TE: returns a tool tip.
2496

2497
2498    /**
2499     * Return the thingumy that should be printed.
2500     */

2501    public Component getPrintComponent()
2502    {
2503        return editor;
2504    }
2505
2506
2507    public boolean isUnique()
2508    {
2509        return false;
2510    }
2511
2512
2513    public DataSink getDataSink()
2514    {
2515        return this;
2516    }
2517
2518    public boolean canCreateEntry()
2519    {
2520        return false;
2521    }
2522
2523    public void registerComponents(JMenuBar menu, JToolBar buttons, JTree tree, JPopupMenu treeMenu, JFrame jx)
2524    {
2525        smartTree = (SmartTree) tree;
2526    }
2527
2528    public void unload()
2529    {
2530    }
2531
2532
2533    /**
2534     * Use the default tree icon system based on naming value
2535     * or object class.
2536     */

2537
2538    public ImageIcon getTreeIcon(String JavaDoc rdn)
2539    {
2540        return null;
2541    }
2542
2543    /**
2544     * Use the default popupmenu.
2545     */

2546
2547    public JPopupMenu getPopupMenu(String JavaDoc rdn)
2548    {
2549        return null;
2550    }
2551
2552    /**
2553     * Don't hide sub entries.
2554     */

2555
2556    public boolean hideSubEntries(String JavaDoc rdn)
2557    {
2558        return false;
2559    }
2560
2561
2562}
Popular Tags