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    }