001 /* 002 Copyright (C) 2002-2003 Laurent Martelli <laurent@aopsys.com> 003 004 This program is free software; you can redistribute it and/or modify 005 it under the terms of the GNU Lesser General Public License as 006 published by the Free Software Foundation; either version 2 of the 007 License, or (at your option) any later version. 008 009 This program is distributed in the hope that it will be useful, 010 but WITHOUT ANY WARRANTY; without even the implied warranty of 011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 GNU Lesser General Public License for more details. 013 014 You should have received a copy of the GNU Lesser General Public License 015 along with this program; if not, write to the Free Software 016 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 017 018 package org.objectweb.jac.aspects.gui.web; 019 020 import java.awt.Dimension; 021 import java.io.File; 022 import java.io.IOException; 023 import java.io.PrintWriter; 024 import java.util.Arrays; 025 import java.util.Hashtable; 026 import java.util.Iterator; 027 import java.util.Map; 028 import org.apache.log4j.Logger; 029 import org.objectweb.jac.aspects.cache.MethodCache; 030 import org.objectweb.jac.aspects.gui.*; 031 import org.objectweb.jac.aspects.gui.web.html.*; 032 import org.objectweb.jac.aspects.timestamp.Timestamps; 033 import org.objectweb.jac.core.rtti.FieldItem; 034 import org.objectweb.jac.core.rtti.MethodItem; 035 import org.objectweb.jac.util.Images; 036 import org.objectweb.jac.util.ObjectArray; 037 import org.objectweb.jac.util.Strings; 038 039 public abstract class AbstractView implements View { 040 static Logger logger = Logger.getLogger("web"); 041 static Logger loggerClose = Logger.getLogger("gui.close"); 042 static Logger loggerDisplay = Logger.getLogger("display"); 043 static Logger loggerContext = Logger.getLogger("display.context"); 044 045 protected String label; 046 protected DisplayContext context; 047 protected int width; 048 protected int height; 049 ViewFactory factory; 050 051 // style used to change display (css for web) 052 String style; 053 054 Object[] parameters; 055 String type; 056 057 /** row number, for TableCellViewer */ 058 protected boolean isCellViewer = false; 059 protected int row; 060 protected int column; 061 protected View table; 062 063 public AbstractView() { 064 } 065 066 public AbstractView(ViewFactory factory, DisplayContext context) { 067 this.factory = factory; 068 this.context = context; 069 } 070 071 Border viewBorder; 072 073 /** 074 * Get the value of viewBorder. 075 * @return value of viewBorder. 076 */ 077 public Border getViewBorder() { 078 return viewBorder; 079 } 080 081 /** 082 * Set the value of viewBorder. 083 * @param v Value to assign to viewBorder. 084 */ 085 public void setViewBorder(Border v) { 086 this.viewBorder = v; 087 } 088 089 MethodItem message; 090 091 /** 092 * Get the value of message. 093 * @return value of message. 094 */ 095 public MethodItem getMessage() { 096 return message; 097 } 098 099 /** 100 * Set the value of message. 101 * @param v Value to assign to message. 102 */ 103 public void setMessage(MethodItem v) { 104 this.message = v; 105 } 106 107 protected String description; 108 109 /** 110 * Get the value of description. 111 * @return value of description. 112 */ 113 public String getDescription() { 114 return description; 115 } 116 117 /** 118 * Set the value of description. 119 * @param v Value to assign to description. 120 */ 121 public void setDescription(String v) { 122 this.description = v; 123 } 124 125 protected View parentView; 126 127 /** 128 * Get the value of parent. 129 * @return value of parent. 130 */ 131 public View getParentView() { 132 return parentView; 133 } 134 135 /** 136 * Set the value of parent. 137 * @param v Value to assign to parent. 138 */ 139 public void setParentView(View v) { 140 this.parentView = v; 141 } 142 143 public View getRootView() { 144 if (parentView==null) 145 return this; 146 return parentView.getRootView(); 147 } 148 149 public boolean isDescendantOf(View ancestor) { 150 if (this==ancestor) 151 return true; 152 else if (parentView==null) 153 return false; 154 else 155 return parentView.isDescendantOf(ancestor); 156 } 157 158 public void setContext(DisplayContext context) { 159 loggerContext.debug("setContext on "+this); 160 this.context = context; 161 } 162 163 public DisplayContext getContext() { 164 return context; 165 } 166 167 public void setFactory(ViewFactory factory) { 168 this.factory = factory; 169 } 170 171 public ViewFactory getFactory() { 172 return factory; 173 } 174 175 public void setLabel(String label) { 176 this.label = label; 177 } 178 179 public String getLabel() { 180 return label; 181 } 182 183 public void setWidth(int width) { 184 this.width = width; 185 } 186 187 public void setHeight(int height) { 188 this.height = height; 189 } 190 191 public void setType(String type) { 192 this.type = type; 193 } 194 195 public String getType() { 196 return type; 197 } 198 199 public void setStyle(String style) { 200 this.style = style; 201 } 202 203 public String getStyle() { 204 return style; 205 } 206 207 public void setParameters(Object[] parameters) { 208 this.parameters = parameters; 209 } 210 211 public Object[] getParameters() { 212 return parameters; 213 } 214 215 public void setFocus(FieldItem field, Object option) { 216 } 217 218 public void close(boolean validate) { 219 loggerClose.debug("closing "+this); 220 closed = true; 221 ((WebDisplay)context.getDisplay()).unregisterView(this); 222 } 223 224 boolean closed = false; 225 226 public boolean isClosed() { 227 return closed; 228 } 229 230 public boolean equalsView(ViewIdentity view) { 231 return 232 ( ( type!=null && 233 type.equals(view.getType()) ) 234 || (type==null && view.getType()==null ) ) 235 && ( ( parameters!=null && 236 Arrays.equals(parameters,view.getParameters()) ) 237 || (parameters==null && view.getParameters()==null) ); 238 } 239 240 public boolean equalsView(String type, Object[] parameters) { 241 return this.type.equals(type) 242 && Arrays.equals(this.parameters,parameters); 243 } 244 245 /** 246 * Are we in a <FORM> element ? 247 */ 248 protected boolean isInForm() { 249 return true; 250 } 251 252 /** 253 * Build an HTML element for an event. It takes into account if we 254 * are in a form, and if the browser is MS-IE. 255 * @param text text to display for the link 256 * @param event the name of the event 257 * @param params additional parameters for the link URL 258 * @return an HTML element */ 259 protected Composite eventURL(String text, String event, String params) { 260 JacRequest request = WebDisplay.getRequest(); 261 String parameters = "event="+event+"&source="+getId()+params; 262 if (request.isIEUserAgent()) { 263 // workaround for MSIE which does not handle <button> the way it should 264 logger.debug("user-agent: "+request.getUserAgent()); 265 Link link = new Link( 266 ((WebDisplay)context.getDisplay()).getServletName()+ 267 "?"+parameters, 268 text); 269 link.attribute("onclick","return commitForm(this,'"+parameters+"')"); 270 return link; 271 } else { 272 if (isInForm()) { 273 Button button = 274 new Button("submit","eventAndAction",parameters); 275 button.add(text); 276 return button; 277 } else { 278 return new Link( 279 ((WebDisplay)context.getDisplay()).getServletName()+ 280 "?event="+event+"&source="+getId()+params, 281 text); 282 } 283 } 284 } 285 286 /** 287 * Write HTML code for a button 288 * 289 * @param out where to write the HTML 290 * @param icon resource name of an icon 291 * @param label text of the button 292 * @param event the event linked to the button 293 */ 294 protected void showButton(PrintWriter out, String icon, String label, String event) { 295 JacRequest request = WebDisplay.getRequest(); 296 if (request.isIEUserAgent()) { 297 out.println( 298 "<table class=\"method\"><td>"+ 299 (icon!=null?iconElement(ResourceManager.getResource(icon),"").toString():"")+ 300 eventURL(label,event,"").toString()+ 301 "</td></table>"); 302 } else { 303 out.println( 304 eventURL(label,event,"") 305 .add(0,(icon!=null?iconElement(ResourceManager.getResource(icon),"").toString():"")) 306 .cssClass("method") 307 .toString()); 308 } 309 } 310 311 public String getOpenBorder() { 312 String s = ""; 313 if (viewBorder==null) 314 return s; 315 s += "<div class=\"BORDER_"+Border.i2aStyle(viewBorder.getStyle())+"\">"; 316 if (viewBorder.hasTitle()) { 317 s += "<div class=\"label\">"+viewBorder.getTitle()+"</div>"; 318 } 319 return s; 320 } 321 322 public String getCloseBorder() { 323 if (viewBorder==null) 324 return ""; 325 return "</div>"; 326 } 327 328 protected String getBaseURL() { 329 return ((WebDisplay)context.getDisplay()).getServletName(); 330 } 331 332 /** 333 * Build the base URL for an event 334 * @param event the name of the event 335 */ 336 protected String eventURL(String event) { 337 String base = getBaseURL()+ 338 "?event="+event+"&source="+getId(); 339 if (isCellViewer) 340 return base+"&tableEventSource="+getId(table)+ 341 "&row="+row+"&col="+column; 342 else 343 return base; 344 } 345 346 /** 347 * Builds an <img> tag for an icon 348 * 349 * @param icon resource path of icon 350 * @param alt alt string for <img> HTML tag 351 */ 352 protected Element iconElement(String icon, String alt) { 353 return iconElement(icon,alt,true); 354 } 355 356 static MethodCache iconCache = new MethodCache(null/*new Timestamps()*/); 357 358 /** 359 * Builds an <img> tag for an icon 360 * 361 * @param icon resource path of icon 362 * @param alt alt string for <img> HTML tag 363 * @param showAlt if true, return alt if icon is null 364 */ 365 protected Element iconElement(String icon, String alt, boolean showAlt) { 366 if (Strings.isEmpty(icon)) { 367 return new Text(showAlt?alt:""); 368 } else { 369 Dimension size = null; 370 File file = new File(icon); 371 ObjectArray args = new ObjectArray(new Object[]{file}); 372 MethodCache.Entry entry = iconCache.getEntry(args,null); 373 if (entry!=null) { 374 size = (Dimension)entry.value; 375 } else { 376 try { 377 size = Images.getImageFileSize(file); 378 logger.debug("size of "+icon+": "+size.width+"x"+size.height); 379 } catch (Exception e) { 380 logger.warn("Could not determine size of icon "+icon,e); 381 } 382 } 383 if (size==null) { 384 logger.warn("Could not determine size of icon "+icon); 385 } else { 386 iconCache.putEntry(args,size); 387 } 388 return new Image("resources/"+icon,alt,size).cssClass("icon"); 389 } 390 } 391 392 protected String getId() { 393 return ((WebDisplay)context.getDisplay()).registerView(this); 394 } 395 396 protected String getId(View view) { 397 return ((WebDisplay)context.getDisplay()).registerView(view); 398 } 399 400 // HTMLViewer interface 401 402 /* the style sheets */ 403 String styleSheet = "resources/org/objectweb/jac/aspects/gui/web/style.css"; 404 String styleSheetIE = "resources/org/objectweb/jac/aspects/gui/web/ie.css"; 405 String styleSheetKonqueror = "resources/org/objectweb/jac/aspects/gui/web/konqueror.css"; 406 407 String javascript = "resources/org/objectweb/jac/aspects/gui/web/script.js"; 408 409 public void setStyleSheet(String styleSheet) { 410 this.styleSheet = styleSheet; 411 } 412 413 /** 414 * Generate an HTML page, with full headers 415 * @see #genBody(PrintWriter) 416 */ 417 protected void genPage(PrintWriter out) throws IOException { 418 out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\">"); 419 out.println("<html>"); 420 out.println(" <head>"); 421 out.println(" <title>"+label+"</title>"); 422 out.println(" <meta name=\"Author\" content=\"JAC web-gui server\">" ); 423 out.println(" <script type=\"text/javascript\" src=\""+javascript+"\"></script>"); 424 genStyleSheets(out,context.getCustomizedView()); 425 out.println(" </head>"); 426 out.println(" <body>"); 427 genBody(out); 428 out.println(" </body>"); 429 out.println("</html>"); 430 } 431 432 protected void genStyleSheets(PrintWriter out, CustomizedView customized) { 433 out.println(" <link rel=\"stylesheet\" type=\"text/css\" "+ 434 "href=\""+styleSheet+"\" title=\"JAC\">"); 435 JacRequest request = WebDisplay.getRequest(); 436 if (request.isIEUserAgent()) { 437 out.println(" <link rel=\"stylesheet\" type=\"text/css\" "+ 438 "href=\""+styleSheetIE+"\">"); 439 } 440 if (request.userAgentMatch("Konqueror")) { 441 out.println(" <link rel=\"stylesheet\" type=\"text/css\" "+ 442 "href=\""+styleSheetKonqueror+"\">"); 443 } 444 445 out.println(" <style type=\"text/css\">"); 446 Iterator it; 447 if (customized!=null) { 448 it = customized.getCustomizedGUI().getStyleSheetURLs().iterator(); 449 while (it.hasNext()) { 450 String url = (String)it.next(); 451 out.println(" @import \""+url+"\";"); 452 } 453 } 454 it = GuiAC.getStyleSheetURLs().iterator(); 455 while (it.hasNext()) { 456 String url = (String)it.next(); 457 out.println(" @import \""+url+"\";"); 458 } 459 out.println(" </style>"); 460 } 461 462 /** 463 * Override this method to generate the body of an HTML page. 464 * @see #genPage(PrintWriter) 465 */ 466 protected void genBody(PrintWriter out) throws IOException { 467 out.println(" <p>Empty page</p>"); 468 } 469 470 // TableCellViewer interface 471 472 public void setTable(View table) { 473 this.table = table; 474 } 475 476 public void setRow(int row) { 477 this.row = row; 478 } 479 480 public void setColumn(int column) { 481 this.column = column; 482 } 483 484 Hashtable attributes = new Hashtable(); 485 public void setAttribute(String name, String value) { 486 attributes.put(name,value); 487 } 488 protected void printAttributes(PrintWriter out) { 489 Iterator it = attributes.entrySet().iterator(); 490 while (it.hasNext()) { 491 Map.Entry entry = (Map.Entry)it.next(); 492 out.write(" "+entry.getKey()+"=\""+entry.getValue()+"\""); 493 } 494 } 495 496 protected void openForm(PrintWriter out) { 497 out.println(" <form action=\""+ 498 ((WebDisplay)context.getDisplay()).getServletName()+"\" "+ 499 "method=\"post\" accept-charset=\""+GuiAC.getEncoding()+"\" "+ 500 "enctype=\"multipart/form-data\">"); 501 } 502 503 protected void closeForm(PrintWriter out) { 504 out.println(" </form>"); 505 } 506 507 protected void showFormButtons(PrintWriter out, boolean dialog) { 508 out.println(" <div class=\"actions\">"); 509 out.println(" <input type=\"hidden\" name=\"source\" value=\""+getId()+"\">"); 510 if (dialog) { 511 showButton(out,null,GuiAC.getLabelOK(),"onOK"); 512 showButton(out,null,GuiAC.getLabelCancel(),"onCancel"); 513 } else { 514 showButton(out,null,GuiAC.getLabelClose(),"onOK"); 515 } 516 if (context.hasEnabledEditor()) { 517 showButton(out,null,"Refresh","onRefresh"); 518 } 519 out.println(" </div>"); 520 } 521 522 protected void showFormButtons(PrintWriter out) { 523 showFormButtons(out,true); 524 } 525 526 protected void genEventAndActionButton(PrintWriter out, String event) { 527 showButton(out,null,"Refresh",event); 528 } 529 }