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 }