/* The contents of this file are subject to the THDL Open Community License Version 1.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License on the THDL web site (http://www.thdl.org/). Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific terms governing rights and limitations under the License. The Initial Developer of this software is the Tibetan and Himalayan Digital Library (THDL). Portions created by the THDL are Copyright 2001-2003 THDL. All Rights Reserved. Contributor(s): ______________________________________. */ package org.thdl.tib.bibl; import java.awt.Event; import java.awt.event.*; import java.awt.Color; import java.awt.Dimension; import java.awt.Toolkit; import java.io.File; import java.util.Vector; import java.util.Iterator; import javax.swing.*; import javax.swing.text.*; import javax.swing.event.*; /** *

* TibFrame is the view for the {@link TiblEdit} program. TiblEdit is the controller. * {@link TibDoc}, or {@link TiblEdit#tibbibl} in its instantiation, is the data model. * TibFrame mainly utilizes a {@link TextPane} (an extension of JTextPane) as its main * view window, but also allows split screens with a {@link DiacriticPanel} on the left and/or * a {@link TibTable} at the bottom. *

* * @author Than Garson, Tibetan and Himalayan Digital Library */ public class TibFrame extends JFrame implements CaretListener, TibConstants { // Attributes private TiblEdit controller; // Frame Attributes private JMenu fileMenu, editMenu, insertMenu, provMenu, viewMenu; // File Menu items private JMenuItem openItem, closeItem, saveItem, saveAsItem, exportItem, exitItem; // Edit Menu items protected JMenuItem cutItem, copyItem, pasteItem, editTransItem, editNormItem, removeAppItem, removeTitleItem, removeEditionItem; // Insert menu items private JMenuItem critTitleItem, edTitleItem, variantItem, insertEdItem, insertDiscItem; // View Menu items private JCheckBoxMenuItem diacItem, edConsultItem; private JMenuItem masterIDItem, userIDItem, aboutItem; private JMenuItem[] recentFileItems; //private JMenuItem authorItem, audienceItem, redactorItem, translatorItem, concealerItem, revealerItem; private JPanel contentPanel; private JComponent rightSp, leftSp, bottomSp, topSp; private JSplitPane horizontalSplit, verticalSplit; private TextPane tp; private DiacriticPanel dp; private TibTable tibTable; Vector styleElements; // Initialization /** *

* This is the initialization method for the TibFrame. The TibFrame is the view for * this program, for which a {@link TiblEdit} object is the controller and * a {@link TibDoc} is the data model. This method establishes a file menu, * an edit menu, an view menu, and an insert menu. Its content pane is set to a * JScrollPane with a {@link TextPane} as its view. *

*/ protected void init() { Toolkit xKit = getToolkit(); Dimension wndSize = xKit.getScreenSize(); setBounds(wndSize.width/16, wndSize.height/16, 7*wndSize.width/8, 7*wndSize.height/8); addWindowListener(new XWindowHandler()); addComponentListener(new XComponentHandler()); // TextPane content pane tp = new TextPane(controller); EditorKit ekit = tp.getEditorKit(); Action[] actions = ekit.getActions(); // MenuBar JMenuBar menuBar = new JMenuBar(); setJMenuBar(menuBar); // File Menu fileMenu = new JMenu(FILE); openItem = fileMenu.add(new FileAction(OPENFILE,this)); openItem.setAccelerator(KeyStroke.getKeyStroke('O',Event.CTRL_MASK)); openItem.setFont(MENU_FONT); openItem.setEnabled(true); closeItem = fileMenu.add(new FileAction(CLOSEFILE,this)); closeItem.setAccelerator(KeyStroke.getKeyStroke('W',Event.CTRL_MASK)); closeItem.setFont(MENU_FONT); closeItem.setEnabled(false); saveItem = fileMenu.add(new FileAction(SAVE,this)); saveItem.setAccelerator(KeyStroke.getKeyStroke('S',Event.CTRL_MASK)); saveItem.setFont(MENU_FONT); saveItem.setEnabled(false); fileMenu.addSeparator(); recentFileItems = new JMenuItem[RECENT_FILE_SIZE]; for(int n=0;n * This sets the {@link #controller} variable to the controller which is the * instantiation of the main {@link TiblEdit} program. *

* * @param TiblEdit - the controller of the program. */ public void setController (TiblEdit jt) { controller = jt; } /** *

* This method returns the controller for this view. *

* * @return TiblEdit - the controller. */ public TiblEdit getController() { return controller; } /** *

* This method sets the list of recent files in the file menu. *

* * @param recent - A Vector of the recent files from the controller. */ public void setRecentFiles(Vector recent) { int n = 0; for(Iterator it=recent.iterator();it.hasNext();) { final File file = (File)it.next(); if(n == RECENT_FILE_SIZE) {break;} JMenuItem fileItem = recentFileItems[n++]; fileItem.setText(file.getName()); ActionListener al[] = fileItem.getActionListeners(); if(al != null && al.length >0) {fileItem.removeActionListener(al[0]);} fileItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { controller.openFile(file); } }); fileItem.setVisible(true); fileItem.setEnabled(true); } for(;n * This returns the {@link TextPane} that is the main view for tibbibl text information. * The TextPane is set in this objects {@link #init} method and is set within a * JScrollPane. *

* * @return TextPane the text pane that is the main content view of the program. */ public TextPane getTextPane() { return tp; } /** *

* This returns the position of the caret within the {@link TextPane} that is * the main text view for the program. *

* * @return int - the position of the caret. */ public int getCaretPosition() { return tp.getCaret().getDot(); } // Helper methods /** *

* This method is called by the controller when a file is opened. It serves to * enable or disable the appropriate menu commands. Open is disabled, and * close, save, view titles, add crit title, add ed title, and view editions consulted * are turned on. *

*/ public void fileOpened() { setTitle(PROG_NAME+controller.getCurrentFile().getName()); openItem.setEnabled(false); closeItem.setEnabled(true); saveItem.setEnabled(true); critTitleItem.setEnabled(true); edTitleItem.setEnabled(true); edConsultItem.setEnabled(true); copyItem.setEnabled(true); cutItem.setEnabled(true); pasteItem.setEnabled(true); editTransItem.setEnabled(true); editNormItem.setEnabled(true); masterIDItem.setEnabled(true); insertEdItem.setEnabled(true); removeEditionItem.setEnabled(true); insertDiscItem.setEnabled(true); for(int n=0;n * This method is called by the controller when a file is closed. It serves to * enable or disable the appropriate menu commands. Open is enabled and * close, save, insert crit title, insert ed title, view titles, and view editions * consulted are all disabled. It also calls {@link TextPane#reset}, which resets * the styled document for the textpane view, calls {@link #hideEditions} to hide * any table that is displaying at the bottom of the screen, and then redisplays itself * with {@link #show}. *

*/ public void fileClosed() { setTitle(DEFAULT_HEADER); openItem.setEnabled(true); closeItem.setEnabled(false); saveItem.setEnabled(false); critTitleItem.setEnabled(false); edTitleItem.setEnabled(false); edConsultItem.setEnabled(false); copyItem.setEnabled(false); cutItem.setEnabled(false); pasteItem.setEnabled(false); editTransItem.setEnabled(false); editNormItem.setEnabled(false); masterIDItem.setEnabled(false); insertEdItem.setEnabled(false); removeEditionItem.setEnabled(false); insertDiscItem.setEnabled(false); tp.reset(); hideEditions(); setRecentFiles(controller.getRecent()); setTitle(DEFAULT_HEADER); show(); } /** *

* This method is called (maybe) when the cursor is on a title. It enables the add * critical title menu option. (May be deprecated?) *

*/ public void titleSelected() { critTitleItem.setEnabled(true); } /** *

* This method is called (maybe) when cursor is on something other than a title. It disables the add * critical title menu option. (May be deprecated?) *

*/ public void titleNotSelected() { critTitleItem.setEnabled(false); } /** *

* This method displays a {@link TibTable} as the bottom half of a split screen with the {@link TextPane} * This particular table displays the editions consulted for the formation of the master record * by displaying the information in the text's tibiddecl element. To do so it uses {@link TibTable#TibTable(IDFactory) TibTable constructor} * that takes an {@link IDFactory} retrieved from the {@link TibDoc}. It then calls {@link #showTable(TibTable) TibTable} * method. *

*/ public void showEditions() { if(controller.getTibDoc() == null) {return;} tibTable = new TibTable(controller.getTibDoc().getIDFactory()); showTable(tibTable); } /** *

* This method hides any table that is displaying at the bottom of the {@link TextPane}. The first * table that used this was the edition's consulted table, but it will close any table including an apparatus * table that is displaying at the bottom of the screen. *

*/ public void hideEditions() { topSp = new JScrollPane(tp); if(horizontalSplit == null) { setContentPane(topSp); show(); } else { int horizLoc = horizontalSplit.getDividerLocation(); horizontalSplit.setRightComponent(topSp); show(); horizontalSplit.setDividerLocation(horizLoc); } show(); verticalSplit = null; } /** *

* This method creates a split screen with a {@link DiacriticPanel#DiacriticPanel(TibFrame) DiacriticPanel} * on the left and the main {@link TextPane} on the right. *

*/ public void showDiacritics() { dp = new DiacriticPanel(this); rightSp = new JScrollPane(dp); JComponent comp; if(verticalSplit == null) { leftSp = new JScrollPane(tp); comp = leftSp; } else { comp = verticalSplit; } horizontalSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,rightSp,comp); setContentPane(horizontalSplit); show(); double loc = 0.1D; horizontalSplit.setDividerLocation(loc); } /** *

* This method hides the {@link DiacriticPanel} that is displayed on the left of * the split screen. *

*/ public void hideDiacritics() { JComponent comp; if(verticalSplit == null) { comp = tp; } else { comp = verticalSplit; } rightSp = new JScrollPane(comp); setContentPane(rightSp); show(); horizontalSplit = null; } /** *

* This method displays a {@link TibTable} underneath the {@link TextPane}. It takes a * {@link TibTable} as its parameter and depending on the value of its {@link TibTable#getType() type} * inserts either an JTable with the editions consulted or it retrieves an {@link TibTable#getAppPanel() specific * JPanel} that has a table with an apparatus' info and control buttons. *

* * @param TibTable the TibTable object that contains the tabular information to be displayed. */ public void showTable(TibTable tt) { JSplitPane tableSplit = new JSplitPane(); if(tt.getType() == TibTable.APP) { edConsultItem.setSelected(false); tt.addObserver(controller); tableSplit = tt.getAppPanel(); bottomSp = tableSplit; } else { bottomSp = new JScrollPane(tt.getTable()); } topSp = new JScrollPane(tp); verticalSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT,topSp,bottomSp); if(horizontalSplit == null) { setContentPane(verticalSplit); show(); } else { int horizLoc = horizontalSplit.getDividerLocation(); horizontalSplit.setRightComponent(verticalSplit); show(); horizontalSplit.setDividerLocation(horizLoc); } double loc = 0.80D; verticalSplit.setDividerLocation(loc); tableSplit.setDividerLocation(loc); } /** *

* This method is called if the insert variant option is chosen from the insert menu. Variant readings * are displayed in the {@link TextPane} with a yellow background and are determined by being marked up * within an app element. When inserting a new variant, the app element was not originally there so the * selected area does not have a yellow background. This method sets the background of the selected area * to yellow until the insertion is complete and the TextPane can be redisplayed. *

*/ public void displayNewApp() { int start = tp.getSelectionStart(); int len = tp.getSelectedText().length(); Style variant = tp.getStyle(TextPane.VARIANT); tp.getStyledDocument().setCharacterAttributes(start,len,variant,false); } /** *

* This method displays all the variations of text titles found in a {@link TibDoc}. It takes the * TibDoc's {@link TitleFactory} and uses its {@link TitleFactory#getAllTitles() getAllTitles} method * to retrive a vector of {@link ElementStyle ElementStyles}. It also adds a text header at the top * and depending on the {@link TiblEdit#mode mode} of the controller (i.e., whether it is inserting a * new title or translation, etc.) adds appropriate prompts. It then calls the {@link TextPane#setTextPane(Vector) TextPane's setTextPane(Vector)} * method with the vector of StyleElements and this displays the information. That setTextPane method * returns an {@link ElementList} which is a list of org.jdom.Elements with their associated positions in * the TextPane (start and end) so that when the caret is positioned somewhere in the TextPane the controller * can find the associated element and make the appropriate options available. *

* * @param TitleFactory - The TibDocs TitleFactory object for retrieving title information * * @return ElementList - The ElementList returned by the TextPane once its document is set. * */ public ElementList showTitles(TitleFactory tf) { int presCaretPos = tp.getCaretPosition(); if(presCaretPos < 0) {presCaretPos = 0;} styleElements = new Vector(); // Do the Text's Header Element as the documents general header String[] headStrings = tf.getHeadStrings(); if(headStrings == null) { styleElements.add(new ElementStyle("No Head Element Found\n\n",TextPane.TEXT_HEAD,NO_ELEM)); } else { styleElements.add(new ElementStyle(headStrings[0]+" ",TextPane.TEXT_HEAD,NO_ELEM)); if(headStrings.length>1) { for(int n=1;n * This method is used by {@link #showTitles(TitleFactory)} to insert prompts for information * at the correct location. The showTitles method creates a vector of {@link ElementStyle}. Once * this is created, if the {@link TiblEdit#mode} is to insert a title or translation. This method * is called with the selected element. It searches the vector for that element and returns its * index in the vector. *

* * @param org.jdom.Element - the selected element. * * @return int - that element's index in the ElementStyle Vector. */ private int findElementStyleIndex(org.jdom.Element el) { if(styleElements == null) { System.out.println("No styleElements list to search in findElementStyleIndex of TibFrame"); return -1; } int index = -1; Iterator it = styleElements.iterator(); while(it.hasNext()) { Object item = it.next(); //System.out.println("It is: " + item.getClass().getName()); ElementStyle es = (ElementStyle)item; if(es.getElement().equals(el)) { index = styleElements.indexOf(es);} } if(index == -1) { //System.out.println("Element was not found: " + TiblEdit.outputString(el)); } return index; } public DiscDialog getDiscussionDialog(TibDoc tibl) { DiscDialog dd = new DiscDialog(this, tibl); return dd; } // Constructor /** *

* This constructor simply takes a title as the corresponding JFrame contructor. *

* * @param String - the frame's title. */ public TibFrame(String title) { super(title); init(); } /** *

* This constructor takes both a title and a {@link TiblEdit} object that is its controller. * It first calls JFrame's title constructor, then {@link #setController(TiblEdit) the setController} method * and then the {@link #init()} method. *

*/ public TibFrame(String title, TiblEdit app) { super(title); setController(app); init(); } // Main for testing public static void main(String[] args) { } // Listeners /** *

* This implementation of the CaretListener interface calls the controller's * {@link TiblEdit#checkCaretPosition(String) checkCaretPosition} method with the type of {@link TibConstants#AP AP} * to see if an appartatus element is insertable. If so, then it turns on the insert variant reading * menu item. If not, that item is turned off. *

* * @param CaretEvent - the required parameter of this abstract method. It is not used here. */ public void caretUpdate(CaretEvent ce) { boolean canInsertAp = controller.checkCaretPosition(AP_CHECK); if(canInsertAp) { variantItem.setEnabled(true); } else { variantItem.setEnabled(false); } if(controller.checkCaretPosition(ED_TITLE_REM)) { removeTitleItem.setEnabled(true); } else { removeTitleItem.setEnabled(false); } } // SubClasses Event Handlers /** *

* The inner class, XWindowHandler, extends the WindowAdapter and is used for the closing of the frame. * It is added to the TibFrame in its {@link #init} method. *

*/ /** *

* When the TibFrame is closed, the program ends. The window is disposed. The controller's * {@link TiblEdit#exit() exit()} method is called, and the system is exited. *

*/ public class XWindowHandler extends WindowAdapter implements TibConstants { /** See class comment. * * @param WindowEvent - the required parameter for this abstract method. */ public void windowClosing(WindowEvent e) { e.getWindow().dispose(); controller.exit(); } } public class XComponentHandler extends ComponentAdapter { public void ComponentResized(ComponentEvent ce) { show(); } } }