001 /* 002 Copyright (C) 2001-2003 Renaud Pawlak <renaud@aopsys.com>, 003 Laurent Martelli <laurent@aopsys.com> 004 005 This program is free software; you can redistribute it and/or modify 006 it under the terms of the GNU Lesser General Public License as 007 published by the Free Software Foundation; either version 2 of the 008 License, or (at your option) any later version. 009 010 This program is distributed in the hope that it will be useful, 011 but WITHOUT ANY WARRANTY; without even the implied warranty of 012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 GNU Lesser General Public License for more details. 014 015 You should have received a copy of the GNU Lesser General Public License 016 along with this program; if not, write to the Free Software 017 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 018 019 package org.objectweb.jac.aspects.gui.swing; 020 021 import java.awt.Component; 022 import java.awt.Dialog; 023 import java.awt.Font; 024 import java.awt.Frame; 025 import java.awt.Window; 026 import java.awt.font.TextAttribute; 027 import java.io.File; 028 import java.io.FileOutputStream; 029 import java.io.IOException; 030 import java.io.OutputStreamWriter; 031 import java.io.Reader; 032 import java.util.Arrays; 033 import java.util.Collection; 034 import java.util.HashSet; 035 import java.util.Hashtable; 036 import java.util.Iterator; 037 import java.util.Map; 038 import javax.swing.JFileChooser; 039 import javax.swing.UIManager; 040 import org.apache.log4j.Logger; 041 import org.objectweb.jac.aspects.gui.CommitException; 042 import org.objectweb.jac.aspects.gui.CustomizedDisplay; 043 import org.objectweb.jac.aspects.gui.CustomizedGUI; 044 import org.objectweb.jac.aspects.gui.CustomizedView; 045 import org.objectweb.jac.aspects.gui.DialogView; 046 import org.objectweb.jac.aspects.gui.DisplayContext; 047 import org.objectweb.jac.aspects.gui.EditorContainer; 048 import org.objectweb.jac.aspects.gui.FieldEditor; 049 import org.objectweb.jac.aspects.gui.GenericFactory; 050 import org.objectweb.jac.aspects.gui.GuiAC; 051 import org.objectweb.jac.aspects.gui.View; 052 import org.objectweb.jac.aspects.gui.ViewFactory; 053 import org.objectweb.jac.core.Collaboration; 054 import org.objectweb.jac.core.NameRepository; 055 import org.objectweb.jac.core.rtti.AbstractMethodItem; 056 import org.objectweb.jac.util.ExtArrays; 057 import org.objectweb.jac.util.Strings; 058 059 public class SwingDisplay implements CustomizedDisplay { 060 static Logger logger = Logger.getLogger("display"); 061 062 /* Generic family -> Swing family */ 063 static Map fontFamilies = new Hashtable(); 064 static { 065 fontFamilies.put("serif","Serif"); 066 fontFamilies.put("sans-serif","SansSerif"); 067 fontFamilies.put("monospace","Monospaced"); 068 } 069 070 ViewFactory factory; 071 // customizedID -> customized 072 Hashtable frames = new Hashtable(); 073 074 public SwingDisplay(ViewFactory factory) { 075 this.factory = factory; 076 initFonts(); 077 } 078 079 protected void initFonts() { 080 // Fonts settings 081 Map fontAttributes = GuiAC.getFontAttributes(); 082 if (fontAttributes.size()>0) { 083 int type = 0; 084 085 String weight = (String)fontAttributes.get("weight"); 086 if (weight!=null) { 087 if (weight.compareToIgnoreCase("bold")==0) { 088 type |= Font.BOLD; 089 } else if (weight.compareToIgnoreCase("normal")==0) { 090 // nothing 091 } else { 092 logger.warn("Unknown font weight "+weight); 093 } 094 } 095 096 String style = (String)fontAttributes.get("style"); 097 if (style!=null) { 098 if (style.compareToIgnoreCase("italic")==0) { 099 type |= Font.ITALIC; 100 } else if (style.compareToIgnoreCase("normal")==0) { 101 // nothing 102 } else { 103 logger.warn("Unknown font style "+style); 104 } 105 } 106 107 String size = (String)fontAttributes.get("size"); 108 String family = (String)fontAttributes.get("family"); 109 110 Font font = new Font( 111 family!=null ? family : "SansSerif", 112 type, 113 size!=null ? Integer.parseInt(size) : 12 ); 114 115 UIManager.put("Label.font", font); 116 UIManager.put("ComboBox.font", font); 117 UIManager.put("Menu.font", font); 118 UIManager.put("MenuBar.font", font); 119 UIManager.put("Panel.font", font); 120 UIManager.put("Border.font", font); 121 UIManager.put("MenuItem.font", font); 122 UIManager.put("Button.font", font); 123 UIManager.put("RadioButton.font", font); 124 UIManager.put("RadioButtonMenuItem.font", font); 125 UIManager.put("CheckBox.font", font); 126 UIManager.put("CheckBoxMenuItem.font", font); 127 UIManager.put("TabbedPane.font", font); 128 } 129 boldifyFont("TableHeader.font"); 130 } 131 132 public static void boldifyFont(String resourceName) { 133 UIManager.put(resourceName,boldifyFont(UIManager.getFont(resourceName))); 134 } 135 136 public static Font boldifyFont(Font font) { 137 Map attributes = font.getAttributes(); 138 attributes.put(TextAttribute.WEIGHT,TextAttribute.WEIGHT_BOLD); 139 return new Font(attributes); 140 } 141 142 // Strings 143 HashSet timedoutDialogs = new HashSet(); 144 public void addTimedoutDialog(DialogView dialog) { 145 timedoutDialogs.add(dialog); 146 } 147 148 public void closeWindow(View window, boolean validate) { 149 window.close(validate); 150 if (window instanceof Window) 151 ((Window)window).dispose(); 152 } 153 154 public void fullRefresh() { 155 Iterator it = frames.entrySet().iterator(); 156 while(it.hasNext()) { 157 Map.Entry entry = (Map.Entry)it.next(); 158 View frame = (View)entry.getValue(); 159 CustomizedGUI customized = ((CustomizedView)frame).getCustomizedGUI(); 160 frame.close(true); 161 ((Window)frame).dispose(); 162 View newframe = factory.createView( 163 customized.getTitle(),"Customized", 164 new Object[] {customized}, 165 new DisplayContext(this,null)); 166 logger.debug("frame created "+newframe); 167 frames.put(entry.getKey(),newframe); 168 ((Component)newframe).setVisible(true); 169 } 170 } 171 172 public void showCustomized(String id, Object object, Map panels) { 173 } 174 175 public void showCustomized(String id, Object object) { 176 logger.debug("showCustomized("+id+","+object+")"); 177 CustomizedGUI customized = (CustomizedGUI)object; 178 Component frame = (Component)frames.get(id); 179 if (frame!=null) { 180 if (frame instanceof Window) { 181 logger.debug("showing window "+id); 182 ((Window)frame).show(); 183 ((Window)frame).toFront(); 184 } 185 } else { 186 try { 187 frame = (Component)factory.createView( 188 customized.getTitle(),"Customized", 189 new Object[] {customized}, 190 new DisplayContext(this,null)); 191 frames.put(id,frame); 192 frame.setVisible(true); 193 // do this after show because otherwise, percentage 194 // positions goes wrong. 195 ((SwingCustomized)frame).setSplitters(); 196 } catch (Exception e) { 197 e.printStackTrace(); 198 } 199 } 200 } 201 202 public CustomizedView getCustomizedView(String customizedID) { 203 return (CustomizedView)frames.get(customizedID); 204 } 205 206 public Collection getCustomizedViews() { 207 return frames.values(); 208 } 209 210 public ViewFactory getFactory() { 211 return factory; 212 } 213 214 // implements the display interface 215 216 public void show(Object object) { 217 show(object, 218 "Object",new String[] {GuiAC.DEFAULT_VIEW}); 219 } 220 221 public void show(Object object, 222 String viewType, Object[] viewParams) { 223 logger.debug("show("+Strings.hex(object)+")"); 224 if (object==null) { 225 return; 226 /* 227 } else if (object instanceof Throwable) { 228 Log.trace("exception",(Throwable)object); 229 String message = ((Throwable)object).getMessage(); 230 if ("".equals(message) || message==null) 231 showMessage(object.getClass().getName(),"Error",false,false,true); 232 else 233 showMessage(message,"Error",false,false,true); 234 */ 235 } else if (object instanceof Reader) { 236 saveStreamToFile((Reader)object); 237 } else if (object.getClass().isArray()) { 238 // create a customized gui to show the array 239 /* 240 SwingCustomizedGUI gui = new SwingCustomizedGUI(true); 241 gui.setSubPanesGeometry(2, Constants.HORIZONTAL, new boolean[] {false,true}); 242 CollectionWrapper c = new CollectionWrapper(Arrays.asList((Object[])object)); 243 gui.setObjectForPane(NameRepository.get().getName(c),0); 244 gui.addReferenceToPane("org.objectweb.jac.aspects.gui.CollectionWrapper","collection",1); 245 gui.applicationStarted(); 246 gui.setPosition(0,0,60,60); 247 gui.show(); 248 */ 249 } else { 250 String name = NameRepository.get().getName(object); 251 logger.debug("name of "+object.getClass().getName()+" is "+name); 252 addViewFor(object,viewType,viewParams); 253 } 254 } 255 256 public boolean showModal(Object object, 257 String viewType, Object[] viewParams, 258 String title, String header, 259 Object parent, 260 boolean okButton, 261 boolean cancelButton, 262 boolean closeButton) 263 { 264 logger.debug("showModal("+ 265 (object!=null?object.getClass().getName():"null")+ 266 viewType+Arrays.asList(viewParams)+ 267 ","+title+",parent="+parent+")"); 268 if (object==null) { 269 return addViewFor( 270 null,viewType,viewParams, 271 title, header, parent, 272 okButton, cancelButton, closeButton); 273 } else if (object instanceof CommitException) { 274 CommitException e = (CommitException)object; 275 showError( 276 "Commit error", 277 "Failed to set value of "+e.getField()+ 278 " on "+GuiAC.toString(e.getObject())+ 279 ": "+e.getNested().getMessage()); 280 return true; 281 } else if (object.getClass().isArray()) { 282 return addViewFor( 283 Arrays.asList((Object[])object),viewType,viewParams, 284 title, header, parent, 285 okButton, cancelButton, closeButton); 286 } else { 287 return addViewFor( 288 object,viewType,viewParams, 289 title, header, parent, 290 okButton, cancelButton, closeButton); 291 } 292 } 293 294 public boolean showModal(Object object, String title, String header, 295 Object parent, 296 boolean okButton, 297 boolean cancelButton, 298 boolean closeButton) 299 { 300 return showModal(object, 301 "Object",new String[] {GuiAC.DEFAULT_VIEW}, 302 title,header, 303 parent, 304 okButton,cancelButton,closeButton); 305 } 306 307 public void openView(Object object) { 308 logger.debug("openView("+object.getClass().getName()+")"); 309 show(object); 310 } 311 312 public boolean showInput(Object substance, AbstractMethodItem method, 313 Object[] parameters) 314 { 315 logger.debug("showInput("+method.getName()+ 316 ","+Arrays.asList(parameters)+")"); 317 DisplayContext dc = (DisplayContext)Collaboration.get() 318 .getAttribute(GuiAC.DISPLAY_CONTEXT); 319 if (dc==null) { 320 dc = new DisplayContext(this,null); 321 } 322 323 DialogView page = GenericFactory.createInputDialog(substance, 324 method,parameters,dc); 325 if (page.waitForClose()) { 326 EditorContainer inputView = (EditorContainer)page.getContentView(); 327 Iterator it = inputView.getEditors().iterator(); 328 int i=0; 329 while (it.hasNext()) { 330 if (method.getParameterTypes()[i] != DisplayContext.class) { 331 FieldEditor editor = (FieldEditor)it.next(); 332 method.setParameter(parameters,i,editor.getValue()); 333 } 334 i++; 335 } 336 return true; 337 } else { 338 return false; 339 } 340 } 341 342 String displayID; 343 344 public String getDisplayID() { 345 return displayID; 346 } 347 348 public void setDisplayID(String displayID) { 349 this.displayID = displayID; 350 } 351 352 public boolean showMessage(String message, String title, 353 boolean okButton, 354 boolean cancelButton, 355 boolean closeButton ) 356 { 357 DisplayContext context = 358 (DisplayContext)Collaboration.get().getAttribute( 359 GuiAC.DISPLAY_CONTEXT); 360 return showModal(null,title,message,context.getWindow(), 361 okButton,cancelButton,closeButton); 362 } 363 364 public void showMessage(String message, String title) { 365 showMessage(message,title,false,false,true); 366 } 367 368 public Object showRefreshMessage(String message, String title) { 369 View page; 370 try { 371 logger.debug("showMessage("+title+","+message+")"); 372 DisplayContext context = new DisplayContext(this,null); 373 View label = factory.createView(message,"Label", 374 new Object[] {},context); 375 page = factory.createView("Object view","Window", 376 new Object[] {label},context); 377 } finally { 378 refresh(); 379 } 380 return page; 381 } 382 383 public void showError(String message, String title) { 384 showMessage(title,message); 385 } 386 387 public void refresh() {} 388 389 public void applicationStarted() { 390 } 391 392 public void close() { 393 // close all customized guis 394 Iterator i = frames.values().iterator(); 395 while(i.hasNext()) { 396 View view = (View)i.next(); 397 view.close(true); 398 } 399 } 400 401 /** show a save dialog and save the stream into the selected file 402 * @param reader the stream to save 403 */ 404 public void saveStreamToFile(Reader reader) 405 { 406 JFileChooser chooser = new JFileChooser(); 407 if (JFileChooser.APPROVE_OPTION == chooser.showSaveDialog(null)) { 408 try { 409 File file = chooser.getSelectedFile(); 410 logger.debug("saving stream to "+file.getAbsolutePath()); 411 OutputStreamWriter writer = new OutputStreamWriter( 412 new FileOutputStream(file),"UTF-8"); 413 int b = reader.read(); 414 while (b != -1) { 415 writer.write(b); 416 b = reader.read(); 417 } 418 writer.close(); 419 } catch (IOException e) { 420 logger.error("saveStreamToFile() failed",e); 421 } 422 } 423 } 424 425 public boolean addViewFor(final Object substance) { 426 return addViewFor(substance, null, null, null, 427 false, false, true); 428 } 429 430 public boolean addViewFor(final Object substance, 431 String viewType, Object[] viewParams) { 432 return addViewFor(substance, 433 viewType,viewParams, 434 null,null,null, 435 false,false,true); 436 } 437 438 public boolean addViewFor(Object substance, 439 String title, String header, 440 Object parent, 441 boolean okButton, boolean cancelButton, 442 boolean closeButton) 443 { 444 return addViewFor(substance, 445 "Object",new String[] {GuiAC.DEFAULT_VIEW}, 446 title,header,parent, 447 okButton,cancelButton,closeButton); 448 } 449 /** 450 * Adds a view for a given Jac object.<p> 451 * 452 * @param substance the object to add a view for 453 * @return true if the OK button or the close button were clicked. 454 */ 455 public boolean addViewFor(Object substance, 456 String viewType, Object[] viewParams, 457 String title, String header, 458 Object parent, 459 boolean okButton, boolean cancelButton, 460 boolean closeButton) 461 { 462 logger.debug("addViewFor: parent="+parent); 463 if (title == null) { 464 if (substance!=null) { 465 Class substance_type = substance.getClass(); 466 if(substance_type==String.class) { 467 title = "Message" + " -" + 468 org.objectweb.jac.core.dist.Distd.getLocalContainerName() + "-"; 469 } else { 470 String tn = substance_type.getName(); 471 title = tn.substring( tn.lastIndexOf('.') + 1) + " " + 472 GuiAC.toString( substance ) + " -" + 473 org.objectweb.jac.core.dist.Distd.getLocalContainerName() + "-"; 474 } 475 } else { 476 if (title == null) { 477 title= "<null> -" + 478 org.objectweb.jac.core.dist.Distd.getLocalContainerName() + "-"; 479 } 480 } 481 } 482 483 ObjectViewDialog view = null; 484 try { 485 DisplayContext context = new DisplayContext(this,null); 486 View objectView = 487 substance==null ? null : factory.createView( 488 "object",viewType,ExtArrays.add(substance,viewParams),context); 489 490 if (parent==null) 491 view = new ObjectViewDialog( 492 objectView,title,header,okButton,cancelButton,closeButton,context); 493 else if (parent instanceof Dialog) 494 view = new ObjectViewDialog( 495 objectView,title,header,(Dialog)parent, 496 okButton,cancelButton,closeButton,context); 497 else if (parent instanceof Frame) 498 view = new ObjectViewDialog( 499 objectView,title,header,(Frame)parent, 500 okButton,cancelButton,closeButton,context); 501 502 context.setWindow(view); 503 return view.ok; 504 505 } catch (Exception e) { 506 e.printStackTrace(); 507 return false; 508 } 509 510 } 511 512 public boolean fillParameters(AbstractMethodItem method, Object[] parameters) { 513 return false; 514 } 515 516 public void onInvocationReturn(Object substance, AbstractMethodItem method) { 517 } 518 }