Clover coverage report -
Coverage timestamp: Sun Apr 18 2004 21:32:30 EDT
file stats: LOC: 976   Methods: 42
NCLOC: 548   Classes: 3
 
 Source file Conditionals Statements Methods TOTAL
DocumentPane.java 37.5% 57.8% 73.8% 55.9%
coverage coverage
 1   
 /*
 2   
  * SimplyHTML, a word processor based on Java, HTML and CSS
 3   
  * Copyright (C) 2002 Ulrich Hilger
 4   
  *
 5   
  * This program is free software; you can redistribute it and/or
 6   
  * modify it under the terms of the GNU General Public License
 7   
  * as published by the Free Software Foundation; either version 2
 8   
  * of the License, or (at your option) any later version.
 9   
  *
 10   
  * This program is distributed in the hope that it will be useful,
 11   
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12   
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13   
  * GNU General Public License for more details.
 14   
  *
 15   
  * You should have received a copy of the GNU General Public License
 16   
  * along with this program; if not, write to the Free Software
 17   
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 18   
  */
 19   
 
 20   
 import java.awt.*;
 21   
 import java.awt.event.*;
 22   
 import java.io.*;
 23   
 import java.net.*;
 24   
 import javax.swing.*;
 25   
 import javax.swing.event.*;
 26   
 import javax.swing.text.*;
 27   
 import javax.swing.text.html.*;
 28   
 //import com.sun.demo.ExampleFileFilter;
 29   
 import java.util.*;
 30   
 import java.util.prefs.*;
 31   
 import javax.swing.text.rtf.RTFEditorKit;
 32   
 
 33   
 /**
 34   
  * GUI representation of a document.
 35   
  *
 36   
  * <p>Swing already uses three types of classes to implement a model, view,
 37   
  * controller (MVC) approach for a document:</p>
 38   
  *
 39   
  * <p>JTextComponent - the view implementation<br>
 40   
  * Document - the model implementation<br>
 41   
  * EditorKit - the controller implementation</p>
 42   
  *
 43   
  * <p>For a GUI representation of a document, additional parts are needed, such
 44   
  * as a JScrollPane as well as listeners and fields to track the state of
 45   
  * the document while it is represented on a GUI.</p>
 46   
  *
 47   
  * <p><code>DocumentPane</code> wraps all those elements to implement a single
 48   
  * document centric external view to all elements.</p>
 49   
  *
 50   
  * <p>If for instance an application wants to create a new document, it simply
 51   
  * creates an instance of this class instead of having to implement own
 52   
  * methods for instatiating each element (editor pane, scroll pane, etc.)
 53   
  * separately.</p>
 54   
  *
 55   
  * @author Ulrich Hilger
 56   
  * @author Light Development
 57   
  * @author <a href="http://www.lightdev.com">http://www.lightdev.com</a>
 58   
  * @author <a href="mailto:info@lightdev.com">info@lightdev.com</a>
 59   
  * @author published under the terms and conditions of the
 60   
  *      GNU General Public License,
 61   
  *      for details see file gpl.txt in the distribution
 62   
  *      package of this software
 63   
  *
 64   
  * @version stage 11, April 27, 2003
 65   
  */
 66   
 
 67   
 public class DocumentPane extends JPanel implements DocumentListener, ChangeListener {
 68   
 
 69   
   /** the editor displaying the document in layout view */
 70   
   private SHTMLEditorPane editor;
 71   
   private SHTMLEditorPane editor2;
 72   
   public boolean split = false;
 73   
   public boolean speak = false;
 74   
   /** the editor displaying the document in HTML code view */
 75   
   private SyntaxPane htmlEditor;
 76   
 
 77   
   /** temporary storage location for this document */
 78   
   public File docTempDir = null;
 79   
 
 80   
   /** the save thread, if a save operation is in progress */
 81   
   public Thread saveThread = null;
 82   
 
 83   
   /** indicator if a save operation was succesful */
 84   
   public boolean saveSuccessful = false;
 85   
 
 86   
   /** indicates if the document text has changed */
 87   
   private boolean textChanged;
 88   
 
 89   
   /** the name of the document */
 90   
   private String docName;
 91   
 
 92   
   /** the file the current style sheet was loaded from, if any */
 93   
   private File loadedStyleSheet = null;
 94   
 
 95   
   /** the URL the document was loaded from (if applicable)*/
 96   
   private URL sourceUrl = null;
 97   
   
 98   
   /** the format that the file will be saved in */
 99   
   private String saveType = "HTML";
 100   
 
 101   
   /** JTabbedPane for our views */
 102   
   private JTabbedPane tpView;
 103   
 
 104   
   private static final int VIEW_TAB_LAYOUT = 0;
 105   
   private static final int VIEW_TAB_HTML = 1;
 106   
 
 107   
   /**
 108   
    * a save place for sourceUrl, when a document is to be saved
 109   
    * under a new name and this fails
 110   
    */
 111   
   private URL savedUrl = null;
 112   
 
 113   
   /** indicates if this document was loaded froma file */
 114   
   private boolean loadedFromFile = false;
 115   
 
 116   
   /** default document name */
 117   
   private String DEFAULT_DOC_NAME = "Untitled";
 118   
 
 119   
   /** default name for style sheet, when saved */
 120   
   public static String DEFAULT_STYLE_SHEET_NAME = "style.css";
 121   
 
 122   
   /** number for title of a new document */
 123   
   private int newDocNo;
 124   
   public boolean topEditor = true;
 125   
   public boolean bottomEditor = false;
 126   
 
 127   
 
 128   
   //private int renderMode;
 129   
   public JScrollPane jspEditor1;
 130   
   public JScrollPane jspEditor2;
 131   
   public JSplitPane _splitPane;
 132   
 
 133   
 
 134   
 
 135   
 
 136   
 
 137  79
   public void init_split() {
 138  79
       SHTMLEditorKit kit = new SHTMLEditorKit(/*renderMode*/);
 139   
       //kit.resetStyleSheet();
 140  79
       editor2.setEditorKit(kit);
 141  79
       jspEditor1 = new JScrollPane(editor);
 142  79
       jspEditor2 = new JScrollPane(editor2);
 143   
 //      jspEditor1.setPreferredSize(new Dimension(800,800));
 144   
 //      jspEditor2.setPreferredSize(new Dimension(800,800));
 145  79
         jspEditor1.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);    
 146  79
         jspEditor2.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
 147  79
       _splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, jspEditor1, jspEditor2);
 148  79
       editor.addFocusListener(new FocusAdapter() {
 149  7
           public void focusGained(FocusEvent e) {
 150  7
               FrmMain.topEditor = true;
 151  7
               FrmMain.bottomEditor = false;
 152  7
               Debug.print("editor1 has foucs");
 153   
           }    
 154   
       });
 155   
 
 156  79
       editor2.addFocusListener(new FocusAdapter() {
 157  0
           public void focusGained(FocusEvent e) {
 158  0
               FrmMain.bottomEditor = true;
 159  0
               FrmMain.topEditor = false;
 160  0
               Debug.print("editor2 has focus");
 161   
           }    
 162   
       });
 163   
 
 164   
     
 165   
      // editor2.setDocument(editor.getDocument());
 166  79
       Debug.print("in init_split of docuemnt pane");
 167  79
       _splitPane.remove(_splitPane.getBottomComponent());
 168  79
       tpView.add(_splitPane, VIEW_TAB_LAYOUT); 
 169  79
     tpView.setTitleAt(VIEW_TAB_LAYOUT, FrmMain.dynRes.getResourceString(FrmMain.resources, "layoutTabTitle"));
 170   
       //editor.setDocument(editor2.getDocument());
 171   
 //    jtpDocs.add("testi", _splitPane);
 172   
       //this.getContentPane().add(_splitPane);
 173   
   }
 174   
   
 175   
   /**
 176   
    * construct a new <code>DocumentPane</code>.
 177   
    *
 178   
    * <p>A document still has to be either created or loaded after using
 179   
    * this constructor, so it is better to use the constructor doing this
 180   
    * right away instead.</p>
 181   
    */
 182   
   
 183  79
   public DocumentPane(String filetype) {
 184  79
     super();
 185   
     
 186  79
     saveType = filetype;
 187   
     
 188   
     // EditorPane and ScrollPane for layout view
 189  79
     editor = new SHTMLEditorPane(this);
 190  79
     SHTMLEditorKit kit = new SHTMLEditorKit(/*renderMode*/);
 191  79
     editor2 = new SHTMLEditorPane(this);
 192   
 
 193   
 //    //kit.resetStyleSheet();
 194  79
     editor.setEditorKit(kit);
 195  79
     JScrollPane sp = new JScrollPane();   // create a new JScrollPane,
 196  79
     sp.getViewport().setView(editor);     // ..add the editor pane to it
 197  79
     sp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
 198   
     // EditorPane and ScrollPane for html view
 199  79
     htmlEditor = new SyntaxPane();
 200  79
     htmlEditor.setFont(new Font("Monospaced", Font.PLAIN, 12));
 201   
     //htmlEditor.addKeyListener(rkw);
 202  79
     JScrollPane htmlSp = new JScrollPane();
 203  79
     htmlSp.getViewport().setView(htmlEditor);
 204   
 
 205   
     // tabbed pane for HTML and layout views
 206  79
     tpView = new JTabbedPane();
 207  79
     tpView.setTabPlacement(JTabbedPane.BOTTOM);
 208   
 //    tpView.add(_splitPane, VIEW_TAB_LAYOUT);
 209  79
     init_split();
 210  79
 System.out.println("Teh savetype is "+saveType);
 211  79
     if (saveType.equals("HTML"))
 212   
     {
 213  79
     tpView.add(htmlSp, VIEW_TAB_HTML);
 214  79
      tpView.setTitleAt(VIEW_TAB_HTML, FrmMain.dynRes.getResourceString(FrmMain.resources, "htmlTabTitle"));
 215  79
      tpView.addChangeListener(this);
 216   
     }
 217   
 
 218   
     // add comnponents to content pane
 219  79
     setLayout(new BorderLayout());        // a simple border layout is enough
 220  79
     add(tpView, BorderLayout.CENTER);         // ..and add both to this DocumentPane
 221  79
     textChanged = false;                  // no changes so far
 222  79
     setPreferredSize(new Dimension(550, 550));
 223   
   }
 224   
 
 225   
   /**
 226   
    * construct a new DocumentPane with either a new Document or an exisiting
 227   
    * Document that is to be loaded into the DocumentPane upon construction.
 228   
    *
 229   
    * @param docToLoad the document to be loaded. If this is null, a new
 230   
    *      Document is created upon construction of the DocumentPane
 231   
    * @param newDocNo  the number a new document shall have in the
 232   
    * title as long as it is not saved (such as in 'Untitled1'). If an
 233   
    * existing document shall be loaded, this number is ignored
 234   
    */
 235  78
   public DocumentPane(URL docToLoad, int newDocNo, String filetype/*, int renderMode*/) {
 236  78
     this(filetype);
 237  78
     DEFAULT_DOC_NAME = FrmMain.dynRes.getResourceString(
 238   
         FrmMain.resources, "defaultDocName");
 239  78
     if(docToLoad != null) {
 240  2
       loadDocument(docToLoad, filetype);
 241   
     }
 242   
     else {
 243  76
       this.newDocNo = newDocNo;
 244   
     
 245  76
       createNewDocument();
 246   
     }
 247   
   }
 248   
 
 249   
   /**
 250   
    * get the <code>JEditorPane</code> of this <code>DocumentPane</code>
 251   
    *
 252   
    * @return the JEditorPane of this DocumentPane
 253   
    */
 254  287
   public SHTMLEditorPane getEditor() {
 255  287
     return editor;
 256   
   }
 257   
 
 258  83
   public SHTMLEditorPane getEditor2() {
 259  83
     return editor2;
 260   
   }
 261   
 
 262   
 
 263   
   /**
 264   
    * create a new HTMLDocument and attach it to the editor
 265   
    */
 266  77
   public void createNewDocument() {
 267  77
     try {
 268  77
       SHTMLEditorKit kit = (SHTMLEditorKit) editor.getEditorKit();
 269  77
       SHTMLDocument doc = (SHTMLDocument) kit.createDefaultDocument();
 270   
       //insertStyleRef(doc); // create style sheet reference in HTML header tag
 271   
       //styles = kit.getStyleSheet();
 272  77
       doc.addDocumentListener(this); // listen to changes
 273  77
       doc.setBase(createTempDir());
 274  77
       editor.setDocument(doc); // let the document be edited in our editor
 275  77
       editor2.setDocument(editor.getDocument());
 276   
       //doc.putProperty(Document.TitleProperty, getDocumentName());
 277  77
       Preferences prefs = Preferences.userNodeForPackage(getClass().forName("PrefsDialog"));
 278  77
       boolean useStyle = prefs.getBoolean(PrefsDialog.PREFS_USE_STD_STYLE_SHEET, false);
 279  77
       if(useStyle) {
 280  0
         doc.insertStyleRef();
 281   
       }
 282   
     }
 283   
     catch(Exception e) {
 284  0
       Util.errMsg(this, e.getMessage(), e);
 285   
     }
 286   
   }
 287   
 
 288  2
   public void setDocument(Document docToSet) {
 289  2
     try {
 290  2
       SHTMLEditorKit kit = (SHTMLEditorKit) editor.getEditorKit();
 291  2
       HTMLDocument doc = (HTMLDocument) getDocument();
 292  2
       if(doc != null) {
 293  2
         doc.removeDocumentListener(this);
 294   
       }
 295  2
       docToSet.addDocumentListener(this); // listen to changes
 296  2
       editor.setDocument(docToSet); // let the document be edited in our editor
 297   
     }
 298   
     catch(Exception e) {
 299  0
       Util.errMsg(this, e.getMessage(), e);
 300   
     }
 301   
   }
 302   
 
 303   
   /**
 304   
    * create temporary directory for a newly created document
 305   
    * so that images can be stored and referenced until the document
 306   
    * is saved.
 307   
    *
 308   
    * @return URL of created temporary document directoy
 309   
    */
 310  77
   private URL createTempDir() throws MalformedURLException {
 311  77
     docTempDir = new File(FrmMain.getAppTempDir().getAbsolutePath() +
 312   
                                File.separator +
 313   
                                getDocumentName() + File.separator);
 314  77
     if(!docTempDir.exists()) {
 315  10
       docTempDir.mkdirs();
 316   
     }
 317  77
     return docTempDir.toURL();
 318   
   }
 319   
 
 320   
   /**
 321   
    * remove the temporary storage created for this <code>DocumentPane</code>
 322   
    */
 323  10
   public void deleteTempDir() {
 324  10
     if(docTempDir != null) {
 325  10
       Util.deleteDir(docTempDir);
 326  10
       docTempDir = null;
 327   
     }
 328   
   }
 329   
 
 330   
   /**
 331   
    * load a document found at a certain URL.
 332   
    *
 333   
    * @param url the URL to look for the document
 334   
    */
 335  2
   public void loadDocument(URL url, String filetype) {
 336  2
       saveType = filetype;
 337  2
       System.out.println("Setting savetype to "+ saveType);
 338  2
     try {
 339  2
     if (filetype.equals("TXT")||(filetype.equals("XML")))
 340   
     {
 341  0
         System.out.println("Opening text file!!");
 342  0
         DefaultEditorKit kit2 = new DefaultEditorKit();
 343   
         //kit.read(inputFile, currentDocument, 0 );
 344  0
         SHTMLDocument doc = new SHTMLDocument();
 345  0
         doc.putProperty("IgnoreCharsetDirective", new Boolean(true));
 346  0
         doc.setBase(new File(url.getPath()).getParentFile().toURL()); // set the doc base
 347  0
         InputStream in = url.openStream(); // get an input stream
 348  0
         kit2.read(in, doc, 0); // ..and read the document contents from it
 349  0
         in.close(); // .. then properly close the stream
 350  0
              doc.addDocumentListener(this); // listen to changes
 351  0
              editor.setDocument(doc); // let the document be edited in our editor
 352   
     }
 353   
     else
 354   
     {
 355   
     
 356  2
       SHTMLEditorKit kit = (SHTMLEditorKit) editor.getEditorKit();
 357   
     
 358  2
       SHTMLDocument doc = (SHTMLDocument) kit.createDefaultDocument();
 359  2
       doc.putProperty("IgnoreCharsetDirective", new Boolean(true));
 360  2
       doc.setBase(new File(url.getPath()).getParentFile().toURL()); // set the doc base
 361  2
       InputStream in = url.openStream(); // get an input stream
 362  2
       kit.read(in, doc, 0); // ..and read the document contents from it
 363   
     
 364  2
       in.close(); // .. then properly close the stream
 365  2
       doc.addDocumentListener(this); // listen to changes
 366  2
       editor.setDocument(doc); // let the document be edited in our editor
 367   
     }
 368  2
       editor2.setDocument(editor.getDocument());
 369  2
       setSource(url); // remember where the document came from
 370  2
       setType(filetype);
 371  2
       loadedFromFile = true;
 372   
     }
 373   
     catch (Exception ex) {
 374  0
       Util.errMsg(this, "An exception occurred while loading the file", ex);
 375  0
       ex.printStackTrace();
 376   
     }
 377   
   }
 378   
 
 379   
   /**
 380   
    * load the rules from a given style sheet file into a new <code>StyleSheet</code> object.
 381   
    *
 382   
    * @param  cssFile  the file object referring to the style sheet to load from
 383   
    *
 384   
    * @return the style sheet with rules loaded
 385   
    */
 386  0
   private StyleSheet loadStyleSheet(File cssFile)
 387   
         throws MalformedURLException, IOException
 388   
   {
 389  0
     StyleSheet s = new StyleSheet();
 390  0
     s.importStyleSheet(cssFile.toURL());
 391  0
     return s;
 392   
   }
 393   
 
 394   
   /**
 395   
    * saves the document to the file specified in the source of the
 396   
    * <code>DocumentPane</code> and creates the associated style sheet.
 397   
    *
 398   
    * The actual save process only is done, when there is a name to save
 399   
    * to. The class(es) calling this method have to make sure that a
 400   
    * name for new documents is requested from the user, for instance.
 401   
    *
 402   
    * The desired name and location for the save need then to be set using method
 403   
    * setSource prior to a call to this method
 404   
    *
 405   
    * @throws DocNameMissingException to ensure the caller gets notified
 406   
    *        that a save did not take place because of a missing name
 407   
    *        and location
 408   
    */
 409  5
   public void saveDocument() throws DocNameMissingException {
 410  5
     if(!saveInProgress()) {
 411  4
       saveThread = Thread.currentThread(); // store thread for saveInProgress
 412  4
       saveSuccessful = false; // if something goes wrong, this remains false
 413  4
       File file = null;
 414  4
       File textfile = null;
 415  4
       try {
 416  4
         if(sourceUrl != null) {
 417   
           /* write the HTML document */
 418  4
           if(tpView.getSelectedIndex() == VIEW_TAB_HTML) {
 419  0
             editor.setText(htmlEditor.getText());
 420   
           }
 421   
         //  System.out.println("THE TEXT FOR TEH SHTMLEDITOR IS "+(editor.getText()));
 422  4
           SHTMLDocument doc = (SHTMLDocument) getDocument();
 423  4
           OutputStream os = new FileOutputStream(sourceUrl.getPath());
 424   
           
 425   
           
 426  4
           OutputStreamWriter osw = new OutputStreamWriter(os);
 427   
           //OutputStreamWriter osw2 = new OutputStreamWriter(os);
 428  4
           Preferences prefs = Preferences.userNodeForPackage(getClass().forName("PrefsDialog"));
 429  4
           String writeMode = prefs.get(PrefsDialog.PREFSID_WRITE_MODE, PrefsDialog.PREFS_WRITE_MODE_HTML32);
 430  4
           if (saveType.equals("HTML"))
 431   
           {
 432  4
             if(writeMode.equalsIgnoreCase(PrefsDialog.PREFS_WRITE_MODE_HTML4)) {
 433  0
                    SHTMLWriter hw = new SHTMLWriter(osw, doc, SHTMLWriter.MODE_HTML);
 434  0
                    hw.write();
 435   
                  }
 436   
                  else {
 437  4
                    FixedHTMLWriter hw = new FixedHTMLWriter(osw, doc);
 438  4
                    hw.write();
 439   
                  }
 440   
           }
 441  0
           else if ((saveType.equals("TXT")) || (saveType.equals("XML")))
 442   
           {
 443  0
                    try {
 444   
                     //OutputStream os2 = new FileOutputStream(sourceUrl.getPath()+".txt");
 445  0
                     OutputStream os2 = new FileOutputStream(sourceUrl.getPath());  
 446  0
                        DefaultEditorKit kit = new DefaultEditorKit();
 447  0
                        kit.write(os2, doc, 0, doc.getLength());
 448  0
                        os2.close();
 449   
                    } catch (Exception e) {
 450   
                    }
 451   
           }
 452  0
          else if (saveType.equals("RTF"))
 453   
          {
 454  0
                  try {
 455   
             //    OutputStream os3 = new FileOutputStream(sourceUrl.getPath()+".rtf"); 
 456  0
             OutputStream os3 = new FileOutputStream(sourceUrl.getPath()); 
 457  0
                 RTFEditorKit kit = new RTFEditorKit();
 458  0
                 kit.write(os3, doc, 0, doc.getLength());
 459  0
                 os3.close();
 460   
             }
 461   
             catch( Exception e){}
 462   
 
 463   
           }
 464   
           
 465  4
           osw.flush();
 466  4
           osw.close();
 467  4
           os.flush();
 468  4
           os.close();
 469   
 
 470   
           /* write the style sheet */
 471  4
           if(doc.hasStyleRef()) {
 472  0
             saveStyleSheet();
 473   
           }
 474   
 
 475   
           /*
 476   
             copy image directory,
 477   
             if new document or saved from different location
 478   
           */
 479  4
           saveImages();
 480   
 
 481   
           /* clean up */
 482   
           //System.out.println("DocumentPane textChanged = false");
 483  3
           textChanged = false; // indicate no changes pending anymore after the save
 484  3
           file = new File(sourceUrl.getPath()).getParentFile();
 485  3
           ((HTMLDocument) getDocument()).setBase(file.toURL()); // set the doc base
 486  3
           deleteTempDir();
 487   
           //System.out.println("DocumentPane saveSuccessful = true");
 488  3
           saveSuccessful = true; // signal that saving was successful
 489   
         }
 490   
         else {
 491  0
           saveThread = null;
 492  0
           throw new DocNameMissingException();
 493   
         }
 494   
       }
 495   
       catch(MalformedURLException mue) {
 496  0
         if(file != null) {
 497  0
           Util.errMsg(this, "Can not create a valid URL for\n" + file.getAbsolutePath(), mue);
 498   
         }
 499   
         else {
 500  0
           Util.errMsg(this, mue.getMessage(), mue);
 501   
         }
 502   
       }
 503   
       catch(Exception e) {
 504  0
         if(savedUrl != null) {
 505  0
           sourceUrl = savedUrl;
 506   
         }
 507  0
         Util.errMsg(this, "An exception occurred while saving the file", e);
 508   
       }
 509  3
       saveThread = null;
 510  3
       savedUrl = sourceUrl;
 511   
     }
 512   
   }
 513   
 
 514   
   /**
 515   
    * determine the directory this <code>DocumentPane</code> references image
 516   
    * files from
 517   
    *
 518   
    * @return the directory image files referenced by this
 519   
    * <code>DocumentPane</code> are found
 520   
    */
 521  7
   public File getImageDir() {
 522  7
     File srcDir = null;
 523  7
     if(savedUrl == null && newDocNo > 0) {
 524   
       // new Document: use temp dir as source
 525  6
       srcDir = new File(
 526   
           docTempDir +
 527   
           File.separator +
 528   
           FrmMain.IMAGE_DIR +
 529   
           File.separator);
 530   
     }
 531   
     else {
 532  1
       if(savedUrl == null) {
 533   
         // document has been saved before: source is 'sourceUrl'
 534  0
         srcDir = new File(
 535   
             new File(sourceUrl.getPath()).getParent() +
 536   
             File.separator +
 537   
             FrmMain.IMAGE_DIR +
 538   
             File.separator);
 539   
       }
 540   
       else {
 541   
         /*
 542   
            document has been saved before but now is
 543   
            to be saved under new name: source is 'old' url
 544   
         */
 545  1
         srcDir = new File(
 546   
             new File(savedUrl.getPath()).getParent() +
 547   
             File.separator +
 548   
             FrmMain.IMAGE_DIR +
 549   
             File.separator);
 550   
       }
 551   
     }
 552  7
     return srcDir;
 553   
   }
 554   
 
 555   
   /**
 556   
    * save image files
 557   
    */
 558  4
   private void saveImages() {
 559  4
     File srcDir = getImageDir();
 560  4
     File destDir = new File(
 561   
         new File(sourceUrl.getPath()).getParent() +
 562   
         File.separator +
 563   
         FrmMain.IMAGE_DIR +
 564   
         File.separator);
 565  4
     try {
 566  4
       if(srcDir.exists()) {
 567  1
         ExampleFileFilter filter = new ExampleFileFilter();
 568  1
         filter.addExtension("gif");
 569  1
         filter.addExtension("jpg");
 570  1
         filter.addExtension("jpeg");
 571  1
         File[] imgFiles = srcDir.listFiles();
 572  3
         for(int i = 0; i < imgFiles.length; i++) {
 573  3
           Util.copyFile(imgFiles[i], new File(destDir.getAbsolutePath() +
 574   
           File.separator + imgFiles[i].getName()));
 575   
         }
 576   
       }
 577   
     }
 578   
     catch(Exception e) {
 579  0
       Util.errMsg(this, e.getMessage(), e);
 580   
     }
 581   
   }
 582   
 
 583   
   /**
 584   
    * indicates whether or not a save process is in progress
 585   
    *
 586   
    * @return true, if a save process is going on, else false
 587   
    */
 588  316
   public boolean saveInProgress() {
 589   
     //System.out.println("DocumentPane.saveInProgress=" + (saveThread != null) + " for document " + getDocumentName());
 590  316
     return saveThread != null;
 591   
   }
 592   
 
 593   
   /**
 594   
    * save the style sheet of this document to a CSS file.
 595   
    *
 596   
    * <p>With stage 8 this saves a style sheet by merging with an existing
 597   
    * one with the same name/location. Styles in this style sheet overwrite
 598   
    * styles in the existing style sheet.</p>
 599   
    */
 600  1
   public void saveStyleSheet() throws IOException {
 601  1
     SHTMLDocument doc = (SHTMLDocument) getDocument();
 602  1
     StyleSheet styles = doc.getStyleSheet();
 603  1
     String styleSheetName = getStyleSheetName();
 604  0
     if(styleSheetName != null) {
 605  0
       File styleSheetFile = new File(new URL(styleSheetName).getFile());
 606  0
       if(!styleSheetFile.exists()) {
 607   
         // no styles present at save location, create new style sheet
 608  0
         styleSheetFile.createNewFile();
 609   
       }
 610   
       else {
 611  0
         if(loadedFromFile) {
 612  0
           if((savedUrl == null) || (!savedUrl.getPath().equals(sourceUrl.getPath())))
 613   
           {
 614   
           /*
 615   
               this style sheet was loaded from somewhere else and now is
 616   
               being saved at a new location where a style sheet exists
 617   
               havig the same name --> merge
 618   
           */
 619  0
             mergeStyleSheets(loadStyleSheet(styleSheetFile), styles);
 620   
           }
 621   
           else {
 622   
           /*
 623   
               same location where styles originally came
 624   
               from, overwrite existing styles with new version
 625   
           */
 626  0
             styleSheetFile.delete();
 627  0
             styleSheetFile.createNewFile();
 628   
           }
 629   
         }
 630   
         else {
 631   
           /*
 632   
               this style sheet was newly created and now is
 633   
               being saved at a location where a style sheet exists
 634   
               havig the same name --> merge
 635   
           */
 636  0
           mergeStyleSheets(loadStyleSheet(styleSheetFile), styles);
 637   
         }
 638   
       }
 639  0
       OutputStream os = new FileOutputStream(styleSheetFile);
 640  0
       OutputStreamWriter osw = new OutputStreamWriter(os);
 641  0
       CSSWriter cssWriter;
 642  0
       cssWriter = new CSSWriter(osw, styles);
 643  0
       cssWriter.write();
 644  0
       osw.close();
 645  0
       os.close();
 646   
     }
 647   
   }
 648   
 
 649   
   /**
 650   
    * merge two style sheets by adding all rules found
 651   
    * in a given source StyleSheet that are not contained
 652   
    * in a given destination StyleSheet. Assumes rules
 653   
    * of src and dest are already loaded.
 654   
    *
 655   
    * @param src  the source StyleSheet
 656   
    * @param dest  the destination StyleSheet
 657   
    */
 658  0
   private void mergeStyleSheets(StyleSheet src, StyleSheet dest) throws IOException {
 659  0
     String name;
 660  0
     Object elem;
 661  0
     Vector srcNames = Util.getStyleNames(src);
 662  0
     Vector destNames = Util.getStyleNames(dest);
 663  0
     StringWriter sw = new StringWriter();
 664  0
     StringBuffer buf = sw.getBuffer();
 665  0
     CSSWriter cw = new CSSWriter(sw, null);
 666  0
     for(int i = 0; i < srcNames.size(); i++) {
 667  0
       elem = srcNames.get(i);
 668  0
       name = elem.toString();
 669  0
       if(destNames.indexOf(elem) < 0) {
 670  0
         buf.delete(0, buf.length());
 671  0
         cw.writeRule(name, src.getStyle(name));
 672  0
         dest.removeStyle(name);
 673  0
         dest.addRule(buf.toString());
 674   
       }
 675   
     }
 676   
   }
 677   
 
 678   
   /**
 679   
    * get the URL of the style sheet of this document
 680   
    *
 681   
    * <p>The name is built by<ol>
 682   
    * <li>get the style sheet reference, if none, use default style
 683   
    * sheet name</li>
 684   
    * <li>get the document base</li>
 685   
    * <li>if the style sheet reference is a relative path, resolve base
 686   
    * and relative path</li>
 687   
    * <li>else simply concatenate doc base and style sheet reference</li>
 688   
    * </ol></p>
 689   
    *
 690   
    * @return the URL of the style sheet
 691   
    */
 692  1
   private String getStyleSheetName() throws MalformedURLException {
 693  1
     String name = DEFAULT_STYLE_SHEET_NAME; //SHTMLEditorKit.DEFAULT_CSS;
 694  1
     SHTMLDocument doc = (SHTMLDocument) getDocument();
 695  1
     String styleRef = doc.getStyleRef();
 696  1
     File file = new File(sourceUrl.getPath()).getParentFile();
 697  0
     String newDocBase = null;
 698  0
     try {
 699  0
       newDocBase = file.toURL().toString();
 700   
     }
 701   
     catch(Exception e) {
 702  0
       if(file != null) {
 703  0
         Util.errMsg(this, "Can not create a valid URL for\n" + file.getAbsolutePath(), e);
 704   
       }
 705   
       else {
 706  0
         Util.errMsg(this, e.getMessage(), e);
 707   
       }
 708   
     }
 709  0
     if(styleRef != null) {
 710  0
       name = Util.resolveRelativePath(styleRef, newDocBase);
 711   
     }
 712   
     else {
 713  0
       name = null; // Util.resolveRelativePath(name, newDocBase);
 714   
     }
 715   
     //System.out.println("DocumentPane.getStyleSheetName=" + name);
 716  0
     return name;
 717   
   }
 718   
 
 719   
   /**
 720   
    * get the name of the document of this pane.
 721   
    *
 722   
    * @return  the name of the document
 723   
    */
 724  205
   public String getDocumentName() {
 725  205
     String theName;
 726  205
     if(docName==null || docName.length() < 1) {
 727  200
       theName = DEFAULT_DOC_NAME + " " + Integer.toString(newDocNo);
 728   
     }
 729   
     else {
 730  5
       theName = docName;
 731   
     }
 732  205
     return theName;
 733   
   }
 734   
 
 735   
   /**
 736   
    * indicates whether or not the document needs to be saved.
 737   
    *
 738   
    * @return  true, if changes need to be saved
 739   
    */
 740  161
   public boolean needsSaving() {
 741   
     //System.out.println("DocumentPane.needsSaving=" + textChanged + " for document " + getDocumentName());
 742  161
     return textChanged;
 743   
   }
 744   
 
 745   
   /**
 746   
    * set the source this document is to be loaded from
 747   
    *
 748   
    * <p>This is only to be used when it is made sure,
 749   
    * that the document is saved at the location specified
 750   
    * by 'source'.</p>
 751   
    *
 752   
    * @param the URL of the source this document is to be loaded from
 753   
    */
 754  5
   public void setSource(URL source) {
 755  5
     savedUrl = sourceUrl;
 756  5
     sourceUrl = source;
 757  5
     String fName = source.getFile();
 758  5
     docName = fName.substring(fName.lastIndexOf("/") + 1);
 759  5
     fireNameChanged();
 760   
   }
 761   
   /** Sets the save type */
 762  6
   public void setType(String type)
 763   
   {
 764  6
       saveType=type;
 765   
   }
 766   
   /** Gets the save type */
 767  22
   public String getType()
 768   
   {
 769  22
       return saveType;
 770   
   }
 771   
 
 772   
   /**
 773   
    * get the source, this document was having before its current sourceUrl
 774   
    * was set.
 775   
    *
 776   
    * @return the source URL before a name change
 777   
    */
 778  0
   public URL getOldSource() {
 779  0
     if(savedUrl == null) {
 780  0
       return sourceUrl;
 781   
     }
 782   
     else {
 783  0
       return savedUrl;
 784   
     }
 785   
   }
 786   
 
 787   
   /**
 788   
    * get the source this document can be loaded from
 789   
    *
 790   
    * @return the URL this document can be loaded from
 791   
    */
 792  9
   public URL getSource() {
 793  9
     return sourceUrl;
 794   
   }
 795   
 
 796   
   /**
 797   
    * indicates whether or not this document was newly created and not saved so
 798   
    * far.
 799   
    *
 800   
    * @return true, if this is a new document that has not been saved so far
 801   
    */
 802  5
   public boolean isNewDoc() {
 803  5
     return sourceUrl == null;
 804   
   }
 805   
 
 806   
   /**
 807   
    * get the document of this <code>DocumentPane</code>
 808   
    *
 809   
    * @return the <code>Document</code> of this <code>DocumentPane</code>
 810   
    */
 811  170
   public Document getDocument() {
 812  170
     return editor.getDocument();
 813   
   }
 814   
 
 815  0
   private Document getHTMLDocument() {
 816  0
     return htmlEditor.getDocument();
 817   
   }
 818   
 
 819   
   /**
 820   
    * switch the DocumentPane to HTML view
 821   
    */
 822  0
   private void setHTMLView() {
 823  0
     try {
 824  0
       editor.getDocument().removeDocumentListener(this);
 825  0
       StringWriter sw = new StringWriter();
 826  0
       SHTMLDocument lDoc = (SHTMLDocument) editor.getDocument();
 827  0
       SHTMLEditorKit kit = (SHTMLEditorKit) editor.getEditorKit();
 828  0
       kit.write(sw, lDoc, 0, lDoc.getLength());
 829  0
       sw.close();
 830  0
       htmlEditor.setText(sw.toString());
 831  0
       htmlEditor.getDocument().addDocumentListener(this);
 832  0
       htmlEditor.addCaretListener(htmlEditor);
 833   
     }
 834   
     catch(Exception ex) {
 835  0
       ex.printStackTrace();
 836   
     }
 837   
   }
 838   
 
 839   
   /**
 840   
    * switch the DocumentPane to layout view
 841   
    */
 842  0
   private void setLayoutView() {
 843  0
     htmlEditor.getDocument().removeDocumentListener(this);
 844  0
     htmlEditor.removeCaretListener(htmlEditor);
 845  0
     editor.setText(htmlEditor.getText());
 846  0
     editor.setCaretPosition(0);
 847  0
     editor.getDocument().addDocumentListener(this);
 848   
   }
 849   
 
 850   
   /* ----------------- changeListener implementation start ---------------------- */
 851   
 
 852  0
   public void stateChanged(ChangeEvent e) {
 853  0
     Object src = e.getSource();
 854  0
     if(src.equals(tpView)) {
 855  0
       switch(tpView.getSelectedIndex()) {
 856  0
         case VIEW_TAB_LAYOUT:
 857  0
           setLayoutView();
 858  0
           break;
 859  0
         case VIEW_TAB_HTML:
 860  0
           setHTMLView();
 861  0
           break;
 862   
       }
 863   
     }
 864   
   }
 865   
 
 866   
 
 867   
   /* ----------------- changeListener implementation end ------------------------ */
 868   
 
 869   
   /* -------- DocumentListener implementation start ------------*/
 870   
 
 871   
   /**
 872   
    * listens to inserts into the document to track whether or not the document
 873   
    * needs to be saved.
 874   
    */
 875  46
   public void insertUpdate(DocumentEvent e) {
 876   
     //System.out.println("insertUpdate setting textChanged=true for " + getDocumentName());
 877  46
     textChanged = true;
 878   
     /*if (tpView.getSelectedIndex() == VIEW_TAB_HTML) {
 879   
       StyledDocument sDoc = (StyledDocument) e.getDocument();
 880   
       htmlEditor.setMarks(sDoc, 0, sDoc.getLength(), this);
 881   
     }*/
 882   
   }
 883   
 
 884   
   /**
 885   
    * listens to removes from the document to track whether or not the document
 886   
    * needs to be saved.
 887   
    */
 888  32
   public void removeUpdate(DocumentEvent e) {
 889   
     //System.out.println("removeUpdate setting textChanged=true for " + getDocumentName());
 890  32
     textChanged = true;
 891   
   }
 892   
 
 893   
   /**
 894   
    * listens to changes on the document to track whether or not the document
 895   
    * needs to be saved.
 896   
    */
 897  36
   public void changedUpdate(DocumentEvent e) {
 898   
     //System.out.println("changedUpdate setting textChanged=true for " + getDocumentName());
 899  36
     if (tpView.getSelectedIndex() == VIEW_TAB_LAYOUT) {
 900  36
       textChanged = true;
 901   
     }
 902   
   }
 903   
 
 904   
   /* -------- DocumentListener implementation end ------------*/
 905   
 
 906   
   /* -------- DocumentPaneListener definition start --------------- */
 907   
 
 908   
   /**
 909   
    * interface to be implemented for being notified of
 910   
    * changes to the name of this document
 911   
    */
 912   
   public interface DocumentPaneListener {
 913   
     public void nameChanged(DocumentPaneEvent e);
 914   
     public void activated(DocumentPaneEvent e);
 915   
   }
 916   
 
 917   
   /** the event object definition for DocumentPaneEvents */
 918   
   public class DocumentPaneEvent extends EventObject {
 919  0
     public DocumentPaneEvent(Object source) {
 920  0
       super(source);
 921   
     }
 922   
   }
 923   
 
 924   
   /** listeners for DocumentPaneEvents */
 925   
   private Vector dpListeners = new Vector();
 926   
 
 927   
   /**
 928   
    * add a DocumentPaneListener to this Document
 929   
    *
 930   
    * @param listener the listener object to add
 931   
    */
 932  0
   public void addDocumentPaneListener(DocumentPaneListener listener) {
 933  0
     if(!dpListeners.contains(listener)) {
 934  0
       dpListeners.addElement(listener);
 935   
     }
 936   
     //System.out.println("DocumentPane.addDocumentPaneListener docName=" + getDocumentName() + ", listener.count=" + dpListeners.size());
 937   
   }
 938   
 
 939   
   /**
 940   
    * remove a DocumentPaneListener from this Document
 941   
    *
 942   
    * @param listener  the listener object to remove
 943   
    */
 944  0
   public void removeDocumentPaneListener(DocumentPaneListener listener) {
 945  0
     dpListeners.remove(listener);
 946   
   }
 947   
 
 948   
   /**
 949   
    * fire a DocumentPaneEvent to all registered DocumentPaneListeners
 950   
    */
 951  5
   public void fireNameChanged() {
 952  5
     Enumeration listenerList = dpListeners.elements();
 953  5
     while(listenerList.hasMoreElements()) {
 954  0
       ((DocumentPaneListener) listenerList.nextElement()).nameChanged(new DocumentPaneEvent(this));
 955   
     }
 956   
   }
 957   
 
 958   
   /**
 959   
    * fire a DocumentPaneEvent to all registered DocumentPaneListeners
 960   
    */
 961  79
   public void fireActivated() {
 962  79
     Enumeration listenerList = dpListeners.elements();
 963  79
     while(listenerList.hasMoreElements()) {
 964  0
       ((DocumentPaneListener) listenerList.nextElement()).activated(new DocumentPaneEvent(this));
 965   
     }
 966   
   }
 967   
 
 968   
   /**
 969   
    * remove all listeners
 970   
    */
 971  11
   public void removeAllListeners() {
 972  11
     dpListeners.clear();
 973   
   }
 974   
 
 975   
   /* -------- DocumentPaneListener definition end --------------- */
 976   
 }