001/* 002 * Copyright (c) 2006-2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: crawl $' 006 * '$Date: 2015-01-26 21:41:18 +0000 (Mon, 26 Jan 2015) $' 007 * '$Revision: 33211 $' 008 * 009 * Permission is hereby granted, without written agreement and without 010 * license or royalty fees, to use, copy, modify, and distribute this 011 * software and its documentation for any purpose, provided that the above 012 * copyright notice and the following two paragraphs appear in all copies 013 * of this software. 014 * 015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 019 * SUCH DAMAGE. 020 * 021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 026 * ENHANCEMENTS, OR MODIFICATIONS. 027 * 028 */ 029 030package org.kepler.gui; 031 032import java.awt.Color; 033import java.awt.Component; 034import java.awt.Dimension; 035import java.awt.Font; 036import java.awt.Frame; 037import java.io.File; 038import java.net.URL; 039import java.util.Enumeration; 040import java.util.Hashtable; 041import java.util.Iterator; 042import java.util.LinkedList; 043import java.util.List; 044 045import javax.swing.BorderFactory; 046import javax.swing.Box; 047import javax.swing.BoxLayout; 048import javax.swing.JComponent; 049import javax.swing.JLabel; 050import javax.swing.JOptionPane; 051import javax.swing.JPanel; 052import javax.swing.JScrollPane; 053import javax.swing.JTextArea; 054import javax.swing.JTextField; 055import javax.swing.text.Caret; 056import javax.swing.text.JTextComponent; 057 058import org.kepler.kar.SuperClassPathFinderDoclet; 059 060import ptolemy.actor.IOPort; 061import ptolemy.actor.gui.Effigy; 062import ptolemy.gui.ComponentDialog; 063import ptolemy.kernel.Entity; 064import ptolemy.kernel.util.Attribute; 065import ptolemy.kernel.util.ConfigurableAttribute; 066import ptolemy.kernel.util.NamedObj; 067import ptolemy.moml.MoMLChangeRequest; 068import ptolemy.util.ExecuteCommands; 069import ptolemy.util.StringUtilities; 070import ptolemy.vergil.actor.DocApplicationSpecializer; 071import ptolemy.vergil.basic.KeplerDocumentationAttribute; 072 073////////////////////////////////////////////////////////////////////////// 074//// KeplerDocApplicationSpecializer 075 076/** 077 * Kepler specific specialization of the Ptolemy II Documentation system. 078 * 079 * @author Christopher Brooks 080 * @version $Id: KeplerDocApplicationSpecializer.java 14354 2008-03-04 21:07:33Z 081 * berkley $ 082 * @since Ptolemy II 6.0 083 * @Pt.ProposedRating Red (cxh) 084 * @Pt.AcceptedRating Red (cxh) 085 */ 086public class KeplerDocApplicationSpecializer implements 087 DocApplicationSpecializer { 088 089 // the standard width of the components in the edit dialog 090 private int standardX = 500; 091 // a hash of the editable components in the edit dialog 092 private Hashtable<String, JTextComponent> editableComponents; 093 094 // ///////////////////////////////////////////////////////////////// 095 // // public methods //// 096 097 /** 098 * Given a dot separated class name, return the URL of the PtDoc .xml file 099 * documentation or the Actor Index. All other document types (Javadoc, 100 * source documentation) are currently not not searched for. Thus the either 101 * the lookForPtDoc or lookForActorIndex parameter must be true, otherwise 102 * this method will return null. 103 * 104 * <p> 105 * If the KEPLER_DOCS property is set, then its value is assumed to point to 106 * the Kepler documentation. If KEPLER_DOCS is not set, then the file 107 * ./doc/docsInfo.txt is read, and if that file contains the string of the 108 * format <code>KeplerDocs: <i>path to kepler-docs</i></code> then the value 109 * of <code><i>path to kepler-docs</i></code> is used. For example, 110 * docsInfo.txt might contain <code>KeplerDocs: c:\src\kepler-docs</code>, 111 * which means that the documentation is to be found in 112 * <code>c:\src\kepler-docs</code>. docsInfo.txt is created by running 113 * <code>cd $KEPLER; ant generateDoc</code>. The documentation for 114 * <code><i>className</i></code> is assumed to be in 115 * <code>$KEPLER_DOCS/dev/documentationFramework/generatedJavadocs/<i>className</i>.doc.xml</code>. 116 * 117 * @param remoteDocumentationURLBase 118 * If non-null, the URL of the documentation. Usually, this is 119 * set by reading the _remoteDocumentationBase parameter from the 120 * configuration in the caller. 121 * @param className 122 * The dot separated class name. 123 * @param lookForPtDoc 124 * True if we should look for ptdoc .xml files. 125 * @param lookForJavadoc 126 * Ignored 127 * @param lookForSource 128 * Ignored 129 * @param lookForActorIndex 130 * True if we should search for the actor index *Idx.htm file. 131 * @return The URL of the documentation, if any. If no documentation was 132 * found, return null. 133 */ 134 @Override 135 public URL docClassNameToURL(String remoteDocumentationURLBase, 136 String className, boolean lookForPtDoc, boolean lookForJavadoc, 137 boolean lookForSource, boolean lookForActorIndex) { 138 if (!lookForPtDoc && !lookForActorIndex) { 139 return null; 140 } 141 URL toRead = null; 142 try { 143 String actorName = className 144 .substring(className.lastIndexOf('.') + 1); 145 146 /** $KEPLER_DOCS no longer set in Kepler 2.0 147 148 // Javadocs located under a elsewhere in Kepler 149 150 // Use StringUtilities.getProperty() so that we properly 151 // handle getting properties under applets or webstart. 152 String keplerDocsHome = StringUtilities.getProperty("KEPLER_DOCS"); 153 154 if (keplerDocsHome.equals("") 155 || keplerDocsHome.equals("${env.KEPLER_DOCS}")) { 156 // Read ./doc/docsInfo.txt 157 BufferedReader inDocsInfo = new BufferedReader(new FileReader( 158 "./doc/docsInfo.txt")); 159 String info = inDocsInfo.readLine(); 160 161 if (info != null) { 162 String docsInfo = info.substring(info.indexOf(":") + 1); 163 docsInfo = docsInfo.replace('\\', '/'); 164 docsInfo = docsInfo.trim(); 165 keplerDocsHome = docsInfo; 166 } 167 } 168 if (keplerDocsHome.equals("") 169 || keplerDocsHome.equals("${env.KEPLER_DOCS}")) { 170 // If $KEPLER_DOCS is not set, look for 171 // $KEPLER/dev/documentationFramework. 172 173 // Use StringUtilities.getProperty() so that we properly 174 // handle getting properties under applets or webstart. 175 String keplerHome = StringUtilities.getProperty("KEPLER"); 176 File file = new File(keplerHome + "/dev/documentationFramework"); 177 if (file.isDirectory()) { 178 keplerDocsHome = keplerHome; 179 } 180 } 181 182 InputStream toReadStream = null; 183 if (!keplerDocsHome.equals("") 184 && !keplerDocsHome.equals("${env.KEPLER_DOCS}")) { 185 186 keplerDocsHome = keplerDocsHome.replace('\\', '/'); 187 188 File file = null; 189 if (lookForActorIndex) { 190 file = new File(keplerDocsHome 191 + "/dev/documentationFramework/generatedJavadocs/" 192 + className.replace('.', '/') + "Idx.htm"); 193 } else { 194 file = new File(keplerDocsHome 195 + "/dev/documentationFramework/generatedJavadocs/" 196 + actorName + ".doc.xml"); 197 198 } 199 toRead = file.toURL(); 200 // Verify that we can read the URL. 201 try { 202 toReadStream = toRead.openStream(); 203 } catch (IOException ex) { 204 toRead = null; 205 } finally { 206 if (toReadStream != null) { 207 try { 208 toReadStream.close(); 209 } catch (IOException ex2) { 210 // Ignore. 211 } 212 } 213 } 214 } 215 if (toRead == null && remoteDocumentationURLBase != null) { 216 try { 217 if (lookForActorIndex) { 218 toRead = new URL(remoteDocumentationURLBase 219 + className.replace('.', '/') + "Idx.htm"); 220 } else { 221 toRead = new URL(remoteDocumentationURLBase + actorName 222 + ".doc.xml"); 223 } 224 toReadStream = toRead.openStream(); 225 } catch (Exception ex) { 226 toRead = null; 227 } finally { 228 if (toReadStream != null) { 229 try { 230 toReadStream.close(); 231 } catch (IOException ex2) { 232 // Ignore. 233 } 234 } 235 } 236 } 237 */ 238 239 if(lookForSource) { 240 String path = SuperClassPathFinderDoclet.getFileNameForClassName(className); 241 File file = new File(path); 242 if(file.isFile()) { 243 toRead = file.toURI().toURL(); 244 } 245 } 246 247 } catch (Throwable throwable) { 248 // Ignore and return null. 249 return null; 250 } 251 252 253 return toRead; 254 } 255 256 /** 257 * Set up the commands necessary to build the documentation. For Kepler, we 258 * run "ant generateDoc" in $KEPLER> 259 * 260 * @param executeCommands 261 * The command execution environment necessary to build the 262 * documentation. 263 * @return A List of Strings, where each String represents the a command to 264 * be executed. 265 */ 266 @Override 267 public List buildCommands(ExecuteCommands executeCommands) { 268 List<String> commands = new LinkedList<String>(); 269 270 String osName = StringUtilities.getProperty("os.name"); 271 if (osName != null && osName.startsWith("Windows")) { 272 commands.add("ant.bat generateDoc"); 273 } else { 274 commands.add("ant generateDoc"); 275 } 276 executeCommands.setCommands(commands); 277 278 File kepler = new File(StringUtilities.getProperty("KEPLER")); 279 executeCommands.setWorkingDirectory(kepler); 280 return commands; 281 } 282 283 /** 284 * returns the name of the documentation attribute 285 */ 286 @Override 287 public String getDocumentationAttributeClassName() { 288 return "ptolemy.vergil.basic.KeplerDocumentationAttribute"; 289 } 290 291 /** 292 * create a gui to edit the documentation in the attribute 293 * 294 * @param owner 295 * the editors gui parent 296 * @param attribute 297 * the documentation attribute to edit 298 * @param target 299 * the parent component to the attribute 300 */ 301 @Override 302 public void editDocumentation(Frame owner, Attribute attribute, 303 NamedObj target) { 304 String actorName = target.getName(); 305 String title = "Editing Documentation for " + actorName; 306 JPanel panel = createEditingPanel(attribute, target, owner 307 .getBackground()); 308 JScrollPane scrollPane = new JScrollPane(panel); 309 scrollPane.setViewportBorder(BorderFactory.createEmptyBorder()); 310 ComponentDialog editor = new ComponentDialog(owner, title, scrollPane); 311 String buttonpressed = editor.buttonPressed(); 312 // System.out.println("the " + buttonpressed + " button was pressed."); 313 if (buttonpressed.equals("OK")) { 314 // save the documentation. if cancel was clicked, do nothing 315 saveDocumentation((KeplerDocumentationAttribute) attribute, panel); 316 } 317 } 318 319 /** 320 * handle the case where the component does not have a KeplerDocumentation 321 * attribute 322 * 323 * @param target 324 * the component 325 */ 326 @Override 327 public void handleDocumentationAttributeDoesNotExist(Frame owner, 328 NamedObj target) { 329 try { 330 KeplerDocumentationAttribute kda = new KeplerDocumentationAttribute( 331 target, "KeplerDocumentation"); 332 kda.createEmptyFields(target); 333 editDocumentation(owner, kda, target); 334 } catch (Exception e) { 335 System.out.println("Error adding documentation attribute"); 336 } 337 } 338 339 /** 340 * handle the case where the user tried to edit documentation and the 341 * attribute does not exist. 342 */ 343 @Override 344 public void handleDocumentationNotFound(String classname, Effigy effigy) { 345 String msg = "Sorry, but there is no documentation associated with this " 346 + "component.\n" 347 + "If you built Kepler from sources, please run " 348 + "'ant javadoc' and restart Kepler.\n" 349 + "To add custom " 350 + "documentation, please right click on the actor and " 351 + "choose 'Documentation/Customize'."; 352 353 try { 354 JOptionPane.showMessageDialog(effigy.getTableauFactory() 355 .createTableau(effigy).getFrame(), msg, "alert", 356 JOptionPane.ERROR_MESSAGE); 357 } catch (Exception e) { 358 } 359 } 360 361 /** 362 * save the user entered documentation in the panel to the attribute 363 */ 364 private void saveDocumentation(KeplerDocumentationAttribute att, 365 JPanel panel) { 366 Enumeration<String> keys = editableComponents.keys(); 367 while (keys.hasMoreElements()) { 368 String name = (String) keys.nextElement(); 369 JTextComponent comp = (JTextComponent) editableComponents.get(name); 370 String value = comp.getText(); 371 ConfigurableAttribute a = (ConfigurableAttribute) att 372 .getAttribute(name); 373 if (a == null) { 374 try { 375 a = new ConfigurableAttribute(att, name); 376 a.setExpression(value); 377 } catch (Exception e) { 378 System.out.println("error saving documentation: " 379 + e.getMessage()); 380 } 381 } else { 382 String oldval = a.getExpression(); 383 if (!value.equals(oldval)) { 384 try { 385 a.setExpression(value); 386 } catch (Exception e) { 387 JOptionPane.showMessageDialog(null, 388 "Error saving attribute " + name + " : " 389 + e.getMessage(), "Error", 390 JOptionPane.ERROR_MESSAGE); 391 } 392 } 393 } 394 } 395 396 // Make sure the revision gets rolled on the lsid by issuing a change 397 // request on one of the fields, chose here to change "author", could be 398 // any of them 399 JTextComponent component = (JTextComponent) editableComponents 400 .get("author"); 401 String value = component.getText(); 402 String caStr = "ptolemy.kernel.util.ConfigurableAttribute"; 403 404 String updateMoml = "<property name=\"author\" " + "class=\"" + caStr 405 + "\" value=\"" + value + "\"/>"; 406 MoMLChangeRequest updateRequest = new MoMLChangeRequest(this, att 407 .getContainer(), updateMoml); 408 att.requestChange(updateRequest); 409 } 410 411 /** 412 * create the panel that does the editing 413 */ 414 private JPanel createEditingPanel(Attribute attribute, NamedObj target, 415 Color background) { 416 editableComponents = new Hashtable<String, JTextComponent>(); 417 // System.out.println("attribute: " + attribute.exportMoML()); 418 KeplerDocumentationAttribute att = (KeplerDocumentationAttribute) attribute; 419 att.createInstanceFromExisting(att); 420 JPanel outerPanel = new JPanel(); 421 // outerPanel.setBackground(background); 422 BoxLayout outerBox = new BoxLayout(outerPanel, BoxLayout.Y_AXIS); 423 outerPanel.setLayout(outerBox); 424 425 // header - name of component 426 JLabel componentNameLabel = new JLabel(target.getName()); 427 componentNameLabel.setFont(new Font("Times", Font.BOLD, 20)); 428 componentNameLabel.setOpaque(false); 429 JPanel componentNamePanel = new JPanel(); 430 componentNamePanel.add(componentNameLabel); 431 componentNamePanel.setMaximumSize(new Dimension(standardX, 50)); 432 componentNamePanel.setOpaque(false); 433 outerPanel.add(componentNamePanel); 434 outerPanel.add(Box.createVerticalStrut(10)); 435 436 // author and version 437 JTextField authorTextField = new JTextField(att.getAuthor()); 438 editableComponents.put("author", authorTextField); 439 authorTextField.setColumns(50); 440 JLabel authorLabel = new JLabel("Author(s):"); 441 JPanel authorPanel = createEditBox(authorLabel, authorTextField); 442 JTextField versionTextField = new JTextField(att.getVersion()); 443 editableComponents.put("version", versionTextField); 444 versionTextField.setColumns(10); 445 JLabel versionLabel = new JLabel("Version:"); 446 JPanel versionPanel = createEditBox(versionLabel, versionTextField); 447 448 JPanel authorVersionPanel = new JPanel(); 449 BoxLayout authorVersionBox = new BoxLayout(authorVersionPanel, 450 BoxLayout.X_AXIS); 451 authorVersionPanel.setLayout(authorVersionBox); 452 authorVersionPanel.add(authorPanel); 453 authorVersionPanel.add(Box.createHorizontalStrut(10)); 454 authorVersionPanel.add(versionPanel); 455 authorVersionPanel.setOpaque(false); 456 authorVersionPanel.setMaximumSize(new Dimension(standardX, 40)); 457 458 outerPanel.add(authorVersionPanel); 459 outerPanel.add(Box.createVerticalStrut(10)); 460 461 // description 462 JTextArea descriptionTextArea = new JTextArea(att.getDescription()); 463 editableComponents.put("description", descriptionTextArea); 464 descriptionTextArea.setLineWrap(true); 465 JScrollPane descriptionScrollPane = new JScrollPane(descriptionTextArea); 466 descriptionTextArea.setColumns(50); 467 descriptionTextArea.setRows(5); 468 JLabel descriptionLabel = new JLabel("Description:"); 469 JPanel descriptionPanel = createEditBox(descriptionLabel, 470 descriptionScrollPane); 471 descriptionPanel.setMaximumSize(new Dimension(standardX, 100)); 472 outerPanel.add(descriptionPanel); 473 outerPanel.add(Box.createVerticalStrut(10)); 474 475 // userLevelDescription 476 JTextArea uldTextArea = new JTextArea(att.getUserLevelDocumentation()); 477 editableComponents.put("userLevelDocumentation", uldTextArea); 478 uldTextArea.setLineWrap(true); 479 JScrollPane uldScrollPane = new JScrollPane(uldTextArea); 480 uldTextArea.setColumns(50); 481 uldTextArea.setRows(8); 482 JLabel uldLabel = new JLabel("Documentation:"); 483 JPanel uldPanel = createEditBox(uldLabel, uldScrollPane); 484 uldPanel.setMaximumSize(new Dimension(standardX, 100)); 485 outerPanel.add(uldPanel); 486 outerPanel.add(Box.createVerticalStrut(10)); 487 488 // TODO: compare the kepler documentation att props and ports with the 489 // actual props and ports in the component. if there are any missing, 490 // add them or remove ones from the docs that no longer exist 491 492 // check for properties that do not have a documentation entry 493 Iterator atts = target.attributeList().iterator(); 494 while (atts.hasNext()) { 495 Attribute a = (Attribute) atts.next(); 496 String aName = a.getName(); 497 Hashtable props = att.getPropertyHash(); 498 Enumeration keys = props.keys(); 499 boolean add = true; 500 while (keys.hasMoreElements()) { 501 String name = (String) keys.nextElement(); 502 if (name.equals(aName)) { 503 add = false; 504 } 505 } 506 507 if (!aName.trim().equals("") && add) { 508 if (!aName.substring(0, 1).equals("_") 509 && !aName.equals("KeplerDocumentation") 510 && !aName.equals("entityId") && !aName.equals("class") 511 && !aName.equals("derivedFrom") 512 && aName.indexOf("semanticType") == -1) { 513 try { 514 att.addProperty(aName, ""); 515 // ConfigurableAttribute ca = new 516 // ConfigurableAttribute(att, "prop:" + aName); 517 // ca.setExpression(""); 518 } catch (Exception e) { 519 JOptionPane.showMessageDialog(null, 520 "Error adding attribute " + aName + " : " 521 + e.getMessage(), "Error", 522 JOptionPane.ERROR_MESSAGE); 523 } 524 525 } 526 } 527 } 528 529 // check for ports that have been added that don't have a doc property 530 if (target instanceof Entity) { 531 Enumeration portEnum = ((Entity) target).getPorts(); 532 while (portEnum.hasMoreElements()) { 533 IOPort iop = (IOPort) portEnum.nextElement(); 534 String iopName = iop.getName(); 535 Hashtable ports = att.getPortHash(); 536 Enumeration keys = ports.keys(); 537 boolean add = true; 538 while (keys.hasMoreElements()) { 539 String name = (String) keys.nextElement(); 540 if (name.equals(iopName)) { 541 add = false; 542 } 543 } 544 545 if (add) { 546 try { 547 att.addPort(iopName, ""); 548 } catch (Exception e) { 549 JOptionPane.showMessageDialog(null, 550 "Error adding port " + iopName + " : " 551 + e.getMessage(), "Error", 552 JOptionPane.ERROR_MESSAGE); 553 } 554 } 555 } 556 557 // ports 558 JPanel portHeaderLabelPanel = new JPanel(); 559 JLabel portHeaderLabel = new JLabel("Ports"); 560 portHeaderLabel.setFont(new Font("Times", Font.BOLD, 20)); 561 portHeaderLabelPanel.add(portHeaderLabel); 562 portHeaderLabelPanel.setMaximumSize(new Dimension(standardX, 50)); 563 portHeaderLabelPanel.setOpaque(false); 564 outerPanel.add(portHeaderLabelPanel); 565 566 Hashtable portHash = att.getPortHash(); 567 JPanel portPanel = createHashPanel(portHash, "port"); 568 portPanel.setMaximumSize(new Dimension(standardX, 1000)); 569 outerPanel.add(portPanel); 570 outerPanel.add(Box.createVerticalStrut(20)); 571 } 572 573 // params 574 JPanel propHeaderLabelPanel = new JPanel(); 575 JLabel propHeaderLabel = new JLabel("Properties"); 576 propHeaderLabel.setFont(new Font("Times", Font.BOLD, 20)); 577 578 propHeaderLabelPanel.add(propHeaderLabel); 579 propHeaderLabelPanel.setMaximumSize(new Dimension(standardX, 50)); 580 propHeaderLabelPanel.setOpaque(false); 581 outerPanel.add(propHeaderLabelPanel); 582 583 Hashtable propHash = att.getPropertyHash(); 584 JPanel propPanel = createHashPanel(propHash, "prop"); 585 propPanel.setMaximumSize(new Dimension(standardX, 1000)); 586 outerPanel.add(propPanel); 587 outerPanel.add(Box.createVerticalStrut(20)); 588 589 Component[] comps = outerPanel.getComponents(); 590 int y = 0; 591 for (int i = 0; i < comps.length; i++) { 592 // set the size of the dialog based on the size of the components in 593 // it 594 y += comps[i].getMinimumSize().getHeight(); 595 } 596 597 outerPanel.setPreferredSize(new Dimension(standardX + 50, y + 100)); 598 return outerPanel; 599 } 600 601 /** 602 * create a panel of inputs based on a hashtable 603 */ 604 private JPanel createHashPanel(Hashtable hash, String type) { 605 JPanel propLabelPanel = new JPanel(); 606 BoxLayout propLabelPanelBox = new BoxLayout(propLabelPanel, 607 BoxLayout.Y_AXIS); 608 propLabelPanel.setLayout(propLabelPanelBox); 609 propLabelPanel.setMaximumSize(new Dimension(100, 1000)); 610 611 JPanel propTextBoxPanel = new JPanel(); 612 BoxLayout propTextBoxPanelBox = new BoxLayout(propTextBoxPanel, 613 BoxLayout.Y_AXIS); 614 propTextBoxPanel.setLayout(propTextBoxPanelBox); 615 propTextBoxPanel.setMaximumSize(new Dimension(400, 1000)); 616 617 JPanel propPanel = new JPanel(); 618 BoxLayout propPanelBox = new BoxLayout(propPanel, BoxLayout.Y_AXIS); 619 propPanel.setLayout(propPanelBox); 620 621 Enumeration propEnum = hash.keys(); 622 while (propEnum.hasMoreElements()) { 623 String name = (String) propEnum.nextElement(); 624 String value = (String) hash.get(name); 625 JLabel propLabel = new JLabel(name.trim() + ":"); 626 propLabel.setMaximumSize(new Dimension(150, 1000)); 627 JTextField propTextField = new JTextField(value.trim()); 628 propTextField.setMaximumSize(new Dimension(350, 1000)); 629 propTextField.setMinimumSize(new Dimension(350, 20)); 630 propTextField.setPreferredSize(new Dimension(350, 20)); 631 Caret caret = propTextField.getCaret(); 632 // move the carot in the text to the beginning instead of the end 633 caret.setDot(0); 634 propTextField.setCaret(caret); 635 editableComponents.put(type + ":" + name, propTextField); 636 JPanel editBoxPanel = createEditBox(propLabel, propTextField); 637 638 propPanel.add(editBoxPanel); 639 } 640 641 propPanel.setMaximumSize(new Dimension(standardX, 1000)); 642 643 return propPanel; 644 } 645 646 /** 647 * create an edit box with a label 648 */ 649 private JPanel createEditBox(JLabel label, JComponent textbox) { 650 JPanel panel = new JPanel(); 651 BoxLayout box = new BoxLayout(panel, BoxLayout.X_AXIS); 652 panel.setLayout(box); 653 double labelWidth = label.getMinimumSize().getWidth(); 654 double textboxWidth = textbox.getMaximumSize().getWidth(); 655 int offset = (int) (150 - labelWidth); 656 657 panel.add(label); 658 panel.add(Box.createHorizontalStrut(offset)); 659 panel.add(textbox); 660 panel.setOpaque(false); 661 662 return panel; 663 } 664 665}