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 java.awt.FontMetrics;
018 import java.awt.image.BufferedImage;
019 import java.util.ArrayList;
020 import java.util.List;
021
022 import nextapp.echo.app.Alignment;
023 import nextapp.echo.app.Color;
024 import nextapp.echo.app.Column;
025 import nextapp.echo.app.Component;
026 import nextapp.echo.app.Font;
027 import nextapp.echo.app.Row;
028 import nextapp.echo.app.event.ActionEvent;
029 import nextapp.echo.app.event.ActionListener;
030 import nextapp.echo.app.layout.RowLayoutData;
031 import ch.uzh.ifi.attempto.acewiki.Wiki;
032 import ch.uzh.ifi.attempto.acewiki.core.Comment;
033 import ch.uzh.ifi.attempto.acewiki.core.LanguageUtils;
034 import ch.uzh.ifi.attempto.acewiki.core.OntologyElement;
035 import ch.uzh.ifi.attempto.acewiki.core.OntologyTextElement;
036 import ch.uzh.ifi.attempto.base.TextElement;
037 import ch.uzh.ifi.attempto.echocomp.HSpace;
038 import ch.uzh.ifi.attempto.echocomp.MessageWindow;
039 import ch.uzh.ifi.attempto.echocomp.SolidLabel;
040 import ch.uzh.ifi.attempto.echocomp.VSpace;
041
042 /**
043 * This class represents a comment component consisting of a drop down menu and a comment text.
044 *
045 * @author Tobias Kuhn
046 */
047 public class CommentComponent extends Column implements ActionListener {
048
049 private static final long serialVersionUID = -540135972060005725L;
050
051 private static final int COMMENT_TEXT_WIDTH = 800;
052
053 private static FontMetrics fontMetrics =
054 (new BufferedImage(2, 2, BufferedImage.TYPE_4BYTE_ABGR_PRE)
055 .createGraphics()).getFontMetrics(new java.awt.Font("Verdana", java.awt.Font.ITALIC, 13));
056
057 private Comment comment;
058 private Wiki wiki;
059 private WikiPage hostPage;
060
061 private Row commentRow = new Row();
062 private StatementMenu statementMenu;
063
064 /**
065 * Creates a new comment row.
066 *
067 * @param comment The comment to be shown.
068 * @param hostPage The host page of the comment row.
069 */
070 public CommentComponent(Comment comment, WikiPage hostPage) {
071 this.comment = comment;
072 this.hostPage = hostPage;
073 this.wiki = hostPage.getWiki();
074 update();
075 }
076
077 private void update() {
078 statementMenu = new StatementMenu(StatementMenu.COMMENT_TYPE, wiki, this);
079 if (!wiki.isReadOnly()) {
080 statementMenu.addMenuEntry("Edit...", "Edit this comment");
081 statementMenu.addMenuEntry("Delete", "Delete this comment from the article");
082 statementMenu.addMenuSeparator();
083 statementMenu.addMenuEntry("Add Sentence...", "Add a new sentence here");
084 statementMenu.addMenuEntry("Add Comment...", "Add a new comment here");
085 }
086 RowLayoutData layout = new RowLayoutData();
087 layout.setAlignment(new Alignment(Alignment.CENTER, Alignment.TOP));
088 statementMenu.setLayoutData(layout);
089 Column c = new Column();
090 for (String s : (comment.getText() + " ").split("\\n")) {
091 int indent = s.replaceFirst("^(\\s*).*$", "$1").length() * 5;
092 s = s.replaceFirst("^\\s*", "");
093 if (indent > COMMENT_TEXT_WIDTH/2) indent = COMMENT_TEXT_WIDTH/2;
094 for (Component comp : wrapText(s, COMMENT_TEXT_WIDTH-indent)) {
095 Row r = new Row();
096 r.add(new VSpace(17));
097 r.add(new HSpace(indent));
098 r.add(comp);
099 c.add(r);
100 }
101 }
102
103 removeAll();
104 commentRow.removeAll();
105 commentRow.add(statementMenu);
106 commentRow.add(new HSpace(5));
107 commentRow.add(c);
108 commentRow.add(new HSpace(10));
109 add(commentRow);
110 }
111
112 public void actionPerformed(ActionEvent e) {
113 if (e.getActionCommand().equals("Edit...")) {
114 wiki.log("page", "dropdown: edit comment: " + comment.getText());
115 if (!wiki.isEditable()) {
116 wiki.showLoginWindow();
117 } else {
118 wiki.showWindow(CommentEditorHandler.generateEditWindow(
119 comment,
120 (ArticlePage) hostPage
121 ));
122 }
123 } else if (e.getActionCommand().equals("Add Sentence...")) {
124 wiki.log("page", "dropdown: add sentence");
125 if (!wiki.isEditable()) {
126 wiki.showLoginWindow();
127 } else {
128 wiki.showWindow(SentenceEditorHandler.generateCreationWindow(
129 comment,
130 (ArticlePage) hostPage
131 ));
132 }
133 } else if (e.getActionCommand().equals("Add Comment...")) {
134 wiki.log("page", "dropdown: add comment");
135 if (!wiki.isEditable()) {
136 wiki.showLoginWindow();
137 } else {
138 wiki.showWindow(CommentEditorHandler.generateCreationWindow(
139 comment,
140 (ArticlePage) hostPage
141 ));
142 }
143 } else if (e.getActionCommand().equals("Delete")) {
144 wiki.log("page", "dropdown: delete sentence: " + comment.getText());
145 if (!wiki.isEditable()) {
146 wiki.showLoginWindow();
147 } else {
148 wiki.showWindow(new MessageWindow(
149 "Delete",
150 "Do you really want to delete this comment?",
151 null,
152 this,
153 "Yes", "No"
154 ));
155 }
156 } else if (e.getSource() instanceof MessageWindow && e.getActionCommand().equals("Yes")) {
157 wiki.log("page", "dropdown: delete confirmed: " + comment.getText());
158 comment.getArticle().remove(comment);
159 wiki.update();
160 wiki.refresh();
161 }
162 }
163
164 private List<Component> wrapText(String text, int width) {
165 List<Component> wrappedText = new ArrayList<Component>();
166 String line = "";
167 Row row = new Row();
168 text = text.replaceAll("~", "~t");
169 while (text.matches(".*\\[\\[[^\\]]* [^\\]]*\\]\\].*")) {
170 text = text.replaceAll("\\[\\[([^\\]]*) ([^\\]]*)\\]\\]", "[[$1_$2]]");
171 }
172 text = text.replaceAll(" ", " ~b");
173 text = text.replaceAll("_of\\]\\]", " of]]");
174 text = text.replaceAll("_by\\]\\]", " by]]");
175 text = text.replaceAll("\\[\\[", "~b[[");
176 text = text.replaceAll("\\]\\]", "]]~b");
177 text = text.replaceAll("~t", "~");
178 for (String s : text.split("~b")) {
179 CommentPart cp = new CommentPart(s);
180 if (line.length() == 0 || fontMetrics.stringWidth(line + cp.getText()) < width) {
181 row.add(cp.getComponent());
182 line += cp.getText();
183 if (cp.getText().endsWith(" ")) row.add(new HSpace());
184 } else {
185 wrappedText.add(row);
186 row = new Row();
187 row.add(cp.getComponent());
188 line = cp.getText();
189 if (cp.getText().endsWith(" ")) row.add(new HSpace());
190 }
191 }
192 if (line.length() > 0) {
193 wrappedText.add(row);
194 }
195 return wrappedText;
196 }
197
198
199 private class CommentPart extends Component {
200
201 private static final long serialVersionUID = 8522664422692717971L;
202
203 private Component comp;
204 private String text;
205
206 public CommentPart(String s) {
207 if (s.startsWith("http://") || s.startsWith("https://") || s.startsWith("ftp://")) {
208 comp = new WebLink(s);
209 text = s;
210 } else if (s.startsWith("[[") && s.endsWith("]]")) {
211 String name = s.substring(2, s.length()-2);
212 Wiki wiki = hostPage.getWiki();
213 TextElement te = wiki.getLanguageHandler().getTextOperator().createTextElement(name);
214 if (te instanceof OntologyTextElement) {
215 OntologyTextElement ote = (OntologyTextElement) te;
216 OntologyElement oe = ote.getOntologyElement();
217 String t = LanguageUtils.getPrettyPrinted(oe.getWord(ote.getWordNumber()));
218 comp = new WikiLink(oe, t, wiki, false);
219 text = name;
220 }
221 }
222 if (comp == null) {
223 SolidLabel label = new SolidLabel(s, Font.ITALIC);
224 label.setForeground(new Color(120, 120, 120));
225 comp = label;
226 text = s;
227 }
228 }
229
230 public Component getComponent() {
231 return comp;
232 }
233
234 public String getText() {
235 return text;
236 }
237
238 }
239
240 }