/* * Created on Jan 14, 2006 * */ package net.atlanticbb.tantlinger.ui.text.actions; import java.awt.Component; import java.awt.Dialog; import java.awt.Frame; import java.awt.Window; import java.awt.event.ActionEvent; import java.util.Enumeration; //import java.util.Hashtable; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import javax.swing.Action; import javax.swing.JEditorPane; import javax.swing.SwingUtilities; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; import javax.swing.text.Element; import javax.swing.text.StyleConstants; import javax.swing.text.html.HTML; import javax.swing.text.html.HTMLDocument; import net.atlanticbb.tantlinger.ui.text.CompoundUndoManager; import net.atlanticbb.tantlinger.ui.text.HTMLUtils; import net.atlanticbb.tantlinger.ui.text.dialogs.ElementStyleDialog; import net.atlanticbb.tantlinger.ui.text.dialogs.HyperlinkDialog; import net.atlanticbb.tantlinger.ui.text.dialogs.ImageDialog; import net.atlanticbb.tantlinger.ui.text.dialogs.ListDialog; import net.atlanticbb.tantlinger.ui.text.dialogs.TablePropertiesDialog; import org.bushe.swing.action.ShouldBeEnabledDelegate; /** * Action for editing an element's properties depending on the * current caret position. * * Currently supports links, images, tables, lists, and paragraphs. * * @author Bob Tantlinger * */ public class HTMLElementPropertiesAction extends HTMLTextEditAction { /** * */ private static final long serialVersionUID = 1L; public static final int TABLE_PROPS = 0; public static final int LIST_PROPS = 1; public static final int IMG_PROPS = 2; public static final int LINK_PROPS = 3; public static final int ELEM_PROPS = 4; public static final String PROPS[] = { i18n.str("table_properties_"), i18n.str("list_properties_"), i18n.str("image_properties_"), i18n.str("hyperlink_properties_"), i18n.str("object_properties_") }; public HTMLElementPropertiesAction() { super(PROPS[ELEM_PROPS]); addShouldBeEnabledDelegate(new ShouldBeEnabledDelegate() { public boolean shouldBeEnabled(Action a) { return getEditMode() != SOURCE && elementAtCaretPosition(getCurrentEditor()) != null; } }); } //public void actionPerformed(ActionEvent e) protected void wysiwygEditPerformed(ActionEvent e, JEditorPane ed) { Element elem = elementAtCaretPosition(ed); int type = getElementType(elem); int caret = ed.getCaretPosition(); if(type == LINK_PROPS) { editLinkProps(elem); } else if(type == IMG_PROPS) { editImageProps(elem); } else if(type == TABLE_PROPS) { editTableProps(elem); } else if(type == LIST_PROPS) { editListProps(elem); } else if(type == ELEM_PROPS) { editStyleProps(elem.getParentElement()); } try { ed.setCaretPosition(caret); } catch(Exception ex){} } private Map getAttribs(Element elem) { Map at = new HashMap(); AttributeSet a = elem.getAttributes(); for(Enumeration e = a.getAttributeNames(); e.hasMoreElements();) { Object n = e.nextElement(); //dont return the name attribute if(n.toString().equals("name") && !elem.getName().equals("a")) continue; at.put(n.toString(), a.getAttribute(n).toString()); } return at; } private String getElementHTML(Element el, Map attribs) { String html = "<" + el.getName(); for(Iterator e = attribs.keySet().iterator(); e.hasNext();) { Object name = e.next(); Object val = attribs.get(name); html += " " + name + "=\"" + val + "\""; } String txt = HTMLUtils.getElementHTML(el, false); html += ">\n" + txt + "\n</" + el.getName() + ">"; return html; } private Map getLinkAttributes(Element elem) { String link = HTMLUtils.getElementHTML(elem, true).trim(); Map attribs = new HashMap(); if(link.startsWith("<a")) { link = link.substring(0, link.indexOf('>')); link = link.substring(link.indexOf(' '), link.length()).trim(); attribs = HTMLUtils.tagAttribsToMap(link); } return attribs; } private void editImageProps(Element elem) { ImageDialog d = createImageDialog(); if(d != null) { Map imgAttribs = getAttribs(elem); d.setImageAttributes(imgAttribs); d.setLocationRelativeTo(d.getParent()); d.setVisible(true); if(!d.hasUserCancelled()) { replace(elem, d.getHTML()); } } } private void editLinkProps(Element elem) { HyperlinkDialog d = createLinkDialog(); if(d != null) { d.setAttributes(getLinkAttributes(elem)); d.setLocationRelativeTo(d.getParent()); try { //get the link text... String text = elem.getDocument().getText( elem.getStartOffset(), elem.getEndOffset() - elem.getStartOffset()); d.setLinkText(text); } catch(BadLocationException ex){} d.setVisible(true); if(!d.hasUserCancelled()) { replace(elem, d.getHTML()); } } } private void editTableProps(Element paraElem) { HTMLDocument doc = null; try { doc = (HTMLDocument)paraElem.getDocument(); } catch(Exception ex) { ex.printStackTrace(); return; } Element tdElem = HTMLUtils.getParent(paraElem, HTML.Tag.TD); Element trElem = HTMLUtils.getParent(paraElem, HTML.Tag.TR); Element tableElem = HTMLUtils.getParent(paraElem, HTML.Tag.TABLE); TablePropertiesDialog dlg = createTablePropertiesDialog(); if(dlg == null || tdElem == null || trElem == null || tableElem == null) return; //no dialog or malformed table! Just return... dlg.setCellAttributes(getAttribs(tdElem)); dlg.setRowAttributes(getAttribs(trElem)); dlg.setTableAttributes(getAttribs(tableElem)); dlg.setLocationRelativeTo(dlg.getParent()); dlg.setVisible(true); if(!dlg.hasUserCancelled()) { CompoundUndoManager.beginCompoundEdit(doc); try { String html = getElementHTML(tdElem, dlg.getCellAttributes()); doc.setOuterHTML(tdElem, html); html = getElementHTML(trElem, dlg.getRowAttribures()); doc.setOuterHTML(trElem, html); html = getElementHTML(tableElem, dlg.getTableAttributes()); doc.setOuterHTML(tableElem, html); } catch(Exception ex) { ex.printStackTrace(); } CompoundUndoManager.endCompoundEdit(doc); } } private void editListProps(Element elem) { elem = HTMLUtils.getListParent(elem); if(elem == null) return; int type; if(elem.getName().equals("ul")) type = ListDialog.UNORDERED; else if(elem.getName().equals("ol")) type = ListDialog.ORDERED; else return; Map attr = getAttribs(elem); ListDialog d = createListDialog(); if(d == null) return; d.setListType(type); d.setListAttributes(attr); d.setLocationRelativeTo(d.getParent()); d.setVisible(true); if(!d.hasUserCancelled()) { attr = d.getListAttributes(); String html = ""; if(d.getListType() != type) { HTML.Tag tag = HTML.Tag.UL; if(d.getListType() == ListDialog.ORDERED) tag = HTML.Tag.OL; String txt = HTMLUtils.getElementHTML(elem, false); html = "<" + tag; for(Iterator ee = attr.keySet().iterator(); ee.hasNext();) { Object o = ee.next(); html += " " + o + "=" + attr.get(o); } html += ">" + txt + "</" + tag + ">"; } else { html = getElementHTML(elem, attr); } replace(elem, html); } } private void editStyleProps(Element elem) { if(elem.getName().equals("p-implied")) elem = elem.getParentElement(); Map attr = getAttribs(elem); ElementStyleDialog d = createStyleDialog(); if(d == null) return; d.setLocationRelativeTo(d.getParent()); d.setStyleAttributes(attr); d.setVisible(true); if(!d.hasUserCancelled()) { System.err.println(elem.getName()); String html = getElementHTML(elem, d.getStyleAttributes()); System.err.println(html); replace(elem, html); } } protected HyperlinkDialog createLinkDialog() { Component c = getCurrentEditor(); HyperlinkDialog d = null; if(c != null) { Window w = SwingUtilities.getWindowAncestor(c); if(w != null && w instanceof Frame) d = new HyperlinkDialog((Frame)w); else if(w != null && w instanceof Dialog) d = new HyperlinkDialog((Dialog)w); } return d; } protected ImageDialog createImageDialog() { Component c = getCurrentEditor(); ImageDialog d = null; if(c != null) { Window w = SwingUtilities.getWindowAncestor(c); if(w != null && w instanceof Frame) d = new ImageDialog((Frame)w); else if(w != null && w instanceof Dialog) d = new ImageDialog((Dialog)w); } return d; } protected TablePropertiesDialog createTablePropertiesDialog() { Component c = getCurrentEditor(); TablePropertiesDialog d = null; if(c != null) { Window w = SwingUtilities.getWindowAncestor(c); if(w != null && w instanceof Frame) d = new TablePropertiesDialog((Frame)w); else if(w != null && w instanceof Dialog) d = new TablePropertiesDialog((Dialog)w); } return d; } protected ListDialog createListDialog() { Component c = getCurrentEditor(); ListDialog d = null; if(c != null) { Window w = SwingUtilities.getWindowAncestor(c); if(w != null && w instanceof Frame) d = new ListDialog((Frame)w); else if(w != null && w instanceof Dialog) d = new ListDialog((Dialog)w); } return d; } protected ElementStyleDialog createStyleDialog() { Component c = getCurrentEditor(); ElementStyleDialog d = null; if(c != null) { Window w = SwingUtilities.getWindowAncestor(c); if(w != null && w instanceof Frame) d = new ElementStyleDialog((Frame)w); else if(w != null && w instanceof Dialog) d = new ElementStyleDialog((Dialog)w); } return d; } private void replace(Element elem, String html) { HTMLDocument document = null; try { document = (HTMLDocument)elem.getDocument(); } catch(Exception ex) { ex.printStackTrace(); } CompoundUndoManager.beginCompoundEdit(document); try { document.setOuterHTML(elem, html); } catch(Exception ex) { ex.printStackTrace(); } CompoundUndoManager.endCompoundEdit(document); } protected void updateWysiwygContextState(JEditorPane ed) { int t = ELEM_PROPS; Element elem = elementAtCaretPosition(ed); if(elem != null) { t = getElementType(elem); } putValue(NAME, PROPS[t]); //Messages.setMnemonic(PROPS[t], this); TODO this won't set the right mnemonic } private int getElementType(Element elem) { AttributeSet att = elem.getAttributes(); String name = att.getAttribute(StyleConstants.NameAttribute).toString(); //is it an image? if(name.equals("img")) return IMG_PROPS; //is it a link? for(Enumeration ee = att.getAttributeNames(); ee.hasMoreElements();) if(ee.nextElement().toString().equals("a")) return LINK_PROPS; //is it a list? if(HTMLUtils.getParent(elem, HTML.Tag.UL) != null) return LIST_PROPS; if(HTMLUtils.getParent(elem, HTML.Tag.OL) != null) return LIST_PROPS; //is it a table? if(HTMLUtils.getParent(elem, HTML.Tag.TD) != null) return TABLE_PROPS; //return the default return ELEM_PROPS; } /** * Computes the (inline or block) element at the focused editor's caret position * @return the element, or null of the element cant be retrieved */ private Element elementAtCaretPosition(JEditorPane ed) { if(ed == null) return null; HTMLDocument doc = (HTMLDocument)ed.getDocument(); int caret = ed.getCaretPosition(); Element elem = doc.getParagraphElement(caret); HTMLDocument.BlockElement blockElem = (HTMLDocument.BlockElement)elem; return blockElem.positionToElement(caret); } /* (non-Javadoc) * @see net.atlanticbb.tantlinger.ui.text.actions.HTMLTextEditAction#sourceEditPerformed(java.awt.event.ActionEvent, javax.swing.JEditorPane) */ protected void sourceEditPerformed(ActionEvent e, JEditorPane editor) { } }