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 }