001/* ---------------------------------------------------------------------------- 002 The Kiwi Toolkit - A Java Class Library 003 Copyright (C) 1998-2004 Mark A. Lindner 004 005 This library is free software; you can redistribute it and/or 006 modify it under the terms of the GNU 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 library 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 GNU 013 General Public License for more details. 014 015 You should have received a copy of the GNU General Public License 016 along with this library; if not, write to the Free Software 017 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 018 02111-1307, USA. 019 020 The author may be contacted at: mark_a_lindner@yahoo.com 021 ---------------------------------------------------------------------------- 022 $Log: WorkspaceEditor.java,v $ 023 Revision 1.9 2004/05/12 19:16:38 markl 024 comment block updates 025 026 Revision 1.8 2004/03/16 06:43:39 markl 027 LocaleManager method change 028 029 Revision 1.7 2003/01/19 09:50:54 markl 030 Javadoc & comment header updates. 031 032 Revision 1.6 2001/03/20 00:54:53 markl 033 Fixed deprecated calls. 034 035 Revision 1.5 2001/03/12 09:56:55 markl 036 KLabel/KLabelArea changes. 037 038 Revision 1.4 2001/03/12 09:28:02 markl 039 Source code and Javadoc cleanup. 040 041 Revision 1.3 2000/03/24 10:17:54 markl 042 Internationalization changes. 043 044 Revision 1.2 1999/01/10 02:57:18 markl 045 minor fixes 046 ---------------------------------------------------------------------------- 047*/ 048 049package kiwi.ui; 050 051import java.awt.*; 052import java.awt.event.*; 053import java.beans.*; 054import javax.swing.*; 055import javax.swing.text.*; 056import javax.swing.border.*; 057 058import kiwi.util.*; 059 060/** An abstract class that defines common behavior for all workspace editors. 061 * This class should be extended to provide the appropriate user interface and 062 * behavior for editing a specific type of problem domain object. Editors 063 * are managed by a <code>WorkspaceManager</code>, which provides some 064 * rudimentary inter-editor coordination, persistence support, and other 065 * useful facilities. 066 * 067 * @see kiwi.ui.WorkspaceManager 068 * 069 * @author Mark Lindner 070 */ 071 072public abstract class WorkspaceEditor extends JInternalFrame 073 implements ActionListener 074 { 075 /** The problem domain object associated with this editor. */ 076 protected Object object = null; 077 078 private KButton b_save, b_cancel; 079 private boolean changesMade = false; 080 private _KeyListener keyAdapter; 081 private _MouseListener mouseAdapter; 082 private _FocusListener focusAdapter; 083 private _ButtonListener actionListener; 084 private Component firstComponent = null; 085 private boolean editable; 086 private JTextComponent curFocus = null; 087 private WorkspaceManager manager = null; 088 private KLabel l_comment; 089 private KPanel pane; 090 091 /** Construct a new <code>WorkspaceEditor</code> with a default window title. 092 * It is created as editable. 093 */ 094 095 public WorkspaceEditor() 096 { 097 this(""); 098 } 099 100 /** Construct a new editable <code>WorkspaceEditor</code> with the given 101 * window title. 102 * 103 * @param title The title for the editor's window. 104 */ 105 106 public WorkspaceEditor(String title) 107 { 108 this(title, true); 109 } 110 111 /** Construct a new <code>WorkspaceEditor</code> with the given window 112 * title and editable mode. 113 * 114 * @param title The title for the editor's window. 115 * @param editable A flag specifying whether the editor will be editable. 116 */ 117 118 public WorkspaceEditor(String title, boolean editable) 119 { 120 super(title, true, true, true, true); 121 122 this.object = object; 123 this.editable = editable; 124 125 keyAdapter = new _KeyListener(); 126 mouseAdapter = new _MouseListener(); 127 actionListener = new _ButtonListener(); 128 focusAdapter = new _FocusListener(); 129 130 LocaleData loc = LocaleManager.getDefault().getLocaleData("KiwiDialogs"); 131 132 setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); 133 134 Container main = getContentPane(); 135 136 pane = new KPanel(UIChangeManager.getInstance() 137 .getDefaultTexture()); 138 pane.setBorder(KiwiUtils.defaultBorder); 139 pane.setLayout(new BorderLayout(0, 0)); 140 141 main.setLayout(new GridLayout(1, 0)); 142 main.add(pane); 143 144 l_comment = new KLabel(); 145 l_comment.setBorder(KiwiUtils.defaultBorder); 146 147 pane.add("Center", buildEditingUI()); 148 149 ButtonPanel buttons = new ButtonPanel(); 150 151 if(isEditable()) 152 { 153 b_save = new KButton(loc.getMessage("kiwi.button.save")); 154 b_save.addActionListener(actionListener); 155 b_save.setEnabled(false); 156 buttons.addButton(b_save); 157 158 b_cancel = new KButton(loc.getMessage("kiwi.button.cancel")); 159 } 160 else 161 { 162 b_cancel = new KButton(loc.getMessage("kiwi.button.close")); 163 } 164 165 b_cancel.addActionListener(actionListener); 166 buttons.addButton(b_cancel); 167 168 pane.add("South", buttons); 169 170 JMenuBar mb = buildMenuBar(); 171 if(mb != null) 172 setJMenuBar(mb); 173 } 174 175 /* Set the workspace manager for this editor. */ 176 177 final void setWorkspaceManager(WorkspaceManager manager) 178 { 179 this.manager = manager; 180 } 181 182 /** Get the <code>WorkspaceManager</code> for this editor. The method will 183 * return <code>null</code> if the editor has not yet been added to a 184 * workspace (that is, a <code>JDesktopPane</code>). 185 */ 186 187 protected final WorkspaceManager getWorkspaceManager() 188 { 189 return(manager); 190 } 191 192 /** Build the editing UI. Subclasses must implement this method to build the 193 * user interface for the editor. 194 */ 195 196 abstract protected Component buildEditingUI(); 197 198 /** Update the editing UI. Subclasses must implement this method to update 199 * the state of the user interface when a new problem domain object is 200 * associated with this editor. 201 */ 202 203 abstract protected void updateEditingUI(); 204 205 /** Set the comment that appears in the top portion of the editor. */ 206 207 protected void setComment(String comment) 208 { 209 if(comment != null) 210 { 211 l_comment.setText(comment); 212 pane.add("North", l_comment); 213 } 214 else 215 { 216 if(l_comment.getText() != null) 217 pane.remove(l_comment); 218 l_comment.setText(null); 219 } 220 } 221 222 /** Construct the menu bar for this editor. The default implementation 223 * returns <code>null</code>, which signifies that no menubar is needed. 224 */ 225 226 protected JMenuBar buildMenuBar() 227 { 228 return(null); 229 } 230 231 /** Give keyboard focus to the first text input component in this editor. 232 * These components are registered via 233 * <code>registerTextInputComponent()</code>. 234 */ 235 236 public final void beginFocus() 237 { 238 if((firstComponent != null) && isEditable()) 239 firstComponent.requestFocus(); 240 } 241 242 /** Handle events. The default implementation of this method does nothing; 243 * subclassers may override it to handle specific user interface events. 244 */ 245 246 public void actionPerformed(ActionEvent evt) 247 { 248 } 249 250 /** Get the current problem domain object associated with this editor, or 251 * <code>null</code> if there is no object associated with the editor. 252 * 253 * @return The object currently associated with this editor. 254 * @see #setObject 255 */ 256 257 public final Object getObject() 258 { 259 return(object); 260 } 261 262 /** Set the problem domain object to be associated with this editor. This 263 * method ultimately results in a call to <code>updateEditingUI()</code>. 264 * 265 * @param object The new object to be associated with this editor. 266 * @see #getObject 267 */ 268 269 public final void setObject(Object object) 270 { 271 this.object = object; 272 updateEditingUI(); 273 } 274 275 /** Determine if this editor is displaying unsaved changes. 276 * 277 * @return <code>true</code> if there are unsaved changes, and 278 * <cod>false</code> otherwise. 279 * @see #setChangesMade 280 */ 281 282 public final boolean hasUnsavedChanges() 283 { 284 return(changesMade); 285 } 286 287 /** Set the <i>changes made</i> flag on this editor. The editor checks this 288 * flag at close time to determine if changes need to be saved. 289 * 290 * @param flag The new value for the flag. 291 * @see #hasUnsavedChanges 292 */ 293 294 protected final void setChangesMade(boolean flag) 295 { 296 if(isEditable()) 297 { 298 changesMade = flag; 299 b_save.setEnabled(flag); 300 } 301 } 302 303 /** Persist the edits made in this editor. 304 * 305 * @return <code>true</code> if the save was successful and 306 * <code>false</code> otherwise. 307 */ 308 309 public abstract boolean save(); 310 311 /** Determine if the editor is editable. 312 * 313 * @return <code>true</code> if the editor is editable, and 314 * <code>false</code> otherwise. 315 */ 316 317 public final boolean isEditable() 318 { 319 return(editable); 320 } 321 322 /** Register a text input component. This method is used by subclassers to 323 * notify the editor of input fields in the user interface. The editor uses 324 * this information when requesting focus, and also listens for keypress 325 * events on all of these components, setting the <i>changes made</i> flag 326 * to <code>true</code> when one occurs. 327 * 328 * @param c The component to register. 329 * @see #registerMouseInputComponent 330 */ 331 332 protected final void registerTextInputComponent(JTextComponent c) 333 { 334 if(firstComponent == null) firstComponent = c; 335 336 c.addKeyListener(keyAdapter); 337 c.addFocusListener(focusAdapter); 338 } 339 340 /** Register a mouse input component. This method is used by subclassers to 341 * notify the editor of components that change the state of the data being 342 * edited when they are clicked. The editor listens for mouse events on all 343 * of these components, setting the <i>changes</i> made flag to 344 * <code>true</code> when one occurs. 345 * 346 * @param c The component to register. 347 * @see #registerTextInputComponent 348 */ 349 350 protected final void registerMouseInputComponent(Component c) 351 { 352 c.addMouseListener(mouseAdapter); 353 } 354 355 356 /** Start editing in this editor. This method is called whenever the editor 357 * is activated in the workspace. The default implementation does nothing. 358 * 359 * @see #stopEditing 360 */ 361 362 protected void startEditing() 363 { 364 } 365 366 /** Start editing in this editor. This method is called whenever the editor 367 * is deactivated in the workspace. The default implementation does nothing. 368 * 369 * @see #startEditing 370 */ 371 372 protected void stopEditing() 373 { 374 } 375 376 /* key listener */ 377 378 private class _KeyListener extends KeyAdapter 379 { 380 public void keyTyped(KeyEvent evt) 381 { 382 setChangesMade(true); 383 } 384 } 385 386 /* focus listener */ 387 388 private class _FocusListener extends FocusAdapter 389 { 390 public void focusGained(FocusEvent evt) 391 { 392 Component c = (Component)evt.getSource(); 393 if(c instanceof JTextComponent) 394 curFocus = (JTextComponent)c; 395 } 396 397 public void focusLost(FocusEvent evt) 398 { 399 Component c = (Component)evt.getSource(); 400 if(c == curFocus) 401 curFocus = null; 402 } 403 } 404 405 /* mouse listener */ 406 407 private class _MouseListener extends MouseAdapter 408 { 409 public void mouseClicked(MouseEvent evt) 410 { 411 setChangesMade(true); 412 } 413 414 public void mouseReleased(MouseEvent evt) 415 { 416 setChangesMade(true); 417 } 418 } 419 420 /* button listener */ 421 422 private class _ButtonListener implements ActionListener 423 { 424 public void actionPerformed(ActionEvent evt) 425 { 426 Object o = evt.getSource(); 427 428 if(o == b_save) 429 { 430 boolean ok = save(); 431 if(ok) 432 _hide(); 433 } 434 else if(o == b_cancel) 435 { 436 setChangesMade(false); 437 _hide(); 438 } 439 } 440 } 441 442 /** Invoke a <i>copy</i> action on this editor. The text in the text input 443 * component that currently has focus (if any) is copied to the system 444 * clipboard. 445 */ 446 447 public final void copy() 448 { 449 if(curFocus != null) 450 curFocus.copy(); 451 } 452 453 /** Invoke a <i>cut</i> action on this editor. The text in the text input 454 * component that currently has focus (if any) is moved to the system 455 * clipboard. 456 */ 457 458 public final void cut() 459 { 460 if(curFocus != null) 461 curFocus.cut(); 462 } 463 464 /** Invoke a <i>paste</i> action on this editor. The text in the system 465 * clipboard is copied to the text input component that currently has focus 466 * (if any). 467 */ 468 469 public final void paste() 470 { 471 if(curFocus != null) 472 curFocus.paste(); 473 } 474 475 /** Fire an <i>editor state changed</i> event. Notifies listeners that the 476 * internal state of this editor has changed in some way. 477 */ 478 479 protected final void fireStateChanged() 480 { 481 if(manager != null) 482 manager.fireEditorStateChanged(this); 483 } 484 485 /* hide the editor */ 486 487 private void _hide() 488 { 489 try 490 { 491 setClosed(true); 492 } 493 catch(PropertyVetoException ex) 494 { 495 } 496 } 497 498 } 499 500/* end of source file */