001 // This file is part of AceWiki. 002 // Copyright 2008-2012, AceWiki developers. 003 // 004 // AceWiki is free software: you can redistribute it and/or modify it under the terms of the GNU 005 // Lesser General Public License as published by the Free Software Foundation, either version 3 of 006 // the License, or (at your option) any later version. 007 // 008 // AceWiki is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 009 // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 010 // Lesser General Public License for more details. 011 // 012 // You should have received a copy of the GNU Lesser General Public License along with AceWiki. If 013 // not, see http://www.gnu.org/licenses/. 014 015 package ch.uzh.ifi.attempto.acewiki.gui; 016 017 import nextapp.echo.app.Alignment; 018 import nextapp.echo.app.Border; 019 import nextapp.echo.app.Button; 020 import nextapp.echo.app.Color; 021 import nextapp.echo.app.Column; 022 import nextapp.echo.app.Extent; 023 import nextapp.echo.app.Font; 024 import nextapp.echo.app.Insets; 025 import nextapp.echo.app.ResourceImageReference; 026 import nextapp.echo.app.Row; 027 import nextapp.echo.app.event.ActionEvent; 028 import nextapp.echo.app.event.ActionListener; 029 import nextapp.echo.app.layout.RowLayoutData; 030 import ch.uzh.ifi.attempto.acewiki.Wiki; 031 import ch.uzh.ifi.attempto.echocomp.Style; 032 import echopoint.ContainerEx; 033 import echopoint.able.Positionable; 034 035 /** 036 * This class represents drop down menus that are shown in front of the ACE sentences as small 037 * triangles. Such drop down menus can have different appearances based on different types. 038 * 039 * @author Tobias Kuhn 040 */ 041 public class StatementMenu extends Row implements ActionListener { 042 043 private static final long serialVersionUID = 3646511994109953476L; 044 045 /** 046 * This type is for sentences used for reasoning. 047 */ 048 public static final int REASONING_TYPE = 0; 049 050 /** 051 * This type is for sentences that are not used for reasoning. 052 */ 053 public static final int NOREASONING_TYPE = 1; 054 055 /** 056 * This type is for questions. 057 */ 058 public static final int QUESTION_TYPE = 2; 059 060 /** 061 * This type is for sentences that are automatically inferred. 062 */ 063 public static final int INFERRED_TYPE = 3; 064 065 /** 066 * This type is for comments. 067 */ 068 public static final int COMMENT_TYPE = 4; 069 070 /** 071 * This type is for drop down menus with no statement. 072 */ 073 public static final int EMPTY_TYPE = 5; 074 075 private Button toggle = new Button(); 076 private ContainerEx popup; 077 private Button overlayLockButton; 078 079 private int type; 080 081 private Column menuColumn = new Column(); 082 private ActionListener actionListener; 083 private Column menuSeparator = null; 084 private Wiki wiki; 085 private RowLayoutData layout; 086 087 /** 088 * Creates a empty drop down menu with an icon of the given color. 089 * 090 * @param type The type of the statement. 091 * @param wiki The wiki object. 092 * @param actionListener The action-listener. 093 */ 094 public StatementMenu(int type, Wiki wiki, ActionListener actionListener) { 095 this.type = type; 096 this.wiki = wiki; 097 this.actionListener = actionListener; 098 099 layout = new RowLayoutData(); 100 layout.setAlignment(new Alignment(Alignment.LEFT, Alignment.TOP)); 101 102 toggle.setWidth(new Extent(13)); 103 toggle.setHeight(new Extent(13)); 104 toggle.setInsets(new Insets(1)); 105 toggle.setLayoutData(layout); 106 toggle.setIcon(getNormalIcon()); 107 toggle.setRolloverEnabled(true); 108 toggle.setRolloverIcon(getActiveIcon()); 109 toggle.setPressedIcon(getActiveIcon()); 110 toggle.setToolTipText(getTooltipText()); 111 toggle.addActionListener(this); 112 add(toggle); 113 } 114 115 /** 116 * Adds a menu entry to the drop down menu. 117 * 118 * @param text The text of the menu entry. 119 * @param tooltip The tool tip text of the menu entry. 120 */ 121 public void addMenuEntry(String text, String tooltip) { 122 if (menuSeparator != null) { 123 menuColumn.add(menuSeparator); 124 menuSeparator = null; 125 } 126 Button menuEntry = new Button(text); 127 menuEntry.setActionCommand(text); 128 menuEntry.setHeight(new Extent(16)); 129 menuEntry.setWidth(new Extent(140)); 130 menuEntry.setBackground(Style.mediumBackground); 131 menuEntry.setForeground(Style.darkForeground); 132 menuEntry.setRolloverEnabled(true); 133 menuEntry.setRolloverForeground(Style.lightForeground); 134 menuEntry.setRolloverBackground(Style.darkBackground); 135 menuEntry.setInsets(new Insets(2, 0)); 136 menuEntry.setAlignment(new Alignment(Alignment.LEFT, Alignment.CENTER)); 137 menuEntry.setTextAlignment(new Alignment(Alignment.LEFT, Alignment.CENTER)); 138 menuEntry.setFont(new Font(Style.fontTypeface, Font.ITALIC, new Extent(13))); 139 menuEntry.setToolTipText(tooltip); 140 menuEntry.addActionListener(this); 141 menuColumn.add(menuEntry); 142 } 143 144 /** 145 * Adds a separator to the menu. 146 */ 147 public void addMenuSeparator() { 148 if (menuColumn.getComponentCount() == 0) return; 149 menuSeparator = new Column(); 150 menuSeparator.setInsets(new Insets(2, 0, 2, 0)); 151 menuSeparator.setBackground(Style.mediumBackground); 152 Column line = new Column(); 153 line.setBackground(Style.darkBackground); 154 line.setInsets(new Insets(0, 1, 0, 0)); 155 menuSeparator.add(line); 156 } 157 158 public void actionPerformed(ActionEvent e) { 159 Object src = e.getSource(); 160 161 if (src == toggle) { 162 setExpanded(true); 163 } else if (src == wiki) { 164 setExpanded(false); 165 } else if (src == overlayLockButton) { 166 setExpanded(false); 167 } else { 168 setExpanded(false); 169 actionListener.actionPerformed(new ActionEvent(this, e.getActionCommand())); 170 } 171 } 172 173 /** 174 * This method shows or hides the popup part of the menu. 175 * 176 * @param expanded true to show the popup; false to hide it. 177 */ 178 public void setExpanded(boolean expanded) { 179 if (expanded) { 180 if (isExpanded()) return; 181 if (menuColumn.getComponentCount() == 0) return; 182 wiki.lock(this); 183 toggle.setIcon(getActiveIcon()); 184 if (popup == null) { 185 popup = new ContainerEx(); 186 popup.setPosition(Positionable.ABSOLUTE); 187 popup.add(menuColumn); 188 popup.setBorder(new Border(1, Color.BLACK, Border.STYLE_OUTSET)); 189 popup.setZIndex(Integer.MAX_VALUE); 190 popup.setLayoutData(layout); 191 add(popup); 192 193 ContainerEx overlayLockComponent = new ContainerEx(); 194 overlayLockComponent.setPosition(Positionable.FIXED); 195 overlayLockComponent.setTop(new Extent(0)); 196 overlayLockComponent.setLeft(new Extent(0)); 197 overlayLockButton = new Button(); 198 overlayLockButton.setWidth(new Extent(10000)); 199 overlayLockButton.setHeight(new Extent(10000)); 200 overlayLockButton.addActionListener(this); 201 overlayLockComponent.add(overlayLockButton); 202 add(overlayLockComponent); 203 } else { 204 popup.setVisible(true); 205 overlayLockButton.setVisible(true); 206 } 207 } else { 208 if (!isExpanded()) return; 209 wiki.unlock(); 210 toggle.setIcon(getNormalIcon()); 211 popup.setVisible(false); 212 overlayLockButton.setVisible(false); 213 } 214 } 215 216 /** 217 * Returns whether the menu is expanded. 218 * 219 * @return true if the menu is expanded. 220 */ 221 public boolean isExpanded() { 222 return popup != null && popup.isVisible(); 223 } 224 225 private ResourceImageReference getNormalIcon() { 226 return Wiki.getImage("tri" + getIconType() + ".png"); 227 } 228 229 private ResourceImageReference getActiveIcon() { 230 return Wiki.getImage("tri" + getIconType() + "l.png"); 231 } 232 233 private String getIconType() { 234 if (type == REASONING_TYPE ) { 235 return "blue"; 236 } else if (type == QUESTION_TYPE) { 237 return "blue"; 238 } else if (type == NOREASONING_TYPE) { 239 return "red"; 240 } else if (type == INFERRED_TYPE) { 241 return "white"; 242 } else if (type == COMMENT_TYPE) { 243 return "gray"; 244 } else if (type == EMPTY_TYPE) { 245 return "gray"; 246 } 247 return ""; 248 } 249 250 private String getTooltipText() { 251 String t = null; 252 if (type == REASONING_TYPE ) { 253 t = "Blue triangle: This statement is considered for reasoning."; 254 } else if (type == QUESTION_TYPE) { 255 t = "This is a question that is automatically answered."; 256 } else if (type == NOREASONING_TYPE) { 257 t = "Red triangle: This statement is too complex to be considered for reasoning."; 258 } else if (type == INFERRED_TYPE) { 259 t = "White triangle: This statement is automatically inferred."; 260 } else if (type == COMMENT_TYPE) { 261 t = "Gray triangle: This statement is an informal comment."; 262 } else if (type == EMPTY_TYPE) { 263 t = "Click here to add a sentence or comment."; 264 } 265 return t; 266 } 267 268 }