From 9129838d208c0df7293e5b757661125545cd6df8 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Wed, 4 Mar 2009 17:31:40 +0000 Subject: flib added --- libs/FLib/JCalendar/License.txt | 123 + libs/FLib/JCalendar/README.txt | 27 + libs/FLib/JCalendar/build.xml | 121 + libs/FLib/JCalendar/doc-templates/License.html | 180 + libs/FLib/JCalendar/doc/example/Example1.java | 181 + libs/FLib/JCalendar/doc/example/Example2.java | 173 + libs/FLib/JCalendar/doc/examples.html | 66 + libs/FLib/JCalendar/doc/features.html | 58 + libs/FLib/JCalendar/doc/images/Logo.png | Bin 0 -> 38186 bytes .../doc/images/screenshot-combo-meta-noedit.gif | Bin 0 -> 5036 bytes .../doc/images/screenshot-combo-metal-all.gif | Bin 0 -> 6029 bytes .../doc/images/screenshot-combo-skin1.gif | Bin 0 -> 12423 bytes .../doc/images/screenshot-combo-skin2.gif | Bin 0 -> 12928 bytes .../doc/images/screenshot-combo-skin3.gif | Bin 0 -> 7246 bytes .../doc/images/screenshot-panel-metal-all.gif | Bin 0 -> 5131 bytes .../doc/images/screenshot-panel-metal-french.gif | Bin 0 -> 4746 bytes libs/FLib/JCalendar/doc/index.html | 64 + libs/FLib/JCalendar/doc/resources.html | 81 + libs/FLib/JCalendar/doc/screenshots.html | 65 + libs/FLib/JCalendar/doc/stylesheet.css | 48 + libs/FLib/JCalendar/doc/tutorial.html | 149 + .../org/freixas/jcalendar/Bundle.properties | 45 + .../JCalendar/org/freixas/jcalendar/DateEvent.java | 86 + .../org/freixas/jcalendar/DateListener.java | 46 + .../JCalendar/org/freixas/jcalendar/JCalendar.java | 1681 +++++++ .../org/freixas/jcalendar/JCalendarCombo.java | 1448 ++++++ .../org/freixas/jcalendar/images/Back16.gif | Bin 0 -> 130 bytes .../org/freixas/jcalendar/images/Back24.gif | Bin 0 -> 164 bytes .../org/freixas/jcalendar/images/FastForward16.gif | Bin 0 -> 200 bytes .../org/freixas/jcalendar/images/FastForward24.gif | Bin 0 -> 279 bytes .../org/freixas/jcalendar/images/Forward16.gif | Bin 0 -> 186 bytes .../org/freixas/jcalendar/images/Forward24.gif | Bin 0 -> 247 bytes .../org/freixas/jcalendar/images/Rewind16.gif | Bin 0 -> 200 bytes .../org/freixas/jcalendar/images/Rewind24.gif | Bin 0 -> 279 bytes libs/FLib/JCalendar/project.dtd | 5193 ++++++++++++++++++++ libs/FLib/JWizard/License.txt | 123 + libs/FLib/JWizard/README.txt | 26 + libs/FLib/JWizard/build.xml | 112 + libs/FLib/JWizard/doc-templates/License.html | 180 + libs/FLib/JWizard/doc/example/Example1.gif | Bin 0 -> 12623 bytes libs/FLib/JWizard/doc/example/Example1.java | 701 +++ libs/FLib/JWizard/doc/examples.html | 69 + libs/FLib/JWizard/doc/features.html | 62 + libs/FLib/JWizard/doc/images/Logo.png | Bin 0 -> 36725 bytes libs/FLib/JWizard/doc/images/screenshot-metal.gif | Bin 0 -> 23563 bytes libs/FLib/JWizard/doc/images/screenshot-skin1.gif | Bin 0 -> 46845 bytes libs/FLib/JWizard/doc/images/screenshot-skin2.gif | Bin 0 -> 51570 bytes libs/FLib/JWizard/doc/images/screenshot-skin3.gif | Bin 0 -> 43363 bytes .../FLib/JWizard/doc/images/screenshot-windows.gif | Bin 0 -> 48207 bytes libs/FLib/JWizard/doc/index.html | 64 + libs/FLib/JWizard/doc/resources.html | 58 + libs/FLib/JWizard/doc/screenshots.html | 55 + libs/FLib/JWizard/doc/stylesheet.css | 48 + libs/FLib/JWizard/doc/tutorial.html | 200 + .../JWizard/org/freixas/jwizard/Bundle.properties | 31 + .../JWizard/org/freixas/jwizard/JWizardDialog.java | 1015 ++++ .../JWizard/org/freixas/jwizard/JWizardPanel.java | 429 ++ .../JWizard/org/freixas/jwizard/images/Back16.gif | Bin 0 -> 183 bytes .../org/freixas/jwizard/images/Forward16.gif | Bin 0 -> 183 bytes .../JWizard/org/freixas/jwizard/images/Help16.gif | Bin 0 -> 661 bytes libs/FLib/JWizard/project.dtd | 5193 ++++++++++++++++++++ libs/FLib/NOTES.txt | 35 + libs/FLib/TableLayout/License.txt | 123 + libs/FLib/TableLayout/README.txt | 34 + libs/FLib/TableLayout/build.xml | 120 + libs/FLib/TableLayout/doc-templates/License.html | 180 + libs/FLib/TableLayout/doc/example/Example1.java | 180 + .../TableLayout/doc/example/TableExplorer.java | 1230 +++++ libs/FLib/TableLayout/doc/examples.html | 76 + libs/FLib/TableLayout/doc/features.html | 55 + libs/FLib/TableLayout/doc/images/Logo.png | Bin 0 -> 62326 bytes libs/FLib/TableLayout/doc/images/screenshot1.png | Bin 0 -> 2523 bytes libs/FLib/TableLayout/doc/images/screenshot2.png | Bin 0 -> 3997 bytes libs/FLib/TableLayout/doc/images/tutorial1.png | Bin 0 -> 1245 bytes libs/FLib/TableLayout/doc/images/tutorial2.png | Bin 0 -> 1724 bytes libs/FLib/TableLayout/doc/images/tutorial3.png | Bin 0 -> 1797 bytes libs/FLib/TableLayout/doc/images/tutorial4.png | Bin 0 -> 1765 bytes libs/FLib/TableLayout/doc/images/tutorial5.png | Bin 0 -> 1433 bytes libs/FLib/TableLayout/doc/images/tutorial6.png | Bin 0 -> 1048 bytes libs/FLib/TableLayout/doc/images/tutorial7.png | Bin 0 -> 821 bytes libs/FLib/TableLayout/doc/images/tutorial8.png | Bin 0 -> 923 bytes libs/FLib/TableLayout/doc/index.html | 64 + libs/FLib/TableLayout/doc/resources.html | 68 + libs/FLib/TableLayout/doc/screenshots.html | 48 + libs/FLib/TableLayout/doc/stylesheet.css | 48 + libs/FLib/TableLayout/doc/tutorial.html | 338 ++ .../org/freixas/tablelayout/TableLayout.java | 2049 ++++++++ libs/FLib/TableLayout/project.dtd | 5193 ++++++++++++++++++++ libs/FLib/build.xml | 79 + libs/FLib/images/Logo.png | Bin 0 -> 30782 bytes libs/FLib/index.html | 56 + libs/FLib/project.dtd | 5193 ++++++++++++++++++++ 92 files changed, 33370 insertions(+) create mode 100644 libs/FLib/JCalendar/License.txt create mode 100644 libs/FLib/JCalendar/README.txt create mode 100644 libs/FLib/JCalendar/build.xml create mode 100644 libs/FLib/JCalendar/doc-templates/License.html create mode 100644 libs/FLib/JCalendar/doc/example/Example1.java create mode 100644 libs/FLib/JCalendar/doc/example/Example2.java create mode 100644 libs/FLib/JCalendar/doc/examples.html create mode 100644 libs/FLib/JCalendar/doc/features.html create mode 100644 libs/FLib/JCalendar/doc/images/Logo.png create mode 100644 libs/FLib/JCalendar/doc/images/screenshot-combo-meta-noedit.gif create mode 100644 libs/FLib/JCalendar/doc/images/screenshot-combo-metal-all.gif create mode 100644 libs/FLib/JCalendar/doc/images/screenshot-combo-skin1.gif create mode 100644 libs/FLib/JCalendar/doc/images/screenshot-combo-skin2.gif create mode 100644 libs/FLib/JCalendar/doc/images/screenshot-combo-skin3.gif create mode 100644 libs/FLib/JCalendar/doc/images/screenshot-panel-metal-all.gif create mode 100644 libs/FLib/JCalendar/doc/images/screenshot-panel-metal-french.gif create mode 100644 libs/FLib/JCalendar/doc/index.html create mode 100644 libs/FLib/JCalendar/doc/resources.html create mode 100644 libs/FLib/JCalendar/doc/screenshots.html create mode 100644 libs/FLib/JCalendar/doc/stylesheet.css create mode 100644 libs/FLib/JCalendar/doc/tutorial.html create mode 100644 libs/FLib/JCalendar/org/freixas/jcalendar/Bundle.properties create mode 100644 libs/FLib/JCalendar/org/freixas/jcalendar/DateEvent.java create mode 100644 libs/FLib/JCalendar/org/freixas/jcalendar/DateListener.java create mode 100644 libs/FLib/JCalendar/org/freixas/jcalendar/JCalendar.java create mode 100644 libs/FLib/JCalendar/org/freixas/jcalendar/JCalendarCombo.java create mode 100644 libs/FLib/JCalendar/org/freixas/jcalendar/images/Back16.gif create mode 100644 libs/FLib/JCalendar/org/freixas/jcalendar/images/Back24.gif create mode 100644 libs/FLib/JCalendar/org/freixas/jcalendar/images/FastForward16.gif create mode 100644 libs/FLib/JCalendar/org/freixas/jcalendar/images/FastForward24.gif create mode 100644 libs/FLib/JCalendar/org/freixas/jcalendar/images/Forward16.gif create mode 100644 libs/FLib/JCalendar/org/freixas/jcalendar/images/Forward24.gif create mode 100644 libs/FLib/JCalendar/org/freixas/jcalendar/images/Rewind16.gif create mode 100644 libs/FLib/JCalendar/org/freixas/jcalendar/images/Rewind24.gif create mode 100644 libs/FLib/JCalendar/project.dtd create mode 100644 libs/FLib/JWizard/License.txt create mode 100644 libs/FLib/JWizard/README.txt create mode 100644 libs/FLib/JWizard/build.xml create mode 100644 libs/FLib/JWizard/doc-templates/License.html create mode 100644 libs/FLib/JWizard/doc/example/Example1.gif create mode 100644 libs/FLib/JWizard/doc/example/Example1.java create mode 100644 libs/FLib/JWizard/doc/examples.html create mode 100644 libs/FLib/JWizard/doc/features.html create mode 100644 libs/FLib/JWizard/doc/images/Logo.png create mode 100644 libs/FLib/JWizard/doc/images/screenshot-metal.gif create mode 100644 libs/FLib/JWizard/doc/images/screenshot-skin1.gif create mode 100644 libs/FLib/JWizard/doc/images/screenshot-skin2.gif create mode 100644 libs/FLib/JWizard/doc/images/screenshot-skin3.gif create mode 100644 libs/FLib/JWizard/doc/images/screenshot-windows.gif create mode 100644 libs/FLib/JWizard/doc/index.html create mode 100644 libs/FLib/JWizard/doc/resources.html create mode 100644 libs/FLib/JWizard/doc/screenshots.html create mode 100644 libs/FLib/JWizard/doc/stylesheet.css create mode 100644 libs/FLib/JWizard/doc/tutorial.html create mode 100644 libs/FLib/JWizard/org/freixas/jwizard/Bundle.properties create mode 100644 libs/FLib/JWizard/org/freixas/jwizard/JWizardDialog.java create mode 100644 libs/FLib/JWizard/org/freixas/jwizard/JWizardPanel.java create mode 100644 libs/FLib/JWizard/org/freixas/jwizard/images/Back16.gif create mode 100644 libs/FLib/JWizard/org/freixas/jwizard/images/Forward16.gif create mode 100644 libs/FLib/JWizard/org/freixas/jwizard/images/Help16.gif create mode 100644 libs/FLib/JWizard/project.dtd create mode 100644 libs/FLib/NOTES.txt create mode 100644 libs/FLib/TableLayout/License.txt create mode 100644 libs/FLib/TableLayout/README.txt create mode 100644 libs/FLib/TableLayout/build.xml create mode 100644 libs/FLib/TableLayout/doc-templates/License.html create mode 100644 libs/FLib/TableLayout/doc/example/Example1.java create mode 100644 libs/FLib/TableLayout/doc/example/TableExplorer.java create mode 100644 libs/FLib/TableLayout/doc/examples.html create mode 100644 libs/FLib/TableLayout/doc/features.html create mode 100644 libs/FLib/TableLayout/doc/images/Logo.png create mode 100644 libs/FLib/TableLayout/doc/images/screenshot1.png create mode 100644 libs/FLib/TableLayout/doc/images/screenshot2.png create mode 100644 libs/FLib/TableLayout/doc/images/tutorial1.png create mode 100644 libs/FLib/TableLayout/doc/images/tutorial2.png create mode 100644 libs/FLib/TableLayout/doc/images/tutorial3.png create mode 100644 libs/FLib/TableLayout/doc/images/tutorial4.png create mode 100644 libs/FLib/TableLayout/doc/images/tutorial5.png create mode 100644 libs/FLib/TableLayout/doc/images/tutorial6.png create mode 100644 libs/FLib/TableLayout/doc/images/tutorial7.png create mode 100644 libs/FLib/TableLayout/doc/images/tutorial8.png create mode 100644 libs/FLib/TableLayout/doc/index.html create mode 100644 libs/FLib/TableLayout/doc/resources.html create mode 100644 libs/FLib/TableLayout/doc/screenshots.html create mode 100644 libs/FLib/TableLayout/doc/stylesheet.css create mode 100644 libs/FLib/TableLayout/doc/tutorial.html create mode 100644 libs/FLib/TableLayout/org/freixas/tablelayout/TableLayout.java create mode 100644 libs/FLib/TableLayout/project.dtd create mode 100644 libs/FLib/build.xml create mode 100644 libs/FLib/images/Logo.png create mode 100644 libs/FLib/index.html create mode 100644 libs/FLib/project.dtd diff --git a/libs/FLib/JCalendar/License.txt b/libs/FLib/JCalendar/License.txt new file mode 100644 index 0000000..be12e9d --- /dev/null +++ b/libs/FLib/JCalendar/License.txt @@ -0,0 +1,123 @@ + Artistic License + +Preamble + +The intent of this document is to state the conditions under which a +Package may be copied, such that the Copyright Holder maintains some +semblance of artistic control over the development of the package, +while giving the users of the package the right to use and distribute +the Package in a more-or-less customary fashion, plus the right to +make reasonable modifications. + +Definitions: + + * "Package" refers to the collection of files distributed by the + Copyright Holder, and derivatives of that collection of files + created through textual modification. + + * "Standard Version" refers to such a Package if it has not been + modified, or has been modified in accordance with the wishes of + the Copyright Holder. + + * "Copyright Holder" is whoever is named in the copyright or + copyrights for the package. + + * "You" is you, if you're thinking about copying or distributing + this Package. + + * "Reasonable copying fee" is whatever you can justify on the + basis of media cost, duplication charges, time of people + involved, and so on. (You will not be required to justify it to + the Copyright Holder, but only to the computing community at + large as a market that must bear the fee.) + + * "Freely Available" means that no fee is charged for the item + itself, though there may be fees involved in handling the item. + It also means that recipients of the item may redistribute it + under the same conditions they received it. + +1. You may make and give away verbatim copies of the source form of + the Standard Version of this Package without restriction, provided + that you duplicate all of the original copyright notices and + associated disclaimers. + +2. You may apply bug fixes, portability fixes and other modifications + derived from the Public Domain or from the Copyright Holder. A + Package modified in such a way shall still be considered the + Standard Version. + +3. You may otherwise modify your copy of this Package in any way, + provided that you insert a prominent notice in each changed file + stating how and when you changed that file, and provided that you + do at least ONE of the following: + + a) place your modifications in the Public Domain or otherwise make + them Freely Available, such as by posting said modifications to + Usenet or an equivalent medium, or placing the modifications on + a major archive site such as ftp.uu.net, or by allowing the + Copyright Holder to include your modifications in the Standard + Version of the Package. + + b) use the modified Package only within your corporation or + organization. + + c) rename any non-standard executables so the names do not + conflict with standard executables, which must also be + provided, and provide a separate manual page for each + non-standard executable that clearly documents how it differs + from the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + +4. You may distribute the programs of this Package in object code or + executable form, provided that you do at least ONE of the + following: + + a) distribute a Standard Version of the executables and library + files, together with instructions (in the manual page or + equivalent) on where to get the Standard Version. + + b) accompany the distribution with the machine-readable source of + the Package with your modifications. + + c) accompany any non-standard executables with their corresponding + Standard Version executables, giving the non-standard + executables non-standard names, and clearly documenting the + differences in manual pages (or equivalent), together with + instructions on where to get the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + +5. You may charge a reasonable copying fee for any distribution of + this Package. You may charge any fee you choose for support of this + Package. You may not charge a fee for this Package itself. However, + you may distribute this Package in aggregate with other (possibly + commercial) programs as part of a larger (possibly commercial) + software distribution provided that you do not advertise this + Package as a product of your own. + +6. The scripts and library files supplied as input to or produced as + output from the programs of this Package do not automatically fall + under the copyright of this Package, but belong to whomever + generated them, and may be sold commercially, and may be aggregated + with this Package. + +7. C or perl subroutines supplied by you and linked into this Package + shall not be considered part of this Package. + +8. Aggregation of this Package with a commercial distribution is + always permitted provided that the use of this Package is embedded; + that is, when no overt attempt is made to make this Package's + interfaces visible to the end user of the commercial distribution. + Such use shall not be construed as a distribution of this Package. + +9. The name of the Copyright Holder may not be used to endorse or + promote products derived from this software without specific prior + written permission. + +10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + PURPOSE. + +The End diff --git a/libs/FLib/JCalendar/README.txt b/libs/FLib/JCalendar/README.txt new file mode 100644 index 0000000..8c51360 --- /dev/null +++ b/libs/FLib/JCalendar/README.txt @@ -0,0 +1,27 @@ + JCalendar + +This package provides a Calendar component for use in Java programs. + +This program is free software; you can redistribute it and/or modify +it under the terms of the Artistic License. You should have received a +copy of the Artistic License along with this program (in file +License.txt). If not, a copy is available at + + http://opensource.org/licenses/artistic-license.php + +To build it you'll need Ant. I used version 1.6.2. Use + + ant all + +This will create build/jcalendar.jar. To create the API documentation, use + + ant javadoc + +To view all the documentation, view doc/index.html. + +There is a tutorial in doc/tutorial.html. There are also two sample +Java program that uses the JCalendar package. You can build and run +these programs with + + ant runExample1 + ant runExample2 diff --git a/libs/FLib/JCalendar/build.xml b/libs/FLib/JCalendar/build.xml new file mode 100644 index 0000000..1bef6f7 --- /dev/null +++ b/libs/FLib/JCalendar/build.xml @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+
+ + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/libs/FLib/JCalendar/doc-templates/License.html b/libs/FLib/JCalendar/doc-templates/License.html new file mode 100644 index 0000000..d5fbdc1 --- /dev/null +++ b/libs/FLib/JCalendar/doc-templates/License.html @@ -0,0 +1,180 @@ + + + + + + +

Artistic License

+ +

Preamble

+ +

The intent of this document is to state the conditions under which a + Package may be copied, such that the Copyright Holder maintains some + semblance of artistic control over the development of the package, + while giving the users of the package the right to use and distribute + the Package in a more-or-less customary fashion, plus the right to + make reasonable modifications.

+ +

Definitions:

+ + + +
+ +
    + +
  1. You may make and give away verbatim copies of the source form of + the Standard Version of this Package without restriction, provided + that you duplicate all of the original copyright notices and + associated disclaimers.
  2. + +
  3. You may apply bug fixes, portability fixes and other modifications + derived from the Public Domain or from the Copyright Holder. A Package + modified in such a way shall still be considered the Standard + Version.
  4. + +
  5. You may otherwise modify your copy of this Package in any way, + provided that you insert a prominent notice in each changed file + stating how and when you changed that file, and provided that you do + at least ONE of the following: + +
      + +
    1. place your modifications in the Public Domain or otherwise make + them Freely Available, such as by posting said modifications to Usenet + or an equivalent medium, or placing the modifications on a major + archive site such as ftp.uu.net, or by allowing the Copyright Holder + to include your modifications in the Standard Version of the Package.
    2. + +
    3. use the modified Package only within your corporation or + organization.
    4. + +
    5. rename any non-standard executables so the names do not conflict + with standard executables, which must also be provided, and provide a + separate manual page for each non-standard executable that clearly + documents how it differs from the Standard Version.
    6. + +
    7. make other distribution arrangements with the Copyright + Holder.
    8. + +
    +
  6. + +
  7. You may distribute the programs of this Package in object code or + executable form, provided that you do at least ONE of the following: + +
      + +
    1. distribute a Standard Version of the executables and library + files, together with instructions (in the manual page or equivalent) + on where to get the Standard Version.
    2. + +
    3. accompany the distribution with the machine-readable source of the + Package with your modifications.
    4. + +
    5. accompany any non-standard executables with their corresponding + Standard Version executables, giving the non-standard executables + non-standard names, and clearly documenting the differences in manual + pages (or equivalent), together with instructions on where to get the + Standard Version.
    6. + +
    7. make other distribution arrangements with the Copyright + Holder.
    8. + +
    +
  8. + +
  9. You may charge a reasonable copying fee for any distribution of + this Package. You may charge any fee you choose for support of this + Package. You may not charge a fee for this Package itself. However, + you may distribute this Package in aggregate with other (possibly + commercial) programs as part of a larger (possibly commercial) + software distribution provided that you do not advertise this Package + as a product of your own.
  10. + +
  11. The scripts and library files supplied as input to or produced as + output from the programs of this Package do not automatically fall + under the copyright of this Package, but belong to whomever generated + them, and may be sold commercially, and may be aggregatedwith this + Package.
  12. + +
  13. r perl subroutines supplied by you and linked into this Package + shall not be considered part of this Package.
  14. + +
  15. Aggregation of this Package with a commercial distribution is + always permitted provided that the use of this Package is embedded; + that is, when no overt attempt is made to make this Package's + interfaces visible to the end user of the commercial distribution. + Such use shall not be construed as a distribution of this Package.
  16. + +
  17. The name of the Copyright Holder may not be used to endorse or + promote products derived from this software without specific prior + written permission.
  18. + +
  19. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + PURPOSE.
  20. + +
+ +

The End

+ + diff --git a/libs/FLib/JCalendar/doc/example/Example1.java b/libs/FLib/JCalendar/doc/example/Example1.java new file mode 100644 index 0000000..57e3b87 --- /dev/null +++ b/libs/FLib/JCalendar/doc/example/Example1.java @@ -0,0 +1,181 @@ +//********************************************************************** +// Package +//********************************************************************** + +package doc.example; + +//********************************************************************** +// Import list +//********************************************************************** + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.border.*; +import java.util.Calendar; +import java.util.Locale; +import org.freixas.jcalendar.*; + +/** + * This example shows various instances of the JCalendar class. + *
+ * This program is free software; you can redistribute it and/or + * modify it under the terms of the Artistic License. You should have + * received a copy of the Artistic License along with this program. If + * not, a copy is available at + * + * opensource.org. + * + * @author Antonio Freixas + */ + +// Copyright © 2004 Antonio Freixas +// All Rights Reserved. + +public class Example1 + extends JFrame +{ + +//********************************************************************** +// main +//********************************************************************** + +public static void +main( + String[] args) +{ + new Example1(); +} + +//********************************************************************** +// Constructors +//********************************************************************** + +/** + * Create various instances of a JCalendar. + */ + +public +Example1() +{ + // Set up the frame + + setTitle("Example1"); + setDefaultCloseOperation(EXIT_ON_CLOSE); + + Container contentPane = getContentPane(); + contentPane.setLayout(new GridLayout(2, 2, 5, 5)); + + // Create a border for all calendars + + Border etchedBorder = + BorderFactory.createEtchedBorder(); + Border emptyBorder = + BorderFactory.createEmptyBorder(10, 10, 10, 10); + Border compoundBorder = + BorderFactory.createCompoundBorder(etchedBorder, emptyBorder); + + // Create a date listener to be used for all calendars + + MyDateListener listener = new MyDateListener(); + + // Display date and time using the default calendar and locale. + // Display today's date at the bottom. + + JCalendar calendar1 = + new JCalendar( + JCalendar.DISPLAY_DATE | JCalendar.DISPLAY_TIME, + true); + calendar1.addDateListener(listener); + calendar1.setBorder(compoundBorder); + + // Set fonts rather than using defaults + + calendar1.setTitleFont(new Font("Serif", Font.BOLD|Font.ITALIC, 24)); + calendar1.setDayOfWeekFont(new Font("SansSerif", Font.ITALIC, 12)); + calendar1.setDayFont(new Font("SansSerif", Font.BOLD, 16)); + calendar1.setTimeFont(new Font("DialogInput", Font.PLAIN, 10)); + calendar1.setTodayFont(new Font("Dialog", Font.PLAIN, 14)); + + // Display date only + + JCalendar calendar2 = new JCalendar(JCalendar.DISPLAY_DATE, false); + calendar2.addDateListener(listener); + calendar2.setBorder(compoundBorder); + + // Display time only and set the time pattern to use as a duration + // from 00:00 to 23:59 + + JCalendar calendar3 = + new JCalendar( + Calendar.getInstance(), + Locale.getDefault(), + JCalendar.DISPLAY_TIME, + false, + "HH:mm"); + calendar3.addDateListener(listener); + calendar3.setBorder(compoundBorder); + + // Display a French calendar + + JCalendar calendar4 = + new JCalendar( + Calendar.getInstance(Locale.FRENCH), + Locale.FRENCH, + JCalendar.DISPLAY_DATE | JCalendar.DISPLAY_TIME, + false); + calendar4.addDateListener(listener); + calendar4.setBorder(compoundBorder); + + // Add all the calendars to the content pane + + JPanel panel1 = new JPanel(new FlowLayout()); + panel1.add(calendar1); + contentPane.add(panel1); + + JPanel panel2 = new JPanel(new FlowLayout()); + panel2.add(calendar2); + contentPane.add(panel2); + + JPanel panel3 = new JPanel(new FlowLayout()); + panel3.add(calendar3); + contentPane.add(panel3); + + JPanel panel4 = new JPanel(new FlowLayout()); + panel4.add(calendar4); + contentPane.add(panel4); + + // Make the window visible + + pack(); + setVisible(true); +} + +//********************************************************************** +// Inner Classes +//********************************************************************** + +private class MyDateListener + implements DateListener +{ + +public void +dateChanged( + DateEvent e) +{ + Calendar c = e.getSelectedDate(); + if (c != null) { + System.out.println(c.getTime()); + } + else { + System.out.println("No time selected."); + } +} + +} + +//********************************************************************** +// End Inner Classes +//********************************************************************** + +} diff --git a/libs/FLib/JCalendar/doc/example/Example2.java b/libs/FLib/JCalendar/doc/example/Example2.java new file mode 100644 index 0000000..0866447 --- /dev/null +++ b/libs/FLib/JCalendar/doc/example/Example2.java @@ -0,0 +1,173 @@ +//********************************************************************** +// Package +//********************************************************************** + +package doc.example; + +//********************************************************************** +// Import list +//********************************************************************** + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import java.util.Calendar; +import java.util.Locale; +import java.text.SimpleDateFormat; +import org.freixas.jcalendar.*; + +/** + * This example shows various instances of the JCalendarCombo class. + *
+ * This program is free software; you can redistribute it and/or + * modify it under the terms of the Artistic License. You should have + * received a copy of the Artistic License along with this program. If + * not, a copy is available at + * + * opensource.org. + * + * @author Antonio Freixas + */ + +// Copyright © 2004 Antonio Freixas +// All Rights Reserved. + +class Example2 + extends JFrame +{ + +//********************************************************************** +// main +//********************************************************************** + +public static void +main( + String[] args) +{ + new Example2(); +} + +//********************************************************************** +// Constructors +//********************************************************************** + +/** + * Create various instances of a JCalendarCombo. + */ + +public +Example2() +{ + // Set up the frame + + setTitle("Example2"); + setDefaultCloseOperation(EXIT_ON_CLOSE); + + Container contentPane = getContentPane(); + contentPane.setLayout(new GridLayout(2, 2, 5, 5)); + + // Create a date listener to be used for all calendars + + MyDateListener listener = new MyDateListener(); + + // Display date and time using the default calendar and locale. + // Display today's date at the bottom. Allow editing + + JCalendarCombo calendar1 = + new JCalendarCombo( + JCalendarCombo.DISPLAY_DATE | JCalendarCombo.DISPLAY_TIME, + true); + calendar1.setEditable(true); + calendar1.addDateListener(listener); + + // Set fonts rather than using defaults + + calendar1.setFont(new Font("DialogInput", Font.PLAIN, 16)); + + calendar1.setTitleFont(new Font("Serif", Font.BOLD|Font.ITALIC, 24)); + calendar1.setDayOfWeekFont(new Font("SansSerif", Font.ITALIC, 12)); + calendar1.setDayFont(new Font("SansSerif", Font.BOLD, 16)); + calendar1.setTimeFont(new Font("DialogInput", Font.PLAIN, 10)); + calendar1.setTodayFont(new Font("Dialog", Font.PLAIN, 14)); + + // Display date only + + JCalendarCombo calendar2 = + new JCalendarCombo(JCalendarCombo.DISPLAY_DATE, false); + calendar2.addDateListener(listener); + + // Display time only and set the time pattern to use as a duration + // from 00:00 to 23:59 + + JCalendarCombo calendar3 = + new JCalendarCombo( + Calendar.getInstance(), + Locale.getDefault(), + JCalendarCombo.DISPLAY_TIME, + false, + "HH:mm:ss"); + calendar3.setDateFormat(new SimpleDateFormat("HH:mm:ss")); + calendar3.addDateListener(listener); + + // Display a French calendar + + JCalendarCombo calendar4 = + new JCalendarCombo( + Calendar.getInstance(Locale.FRENCH), + Locale.FRENCH, + JCalendarCombo.DISPLAY_DATE | JCalendarCombo.DISPLAY_TIME, + false); + calendar4.addDateListener(listener); + + // Add all the calendars to the content pane + + JPanel panel1 = new JPanel(new BorderLayout()); + panel1.add(calendar1, BorderLayout.NORTH); + contentPane.add(panel1); + + JPanel panel2 = new JPanel(new BorderLayout()); + panel2.add(calendar2, BorderLayout.NORTH); + contentPane.add(panel2); + + JPanel panel3 = new JPanel(new BorderLayout()); + panel3.add(calendar3, BorderLayout.NORTH); + contentPane.add(panel3); + + JPanel panel4 = new JPanel(new BorderLayout()); + panel4.add(calendar4, BorderLayout.NORTH); + contentPane.add(panel4); + + // Make the window visible + + pack(); + setVisible(true); +} + +//********************************************************************** +// Inner Classes +//********************************************************************** + +private class MyDateListener + implements DateListener +{ + +public void +dateChanged( + DateEvent e) +{ + Calendar c = e.getSelectedDate(); + if (c != null) { + System.out.println(c.getTime()); + } + else { + System.out.println("No time selected."); + } +} + +} + +//********************************************************************** +// End Inner Classes +//********************************************************************** + +} diff --git a/libs/FLib/JCalendar/doc/examples.html b/libs/FLib/JCalendar/doc/examples.html new file mode 100644 index 0000000..b741ca1 --- /dev/null +++ b/libs/FLib/JCalendar/doc/examples.html @@ -0,0 +1,66 @@ + + + + + +JCalendar - Examples + + + + + + + + +

+ + + + + +
+

Examples

+

There are two example programs provided for JCalendar. The two programs + are similar except one uses the JCalendar component and the other uses + the JCalendarCombo component.

+

View the Example1 program. View the + Example2 program.

+

If you download the FLib source, you can use Ant to build and run + the example programs:

+
cd JCalendar
+ant runExample1
+ant runExample2
+

Four calendars appear in each example. The upper-left calendar is used + to select a date and time. Today's date is displayed at the bottom of + the calendar. In Example2, it is the only one of the four combo box calendars + which is editable.

+

The upper-right calendar selects just a date. The lower-left calendar + selects just a time.

+

The lower-right calendar uses the French locale (all the others use the + default locale). Because the JCalendar component takes advantage of the + localization in the Calendar class, we get a French-version of the Gregorian + calendar. The month and weekday names are in French. The week starts on + a Monday. The time uses a 24-hour clock.

+

The JCalendar package is not completely localized for French. For instance, + the tool tips on the calendar buttons appear in English. See the tutorial + for instructions on fully localizing the package.

+

When you run either example, each date selection will be echoed to the + window from which you ran the ant command.

+
+ + diff --git a/libs/FLib/JCalendar/doc/features.html b/libs/FLib/JCalendar/doc/features.html new file mode 100644 index 0000000..2e3c824 --- /dev/null +++ b/libs/FLib/JCalendar/doc/features.html @@ -0,0 +1,58 @@ + + + + + +JCalendar - Features + + + + + + + + +

+ + + + + +
+

Features

+

The main features of JCalendar are:

+
    +
  • Easy to use.
  • +
  • Can input the date, time or both.
  • +
  • Can set entry format for time selection.
  • +
  • Can optionally display today's date.
  • +
  • Can use as a panel (JCalendar) or combo-box (JCalendarCombo).
  • +
  • The combo-box can be editable.
  • +
  • Can select date format for selected date in combo-box.
  • +
  • Can select the font to use for all display elements.
  • +
  • Can optionally allow null date (no date) to be selected.
  • +
  • Keyboard access to all functionality.
  • +
  • Combo-box can adopt current L&F (requires modifications for new + L&F's).
  • +
  • Fully internationalized and ready for localization. Most localization + is already done by taking advantage of the localization in the Java + Calendar class.
  • +
+
+ + diff --git a/libs/FLib/JCalendar/doc/images/Logo.png b/libs/FLib/JCalendar/doc/images/Logo.png new file mode 100644 index 0000000..774900e Binary files /dev/null and b/libs/FLib/JCalendar/doc/images/Logo.png differ diff --git a/libs/FLib/JCalendar/doc/images/screenshot-combo-meta-noedit.gif b/libs/FLib/JCalendar/doc/images/screenshot-combo-meta-noedit.gif new file mode 100644 index 0000000..46a9ed5 Binary files /dev/null and b/libs/FLib/JCalendar/doc/images/screenshot-combo-meta-noedit.gif differ diff --git a/libs/FLib/JCalendar/doc/images/screenshot-combo-metal-all.gif b/libs/FLib/JCalendar/doc/images/screenshot-combo-metal-all.gif new file mode 100644 index 0000000..7e9889c Binary files /dev/null and b/libs/FLib/JCalendar/doc/images/screenshot-combo-metal-all.gif differ diff --git a/libs/FLib/JCalendar/doc/images/screenshot-combo-skin1.gif b/libs/FLib/JCalendar/doc/images/screenshot-combo-skin1.gif new file mode 100644 index 0000000..1a22a98 Binary files /dev/null and b/libs/FLib/JCalendar/doc/images/screenshot-combo-skin1.gif differ diff --git a/libs/FLib/JCalendar/doc/images/screenshot-combo-skin2.gif b/libs/FLib/JCalendar/doc/images/screenshot-combo-skin2.gif new file mode 100644 index 0000000..848f520 Binary files /dev/null and b/libs/FLib/JCalendar/doc/images/screenshot-combo-skin2.gif differ diff --git a/libs/FLib/JCalendar/doc/images/screenshot-combo-skin3.gif b/libs/FLib/JCalendar/doc/images/screenshot-combo-skin3.gif new file mode 100644 index 0000000..91d2e98 Binary files /dev/null and b/libs/FLib/JCalendar/doc/images/screenshot-combo-skin3.gif differ diff --git a/libs/FLib/JCalendar/doc/images/screenshot-panel-metal-all.gif b/libs/FLib/JCalendar/doc/images/screenshot-panel-metal-all.gif new file mode 100644 index 0000000..a10a5f3 Binary files /dev/null and b/libs/FLib/JCalendar/doc/images/screenshot-panel-metal-all.gif differ diff --git a/libs/FLib/JCalendar/doc/images/screenshot-panel-metal-french.gif b/libs/FLib/JCalendar/doc/images/screenshot-panel-metal-french.gif new file mode 100644 index 0000000..15a5f9f Binary files /dev/null and b/libs/FLib/JCalendar/doc/images/screenshot-panel-metal-french.gif differ diff --git a/libs/FLib/JCalendar/doc/index.html b/libs/FLib/JCalendar/doc/index.html new file mode 100644 index 0000000..8059eeb --- /dev/null +++ b/libs/FLib/JCalendar/doc/index.html @@ -0,0 +1,64 @@ + + + + + +JCalendar - Introduction + + + + + + + + +

+ + + + + +
+

Introduction

+

Hi! My name is Tony Freixas and I am currently working on an application + that I intend to release as Open Source. In the process of building the + application, I am using as many Open Source classes and components as + I can find.

+

In some cases, I have been disappointed with what I have found on the + web:

+
    +
  • Classes that are not free.
  • +
  • Classes with restrictive licensing.
  • +
  • Classes which ignore internationalization.
  • +
  • Classes which are not easy to use.
  • +
  • Components which are limited with respect to the Look & Feel that + can be used.
  • +
+

When I have not found a suitable Java class, I have implemented my own. + I have decided to release these for use by others as part of a library + I call FLib.

+

Currently, there are three components available in FLib and I have chosen + to make them completely independent of each other. In the future, you + + may have to load some common code in order to use the FLib classes.

+

These web pages are for the Swing-based JCalendar component. Use the + links on the left to learn more.

+

Support This Project

+
+ + diff --git a/libs/FLib/JCalendar/doc/resources.html b/libs/FLib/JCalendar/doc/resources.html new file mode 100644 index 0000000..a384e20 --- /dev/null +++ b/libs/FLib/JCalendar/doc/resources.html @@ -0,0 +1,81 @@ + + + + + +JCalendar - Other Resources + + + + + + + + +

+ + + + + +
+

Other Resources

+

I think it's only fair to note some of the other Java calendar component + implementations. Some of these have appeared since I wrote my version. + You may do a Google search to find yet other versions.

+

I tried the JCalendarCombo from OnlyJava. + It looked nice at first, but I had several problems with it:

+
    +
  • You had to set start/end years since the year was chosen from a combo + box.
  • +
  • The combo box (textfield and down-arrow) always had the Metal L&F.
  • +
  • The component was not internationalized.
  • +
  • The license does not allow for derivative works.
  • +
+

The JCalendar from toedter.com + looks promising. There doesn't seem to be an option for a combo-box version, + though. It uses the LGPL license.

+

A CalendarPanel + was written by Wong Kok Wai. It also lacks combo-box entry. I'm not sure + about the license.

+

There are a number of commercial products you could try if you're willing + to pay:

+
    +
  • JavaDatePicker starts + at $119 for a single-developer license.
  • +
  • ExtremeComponent + offers a JCalendar component binary license for $19. I didn't see a + combo-box option.
  • +
  • LavanTech has + a pretty fancy date/time selector starting at $75 for a single-user + license. It does provide a combo-box selection, but I'm not sure how + well it adapts to the various L&F's.
  • +
  • jProductivity + offers a calendar with a lot of options, including a combo-box version. + Again, I'm not sure how it adapts to various L&F's since the only + way I've found to do it is to modify the code for each L&F.
  • +
+

There are some less-fancy calendar selectors which might be useful for + applets. tCalDate + is free for personal use and appears to only require registration for + professional use. Scand + LLC offers two versions of a calendar: one for free and an advanced + version for $29.

+
+ + diff --git a/libs/FLib/JCalendar/doc/screenshots.html b/libs/FLib/JCalendar/doc/screenshots.html new file mode 100644 index 0000000..9b3f70e --- /dev/null +++ b/libs/FLib/JCalendar/doc/screenshots.html @@ -0,0 +1,65 @@ + + + + + +JCalendar - Screen Shots + + + + + + + + +

+ + + + + +
+

Screen Shots

+

The following are screen shots of JCalendar components using various + look-and-feels:

+

+

A JCalendar from the Example1 program using the Metal + L&F. Both date and time are input and today's date is displayed on + the bottom.

+

+

A JCalendar from the Example1 program using the French + locale. Note that the week starts on a Monday and that the time entry + uses a 24-hour clock.

+

+

An editable JCalendarCombo from the Example2 program with + the calendar pop-up displayed.

+

+

A non-editable JCalendarCombo from the Example2 program. + Only the date (not the time) is requested.

+

+

An editable JCalendarCombo using the Skin L&F with + the Aqua package.

+

+

An editable JCalendarCombo using the Skin L&F with + the Modern package.

+

+

An editable JCalendarCombo using the Skin L&F with + the XPLuna package.

+
+ + diff --git a/libs/FLib/JCalendar/doc/stylesheet.css b/libs/FLib/JCalendar/doc/stylesheet.css new file mode 100644 index 0000000..dc693da --- /dev/null +++ b/libs/FLib/JCalendar/doc/stylesheet.css @@ -0,0 +1,48 @@ +body { + font-family: Arial, Helvetica, sans-serif; + background: white: + color: black; +} + +td { + font-family: Arial, Helvetica, sans-serif; +} + +th { + font-family: Arial, Helvetica, sans-serif; +} + +#sidebar { + font-family: "Times New Roman", Times, serif; + font-weight: bold; + font-style: italic; + font-size: 20px; +} + +#content { + font-size: 100%; +} + +a:visited { + color: #8080FF; + text-decoration: none; +} + +a:link { + color: #8080FF; + text-decoration: none; +} + +a:hover { + color: #C00000; + text-decoration: none; +} + +a:active { + color: #C00000; + text-decoration: none; +} + +pre { + margin-left: 1em; +} diff --git a/libs/FLib/JCalendar/doc/tutorial.html b/libs/FLib/JCalendar/doc/tutorial.html new file mode 100644 index 0000000..6fd8422 --- /dev/null +++ b/libs/FLib/JCalendar/doc/tutorial.html @@ -0,0 +1,149 @@ + + + + + +JCalendar - Tutorial + + + + + + + + +

+ + + + + +
+

Tutorial

+

JCalendar

+

JCalendar is the generic name for two Java components: one is called + JCalendar and the other is called JCalendarCombo. They both share common + features, particularly the ability to select a date and/or time. The former + accomplishes this with a panel and the latter with a combo-box.

+

Creating the Components

+

The simplest constructors for JCalendar and JCalendarCombo have no arguments. + They create calendar components that allow a date to be selected from + the default calendar in the default locale.

+

The next step is to select the specific Calendar and Locale classes to + use (but the JCalendar components have only been tested with the Gregorian + calendar). There are three more parameters that can be specified:

+
    +
  • Whether to select a date, a time or both.
  • +
  • Whether to display today's date at the bottom of the component.
  • +
  • The SimpleDateFormat pattern to use in displaying the time selection + field.
  • +
+

Normally, the calendar components allow you to select a null date/time + (press Delete or Backspace to set a null selection). This is useful for + cases where the user has an option of not specifying a date/time. You + can turn this off by calling setNullAllowed(false).

+

For the JCalendarCombo, you also have the option of making the combo-box + editable (as with any combo-box). You can control the date format that + appears in the combo-box field with setDateFormat().

+

Date Selections

+

You can set the selected date with setDate(). The default + date/time selection will be today's date/time unless you explicitly set + a date. You can read the currently selected date at any time using getDate() + or getCalendar(). Finally, you can add a DateListener to + listen for date changes. Each time the date/time changes, the listener + is called.

+ +

Fonts

+

You may specify the font to use for each elements that makes + up a calendar component. The elements are:

+
    +
  • The month-year title.
  • +
  • The day-of-week labels (Mon, Tue, etc.).
  • +
  • The day buttons.
  • +
  • The time spinner.
  • +
  • The today's date message.
  • +
+

In addition, the combo box text can be changed in the usual + way—by calling setFont() on the combo box component.

+

Keyboard Control

+

The calendar appears with buttons that allow the user to move a month + or year backwards or forward. You can use the arrow keys to do the same:

+
    +
  • Left Arrow - Move back a month.
  • +
  • Right Arrow - Move forward a month.
  • +
  • Shift Left Arrow - Move back a year.
  • +
  • Shift Right Arrow - Move forward a year.
  • +
+

In addition, you can use Delete or Backspace to select a null date (if + null dates are allowed).

+

As normal, you can tab through the various buttons (including the day + buttons) and press Enter to activate the button.

+

If there is a time field, it can be a little problematic. Once it has + focus, the up/down arrow keys increment/decrement portions of the time + field. The left/right keys select the portion of the time to increment/decrement. + You will need to tab out of the time field or use the mouse to select + a button elsewhere in the calendar in order to restore the normal keyboard + controls.

+

The JCalendarCombo has some additional keyboard controls. The down arrow + pops up a calendar if one is not visible. The up arrow hides the calendar + pop-up (as does the Enter key). The Escape key also hides the calendar, + but restores the date to the value it had before the calendar was popped + up.

+

Internationalization

+

The JCalendar components take advantage of the internationalization and + localization work done by the Calendar class. In order to fully localize + JCalendar to other than US English, you will need to obtain the source + code for JCalendar and create a org.freixas.jcalendar.Bundle_<locale>.properties + file which translates the text in org.freixas.jcalendar.Bundle.properties, + where <locale> is a two-letter country code.

+

The main thing in this file are the tooltips for the various buttons + and the text for displaying today's date as well as some error messages.

+

Look-and-Feel

+

It was important for my own use that the JCalendar combo-box adopt the + current Java Look-and-Feel (L&F). As it turns out, it is impossible + to design a class that can automatically do this for all possible L&F's. + If you need to use a L&F other than Metal, Windows or Motif, you will + need to obtain the JCalendar source code and make some changes.

+

In the updateUI() method of JCalendarCombo.java, you will + need to add some code that looks like this:

+
else if (cui instanceof SomeComboBoxUI) {
+    cui = new SomeDateComboBoxUI();
+}
+ +

Then in the inner class section of the code, add a new inner class:

+
class SomeDateComboBoxUI
+    extends SomeComboBoxUI
+{
+    protected ComboPopup createPopup() {
+        return new CalendarComboPopup();
+    }
+}
+
+

Of course, the word "Some" would be replaced by the name of + your L&F (Metal, Motif, etc.). When your L&F is installed, the + JCalendarCombo combo-box will now look the same as a normal JComboBox.

+

Summary

+

The JCalendar components are designed to be easy to use—create + the component you want, set up a few options and register a DateListener + and you're in business.

+

After reading this tutorial, you should examine the example + programs provided which exercise many of the features of JCalendar + components.

+
+ + diff --git a/libs/FLib/JCalendar/org/freixas/jcalendar/Bundle.properties b/libs/FLib/JCalendar/org/freixas/jcalendar/Bundle.properties new file mode 100644 index 0000000..5d6f641 --- /dev/null +++ b/libs/FLib/JCalendar/org/freixas/jcalendar/Bundle.properties @@ -0,0 +1,45 @@ +# org.freixas.jcalendar Resource Bundle + +# Arg 0 is today's date +Today=Today''s date is {0, date, medium}' + +# Arg 0 is the month and arg 1 is the year. This is used to display +# the month/year of the calendar page +MonthYearTitle={0} {1} + +# The following are the navigation buttons +# +# Images must be placed in the image directory and should be supplied +# in gif format in 16x16 (name ends with 16) and 24x24 sizes (name +# ends with 24). Only the base name is given; for example +# images/Sample16.gif would be named Sample + +YearDecrButton= +YearDecrButtonMnemonic= +YearDecrButtonAccelerator= +YearDecrButtonImage=Rewind +YearDecrButtonShort=Back one year +YearDecrButtonLong=Back one year + +MonthDecrButton= +MonthDecrButtonMnemonic= +MonthDecrButtonAccelerator= +MonthDecrButtonImage=Back +MonthDecrButtonShort=Back one month +MonthDecrButtonLong=Back one month. + +MonthIncrButton= +MonthIncrButtonMnemonic= +MonthIncrButtonAccelerator= +MonthIncrButtonImage=Forward +MonthIncrButtonShort=Forward one month +MonthIncrButtonLong=Forward one month. + +YearIncrButton= +YearIncrButtonMnemonic= +YearIncrButtonAccelerator= +YearIncrButtonImage=FastForward +YearIncrButtonShort=Forward one year +YearIncrButtonLong=Forward one year. + +IllegalStateException=You must display the date and/or the time. diff --git a/libs/FLib/JCalendar/org/freixas/jcalendar/DateEvent.java b/libs/FLib/JCalendar/org/freixas/jcalendar/DateEvent.java new file mode 100644 index 0000000..dfd4f9f --- /dev/null +++ b/libs/FLib/JCalendar/org/freixas/jcalendar/DateEvent.java @@ -0,0 +1,86 @@ +//********************************************************************** +// Package +//********************************************************************** + +package org.freixas.jcalendar; + +//********************************************************************** +// Import list +//********************************************************************** + +import java.util.EventObject; +import java.util.Calendar; + +/** + * This class holds information related to a date change in a + * calendar. + * + * @see JCalendar + * @see JCalendarCombo + * @author Antonio Freixas + */ + +// Copyright © 2003 Antonio Freixas +// All Rights Reserved. + +public class DateEvent + extends EventObject +{ + +//********************************************************************** +// Private Members +//********************************************************************** + +private Calendar selectedDate; + +//********************************************************************** +// Constructors +//********************************************************************** + +/** + * Create a date event. + * + * @param source The object on which the event occurred. + * @param selectedDate The selected date. + */ + +public +DateEvent( + Object source, + Calendar selectedDate) +{ + super(source); + this.selectedDate = selectedDate; +} + +//********************************************************************** +// Public +//********************************************************************** + +/** + * Return the selected date. + * + * @return The selected date. + */ + +public Calendar +getSelectedDate() +{ + return selectedDate; +} + +//The default equals and hashCode methods are acceptable. + +/** + * {@inheritDoc} + */ + +public String +toString() +{ + return + super.toString() + ",selectedDate=" + + selectedDate.getTime().toString(); +} + +} diff --git a/libs/FLib/JCalendar/org/freixas/jcalendar/DateListener.java b/libs/FLib/JCalendar/org/freixas/jcalendar/DateListener.java new file mode 100644 index 0000000..7d3f723 --- /dev/null +++ b/libs/FLib/JCalendar/org/freixas/jcalendar/DateListener.java @@ -0,0 +1,46 @@ +//********************************************************************** +// Package +//********************************************************************** + +package org.freixas.jcalendar; + +//********************************************************************** +// Import list +//********************************************************************** + +import java.util.EventListener; + +/** + * Listen for date changes. + * + * @see JCalendar + * @see JCalendarCombo + * @author Antonio Freixas + */ + +// Copyright © 2003 Antonio Freixas +// All Rights Reserved. + +public interface DateListener + extends EventListener +{ + +//********************************************************************** +// Public Constants +//********************************************************************** + +//********************************************************************** +// Public +//********************************************************************** + +/** + * This method is called each time a date in a calendar changes. + * + * @param e The date event information. + */ + +public void +dateChanged( + DateEvent e); + +} diff --git a/libs/FLib/JCalendar/org/freixas/jcalendar/JCalendar.java b/libs/FLib/JCalendar/org/freixas/jcalendar/JCalendar.java new file mode 100644 index 0000000..5e305f1 --- /dev/null +++ b/libs/FLib/JCalendar/org/freixas/jcalendar/JCalendar.java @@ -0,0 +1,1681 @@ +//********************************************************************** +// Package +//********************************************************************** + +package org.freixas.jcalendar; + +//********************************************************************** +// Import list +//********************************************************************** + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.event.*; + +import java.text.*; +import java.net.URL; +import java.util.Calendar; +import java.util.Date; +import java.util.Locale; +import java.util.ResourceBundle; + +/** + * This class displays a panel through which a user can select a date + * and/or time. A time-only selection can be used to select a + * duration, as long as the duration is no longer than 23 hours, 59 + * minutes and 59 seconds. + *

+ * The date is selected using a calendar display. The time is selected + * using a date spinner. + *

+ * In reality, both date and time are part of the same Date returned + * by getDate() or getCalendar(). If you are selecting only the date, + * you should ignore the time portion of the Date or Calendar. If you + * are selecting only the time, ignore the date portion. + *

+ * You can set the pattern used to display the time in the date + * spinner. The pattern is the same as used by SimpleDateFormat. The + * default format displays hours, minutes and seconds in a + * locale-specific way (some locales use AM/PM, some use a 24-hour + * clock). If you want to get a time duration, you will want to use a + * pattern such as "HH:mm:ss" to eliminate the possibility of an AM/PM + * field appearing. You can also use setTimePattern() to reduce the + * precision of the time obtained (e.g. "HH:mm"). + *

+ * You may specify a font for each of the elements that make up the + * calendar. If you do not specify a font (or specify a null font), a + * reasonable default will be generated based on the current Look + * & Feel. + *

+ * When the calendar has focus, the following key bindings are + * supported: + *

+ * This is in addition to using Tab and Enter to move through and + * select the buttons. + *

+ * The time field is divided into hour, minute, second and AM/PM + * portions. You can select any portion and use the spinner arrows on + * the right side of the field to increment or decrement that portion. + * However, the entire time is being incremented or decremented, so + * that incrementing 1:59:59 by one second will generate 2:00:00. + *

+ * Due to a design limitation in JFormatedTextField, incrementing + * 24:59:59 will not increment the day. A value in a + * JFormatedTextField (which is what the time field is), only + * calculates a date from the fields displayed. Since usually we + * display a HH:mm:ss pattern, the JFormattedTextField will set the + * date to a default value, not influenced by the date in the calendar + *

+ * It is possible to pass in a time pattern that displays more than just + * the time -- this is not advisable since the date portion displayed + * in the JFormatedTextField will be ignored by the JCalendar + * component. + *

+ * When the time field has focus, the up/down arrow keys increment or + * decrement the currently selected time portion, just like the + * spinner keys. The left and right arrow keys can be used to move to + * the next or previous portion. + * + * @see Calendar + * @see Date + * @see DateFormat + * @see SimpleDateFormat + * @author Antonio Freixas + */ + +// Copyright © 2003 Antonio Freixas +// All Rights Reserved. + +public class JCalendar + extends JPanel +{ + +//********************************************************************** +// Public Constants +//********************************************************************** + +/** + * Used to indicate that this component should display the date. + */ + +public static final int DISPLAY_DATE = 0x01; + +/** + * Used to indicate that this component should display the time. + */ + +public static final int DISPLAY_TIME = 0x02; + +//********************************************************************** +// Private Constants +//********************************************************************** + +private static final int MONTH_DECR_BUTTON = 0; +private static final int MONTH_INCR_BUTTON = 1; +private static final int YEAR_DECR_BUTTON = 2; +private static final int YEAR_INCR_BUTTON = 3; + +//********************************************************************** +// Private Members +//********************************************************************** + +// This determines the components being displayed: the calendar, the +// time spinner, or both + +private int selectedComponents; + +// The calendar containing a selected day. The selected day may not be +// always be displayed + +private Calendar selectedCalendar; +private int selectedYear = -1; +private int selectedMonth = -1; +private int selectedDay = -1; +private int selectedHour = -1; +private int selectedMinute = -1; +private int selectedSecond = -1; + +// The calendar we display + +private Calendar displayCalendar; +private int displayYear; +private int displayMonth; + +// The locale to use + +private Locale locale; + +// True if we display today's date + +private boolean isTodayDisplayed = false; + +// A null date is equivalent to having no date selected. Note that the +// constructor selects the current date (today) + +private boolean isNullAllowed = true; +private boolean isNullDate = true; + +// The time pattern used to set the format of the time spinner + +private String timePattern; + +// Components + +private JButton yearDecrButton; +private JButton monthDecrButton; +private JLabel monthYearLabel; +private JButton monthIncrButton; +private JButton yearIncrButton; + +private JLabel[] dayOfWeekLabels; +private JToggleButton[][] dayButtons; +private JToggleButton offScreenButton; +private ButtonGroup dayGroup; + +private SpinnerDateModel spinnerDateModel; +private JSpinner spinner; + +private JLabel todaysLabel; + +// Fonts + +private Font titleFont; +private Font dayOfWeekFont; +private Font dayFont; +private Font timeFont; +private Font todayFont; + +// Date formats + +private DateFormat formatMonth; +private DateFormat formatWeekDay; + +private String lastMonth; +private String lastYear; + +// These maps are used to bind keyboard keys to methods + +static InputMap inputMap = new InputMap(); +static ActionMap actionMap = new ActionMap(); + +// The input map maps a key to a name. The action map maps a name to +// an action. The actions below map the action to a method call + +private static Action yearBackward = new AbstractAction("yearBackward") { + public void actionPerformed(ActionEvent e) { + ((JCalendar)e.getSource()).yearBackward(); + } +}; + +private static Action yearForward = new AbstractAction("yearForward") { + public void actionPerformed(ActionEvent e) { + ((JCalendar)e.getSource()).yearForward(); + } +}; + +private static Action monthBackward = new AbstractAction("montBackward") { + public void actionPerformed(ActionEvent e) { + ((JCalendar)e.getSource()).monthBackward(); + } +}; + +private static Action monthForward = new AbstractAction("monthForward") { + public void actionPerformed(ActionEvent e) { + ((JCalendar)e.getSource()).monthForward(); + } +}; + +private static Action setNullDate = new AbstractAction("setNullDate") { + public void actionPerformed(ActionEvent e) { + ((JCalendar)e.getSource()).setDate(null); + } +}; + +// The resource bundle + +private static ResourceBundle bundle = + ResourceBundle.getBundle("org.freixas.jcalendar.Bundle"); + +//********************************************************************** +// Static Constructors +//********************************************************************** + +static +{ + // Set up the input map that will be shared by all instances + + inputMap.put(KeyStroke.getKeyStroke("BACK_SPACE"), "setNullDate"); + inputMap.put(KeyStroke.getKeyStroke("DELETE"), "setNullDate"); + inputMap.put(KeyStroke.getKeyStroke("shift LEFT"), "yearBackward"); + inputMap.put(KeyStroke.getKeyStroke("shift RIGHT"), "yearForward"); + inputMap.put(KeyStroke.getKeyStroke("LEFT"), "monthBackward"); + inputMap.put(KeyStroke.getKeyStroke("RIGHT"), "monthForward"); + + actionMap.put("setNullDate", setNullDate); + actionMap.put("yearBackward", yearBackward); + actionMap.put("yearForward", yearForward); + actionMap.put("monthBackward", monthBackward); + actionMap.put("monthForward", monthForward); +} + +//********************************************************************** +// Constructors +//********************************************************************** + +/** + * Create an instance of JCalendar using the default calendar and + * locale. Display the date but not the time. Don't display today's + * date at the bottom of the panel. + */ + +public +JCalendar() +{ + this(Calendar.getInstance(), + Locale.getDefault(), + DISPLAY_DATE, + false, + null); +} + +/** + * Create an instance of JCalendar using the default calendar and + * locale. Display a calendar and/or a time spinner as requested (to + * display both use DISPLAY_DATE | DISPLAY_TIME). Display today's + * date if requested. Use the defult pattern to display the time in the + * time spinner field (if there is one). + * + * @param selectedComponents Use DISPLAY_DATE, DISPLAY_TIME or + * (DISPLAY_DATE | DISPLAY_TIME). + * @param isTodayDisplayed True if today's date should be displayed at + * the bottom of the panel. + */ + +public +JCalendar( + int selectedComponents, + boolean isTodayDisplayed) +{ + this(Calendar.getInstance(), + Locale.getDefault(), + selectedComponents, + isTodayDisplayed, + null); +} + +/** + * Create an instance of JCalendar using the given calendar and + * locale. Display a calendar and/or a time spinner as requested (to + * display both use DISPLAY_DATE | DISPLAY_TIME). Display today's + * date if requested. Use the default pattern to display the time in the + * time spinner field (if there is one). + * + * @param calendar The calendar to use. + * @param locale The locale to use. + * @param selectedComponents Use DISPLAY_DATE, DISPLAY_TIME or + * (DISPLAY_DATE | DISPLAY_TIME). + * @param isTodayDisplayed True if today's date should be displayed at + * the bottom of the panel. + */ + +public +JCalendar( + Calendar calendar, + Locale locale, + int selectedComponents, + boolean isTodayDisplayed) +{ + this(calendar, + locale, + selectedComponents, + isTodayDisplayed, + null); +} + +/** + * Create an instance of JCalendar using the given calendar and + * locale. Display a calendar and/or a time spinner as requested (to + * display both use DISPLAY_DATE | DISPLAY_TIME). Display today's + * date if requested. Set the pattern used to display the time in the time + * spinner field (if there is one). If null, use the default MEDIUM + * format for the given locale. Patterns are from DateFormat and + * SimpleDateFormat. + * + * @param calendar The calendar to use. + * @param locale The locale to use. + * @param selectedComponents Use DISPLAY_DATE, DISPLAY_TIME or + * (DISPLAY_DATE | DISPLAY_TIME). + * @param isTodayDisplayed True if today's date should be displayed at + * the bottom of the panel. + * @param timePattern The pattern used to display the time in the time + * spinner field. + * @see DateFormat + * @see SimpleDateFormat + */ + +public +JCalendar( + Calendar calendar, + Locale locale, + int selectedComponents, + boolean isTodayDisplayed, + String timePattern) +{ + this.selectedCalendar = (Calendar)calendar.clone(); + this.displayCalendar = (Calendar)selectedCalendar.clone(); + this.selectedComponents = selectedComponents; + if ((selectedComponents & (DISPLAY_DATE | DISPLAY_TIME)) == 0) { + throw new IllegalStateException( + bundle.getString("IllegalStateException")); + } + + this.locale = locale; + this.isTodayDisplayed = isTodayDisplayed; + + if ((selectedComponents & DISPLAY_TIME) > 0) { + if (timePattern == null) { + DateFormat timeFormat = + DateFormat.getTimeInstance(DateFormat.MEDIUM, locale); + this.timePattern = "HH:mm:ss"; + if (timeFormat instanceof SimpleDateFormat) { + this.timePattern = ((SimpleDateFormat)timeFormat).toPattern(); + } + } + else { + this.timePattern = timePattern; + } + } + + createCalendarComponents(); + setDate(new Date()); +} + +//********************************************************************** +// Public +//********************************************************************** + +/** + * Add a date listener. This listener will receive events each time + * the selected date changes. + * + * @param listener The date listener to add. + */ + +public void +addDateListener( + DateListener listener) +{ + listenerList.add(DateListener.class, listener); +} + +/** + * Remove a date listener. + * + * @param listener The date listener to remove. + */ + +public void +removeDateListener( + DateListener listener) +{ + listenerList.remove(DateListener.class, listener); +} + +/** + * Get whether a null date is allowed. + * + * @return Whether a null date is allowed. + */ + +public boolean +isNullAllowed() +{ + return isNullAllowed; +} + +/** + * Set whether a null date is allowed. A null date means that no date + * is selected. The user can select a null date by pressing DELETE + * anywhere within the calendar. + *

+ * If nulls are not allowed, a setDate(null) will be ignored without + * error. The DELETE key will do nothing. + *

+ * If you switch from allowing nulls to not allowing nulls and the + * current date is null, it will remain null until a date is selected. + *

+ * The component default is to allow nulls. + * + * @param isNullAllowed Whether a null date is allowed. + */ + +public void +setNullAllowed( + boolean isNullAllowed) +{ + this.isNullAllowed = isNullAllowed; +} + +/** + * Get the date currently displayed by the calendar panel. If no date + * is selected, null is returned. + * + * @return The date currently displayed. + * @see #getCalendar + */ + +public Date +getDate() +{ + if (isNullDate) return null; + return selectedCalendar.getTime(); +} + +/** + * Set the calendar panel to display the given date. This will fire a + * DateEvent. The date may be null. If isNullAllowed() is true, then + * all dates will be unselected. If isNullAllowed() is false, a null + * date is ignored. + * + * @param date The date to set. + */ + +public void +setDate( + Date date) +{ + if (date == null) { + + // Ignore nulls if nulls aren't allowed + + if (!isNullAllowed) return; + + if (!isNullDate) { + isNullDate = true; + selectedYear = -1; + selectedMonth = -1; + selectedDay = -1; + selectedCalendar.set(Calendar.YEAR, 9999); + selectedCalendar.set(Calendar.MONTH, 9); + selectedCalendar.set(Calendar.DATE, 9); + selectedCalendar.set(Calendar.HOUR_OF_DAY, 0); + selectedCalendar.set(Calendar.MINUTE, 0); + selectedCalendar.set(Calendar.SECOND, 0); + updateCalendarComponents(); + fireDateChange(); + } + } + + else { + int oldYear = selectedYear; + int oldMonth = selectedMonth; + int oldDay = selectedDay; + int oldHour = selectedHour; + int oldMinute = selectedMinute; + int oldSecond = selectedSecond; + + selectedCalendar.setTime(date); + selectedYear = selectedCalendar.get(Calendar.YEAR); + selectedMonth = selectedCalendar.get(Calendar.MONTH); + selectedDay = selectedCalendar.get(Calendar.DATE); + selectedHour = selectedCalendar.get(Calendar.HOUR_OF_DAY); + selectedMinute = selectedCalendar.get(Calendar.MINUTE); + selectedSecond = selectedCalendar.get(Calendar.SECOND); + + if ((((selectedComponents & DISPLAY_DATE) > 0) && + oldDay != selectedDay || + oldMonth != selectedMonth || + oldYear != selectedYear) || + + (((selectedComponents & DISPLAY_TIME) > 0) && + oldHour != selectedHour || + oldMinute != selectedMinute || + oldSecond != selectedSecond)) { + + isNullDate = false; + displayCalendar.setTime(date); + updateCalendarComponents(); + fireDateChange(); + } + } +} + +/** + * Reset the displayed date without changing the selected date. No + * event occurs. A null date will reset to today's date. The display + * date simply selects the calendar page (month/year) to display. + * + * @param date The date to display. + */ + +public void +setDisplayDate( + Date date) +{ + if (date == null) date = new Date(); + + displayCalendar.setTime(date); + int oldMonth = displayCalendar.get(Calendar.MONTH); + int oldYear = displayCalendar.get(Calendar.YEAR); + if (oldMonth != displayMonth || oldYear != displayYear) { + updateCalendarComponents(); + } +} + +/** + * Get the pattern used to display the time in the time selection + * spinner. This is null if the time is not displayed. + * + * @return The pattern used to display the time in the time selection + * spinner. + */ + +public String +getTimePattern() +{ + if ((selectedComponents & DISPLAY_TIME) != 0) { + return timePattern; + } + return null; +} + +/** + * Get a copy of the calendar used by this JCalendar. This calendar + * will be set to the currently selected date, so it is an alternative + * to the getDate() method. If no date is selected (getDate() returns + * null), the calendar's selected date is 9/9/9999 and should not be + * used. + * + * @return A copy of the calendar used by JCalendar. + * @see #getDate + */ + +public Calendar +getCalendar() +{ + return (Calendar)selectedCalendar.clone(); +} + +/** + * Return the locale used by this JCalendar. + * + * @return The locale used by this JCalendar. + */ + +public Locale +getLocale() +{ + return locale; +} + +/** + * Return the components being displayed: + * + * (getSelectedComponents() & DISPLAY_DATE) > 0 + * + * means that the date calendar is being displayed. + * + * (getSelectedComponents() & DISPLAY_TIME) > 0 + * + * menas that the time spinner field is being displayed. + * + * @return The selected components. + */ + +public int +getSelectedComponents() +{ + return selectedComponents; +} + + +/** + * Returns true if today's date is displayed at the bottom of the + * calendar. + * + * @return True if today's date is displayed at the bottom of the + * calendar. + */ + +public boolean +isTodayDisplayed() +{ + return isTodayDisplayed; +} + +/** + * Get the title font. + * + * @return The title font. + */ + +public Font +getTitleFont() +{ + return titleFont; +} + +/** + * If the font is set to null, then the title font (for the Month Year + * title) will default to the L&F's Label default font. + *

+ * Otherwise, the title font is set as given. + * + * @param font The font to set. + */ + +public void +setTitleFont( + Font font) +{ + if (font == null && titleFont != null || + !font.equals(titleFont)) { + + titleFont = font; + if (isDisplayable()) setupTitleFont(); + } +} + +/** + * Get the day-of-week font (Mon, Tue, etc.). + * + * @return The day-of-week font. + */ + +public Font +getDayOfWeekFont() +{ + return dayOfWeekFont; +} + +/** + * If the font is set to null, then the day-of-week font (Mon, Tue, + * etc.) will default to 9/11th's of the L&F's Label default font. + *

+ * Otherwise, the day-of-week font is set as given. + * + * @param font The font to set. + */ + +public void +setDayOfWeekFont( + Font font) +{ + if (font == null && dayOfWeekFont != null || + !font.equals(dayOfWeekFont)) { + + dayOfWeekFont = font; + if (isDisplayable()) setupDayOfWeekFonts(); + } +} + +/** + * Get the day font. + * + * @return The day font. + */ + +public Font +getDayFont() +{ + return dayFont; +} + +/** + * If the font is set to null, then the day font will default to + * 9/11th's of the L&F's Button default font. + *

+ * Otherwise, the day font is set as given. + * + * @param font The font to set. + */ + +public void +setDayFont( + Font font) +{ + if (font == null && dayFont != null || + !font.equals(dayFont)) { + + dayFont = font; + if (isDisplayable()) setupDayFonts(); + } +} + +/** + * Get the time spinner font. + * + * @return The time spinner font. + */ + +public Font +getTimeFont() +{ + return timeFont; +} + +/** + * If the font is set to null, then the time spinner font will default + * to the L&F's Spinner default font. + *

+ * Otherwise, the time spinner font is set as given. + * + * @param font The font to set. + */ + +public void +setTimeFont( + Font font) +{ + if (font == null && timeFont != null || + !font.equals(timeFont)) { + + timeFont = font; + if (isDisplayable()) setupTimeFont(); + } +} + +/** + * Get the font used to display today's date as text. + * + * @return The font used to display today's date. + */ + +public Font +getTodayFont() +{ + return todayFont; +} + +/** + * If the font is set to null, then the font used to display today's + * date as text will default to the L&F's Label default font. + *

+ * Otherwise, the font used to display today's date is set as given. + * + * @param font The font to set. + */ + +public void +setTodayFont( + Font font) +{ + if (font == null && todayFont != null || + !font.equals(todayFont)) { + + todayFont = font; + if (isDisplayable()) setupTodayFont(); + } +} + +/** + * {@inheritDoc} + */ + +public void +setEnabled( + boolean b) +{ + if (b != isEnabled()) { + super.setEnabled(b); + + if ((selectedComponents & DISPLAY_DATE) > 0) { + yearDecrButton.setEnabled(b); + monthDecrButton.setEnabled(b); + monthYearLabel.setEnabled(b); + monthIncrButton.setEnabled(b); + yearIncrButton.setEnabled(b); + + for (int day = 0; day < 7; day++) { + dayOfWeekLabels[day].setEnabled(b); + } + + for (int row = 0; row < 6; row++) { + for (int day = 0; day < 7; day++) { + if (dayButtons[row][day].getText().length() > 0) { + dayButtons[row][day].setEnabled(b); + } + } + } + } + + if ((selectedComponents & DISPLAY_TIME) > 0) { + spinner.setEnabled(b); + } + } +} + +/** + * {@inheritDoc} + */ + +public void +addNotify() +{ + // We don't try to do anything with the fonts until we know the + // component is displayable + + setupTitleFont(); + setupDayOfWeekFonts(); + setupDayFonts(); + setupTimeFont(); + setupTodayFont(); + + super.addNotify(); +} + +// The default equals and hashCode methods are acceptable. In +// general, two components are never equal unless they are the same +// component. + +/** + * {@inheritDoc} + */ + +protected String +paramString() +{ + String curDate; + if ((selectedComponents & DISPLAY_DATE) == DISPLAY_DATE) { + curDate = DateFormat.getDateInstance( + DateFormat.FULL, locale).format(getDate()); + } + else if ((selectedComponents & DISPLAY_TIME) == DISPLAY_TIME) { + curDate = DateFormat.getTimeInstance( + DateFormat.FULL, locale).format(getDate()); + } + else { + curDate = DateFormat.getDateTimeInstance( + DateFormat.FULL, DateFormat.FULL, locale).format(getDate()); + } + + return super.paramString() + ",selectedDate=" + curDate; +} + +//********************************************************************** +// Package Public +//********************************************************************** + +private JCalendarCombo comboCalendar; + +/** + * Get the JCalendarCombo component which uses this JCalendar in its + * combo popup. + * + * @return The JCalendarCombo component which uses this JCalendar in + * its combo popup. + * @see JCalendarCombo + */ + +JCalendarCombo +getJCalendarComboParent() +{ + return comboCalendar; +} + +/** + * Set the JCalendarCombo component which uses this JCalendar in its + * combo popup. + * + * @param comboCalendar The JCalendarCombo component which uses this + * JCalendar in its combo popup. + * @see JCalendarCombo + */ + +void +setJCalendarComboParent( + JCalendarCombo comboCalendar) +{ + this.comboCalendar = comboCalendar; +} + +/** + * Add the given input/action maps to the spinner. + */ + +void +addSpinnerMaps( + InputMap sim, + ActionMap sam) +{ + sim.setParent(spinner.getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)); + spinner.setInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, sim); + sam.setParent(spinner.getActionMap()); + spinner.setActionMap(sam); +} + +//********************************************************************** +// Protected +//********************************************************************** + +/** + * Fire a date change. This notifies all listeners that the date has + * changed. + */ + +protected void +fireDateChange() +{ + // Guaranteed to return a non-null array + + Object[] listeners = listenerList.getListenerList(); + + // Process the listeners last to first, notifying + // those that are interested in this event + + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == DateListener.class) { + DateEvent dateEvent; + if (isNullDate) { + dateEvent = new DateEvent(this, null); + } + else { + dateEvent = new DateEvent(this, selectedCalendar); + } + ((DateListener)listeners[i + 1]).dateChanged(dateEvent); + } + } +} + +/** + * Set the title's font. + */ + +protected void +setupTitleFont() +{ + Font font; + if (monthYearLabel == null) return; + + // If not null, use what the user gave us + + if (titleFont != null) { + monthYearLabel.setFont(titleFont); + } + + // Otherwise, use the L&F default for a label + + else { + font = UIManager.getFont("Label.font"); + monthYearLabel.setFont(font); + } +} + +/** + * Set the day-of-week labels' font. + */ + +protected void +setupDayOfWeekFonts() +{ + Font font; + if (dayOfWeekLabels == null) return; + + // If not null, use what the user gave us + + font = dayOfWeekFont; + + // Otherwise, use 9/11 of the L&F default for a label + + if (font == null) { + font = UIManager.getFont("Label.font"); + font = font.deriveFont((float)(font.getSize2D() * 9.0 / 11.0)); + } + + // Set the day of week labels' font + + for (int day = 0; day < 7; day++) { + dayOfWeekLabels[day].setFont(font); + } +} + +/** + * Set the day labels' font. + */ + +protected void +setupDayFonts() +{ + Font font; + if (dayButtons == null) return; + + // If null, use what the user gave us + + font = dayFont; + + // Otherwise, use 9/11 of the L&F default for a button + + if (font == null) { + font = UIManager.getFont("Button.font"); + font = font.deriveFont((float)(font.getSize2D() * 9.0 / 11.0)); + } + + // Set the day labels' font + + for (int row = 0; row < 6; row++) { + for (int day = 0; day < 7; day++) { + dayButtons[row][day].setFont(font); + } + } +} + +/** + * Set the time spinner's font. + */ + +protected void +setupTimeFont() +{ + Font font; + if (spinner == null) return; + + // If not null, use what the user gave us + + if (timeFont != null) { + spinner.setFont(timeFont); + } + else { + font = UIManager.getFont("Spinner.font"); + spinner.setFont(font); + } +} + +/** + * Set the font used to display today's date as text. + */ + +protected void +setupTodayFont() +{ + Font font; + if (todaysLabel == null) return; + + // If not null, use what the user gave us + + if (todayFont != null) { + todaysLabel.setFont(todayFont); + } + else { + font = UIManager.getFont("Label.font"); + todaysLabel.setFont(font); + } +} + +//********************************************************************** +// Private +//********************************************************************** + +/** + * Set up the calendar panel with the basic layout and components. + * These are not date specific. + */ + +private void +createCalendarComponents() +{ + // The date panel will hold the calendar and/or the time spinner + + JPanel datePanel = new JPanel(new BorderLayout(2, 2)); + + // Create the calendar if we are displaying a calendar + + if ((selectedComponents & DISPLAY_DATE) > 0) { + formatMonth = new SimpleDateFormat("MMM", locale); + formatWeekDay = new SimpleDateFormat("EEE", locale); + + // Set up the shared keyboard bindings + + setInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, inputMap); + setActionMap(actionMap); + + // Set up the decrement buttons + + yearDecrButton = + new JButton( + new ButtonAction( + "YearDecrButton", + "YearDecrButtonMnemonic", "YearDecrButtonAccelerator", + "YearDecrButtonImage", + "YearDecrButtonShort", "YearDecrButtonLong", + YEAR_DECR_BUTTON)); + monthDecrButton = + new JButton( + new ButtonAction( + "MonthDecrButton", + "MonthDecrButtonMnemonic", "MonthDecrButtonAccelerator", + "MonthDecrButtonImage", + "MonthDecrButtonShort", "MonthDecrButtonLong", + MONTH_DECR_BUTTON)); + JPanel decrPanel = + new JPanel(new FlowLayout(FlowLayout.LEFT, 2, 0)); + decrPanel.add(yearDecrButton); + decrPanel.add(monthDecrButton); + + // Set up the month/year label + + monthYearLabel = new JLabel(); + monthYearLabel.setHorizontalAlignment(JLabel.CENTER); + + // Set up the increment buttons + + monthIncrButton = + new JButton( + new ButtonAction( + "MonthIncrButton", + "MonthIncrButtonMnemonic", "MonthIncrButtonAccelerator", + "MonthIncrButtonImage", + "MonthIncrButtonShort", "MonthIncrButtonLong", + MONTH_INCR_BUTTON)); + yearIncrButton = + new JButton( + new ButtonAction( + "YearIncrButton", + "YearIncrButtonMnemonic", "YearIncrButtonAccelerator", + "YearIncrButtonImage", + "YearIncrButtonShort", "YearIncrButtonLong", + YEAR_INCR_BUTTON)); + JPanel incrPanel = + new JPanel(new FlowLayout(FlowLayout.LEFT, 2, 0)); + incrPanel.add(monthIncrButton); + incrPanel.add(yearIncrButton); + + // Put them all together + + JPanel monthYearNavigator = new JPanel(new BorderLayout(2, 2)); + monthYearNavigator.add(decrPanel, BorderLayout.WEST); + monthYearNavigator.add(monthYearLabel); + monthYearNavigator.add(incrPanel, BorderLayout.EAST); + + // Set up the day panel + + JPanel dayPanel = new JPanel(new GridLayout(7, 7)); + int firstDay = displayCalendar.getFirstDayOfWeek(); + + // Get the week day labels. The following technique is used so + // that we can start the calendar on the right day of the week and + // we can get the week day labels properly localized + + Calendar temp = Calendar.getInstance(locale); + temp.set(2000, Calendar.MARCH, 15); + while (temp.get(Calendar.DAY_OF_WEEK) != firstDay) { + temp.add(Calendar.DATE, 1); + } + dayOfWeekLabels = new JLabel[7]; + for (int i = 0; i < 7; i++) { + Date date = temp.getTime(); + String dayOfWeek = formatWeekDay.format(date); + dayOfWeekLabels[i] = new JLabel(dayOfWeek); + dayOfWeekLabels[i].setHorizontalAlignment(JLabel.CENTER); + dayPanel.add(dayOfWeekLabels[i]); + temp.add(Calendar.DATE, 1); + } + + // Add all the day buttons + + dayButtons = new JToggleButton[6][7]; + dayGroup = new ButtonGroup(); + DayListener dayListener = new DayListener(); + for (int row = 0; row < 6; row++) { + for (int day = 0; day < 7; day++) { + dayButtons[row][day] = new JToggleButton(); + dayButtons[row][day].addItemListener(dayListener); + dayPanel.add(dayButtons[row][day]); + dayGroup.add(dayButtons[row][day]); + } + } + + // We add this special button to the button group, so we have a + // way of unselecting all the visible buttons + + offScreenButton = new JToggleButton("X"); + dayGroup.add(offScreenButton); + + // Combine the navigators and days + + datePanel.add(monthYearNavigator, BorderLayout.NORTH); + datePanel.add(dayPanel); + } + + // Create the time spinner field if we are displaying the time + + if ((selectedComponents & DISPLAY_TIME) > 0) { + + // Create the time component + + spinnerDateModel = new SpinnerDateModel(); + spinnerDateModel.addChangeListener(new TimeListener()); + spinner = new JSpinner(spinnerDateModel); + + JSpinner.DateEditor dateEditor = + new JSpinner.DateEditor(spinner, timePattern); + dateEditor.getTextField().setEditable(false); + dateEditor.getTextField().setHorizontalAlignment(JTextField.CENTER); + spinner.setEditor(dateEditor); + + // Set the input/action maps for the spinner. (Only BACK_SPACE + // seems to work!) + + InputMap sim = new InputMap(); + sim.put(KeyStroke.getKeyStroke("BACK_SPACE"), "setNullDate"); + sim.put(KeyStroke.getKeyStroke("DELETE"), "setNullDate"); + sim.setParent(spinner.getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)); + + ActionMap sam = new ActionMap(); + sam.put( + "setNullDate", + new AbstractAction("setNullDate") { + public void actionPerformed(ActionEvent e) { + JCalendar.this.setDate(null); + }}); + sam.setParent(spinner.getActionMap()); + + spinner.setInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, sim); + spinner.setActionMap(sam); + + // Create a special panel for the time display + + JPanel timePanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 2, 2)); + timePanel.add(spinner); + + // Now add it to the bottom + + datePanel.add(timePanel, BorderLayout.SOUTH); + } + + setLayout(new BorderLayout(2, 2)); + add(datePanel); + + // Add today's date at the bottom of the calendar/time, if needed + + if (isTodayDisplayed) { + Object[] args = { + new Date() + }; + String todaysDate = + MessageFormat.format(bundle.getString("Today"), args); + todaysLabel = new JLabel(todaysDate); + todaysLabel.setHorizontalAlignment(JLabel.CENTER); + + // Add today's date at the very bottom + + add(todaysLabel, BorderLayout.SOUTH); + } +} + +/** + * Update the calendar panel to display the currently selected date. + */ + +private void +updateCalendarComponents() +{ + if ((selectedComponents & DISPLAY_DATE) > 0) { + + // Unselect all visible dates + + offScreenButton.setSelected(true); + + // Get the display date. We only need the month and year + + displayMonth = displayCalendar.get(Calendar.MONTH); + displayYear = displayCalendar.get(Calendar.YEAR); + + // Get the localized display month name and year + + String month = formatMonth.format(displayCalendar.getTime()); + String year = Integer.toString(displayYear); + + { + Object[] args = { + month, + year + }; + monthYearLabel.setText( + MessageFormat.format( + bundle.getString("MonthYearTitle"), args)); + } + + // If the month or year have changed, we need to re-lay out + // the days. Otherwise, we don't + + if (!month.equals(lastMonth) || !year.equals(lastYear)) { + + // Create a temporary calendar that we will use to + // determine where day 1 goes and how many days there are + // in this month + + Calendar temp = (Calendar)displayCalendar.clone(); + temp.set(Calendar.DATE, 1); + + int dayOfWeek = temp.get(Calendar.DAY_OF_WEEK); + int firstDay = temp.getFirstDayOfWeek(); + + // Determine how many blank slots occur before day 1 of this + // month + + int dayPtr; + for (dayPtr = 0; dayPtr < 7; dayPtr++) { + int curDay = ((firstDay - 1) + dayPtr) % 7 + 1; + if (curDay != dayOfWeek) { + dayButtons[0][dayPtr].setText(""); + dayButtons[0][dayPtr].setEnabled(false); + } + else { + break; + } + } + + // Determine the number of days in this month + + int maxDays = temp.getActualMaximum(Calendar.DATE); + + // Fill in the days + + int row = 0; + for (int day = 1; day <= maxDays; day++) { + dayButtons[row][dayPtr].setText(Integer.toString(day)); + dayButtons[row][dayPtr].setEnabled(true); + + // If this is the selected date, select the button; + // otherwise, deselect it + + if (day == selectedDay && + displayMonth == selectedMonth && + displayYear == selectedYear) { + dayButtons[row][dayPtr].setSelected(true); + } + else { + dayButtons[row][dayPtr].getModel().setSelected(false); + } + + // Wrap as needed + + dayPtr = (dayPtr + 1) % 7; + if (dayPtr == 0) row++; + } + + // Set the blanks slots after the last day + + while (row < 6) { + dayButtons[row][dayPtr].setText(""); + dayButtons[row][dayPtr].setEnabled(false); + dayButtons[row][dayPtr].getModel().setSelected(false); + dayPtr = (dayPtr + 1) % 7; + if (dayPtr == 0) row++; + } + } + } + + // Update the time component, if displayed + + if ((selectedComponents & DISPLAY_TIME) > 0) { + + // If no date is selected, we set the date used by the time + // field to today @ noon. We also make the field insensitive + // -- the user must pick a non-null date before being able to + // change the time (unless all we have is a time field) + + if (isNullDate) { + Calendar temp = (Calendar)selectedCalendar.clone(); + temp.setTime(new Date()); + temp.set(Calendar.HOUR, 12); + temp.set(Calendar.MINUTE, 0); + temp.set(Calendar.SECOND, 0); + spinnerDateModel.setValue(temp.getTime()); + spinner.setEnabled((selectedComponents & DISPLAY_DATE) == 0); + } + + // If a date is selected, use it + + else { + spinner.setEnabled(JCalendar.this.isEnabled()); + spinnerDateModel.setValue(selectedCalendar.getTime()); + spinnerDateModel.setStart(null); + spinnerDateModel.setEnd(null); + spinner.revalidate(); + } + } +} + +/** + * Move backward one year. + */ + +private void +yearBackward() +{ + displayCalendar.add(Calendar.YEAR, -1); + updateCalendarComponents(); +} + +/** + * Move forward one year. + */ + +private void +yearForward() +{ + displayCalendar.add(Calendar.YEAR, 1); + updateCalendarComponents(); +} + +/** + * Move backward one month. + */ + +private void +monthBackward() +{ + displayCalendar.add(Calendar.MONTH, -1); + updateCalendarComponents(); +} + +/** + * Move forward one month. + */ + +private void +monthForward() +{ + displayCalendar.add(Calendar.MONTH, 1); + updateCalendarComponents(); +} + +//********************************************************************** +// Inner Classes +//********************************************************************** + +//********************************************************************** +// ButtonAction +//********************************************************************** + +// This inner class is used to define the action associated with a +// button. + +private class ButtonAction + extends AbstractAction +{ + +public final static String SMALL = "16.gif"; +public final static String LARGE = "24.gif"; + +ButtonAction( + String name, + String mnemonic, + String accelerator, + String image, + String shortDescription, + String longDescription, + int actionId) +{ + if (name != null) { + putValue(Action.NAME, bundle.getString(name)); + } + + if (mnemonic != null) { + String mnemonicString = bundle.getString(mnemonic); + if (mnemonicString != null && mnemonicString.length() > 0) { + putValue(Action.MNEMONIC_KEY, + new Integer(bundle.getString(mnemonic).charAt(0))); + } + } + + if (accelerator != null) { + String acceleratorString = bundle.getString(accelerator); + if (accelerator != null && acceleratorString.length() > 0) { + putValue( + Action.ACCELERATOR_KEY, + KeyStroke.getKeyStroke(acceleratorString)); + } + } + + if (image != null) { + String imageName = bundle.getString(image); + if (imageName != null && imageName.length() > 0) { + imageName = "images/" + imageName + SMALL; + URL url = this.getClass().getResource(imageName); + if (url != null) { + putValue(Action.SMALL_ICON, new ImageIcon(url)); + } + } + } + + if (shortDescription != null) { + String shortString = bundle.getString(shortDescription); + if (shortString != null & shortString.length() > 0) { + putValue(Action.SHORT_DESCRIPTION, shortString); + } + } + + if (longDescription != null) { + String longString = bundle.getString(longDescription); + if (longString != null && longString.length() > 0) { + putValue(Action.LONG_DESCRIPTION, longString); + } + } + + putValue("buttonAction", new Integer(actionId)); +} + +public void +actionPerformed( + ActionEvent e) +{ + Integer value = (Integer)getValue("buttonAction"); + switch (value.intValue()) { + case YEAR_DECR_BUTTON: + yearBackward(); + break; + case YEAR_INCR_BUTTON: + yearForward(); + break; + case MONTH_DECR_BUTTON: + monthBackward(); + break; + case MONTH_INCR_BUTTON: + monthForward(); + break; + } +} + +} + +//********************************************************************** +// DayListener +//********************************************************************** + +// This is called when a day button is pressed + +private class DayListener + implements ItemListener +{ + +public void +itemStateChanged( + ItemEvent e) +{ + if (e.getStateChange() == ItemEvent.SELECTED) { + int oldDay = selectedDay; + int oldMonth = selectedMonth; + int oldYear = selectedYear; + + String dayString = ((JToggleButton)e.getItem()).getText(); + try { + selectedDay = Integer.parseInt(dayString); + } + catch (Exception ex) { + selectedDay = 1; + } + selectedMonth = displayMonth; + selectedYear = displayYear; + + if (oldDay != selectedDay || + oldMonth != selectedMonth || + oldYear != selectedYear) { + + isNullDate = false; + selectedCalendar.set(Calendar.YEAR, selectedYear); + selectedCalendar.set(Calendar.MONTH, selectedMonth); + selectedCalendar.set(Calendar.DATE, selectedDay); + + updateCalendarComponents(); + fireDateChange(); + } + } +} + +} + +//********************************************************************** +// TimeListener +//********************************************************************** + +// Called whenever the time field changes + +private class TimeListener + implements ChangeListener +{ + +Calendar lastTemp = null; +Calendar temp = Calendar.getInstance(locale); + +public void +stateChanged( + ChangeEvent e) +{ + Date date = spinnerDateModel.getDate(); + + // We only care about the time portion of the field. If no date is + // selected, we shouldn't be able to change the time (unless there + // is no date to select) + + if (!isNullDate || (selectedComponents & DISPLAY_DATE) == 0) { + temp.setTime(date); + temp.set(Calendar.YEAR, selectedCalendar.get(Calendar.YEAR)); + temp.set(Calendar.MONTH, selectedCalendar.get(Calendar.MONTH)); + temp.set(Calendar.DATE, selectedCalendar.get(Calendar.DATE)); + + // Make sure we change the time only if necessary + + if (lastTemp == null || !lastTemp.equals(temp)) { + setDate(temp.getTime()); + lastTemp = (Calendar)temp.clone(); + } + } +} + +} + +//********************************************************************** +// End Inner Classes +//********************************************************************** + +} diff --git a/libs/FLib/JCalendar/org/freixas/jcalendar/JCalendarCombo.java b/libs/FLib/JCalendar/org/freixas/jcalendar/JCalendarCombo.java new file mode 100644 index 0000000..5515c88 --- /dev/null +++ b/libs/FLib/JCalendar/org/freixas/jcalendar/JCalendarCombo.java @@ -0,0 +1,1448 @@ +//********************************************************************** +// Package +//********************************************************************** + +package org.freixas.jcalendar; + +//********************************************************************** +// Import list +//********************************************************************** + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.border.*; +import javax.swing.event.*; +import javax.swing.plaf.*; +import javax.swing.plaf.basic.*; +import java.beans.*; + +import javax.swing.plaf.metal.MetalComboBoxUI; +import com.sun.java.swing.plaf.motif.MotifComboBoxUI; +import com.sun.java.swing.plaf.windows.WindowsComboBoxUI; +// For Skin L&F +//import com.l2fprod.gui.plaf.skin.SkinComboBoxUI; + +import java.text.*; +import java.net.URL; +import java.util.Calendar; +import java.util.Date; +import java.util.EventListener; +import java.util.Locale; +import java.util.ResourceBundle; + +import javax.accessibility.*; + +/** + * This class is a combo box that allows you to select a date either + * by typing one in (if the combo box is editable) or through a + * JCalendar pop-up. Normally, a combo box expects to use a a popup + * that contains a list. We've perverted this a bit; while you can + * select a variety of dates, the list always has one item which + * changes to match the selected date. + *

+ * You may specify a font for each of the elements that make up the + * pop-up calendar. If you do not specify a font (or specify a null + * font), a reasonable default will be generated based on the current + * Look & Feel. + *

+ * The JCalendarCombo uses a non-mutable ComboBoModel. This means that + * the following methods will generate an exception: + *

+ * You would be ill-advised to to call setModel() with your own + * ComboBoxModel unless you use some variant of a + * JCalendarCombo.CalendarComboBoxModel class. + *

+ * The combo box listeners work pretty much as for normal combo boxes. + * The item changed event reports the date "unselected" (the previous + * date) and "selected" (the new date set), but as Strings. It's + * probably better to add a DateListener and ignore the ItemListener + * and ActionListener. + *

+ * The following key bindings should work (some may depend on the + * selected Look-and-Feel): + *

+ *

+ * This component tries to adapt it's Look-and-Feel to match the + * current Look-and-Feel. But it can only do so for Look-and-Feels's + * that it knows about. To adapt it for new Look-and-Feels, create a + * sub-class: + *


+ *  public class MyCalendarCombo extends JCalendarCombo {
+ *    public void updateUI() {
+ *      ComboBoxUI cui = (ComboBoxUI)UIManager.getUI(this);
+ *      if (cui instanceof SomeLAFComboBoxUI) {
+ *        cui = new SomeLAFCalComboBoxUI();
+ *      }
+ *      else {
+ *        super.updateUI();
+ *      }
+ *    }
+ *    private class SomeLAFCalComboBoxUI extends SomeLAFComboBoxUI {
+ *      return new CalendarComboPopup();
+ *    }
+ *  }
+ * 
+ * If it can't figure out an appropriate Look-and-Feel, it uses the + * Metal Look-and-Feel. + * + * @author Antonio Freixas + */ + +// Copyright © 2003 Antonio Freixas +// All Rights Reserved. + +public class JCalendarCombo + extends JComboBox +{ + +//********************************************************************** +// Public Constants +//********************************************************************** + +/** + * Used to indicate that this component should display the date. + */ + +public static final int DISPLAY_DATE = JCalendar.DISPLAY_DATE; + +/** + * Used to indicate that this component should display the time. + */ + +public static final int DISPLAY_TIME = JCalendar.DISPLAY_TIME; + +//********************************************************************** +// Private Members +//********************************************************************** + +// The currently displayed popup + +static JCalendarCombo currentPopup = null; + +// The locale to use + +private Locale locale; + +// The date format used to display the selected date + +private DateFormat dateFormat; + +// Date formats used for parsing + +private DateFormat parseFormat[]; +private DateFormat timePatternFormat; + +// The components + +private Window parentWindow; +private JWindow oldWindow; +private JWindow calendarWindow; +private JCalendar calendarPanel; + +// True if the calendar panel is displayed + +private boolean isCalendarDisplayed = false; + +// Keep track of the original date in case the date change is canceled + +private Date originalDate = null; + +// Cache the date so we can tell when to take down the calendar + +private Calendar cacheCalendar = null; + +// These maps are used to bind keyboard keys to methods. These maps +// are added to the maps used by JCalendar. + +private static InputMap inputMap = new InputMap(); +private static InputMap spinnerInputMap = new InputMap(); +private static ActionMap actionMap = new ActionMap(); + +// The input map maps a key to a name. The action map maps a name to +// an action. The actions below map the action to a method call + +private static Action setNullDate = new AbstractAction("setNullDate") { + public void actionPerformed(ActionEvent e) { + ((JCalendar)e.getSource()).setDate(null); + ((JCalendar)e.getSource()).getJCalendarComboParent().hideCalendar(); + } +}; + +private static Action cancel = new AbstractAction("cancel") { + public void actionPerformed(ActionEvent e) { + JCalendar cal = (JCalendar)e.getSource(); + JCalendarCombo calCombo = cal.getJCalendarComboParent(); + + cal.setDate(calCombo.originalDate); + calCombo.firePopupMenuCanceled(); + calCombo.hideCalendar(); + } +}; + +private static Action apply = new AbstractAction("apply") { + public void actionPerformed(ActionEvent e) { + JCalendar cal = (JCalendar)e.getSource(); + JCalendarCombo calCombo = cal.getJCalendarComboParent(); + calCombo.hideCalendar(); + } +}; +//********************************************************************** +// Static Constructors +//********************************************************************** + +static +{ + // Set up the input map that will be shared by all instances + + inputMap.put(KeyStroke.getKeyStroke("ESCAPE"), "cancel"); + inputMap.put(KeyStroke.getKeyStroke("UP"), "apply"); + inputMap.put(KeyStroke.getKeyStroke("ENTER"), "apply"); + inputMap.setParent(JCalendar.inputMap); + + actionMap.put("cancel", cancel); + actionMap.put("apply", apply); + actionMap.setParent(JCalendar.actionMap); +} + +//********************************************************************** +// Constructors +//********************************************************************** + +/** + * Create an instance of JCalendarCombo using the default calendar and + * locale. Display the date but not the time. Don't display today's + * date. + */ + +public +JCalendarCombo() +{ + this(Calendar.getInstance(), + Locale.getDefault(), + DISPLAY_DATE, + false, + null); +} + +/** + * Create an instance of JCalendarCombo using the default calendar and + * locale. Display a calendar and a time spinner as requested (to + * display both use DISPLAY_DATE | DISPLAY_TIME). Display today's + * date if requested. Use the default pattern to display the time in the + * time spinner field (if there is one). + * + * @param selectedComponents Use DISPLAY_DATE, DISPLAY_TIME or + * (DISPLAY_DATE | DISPLAY_TIME). + * @param isTodayDisplayed True if today's date should be displayed. + */ + +public +JCalendarCombo( + int selectedComponents, + boolean isTodayDisplayed) +{ + this(Calendar.getInstance(), + Locale.getDefault(), + selectedComponents, + isTodayDisplayed, + null); +} + +/** + * Create an instance of JCalendarCombo using the given calendar and + * locale. Display a calendar and a time spinner as requested (to + * display both use DISPLAY_DATE | DISPLAY_TIME). Display today's + * date if requested. Use the default pattern to display the time in the + * time spinner field (if there is one). + * + * @param calendar The calendar to use. + * @param locale The locale to use. + * @param selectedComponents Use DISPLAY_DATE, DISPLAY_TIME or + * (DISPLAY_DATE | DISPLAY_TIME). + * @param isTodayDisplayed True if today's date should be displayed. + */ + +public +JCalendarCombo( + Calendar calendar, + Locale locale, + int selectedComponents, + boolean isTodayDisplayed) +{ + this(calendar, + locale, + selectedComponents, + isTodayDisplayed, + null); +} + +/** + * Create an instance of JCalendarCombo using the given calendar and + * locale. Display a calendar and a time spinner as requested (to + * display both use DISPLAY_DATE | DISPLAY_TIME). Display today's + * date if requested. Use the default pattern to display the time in the + * time spinner field (if there is one). + * + * @param calendar The calendar to use. + * @param locale The locale to use. + * @param selectedComponents Use DISPLAY_DATE, DISPLAY_TIME or + * (DISPLAY_DATE | DISPLAY_TIME). + * @param isTodayDisplayed True if today's date should be displayed. + * @see DateFormat + * @see SimpleDateFormat + */ + +public +JCalendarCombo( + Calendar calendar, + Locale locale, + int selectedComponents, + boolean isTodayDisplayed, + String timePattern) +{ + super(); + calendarPanel = + new JCalendar( + calendar, + locale, + selectedComponents, + isTodayDisplayed, + timePattern); + this.locale = locale; + + // Set up the parse formats + + parseFormat = new DateFormat[12]; + + parseFormat[0] = + DateFormat.getDateTimeInstance( + DateFormat.SHORT, DateFormat.SHORT, locale); + parseFormat[1] = + DateFormat.getDateTimeInstance( + DateFormat.MEDIUM, DateFormat.MEDIUM, locale); + parseFormat[2] = + DateFormat.getDateTimeInstance( + DateFormat.LONG, DateFormat.LONG, locale); + parseFormat[3] = + DateFormat.getDateTimeInstance( + DateFormat.FULL, DateFormat.FULL, locale); + + parseFormat[4] = DateFormat.getDateInstance(DateFormat.SHORT, locale); + parseFormat[5] = DateFormat.getDateInstance(DateFormat.MEDIUM, locale); + parseFormat[6] = DateFormat.getDateInstance(DateFormat.LONG, locale); + parseFormat[7] = DateFormat.getDateInstance(DateFormat.FULL, locale); + + parseFormat[8] = DateFormat.getTimeInstance(DateFormat.SHORT, locale); + parseFormat[9] = DateFormat.getTimeInstance(DateFormat.MEDIUM, locale); + parseFormat[10] = DateFormat.getTimeInstance(DateFormat.LONG, locale); + parseFormat[11] = DateFormat.getTimeInstance(DateFormat.FULL, locale); + + // Add a format if the timePattern was specified + + if (timePattern != null) { + timePatternFormat = new SimpleDateFormat(timePattern, locale); + } + + if (selectedComponents == DISPLAY_DATE) { + setDateFormat(DateFormat.getDateInstance(DateFormat.FULL, locale)); + } + else if (selectedComponents == DISPLAY_TIME) { + setDateFormat(DateFormat.getTimeInstance(DateFormat.FULL, locale)); + if (timePattern != null) { + timePatternFormat = new SimpleDateFormat(timePattern, locale); + } + } + else { + setDateFormat + (DateFormat.getDateTimeInstance( + DateFormat.FULL, DateFormat.FULL, locale)); + } + + super.setModel(new CalendarComboBoxModel()); + super.setKeySelectionManager(new CalendarKeySelectionManager()); + + createCalendarComponents(); +} + +//********************************************************************** +// Public +//********************************************************************** + +/** + * Add a date listener. This listener will receive events each time + * the selected date changes. + * + * @param listener The date listener to add. + */ + +public void +addDateListener( + DateListener listener) +{ + calendarPanel.addDateListener(listener); +} + +/** + * Remove a date listener. + * + * @param listener The date listener to remove. + */ + +public void +removeDateListener( + DateListener listener) +{ + calendarPanel.removeDateListener(listener); +} + +/** + * Get whether a null date is allowed. + * + * @return The whether a null date is allowed. + */ + +public boolean +isNullAllowed() +{ + return calendarPanel.isNullAllowed(); +} + +/** + * Set whether a null date is allowed. A null date means that no date + * is selected. The user can select a null date by pressing DELETE + * anywhere within the calendar. + *

+ * If nulls are not allowed, a setDate(null) will be ignored without + * error. The DELETE key will do nothing. + *

+ * If you switch from allowing nulls to not allowing nulls and the + * current date is null, it will remain null until a date is selected. + *

+ * The component default is to allow nulls. + * + * @param isNullAllowed The whether a null date is allowed. + */ + +public void +setNullAllowed( + boolean isNullAllowed) +{ + calendarPanel.setNullAllowed(isNullAllowed); +} + +/** + * Get the date currently displayed by the calendar panel. If null, + * then no date was selected. + * + * @return The date currently displayed. + * @see #getCalendar + */ + +public Date +getDate() +{ + return calendarPanel.getDate(); +} + +/** + * Set the calendar panel to display the given date. This will fire a + * DateEvent. + * + * @param date The date to set. + */ + +public void +setDate( + Date date) +{ + calendarPanel.setDate(date); +} + +/** + * Get the date format used to display the selected date in the combo + * box's text field. + * + * @return The date format used to display the selected date in the + * combo box's text field. + */ + +public DateFormat +getDateFormat() +{ + return dateFormat; +} + +/** + * Set the date format used to display the selected date in the combo + * box's text field. Nulls are not allowed. + * + * @param dateFormat The date format used to display the selected date + * in the combo box's text field. + * @throws java.lang.NullPointerException + */ + +public void +setDateFormat( + DateFormat dateFormat) + throws NullPointerException +{ + if (dateFormat == null) { + throw new NullPointerException("Date format cannot be null."); + } + + this.dateFormat = dateFormat; +} + +/** + * Get a copy of the calendar used by this JCalendar. This calendar + * will be set to the currently selected date, so it is an alternative + * to the getDate() method. + * + * @return A copy of the calendar used by JCalendar. + * @see #getDate + */ + +public Calendar +getCalendar() +{ + return calendarPanel.getCalendar(); +} + +/** + * Return the locale used by this JCalendar. + * + * @return The locale used by this JCalendar. + */ + +public Locale +getLocale() +{ + return locale; +} + +/** + * Returns true if today's date is displayed at the bottom of the + * calendar. + * + * @return True if today's date is displayed at the bottom of the + * calendar. + */ + +public boolean +isTodayDisplayed() +{ + return calendarPanel.isTodayDisplayed(); +} + +/** + * Get the title font. + * + * @return The title font. + */ + +public Font +getTitleFont() +{ + return calendarPanel.getTitleFont(); +} + +/** + * If the font is set to null, then the title font (for the Month Year + * title) will default to the L&F's Label default font. + *

+ * Otherwise, the title font is set as given. + * + * @param font The font to set. + */ + +public void +setTitleFont( + Font font) +{ + calendarPanel.setTitleFont(font); +} + +/** + * Get the day-of-week font (Mon, Tue, etc.). + * + * @return The day-of-week font. + */ + +public Font +getDayOfWeekFont() +{ + return calendarPanel.getDayOfWeekFont(); +} + +/** + * If the font is set to null, then the day-of-week font (Mon, Tue, + * etc.) will default to 9/11th's of the L&F's Label default font. + *

+ * Otherwise, the day-of-week font is set as given. + * + * @param font The font to set. + */ + +public void +setDayOfWeekFont( + Font font) +{ + calendarPanel.setDayOfWeekFont(font); +} + +/** + * Get the day font. + * + * @return The day font. + */ + +public Font +getDayFont() +{ + return calendarPanel.getDayFont(); +} + +/** + * If the font is set to null, then the day font will default to + * 9/11th's of the L&F's Button default font. + *

+ * Otherwise, the day font is set as given. + * + * @param font The font to set. + */ + +public void +setDayFont( + Font font) +{ + calendarPanel.setDayFont(font); +} + +/** + * Get the time spinner font. + * + * @return The time spinner font. + */ + +public Font +getTimeFont() +{ + return calendarPanel.getTimeFont(); +} + +/** + * If the font is set to null, then the time spinner font will default + * to the L&F's Spinner default font. + *

+ * Otherwise, the time spinner font is set as given. + * + * @param font The font to set. + */ + +public void +setTimeFont( + Font font) +{ + calendarPanel.setTimeFont(font); +} + +/** + * Get the font used to display today's date as text. + * + * @return The font used to display today's date. + */ + +public Font +getTodayFont() +{ + return calendarPanel.getTodayFont(); +} + +/** + * If the font is set to null, then the font used to display today's + * date as text will default to the L&F's Label default font. + *

+ * Otherwise, the font used to display today's date is set as given. + * + * @param font The font to set. + */ + +public void +setTodayFont( + Font font) +{ + calendarPanel.setTodayFont(font); +} + +/** + * Sets the selected item in the combo box display area to the object + * in the argument. The object should be a String representation of a + * date. + *

+ * If this constitutes a change in the selected item, ItemListeners + * added to the combo box will be notified with one or two ItemEvents. + * If there is a current selected item, an ItemEvent will be fired and + * the state change will be ItemEvent.DESELECTED. If anObject is in + * the list and is not currently selected then an ItemEvent will be + * fired and the state change will be ItemEvent.SELECTED. + *

ActionListeners added to the combo box will be notified with an + * ActionEvent when this method is called (assuming the date actually + * changed). + * + * @param anObject The object to select. + */ + +public void +setSelectedItem( + Object anObject) +{ + getModel().setSelectedItem(anObject); +} + +/** + * This method is ignored. You cannot change the KeySelectionManager + * for JCalendarCombo. + * + * @param aManager The new key selection manager. + */ + +public void +setKeySelectionManager( + JComboBox.KeySelectionManager aManager) +{ +// In JDK1.5, this method is called by BasicComboBoxUI. It did not +// use to get called, so we were able to throw an exception. +// throw new UnsupportedOperationException( +// "The KeySelectionManager for a JCalendarCombo cannot be changed."); +} + +/** + * Resets the UI property to a value from the current look and feel. + * Read the class documentation for instructions on how to override + * this to make the JCalendarCombo support a new Look-and-Feel. + */ + +public void +updateUI() { + ComboBoxUI cui = (ComboBoxUI)UIManager.getUI(this); + if (cui instanceof WindowsComboBoxUI) { + cui = new WindowsDateComboBoxUI(); + } + else if (cui instanceof MetalComboBoxUI) { + cui = new MetalDateComboBoxUI(); + } + else if (cui instanceof MotifComboBoxUI) { + cui = new MotifDateComboBoxUI(); + } +// For Skin L&F +// else if (cui instanceof SkinComboBoxUI) { +// cui = new SkinDateComboBoxUI(); +// } + else { + cui = new MetalDateComboBoxUI(); + } + + setUI(cui); +} + +// The inherited equals and hashCode methods are acceptable as they +// are generally not used for components. + +/** + * {@inheritDoc} + */ + +protected String +paramString() +{ + int selectedComponents = calendarPanel.getSelectedComponents(); + String curDate; + if ((selectedComponents & DISPLAY_DATE) == DISPLAY_DATE) { + curDate = DateFormat.getDateInstance( + DateFormat.FULL, locale).format(getDate()); + } + else if ((selectedComponents & DISPLAY_TIME) == DISPLAY_TIME) { + curDate = DateFormat.getTimeInstance( + DateFormat.FULL, locale).format(getDate()); + } + else { + curDate = DateFormat.getDateTimeInstance( + DateFormat.FULL, DateFormat.FULL, locale).format(getDate()); + } + + return super.paramString() + ",selectedDate=" + curDate; +} + +//********************************************************************** +// Protected +//********************************************************************** + +/** + * Given a date in String form, convert it to a Date object. If no + * conversion is possible, return null. This method tries to parse + * the string using DateFormat and SHORT, MEDIUM, LONG and FULL forms. + * If none of these work, a null date is returned. + * + * @param string The date in String form. + * @return The equivalent Date object or null. + */ + +protected Date +stringToDate( + String string) +{ + if (string == null || string.length() < 1) return null; + + Date date = null; + if (timePatternFormat != null) { + try { + date = timePatternFormat.parse(string); + } + catch (ParseException e) { } + } + + try { + date = dateFormat.parse(string); + } + catch (ParseException e) { } + + if (date == null) { + for (int i = 0; i < parseFormat.length; i++) { + try { + date = parseFormat[i].parse(string); + } + catch (ParseException e) { } + if (date != null) break; + } + } + + return date; +} + +//********************************************************************** +// Private +//********************************************************************** + +/** + * Set up the calendar combo box layout and components. These are not + * date specific. + */ + +private void +createCalendarComponents() +{ + // Set the combo parent of the calendar panel + + calendarPanel.setJCalendarComboParent(this); + + // Add some extra key bindings to the calendar panel. Note that + // this input map has a parent InputMap from JCalendar + + calendarPanel.setInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, inputMap); + calendarPanel.setActionMap(actionMap); + + // Add some extra key bindings to the spinner in the calendar + // panel (this doesn't seem to work!) + + if ((calendarPanel.getSelectedComponents() & DISPLAY_TIME) > 0) { + InputMap sim = new InputMap(); + sim.put(KeyStroke.getKeyStroke("ESCAPE"), "cancel"); + sim.put(KeyStroke.getKeyStroke("ENTER"), "apply"); + + ActionMap sam = new ActionMap(); + sam.put( + "cancel", + new AbstractAction("cancel") { + public void actionPerformed(ActionEvent e) { + JCalendarCombo calCombo = JCalendarCombo.this; + calendarPanel.setDate(calCombo.originalDate); + calCombo.firePopupMenuCanceled(); + calCombo.hideCalendar(); + }}); + sam.put( + "apply", + new AbstractAction("apply") { + public void actionPerformed(ActionEvent e) { + JCalendarCombo calCombo = JCalendarCombo.this; + calCombo.hideCalendar(); + }}); + + calendarPanel.addSpinnerMaps(sim, sam); + } + + // Add a border for the calendar panel + + Border border = (Border)UIManager.get("PopupMenu.border"); + if (border == null) { + border = new BevelBorder(BevelBorder.RAISED); + } + + calendarPanel.setBorder(border); + + // Add a listener for date events + + calendarPanel.addDateListener(new CalDateListener()); + + // Add a listener for ancestor events + + addAncestorListener(new ComboAncestorListener()); +} + +/** + * Make the calendar panel invisible. + */ + +private void +hideCalendar() +{ + if (isCalendarDisplayed) { + + // If it's visible, make it invisible + + firePopupMenuWillBecomeInvisible(); + + calendarWindow.setVisible(false); + isCalendarDisplayed = false; + requestFocus(); + if (currentPopup == this) currentPopup = null; + } +} + +/** + * Make the calendar panel visible. + */ + +private void +showCalendar() +{ + if (!isCalendarDisplayed) { + + // If another JCalendarCombo popup is visible, hide it + + if (currentPopup != null) currentPopup.hideCalendar(); + + firePopupMenuWillBecomeVisible(); + + // If the combo box is editable, we need to convert the edit + // field into a date before bringing up the calendar. If the + // combo box is not editable, then the calendar already + // contains the selected date + + if (isEditable()) { + setSelectedItem(getEditor().getItem()); + getEditor().selectAll(); + } + + Window oldParentWindow = parentWindow; + parentWindow = SwingUtilities.getWindowAncestor(this); + if (parentWindow == null) return; + + // If we don't have a window or if we need to reparent the + // window... + + if (calendarWindow == null || parentWindow != oldParentWindow) { + + // If a window exists, get rid of it + + if (calendarWindow != null) calendarWindow.dispose(); + + // Create the new window and add the calendar panel + + calendarWindow = new JWindow(parentWindow); + calendarWindow.getContentPane().add(calendarPanel); + calendarWindow.pack(); + } + + // Now position the window properly + + Point fieldLocation = getLocationOnScreen(); + Dimension fieldSize = getSize(); + Dimension windowSize = calendarWindow.getSize(); + Dimension screenSize = getToolkit().getScreenSize(); + + int x = fieldLocation.x + (fieldSize.width - windowSize.width); + int y = fieldLocation.y + fieldSize.height; + + // Adjust the x position to keep the calendar window on the + // screen as much as possible + + if (x + windowSize.width > screenSize.width) { + x = screenSize.width - windowSize.width; + } + if (x < 0) x = 0; + + // Adjust the y position to keep the calendar window on the + // screen. We are already set to display below the text field; + // if that doesn't work, we display it above + + if (y + windowSize.height > screenSize.height) { + y = fieldLocation.y - windowSize.height; + } + + // Reset the displayed date to include the selected date (or + // today's date if the selected date is null) + + originalDate = calendarPanel.getDate(); + calendarPanel.setDisplayDate(originalDate); + cacheCalendar = calendarPanel.getCalendar(); + + // Make it visible + + calendarWindow.setLocation(x, y); + calendarWindow.setVisible(true); + isCalendarDisplayed = true; + currentPopup = this; + } +} + +/** + * Toggle the display of the calendar panel. + */ + +private void +toggleCalendar() +{ + if (isCalendarDisplayed) { + hideCalendar(); + } + else { + showCalendar(); + } +} + +//********************************************************************** +// Inner Classes +//********************************************************************** + +//////////////////////////////////////////////////////////////////////// +// Class MetalDateComboBoxUI +//////////////////////////////////////////////////////////////////////// + +// Override the MetalComboBoxUI to add a Calendar pop-up + +private class MetalDateComboBoxUI + extends MetalComboBoxUI +{ + +protected ComboPopup createPopup() { + return new CalendarComboPopup(); +} + +} + +//////////////////////////////////////////////////////////////////////// +// Class WindowsDateComboBoxUI +//////////////////////////////////////////////////////////////////////// + +// Override the WindowsComboBoxUI to add a Calendar pop-up + +class WindowsDateComboBoxUI + extends WindowsComboBoxUI +{ + +protected ComboPopup createPopup() { + return new CalendarComboPopup(); +} + +} + +//////////////////////////////////////////////////////////////////////// +// Class MotifDateComboBoxUI +//////////////////////////////////////////////////////////////////////// + +// Override the MotifComboBoxUI to add a Calendar pop-up + +class MotifDateComboBoxUI + extends MotifComboBoxUI +{ + +protected ComboPopup createPopup() { + return new CalendarComboPopup(); +} + +} + +//////////////////////////////////////////////////////////////////////// +// Class SkinDateComboBoxUI +//////////////////////////////////////////////////////////////////////// + +// Override the SkinComboBoxUI to add a Calendar pop-up + +// For Skin L&F +// class SkinDateComboBoxUI +// extends SkinComboBoxUI +// { + +// protected ComboPopup createPopup() { +// return new CalendarComboPopup(); +// } + +// } + +//////////////////////////////////////////////////////////////////////// +// Class CalDateListener +//////////////////////////////////////////////////////////////////////// + +// This class listens for calendar events in the calendarPanel and +// passes the selection change to the combo box. The calendar pop-up +// is also made invisible if the date (not just the time) changes + +private class CalDateListener + implements DateListener +{ + +public void +dateChanged( + DateEvent e) +{ + Calendar cal = e.getSelectedDate(); + + if (cal == null) { + setSelectedItem(null); + } + else { + setSelectedItem(dateFormat.format(e.getSelectedDate().getTime())); + } + + // Hide the calendar only if the day changes (ignore the time) + + if (cal == null && cacheCalendar == null) return; + if (cal != null && cacheCalendar != null) { + if (cal.get(Calendar.YEAR) == cacheCalendar.get(Calendar.YEAR) && + cal.get(Calendar.MONTH) == cacheCalendar.get(Calendar.MONTH) && + cal.get(Calendar.DATE) == cacheCalendar.get(Calendar.DATE)) { + return; + } + } + hideCalendar(); +} + +} + +//////////////////////////////////////////////////////////////////////// +// Class CalendarComboBoxModel +//////////////////////////////////////////////////////////////////////// + +// This is the ComboBoxModel used for calendars. + +protected class CalendarComboBoxModel + implements ComboBoxModel +{ + +protected EventListenerList listenerList = new EventListenerList(); + +// Add a ListDataListener + +public void +addListDataListener( + ListDataListener l) +{ + listenerList.add(ListDataListener.class, l); +} + +// Remove a ListDataListener + +public void +removeListDataListener( + ListDataListener l) +{ + listenerList.remove(ListDataListener.class, l); +} + +// Look at the calendarPanel and get its date in String form, using +// the user's selected DateFormat. We ignore the index as our +// "pretend" list has only one item -- the date in the calendar. + +public Object +getElementAt( + int index) +{ + return getSelectedItem(); +} + +// The list size is always 1 + +public int +getSize() +{ + return 1; +} + +// Get the selected date in String form. Null dates are converted to +// empty strings + +public Object +getSelectedItem() +{ + Date date = calendarPanel.getDate(); + if (date == null) return ""; + return dateFormat.format(date); +} + +// Set the selected date. We get the source date by calling the +// toString() method of the item passed in. This gets converted to a +// Date which is applied to the calendarPanel and to the combo box +// editor (if the combo box is editable). If we note that either had +// to be changed, we fire an action event and an item change event + +public void +setSelectedItem( + Object anItem) +{ + // Get the date to set + + Date date = null; + if (anItem != null) date = stringToDate(anItem.toString()); + + // This method may be called because: + // - of a direct call by a programmer + // - of a DateEvent (the user selected a date on the calendar) + // - of a change in the editor (the user typed in a new date) + // We want to fire an event only if there is a change to either + // the calendar date or the editor date + + boolean fireEvent = false; + + Date calDate = calendarPanel.getDate(); + if (date == null && calDate != null || + date != null && !date.equals(calDate)) { + + fireEvent = true; + calendarPanel.setDate(date); + } + + if (isEditable()) { + Object editorItem = getEditor().getItem(); + Date editorDate = null; + if (editorItem != null) { + editorDate = stringToDate(editorItem.toString()); + } + if (date == null && editorDate != null || + date != null && !date.equals(editorDate)) { + + fireEvent = true; + if (date == null) { + getEditor().setItem(""); + } + else { + getEditor().setItem(dateFormat.format(date)); + } + } + } + + if (fireEvent) { + + // This method will cause an Action event to be fired + + fireContentsChanged(this, -1, -1); + } +} + +// Generate contentChanged() events + +private void +fireContentsChanged( + Object source, + int index0, + int index1) +{ + Object[] listeners = listenerList.getListenerList(); + ListDataEvent e = null; + + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == ListDataListener.class) { + if (e == null) { + e = new ListDataEvent( + source, ListDataEvent.CONTENTS_CHANGED, index0, index1); + } + ((ListDataListener)listeners[i+1]).contentsChanged(e); + } + } +} + +} + +//////////////////////////////////////////////////////////////////////// +// Class CalendarKeySelectionManager +//////////////////////////////////////////////////////////////////////// + +// We use this KeySelectionManager which has no key selections + +private class CalendarKeySelectionManager + implements JComboBox.KeySelectionManager +{ + +public int +selectionForKey( + char aKey, + ComboBoxModel aModel) +{ + // There are no key selections + return -1; +} + +} + +//////////////////////////////////////////////////////////////////////// +// Class CalendarComboPopup +//////////////////////////////////////////////////////////////////////// + +// This is the calendar pop-up + +protected class CalendarComboPopup + implements ComboPopup +{ + +private JList list = new JList(); +private MouseListener mouseListener = null; + + +// There is no key listener + +public KeyListener +getKeyListener() +{ + return null; +} + +// We return a JList with no items + +public JList +getList() +{ + return list; +} + +// Create a mouse listener which is used to display the combo pop-up +// on a mouse press + +public MouseListener +getMouseListener() +{ + if (mouseListener == null) { + mouseListener = new InvocationMouseListener(); + } + return mouseListener; +} + +// There is no mouse motion listerne + +public MouseMotionListener +getMouseMotionListener() +{ + return null; +} + +// Determine if the pop-up is visible + +public boolean +isVisible() +{ + return isCalendarDisplayed; +} +// Hide the calendar. The work is done elsewhere + +public void +hide() +{ + hideCalendar(); +} + +// Show the calendar. The work is done elsewhere + +public void +show() +{ + showCalendar(); +} + +// I'm not sure there's anything we need to do here + +public void +uninstallingUI() +{ +} + +} + +//////////////////////////////////////////////////////////////////////// +// Class ComboAncestorListener +//////////////////////////////////////////////////////////////////////// + +// Hide the calendar if anything happens to its ancestor + +private class ComboAncestorListener + implements AncestorListener +{ + +public void +ancestorAdded( + AncestorEvent e) +{ + hideCalendar(); +} + +public void +ancestorRemoved( + AncestorEvent e) +{ + hideCalendar(); +} + +public void +ancestorMoved( + AncestorEvent e) +{ + hideCalendar(); +} + +} + +//////////////////////////////////////////////////////////////////////// +// Class InvocationMouseListener +//////////////////////////////////////////////////////////////////////// + +// A listener to be registered upon the combo box (not its popup menu) +// to handle mouse events that affect the state of the popup menu. The +// main purpose of this listener is to make the popup menu appear and +// disappear. + +private class InvocationMouseListener + extends MouseAdapter +{ +public void +mousePressed( + MouseEvent e) +{ + if (!SwingUtilities.isLeftMouseButton(e) || !isEnabled()) + return; + + toggleCalendar(); +} + +} + +//********************************************************************** +// End Inner Classes +//********************************************************************** + +} diff --git a/libs/FLib/JCalendar/org/freixas/jcalendar/images/Back16.gif b/libs/FLib/JCalendar/org/freixas/jcalendar/images/Back16.gif new file mode 100644 index 0000000..945dd14 Binary files /dev/null and b/libs/FLib/JCalendar/org/freixas/jcalendar/images/Back16.gif differ diff --git a/libs/FLib/JCalendar/org/freixas/jcalendar/images/Back24.gif b/libs/FLib/JCalendar/org/freixas/jcalendar/images/Back24.gif new file mode 100644 index 0000000..3815623 Binary files /dev/null and b/libs/FLib/JCalendar/org/freixas/jcalendar/images/Back24.gif differ diff --git a/libs/FLib/JCalendar/org/freixas/jcalendar/images/FastForward16.gif b/libs/FLib/JCalendar/org/freixas/jcalendar/images/FastForward16.gif new file mode 100644 index 0000000..679d894 Binary files /dev/null and b/libs/FLib/JCalendar/org/freixas/jcalendar/images/FastForward16.gif differ diff --git a/libs/FLib/JCalendar/org/freixas/jcalendar/images/FastForward24.gif b/libs/FLib/JCalendar/org/freixas/jcalendar/images/FastForward24.gif new file mode 100644 index 0000000..814664c Binary files /dev/null and b/libs/FLib/JCalendar/org/freixas/jcalendar/images/FastForward24.gif differ diff --git a/libs/FLib/JCalendar/org/freixas/jcalendar/images/Forward16.gif b/libs/FLib/JCalendar/org/freixas/jcalendar/images/Forward16.gif new file mode 100644 index 0000000..a8bfcf5 Binary files /dev/null and b/libs/FLib/JCalendar/org/freixas/jcalendar/images/Forward16.gif differ diff --git a/libs/FLib/JCalendar/org/freixas/jcalendar/images/Forward24.gif b/libs/FLib/JCalendar/org/freixas/jcalendar/images/Forward24.gif new file mode 100644 index 0000000..572467c Binary files /dev/null and b/libs/FLib/JCalendar/org/freixas/jcalendar/images/Forward24.gif differ diff --git a/libs/FLib/JCalendar/org/freixas/jcalendar/images/Rewind16.gif b/libs/FLib/JCalendar/org/freixas/jcalendar/images/Rewind16.gif new file mode 100644 index 0000000..3f1b1e6 Binary files /dev/null and b/libs/FLib/JCalendar/org/freixas/jcalendar/images/Rewind16.gif differ diff --git a/libs/FLib/JCalendar/org/freixas/jcalendar/images/Rewind24.gif b/libs/FLib/JCalendar/org/freixas/jcalendar/images/Rewind24.gif new file mode 100644 index 0000000..4e77dde Binary files /dev/null and b/libs/FLib/JCalendar/org/freixas/jcalendar/images/Rewind24.gif differ diff --git a/libs/FLib/JCalendar/project.dtd b/libs/FLib/JCalendar/project.dtd new file mode 100644 index 0000000..dee3c51 --- /dev/null +++ b/libs/FLib/JCalendar/project.dtd @@ -0,0 +1,5193 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/FLib/JWizard/License.txt b/libs/FLib/JWizard/License.txt new file mode 100644 index 0000000..be12e9d --- /dev/null +++ b/libs/FLib/JWizard/License.txt @@ -0,0 +1,123 @@ + Artistic License + +Preamble + +The intent of this document is to state the conditions under which a +Package may be copied, such that the Copyright Holder maintains some +semblance of artistic control over the development of the package, +while giving the users of the package the right to use and distribute +the Package in a more-or-less customary fashion, plus the right to +make reasonable modifications. + +Definitions: + + * "Package" refers to the collection of files distributed by the + Copyright Holder, and derivatives of that collection of files + created through textual modification. + + * "Standard Version" refers to such a Package if it has not been + modified, or has been modified in accordance with the wishes of + the Copyright Holder. + + * "Copyright Holder" is whoever is named in the copyright or + copyrights for the package. + + * "You" is you, if you're thinking about copying or distributing + this Package. + + * "Reasonable copying fee" is whatever you can justify on the + basis of media cost, duplication charges, time of people + involved, and so on. (You will not be required to justify it to + the Copyright Holder, but only to the computing community at + large as a market that must bear the fee.) + + * "Freely Available" means that no fee is charged for the item + itself, though there may be fees involved in handling the item. + It also means that recipients of the item may redistribute it + under the same conditions they received it. + +1. You may make and give away verbatim copies of the source form of + the Standard Version of this Package without restriction, provided + that you duplicate all of the original copyright notices and + associated disclaimers. + +2. You may apply bug fixes, portability fixes and other modifications + derived from the Public Domain or from the Copyright Holder. A + Package modified in such a way shall still be considered the + Standard Version. + +3. You may otherwise modify your copy of this Package in any way, + provided that you insert a prominent notice in each changed file + stating how and when you changed that file, and provided that you + do at least ONE of the following: + + a) place your modifications in the Public Domain or otherwise make + them Freely Available, such as by posting said modifications to + Usenet or an equivalent medium, or placing the modifications on + a major archive site such as ftp.uu.net, or by allowing the + Copyright Holder to include your modifications in the Standard + Version of the Package. + + b) use the modified Package only within your corporation or + organization. + + c) rename any non-standard executables so the names do not + conflict with standard executables, which must also be + provided, and provide a separate manual page for each + non-standard executable that clearly documents how it differs + from the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + +4. You may distribute the programs of this Package in object code or + executable form, provided that you do at least ONE of the + following: + + a) distribute a Standard Version of the executables and library + files, together with instructions (in the manual page or + equivalent) on where to get the Standard Version. + + b) accompany the distribution with the machine-readable source of + the Package with your modifications. + + c) accompany any non-standard executables with their corresponding + Standard Version executables, giving the non-standard + executables non-standard names, and clearly documenting the + differences in manual pages (or equivalent), together with + instructions on where to get the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + +5. You may charge a reasonable copying fee for any distribution of + this Package. You may charge any fee you choose for support of this + Package. You may not charge a fee for this Package itself. However, + you may distribute this Package in aggregate with other (possibly + commercial) programs as part of a larger (possibly commercial) + software distribution provided that you do not advertise this + Package as a product of your own. + +6. The scripts and library files supplied as input to or produced as + output from the programs of this Package do not automatically fall + under the copyright of this Package, but belong to whomever + generated them, and may be sold commercially, and may be aggregated + with this Package. + +7. C or perl subroutines supplied by you and linked into this Package + shall not be considered part of this Package. + +8. Aggregation of this Package with a commercial distribution is + always permitted provided that the use of this Package is embedded; + that is, when no overt attempt is made to make this Package's + interfaces visible to the end user of the commercial distribution. + Such use shall not be construed as a distribution of this Package. + +9. The name of the Copyright Holder may not be used to endorse or + promote products derived from this software without specific prior + written permission. + +10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + PURPOSE. + +The End diff --git a/libs/FLib/JWizard/README.txt b/libs/FLib/JWizard/README.txt new file mode 100644 index 0000000..6698b99 --- /dev/null +++ b/libs/FLib/JWizard/README.txt @@ -0,0 +1,26 @@ + JWizard + +This package provides a Wizard component for use in Java programs. + +This program is free software; you can redistribute it and/or modify +it under the terms of the Artistic License. You should have received a +copy of the Artistic License along with this program (in file +License.txt). If not, a copy is available at + + http://opensource.org/licenses/artistic-license.php + +To build it you'll need Ant. I used version 1.6.2. Use + + ant all + +This will create build/jwizard.jar. To create the API documentation, use + + ant javadoc + +To view all the documentation, view doc/index.html. + +There is a tutorial in doc/tutorial.html. There is also a sample Java +program that uses the JWizard package. You can build and run this +program with + + ant runExample1 diff --git a/libs/FLib/JWizard/build.xml b/libs/FLib/JWizard/build.xml new file mode 100644 index 0000000..d8e7ceb --- /dev/null +++ b/libs/FLib/JWizard/build.xml @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/FLib/JWizard/doc-templates/License.html b/libs/FLib/JWizard/doc-templates/License.html new file mode 100644 index 0000000..d5fbdc1 --- /dev/null +++ b/libs/FLib/JWizard/doc-templates/License.html @@ -0,0 +1,180 @@ + + + + + + +

Artistic License

+ +

Preamble

+ +

The intent of this document is to state the conditions under which a + Package may be copied, such that the Copyright Holder maintains some + semblance of artistic control over the development of the package, + while giving the users of the package the right to use and distribute + the Package in a more-or-less customary fashion, plus the right to + make reasonable modifications.

+ +

Definitions:

+ +
    + +
  • "Package" refers to the collection of files distributed by the + Copyright Holder, and derivatives of that collection of files created + through textual modification.
  • + +
  • "Standard Version" refers to such a Package if it has not been + modified, or has been modified in accordance with the wishes of the + Copyright Holder.
  • + +
  • "Copyright Holder" is whoever is named in the copyright or + copyrights for the package.
  • + +
  • "You" is you, if you're thinking about copying or distributing + this Package.
  • + +
  • "Reasonable copying fee" is whatever you can justify on the basis + of media cost, duplication charges, time of people involved, and so + on. (You will not be required to justify it to the Copyright Holder, + but only to the computing community at large as a market that must + bear the fee.)
  • + +
  • "Freely Available" means that no fee is charged for the item + itself, though there may be fees involved in handling the item. It + also means that recipients of the item may redistribute it under the + same conditions they received it.
  • + +
+ +
+ +
    + +
  1. You may make and give away verbatim copies of the source form of + the Standard Version of this Package without restriction, provided + that you duplicate all of the original copyright notices and + associated disclaimers.
  2. + +
  3. You may apply bug fixes, portability fixes and other modifications + derived from the Public Domain or from the Copyright Holder. A Package + modified in such a way shall still be considered the Standard + Version.
  4. + +
  5. You may otherwise modify your copy of this Package in any way, + provided that you insert a prominent notice in each changed file + stating how and when you changed that file, and provided that you do + at least ONE of the following: + +
      + +
    1. place your modifications in the Public Domain or otherwise make + them Freely Available, such as by posting said modifications to Usenet + or an equivalent medium, or placing the modifications on a major + archive site such as ftp.uu.net, or by allowing the Copyright Holder + to include your modifications in the Standard Version of the Package.
    2. + +
    3. use the modified Package only within your corporation or + organization.
    4. + +
    5. rename any non-standard executables so the names do not conflict + with standard executables, which must also be provided, and provide a + separate manual page for each non-standard executable that clearly + documents how it differs from the Standard Version.
    6. + +
    7. make other distribution arrangements with the Copyright + Holder.
    8. + +
    +
  6. + +
  7. You may distribute the programs of this Package in object code or + executable form, provided that you do at least ONE of the following: + +
      + +
    1. distribute a Standard Version of the executables and library + files, together with instructions (in the manual page or equivalent) + on where to get the Standard Version.
    2. + +
    3. accompany the distribution with the machine-readable source of the + Package with your modifications.
    4. + +
    5. accompany any non-standard executables with their corresponding + Standard Version executables, giving the non-standard executables + non-standard names, and clearly documenting the differences in manual + pages (or equivalent), together with instructions on where to get the + Standard Version.
    6. + +
    7. make other distribution arrangements with the Copyright + Holder.
    8. + +
    +
  8. + +
  9. You may charge a reasonable copying fee for any distribution of + this Package. You may charge any fee you choose for support of this + Package. You may not charge a fee for this Package itself. However, + you may distribute this Package in aggregate with other (possibly + commercial) programs as part of a larger (possibly commercial) + software distribution provided that you do not advertise this Package + as a product of your own.
  10. + +
  11. The scripts and library files supplied as input to or produced as + output from the programs of this Package do not automatically fall + under the copyright of this Package, but belong to whomever generated + them, and may be sold commercially, and may be aggregatedwith this + Package.
  12. + +
  13. r perl subroutines supplied by you and linked into this Package + shall not be considered part of this Package.
  14. + +
  15. Aggregation of this Package with a commercial distribution is + always permitted provided that the use of this Package is embedded; + that is, when no overt attempt is made to make this Package's + interfaces visible to the end user of the commercial distribution. + Such use shall not be construed as a distribution of this Package.
  16. + +
  17. The name of the Copyright Holder may not be used to endorse or + promote products derived from this software without specific prior + written permission.
  18. + +
  19. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + PURPOSE.
  20. + +
+ +

The End

+ + diff --git a/libs/FLib/JWizard/doc/example/Example1.gif b/libs/FLib/JWizard/doc/example/Example1.gif new file mode 100644 index 0000000..15ea4b1 Binary files /dev/null and b/libs/FLib/JWizard/doc/example/Example1.gif differ diff --git a/libs/FLib/JWizard/doc/example/Example1.java b/libs/FLib/JWizard/doc/example/Example1.java new file mode 100644 index 0000000..60ef098 --- /dev/null +++ b/libs/FLib/JWizard/doc/example/Example1.java @@ -0,0 +1,701 @@ +//********************************************************************** +// Package +//********************************************************************** + +package doc.example; + +//********************************************************************** +// Import list +//********************************************************************** + +import java.io.File; +import java.net.URL; +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import org.freixas.jwizard.*; + +/** + * This class simulates an installation Wizard using the FLib JWizard + * component. + *
+ * This program is free software; you can redistribute it and/or + * modify it under the terms of the Artistic License. You should have + * received a copy of the Artistic License along with this program. If + * not, a copy is available at + * + * opensource.org. + * + * @author Antonio Freixas + */ + +// Copyright © 2004 Antonio Freixas +// All Rights Reserved. + +class Example1 + extends JWizardDialog +{ + +//********************************************************************** +// Public Constants +//********************************************************************** + +//********************************************************************** +// Private Constants +//********************************************************************** + +static final String LICENSE = +"Artistic License\n" + +"\n" + +"Preamble\n" + +"\n" + +"The intent of this document is to state the conditions under which a\n" + +"Package may be copied, such that the Copyright Holder maintains some\n" + +"semblance of artistic control over the development of the package,\n" + +"while giving the users of the package the right to use and distribute\n" + +"the Package in a more-or-less customary fashion, plus the right to\n" + +"make reasonable modifications.\n" + +"\n" + +"Definitions:\n" + +"\n" + +" * \"Package\" refers to the collection of files distributed by the\n" + +" Copyright Holder, and derivatives of that collection of files\n" + +" created through textual modification.\n" + +"\n" + +" * \"Standard Version\" refers to such a Package if it has not been\n" + +" modified, or has been modified in accordance with the wishes of\n" + +" the Copyright Holder.\n" + +"\n" + +" * \"Copyright Holder\" is whoever is named in the copyright or\n" + +" copyrights for the package.\n" + +"\n" + +" * \"You\" is you, if you're thinking about copying or distributing\n" + +" this Package.\n" + +"\n" + +" * \"Reasonable copying fee\" is whatever you can justify on the\n" + +" basis of media cost, duplication charges, time of people\n" + +" involved, and so on. (You will not be required to justify it to\n" + +" the Copyright Holder, but only to the computing community at\n" + +" large as a market that must bear the fee.)\n" + +"\n" + +" * \"Freely Available\" means that no fee is charged for the item\n" + +" itself, though there may be fees involved in handling the item.\n" + +" It also means that recipients of the item may redistribute it\n" + +" under the same conditions they received it.\n" + +"\n" + +"1. You may make and give away verbatim copies of the source form of\n" + +" the Standard Version of this Package without restriction, provided\n" + +" that you duplicate all of the original copyright notices and\n" + +" associated disclaimers.\n" + +"\n" + +"2. You may apply bug fixes, portability fixes and other modifications\n" + +" derived from the Public Domain or from the Copyright Holder. A\n" + +" Package modified in such a way shall still be considered the\n" + +" Standard Version.\n" + +"\n" + +"3. You may otherwise modify your copy of this Package in any way,\n" + +" provided that you insert a prominent notice in each changed file\n" + +" stating how and when you changed that file, and provided that you\n" + +" do at least ONE of the following:\n" + +"\n" + +" a) place your modifications in the Public Domain or otherwise make\n" + +" them Freely Available, such as by posting said modifications to\n" + +" Usenet or an equivalent medium, or placing the modifications on\n" + +" a major archive site such as ftp.uu.net, or by allowing the\n" + +" Copyright Holder to include your modifications in the Standard\n" + +" Version of the Package.\n" + +"\n" + +" b) use the modified Package only within your corporation or\n" + +" organization.\n" + +"\n" + +" c) rename any non-standard executables so the names do not\n" + +" conflict with standard executables, which must also be\n" + +" provided, and provide a separate manual page for each\n" + +" non-standard executable that clearly documents how it differs\n" + +" from the Standard Version.\n" + +"\n" + +" d) make other distribution arrangements with the Copyright Holder.\n" + +"\n" + +"4. You may distribute the programs of this Package in object code or\n" + +" executable form, provided that you do at least ONE of the\n" + +" following:\n" + +"\n" + +" a) distribute a Standard Version of the executables and library\n" + +" files, together with instructions (in the manual page or\n" + +" equivalent) on where to get the Standard Version.\n" + +"\n" + +" b) accompany the distribution with the machine-readable source of\n" + +" the Package with your modifications.\n" + +"\n" + +" c) accompany any non-standard executables with their corresponding\n" + +" Standard Version executables, giving the non-standard\n" + +" executables non-standard names, and clearly documenting the\n" + +" differences in manual pages (or equivalent), together with\n" + +" instructions on where to get the Standard Version.\n" + +"\n" + +" d) make other distribution arrangements with the Copyright Holder.\n" + +"\n" + +"5. You may charge a reasonable copying fee for any distribution of\n" + +" this Package. You may charge any fee you choose for support of this\n" + +" Package. You may not charge a fee for this Package itself. However,\n" + +" you may distribute this Package in aggregate with other (possibly\n" + +" commercial) programs as part of a larger (possibly commercial)\n" + +" software distribution provided that you do not advertise this\n" + +" Package as a product of your own.\n" + +"\n" + +"6. The scripts and library files supplied as input to or produced as\n" + +" output from the programs of this Package do not automatically fall\n" + +" under the copyright of this Package, but belong to whomever\n" + +" generated them, and may be sold commercially, and may be aggregated\n" + +" with this Package.\n" + +"\n" + +"7. C or perl subroutines supplied by you and linked into this Package\n" + +" shall not be considered part of this Package.\n" + +"\n" + +"8. Aggregation of this Package with a commercial distribution is\n" + +" always permitted provided that the use of this Package is embedded;\n" + +" that is, when no overt attempt is made to make this Package's\n" + +" interfaces visible to the end user of the commercial distribution.\n" + +" Such use shall not be construed as a distribution of this Package.\n" + +"\n" + +"9. The name of the Copyright Holder may not be used to endorse or\n" + +" promote products derived from this software without specific prior\n" + +" written permission.\n" + +"\n" + +"10. THIS PACKAGE IS PROVIDED \"AS IS\" AND WITHOUT ANY EXPRESS OR\n" + +" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\n" + +" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR\n" + +" PURPOSE.\n" + +"\n" + +"The End\n"; + +//********************************************************************** +// Private Members +//********************************************************************** + +private File installationFolder; +private boolean standardInstall = true; +private boolean installProgram = true; +private boolean installDocumentation = true; +private boolean installExamples = true; + +//********************************************************************** +// main +//********************************************************************** + +public static void +main( + String[] args) +{ + new Example1(); + System.exit(0); +} + +//********************************************************************** +// Constructors +//********************************************************************** + +/** + * Create an instance of Example1. Note that this class is a subclass + * of JWizardDialog. + */ + +public +Example1() +{ + // We want the dialog modal -- when the dialog is finished, we + // exit the program + + setModal(true); + + // Set the dialog title. This is the title for the wizard as a + // whole + + setTitle("Install Example1"); + + // Set the logo image + + URL url = getClass().getResource("Example1.gif"); + setWizardIcon(new ImageIcon(url)); + + // Create each step + + addWizardPanel(new Step0()); + addWizardPanel(new Step1()); + addWizardPanel(new Step2()); + addWizardPanel(new Step3()); + addWizardPanel(new Step4()); + addWizardPanel(new Step5()); + addWizardPanel(new Step6()); + + // We don't want to have the cancel button enabled when we're done + + disableCancelAtEnd(); + + // Make the dialog visible + + pack(); + setVisible(true); +} + +//********************************************************************** +// Protected +//********************************************************************** + +/** + * If the user presses cancel, we want to give him/her the option of + * continuing with the installation. + */ + +protected void +cancel() +{ + int response = + JOptionPane.showConfirmDialog( + this, + "Cancel the installation of Example1?", + "Cancel Installation", + JOptionPane.OK_CANCEL_OPTION); + + if (response == JOptionPane.OK_OPTION) { + super.cancel(); + } +} + +//********************************************************************** +// Inner Classes +//********************************************************************** + +//********************************************************************** +// Step0 +//********************************************************************** + +// This panel just introduces the Example1 wizard (which pretends that +// its going to install a package called Example1) + +private class Step0 + extends JWizardPanel +{ + +public +Step0() +{ + setStepTitle("Welcome to the Example1 Installation!"); + + JPanel contentPane = getContentPane(); + contentPane.setLayout(new BorderLayout()); + + JLabel label = + new JLabel( + ""+ + "The following steps will install the Example1 program.
" + + "Press Next to begin the installation.

" + + "Note: This is an example of the JWizard component.
"+ + "Nothing will be installed and no directories will be
"+ + "created.
"); + + contentPane.add(label, BorderLayout.NORTH); + + // Set the previous (none) and next steps + + setBackStep(-1); + setNextStep(1); +} + +} + +//********************************************************************** +// Step1 +//********************************************************************** + +// This panel displays the installation license + +private class Step1 + extends JWizardPanel +{ + +public +Step1() +{ + setStepTitle("License Terms"); + + JPanel contentPane = getContentPane(); + contentPane.setLayout(new BorderLayout()); + + JTextArea text = new JTextArea(20, 40); + text.setText(LICENSE); + JScrollPane scroll = new JScrollPane(text); + + JCheckBox checkbox = new JCheckBox("I agree."); + checkbox.addItemListener( + new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if (e.getStateChange() == ItemEvent.SELECTED) { + setNextStep(2); + } + else { + setNextStep(-1); + } + }}); + + contentPane.add(scroll); + contentPane.add(checkbox, BorderLayout.SOUTH); + + // Set the previous and next steps. Note that we don't have a next + // step until the user agrees to the license terms + + setBackStep(0); + setNextStep(-1); +} + +} + +//********************************************************************** +// Step2 +//********************************************************************** + +// Select the installation location + +private class Step2 + extends JWizardPanel +{ + +private JTextField field; + +public +Step2() +{ + setStepTitle("Select Installation Location"); + + JPanel contentPane = getContentPane(); + contentPane.setLayout(new BorderLayout()); + + // Field to enter install location + + field = + new JTextField( + "C:\\Program Files\\Example1"); + + // Browse button for browsing to install location + + final JButton browse = new JButton("Browse"); + browse.addActionListener( + new ActionListener() { + public void actionPerformed(ActionEvent e) { + File defaultDir = new File("C:\\Program Files"); + JFileChooser chooser = new JFileChooser(defaultDir); + chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + int result = chooser.showDialog(browse, "Select"); + if (result == JFileChooser.APPROVE_OPTION) { + field.setText(chooser.getSelectedFile().getAbsolutePath()); + } + } + }); + + JPanel filePanel = new JPanel(new BorderLayout()); + filePanel.add(field); + filePanel.add(browse, BorderLayout.EAST); + + contentPane.add(filePanel, BorderLayout.NORTH); + + // Set the previous and next steps + + setBackStep(1); + setNextStep(3); +} + +// We're going to override the next button so we can check if the +// specified directory exists. If it does, we go on to the next step. +// If not, we ask whether we should create it. If the answer is No or +// if we can't create it, we remain on the current step + +protected void +next() +{ + String folderName = field.getText().trim(); + installationFolder = new File(folderName); + + // If valid, go on to next step + + if (installationFolder.isDirectory()) { + super.next(); + return; + } + + // If it exists, check that it is a folder and not a file + + if (installationFolder.exists()) { + JOptionPane.showMessageDialog( + Step2.this, + "The given path points to a file, not a folder!", + "Error", + JOptionPane.ERROR_MESSAGE); + return; + } + + // If nothing was entered, report an error + + if (folderName.length() < 1) { + JOptionPane.showMessageDialog( + Step2.this, + "Please enter a folder name.", + "Error", + JOptionPane.ERROR_MESSAGE); + } + + + // If it doesn't exist, query whether we should create it + + int response = + JOptionPane.showConfirmDialog( + Step2.this, + installationFolder.getName() + " does not exist. Create?", + "Create Folder", + JOptionPane.OK_CANCEL_OPTION); + + if (response == JOptionPane.OK_OPTION) { +// This is what we'd do if we were really creating the folder +// try { +// installationFolder.mkdirs(); +// } + +// // Unsuccessful creation, report error + +// catch (Exception e) { +// JOptionPane.showMessageDialog( +// Step2.this, +// e.getMessage(), +// "Error", +// JOptionPane.ERROR_MESSAGE); +// return; +// } + + // Successful creation, continue to next step + + super.next(); + return; + } +} + +} + +//********************************************************************** +// Step3 +//********************************************************************** + +// Select the installation type: standard or custom + +private class Step3 + extends JWizardPanel +{ + +public +Step3() +{ + setStepTitle("Select Installation Type"); + + JPanel contentPane = getContentPane(); + contentPane.setLayout(new BorderLayout()); + + JRadioButton standard = new JRadioButton("Standard (Recommended)"); + standard.setSelected(standardInstall); + standard.addItemListener( + new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if (e.getStateChange() == ItemEvent.SELECTED) { + standardInstall = true; + } + } + }); + JRadioButton custom = new JRadioButton("Custom"); + custom.setSelected(!standardInstall); + custom.addItemListener( + new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if (e.getStateChange() == ItemEvent.SELECTED) { + standardInstall = false; + } + } + }); + + ButtonGroup group = new ButtonGroup(); + group.add(standard); + group.add(custom); + + JPanel radioBox = new JPanel(new GridLayout(2, 1)); + radioBox.add(standard); + radioBox.add(custom); + + contentPane.add(radioBox, BorderLayout.NORTH); + + // Set the previous and next steps. The next step will change if + // the user selects "Custom" installation + + setBackStep(2); + setNextStep(5); +} + +// Override the next() method so we can decide whether to go to step 4 +// (custom installation) or 5 (standard installation) + +protected void +next() +{ + // If we have a custom installation, go to step 4, rather than 5 + + if (!standardInstall) { + setNextStep(4); + } + super.next(); +} + +} + +//********************************************************************** +// Step4 +//********************************************************************** + +// If the user wanted a custom installation, select the components to +// install + +private class Step4 + extends JWizardPanel +{ + +private JCheckBox program; +private JCheckBox documentation; +private JCheckBox examples; + +public +Step4() +{ + setStepTitle("Select Components to Install"); + + JPanel contentPane = getContentPane(); + contentPane.setLayout(new BorderLayout()); + + program = new JCheckBox("Install program (890K)"); + program.setSelected(installProgram); + documentation = new JCheckBox("Install documentation (500K)"); + documentation.setSelected(installDocumentation); + examples = new JCheckBox("Install examples (103K)"); + examples.setSelected(installExamples); + + JPanel choices = new JPanel(new GridLayout(3, 1)); + choices.add(program); + choices.add(documentation); + choices.add(examples); + + contentPane.add(choices, BorderLayout.NORTH); + + // Set the previous and next steps + + setBackStep(3); + setNextStep(5); +} + +// We override the next() method just to determine what the user +// selected + +protected void +next() +{ + installProgram = program.isSelected(); + installDocumentation = documentation.isSelected(); + installExamples = examples.isSelected(); + super.next(); +} + +} + +//********************************************************************** +// Step5 +//********************************************************************** + +// Summarize the installation -- the user can proceed or cancel. + +private class Step5 + extends JWizardPanel +{ + +private JLabel label; + +public +Step5() +{ + setStepTitle("Installation Summary"); + + JPanel contentPane = getContentPane(); + contentPane.setLayout(new BorderLayout()); + + label = new JLabel(); + contentPane.add(label, BorderLayout.NORTH); + + // Set the previous and next steps + + setBackStep(standardInstall ? 3 : 4 ); + setNextStep(6); +} + +// We need to set the label text when the panel is displayed, not when +// the panel is constructed + +protected void +makingVisible() +{ + label.setText( + "" + + "Installation Summary:

" + + "Installation folder: " + + installationFolder.getAbsolutePath() + + "
" + + (standardInstall ? + "Standard installation

" : + "Custom installation
    " + + (installProgram ? "
  • Install program
  • " : "") + + (installDocumentation ? "
  • Install documentation
  • " : "") + + (installExamples ? "
  • Install examples
  • " : "") + + "
") + + "Press Next to start installing."); +} + +} + +//********************************************************************** +// Step6 +//********************************************************************** + +// We're done installing + +private class Step6 + extends JWizardPanel +{ + +public +Step6() +{ + setStepTitle("Installation Complete!"); + + JPanel contentPane = getContentPane(); + contentPane.setLayout(new BorderLayout()); + + JLabel label = + new JLabel( + "The Example1 installation is complete."); + + contentPane.add(label, BorderLayout.NORTH); + + // There's nothing more to do and there's no point going back a + // step either + + setBackStep(-1); + setNextStep(-1); +} + +} + +//********************************************************************** +// End Inner Classes +//********************************************************************** + +} diff --git a/libs/FLib/JWizard/doc/examples.html b/libs/FLib/JWizard/doc/examples.html new file mode 100644 index 0000000..1dfd1d5 --- /dev/null +++ b/libs/FLib/JWizard/doc/examples.html @@ -0,0 +1,69 @@ + + + + + +JWizard - Examples + + + + + + + + +

+ + + + + +
+

Examples

+

There is only one example program provided for JWizard, but it is a fairly + detailed reproduction of a typical installation wizard. It includes steps + such as a license which you have to agree to before installation can proceed + and variant paths for standard and custom installation.

+

The example will not create any folders (even though it may ask you if + it should create a folder) and will not install anything.

+

View the Example1 program.

+

If you download the FLib source, you can use Ant to build and run + the example program:

+
cd JWizard
+ant runExample1
+

The Example1 class is a subclass of JWizardDialog. It consists of seven + steps (numbered 0 through 6), each step represented by an inner class + which subclasses JWizardPanel. When the Example1 class is constructed, + it constructs an instance of each step and adds it to its sequence. Information + about the user's installation choices are stored in Example1 fields which + can be easily accessed and modified by the inner classes.

+

In most cases, each step's components are fully created and added to + the JWizardPanel at construction time. In step 5, a panel needs to display + a summary of the user's installation choices. The text cannot be determined + at construction time—it must be created just before the step is + displayed.

+

Each step defines the flow (the next and previous steps). Sometimes the + flow is constant and sometimes it is dynamic based on the user's entries. + For instance, in step 1, the next step is -1 (which enables the Finish + button) until the user agrees to the license terms. In step 3, we go to + step 5 for a standard install or to step 4 for a custom install.

+

The cancel button is handled in the JWizardDialog. It confirms that the + user wants to cancel the installation before proceeding with the exit.

+
+ + diff --git a/libs/FLib/JWizard/doc/features.html b/libs/FLib/JWizard/doc/features.html new file mode 100644 index 0000000..a992acb --- /dev/null +++ b/libs/FLib/JWizard/doc/features.html @@ -0,0 +1,62 @@ + + + + + +JWizard - Features + + + + + + + + +

+ + + + + +
+

Features

+

A wizard is a dialog that leads a user through a procedure step-by-step.

+

The main features of JWizard are:

+
    +
  • Easy to use.
  • +
  • Can add a logo image to the left side of the wizard dialog.
  • +
  • Can set a title for the wizard.
  • +
  • Can set a title for each step of the wizard.
  • +
  • Contains the commonly-used buttons Back, Next, Finish and Cancel.
  • +
  • Can enable the Finish button during sequencing or only on the last + step.
  • +
  • Can enable the Cancel button for all steps or all steps except the + last one.
  • +
  • Can add a Help button
  • +
  • Can handle complicated run-time sequencing where the next step depends + on the user's response to the current step or even on external factors.
  • +
  • Easy to centralize the storage of information gathered by the various + steps.
  • +
  • Can perform actions as the user sequences through the steps or can + hold off on all actions until Finish is pressed.
  • +
  • Fully internationalized and ready for localization.
  • +
  • Uses standard Java icons for the Back, Next and Help buttons.
  • +
+
+ + diff --git a/libs/FLib/JWizard/doc/images/Logo.png b/libs/FLib/JWizard/doc/images/Logo.png new file mode 100644 index 0000000..87ab5a8 Binary files /dev/null and b/libs/FLib/JWizard/doc/images/Logo.png differ diff --git a/libs/FLib/JWizard/doc/images/screenshot-metal.gif b/libs/FLib/JWizard/doc/images/screenshot-metal.gif new file mode 100644 index 0000000..08a2af6 Binary files /dev/null and b/libs/FLib/JWizard/doc/images/screenshot-metal.gif differ diff --git a/libs/FLib/JWizard/doc/images/screenshot-skin1.gif b/libs/FLib/JWizard/doc/images/screenshot-skin1.gif new file mode 100644 index 0000000..f46d690 Binary files /dev/null and b/libs/FLib/JWizard/doc/images/screenshot-skin1.gif differ diff --git a/libs/FLib/JWizard/doc/images/screenshot-skin2.gif b/libs/FLib/JWizard/doc/images/screenshot-skin2.gif new file mode 100644 index 0000000..470aa62 Binary files /dev/null and b/libs/FLib/JWizard/doc/images/screenshot-skin2.gif differ diff --git a/libs/FLib/JWizard/doc/images/screenshot-skin3.gif b/libs/FLib/JWizard/doc/images/screenshot-skin3.gif new file mode 100644 index 0000000..3c001f7 Binary files /dev/null and b/libs/FLib/JWizard/doc/images/screenshot-skin3.gif differ diff --git a/libs/FLib/JWizard/doc/images/screenshot-windows.gif b/libs/FLib/JWizard/doc/images/screenshot-windows.gif new file mode 100644 index 0000000..25841e4 Binary files /dev/null and b/libs/FLib/JWizard/doc/images/screenshot-windows.gif differ diff --git a/libs/FLib/JWizard/doc/index.html b/libs/FLib/JWizard/doc/index.html new file mode 100644 index 0000000..98c26fb --- /dev/null +++ b/libs/FLib/JWizard/doc/index.html @@ -0,0 +1,64 @@ + + + + + +JWizard - Introduction + + + + + + + + +

+ + + + + +
+

Introduction

+

Hi! My name is Tony Freixas and I am currently working on an application + that I intend to release as Open Source. In the process of building the + application, I am using as many Open Source classes and components as + I can find.

+

In some cases, I have been disappointed with what I have found on the + web:

+
    +
  • Classes that are not free.
  • +
  • Classes with restrictive licensing.
  • +
  • Classes which ignore internationalization.
  • +
  • Classes which are not easy to use.
  • +
  • Components which are limited with respect to the Look & Feel that + can be used.
  • +
+

When I have not found a suitable Java class, I have implemented my own. + I have decided to release these for use by others as part of a library + I call FLib.

+

Currently, there are three components available in FLib and I have chosen + to make them completely independent of each other. In the future, you + + may have to load some common code in order to use the FLib classes.

+

These web pages are for the Swing-based JWizard component. Use the links + on the left to learn more.

+

Support This Project

+
+ + diff --git a/libs/FLib/JWizard/doc/resources.html b/libs/FLib/JWizard/doc/resources.html new file mode 100644 index 0000000..91c1faf --- /dev/null +++ b/libs/FLib/JWizard/doc/resources.html @@ -0,0 +1,58 @@ + + + + + +JWizard - Other Resources + + + + + + + + +

+ + + + + +
+

Other Resources

+

I think it's only fair to note some of the other Java Wizard component + implementations. Some of these have appeared since I wrote my version. + You may do a Google search to find yet other versions.

+

There's a JWizard package at SourceForge.net + which became the inspiration for my own version. I had some complicated + sequencing to do and this package seemed to make it harder than I thought + it needed to be. You can judge for yourself. It is open source and it + does appear to have paid attention to internationalization.

+

There's source code for a JWizard component at informit.com. + It separates the Wizard panels from the navigation which may create some + excess cross-talk among the classes. The code seems to be free and unlicensed. + The code is not internationalized and uses characters ">" + and "<" instead of icons for the Back and Next buttons.

+

For $99, Visionary + Technologies offers a JWizard component which sounds pretty nice. + I haven't tried it as its not open source. If you do a Google search, + most of your hits will point back to this version.

+

+
+ + diff --git a/libs/FLib/JWizard/doc/screenshots.html b/libs/FLib/JWizard/doc/screenshots.html new file mode 100644 index 0000000..7b6fc51 --- /dev/null +++ b/libs/FLib/JWizard/doc/screenshots.html @@ -0,0 +1,55 @@ + + + + + +JWizard - Screen Shots + + + + + + + + +

+ + + + + +
+

Screen Shots

+

The following are screen shots of JWizardDialogs using various look-and-feels:

+

+

From the JWizard example program using the Metal L&F.

+

+

From the MediaTracker application using the Windows L&F + .

+

+

From the MediaTracker application using the Skin L&F + with the Aqua package.

+

+

From the MediaTracker application using the Skin L&F + with the Modern package.

+

+

From the MediaTracker application using the Skin L&F + with the XPLuna package.

+
+ + diff --git a/libs/FLib/JWizard/doc/stylesheet.css b/libs/FLib/JWizard/doc/stylesheet.css new file mode 100644 index 0000000..dc693da --- /dev/null +++ b/libs/FLib/JWizard/doc/stylesheet.css @@ -0,0 +1,48 @@ +body { + font-family: Arial, Helvetica, sans-serif; + background: white: + color: black; +} + +td { + font-family: Arial, Helvetica, sans-serif; +} + +th { + font-family: Arial, Helvetica, sans-serif; +} + +#sidebar { + font-family: "Times New Roman", Times, serif; + font-weight: bold; + font-style: italic; + font-size: 20px; +} + +#content { + font-size: 100%; +} + +a:visited { + color: #8080FF; + text-decoration: none; +} + +a:link { + color: #8080FF; + text-decoration: none; +} + +a:hover { + color: #C00000; + text-decoration: none; +} + +a:active { + color: #C00000; + text-decoration: none; +} + +pre { + margin-left: 1em; +} diff --git a/libs/FLib/JWizard/doc/tutorial.html b/libs/FLib/JWizard/doc/tutorial.html new file mode 100644 index 0000000..3a8dc2d --- /dev/null +++ b/libs/FLib/JWizard/doc/tutorial.html @@ -0,0 +1,200 @@ + + + + + +JWizard - Tutorial + + + + + + + + +

+ + + + + +
+

Tutorial

+

JWizard

+

Creating the JWizardDialog

+

To create a Wizard, begin by creating a storyboard, sketching each step + and the sequence through the steps. The sequencing may depend on the information + users supply as they proceed through the Wizard. Number each step, from + 0 to n, roughly following the flow from beginning to end.

+

Now you're ready to create your Wizard class. The basic pattern is:

+
public class SampleWizard
+    extends JWizardDialog
+{
+
+
+public SampleWizard(Frame owner) {
+    super(owner, "Sample Wizard", true);
+
+    // Set the logo image
+
+    URL url = getClass().getResource("SampleWizard.gif");
+    setWizardIcon(new ImageIcon(url));
+
+    // Create each step
+
+    addWizardPanel(new Step0());
+    addWizardPanel(new Step1());
+    addWizardPanel(new Step2());
+    ...
+    
+    // Make the dialog visible
+
+    pack();
+    setVisible(true);
+}
+
+}
+
+

Each Wizard is a subclass of JWizardDialog. In this case, the sample + wizard will be the child of a Frame. This will center the Wizard over + the Frame. If the Frame is null, the Wizard will be centered in the middle + of the screen. You can turn off the centering behavior by calling disableCentering() + before calling setVisible().

+

The dialog title will be "Sample Wizard" and the dialog will + be modal (which is fairly standard for Wizards). An icon is added to the + Wizard and will be displayed on the left side of the dialog.

+

Note that each Wizard step is a separate class that is instantiated and + added to the dialog. The class names are arbitrary, but the first step + will be identified as step 0, so the above naming makes it easy to associate + a step with its corresponding class.

+

The step classes can be created however you like, but my recommendation + is that they be inner classes of the JWizardDialog. This makes it very + easy for global information to be accumulated in a central place (the + JWizardDialog) and accessed by all steps.

+

Creating the Wizard Steps

+

The basic pattern for a Wizard step is as follows:

+
private class Step0
+      extends JWizardPanel
+{
+
+public
+Step0()
+{
+    setStepTitle("Sample Wizard Step 0");
+
+    JPanel contentPane = getContentPane();
+    ...
+
+    // Set the previous and next steps
+
+    setBackStep(-1);
+    setNextStep(1);
+}
+
+}
+
+

Each step is a subclass of JWizardPanel. You will normally start by setting + the title for this specific step. Then you will construct all the appropriate + components for the step and add them to the JPanel obtained by calling + getContentPane() (don't add them directly to the JWizardPanel).

+

You end each step constructor by calling setBackStep() and + setNextStep(). This defines the flow from this panel to the + previous and next panels. A previous panel of -1 means that we are on + the first panel; a -1 for the next panel means we are on the last panel. + Any other number identifies the step we will sequence back or forwards + to.

+

If you need more dynamic sequencing, you will set up the default sequence + in the constructor. Then you will override the back() or + next() methods. You would determine the correct previous + or next step (calling setBackStep() or setNextStep()) + and then call super.back() or super.next().

+

This also allows you to perform error checking. You override the next() + method and perform error checking based on the user's step entries. If + there is an error, you can display an error dialog and return without + calling super.next(). This will leave the step unchanged.

+

The next() method is also a convenient place to read the + user's entries and copy them into JWizardDialog fields so that the information + is globally available to all steps.

+

If you have a complicated Wizard with many steps and lots of components, + it may take a while to display if you construct each panel in the JWizardPanel + constructor. You perform a delayed construction by overriding makingVisible(). + makingVisible() is called just prior to displaying the step, + so you'll need to make sure you construct the panel only the first time + its called.

+

This will speed up the initial appearance of the Wizard, but it will + make it difficult to size the dialog properly (the dialog should be large + enough to accommodate the largest panel). You may think you can manually + set the size by calling setSize() on the JWizardDialog. This + is not a good idea. There are various circumstances which may change the + size needed:

+
    +
  • If the application is internationalized, the translated labels may + be longer than expected.
  • +
  • If the application is designed for people with poor vision, you may + want to allow for larger font sizes.
  • +
  • You may also want larger font sizes for demo purposes (showing the + application to a group of people gathered around a display).
  • +
+

JWizardDialog does make allowances for panels created in makingVisible(). + Before each panel is displayed, it checks the preferred size against the + current size. If the preferred size is bigger, it will increase the dialog's + size to match. It will never decrease the size—this minimizes the + amount of size changes the dialog goes through.

+

Handling Finish and Cancel

+

In JWizardDialog, the finish() and cancel() + methods are called when the Finish and Cancel buttons are called, respectively. + Each of these methods calls dispose(). You may want to override them. + For instance, finish() may want to take all the user's input + and do something with it. In cancel(), you may want to query + the user to confirm the cancellation. Call super.cancel() + if confirmed or else just return.

+

Handling Help

+

You add a Help button by calling addHelpButton() in the + JWizardDialog constructor. If all Wizard panels have the same help message, + you would override help() in the JWizardDialog class. Otherwise, + each step should over JWizardPanel's help() method.

+

Sequencing Options

+

In general, the sequencing is handled by each step. This is usually the + easiest way to do it as each step usually has the information it needs + to decide where to go next. However, if you need more central control + of the sequencing algorithm, you can override switchToStep() + in the JWizardDialog. This method receives the current step value and + the requested next step (from the JWizardPanel). Note that the "next" + step is the step selected by the user pressing either the Back or Next + button. You can change the change the next step value based on whatever + criteria you want.

+

Other Options

+

In most Wizards, the Finish button is enabled only on the last step. + But some Wizards allow the user to call Finish while steps still remain. + The information gathered in the remaining steps is defaulted. If you have + this model, call setEarlyFinish() in the JWizardDialog.

+

In some Wizards, the last step is simply where all the necessary user + information has been gathered—pressing Finish begins processing + the information. In other Wizards, actions may be performed as the Wizard + proceeds and the last step is simply to confirm completion of the task. + In this latter case, call disableCancelAtEnd() in the JWizardDialog. + This disables the Cancel button on the last step.

+

Summary

+

The JWizard components are designed to be easy to use. In most cases + you will override just a few methods. The rest will normally do the + right + thing. After reading this tutorial, you should examine the example + program provided which exercises many of the features of JWizard.

+
+ + diff --git a/libs/FLib/JWizard/org/freixas/jwizard/Bundle.properties b/libs/FLib/JWizard/org/freixas/jwizard/Bundle.properties new file mode 100644 index 0000000..8c90245 --- /dev/null +++ b/libs/FLib/JWizard/org/freixas/jwizard/Bundle.properties @@ -0,0 +1,31 @@ +# org.freixas.jwizard Resource Bundle + +BackButton=Back +BackButtonMnemonic=B +BackButtonAccelerator= +BackButtonShort= +BackButtonLong=Go back to the previous step. + +NextButton=Next +NextButtonMnemonic=N +NextButtonAccelerator= +NextButtonShort= +NextButtonLong=Go to the next step. + +FinishButton=Finish +FinishButtonMnemonic=F +FinishButtonAccelerator= +FinishButtonShort= +FinishButtonLong=End the wizard. + +CancelButton=Cancel +CancelButtonMnemonic=C +CancelButtonAccelerator=ESCAPE +CancelButtonShort= +CancelButtonLong=Cancel the wizard. + +HelpButton=Help +HelpButtonMnemonic=H +HelpButtonAccelerator=F1 +HelpButtonShort= +HelpButtonLong=Get Help for this dialog. diff --git a/libs/FLib/JWizard/org/freixas/jwizard/JWizardDialog.java b/libs/FLib/JWizard/org/freixas/jwizard/JWizardDialog.java new file mode 100644 index 0000000..355a9d4 --- /dev/null +++ b/libs/FLib/JWizard/org/freixas/jwizard/JWizardDialog.java @@ -0,0 +1,1015 @@ +//********************************************************************** +// Package +//********************************************************************** + +package org.freixas.jwizard; + +//********************************************************************** +// Import list +//********************************************************************** + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; + +import java.net.URL; +import java.util.ResourceBundle; + +/** + * This class creates a Wizard dialog. + *

+ * I wrote this class because I couldn't find a good, free, + * easy-to-use, well-documented Java Wizard dialog. I hope this one is + * both flexible and easy-to-use. + *

+ * A wizard is a dialog that leads a user through a procedure + * step-by-step. Some Wizards only gather information until the very + * last step, when they execute some tasks. Others will perform + * actions as they go. + *

+ * To create a Wizard, you need two deal with two classes: + * JWizardDialog (this class) and JWizardPanel. The basic steps are: + *

    + *
  • Create a JWizardDialog subclass. + *
  • Set the Wizard dialog title (usually constant, though it + * needn't be). + *
  • Set the optional Image displayed on the left side of the + * Wizard. + *
  • Create a series of JWizardPanel's and add them to the dialog + * using addWizardPanel(). The order in which the panels are added + * determine their step number, with the first step starting at 0. + *
  • Call pack() and call setVisible(true) to display it. + *
+ *

+ * Each JWizardPanel consists of a step title (which should be + * specific to each step) and a set of components which you layout as + * you wish. If possible, you should try to create and layout all + * panel components at construction time (so that the Wizard size can + * be accurately determined). If you need some dynamic layout, the + * method makingVisible() is called each time prior to making the + * JWizardPanel step visible. + *

+ * The Wizard has four buttons which always appear, although they may + * at times be disabled. The buttons are Back, Next, Finish and Cancel. + * You can also add a Help button with addHelpButton(). + *

+ * When the buttons are pressed, they call the methods back(), next(), + * finish(), cancel() and help(), respectively. You can override any + * of these. The default finish() and cancel() methods call dispose(); + * when you override these, you would usually finish by calling + * super.finish() or super.cancel(). + *

+ * The default back(), next() and help() methods call equivalent + * methods in the current JWizardPanel. You would not normally + * override these methods, but the hooks are there if you need them. + *

+ * In the JWizardPanel, the default back() and next() methods usally + * go to the previous or next panel. You can change the panel they go + * to by calling setBackPanel() or setNextPanel(), giving the index of + * the panel to go to. A value of -1 disables the corresponding + * button. Again, you can override these and then finish by calling + * super.back() or super.next(). The default help() method does + * nothing. + *

+ * The Finish button is normally enabled only on the last step. If you + * allow an early exit from the Wizard, call setEarlyFinish() and the + * Finish button will be enabled. + *

+ * The Cancel button is normally always enabled. To disable it on the + * last step, call disableCancelAtEnd(). + *

+ * Just prior to switching steps, switchToStep() is called in + * JWizardDialog. This method supplies the current and new step + * indices. The return value is the index of the panel which will + * actually be displayed. The default method returns the input value, + * but you can override this if you need special flow control in the + * JWizardDialog rather than the JWizardPanel. + *

+ * When the dialog is displayed, it is normally centered over its + * parent. If there is no Frame parent, it is centered on the screen. + * You can disable this with disableCentering(), which must be called + * before the JWizardDialog is made visible. + *

+ * That's about all there is to it. + *


+ * This program is free software; you can redistribute it and/or + * modify it under the terms of the Artistic License. You should have + * received a copy of the Artistic License along with this program. If + * not, a copy is available at + * + * opensource.org. + * + * @see JWizardPanel + * @author Antonio Freixas + */ + +// Copyright © 2004 Antonio Freixas +// All Rights Reserved. + +public class JWizardDialog + extends JDialog +{ + +//********************************************************************** +// Private Constants +//********************************************************************** + +private static final int BACK_BUTTON = 0; +private static final int NEXT_BUTTON = 1; +private static final int FINISH_BUTTON = 2; +private static final int CANCEL_BUTTON = 3; +private static final int HELP_BUTTON = 4; + +//********************************************************************** +// Private Members +//********************************************************************** + +// The label which holds the image to display on the left side of the +// wizard. + +private JPanel logoPanel; +private JLabel logoLabel; + +// The panel to which JWizardPanel's are added. + +private JPanel workArea; + +// The layout for the work area. + +private CardLayout cardLayout; + +// The current JWizardPanel + +private JWizardPanel currentWizard = null; +private int currentStep = -1; +private int lastStep = -1; +private int panelCount = 0; + +// The button panel and buttons + +private JPanel buttonPanel; +private JPanel buttons; +private JButton buttonBack; +private JButton buttonNext; +private JButton buttonFinish; +private JButton buttonCancel; +private JButton buttonHelp; + +// True if the finish button should be enabled all the time + +private boolean enableEarlyFinish = false; + +// True if the cancel button is enabled on the final step + +private boolean enableCancelAtEnd = true; + +// True if the dialog should be centered on display + +private boolean isCentered = true; + +// True if the wizard finished + +private boolean isFinished = false; + +// The resource bundle + +private static ResourceBundle bundle = + ResourceBundle.getBundle("org.freixas.jwizard.Bundle"); + +//********************************************************************** +// Constructors +//********************************************************************** + +/** + * Creates a non-modal JWizardDialog without a title and without a + * specified Frame owner. A shared, hidden frame will be set as the + * owner of the dialog. + *

+ * This constructor sets the component's locale property to the value + * returned by JComponent.getDefaultLocale(). + * + * @throws HeadlessException If GraphicsEnvironment.isHeadless() returns true. + */ + +public +JWizardDialog() + throws HeadlessException +{ + super(); + init(); +} + +/** + * Creates a non-modal JWizardDialog without a title with the + * specified Frame as its owner. If owner is null, a shared, hidden + * frame will be set as the owner of the dialog. + *

+ * This constructor sets the component's locale property to the value + * returned by JComponent.getDefaultLocale(). + * + * @param owner The Frame owning the dialog. + * @throws HeadlessException If GraphicsEnvironment.isHeadless() returns true. + */ + +public +JWizardDialog( + Frame owner) + throws HeadlessException +{ + super(owner); + init(); +} + +/** + * Creates a modal or non-modal JWizardDialog without a title and with + * the specified owner Frame. If owner is null, a shared, hidden + * frame will be set as the owner of the dialog. + * + * This constructor sets the component's locale property to the value + * returned by JComponent.getDefaultLocale(). + * + * @param owner The Frame owning the dialog. + * @param modal True for a modal dialog, false for one that allows + * others windows to be active at the same time. + * @throws HeadlessException If GraphicsEnvironment.isHeadless() returns true. + */ + +public +JWizardDialog( + Frame owner, + boolean modal) + throws HeadlessException +{ + super(owner, modal); + init(); +} + +/** + * Creates a non-modal JWizardDialog with the specified title and with + * the specified owner frame. If owner is null, a shared, hidden + * frame will be set as the owner of the dialog. + *

+ * This constructor sets the component's locale property to the value + * returned by JComponent.getDefaultLocale(). + * + * @param owner The Frame owning the dialog. + * @param title The String to display in the dialog's title bar. + * @throws HeadlessException If GraphicsEnvironment.isHeadless() returns true. + */ + +public +JWizardDialog( + Frame owner, + String title) + throws HeadlessException +{ + super(owner, title); + init(); +} + +/** + * Creates a modal or non-modal JWizardDialog with the specified title + * and the specified owner Frame. If owner is null, a shared, hidden + * frame will be set as the owner of this dialog. All constructors + * defer to this one. + *

+ * NOTE: Any popup components (JComboBox, JPopupMenu, JMenuBar) + * created within a modal dialog will be forced to be lightweight. + *

+ * This constructor sets the component's locale property to the value + * returned by JComponent.getDefaultLocale(). + * + * @param owner The Frame owning the dialog. + * @param title The String to display in the dialog's title bar. + * @param modal True for a modal dialog, false for one that allows + * others windows to be active at the same time. + * @throws HeadlessException If GraphicsEnvironment.isHeadless() returns true. + */ + +public +JWizardDialog( + Frame owner, + String title, + boolean modal) + throws HeadlessException +{ + super(owner, title, modal); + init(); +} + +/** + * Creates a modal or non-modal JWizardDialog with the specified + * title, owner Frame, and GraphicsConfiguration. + *

+ * NOTE: Any popup components (JComboBox, JPopupMenu, JMenuBar) + * created within a modal dialog will be forced to be lightweight. + *

+ * This constructor sets the component's locale property to the value + * returned by JComponent.getDefaultLocale. + * + * @param owner The Frame owning the dialog. + * @param title The String to display in the dialog's title bar. + * @param modal True for a modal dialog, false for one that allows + * others windows to be active at the same time. + * @param gc The GraphicsConfiguration of the target screen device. If + * gc is null, the same GraphicsConfiguration as the owning Frame + * is used. + * @throws HeadlessException If GraphicsEnvironment.isHeadless() returns true. + */ + +public +JWizardDialog( + Frame owner, + String title, + boolean modal, + GraphicsConfiguration gc) + throws HeadlessException +{ + super(owner, title, modal, gc); + init(); +} + +/** + * Creates a non-modal JWizardDialog without a title with the + * specified Dialog as its owner. If owner is null, a shared, hidden + * frame will be set as the owner of the dialog. + *

+ * This constructor sets the component's locale property to the value + * returned by JComponent.getDefaultLocale(). + * + * @param owner The Dialog owning the dialog. + * @throws HeadlessException If GraphicsEnvironment.isHeadless() returns true. + */ + +public +JWizardDialog( + Dialog owner) + throws HeadlessException +{ + super(owner); + init(); +} + +/** + * Creates a modal or non-modal JWizardDialog without a title and with + * the specified owner Dialog. If owner is null, a shared, hidden + * frame will be set as the owner of the dialog. + * + * This constructor sets the component's locale property to the value + * returned by JComponent.getDefaultLocale(). + * + * @param owner The Dialog owning the dialog. + * @param modal True for a modal dialog, false for one that allows + * others windows to be active at the same time. + * @throws HeadlessException If GraphicsEnvironment.isHeadless() returns true. + */ + +public +JWizardDialog( + Dialog owner, + boolean modal) + throws HeadlessException +{ + super(owner, modal); + init(); +} + +/** + * Creates a non-modal JWizardDialog with the specified title and with + * the specified owner frame. If owner is null, a shared, hidden + * frame will be set as the owner of the dialog. + *

+ * This constructor sets the component's locale property to the value + * returned by JComponent.getDefaultLocale(). + * + * @param owner The Dialog owning the dialog. + * @param title The String to display in the dialog's title bar. + * @throws HeadlessException If GraphicsEnvironment.isHeadless() returns true. + */ + +public +JWizardDialog( + Dialog owner, + String title) + throws HeadlessException +{ + super(owner, title); + init(); +} + +/** + * Creates a modal or non-modal JWizardDialog with the specified title + * and the specified owner Dialog. If owner is null, a shared, hidden + * frame will be set as the owner of this dialog. All constructors + * defer to this one. + *

+ * NOTE: Any popup components (JComboBox, JPopupMenu, JMenuBar) + * created within a modal dialog will be forced to be lightweight. + *

+ * This constructor sets the component's locale property to the value + * returned by JComponent.getDefaultLocale(). + * + * @param owner The Dialog owning the dialog. + * @param title The String to display in the dialog's title bar. + * @param modal True for a modal dialog, false for one that allows + * others windows to be active at the same time. + * @throws HeadlessException If GraphicsEnvironment.isHeadless() returns true. + */ + +public +JWizardDialog( + Dialog owner, + String title, + boolean modal) + throws HeadlessException +{ + super(owner, title, modal); + init(); +} + +/** + * Creates a modal or non-modal JWizardDialog with the specified + * title, owner Dialog, and GraphicsConfiguration. + *

+ * NOTE: Any popup components (JComboBox, JPopupMenu, JMenuBar) + * created within a modal dialog will be forced to be lightweight. + *

+ * This constructor sets the component's locale property to the value + * returned by JComponent.getDefaultLocale. + * + * @param owner The Dialog owning the dialog. + * @param title The String to display in the dialog's title bar. + * @param modal True for a modal dialog, false for one that allows + * others windows to be active at the same time. + * @param gc The GraphicsConfiguration of the target screen device. If + * gc is null, the same GraphicsConfiguration as the owning Dialog + * is used. + * @throws HeadlessException If GraphicsEnvironment.isHeadless() returns true. + */ + +public +JWizardDialog( + Dialog owner, + String title, + boolean modal, + GraphicsConfiguration gc) + throws HeadlessException +{ + super(owner, title, modal, gc); + init(); +} + +//********************************************************************** +// Public +//********************************************************************** + +/** + * Add an image which displays on the left side of the wizard. By + * default, no image is displayed. This must be set before the dialog + * is made visible. + * + * @param icon The icon representing the image to display. If null, no + * image is displayed. + */ + +public void +setWizardIcon( + Icon icon) +{ + // If null, remove any existing logo panel + + if (icon == null) { + if (logoPanel != null) { + remove(logoPanel); + logoPanel = null; + logoLabel = null; + } + } + + // If not null, add it or replace an existing label + + else { + if (logoPanel != null) { + remove(logoPanel); + } + logoPanel = new JPanel(new BorderLayout()); + logoLabel = new JLabel(icon); + logoPanel.add(logoLabel, BorderLayout.NORTH); + getContentPane().add(logoPanel, BorderLayout.WEST); + } +} + +/** + * Add a panel representing a step in the wizard. Since removing a + * panel would force a renumbering of the remaining panels and since + * you have flexible sequencing control, there is no matching + * removeWizardPanel() method. + * + * @param panel The JWizardPanel to add + */ + +public void +addWizardPanel( + JWizardPanel panel) +{ + if (currentWizard == null) { + currentWizard = panel; + currentStep = 0; + } + workArea.add(panel, Integer.toString(panelCount++)); + panel.setWizardParent(this); +} + +/** + * This adds a help button to the wizard. When the button is pressed, + * the help() method is called. + * + * @see #help() + */ + +public void +addHelpButton() +{ + if (buttonHelp == null) { + buttonHelp = + new JButton( + new ButtonAction( + "HelpButton", "HelpButtonMnemonic", + "HelpButtonAccelerator", + "images/Help16.gif", + "HelpButtonShort", "HelpButtonLong", HELP_BUTTON)); + buttons.add(buttonHelp); + } +} + +/** + * If this method is called, the Finish button is enabled immediately. + * By default, it is enabled only on the last step (any step where the + * next JWizardPanel step is -1). + */ + +public void +setEarlyFinish() +{ + enableEarlyFinish = true; +} + +/** + * Returns true if the wizard finished (the user pressed the Finish) + * button). Returns false otherwise (either the wizard hasn't finished + * or the user pressed Cancel to exit). + * + * @return True if the wizard finished. + */ + +public boolean +isFinished() +{ + return isFinished; +} + +/** + * If this method is called, the Cancel button is disabled when on the + * last step. If setEarlyFinish() is called, it is still disabled only + * on the last step. + */ + +public void +disableCancelAtEnd() +{ + enableCancelAtEnd = false; +} + +/** + * Don't center the dialog. This method must be called before the + * dialog is made visible. The default behavior is to center the + * dialog over its parent, or on the screen if no parent was given. + */ + +public void +disableCentering() +{ + isCentered = false; +} + +/** + * Returns the current step being displayed by the wizard. Steps start + * at 0. If no step is yet displayed, a -1 is returned. + * + * @return The current step being displayed by the wizard. + */ + +public int +getCurrentStep() +{ + return currentStep; +} + +/** + * Returns the last step displayed by the wizard. Steps start at 0. If + * there is no previous step yet, -1 is returned. + * + * @return The last step being displayed by the wizard. + */ + +public int +getLastStep() +{ + return lastStep; +} + +/** + * @deprecated As of JDK version 1.1, replaced by setVisible(boolean). + */ + +public void +show() +{ + goTo(0); + + if (isCentered) { + Dimension screenSize = getToolkit().getScreenSize(); + Dimension parentSize = getParent().getSize(); + Point parentLocation = getParent().getLocation(); + + // If the parent Frame is invisible, we center the dialog on + // the screen + + if (!getParent().isVisible()) { + parentSize = getToolkit().getScreenSize(); + parentLocation.setLocation(0, 0); + } + + Dimension size = getSize(); + + int x = parentLocation.x + (parentSize.width - size.width ) / 2; + int y = parentLocation.y + (parentSize.height - size.height) / 2; + + // Make sure the dialog is placed completely on the screen (as + // long as it is smaller than the screen size) + + if (size.width < screenSize.width && + x + size.width > screenSize.width) { + x = screenSize.width - size.width; + } + if (size.height < screenSize.height && + y + size.height > screenSize.height) { + y = screenSize.height - size.height; + } + if (x < 0) x = 0; + if (y < 0) y = 0; + + setBounds(x, y, size.width, size.height); + } + + super.show(); +} + +// WizardDialogs are equal if they are the same object, so the default +// equals() and hashCode() methods are acceptable. I'm not using the +// paramString() method for debugging, so the default is OK + +//********************************************************************** +// Package Public +//********************************************************************** + +/** + * Set the sensitivity of each button based on the back and next step + * values. This should be called when changing steps or when the back + * or next button values are changed. + */ + +void +setButtonStates() +{ + int backStep = currentWizard.getBackStep(); + int nextStep = currentWizard.getNextStep(); + + boolean atBegin = backStep < 0 || backStep >= panelCount; + + boolean atEnd = nextStep < 0 || nextStep >= panelCount; + + buttonBack.setEnabled(!atBegin); + buttonNext.setEnabled(!atEnd); + buttonFinish.setEnabled(enableEarlyFinish || atEnd); + buttonCancel.setEnabled(!atEnd || enableCancelAtEnd); + + // Set the default button + + if (buttonNext.isEnabled()) { + getRootPane().setDefaultButton(buttonNext); + } + else if (buttonFinish.isEnabled()) { + getRootPane().setDefaultButton(buttonFinish); + } + else if (buttonBack.isEnabled()) { + getRootPane().setDefaultButton(buttonBack); + } + else { + getRootPane().setDefaultButton(null); + } +} + +/** + * Display the JWizardPanel with the given step number. This method is + * package public so that JWizardPanel can call it. The + * switchToStep() method may override the step choice. + * + * + * @param step The step number of the JWizardPanel to display. + * @see #switchToStep(int,int) + */ + +void +goTo( + int step) +{ + // Give the user a last chance to change things + + step = switchToStep(currentStep, step); + + // We can't do anything if we're outside the valid range + + if (step < 0 || step >= panelCount) return; + + // Save the current step as the previous step + + lastStep = currentStep; + + currentWizard = (JWizardPanel)workArea.getComponent(step); + currentStep = step; + currentWizard.doMakingVisible(); + cardLayout.show(workArea, Integer.toString(step)); + + // The panel may have just been created or modified in the + // doMakingVisible() method. If so, the CardLayout's original + // guess at the window size may be too small. We increase the size + // if we have to -- but we never decrease the size + + Dimension prefSize = getPreferredSize(); + Dimension curSize = getSize(); + if (prefSize.width > curSize.width || + prefSize.height > curSize.height) { + Dimension newSize = + new Dimension(Math.max(prefSize.width, curSize.width), + Math.max(prefSize.height, curSize.height)); + setSize(newSize); + invalidate(); + validate(); + } + + // Set the button states + + setButtonStates(); +} + +//********************************************************************** +// Protected +//********************************************************************** + +/** + * Called when the Back button is pressed. This calls the back() + * method in the current JWizardPanel. + * + * @see JWizardPanel#back() + */ + +protected void +back() +{ + if (currentWizard != null) currentWizard.doBack(); +} + +/** + * Called when the Next button is pressed. This calls the next() + * method in the current JWizardPanel. + * + * @see JWizardPanel#next() + */ + +protected void +next() +{ + if (currentWizard != null) currentWizard.doNext(); +} + +/** + * Called when the Finish button is pressed. This calls dispose(). You + * will probably want to override this. + */ + +protected void +finish() +{ + isFinished = true; + dispose(); +} + +/** + * Called when the Cancel button is pressed. This calls dispose(). + */ + +protected void +cancel() +{ + dispose(); +} + +/** + * Called when the Help button is pressed. This calls the help() + * method in the current JWizardPanel. If the help text is the same + * for all panels, you will want to override this. + */ + +protected void +help() +{ + if (currentWizard != null) currentWizard.doHelp(); +} + +/** + * This method is called just prior to switching from one step to + * another (after any next() or back() method is called). It receives + * the current and new indices. By default, it returns the new index. + * You can override the method if you need to control sequencing from + * this JWizardDialog class (normally, each step decides what the back + * and next steps should be). + * + * @param currentIndex The index of the current JWizardPanel. + * @param newIndex The index of the JWizardPanel we are about to + * display. + * @return The index of the JWizardPanel to display. + */ + +protected int +switchToStep( + int currentIndex, + int newIndex) +{ + return newIndex; +} + +//********************************************************************** +// Private +//********************************************************************** + +/** + * Initialize the JWizardDialog. + */ + +private void +init() +{ + getContentPane().setLayout(new BorderLayout(5, 2)); + + // If the user tries to close the wizard, the result should be the + // same as pressing Cancel + + setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); + + // Window close is the same as cancel. If the cancel button is + // disabled, then a window close does nothing + + addWindowListener( + new WindowAdapter() { + public void windowClosing(WindowEvent e) { + if (buttonCancel.isEnabled()) { + cancel(); + } + } + }); + + // Work area for WizardPanel's + + workArea = new JPanel(); + cardLayout = new CardLayout(); + workArea.setLayout(cardLayout); + + // Buttons + + buttonBack = + new JButton( + new ButtonAction( + "BackButton", "BackButtonMnemonic", "BackButtonAccelerator", + "images/Back16.gif", + "BackButtonShort", "BackButtonLong", BACK_BUTTON)); + buttonNext = + new JButton( + new ButtonAction( + "NextButton", "NextButtonMnemonic", "NextButtonAccelerator", + "images/Forward16.gif", + "NextButtonShort", "NextButtonLong", NEXT_BUTTON)); + buttonFinish = + new JButton( + new ButtonAction( + "FinishButton", "FinishButtonMnemonic", + "FinishButtonAccelerator", + null, + "FinishButtonShort", "FinishButtonLong", FINISH_BUTTON)); + buttonCancel = + new JButton( + new ButtonAction( + "CancelButton", "CancelButtonMnemonic", + "CancelButtonAccelerator", + null, + "CancelButtonShort", "CancelButtonLong", CANCEL_BUTTON)); + + buttons = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + + buttons.add(buttonBack); + buttons.add(buttonNext); + buttons.add(buttonFinish); + buttons.add(buttonCancel); + + buttonPanel = new JPanel(new BorderLayout()); + buttonPanel.add(new JSeparator(), BorderLayout.NORTH); + buttonPanel.add(buttons); + + getContentPane().add(buttonPanel, BorderLayout.SOUTH); + getContentPane().add(workArea); +} + +//********************************************************************** +// Inner Classes +//********************************************************************** + +// ButtonAction + +private class ButtonAction + extends AbstractAction +{ + +ButtonAction( + String name, + String mnemonic, + String accelerator, + String imageName, + String shortDescription, + String longDescription, + int actionId) +{ + if (name != null) { + putValue(Action.NAME, bundle.getString(name)); + } + + if (mnemonic != null) { + putValue(Action.MNEMONIC_KEY, + new Integer(bundle.getString(mnemonic).charAt(0))); + } + + if (accelerator != null) { + putValue( + Action.ACCELERATOR_KEY, + KeyStroke.getKeyStroke(bundle.getString(accelerator))); + } + + URL url = null; + if (imageName != null) { + url = + this.getClass().getResource(imageName); + if (url != null) { + putValue(Action.SMALL_ICON, new ImageIcon(url)); + } + } + + if (shortDescription != null) { + putValue(Action.SHORT_DESCRIPTION, bundle.getString(shortDescription)); + } + + if (longDescription != null) { + putValue(Action.LONG_DESCRIPTION, bundle.getString(longDescription)); + } + putValue("buttonAction", new Integer(actionId)); +} + +public void +actionPerformed( + ActionEvent e) +{ + Integer value = (Integer)getValue("buttonAction"); + switch (value.intValue()) { + case BACK_BUTTON: + back(); + break; + case NEXT_BUTTON: + next(); + break; + case FINISH_BUTTON: + finish(); + break; + case CANCEL_BUTTON: + cancel(); + break; + case HELP_BUTTON: + help(); + break; + } +} + +} + +//********************************************************************** +// End Inner Classes +//********************************************************************** + +} diff --git a/libs/FLib/JWizard/org/freixas/jwizard/JWizardPanel.java b/libs/FLib/JWizard/org/freixas/jwizard/JWizardPanel.java new file mode 100644 index 0000000..840321e --- /dev/null +++ b/libs/FLib/JWizard/org/freixas/jwizard/JWizardPanel.java @@ -0,0 +1,429 @@ +//********************************************************************** +// Package +//********************************************************************** + +package org.freixas.jwizard; + +//********************************************************************** +// Import list +//********************************************************************** + +import java.awt.*; +import javax.swing.*; + +/** + * This class creates a panel that can be used for a single step in a + * Wizard dialog. See the class documentation for JWizardDialog for + * more information on using this class together with JWizardDialog. + *

+ * Components added to this panel should be added to the panel + * returned by getContentPanel(). + *


+ * This program is free software; you can redistribute it and/or + * modify it under the terms of the Artistic License. You should have + * received a copy of the Artistic License along with this program. If + * not, a copy is available at + * + * opensource.org. + * + * @see JWizardDialog + * @author Antonio Freixas + */ + +// Copyright © 2004 Antonio Freixas +// All Rights Reserved. + +public class JWizardPanel + extends JPanel +{ + +//********************************************************************** +// Private Members +//********************************************************************** + +// The JWizardDialog parent + +JWizardDialog dialogParent; + +// The step title + +JPanel titlePanel; +String stepTitle; +JLabel stepTitleLabel; + +// The content pane + +JPanel contentPane; + +// The back and next steps + +int backStep = -1; +int nextStep = -1; + +// Flags the first time the component is added to a window + +boolean firstNotify = true; + +//********************************************************************** +// Constructors +//********************************************************************** + +/** + * Creates a new JWizardPanel with a double buffer and a flow layout. + * The flow layout is assigned to the panel accessed through + * getContentPane(). + */ + +public +JWizardPanel() +{ + super(); + init(new FlowLayout()); +} + +/** + * Create a new buffered JWizardPanel with the specified layout + * manager. The layout is assigned to the panel accessed through + * getContentPane(). + * + * @param layout The LayoutManager for the content pane. + */ + +public +JWizardPanel( + LayoutManager layout) +{ + super(); + init(layout); +} + +/** + * Creates a new JWizardPanel a flow layout and the specified + * buffering strategy. If isDoubleBuffered is true, the JWizardPanel + * will use a double buffer. The layout is assigned to the panel + * accessed through getContentPane(). + * + * @param isDoubleBuffered True for double-buffering, which uses + * additional memory space to achieve fast, flicker-free updates. + */ + +public +JWizardPanel( + boolean isDoubleBuffered) +{ + super(isDoubleBuffered); + init(new FlowLayout()); +} + +/** + * Creates a new JWizardPanel with the specified layout manager and + * buffering strategy. The layout is assigned to the panel accessed + * through getContentPane(). + * + * @param layout The LayoutManager for the content pane. + * @param isDoubleBuffered True for double-buffering, which uses + * additional memory space to achieve fast, flicker-free updates. + */ + +public +JWizardPanel( + LayoutManager layout, + boolean isDoubleBuffered) +{ + super(isDoubleBuffered); + init(layout); +} + +//********************************************************************** +// Public +//********************************************************************** + +/** + * Set the title to use for this step. Normally this title would be + * unique for each wizards step. + * + * @param stepTitle The title to use for this step. + */ + +public void +setStepTitle( + String stepTitle) +{ + this.stepTitle = stepTitle; + stepTitleLabel.setText(stepTitle); + + stepTitleLabel.invalidate(); + validate(); +} + +/** + * Get the step title to use for this step. + * + * @return The step title to use for this step. + */ + +public String +getStepTitle() +{ + return stepTitle; +} + +/** + * Get a JPanel to use for adding your own components to this + * WizardPanel. Do not add components directly to the JWizardPanel. + * The JPanel uses the layout given in the JWizardPanel constructor. + * + * @return The JPanel to use for adding components for this wizard + * step. + */ + +public JPanel +getContentPane() +{ + return contentPane; +} + +/** + * Get the wizard step to go to when the Back button is pressed. + * + * @return The wizard step to go to when the Back button is pressed. + */ + +public int +getBackStep() +{ + return backStep; +} + +/** + * Set the wizard step to go to when the Back button is pressed. This + * should be set in the constructor of the JWizardPanel subclass since + * it determines whether the Back button is enabled or not. + * + * @param backStep The wizard step to go to when the Back button is pressed. + */ + +public void +setBackStep( + int backStep) +{ + this.backStep = backStep; + JWizardDialog dialog = getWizardParent(); + if (dialog != null) dialog.setButtonStates(); +} + +/** + * Get the wizard step to go to when the Next button is pressed. + * + * @return The wizard step to go to when the Next button is pressed. + */ + +public int +getNextStep() +{ + return nextStep; +} + +/** + * Set the wizard step to go to when the Next button is pressed. This + * should be set in the constructor of the JWizardPanel subclass since + * it determines whether the Next and Finish buttons are enabled or not. + * + * @param nextStep The wizard step to go to when the Next button is pressed. + */ + +public void +setNextStep( + int nextStep) +{ + this.nextStep = nextStep; + JWizardDialog dialog = getWizardParent(); + if (dialog != null) dialog.setButtonStates(); +} + +/** + * Returns the JWizardDialog in which this JWizardPanel resides. This + * is valid only after the panel has been added to the dialog. + * + * @return The JWizardDialog in which this JWizardPanel resides. + */ + +public JWizardDialog +getWizardParent() +{ + return dialogParent; +} + +/** + * Do not call directly. + */ + +public void +addNotify() +{ + if (firstNotify) { + Font font = stepTitleLabel.getFont(); + font = font.deriveFont(Font.BOLD, font.getSize() * 14 / 10); + stepTitleLabel.setFont(font); + firstNotify = false; + } + super.addNotify(); +} + +// WizardPanels are equal if they are the same object, so the default +// equals() and hashCode() methods are acceptable. I'm not using the +// paramString() method for debugging, so the default is OK. + +//********************************************************************** +// Package Public +//********************************************************************** + +/** + * Set the JWizardDialog parent for this JWizardPanel. + * + * @param dialogParent The JWizardPanel parent for this JWizardPanel. + */ + +void +setWizardParent( + JWizardDialog dialogParent) +{ + this.dialogParent = dialogParent; +} + +/** + * Calls makingVisible(). This allows the JWizardDialog to call the + * protected method makingVisible(). + * + * @see #makingVisible() + */ + +void +doMakingVisible() +{ + makingVisible(); +} + +/** + * Calls back(). This allows the JWizardDialog to call the protected + * method back(). + * + * @see #back() + */ + +void +doBack() +{ + back(); +} + +/** + * Calls next(). This allows the JWizardDialog to call the protected + * method next(). + * + * @see #next() + */ + +void +doNext() +{ + next(); +} + +/** + * Calls help(). This allows the JWizardDialog to call the protected + * method help(). + * + * @see #help() + */ + +void +doHelp() +{ + help(); +} + +//********************************************************************** +// Protected +//********************************************************************** + +/** + * Called just prior to making this panel visible. This is a hook in + * case information in the panel needs to be created dynamically based + * on previous steps. + */ + +protected void +makingVisible() +{ +} + +/** + * Called when the Back button is pressed. By default this displays + * the wizard step set by setBackStep(). + * + * @see #setBackStep(int) + */ + +protected void +back() +{ + dialogParent.goTo(getBackStep()); +} + +/** + * Called when the Next button is pressed. By default this displays + * the wizard step set by setNextStep(). + * + * @see #setNextStep(int) + */ + +protected void +next() +{ + dialogParent.goTo(getNextStep()); +} + +/** + * Called when the Help button is pressed. By default this does nothing. + */ + +protected void +help() +{ +} + +//********************************************************************** +// Private +//********************************************************************** + +/** + * Initialize the JWizardPanel. + * + * @param layout The layout to use. + */ + +private void +init( + LayoutManager layout) +{ + // Set the layout for the JWizardPanel + + setLayout(new BorderLayout(0, 5)); + + // Set the layout for the content area + + contentPane = new JPanel(layout); + + // Step title + + titlePanel = new JPanel(new BorderLayout(0, 5)); + titlePanel.add(new JSeparator(), BorderLayout.SOUTH); + stepTitleLabel = new JLabel(" "); + titlePanel.add(stepTitleLabel); + + add(titlePanel, BorderLayout.NORTH); + add(contentPane); +} + +} diff --git a/libs/FLib/JWizard/org/freixas/jwizard/images/Back16.gif b/libs/FLib/JWizard/org/freixas/jwizard/images/Back16.gif new file mode 100644 index 0000000..f48362d Binary files /dev/null and b/libs/FLib/JWizard/org/freixas/jwizard/images/Back16.gif differ diff --git a/libs/FLib/JWizard/org/freixas/jwizard/images/Forward16.gif b/libs/FLib/JWizard/org/freixas/jwizard/images/Forward16.gif new file mode 100644 index 0000000..d25a3f9 Binary files /dev/null and b/libs/FLib/JWizard/org/freixas/jwizard/images/Forward16.gif differ diff --git a/libs/FLib/JWizard/org/freixas/jwizard/images/Help16.gif b/libs/FLib/JWizard/org/freixas/jwizard/images/Help16.gif new file mode 100644 index 0000000..dc5c2d3 Binary files /dev/null and b/libs/FLib/JWizard/org/freixas/jwizard/images/Help16.gif differ diff --git a/libs/FLib/JWizard/project.dtd b/libs/FLib/JWizard/project.dtd new file mode 100644 index 0000000..dee3c51 --- /dev/null +++ b/libs/FLib/JWizard/project.dtd @@ -0,0 +1,5193 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/FLib/NOTES.txt b/libs/FLib/NOTES.txt new file mode 100644 index 0000000..f4f1e86 --- /dev/null +++ b/libs/FLib/NOTES.txt @@ -0,0 +1,35 @@ + Release Notes for FLib + +Release 1.1.1 + + This version has some bug fixes and one enhancement. The bug fixes + are: + + * The year increment button was using the wrong icon. + * Calling setDateFormat() on a JCalendarCombo caused the time to + become null and unsettable. + + The enhancement is that you can now set the font of each element of + the calendar component. + +Release 1.1 + + The major changes to this release are: + + * TableLayout has been added. + * JCalendar was updated to work with JDK 1.5. + * Ant 1.6.2 was used to build the project. + * The documentation was revised and expanded. + +Release 1.0.1 + + This version has some minor fixes to the 1.0 release, mostly in some + reworking of the Ant build files. + + * Fixed various problems in the Ant build files. + * Created a top-level Ant build file. + * The isFinished() method in JWizardDialog is now public. + +Release 1.0 + + Initial release. diff --git a/libs/FLib/TableLayout/License.txt b/libs/FLib/TableLayout/License.txt new file mode 100644 index 0000000..be12e9d --- /dev/null +++ b/libs/FLib/TableLayout/License.txt @@ -0,0 +1,123 @@ + Artistic License + +Preamble + +The intent of this document is to state the conditions under which a +Package may be copied, such that the Copyright Holder maintains some +semblance of artistic control over the development of the package, +while giving the users of the package the right to use and distribute +the Package in a more-or-less customary fashion, plus the right to +make reasonable modifications. + +Definitions: + + * "Package" refers to the collection of files distributed by the + Copyright Holder, and derivatives of that collection of files + created through textual modification. + + * "Standard Version" refers to such a Package if it has not been + modified, or has been modified in accordance with the wishes of + the Copyright Holder. + + * "Copyright Holder" is whoever is named in the copyright or + copyrights for the package. + + * "You" is you, if you're thinking about copying or distributing + this Package. + + * "Reasonable copying fee" is whatever you can justify on the + basis of media cost, duplication charges, time of people + involved, and so on. (You will not be required to justify it to + the Copyright Holder, but only to the computing community at + large as a market that must bear the fee.) + + * "Freely Available" means that no fee is charged for the item + itself, though there may be fees involved in handling the item. + It also means that recipients of the item may redistribute it + under the same conditions they received it. + +1. You may make and give away verbatim copies of the source form of + the Standard Version of this Package without restriction, provided + that you duplicate all of the original copyright notices and + associated disclaimers. + +2. You may apply bug fixes, portability fixes and other modifications + derived from the Public Domain or from the Copyright Holder. A + Package modified in such a way shall still be considered the + Standard Version. + +3. You may otherwise modify your copy of this Package in any way, + provided that you insert a prominent notice in each changed file + stating how and when you changed that file, and provided that you + do at least ONE of the following: + + a) place your modifications in the Public Domain or otherwise make + them Freely Available, such as by posting said modifications to + Usenet or an equivalent medium, or placing the modifications on + a major archive site such as ftp.uu.net, or by allowing the + Copyright Holder to include your modifications in the Standard + Version of the Package. + + b) use the modified Package only within your corporation or + organization. + + c) rename any non-standard executables so the names do not + conflict with standard executables, which must also be + provided, and provide a separate manual page for each + non-standard executable that clearly documents how it differs + from the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + +4. You may distribute the programs of this Package in object code or + executable form, provided that you do at least ONE of the + following: + + a) distribute a Standard Version of the executables and library + files, together with instructions (in the manual page or + equivalent) on where to get the Standard Version. + + b) accompany the distribution with the machine-readable source of + the Package with your modifications. + + c) accompany any non-standard executables with their corresponding + Standard Version executables, giving the non-standard + executables non-standard names, and clearly documenting the + differences in manual pages (or equivalent), together with + instructions on where to get the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + +5. You may charge a reasonable copying fee for any distribution of + this Package. You may charge any fee you choose for support of this + Package. You may not charge a fee for this Package itself. However, + you may distribute this Package in aggregate with other (possibly + commercial) programs as part of a larger (possibly commercial) + software distribution provided that you do not advertise this + Package as a product of your own. + +6. The scripts and library files supplied as input to or produced as + output from the programs of this Package do not automatically fall + under the copyright of this Package, but belong to whomever + generated them, and may be sold commercially, and may be aggregated + with this Package. + +7. C or perl subroutines supplied by you and linked into this Package + shall not be considered part of this Package. + +8. Aggregation of this Package with a commercial distribution is + always permitted provided that the use of this Package is embedded; + that is, when no overt attempt is made to make this Package's + interfaces visible to the end user of the commercial distribution. + Such use shall not be construed as a distribution of this Package. + +9. The name of the Copyright Holder may not be used to endorse or + promote products derived from this software without specific prior + written permission. + +10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + PURPOSE. + +The End diff --git a/libs/FLib/TableLayout/README.txt b/libs/FLib/TableLayout/README.txt new file mode 100644 index 0000000..6a3ac6e --- /dev/null +++ b/libs/FLib/TableLayout/README.txt @@ -0,0 +1,34 @@ + TableLayout + +This package provides a TableLayout manager for use in Java programs. + +This program is free software; you can redistribute it and/or modify +it under the terms of the Artistic License. You should have received a +copy of the Artistic License along with this program (in file +License.txt). If not, a copy is available at + + http://opensource.org/licenses/artistic-license.php + +To build it you'll need Ant. I used version 1.6.2. Use + + ant all + +This will create build/tablelayout.jar. To create the API +documentation, use + + ant javadoc + +To view all the documentation, view doc/index.html. + +There is a tutorial in doc/tutorial.html. There is also a sample Java +program that uses the TableLayout class. You can build and run this +program with + + ant runExample1 + +In addition, there is a tool you can use to practice using the +TableLayout. It's called TableExplorer and follows the approach of a +similar tool written for the GridBagLayout. Build and run this program +with + + ant runTableExplorer diff --git a/libs/FLib/TableLayout/build.xml b/libs/FLib/TableLayout/build.xml new file mode 100644 index 0000000..99384a6 --- /dev/null +++ b/libs/FLib/TableLayout/build.xml @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+
+ + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/libs/FLib/TableLayout/doc-templates/License.html b/libs/FLib/TableLayout/doc-templates/License.html new file mode 100644 index 0000000..d5fbdc1 --- /dev/null +++ b/libs/FLib/TableLayout/doc-templates/License.html @@ -0,0 +1,180 @@ + + + + + + +

Artistic License

+ +

Preamble

+ +

The intent of this document is to state the conditions under which a + Package may be copied, such that the Copyright Holder maintains some + semblance of artistic control over the development of the package, + while giving the users of the package the right to use and distribute + the Package in a more-or-less customary fashion, plus the right to + make reasonable modifications.

+ +

Definitions:

+ +
    + +
  • "Package" refers to the collection of files distributed by the + Copyright Holder, and derivatives of that collection of files created + through textual modification.
  • + +
  • "Standard Version" refers to such a Package if it has not been + modified, or has been modified in accordance with the wishes of the + Copyright Holder.
  • + +
  • "Copyright Holder" is whoever is named in the copyright or + copyrights for the package.
  • + +
  • "You" is you, if you're thinking about copying or distributing + this Package.
  • + +
  • "Reasonable copying fee" is whatever you can justify on the basis + of media cost, duplication charges, time of people involved, and so + on. (You will not be required to justify it to the Copyright Holder, + but only to the computing community at large as a market that must + bear the fee.)
  • + +
  • "Freely Available" means that no fee is charged for the item + itself, though there may be fees involved in handling the item. It + also means that recipients of the item may redistribute it under the + same conditions they received it.
  • + +
+ +
+ +
    + +
  1. You may make and give away verbatim copies of the source form of + the Standard Version of this Package without restriction, provided + that you duplicate all of the original copyright notices and + associated disclaimers.
  2. + +
  3. You may apply bug fixes, portability fixes and other modifications + derived from the Public Domain or from the Copyright Holder. A Package + modified in such a way shall still be considered the Standard + Version.
  4. + +
  5. You may otherwise modify your copy of this Package in any way, + provided that you insert a prominent notice in each changed file + stating how and when you changed that file, and provided that you do + at least ONE of the following: + +
      + +
    1. place your modifications in the Public Domain or otherwise make + them Freely Available, such as by posting said modifications to Usenet + or an equivalent medium, or placing the modifications on a major + archive site such as ftp.uu.net, or by allowing the Copyright Holder + to include your modifications in the Standard Version of the Package.
    2. + +
    3. use the modified Package only within your corporation or + organization.
    4. + +
    5. rename any non-standard executables so the names do not conflict + with standard executables, which must also be provided, and provide a + separate manual page for each non-standard executable that clearly + documents how it differs from the Standard Version.
    6. + +
    7. make other distribution arrangements with the Copyright + Holder.
    8. + +
    +
  6. + +
  7. You may distribute the programs of this Package in object code or + executable form, provided that you do at least ONE of the following: + +
      + +
    1. distribute a Standard Version of the executables and library + files, together with instructions (in the manual page or equivalent) + on where to get the Standard Version.
    2. + +
    3. accompany the distribution with the machine-readable source of the + Package with your modifications.
    4. + +
    5. accompany any non-standard executables with their corresponding + Standard Version executables, giving the non-standard executables + non-standard names, and clearly documenting the differences in manual + pages (or equivalent), together with instructions on where to get the + Standard Version.
    6. + +
    7. make other distribution arrangements with the Copyright + Holder.
    8. + +
    +
  8. + +
  9. You may charge a reasonable copying fee for any distribution of + this Package. You may charge any fee you choose for support of this + Package. You may not charge a fee for this Package itself. However, + you may distribute this Package in aggregate with other (possibly + commercial) programs as part of a larger (possibly commercial) + software distribution provided that you do not advertise this Package + as a product of your own.
  10. + +
  11. The scripts and library files supplied as input to or produced as + output from the programs of this Package do not automatically fall + under the copyright of this Package, but belong to whomever generated + them, and may be sold commercially, and may be aggregatedwith this + Package.
  12. + +
  13. r perl subroutines supplied by you and linked into this Package + shall not be considered part of this Package.
  14. + +
  15. Aggregation of this Package with a commercial distribution is + always permitted provided that the use of this Package is embedded; + that is, when no overt attempt is made to make this Package's + interfaces visible to the end user of the commercial distribution. + Such use shall not be construed as a distribution of this Package.
  16. + +
  17. The name of the Copyright Holder may not be used to endorse or + promote products derived from this software without specific prior + written permission.
  18. + +
  19. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + PURPOSE.
  20. + +
+ +

The End

+ + diff --git a/libs/FLib/TableLayout/doc/example/Example1.java b/libs/FLib/TableLayout/doc/example/Example1.java new file mode 100644 index 0000000..797d1e7 --- /dev/null +++ b/libs/FLib/TableLayout/doc/example/Example1.java @@ -0,0 +1,180 @@ +//********************************************************************** +// Package +//********************************************************************** + +package doc.example; + +//********************************************************************** +// Import list +//********************************************************************** + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; + +import org.freixas.tablelayout.*; + +/** + * This example compares the GridBagLayout to the TableLayout. The + * same layout is created using each layout manager. The layouts are + * displayed in their own window. + * + * @author Antonio Freixas + */ + +// Copyright © 2004 Antonio Freixas +// All Rights Reserved. + +public class Example1 +{ + +//********************************************************************** +// Public Constants +//********************************************************************** + +//********************************************************************** +// Private Constants +//********************************************************************** + +//********************************************************************** +// Private Members +//********************************************************************** + +//********************************************************************** +// main +//********************************************************************** + +public static void +main( + String[] args) +{ + new Example1(); +} + +//********************************************************************** +// Constructors +//********************************************************************** + +/** + * Create the two windows and display them. + */ + +public +Example1() +{ + JFrame frame1 = createGridBagLayout(); + JFrame frame2 = createTableLayout(); + frame1.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame2.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame1.pack(); + frame2.pack(); + frame1.setLocation(10, 100); + frame2.setLocation(400, 100); + frame1.setVisible(true); + frame2.setVisible(true); +} + +//********************************************************************** +// Private +//********************************************************************** + +/** + * Create the layout using GridBagLayout. This code comes from the API + * page for GridBagLayout. + * + * @return The JFrame containing the layout. + */ + +public JFrame +createGridBagLayout() +{ + JFrame frame = new JFrame("GridBagLayout"); + + GridBagLayout gridbag = new GridBagLayout(); + GridBagConstraints c = new GridBagConstraints(); + + JPanel panel = new JPanel(gridbag); + frame.getContentPane().add(panel); + + c.fill = GridBagConstraints.BOTH; + c.weightx = 1.0; + makebutton(panel, "Button1", gridbag, c); + makebutton(panel, "Button2", gridbag, c); + makebutton(panel, "Button3", gridbag, c); + + c.gridwidth = GridBagConstraints.REMAINDER; //end row + makebutton(panel, "Button4", gridbag, c); + + c.weightx = 0.0; //reset to the default + makebutton(panel, "Button5", gridbag, c); //another row + + c.gridwidth = GridBagConstraints.RELATIVE; //next-to-last in row + makebutton(panel, "Button6", gridbag, c); + + c.gridwidth = GridBagConstraints.REMAINDER; //end row + makebutton(panel, "Button7", gridbag, c); + + c.gridwidth = 1; //reset to the default + c.gridheight = 2; + c.weighty = 1.0; + makebutton(panel, "Button8", gridbag, c); + + c.weighty = 0.0; //reset to the default + c.gridwidth = GridBagConstraints.REMAINDER; //end row + c.gridheight = 1; //reset to the default + makebutton(panel, "Button9", gridbag, c); + makebutton(panel, "Button10", gridbag, c); + + return frame; +} + +/** + * Helper method for createGridBagLayout(). + * + * @param panel The panel to add the button to. + * @param name The button's label. + * @param gridbag The GridBagLayout to use. + * @param c The constraints to use. + */ + +private void +makebutton( + JPanel panel, + String name, + GridBagLayout gridbag, + GridBagConstraints c) +{ + JButton button = new JButton(name); + gridbag.setConstraints(button, c); + panel.add(button); +} + +/** + * Create the layout using TableLayout. + * + * @return The JFrame containing the layout. + */ + +public JFrame +createTableLayout() +{ + JFrame frame = new JFrame("TableLayout"); + + JPanel panel = new JPanel(new TableLayout("cols=4")); + frame.getContentPane().add(panel); + + panel.add(new JButton("Button1")); + panel.add(new JButton("Button2")); + panel.add(new JButton("Button3")); + panel.add(new JButton("Button4")); + panel.add(new JButton("Button5"), "cspan=4"); + panel.add(new JButton("Button6"), "cspan=3"); + panel.add(new JButton("Button7")); + panel.add(new JButton("Button8"), "rspan=2"); + panel.add(new JButton("Button9"), "cspan=3"); + panel.add(new JButton("Button10"), "cspan=3 rweight=1"); + + return frame; +} + +} diff --git a/libs/FLib/TableLayout/doc/example/TableExplorer.java b/libs/FLib/TableLayout/doc/example/TableExplorer.java new file mode 100644 index 0000000..d66c497 --- /dev/null +++ b/libs/FLib/TableLayout/doc/example/TableExplorer.java @@ -0,0 +1,1230 @@ +//********************************************************************** +// Package +//********************************************************************** + +package doc.example; + +//********************************************************************** +// Import list +//********************************************************************** + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.event.*; +import java.util.*; + +import org.freixas.tablelayout.*; + +/** + * This class allows a user to dynamically alter a set of components + * using the TableLayout class to explore the layout's abilities. + * + * @author Antonio Freixas + */ + +public class TableExplorer + extends JFrame + implements CaretListener, ActionListener, ListSelectionListener, + FocusListener, MenuListener +{ + +//********************************************************************** +// Constants +//********************************************************************** + +static final String[] tablePositionList = { + "Default", + "tn", "tne", "tnw", + "ts", "tse", "tsw", + "te", "tw", "tc" +}; + +static final String[] tableFillList = { + "Default", "tfh", "tfv", "tf" +}; + +static final String[] positionList = { + "Default", + "n", "ne", "nw", + "s", "se", "sw", + "e", "w", "c" +}; + +static final String[] fillList = { + "Default", "fh", "fv", "f" +}; + +//********************************************************************** +// Fields +//********************************************************************** + +JFrame layout; +JPanel layoutPane; +JFrame code; +JPanel codePane; + +HashMap compHash = new HashMap(); +HashMap attrHash = new HashMap(); + +JMenu fileMenu; +JMenu windowMenu; +JMenu helpMenu; + +JMenuItem exitItem; +JMenuItem previewItem; +JMenuItem packItem; +JMenuItem codeItem; +JMenuItem generateItem; +JMenuItem aboutItem; + +JButton upButton; +JButton downButton; +JButton removeButton; +JButton addButton; + +JList compList; +DefaultListModel compListModel; +JTextField compEntryField; + +JTextField columnsField; +JTextField[] tableInsetFields = new JTextField[4]; +JTextField rowGapField; +JTextField colGapField; +JComboBox tablePositionBox; +JComboBox tableFillBox; + +JTextField[] tableCellInsetFields = new JTextField[4]; +JComboBox tableCellPositionBox; +JComboBox tableCellFillBox; +JTextField tableRowWeightField; +JTextField tableColWeightField; + +JTextField tableAttributesField; + +JTextField[] insetFields = new JTextField[4]; +JComboBox positionBox; +JComboBox fillBox; +JTextField rowWeightField; +JTextField colWeightField; +JTextField colPositionField; +JTextField skipCellsField; +JTextField rowSpanField; +JTextField colSpanField; + +JTextField cellAttributesField; + +JTextArea codeTextArea; +JScrollPane codeTextScroll; + +String textWhenFocusGained = null; +boolean ignoreEvents = false; + +TableAttributes tableAttributes = null; + +//********************************************************************** +// Main +//********************************************************************** + +static public void +main( + String[] args) +{ + new TableExplorer(); +} + +//********************************************************************** +// Constructors +//********************************************************************** + +/** + * Create the TableExplorer JFrame. + */ + +TableExplorer() +{ + super("TableExplorer"); + + // Table with three columns + // Row 1: Buttons for managing component list + // Row 2: Component list + // Row 3: Attribute settings + + setJMenuBar(createJMenuBar()); + + getContentPane().setLayout( + new TableLayout("cols=3 cgap=5 " + + "titop=2 tibottom=2 tileft=2 tiright=2")); + + getContentPane().add(createButtonPane()); + getContentPane().add(createListPane(), "cweight=1"); + getContentPane().add(createAttributePane(), "n fh"); + + pack(); + setVisible(true); + + layout = new JFrame("Table Layout Preview"); + layoutPane = (JPanel)layout.getContentPane(); + layoutPane.setName("DEBUG"); + layoutPane.setLayout(new TableLayout()); + layoutPane.setOpaque(true); + + code = new JFrame("Table Layout Code"); + codePane = createCodePane(); + code.setContentPane(codePane); + code.pack(); + + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + compEntryField.grabFocus(); + + layout.setSize(300, 300); +} + +//********************************************************************** +// Public +//********************************************************************** + +public void +caretUpdate( + CaretEvent e) +{ + if (e.getSource() == compEntryField) { + String text = compEntryField.getText(); + addButton.setEnabled(text.length() > 0); + } +} + +public void +actionPerformed( + ActionEvent e) +{ + if (ignoreEvents) return; + + if (e.getSource() == addButton || + e.getSource() == compEntryField) { + + String name = compEntryField.getText(); + + JButton button = new JButton(name); + addToLayout(button); + compHash.put(name, button); + attrHash.put(name, new Attributes()); + compListModel.addElement(name); + compEntryField.setText(""); + addButton.setEnabled(false); + } + + else if (e.getSource() == removeButton) { + String name = (String)compList.getSelectedValue(); + if (name != null) { + Component c = (Component)compHash.get(name); + layoutPane.remove(c); + compHash.remove(name); + attrHash.remove(name); + compListModel.removeElement(name); + removeButton.setEnabled(false); + layoutPane.revalidate(); + } + } + + else if (e.getSource() == upButton) { + int index = compList.getSelectedIndex(); + if (index > 0) { + String name = (String)compListModel.elementAt(index); + compListModel.removeElementAt(index); + compListModel.insertElementAt(name, index - 1); + compList.setSelectedIndex(index - 1); + + Component c = (Component)compHash.get(name); + Attributes a = (Attributes)attrHash.get(name); + layoutPane.remove(index); + layoutPane.add(c, a.toString(), index - 1); + layoutPane.revalidate(); + } + } + + else if (e.getSource() == downButton) { + int index = compList.getSelectedIndex(); + if (index > -1 && index < compListModel.getSize() - 1) { + String name = (String)compListModel.elementAt(index); + compListModel.removeElementAt(index); + compListModel.insertElementAt(name, index + 1); + compList.setSelectedIndex(index + 1); + + Component c = (Component)compHash.get(name); + Attributes a = (Attributes)attrHash.get(name); + layoutPane.remove(index); + layoutPane.add(c, a.toString(), index + 1); + layoutPane.revalidate(); + } + } + + else if (e.getSource() == insetFields[0] || + e.getSource() == insetFields[1] || + e.getSource() == insetFields[2] || + e.getSource() == insetFields[3] || + e.getSource() == positionBox || + e.getSource() == fillBox || + e.getSource() == rowWeightField || + e.getSource() == colWeightField || + e.getSource() == colPositionField || + e.getSource() == skipCellsField || + e.getSource() == rowSpanField || + e.getSource() == colSpanField) { + String name = (String)compList.getSelectedValue(); + changeLayout(name); + } + + else if (e.getSource() == columnsField || + e.getSource() == tableInsetFields[0] || + e.getSource() == tableInsetFields[1] || + e.getSource() == tableInsetFields[2] || + e.getSource() == tableInsetFields[3] || + e.getSource() == rowGapField || + e.getSource() == colGapField || + e.getSource() == tablePositionBox || + e.getSource() == tableFillBox || + e.getSource() == tableCellInsetFields[0] || + e.getSource() == tableCellInsetFields[1] || + e.getSource() == tableCellInsetFields[2] || + e.getSource() == tableCellInsetFields[3] || + e.getSource() == tableCellPositionBox || + e.getSource() == tableCellFillBox || + e.getSource() == tableRowWeightField || + e.getSource() == tableColWeightField) { + changeTableLayout(); + } + + else if (e.getSource() == exitItem) { + System.exit(0); + } + + else if (e.getSource() == previewItem) { + if (layout.isVisible()) { + layout.setVisible(false); + } + else { + layout.setVisible(true); + } + } + + else if (e.getSource() == packItem) { + layout.pack(); + } + + else if (e.getSource() == codeItem) { + if (code.isVisible()) { + code.setVisible(false); + } + else { + generateCode(); + code.setVisible(true); + } + } + + else if (e.getSource() == generateItem) { + generateCode(); + } + + else if (e.getSource() == aboutItem) { + JOptionPane.showMessageDialog(this, + "" + + "

Table Explorer V1.0

" + + "Written by Antonio Freixas
" + + "tonyf@freixas.org", + "About Table Explorer
", + JOptionPane.INFORMATION_MESSAGE); + } +} + +public void +valueChanged( + ListSelectionEvent e) +{ + if (ignoreEvents) return; + + if (e.getSource() == compList) { + String name = (String)compList.getSelectedValue(); + int index = compList.getSelectedIndex(); + + boolean hasObject = name != null; + + removeButton.setEnabled(hasObject); + upButton.setEnabled(hasObject && index != 0); + downButton.setEnabled(hasObject && + index != compListModel.getSize() - 1); + enableAttributes(hasObject); + + if (hasObject) { + Attributes attributes = (Attributes)attrHash.get(name); + setAttributes(attributes); + } + } +} + +public void +focusGained( + FocusEvent e) +{ + if (e.getSource() == insetFields[0] || + e.getSource() == insetFields[1] || + e.getSource() == insetFields[2] || + e.getSource() == insetFields[3] || + e.getSource() == rowWeightField || + e.getSource() == colWeightField || + e.getSource() == colPositionField || + e.getSource() == skipCellsField || + e.getSource() == rowSpanField || + e.getSource() == colSpanField|| + e.getSource() == columnsField || + e.getSource() == tableInsetFields[0] || + e.getSource() == tableInsetFields[1] || + e.getSource() == tableInsetFields[2] || + e.getSource() == tableInsetFields[3] || + e.getSource() == rowGapField || + e.getSource() == colGapField || + e.getSource() == tableCellInsetFields[0] || + e.getSource() == tableCellInsetFields[1] || + e.getSource() == tableCellInsetFields[2] || + e.getSource() == tableCellInsetFields[3] || + e.getSource() == tableRowWeightField || + e.getSource() == tableColWeightField) { + + JTextField field = (JTextField)e.getSource(); + textWhenFocusGained = field.getText(); + } + else if (e.getSource() == positionBox || + e.getSource() == fillBox || + e.getSource() == tablePositionBox || + e.getSource() == tableFillBox || + e.getSource() == tableCellPositionBox || + e.getSource() == tableCellFillBox) { + + JComboBox box = (JComboBox)e.getSource(); + textWhenFocusGained = (String)box.getSelectedItem(); + } + else { + textWhenFocusGained = null; + } +} + +public void +focusLost( + FocusEvent e) +{ + if (textWhenFocusGained != null) { + if (e.getSource() == insetFields[0] || + e.getSource() == insetFields[1] || + e.getSource() == insetFields[2] || + e.getSource() == insetFields[3] || + e.getSource() == rowWeightField || + e.getSource() == colWeightField || + e.getSource() == colPositionField || + e.getSource() == skipCellsField || + e.getSource() == rowSpanField || + e.getSource() == colSpanField) { + + JTextField field = (JTextField)e.getSource(); + if (!textWhenFocusGained.equals(field.getText())) { + changeLayout(); + } + } + else if (e.getSource() == positionBox || + e.getSource() == fillBox) { + JComboBox box = (JComboBox)e.getSource(); + if (!textWhenFocusGained.equals(box.getSelectedItem())) { + changeLayout(); + } + } + else if (e.getSource() == columnsField || + e.getSource() == tableInsetFields[0] || + e.getSource() == tableInsetFields[1] || + e.getSource() == tableInsetFields[2] || + e.getSource() == tableInsetFields[3] || + e.getSource() == rowGapField || + e.getSource() == colGapField || + e.getSource() == tableCellInsetFields[0] || + e.getSource() == tableCellInsetFields[1] || + e.getSource() == tableCellInsetFields[2] || + e.getSource() == tableCellInsetFields[3] || + e.getSource() == tableRowWeightField || + e.getSource() == tableColWeightField) { + + JTextField field = (JTextField)e.getSource(); + if (!textWhenFocusGained.equals(field.getText())) { + changeTableLayout(); + } + } + + else if (e.getSource() == tablePositionBox || + e.getSource() == tableFillBox || + e.getSource() == tableCellPositionBox || + e.getSource() == tableCellFillBox) { + + JComboBox box = (JComboBox)e.getSource(); + if (!textWhenFocusGained.equals(box.getSelectedItem())) { + changeTableLayout(); + } + } + } + + textWhenFocusGained = null; +} + +public void +menuCanceled( + MenuEvent e) +{ +} + +public void +menuDeselected( + MenuEvent e) +{ +} + +public void +menuSelected( + MenuEvent e) +{ + if (e.getSource() == windowMenu) { + if (layout.isVisible()) { + previewItem.setText("Hide Preview Window"); + } + else { + previewItem.setText("Show Preview Window"); + } + if (code.isVisible()) { + codeItem.setText("Hide Code Window"); + } + else { + codeItem.setText("Show Code Window"); + } + } +} + +//********************************************************************** +// Package Public +//********************************************************************** + +JMenuBar +createJMenuBar() +{ + JMenuBar menuBar = new JMenuBar(); + + fileMenu = new JMenu("File"); + menuBar.add(fileMenu); + windowMenu = new JMenu("Window"); + windowMenu.addMenuListener(this); + menuBar.add(windowMenu); + helpMenu = new JMenu("Help"); + menuBar.add(helpMenu); + + exitItem = new JMenuItem("Exit"); + exitItem.addActionListener(this); + fileMenu.add(exitItem); + + previewItem = new JMenuItem("Show Preview Window"); + previewItem.addActionListener(this); + windowMenu.add(previewItem); + + packItem = new JMenuItem("Pack Preview Window"); + packItem.addActionListener(this); + windowMenu.add(packItem); + + windowMenu.add(new JSeparator()); + + codeItem = new JMenuItem("Show Code Window"); + codeItem.addActionListener(this); + windowMenu.add(codeItem); + + generateItem = new JMenuItem("Generate Code"); + generateItem.addActionListener(this); + windowMenu.add(generateItem); + + aboutItem = new JMenuItem("About TableExplorer..."); + aboutItem.addActionListener(this); + helpMenu.add(aboutItem); + + return menuBar; +} + +Component +createButtonPane() +{ + JPanel topLevel = new JPanel(new TableLayout("cols=1")); + + upButton = new JButton("Up"); + upButton.setEnabled(false); + upButton.addActionListener(this); + + downButton = new JButton("Down"); + downButton.setEnabled(false); + downButton.addActionListener(this); + + removeButton = new JButton("Remove"); + removeButton.setEnabled(false); + removeButton.addActionListener(this); + + addButton = new JButton("Add"); + addButton.addActionListener(this); + + topLevel.add(upButton); + topLevel.add(downButton, "rweight=1 n fh"); + topLevel.add(removeButton, "rweight=1 s fh "); + topLevel.add(addButton); + + return topLevel; +} + +Component +createListPane() +{ + JPanel topLevel = new JPanel(new TableLayout("cols=1 rgap=2")); + + compListModel = new DefaultListModel(); + compList = new JList(compListModel); + compList.setVisibleRowCount(20); + compList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + compList.addListSelectionListener(this); + + compEntryField = new JTextField("Start Here!"); + compEntryField.selectAll(); + compEntryField.setColumns(20); + compEntryField.addCaretListener(this); + compEntryField.addActionListener(this); + + topLevel.add(compList, "rweight=1"); + topLevel.add(compEntryField); + + return topLevel; +} + +Component +createAttributePane() +{ + JPanel topLevel = new JPanel(new TableLayout("cols=3 rgap=2 cgap=5")); + + // Table Attributes + + topLevel.add(new JLabel("Table Attributes"), "cspan=3"); + + JPanel spacer1= new JPanel(); + spacer1.setSize(20, 1); + topLevel.add(spacer1); + topLevel.add(new JLabel("Columns")); + columnsField = new JTextField(10); + columnsField.addActionListener(this); + columnsField.addFocusListener(this); + topLevel.add(columnsField); + + topLevel.add(new JLabel("Table insets"), "col=1"); + topLevel.add(createInsetsPane(tableInsetFields)); + + topLevel.add(new JLabel("Row gap"), "col=1"); + rowGapField = new JTextField(10); + rowGapField.addActionListener(this); + rowGapField.addFocusListener(this); + topLevel.add(rowGapField); + + topLevel.add(new JLabel("Column gap"), "col=1"); + colGapField = new JTextField(10); + colGapField.addActionListener(this); + colGapField.addFocusListener(this); + topLevel.add(colGapField); + + topLevel.add(new JLabel("Table position"), "col=1"); + tablePositionBox = new JComboBox(tablePositionList); + tablePositionBox.addActionListener(this); + topLevel.add(tablePositionBox); + + topLevel.add(new JLabel("Table fill"), "col=1"); + tableFillBox = new JComboBox(tableFillList); + tableFillBox.addActionListener(this); + topLevel.add(tableFillBox); + + // Table Cell Defaults + + topLevel.add(new JLabel("Table Cell Defaults"), "cspan=3 itop=20"); + + topLevel.add(new JLabel("Cell insets"), "col=1"); + topLevel.add(createInsetsPane(tableCellInsetFields)); + + topLevel.add(new JLabel("Cell position"), "col=1"); + tableCellPositionBox = new JComboBox(positionList); + tableCellPositionBox.addActionListener(this); + topLevel.add(tableCellPositionBox); + + topLevel.add(new JLabel("Cell fill"), "col=1"); + tableCellFillBox = new JComboBox(fillList); + tableCellFillBox.addActionListener(this); + topLevel.add(tableCellFillBox); + + topLevel.add(new JLabel("Row weight"), "col=1"); + tableRowWeightField = new JTextField(10); + tableRowWeightField.addActionListener(this); + tableRowWeightField.addFocusListener(this); + topLevel.add(tableRowWeightField); + + topLevel.add(new JLabel("Column weight"), "col=1"); + tableColWeightField = new JTextField(10); + tableColWeightField.addActionListener(this); + + tableColWeightField.addFocusListener(this); + topLevel.add(tableColWeightField); + + topLevel.add(new JLabel("Attributes"), "itop=5 col=0 cspan=2"); + tableAttributesField = new JTextField(); + tableAttributesField.setEditable(false); + topLevel.add(tableAttributesField, "itop=5"); + + // Make sure components are initialized as per the default table + // attributes + + tableAttributes = new TableAttributes(); + setTableAttributes(tableAttributes); + + // Cell Attributes + + topLevel.add(new JSeparator(), "cspan=3 itop=20 ibottom=5"); + + topLevel.add(new JLabel("Cell Attributes"), "cspan=3"); + + topLevel.add(new JLabel("Cell insets"), "col=1"); + topLevel.add(createInsetsPane(insetFields)); + + topLevel.add(new JLabel("Cell position"), "col=1"); + positionBox = new JComboBox(positionList); + positionBox.addActionListener(this); + topLevel.add(positionBox); + + topLevel.add(new JLabel("Cell fill"), "col=1"); + fillBox = new JComboBox(fillList); + fillBox.addActionListener(this); + topLevel.add(fillBox); + + topLevel.add(new JLabel("Row weight"), "col=1"); + rowWeightField = new JTextField(10); + rowWeightField.addActionListener(this); + rowWeightField.addFocusListener(this); + topLevel.add(rowWeightField); + + topLevel.add(new JLabel("Column weight"), "col=1"); + colWeightField = new JTextField(10); + colWeightField.addActionListener(this); + colWeightField.addFocusListener(this); + topLevel.add(colWeightField); + + topLevel.add(new JLabel("Column position"), "col=1"); + colPositionField = new JTextField(10); + colPositionField.addActionListener(this); + colPositionField.addFocusListener(this); + topLevel.add(colPositionField); + + topLevel.add(new JLabel("Skip cells"), "col=1"); + skipCellsField = new JTextField(10); + skipCellsField.addActionListener(this); + skipCellsField.addFocusListener(this); + topLevel.add(skipCellsField); + + topLevel.add(new JLabel("Row span"), "col=1"); + rowSpanField = new JTextField(10); + rowSpanField.addActionListener(this); + rowSpanField.addFocusListener(this); + topLevel.add(rowSpanField); + + topLevel.add(new JLabel("Column span"), "col=1"); + colSpanField = new JTextField(10); + colSpanField.addActionListener(this); + colSpanField.addFocusListener(this); + topLevel.add(colSpanField); + + topLevel.add(new JLabel("Attributes"), "itop=5 col=0 cspan=2"); + cellAttributesField = new JTextField(); + cellAttributesField.setEditable(false); + topLevel.add(cellAttributesField, "itop=5"); + + enableAttributes(false); + + return topLevel; +} + +Component +createInsetsPane( + JTextField[] insetFields) +{ + JPanel topLevel = new JPanel(new TableLayout("cols=3")); + + for (int i = 0; i < 4; i++) { + insetFields[i] = new JTextField(2); + insetFields[i].addActionListener(this); + insetFields[i].addFocusListener(this); + } + + topLevel.add(insetFields[0], "col=1"); + topLevel.add(insetFields[1], "col=0"); + topLevel.add(insetFields[2], "col=2"); + topLevel.add(insetFields[3], "col=1"); + + return topLevel; +} + +JPanel +createCodePane() +{ + JPanel topLevel = new JPanel(new TableLayout("cols=2 rgap=2 cgap=5")); + + codeTextArea = new JTextArea(15, 30); + codeTextScroll = new JScrollPane(codeTextArea); + topLevel.add(codeTextScroll, "cspan=2 rweight=1"); + + return topLevel; +} + +void +addToLayout( + Component c) +{ + try { + layoutPane.add(c); + } + catch (IllegalArgumentException e) { + JOptionPane.showMessageDialog( + this, e.toString(), "Attribute Error", JOptionPane.ERROR_MESSAGE); + } + layoutPane.revalidate(); +} + +void +addToLayout( + Component c, + String a, + int index) +{ + try { + layoutPane.add(c, a, index); + } + catch (IllegalArgumentException e) { + JOptionPane.showMessageDialog( + this, e.toString(), "Attribute Error", JOptionPane.ERROR_MESSAGE); + } + layoutPane.revalidate(); +} + +void +changeTableLayout() +{ + tableAttributes = getTableAttributes(); + try { + ((TableLayout)layoutPane.getLayout()).setTableAttributes( + tableAttributes.toString()); + } + catch (IllegalArgumentException e) { + JOptionPane.showMessageDialog( + this, e.toString(), "Attribute Error", JOptionPane.ERROR_MESSAGE); + } + layoutPane.revalidate(); + setTableAttributes(tableAttributes); // Normalize appearance +} + +void +changeLayout() +{ + String name = (String)compList.getSelectedValue(); + changeLayout(name); +} + +void +changeLayout( + String name) +{ + if (name == null) return; + + Component c = (Component)compHash.get(name); + Attributes attributes = getAttributes(); + try { + ((TableLayout)layoutPane.getLayout()).setAttributes( + c, attributes.toString()); + } + catch (IllegalArgumentException e) { + JOptionPane.showMessageDialog( + this, e.toString(), "Attribute Error", JOptionPane.ERROR_MESSAGE); + } + layoutPane.revalidate(); + setAttributes(attributes); // Normalize appearance + attrHash.put(name, attributes); +} + +TableAttributes +getTableAttributes() +{ + TableAttributes attributes = new TableAttributes(); + + attributes.columns = getNumber(attributes.columns, columnsField); + attributes.rGap = getNumber(attributes.rGap, rowGapField); + attributes.cGap = getNumber(attributes.cGap, colGapField); + + attributes.tableInsets.top = + getNumber(attributes.tableInsets.top, tableInsetFields[0]); + attributes.tableInsets.left = + getNumber(attributes.tableInsets.left, tableInsetFields[1]); + attributes.tableInsets.right = + getNumber(attributes.tableInsets.right, tableInsetFields[2]); + attributes.tableInsets.bottom = + getNumber(attributes.tableInsets.bottom, tableInsetFields[3]); + + attributes.tablePosition = getString(tablePositionBox); + attributes.tableFill = getString(tableFillBox); + + attributes.insets.top = + getNumber(attributes.insets.top, tableCellInsetFields[0]); + attributes.insets.left = + getNumber(attributes.insets.left, tableCellInsetFields[1]); + attributes.insets.right = + getNumber(attributes.insets.right, tableCellInsetFields[2]); + attributes.insets.bottom = + getNumber(attributes.insets.bottom, tableCellInsetFields[3]); + + attributes.position = getString(tableCellPositionBox); + attributes.fill = getString(tableCellFillBox); + attributes.rWeight = getNumber(attributes.rWeight, tableRowWeightField); + attributes.cWeight = getNumber(attributes.cWeight, tableColWeightField); + + return attributes; +} + +void +setTableAttributes( + TableAttributes attributes) +{ + ignoreEvents = true; + + columnsField.setText(Integer.toString(attributes.columns)); + rowGapField.setText(Integer.toString(attributes.rGap)); + colGapField.setText(Integer.toString(attributes.cGap)); + + tableInsetFields[0].setText( + Integer.toString(attributes.tableInsets.top)); + tableInsetFields[1].setText( + Integer.toString(attributes.tableInsets.left)); + tableInsetFields[2].setText( + Integer.toString(attributes.tableInsets.right)); + tableInsetFields[3].setText( + Integer.toString(attributes.tableInsets.bottom)); + + tablePositionBox.setSelectedItem(attributes.tablePosition); + tableFillBox.setSelectedItem(attributes.tableFill); + + tableCellInsetFields[0].setText( + Integer.toString(attributes.insets.top)); + tableCellInsetFields[1].setText( + Integer.toString(attributes.insets.left)); + tableCellInsetFields[2].setText( + Integer.toString(attributes.insets.right)); + tableCellInsetFields[3].setText( + Integer.toString(attributes.insets.bottom)); + + tableCellPositionBox.setSelectedItem(attributes.position); + tableCellFillBox.setSelectedItem(attributes.fill); + tableRowWeightField.setText(Integer.toString(attributes.rWeight)); + tableColWeightField.setText(Integer.toString(attributes.cWeight)); + + tableAttributesField.setText(attributes.toString()); + + ignoreEvents = false; +} + +Attributes +getAttributes() +{ + Attributes attributes = new Attributes(); + + attributes.insets.top = + getNumber(attributes.insets.top, insetFields[0]); + attributes.insets.left = + getNumber(attributes.insets.left, insetFields[1]); + attributes.insets.right = + getNumber(attributes.insets.right, insetFields[2]); + attributes.insets.bottom = + getNumber(attributes.insets.bottom, insetFields[3]); + + attributes.position = getString(positionBox); + attributes.fill = getString(fillBox); + attributes.rWeight = getNumber(attributes.rWeight, rowWeightField); + attributes.cWeight = getNumber(attributes.cWeight, colWeightField); + attributes.column = getNumber(attributes.column, colPositionField); + attributes.skip = getNumber(attributes.skip, skipCellsField); + attributes.rSpan = getNumber(attributes.rSpan, rowSpanField); + attributes.cSpan = getNumber(attributes.cSpan, colSpanField); + + return attributes; +} + +void +setAttributes( + Attributes attributes) +{ + ignoreEvents = true; + + insetFields[0].setText(Integer.toString(attributes.insets.top)); + insetFields[1].setText(Integer.toString(attributes.insets.left)); + insetFields[2].setText(Integer.toString(attributes.insets.right)); + insetFields[3].setText(Integer.toString(attributes.insets.bottom)); + + positionBox.setSelectedItem(attributes.position); + fillBox.setSelectedItem(attributes.fill); + rowWeightField.setText(Integer.toString(attributes.rWeight)); + colWeightField.setText(Integer.toString(attributes.cWeight)); + colPositionField.setText(Integer.toString(attributes.column)); + skipCellsField.setText(Integer.toString(attributes.skip)); + rowSpanField.setText(Integer.toString(attributes.rSpan)); + colSpanField.setText(Integer.toString(attributes.cSpan)); + + cellAttributesField.setText(attributes.toString()); + + ignoreEvents = false; +} + +int +getNumber( + int defaultValue, + JTextField field) +{ + String text = field.getText().trim(); + if (text.length() == 0) return defaultValue; + + int value = 0; + try { + value = Integer.parseInt(text); + } + catch (NumberFormatException e) {} + + return value; +} + +String +getString( + JComboBox box) +{ + return (String)box.getSelectedItem(); +} + +void +enableAttributes( + boolean enable) +{ + positionBox.setEnabled(enable); + fillBox.setEnabled(enable); + rowWeightField.setEnabled(enable); + colWeightField.setEnabled(enable); + colPositionField.setEnabled(enable); + skipCellsField.setEnabled(enable); + rowSpanField.setEnabled(enable); + colSpanField.setEnabled(enable); + + for (int i = 0; i < 4; i++) { + insetFields[i].setEnabled(enable); + } +} + +void +generateCode() +{ + tableAttributes = getTableAttributes(); + + String indent = ""; + String containerName = ""; + + StringBuffer code = new StringBuffer( + indent + "// Code generated by Table Explorer V1.0\n" + + indent + + "// Copyright © 2004, Antonio Freixas\n" + + indent + "// All Rights Reserved.\n" + + indent + "// tony@freixas.org\n\n" + + indent + "// Define the table layout\n\n" + + indent + "JPanel panel = new JPanel(new TableLayout(" + + "\"" + tableAttributes.toString().trim() + "\"));\n\n"); + + for (int i = 0; i < compListModel.size(); i++) { + String name = (String)compListModel.elementAt(i); + Attributes attr = (Attributes)attrHash.get(name); + String sAttr = attr.toString().trim(); + code.append( + indent + "panel.add(new JButton(\"" + name + "\"" + + (sAttr.length() > 0 ? ", \"" + sAttr + "\"" : "") + "));\n"); + } + + codeTextArea.setText(code.toString()); +} + +//********************************************************************** +// Protected +//********************************************************************** + +//********************************************************************** +// Private +//********************************************************************** + +//********************************************************************** +// Inner Classes +//********************************************************************** + +class TableAttributes +{ + +// Table-only options + +int columns = 1; +int rGap = 0; +int cGap = 0; +Insets tableInsets = new Insets(0, 0, 0, 0); +String tablePosition = "Default"; +String tableFill = "Default"; + +// Table/cell options + +Insets insets = new Insets(0, 0, 0, 0); +String position = "Default"; +String fill = "Default"; +int rWeight = 0; +int cWeight = 0; + +public String +toString() +{ + StringBuffer b = new StringBuffer(); + + if (columns != 1) { + b.append("cols=" + columns + " "); + } + + if (rGap != 0) { + b.append("rgap=" + rGap + " "); + } + if (cGap != 0) { + b.append("cgap=" + cGap + " "); + } + + if (tableInsets.top != 0) { + b.append("titop=" + tableInsets.top + " "); + } + if (tableInsets.bottom != 0) { + b.append("tibottom=" + tableInsets.bottom + " "); + } + if (tableInsets.left != 0) { + b.append("tileft=" + tableInsets.left + " "); + } + if (tableInsets.right != 0) { + b.append("tiright=" + tableInsets.right + " "); + } + + if (!"Default".equals(tablePosition)) { + b.append(tablePosition + " "); + } + if (!"Default".equals(tableFill)) { + b.append(tableFill + " "); + } + + if (insets.top != 0) { + b.append("itop=" + insets.top + " "); + } + if (insets.bottom != 0) { + b.append("ibottom=" + insets.bottom + " "); + } + if (insets.left != 0) { + b.append("ileft=" + insets.left + " "); + } + if (insets.right != 0) { + b.append("iright=" + insets.right + " "); + } + + if (!"Default".equals(position)) { + b.append(position + " "); + } + if (!"Default".equals(fill)) { + b.append(fill + " "); + } + + if (rWeight != 0) { + b.append("rweight=" + rWeight + " "); + } + if (cWeight != 0) { + b.append("cweight=" + cWeight + " "); + } + + return new String(b); +} + +} + +class Attributes +{ + +Insets insets = new Insets(0, 0, 0, 0); +String position = "Default"; +String fill = "Default"; +int rWeight = 0; +int cWeight = 0; +int column = -1; +int skip = 0; +int rSpan = 1; +int cSpan = 1; + +public String +toString() +{ + StringBuffer b = new StringBuffer(); + + if (insets.top != tableAttributes.insets.top) { + b.append("itop=" + insets.top + " "); + } + if (insets.bottom != tableAttributes.insets.bottom) { + b.append("ibottom=" + insets.bottom + " "); + } + if (insets.left != tableAttributes.insets.left) { + b.append("ileft=" + insets.left + " "); + } + if (insets.right != tableAttributes.insets.right) { + b.append("iright=" + insets.right + " "); + } + + if (!"Default".equals(position)) { + b.append(position + " "); + } + if (!"Default".equals(fill)) { + b.append(fill + " "); + } + + if (rWeight != tableAttributes.rWeight) { + b.append("rweight=" + rWeight + " "); + } + if (cWeight != tableAttributes.cWeight) { + b.append("cweight=" + cWeight + " "); + } + + if (column != -1) { + b.append("col=" + column + " "); + } + + if (skip != 0) { + b.append("skip=" + skip + " "); + } + + if (rSpan != 1) { + b.append("rspan=" + rSpan + " "); + } + if (cSpan != 1) { + b.append("cspan=" + cSpan + " "); + } + + return new String(b); +} + +} + +//********************************************************************** +// End Inner Classes +//********************************************************************** + +} diff --git a/libs/FLib/TableLayout/doc/examples.html b/libs/FLib/TableLayout/doc/examples.html new file mode 100644 index 0000000..7f8217f --- /dev/null +++ b/libs/FLib/TableLayout/doc/examples.html @@ -0,0 +1,76 @@ + + + + + +TableLayout - Examples + + + + + + + + +

+ + + + + +
+

Examples

+

There are two example programs provided for TableLayout.

+

The Example1 program compares TableLayout + with GridBagLayout. It uses the code found on the API page for GridBagLayout + and then adds code to create + the equivalent layout using TableLayout.

+

I hope the TableLayout version is much easier to understand. It's definitely + a lot shorter!

+

The second program is called + TableExplorer. While you are + free to examine the code, it is really a tool you run to learn how to + use the TableLayout.

+

If you download the FLib source, you can use Ant to build and run + the example programs:

+
cd TableLayout
+ant runExample1
+ant runTableExplorer
+

The Example1 class will display two windows, one created using GridBagLayout + and the other using TableLayout. You can resize the windows to verify + that + the behavior + is + identical.

+

When you run the TableExplorer program, it will display a text field + at the bottom with the words "Start Here!" and an Add button + next to it. You create JButton components by entering the component name + (which + also + becomes its label) and pressing the Add button. Each component added + shows up in the list above the text field.

+

Selecting Window / Show Preview Window from the menu will bring up a + window containing the JButtons. You can then set the table attributes + and table cell defaults to control the table layout. You can also select + a component from the list and set its cell attributes. Your changes should + be reflected immediately in the preview window.

+

You can also display a code window which will show you the code necessary + to generate the displayed layout.

+
+ + diff --git a/libs/FLib/TableLayout/doc/features.html b/libs/FLib/TableLayout/doc/features.html new file mode 100644 index 0000000..47bf332 --- /dev/null +++ b/libs/FLib/TableLayout/doc/features.html @@ -0,0 +1,55 @@ + + + + + +TableLayout - Features + + + + + + + + +

+ + + + + +
+

Features

+

The main features of TableLayout are:

+
    +
  • Easy to use.
  • +
  • Efficient.
  • +
  • Inspired by the HTML table element.
  • +
  • Text attributes are used to control a component's layout. These are + fairly easy to remember, both when creating the layout and when reviewing + an existing layout.
  • +
  • Attributes can also be set for the table itself.
  • +
  • Default component attributes can be set to simplify entry.
  • +
  • Can duplicate any layout created with GridBagLayout, but usually + with much fewer lines of code.
  • +
  • Components are laid out as they are added, with rows added automatically + as needed.
  • +
+
+ + diff --git a/libs/FLib/TableLayout/doc/images/Logo.png b/libs/FLib/TableLayout/doc/images/Logo.png new file mode 100644 index 0000000..db18dce Binary files /dev/null and b/libs/FLib/TableLayout/doc/images/Logo.png differ diff --git a/libs/FLib/TableLayout/doc/images/screenshot1.png b/libs/FLib/TableLayout/doc/images/screenshot1.png new file mode 100644 index 0000000..ac7a594 Binary files /dev/null and b/libs/FLib/TableLayout/doc/images/screenshot1.png differ diff --git a/libs/FLib/TableLayout/doc/images/screenshot2.png b/libs/FLib/TableLayout/doc/images/screenshot2.png new file mode 100644 index 0000000..c669bce Binary files /dev/null and b/libs/FLib/TableLayout/doc/images/screenshot2.png differ diff --git a/libs/FLib/TableLayout/doc/images/tutorial1.png b/libs/FLib/TableLayout/doc/images/tutorial1.png new file mode 100644 index 0000000..c441e32 Binary files /dev/null and b/libs/FLib/TableLayout/doc/images/tutorial1.png differ diff --git a/libs/FLib/TableLayout/doc/images/tutorial2.png b/libs/FLib/TableLayout/doc/images/tutorial2.png new file mode 100644 index 0000000..a197850 Binary files /dev/null and b/libs/FLib/TableLayout/doc/images/tutorial2.png differ diff --git a/libs/FLib/TableLayout/doc/images/tutorial3.png b/libs/FLib/TableLayout/doc/images/tutorial3.png new file mode 100644 index 0000000..4e2c0f4 Binary files /dev/null and b/libs/FLib/TableLayout/doc/images/tutorial3.png differ diff --git a/libs/FLib/TableLayout/doc/images/tutorial4.png b/libs/FLib/TableLayout/doc/images/tutorial4.png new file mode 100644 index 0000000..b01cfbd Binary files /dev/null and b/libs/FLib/TableLayout/doc/images/tutorial4.png differ diff --git a/libs/FLib/TableLayout/doc/images/tutorial5.png b/libs/FLib/TableLayout/doc/images/tutorial5.png new file mode 100644 index 0000000..3871325 Binary files /dev/null and b/libs/FLib/TableLayout/doc/images/tutorial5.png differ diff --git a/libs/FLib/TableLayout/doc/images/tutorial6.png b/libs/FLib/TableLayout/doc/images/tutorial6.png new file mode 100644 index 0000000..533c57c Binary files /dev/null and b/libs/FLib/TableLayout/doc/images/tutorial6.png differ diff --git a/libs/FLib/TableLayout/doc/images/tutorial7.png b/libs/FLib/TableLayout/doc/images/tutorial7.png new file mode 100644 index 0000000..8744c42 Binary files /dev/null and b/libs/FLib/TableLayout/doc/images/tutorial7.png differ diff --git a/libs/FLib/TableLayout/doc/images/tutorial8.png b/libs/FLib/TableLayout/doc/images/tutorial8.png new file mode 100644 index 0000000..bf92254 Binary files /dev/null and b/libs/FLib/TableLayout/doc/images/tutorial8.png differ diff --git a/libs/FLib/TableLayout/doc/index.html b/libs/FLib/TableLayout/doc/index.html new file mode 100644 index 0000000..7a60e27 --- /dev/null +++ b/libs/FLib/TableLayout/doc/index.html @@ -0,0 +1,64 @@ + + + + + +TableLayout - Introduction + + + + + + + + +

+ + + + + +
+

Introduction

+

Hi! My name is Tony Freixas and I am currently working on an application + that I intend to release as Open Source. In the process of building the + application, I am using as many Open Source classes and components as + I can find.

+

In some cases, I have been disappointed with what I have found on the + web:

+
    +
  • Classes that are not free.
  • +
  • Classes with restrictive licensing.
  • +
  • Classes which ignore internationalization.
  • +
  • Classes which are not easy to use.
  • +
  • Components which are limited with respect to the Look & Feel that + can be used.
  • +
+

When I have not found a suitable Java class, I have implemented my own. + I have decided to release these for use by others as part of a library + I call FLib.

+

Currently, there are three components available in FLib and I have chosen + to make them completely independent of each other. In the future, you + + may have to load some common code in order to use the FLib classes.

+

These web pages are for the TableLayout manager. Use the + links on the left to learn more.

+

Support This Project

+
+ + diff --git a/libs/FLib/TableLayout/doc/resources.html b/libs/FLib/TableLayout/doc/resources.html new file mode 100644 index 0000000..3300cad --- /dev/null +++ b/libs/FLib/TableLayout/doc/resources.html @@ -0,0 +1,68 @@ + + + + + +TableLayout - Other Resources + + + + + + + + +

+ + + + + +
+

Other Resources

+

Back in 2000, I started thinking about creating a table layout manager + that would be as easy-to-use as HTML tables. I looked on the internet + for existing solutions and found several. One I particularly liked had + a user interface quite similar to the TableLayout I provide. However, + it had subtle bugs which were not easy to fix given the existing architecture. + This caused me to write my own version from scratch while retaining + many of its good UI ideas.

+

Unfortunately, I no longer have a pointer to that TableLayout or the + author who wrote it. I found a version that has an interface similar + to mine and may have been the original inspiration, although I cannot + verify it.

+

My version of TableLayout appears now through the courtesy of Credence + Systems Corporation, who holds the copyright and has allowed me to release + the code under the Artistic License.

+

The most well-known TableLayout is + written by Daniel Barbalace. I've used this version, but I dislike its + approach of having to define row widths and column heights in advance. + As I recall, if you want row or column gaps, these had to be treated + as empty rows and columns.

+

My TableLayout is for lazier designers: Other + than specifying the number of columns, you can decide on additional + settings as you add components. Row and column gaps, which I + use often and which I almost always want to be a consistent size, can + be set with two simple attributes specified when the layout manager is + created.

+

There are many other TableLayout managers. Obviously a lot of people + had the same idea! Rather than try to list all others, I suggest you + do a Google search.

+
+ + diff --git a/libs/FLib/TableLayout/doc/screenshots.html b/libs/FLib/TableLayout/doc/screenshots.html new file mode 100644 index 0000000..ec37ca8 --- /dev/null +++ b/libs/FLib/TableLayout/doc/screenshots.html @@ -0,0 +1,48 @@ + + + + + +TableLayout - Screen Shots + + + + + + + + +

+ + + + + +
+

Screen Shots

+

This is a the initial appearance + of a set of JButton's in a JPanel as laid out by TableLayout (from the + Example1 program).

+

+

This is the same JPanel resized larger.

+

+

Additional + screen shots available on the Tutorial page.

+
+ + diff --git a/libs/FLib/TableLayout/doc/stylesheet.css b/libs/FLib/TableLayout/doc/stylesheet.css new file mode 100644 index 0000000..dc693da --- /dev/null +++ b/libs/FLib/TableLayout/doc/stylesheet.css @@ -0,0 +1,48 @@ +body { + font-family: Arial, Helvetica, sans-serif; + background: white: + color: black; +} + +td { + font-family: Arial, Helvetica, sans-serif; +} + +th { + font-family: Arial, Helvetica, sans-serif; +} + +#sidebar { + font-family: "Times New Roman", Times, serif; + font-weight: bold; + font-style: italic; + font-size: 20px; +} + +#content { + font-size: 100%; +} + +a:visited { + color: #8080FF; + text-decoration: none; +} + +a:link { + color: #8080FF; + text-decoration: none; +} + +a:hover { + color: #C00000; + text-decoration: none; +} + +a:active { + color: #C00000; + text-decoration: none; +} + +pre { + margin-left: 1em; +} diff --git a/libs/FLib/TableLayout/doc/tutorial.html b/libs/FLib/TableLayout/doc/tutorial.html new file mode 100644 index 0000000..5522d3f --- /dev/null +++ b/libs/FLib/TableLayout/doc/tutorial.html @@ -0,0 +1,338 @@ + + + + + +TableLayout - Tutorial + + + + + + + + +

+ + + + + +
+

Tutorial

+

TableLayout

+

This layout manager was loosely inspired by the HTML table. It has all + the power of the GridBagLayout, but is much easier to use.

+

The Layout Manager Concept

+

Container is a Component class which contains one or more other components. + Every container has a layout manager which arranges the positions and + sizes of the components in the container.

+

The container is given a certain + amount of screen space for its components. The layout manager then + needs to figure out how to size and position the container's components + within + this space. It can use any algorithm it wants. It does not need to + fill all the space nor does it need to prevent components from overlapping.

+

The TableLayout

+

The TableLayout lays out components in a table format. The table has + rows and columns which are typically not all the same width or height + (if you need constant width and height, consider using the GridLayout).

+

You usually need + to define the number of columns in the table (the default is 1, which + is typically not what you want). As components are added to the container, + they are placed in the next available column of the current row. When + a row is filled, the next component adds a row and is placed in the first + column.

+

Consider this code:

+
JPanel panel = new JPanel(new TableLayout("cols=3"));
+panel.add(new JButton("0"));
+panel.add(new JButton("1"));
+panel.add(new JButton("2"));
+panel.add(new JButton("3"));
+panel.add(new JButton("4"));
+
+

This generates the following layout:

+

+

I started numbering with "0" because, for the TableLayout, + the first column is column 0. In this example, we see a three-column + table, with each JButton component added to the next available column. + Since there are only five components, the last "slot" is left empty.

+

Attributes

+

The above example is very simple because only one attribute was given + to the TableLayout ("cols=5"). Attributes are instructions to the TableLayout + which tell it how to lay out each component in the table or the table + as a whole.

+

The format of the attributes is similar to HTML attributes. The attributes + are case insensitive and can be separated with any white space. Attributes + which take a value are followed by an '=' and then an integer. Here's + an example: "cols=6 rgap=2 cgap=5 w".

+

Attributes are evaluated from left to right. If you duplicate an attribute, + the right-most one wins.

+

Some attributes apply only to the table as whole. You pass them in a + String given either in the TableLayout constructor or in the setTableAttributes() + method.

+

The remaining attributes apply to the components in the container. Of + these, some can also be specified along with the table attributes. These + become the defaults for all components in the table. This is one of the + features which makes the TableLayout easy to use.

+

Here is the complete list of attributes:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameDescriptionHas Value?DefaultScope
colsNumber of columnsYes1Table
colPlace Component in this columnYesNext empty columnComponent
skipSkip a number of columnsYes0Component
rspan, cspanRow and column spanningYes1Component
titop, tibottom, tileft, tirightTable insetsYes0Table
rgap, cgapRow and column gapsYes0Table
itop, ibottom, ileft, irightComponent insetsYes0Table/Component
tn, tne, te, tse, ts, tsw, tw, tnw, tc, tf, tfh, tfvTable placement and fillNotfTable
n, ne, e, se, s, sw, w, nw, c, f, fh, fvComponent placement and fillNofTable/Component
rweight, cweightRow and column weightsYes0Table/Component
+

Rows and Columns

+

As I stated above, you will almost always specify the number of columns + in the table. Components are then placed in the table from left to right, + adding new rows as necessary.

+

You can override the default component placement somewhat with "col" + and "skip". + With "col", you specify the column number in which the component + should be placed. If you have already passed the given column, the layout + adds another row and places the Component in the column on that new row.

+

"skip" allows you to skip a number of cells. If the layout reaches + the end of the row, skipping continues on the next row.

+

You can also make a component span multiple rows or columns with rspan + and cspan. Components added later will skip over any occupied cells, + which is important to note for row spanning.

+

Let's take the example above and make it use these attributes:

+
JPanel panel = new JPanel(new TableLayout("cols=3"));
+panel.add(new JButton("0"));
+panel.add(new JButton("1"),"skip=1");
+panel.add(new JButton("2"), "col=1");
+panel.add(new JButton("3"), "rspan=2");
+panel.add(new JButton("4"), "cspan=2");
+

+

Spacing

+ The space the TableLayout works with is inside the container's insets. + Some containers have insets of 0 (e.g. JPanel) and most don't allow you + to alter the insets. Since you will often want to control the space between + the table and the edges of the container, +an "extra" table inset can be given: titop, tibottom, tileft and tiright +(in +the "ti" prefix, the "t" stands for "table" and +the "i" stands +for "inset"). +

Within a cell, you can create space between the cells edges and the component + in the cell. The attributes are itop, ibottom, ileft and iright.

+

You can also add space between cells in the table. This space is only placed + between cells; never along the edges of the table. This allows you to nest + table layouts and keep consistent cell spacing. The attributes used are rgap + and cgap and their default value is 0.

+

Here is our example with the addition of table and cell insets plus cell spacing. + Note that we specify the cell insets and spacing when we define the table attributes. + This means that all components will get the same insets and spacing without + having to duplicate this information for each individual component. We override + the default insets for one of the components.

+
JPanel panel = new JPanel(
+  new TableLayout(
+    "cols=3 rgap=3 cgap=3 " +
+    "titop=5 tibottom=5 tileft=5 tiright=5 " +
+    "itop=2 ibottom=2 ileft=2 iright=2"));
+panel.add(new JButton("0"));
+panel.add(new JButton("1"), "skip=1");
+panel.add(new JButton("2"), "itop=0 ibottom=0 ileft=0 iright=0 col=1");
+panel.add(new JButton("3"), "rspan=2");
+panel.add(new JButton("4"), "cspan=2");
+

Here's what we get:

+

+

Placement and Filling

+

Given that you have something to draw and a space to draw it in, you have + some choices as to where to place it and how to fill it, particularly when + the available area is bigger than required. So far, except for the insets, + we've allowed the table to completely fill the available container space and + we've + allowed each component to completely fill its table cell.

+

Placement attributes allow you to place a component centered or in one of + eight compass directions within its cell. It's easier to demonstrate than to + describe:

+
JPanel panel = new JPanel(new TableLayout("cols=3"));
+panel.add(new JButton("1"), "nw");
+panel.add(new JButton("2"), "n");
+panel.add(new JButton("3"), "ne");
+panel.add(new JButton("4"), "w");
+panel.add(new JButton("5"), "c");
+panel.add(new JButton("6"), "e");
+panel.add(new JButton("7"), "sw");
+panel.add(new JButton("8"), "s");
+panel.add(new JButton("9"), "se");
+

+

Using the placement attributes, a component is left at its preferred size. + Then it is moved to the designated edge or corner (or center) of the cell.

+

There are placement attributes for the table itself. These are just like the + component placement attributes, but start with a "t". You can find these in + the attribute table above. Like the component, the table is set to its preferred + size and moved to the edge, corner or center of the container.

+

The entire table can be placed within the container using tn, tne, te, tse, + ts, tsw, tw, tnw and tc (the "t" prefix is for "table").

+

Fill attributes allow you to fill the item to cover all available space. + Horizontal and vertical filling are handled separately. For tables, the attributes + are tfh, tfv and tf. "tf" fills in both directions. For Components, use + fh, fv and f. For instance, if we change just the first line of the example + to:

+
JPanel panel = new JPanel(new TableLayout("cols=3 tnw"));
+
+

We get

+

+

The table is at its preferred size and placed in the northwest + corner of the container. Since the preferred sizes of the buttons are all the + same, the cells appeared to be filled even though they still have the same + placement attributes as before.

+

Instead of placing a component within a cell, you can have it stretch to fill + the cell, either vertically, horizontally or both. Here's our example:

+
JPanel panel = new JPanel(new TableLayout("cols=3"));
+panel.add(new JButton("1"), "c fh");
+panel.add(new JButton("2"), "f");
+panel.add(new JButton("3"), "c fh");
+

+

Since the default is "f", we turn off filling by using "c". Then we can fill + horizontally, vertically or in both directions.

+

The "f" in the second component + is redundant, since this is the default. But keep in mind that you can define + the default placement or fill by specifying it in the table attributes. + For example,

+
JPanel panel = new JPanel(new TableLayout("cols=3 nw"));
+

would place all components in the top left corner of each cell, unless a + component overrides the default.

+

When combining placement and fill attributes, the rules are:

+
    +
  • Placement attributes turn off all filling.
  • +
  • Fill attributes turn off placement, but only in the fill direction.
  • +
+

So, for example, "n fh" will stretch a component horizontally, but will attach + its top edge at the top of the cell.

+

Weighting

+

By setting the "weight" of each row or column, you can control how the rows + and columns are allocated space when there is more space available than is + needed (given the preferred sizes of the components).

+

The default is to equally distribute the extra space to all cells. This is + not always what you want. Sometimes you'd like some rows or columns to stretch + while others stay a fixed size. This is easy to do: assign the rows and columns + you want to stretch a weight of 1 ("rweight" for row weight and "cweight" for + column weight). Here's an example. To keep it simple, we'll stretch components + "1" and "3" horizontally, while the rest of the components are fixed.

+
JPanel panel = new JPanel(new TableLayout("cols=5"));
+panel.add(new JButton("0"));
+panel.add(new JButton("1"), "cweight=1");
+panel.add(new JButton("2"));
+panel.add(new JButton("3"), "cweight=1");
+panel.add(new JButton("4"));
+

+

+

There are a few things to keep in mind about weighting. The weight of a row + is the largest weight of any component in the row. The advantage is that you + only have to set the row weight for one component in a row and the column weight + for one component in the column.

+

Keep in mind that assigning the same weight to two rows or columns does + not make them the same size! Weighting only describes how excess space + is distributed to the cells. If the two components have different preferred + sizes, the row or column sizes won't be equal.

+

Also remember that what we resize is the cell, not the component! If you want + the component to stretch, make sure it fills in the appropriate direction.

+

There's a subtlety to weighting: weighting is only used when there is excess + space available given the components' preferred sizes. When there is not enough + space for preferred sizes, space is taken away from cells equally, regardless + of the weighting. However, components that shrink to their minimum allowed + size will not shrink further.

+

There is further detail on all attributes, but particularly on weighting in + the TableLayout API.

+

Summary

+

The TableLayout is both powerful and easy-to-use. After reading this tutorial, + you should examine the example programs provided. + One program places TableLayout head-to-head with GridBagLayout. The + other example simulates the GridBagExplorer written by Eric Burke. I call it + TableExplorer. It allows you to place some JButtons in a container and dynamically + change the table and component attributes. I used this program to create the + examples on this page.

+
+ + diff --git a/libs/FLib/TableLayout/org/freixas/tablelayout/TableLayout.java b/libs/FLib/TableLayout/org/freixas/tablelayout/TableLayout.java new file mode 100644 index 0000000..870115d --- /dev/null +++ b/libs/FLib/TableLayout/org/freixas/tablelayout/TableLayout.java @@ -0,0 +1,2049 @@ +//********************************************************************** +// Package +//********************************************************************* + +package org.freixas.tablelayout; + +//********************************************************************** +// Import list +//********************************************************************** + +import java.awt.*; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; + +/** + * This layout was inspired by the HTML table: it lays out components + * much like the HTML table lays out table data. It is as capable as + * the GridBagLayout, but much easier to use. + *

Attributes

+ *

+ * When you create a TableLayout, you pass in a String which defines a + * set of attributes for the table. The TableLayout is then assigned + * to a Container. As you add each Component to the Container, you can + * also associate the Component with its own set of attributes. + *

+ * The format of the attributes is similar to HTML attributes. The + * attributes are case insensitive and can be separated with + * any whitespace. Attributes which take a value are followed by an + * '=' and then an integer. Here's an example: "cols=6 rgap=2 cgap=5 + * w". + *

+ * Attributes are evaluated from left to right. If you duplicate an + * attribute, the right-most one wins. + *

All attributes can be specified for both the table and the + * individual Components. Some attributes are only used by the table, + * some are only used by the Components and some are used by both: the + * table instance is the default which each Component can override. + *

Rows and Columns

+ *

+ * When you create a table, you will almost always specify the number + * of columns in it. The default is 1. Columns are filled from left to + * right. When all columns are filled, a new row is automatically + * created. + *

+ * You can override the default Component placement somewhat with "col" + * and "skip". col takes as a value, the column number in which the + * Component should be placed. Column numbers begin with 0. The + * default is to place the Component in the next available table cell. + * One caveat when using col is that if you have already passed the + * given column, the layout adds another row and places the Component + * in the column on that new row. + *

+ * "skip" allows you to skip a number of cells. The default is 0. If + * the layout reaches the end of the row, skipping continues on the + * next row. + *

+ * You can make a Component span multiple rows or columns with rspan + * and cspan. The default value for these is 1. Later components will + * skip over any occupied cells, which is particularly important to + * note for row spanning. + *

Spacing

+ * The space the TableLayout works with is inside the Container's + * insets. Some Containers have insets of 0 (e.g. JPanel) and most + * don't allow you to alter the insets. Since you will often want to + * control the space between the table and the edges of the Container, + * an "extra" table inset can be given: titop, tibottom, tileft and + * tiright. Each of these takes a value, the pixel offset from the top, + * bottom, etc. The default value of each is 0. + *

+ * You can create some space between cells in the table. This space is + * only placed between cells; never along the edges of the + * table. This allows you to nest table layouts and keep consistent + * cell spacing. The attributes used are rgap and cgap and their + * default value is 0. + *

+ * Within a cell, you can also create some space between the cells + * edges and the Component in the cell. The attributes are itop, + * ibottom, ileft and iright. Their default value is 0. + *

Placement and Filling

+ *

+ * Given that you have something to draw and a space to draw it in, + * you have some choices as to where to place it and how to fill it, + * particularly when the drawing area is bigger than required. + *

+ * Placement attributes allow you to place the item in one of eight + * compass directions or centered. The entire table can be placed + * within the container using tn, tne, te, tse, ts, tsw, tw, tnw and + * tc. Components can be placed within their cell using n, ne, e, se, + * s, sw, w, nw and c. + *

+ * Fill attributes allow you to fill the item to cover all available + * space. Horizontal and vertical filling are handled separately. For + * tables, the attributes are tfh, tfv and tf. "tf" fills in both + * directions. For Components, use fh, fv and f. + *

+ * Placement attributes turn off all filling. Fill attributes turn off + * placement, but only in the fill direction. So "n fh" will stretch a + * Component horizontally, but will place it at the "north" position + * (at the top of the cell). + *

+ * The default value for both the table and the individual Components + * is to fill in both directions. You will almost always want to + * specify your own values. + *

Weighting

+ *

+ * When a table is filled, if the available space exceeds the space + * required, we stretch the table to fill the space. This implies that + * we have to stretch each cell. How much each cell should be filled + * is what weighting is all about. The attributes are rweight and + * cweight which take an integer weight factor. The default is 0. + *

+ * Note that stretching a cell is not the same as stretching the + * Component inside the cell unless the component uses filling. + *

+ * If you'd like some simple rules of thumbs, use these: + *

    + *
  • Assign a weight of 1 to rows or columns that you want to + * stretch (Also set the "f" attribute for the Components in that row + * or column!). Other rows and columns won't. + *
  • In some cases, you may want the table to fill while the + * components inside it don't. For example, you may want a JPanel's + * TitledBorder to fill the available space while the components in + * the JPanel stay at their preferred sizes. The solution is to fill + * the table, but set the component at the highest row and column + * position to have row and column weights of 1. Use "nw" position on + * all components in the last row or column. There are alternate + * solutions using nested layouts. + *
+ *

+ * Ok, here are the dirty details. + *

+ * If the available size is greater than the table's preferred size + * and table filling is enabled, weighting is used (they are otherwise + * ignored). + *

+ * Weights are obtained by looking at each row and column and locating + * the largest weight; this becomes the row or column weight. If all + * weights are 0, we treat them as though they are all 1. We create + * a sum for all row weights and one for all column weights. This + * number defines the number of units into which the excess space will + * be divided. + *

+ * For example, with three column weights of 1, 1, and 1, the space is + * divided into 3 units. If the excess space is 30 pixels, each unit + * is 10 pixels, which is the extra space each column receives. If the + * column weights were 0, 2, and 1, the space is still divided into 3 + * units. But the column weights specify how many units each column + * receives. So, column 0 will receive nothing, column 1, 20 pixels + * and column 2, 10 pixels. + *

+ * Keep in mind that rows and columns are handled separately. One may + * need filling and the other not. + *

+ * When we don't have enough space for the preferred row or column + * sizes, we ignore the user-defined weights and treat each row or + * column as having equal weight. The approach then, is as above + * except that we are reducing cell sizes. Another difference is that + * no cell will be made smaller than its minimum size. + *

Special Spanning Issues

+ * There are some special issues with row and column spanning. When + * determining minimum or preferred sizes, we need to know what + * portion of the Component's size to assign to each row and column + * that it spans. We solve this by doing two passes. In the first, we + * ignore spanning cells and determine row and column sizes without + * them. In the second pass, we look to see if the spanning Component + * will fit within the row and column sizes we determined. If not, we + * currently distribute the extra space based on the row or column + * weights of the rows or columns spanned. Someday, we may need to add + * attributes to provide more control. + *

+ * The row and column weights given are applied to the row or column + * in which the Component begins. + *

+ *

Summary

+ *

+ * This table summarizes the attribute information: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
NameDescriptionHas Value?DefaultScope
colsNumber of columnsYes1Table
colPlace Component in this columnYesNext empty columnComponent
skipSkip a number of columnsYes0Component
rspan, cspanRow and column spanningYes1Component
titop, tibottom, tileft, tirightTable insetsYes0Table
rgap, cgapRow and column gapsYes0Table
itop, ibottom, ileft, irightComponent insetsYes0Table/Component
tn, tne, te, tse, ts, tsw, tw, tnw, tc, tf, tfh, tfvTable placement and fillNotfTable
n, ne, e, se, s, sw, w, nw, c, f, fh, fvComponent placement and fillNofTable/Component
rweight, cweightRow and column weightsYes0Table/Component
+ * + * @author Antonio Freixas + */ + +// Copyright © 2000-2004 Credence Systems Corporation. +// All Rights Reserved. + +public class TableLayout + implements LayoutManager2 +{ + +//********************************************************************** +// Private Members +//********************************************************************** + +// This is the set of attributes applied to the table. Some attributes +// are used as cell defaults. Cell-only attributes are ignored + +private Attributes tableAttributes; + +// Attributes for each component can be found in these hash tables + +private HashMap compAttributes = new HashMap(); + +// These variables store information about the row/col arrangement of +// the components. These are set by placeComponents() + +private int nRows = 0; +private int nCols = 0; +private Component[][] components = null; + +// We cache measureComponents() information so that it is recalculated +// after invalidateLayout() is called + +private boolean useCacheMeasureResults = false; + +// These variables store sizing information set by measureComponents() + +private int[] minWidth; +private int[] prefWidth; +private int[] maxWidth; +private int[] adjWidth; +private int[] colWeight; + +private int[] minHeight; +private int[] prefHeight; +private int[] maxHeight; +private int[] adjHeight; +private int[] rowWeight; + +// These sizes are the minimum width for the table, not including +// either the container's insets or the table's insets + +private int MinWidth = 0; +private int MinHeight = 0; +private int PrefWidth = 0; +private int PrefHeight = 0; +private int MaxWidth = 0; +private int MaxHeight = 0; +private int ColWeight = 0; +private int RowWeight = 0; + +static private int classCount = 0; +private int instanceCount = classCount++; + +//********************************************************************** +// Constructors +//********************************************************************** + +/** + * Construct a new TableLayout. + */ + +public +TableLayout() +{ + this(null); +} + +/** + * Construct a new TableLayout with the given attributes. + * + * @param attributes A list of attributes for the table. The list is + * described in the class documentation above. Cell-only + * attributes are ignored. + */ + +public +TableLayout( + String attributes) +{ + tableAttributes = new Attributes(attributes); +} + +//********************************************************************** +// Public +//********************************************************************** + +/** + * Reset the table attributes for the layout. + * + * @param attributes The new table attributes. + */ + +public void +setTableAttributes( + String attributes) +{ + // Set the attributes for the table + + tableAttributes = new Attributes(attributes); + + // Since the component attributes "inherit" from the table + // attributes, any change to the table attributes causes us to + // reprocess all existing component attributes + + Iterator iter = compAttributes.keySet().iterator(); + while (iter.hasNext()) { + Component comp = (Component)iter.next(); + Attributes a = (Attributes)compAttributes.get(comp); + a.parse(); // Re-parse + } + + components = null; + useCacheMeasureResults = false; +} + +/** + * Reset the attributes for a component in the layout. The component + * must already have been added to the container or else this call has + * no effect. + * + * @param comp The component to alter. + * @param attributes The new attributes for the component. + */ + +public void +setAttributes( + Component comp, + String attributes) +{ + if (compAttributes.get(comp) != null) { + Attributes a = new Attributes(attributes, false); + compAttributes.put(comp, a); + + components = null; + useCacheMeasureResults = false; + } +} + +/** + * Adds the component with the specified attributes to the layout. + * + * @param attributes A list of attributes for the component. The list + * is described in the class documentation above. Table-only + * attributes are ignored. + * @param comp The component to be added. + */ + +public void +addLayoutComponent( + String attributes, + Component comp) +{ + Attributes a = new Attributes(attributes, false); + compAttributes.put(comp, a); + + components = null; + useCacheMeasureResults = false; + + // DEBUG + +// if ("DEBUG".equals(comp.getName())) { +// System.out.println( +// "Adding comp " + comp.getClass().getName() + " " + a); +// } +} + +/** + * Adds the specified component to the layout, using the specified + * constraint object (which we expect to be a String of attributes). + * + * @param comp The component to be added. + * @param constraints A list of attributes for the component. The list + * is described in the class documentation above. Table-only + * attributes are ignored. + */ + +public void +addLayoutComponent( + Component comp, + Object constraints) +{ + String attributes = ""; + if (constraints instanceof String) { + attributes = (String)constraints; + } + addLayoutComponent(attributes, comp); +} + +/** + * Removes the specified component from the layout. + + * @param comp The component to be removed. + */ + +public void +removeLayoutComponent( + Component comp) +{ + compAttributes.remove(comp); + components = null; +} + +/** + * Calculates the minimum size dimensions for the layout given the + * components in the a parent container. + * + * @param parent The container to be laid out. + * @return The minimum layout size. + * @see #preferredLayoutSize(Container) + * @see #maximumLayoutSize(Container) + */ + +public Dimension +minimumLayoutSize( + Container parent) +{ + Insets insets = parent.getInsets(); + measureComponents(parent); + int w = + insets.left + insets.right + + tableAttributes.tableInsets.left + + tableAttributes.tableInsets.right + + MinWidth; + int h = + insets.top + insets.bottom + + tableAttributes.tableInsets.top + + tableAttributes.tableInsets.bottom + + MinHeight; + if (w > Short.MAX_VALUE) w = Short.MAX_VALUE; + if (h > Short.MAX_VALUE) h = Short.MAX_VALUE; + + return new Dimension(w, h); +} + +/** + * Calculates the preferred size dimensions for the layout given the + * components in a parent container. + * + * @param parent The container to be laid out. + * @return The preferred layout size. + * @see #minimumLayoutSize(Container) + * @see #maximumLayoutSize(Container) + */ + +public Dimension +preferredLayoutSize( + Container parent) +{ + Insets insets = parent.getInsets(); + measureComponents(parent); + int w = + insets.left + insets.right + + tableAttributes.tableInsets.left + + tableAttributes.tableInsets.right + + PrefWidth; + int h = + insets.top + insets.bottom + + tableAttributes.tableInsets.top + + tableAttributes.tableInsets.bottom + + PrefHeight; + if (w > Short.MAX_VALUE) w = Short.MAX_VALUE; + if (h > Short.MAX_VALUE) h = Short.MAX_VALUE; + + return new Dimension(w, h); +} + +/** + * Calculates the maximum size dimensions for the layout given the + * components in a parent container. + * + * @param parent The container parent. + * @return The maximum layout size. + * @see #minimumLayoutSize(Container) + * @see #preferredLayoutSize(Container) + */ + +public Dimension +maximumLayoutSize( + Container parent) +{ + Insets insets = parent.getInsets(); + measureComponents(parent); + + // Note that the maximum size of the container is not the maximum + // size of the table if the fill options are not used + + int w = Short.MAX_VALUE; + if (tableAttributes.tableHorizontal != Attributes.FILL) { + w = insets.left + insets.right + + tableAttributes.tableInsets.left + + tableAttributes.tableInsets.right + + MaxWidth; + if (w > Short.MAX_VALUE) w = Short.MAX_VALUE; + } + + int h = Short.MAX_VALUE; + if (tableAttributes.tableVertical != Attributes.FILL) { + h = insets.top + insets.bottom + + tableAttributes.tableInsets.top + + tableAttributes.tableInsets.bottom + + MaxHeight; + if (h > Short.MAX_VALUE) h = Short.MAX_VALUE; + } + + return new Dimension(w, h); +} + +/** + * Returns the alignment along the x axis. This always returns 0.5. + * + * @param parent The container whose alignment we want. + * @return The alignment along the x axis. + */ + +public float +getLayoutAlignmentX( + Container parent) +{ + return 0.5f; +} + +/** + * Returns the alignment along the y axis. This always returns 0.5. + * + * @param parent The container whose alignment we want. + * @return The alignment along the y axis. + */ + +public float +getLayoutAlignmentY( + Container parent) +{ + return 0.5f; +} + +/** + * Invalidates the layout. Cached information will be discarded. + * + * @param parent The container whose alignment we want. + */ + +public void +invalidateLayout( + Container parent) +{ + useCacheMeasureResults = false; +} + +/** + * Lays out the components in the given container. + * + * @param parent The container which needs to be laid out. + */ + +public void +layoutContainer( + Container parent) +{ + // Get the row and column measurements + + measureComponents(parent); + + // Get the parent insets and determine the full amount of space we + // have available + + Insets insets = parent.getInsets(); + int fullWidth = + parent.getSize().width - + (insets.left + insets.right) - + (tableAttributes.tableInsets.left + + tableAttributes.tableInsets.right); + int fullHeight = parent.getSize().height - + (insets.top + insets.bottom) - + (tableAttributes.tableInsets.top + + tableAttributes.tableInsets.bottom); + + // We normally draw each row and column in its preferred size. If + // we have more space, we grow the cells. If less, we shrink the + // cells + + boolean shrinkWidth = fullWidth < PrefWidth; + boolean shrinkHeight = fullHeight < PrefHeight; + + // Get the position and size of the table. There are three + // possibilities for the table size: + // + // * The available space equals or exceeds the preferred size + // and the table is filled - use the full space available. We + // will expand the cells in a later step. + // + // * The available space equals or exceeds the preferred size + // and the table is not filled - use the preferred size. + // + // * The available space is less than the preferred size - use + // the available space. We will shrink the cells in a later + // step. + + int tableX = insets.left + tableAttributes.tableInsets.left; + int tableY = insets.top + tableAttributes.tableInsets.top; + + int tableWidth = PrefWidth; + if (shrinkWidth || + tableAttributes.tableHorizontal == Attributes.FILL) { + tableWidth = fullWidth; + } + int tableHeight = PrefHeight; + if (shrinkHeight || + tableAttributes.tableVertical == Attributes.FILL) { + tableHeight = fullHeight; + } + + if (tableAttributes.tableHorizontal == Attributes.CENTER || + tableAttributes.tableHorizontal == Attributes.FILL) { + tableX += (fullWidth - tableWidth) / 2; + } + else if (tableAttributes.tableHorizontal == Attributes.RIGHT) { + tableX += fullWidth - tableWidth; + } + + if (tableAttributes.tableVertical == Attributes.CENTER || + tableAttributes.tableVertical == Attributes.FILL) { + tableY += (fullHeight - tableHeight) / 2; + } + else if (tableAttributes.tableVertical == Attributes.BOTTOM) { + tableY += fullHeight - tableHeight; + } + + // Now adjust the column and row cell sizes + + adjustCellSizes( + nCols, + (tableAttributes.tableHorizontal == Attributes.FILL), + shrinkWidth, + minWidth, + PrefWidth, prefWidth, + fullWidth, + ColWeight, colWeight, + adjWidth, + parent); + + adjustCellSizes( + nRows, + (tableAttributes.tableVertical == Attributes.FILL), + shrinkHeight, + minHeight, + PrefHeight, prefHeight, + fullHeight, + RowWeight, rowWeight, + adjHeight, + parent); + + // Begin the component layout loop + + for (int r = 0; r < nRows; r++) { + for (int c = 0; c < nCols; c++) { + Component comp = components[r][c]; + if (comp == null) continue; + + Attributes attributes = (Attributes)compAttributes.get(comp); + + Dimension compMinSize = comp.getMinimumSize(); + Dimension compPrefSize = comp.getPreferredSize(); + Dimension compMaxSize = comp.getMaximumSize(); + + // Base position + + int compX = + tableX + + (tableAttributes.cGap * c) + + attributes.cellInsets.left; + for (int i = 0; i < c; i++) compX += adjWidth[i]; + + int compY = + tableY + + (tableAttributes.rGap * r) + + attributes.cellInsets.top; + for (int i = 0; i < r; i++) compY += adjHeight[i]; + + // Get the cell size. This has to take into account row + // and column spanning + + int cellWidth = adjWidth[c]; + for (int i = 1; i < attributes.cSpan; i++) { + cellWidth += tableAttributes.cGap + adjWidth[c + i]; + } + + int cellHeight = adjHeight[r]; + for (int i = 1; i < attributes.rSpan; i++) { + cellHeight += tableAttributes.rGap + adjHeight[r + i]; + } + + int insetCellWidth = + cellWidth - + attributes.cellInsets.left - attributes.cellInsets.right; + int insetCellHeight = + cellHeight - + attributes.cellInsets.top - attributes.cellInsets.bottom; + + // Get the component size. Use the preferred size, if + // possible. If not use the cell size minus insets + + int compWidth = compPrefSize.width; + int compHeight = compPrefSize.height; + if (compWidth > insetCellWidth) compWidth = insetCellWidth; + if (compHeight > insetCellHeight) compHeight = insetCellHeight; + + // Adjust for fill + + if (attributes.horizontal == Attributes.FILL) { + compWidth = insetCellWidth; + compWidth = Math.max(compWidth, compMinSize.width); + // Some components (like JButton) can exceed their max size + // compWidth = Math.min(compWidth, compMaxSize.width); + } + if (attributes.vertical == Attributes.FILL) { + compHeight = insetCellHeight; + compHeight = Math.max(compHeight, compMinSize.height); + // Some components (like JButton) can exceed their max size + // compHeight = Math.min(compHeight, compMaxSize.height); + } + + // Position properly. We treat FILL like CENTER since + // the min/max limits may have prevented us from really + // filling + + if (attributes.horizontal == Attributes.CENTER || + attributes.horizontal == Attributes.FILL) { + compX += (cellWidth - + (attributes.cellInsets.left + + attributes.cellInsets.right) - compWidth) / 2; + } + else if (attributes.horizontal == Attributes.RIGHT) { + compX += (cellWidth - + (attributes.cellInsets.left + + attributes.cellInsets.right) - compWidth); + } + + if (attributes.vertical == Attributes.CENTER || + attributes.vertical == Attributes.FILL) { + compY += (cellHeight - + (attributes.cellInsets.top + + attributes.cellInsets.bottom) - compHeight) / 2; + } + else if (attributes.vertical == Attributes.BOTTOM) { + compY += (cellHeight - + (attributes.cellInsets.top + + attributes.cellInsets.bottom) - compHeight); + } + + // Place the component + + comp.setBounds(compX, compY, compWidth, compHeight); + + // DEBUG + +// if ("DEBUG".equals(parent.getName())) { +// System.out.println("Placing component " + +// comp.getClass().getName() + +// " (" + compX + ", " + compY + ") " + +// compWidth + " x " + compHeight); +// } + } + } +} + +// The inherited toString() method is acceptable. + +//********************************************************************** +// Private +//********************************************************************** + +/** + * The row or column sizes need to be adjusted. We may want to grow + * or shrink the sizes, based on whether the available space is larger + * or smaller than the preferred size. + *

+ * If we grow the table, we pay attention to the user's weighting + * factors. If we shrink the table, we assign all cells a weight + * factor of 1. + * + * @param nCells The number of cells in the row or column. + * @param fill True if the table rows or columns should fill the + * available space. + * @param shrink True if the available size is less than the preferred + * size. + * @param minSize The minimum sizes of each row or column. + * @param PrefSize The sum of the preferred sizes of all cells in the + * row or column plus any cell gaps. + * @param prefSize The preferred sizes of each row or column. + * @param CellWeight The sum of all cell weights in the row or column. + * @param cellWeight The weight of each row or column. + * @param adjSize The adjusted size of each row or column. The + * contents of this array are set and returned. + */ + +private void +adjustCellSizes( + int nCells, + boolean fill, + boolean shrink, + int[] minSize, + int PrefSize, + int[] prefSize, + int fullSize, + int CellWeight, + int[] cellWeight, + int[] adjSize, + Container parent) + +{ + // The sum of the weights (CellWeight) determines how many units + // any excess (or reduced) space should be divided into. The + // unitOfSpace variable is the size of each unit. + // + // We use weighting under two conditions: + // + // * We are shrinking the table. + // + // * We have more space than we need and the user asked us to + // fill the available space + // + // When we have more than enough space for the preferred row and + // column sizes, we follow the user's weighting. There is a + // special case if all weights are 0: the weights are treated as + // thought they were all 1. + // + // When do not have enough space, we weight everything the same. + + double unitOfSpace = 0.0; + if (shrink || fill) { + unitOfSpace = + (double)(fullSize - PrefSize) / + (double)((shrink || CellWeight == 0) ? nCells : CellWeight); + } + else { + // No adjustment needed: use the preferred sizes + + for (int i = 0; i < nCells; i++) { + adjSize[i] = prefSize[i]; + } + return; + } + + double extraSpace; int iExtraSpace; + double error = 0.0; int iError = -999999; + + int adjWeight; + + for (int i = 0; i < nCells; i++) { + + // Initialize the adjusted size to the preferred size + + adjSize[i] = prefSize[i]; + + // Get the cell weight based on various conditions + + adjWeight = (shrink || CellWeight == 0) ? 1 : cellWeight[i]; + + // Determine how much extra space to give each cell. The space + // is the weight (number of units) times the unit size. We can + // only assign an integer number of pixels, which creates a + // fractional error + + extraSpace = unitOfSpace * adjWeight; + iExtraSpace = (int)extraSpace; + adjSize[i] += iExtraSpace; + + error += extraSpace - iExtraSpace; + iError = (int)error; + + // Increment/decrement this cell by the accumulated integer + // error, if it's not 0 + + if (shrink) { + if (iError < 0) { + adjSize[i] += iError; + } + } + else { + if (iError > 0) { + adjSize[i] += iError; + } + } + error -= iError; + + // If we're shrinking, we need to prevent any cell from + // shrinking below its minimum size. The error is adjusted to + // include the space added to the cell + + if (shrink && (adjSize[i] < minSize[i])) { + error -= minSize[i] - adjSize[i]; + adjSize[i] = minSize[i]; + } + + iError = (int)error; + } + + // If we are growing, the error should be less than 1 pixel. If we + // are shrinking, we limit each cell to its minimum size, so we + // can accumulate larger errors as cells refuse to shrink. So we + // distribute the error to cells that can still shrink. We repeat + // this until we've reduced the error to 0 or we're unable to + // shrink the error anymore. + // + // Remember that iError is a negative number + + if (shrink || iError < 0) { + int lastIError; + + do { + lastIError = iError; + for (int i = 0; i < nCells; i++) { + + // If the cell is already at its minimum size, skip it + + if (adjSize[i] > minSize[i]) { + adjSize[i]--; + iError++; + } + } + } + while (iError < 0 && iError > lastIError); + } + + // DEBUG + +// if ("DEBUG".equals(parent.getName())) { +// System.out.println(" iError " + iError); +// for (int i = 0; i < nCells; i++) { +// System.out.println(" " + i + ") Adjusted size = " + adjSize[i]); +// } +// } +} + +/** + * For each component, determine its row/col position and place it in + * an array for easy access later. Elements spanning multiple rows + * and/or columns are placed in the NW row/col slot in the array. + * Results are placed in class fields. + * + * @param parent The parent container. + */ + +private void +placeComponents( + Container parent) +{ + // If we haven't added or removed a component since the last time + // placeComponents() was called, we assume the current results are + // OK + + if (components != null) return; + + int compCount = parent.getComponentCount(); + + // Get the number of columns specified by the user + + nCols = tableAttributes.columns; + + // Create the array of components + + CompArray compArray = new CompArray(tableAttributes.columns, compCount); + + // Fill the array with components, taking row/column spanning + // into account + + int row = 0; + int col = 0; + + for (int i = 0; i < compCount; i++) { + + // Get the next component and its options + + Component comp = parent.getComponent(i); + Attributes attributes = (Attributes)compAttributes.get(comp); + + // If the column span is greater than the column size, + // truncate it to the column size + + attributes.cSpan = attributes.originalCSpan; + if (attributes.cSpan > tableAttributes.columns) { + attributes.cSpan = tableAttributes.columns; + + } + // Handle options to force us to column 0 or to skip columns + + if (attributes.column != Attributes.NEXT_COLUMN) { + if (col > attributes.column) row++; + col = attributes.column; + } + col += attributes.skip; + if (col >= nCols) { + row++; + col = 0; + } + + // Skip over any cells that are already occupied + + while (compArray.get(row, col) != null) { + col++; + if (col >= nCols) { + row++; + col = 0; + } + } + + // If spanning multiple columns, will we fit on this row? + + if (col + attributes.cSpan > nCols) { + row++; + col = 0; + } + + // For now, fill all the cells that are occupied by this + // component + + for (int c = 0; c < attributes.cSpan; c++) { + for (int r = 0; r < attributes.rSpan; r++) { + compArray.set(row + r, col + c, comp); + } + } + + // Advance to the next cell, ready for the next component + + col += attributes.cSpan; + if (col >= nCols) { + row++; + col = 0; + } + } + + // Now we know how many rows there are. We can use a normal, + // properly sized array from now on. The array returned includes + // the maximum row into which anything was entered, including any + // row spans + + components = compArray.getArray(); + nRows = components.length; + + // Now we've positioned our components we can thin out the cells so + // we only remember the top left corner of each component + + for (row = 0; row < nRows; row++) { + for (col = 0; col < nCols; col++) { + Component comp = components[row][col]; + for (int r = row; r < nRows && components[r][col] == comp; r++) { + for (int c = col; c < nCols && components[r][c] == comp; c++) { + if (r > row || c > col) { + components[r][c] = null; + } + } + } + } + } + + // DEBUG + +// if ("DEBUG".equals(parent.getName())) { +// System.out.println("placeComponents finished: rows = " + +// nRows + " cols = " + nCols); +// for (int r = 0; r < nRows; r++) { +// System.out.println("Row " + r + ":"); +// for (int c = 0; c < nCols; c++) { +// System.out.println(" Col " + c + " Comp " + +// ((components[r][c] == null) ? +// "none" : +// components[r][c].getClass().getName())); +// } +// } +// } +} + +/** + * In this method, we will determine the minimum, preferred and + * maximum sizes of the components as layed out by the table layout + * manager + * + * @param parent The parent container. + */ + +private void +measureComponents( + Container parent) +{ + if (useCacheMeasureResults) return; + + // Determine the row/col positions for the components + + placeComponents(parent); + + // Allocate new arrays to store row and column preferred and min + // sizes, but only if the old arrays aren't big enough + + if (minWidth == null || minWidth.length < nCols) { + minWidth = new int[nCols]; + prefWidth = new int[nCols]; + maxWidth = new int[nCols]; + adjWidth = new int[nCols]; + colWeight = new int[nCols]; + } + if (minHeight == null || minHeight.length < nRows) { + minHeight = new int[nRows]; + prefHeight = new int[nRows]; + maxHeight = new int[nRows]; + adjHeight = new int[nRows]; + rowWeight = new int[nRows]; + } + + for (int i = 0; i < nCols; i++) { + minWidth[i] = 0; + prefWidth[i] = 0; + maxWidth[i] = 0; + colWeight[i] = 0; + } + for (int i = 0; i < nRows; i++) { + minHeight[i] = 0; + prefHeight[i] = 0; + maxHeight[i] = 0; + rowWeight[i] = 0; + } + + // Measure the minimum and preferred size of each row and column + + for (int row = 0; row < nRows; row++) { + for (int col = 0; col < nCols; col++) { + Component comp = components[row][col]; + if (comp != null) { + Attributes attributes = (Attributes)compAttributes.get(comp); + + Dimension minSize = new Dimension(comp.getMinimumSize()); + Dimension prefSize = new Dimension(comp.getPreferredSize()); + Dimension maxSize = new Dimension(comp.getMaximumSize()); + + // Add the cell insets + + minSize.width += + attributes.cellInsets.left + attributes.cellInsets.right; + minSize.height += + attributes.cellInsets.top + attributes.cellInsets.bottom; + prefSize.width += + attributes.cellInsets.left + attributes.cellInsets.right; + prefSize.height += + attributes.cellInsets.top + attributes.cellInsets.bottom; + maxSize.width += + attributes.cellInsets.left + attributes.cellInsets.right; + maxSize.height += + attributes.cellInsets.right + attributes.cellInsets.bottom; + + // Make sure that 0 <= minSize <= prefSize <= maxSize + + limitDimension(minSize, new Dimension(0, 0)); + limitDimension(prefSize, minSize); + limitDimension(maxSize, prefSize); + + // First pass, we determine the sizes while ignoring + // components which span columns or rows + + if (attributes.cSpan == 1) { + minWidth[col] = + Math.max(minSize.width, minWidth[col]); + prefWidth[col] = + Math.max(prefSize.width, prefWidth[col]); + maxWidth[col] = + Math.max(maxSize.width, maxWidth[col]); + } + + if (attributes.rSpan == 1) { + minHeight[row] = + Math.max(minSize.height, minHeight[row]); + prefHeight[row] = + Math.max(prefSize.height, prefHeight[row]); + maxHeight[row] = + Math.max(maxSize.height, maxHeight[row]); + } + + // Get the row and column weights. The weight is the + // maximum value for the row or column + + if (attributes.cWeight > colWeight[col]) { + colWeight[col] = attributes.cWeight; + } + if (attributes.rWeight > rowWeight[row]) { + rowWeight[row] = attributes.rWeight; + } + } + } + } + + // Do it again, but just for components which span multiple cells. + // + + for (int row = 0; row < nRows; row++) { + for (int col = 0; col < nCols; col++) { + Component comp = components[row][col]; + if (comp != null) { + Attributes attributes = (Attributes)compAttributes.get(comp); + + if (attributes.rSpan == 1 && attributes.cSpan == 1) continue; + + Dimension minSize = new Dimension(comp.getMinimumSize()); + Dimension prefSize = new Dimension(comp.getPreferredSize()); + Dimension maxSize = new Dimension(comp.getMaximumSize()); + + // Add the cell insets + + minSize.width += + attributes.cellInsets.top + attributes.cellInsets.bottom; + minSize.height += + attributes.cellInsets.left + attributes.cellInsets.right; + prefSize.width += + attributes.cellInsets.top + attributes.cellInsets.bottom; + prefSize.height += + attributes.cellInsets.left + attributes.cellInsets.right; + maxSize.width += + attributes.cellInsets.top + attributes.cellInsets.bottom; + maxSize.height += + attributes.cellInsets.left + attributes.cellInsets.right; + + // Make sure that 0 <= minSize <= prefSize <= maxSize + + limitDimension(minSize, new Dimension(0, 0)); + limitDimension(prefSize, minSize); + limitDimension(maxSize, prefSize); + + if (attributes.cSpan > 1) { + adjustForSpans(col, + minSize.width, + minWidth, + colWeight, + attributes.cSpan, + tableAttributes.cGap); + adjustForSpans(col, + prefSize.width, + prefWidth, + colWeight, + attributes.cSpan, + tableAttributes.cGap); + adjustForSpans(col, + maxSize.width, + maxWidth, + colWeight, + attributes.cSpan, + tableAttributes.cGap); + } + + if (attributes.rSpan > 1) { + adjustForSpans(row, + minSize.height, + minHeight, + rowWeight, + attributes.rSpan, + tableAttributes.rGap); + adjustForSpans(row, + prefSize.height, + prefHeight, + rowWeight, + attributes.rSpan, + tableAttributes.rGap); + adjustForSpans(row, + maxSize.height, + maxHeight, + rowWeight, + attributes.rSpan, + tableAttributes.rGap); + } + } + } + } + + // Add up all the individual values + + MinWidth = 0; + MinHeight = 0; + PrefWidth = 0; + PrefHeight = 0; + MaxWidth = 0; + MaxHeight = 0; + ColWeight = 0; + RowWeight = 0; + + // Sum up everything + + for (int i = 0; i < nCols; i++) { + MinWidth += minWidth[i]; + PrefWidth += prefWidth[i]; + MaxWidth += maxWidth[i]; + ColWeight += colWeight[i]; + } + + for (int i = 0; i < nRows; i++) { + MinHeight += minHeight[i]; + PrefHeight += prefHeight[i]; + MaxHeight += maxHeight[i]; + RowWeight += rowWeight[i]; + } + + // Add in the table gaps + + int cExtra = tableAttributes.cGap * (nCols - 1); + int rExtra = tableAttributes.rGap * (nRows - 1); + + MinWidth += cExtra; + PrefWidth += cExtra; + MaxWidth += cExtra; + + MinHeight += rExtra; + PrefHeight += rExtra; + MaxHeight += rExtra; + + // DEBUG + +// if ("DEBUG".equals(parent.getName())) { +// System.out.println("MeasureComponents:"); +// System.out.println(" Min " + MinWidth + ", " + MinHeight); +// System.out.println(" Pref " + PrefWidth + ", " + PrefHeight); +// System.out.println(" Max " + MaxWidth + ", " + MaxHeight); +// System.out.println(" Weight " + ColWeight + ", " + RowWeight ); + +// for (int c = 0; c < nCols; c++) { +// System.out.println(" Col " + c + +// " min " + minWidth[c] + +// " pref " + prefWidth[c] + +// " max " + maxWidth[c] + +// " wgt " + colWeight[c]); +// } +// for (int r = 0; r < nRows; r++) { +// System.out.println(" Row " + r + +// " min " + minHeight[r] + +// " pref " + prefHeight[r] + +// " max " + maxHeight[r] + +// " wgt " + rowWeight[r]); +// } +// } + + // We keep using these results until the layout is invalidated + + useCacheMeasureResults = true; +} + +/** + * Make sure the first dimension is greater than or equal to the + * second. Also make sure the first dimension is less than an absolute + * maximum. + * + * @param d1 The first dimension (may be modified). + * @param d2 The second dimension (will not be modified). + */ + +private void +limitDimension( + Dimension d1, + Dimension d2) +{ + if (d1.width < d2.width) d1.width = d2.width; + if (d1.height < d2.height) d1.height = d2.height; + if (d1.width > Short.MAX_VALUE) d1.width = Short.MAX_VALUE; + if (d1.height > Short.MAX_VALUE) d1.height = Short.MAX_VALUE; +} + +/** + * If a component spans multiple rows or columns, we need to + * distribute portions of its size to the individual rows and columns. + * + * @param pos Row or column position where the span component starts. + * @param compSize The height or width of the component + * @param sizes The array of widths or heights to adjust. + * @param span The number of cells spanned by the component. + * @param gap The row or column gap. + */ + +private void +adjustForSpans( + int pos, + int compSize, + int[] sizes, + int[] weight, + int span, + int gap) +{ + // The total size is the size of the rows or columns plus all the + // space in between + + int totalSize = 0; + for (int i = 0; i < span; i++) { + totalSize += sizes[pos + i]; + } + totalSize += gap * (span - 1); + + // If the spanned component is bigger than the the rows or columns + // it spans, we divide the extra space based on the weights of the + // spanned rows or columns + + if (compSize > totalSize) { + int extra = compSize - totalSize; + int totalWeight = 0; + for (int i = 0; i < span; i++) { + totalWeight += weight[pos + i]; + } + if (totalWeight == 0) totalWeight = span; + + int remainder = extra; + for (int i = 0; i < span; i++) { + int portion = (extra * weight[pos + i]) / totalWeight; + sizes[pos + i] += portion; + remainder -= portion; + } + + // Because of truncation, we may have a little left over which + // we give to the last row or column + + if (remainder > 0) { + sizes[pos + span - 1] += remainder; + } + } +} + +//********************************************************************** +// Inner Classes +//********************************************************************** + +//********************************************************************** +// +// Attributes +// +// This class converts a string attribute into a data structure. +// +//********************************************************************** + +// Attributes not needing assigment + +static String[] attr = { + "tn", "tne", "tnw", + "ts", "tse", "tsw", + "te", "tw", "tc", + "tfh", "tfv", "tf", + "n", "ne", "nw", + "s", "se", "sw", + "e", "w", "c", + "fh", "fv", "f", +}; + +// Attributes needing assigment + +static String[] assgn = { + "cols", + "rgap", + "cgap", + "titop", + "tibottom", + "tileft", + "tiright", + "itop", + "ibottom", + "ileft", + "iright", + "rweight", + "cweight", + "rspan", + "cspan", + "col", + "skip" +}; + +private class Attributes +{ + +// Constants used for fill and placement operations + +static final int CENTER = 0; +static final int LEFT = 1; +static final int RIGHT = 2; +static final int TOP = 3; +static final int BOTTOM = 4; +static final int FILL = 5; + +// Constants for column placement + +static final int NEXT_COLUMN = -1; + +// The attributes in their original string form + +String attrString; + +// Table-only options + +int columns = 1; +int tableHorizontal = FILL; +int tableVertical = FILL; +int rGap = 0; +int cGap = 0; +Insets tableInsets = new Insets(0, 0, 0, 0); + +// Table/cell options + +int horizontal = FILL; +int vertical = FILL; +Insets cellInsets = new Insets(0, 0, 0, 0); +int rWeight = 0; +int cWeight = 0; + +// Cell-only options + +int rSpan = 1; +int cSpan = 1; +int originalCSpan = cSpan; +int column = NEXT_COLUMN; +int skip = 0; + +int tkPos = 0; +boolean isTableAttributes = false; + +Attributes( + String attrString) +{ + this(attrString, true); +} + +Attributes( + String attrString, + boolean isTableAttributes) +{ + // Save the string for later access + + this.attrString = attrString; + + this.isTableAttributes = isTableAttributes; + + parse(); +} + +public String +toString() +{ + String sep = System.getProperty("line.separator"); + return "TableLayout Attributes:" + sep + + "isTableAttributes = " + isTableAttributes + sep + + "columns = " + columns + sep + + "tableHorizontal = " + tableHorizontal + " " + + "tableVertical = " + tableVertical + sep + + "rGap = " + rGap + " " + + "cGap = " + cGap + sep + + "tableInsets = " + tableInsets + sep + + "horizontal = " + horizontal + " " + + "vertical = " + vertical + sep + + "cellInsets = " + cellInsets + sep + + "rWeight = " + rWeight + " " + + "cWeight = " + cWeight + sep + + "rSpan = " + rSpan + " " + + "cSpan = " + cSpan + sep + + "originalCSpan = " + originalCSpan + sep + + "column = " + column + sep + + "skip = " + skip; +} + +String +getStringAttributes() +{ + return attrString; +} + +private char +getTokenChar() +{ + if (tkPos >= attrString.length()) return 0; + return Character.toLowerCase(attrString.charAt(tkPos++)); +} + + +private String +getToken() +{ + StringBuffer token = new StringBuffer(); + + char c = getTokenChar(); + + // Skip whitespace + + if (Character.isWhitespace(c)) { + do { + c = getTokenChar(); + } + while (Character.isWhitespace(c)); + } + + // Attributes + + if (Character.isLetter(c)) { + do { + token.append(c); + c = getTokenChar(); + } + while (Character.isLetter(c)); + if (c != 0) tkPos--; + } + + // Integers + + else if (Character.isDigit(c)) { + do { + token.append(c); + c = getTokenChar(); + } + while (Character.isDigit(c)); + if (c != 0) tkPos--; + } + + // End of string + + else if (c == 0) { + return null; + } + + // Everything else is a single-character token + + else { + token.append(c); + } + + return new String(token); +} + +void +parse() +{ + // Initialize this set of attributes so it starts out as a copy of + // the given default, at least for those options where the cell + // can override a table default + + if (!isTableAttributes) { + horizontal = tableAttributes.horizontal; + vertical = tableAttributes.vertical; + cellInsets = (Insets)tableAttributes.cellInsets.clone(); + rWeight = tableAttributes.rWeight; + cWeight = tableAttributes.cWeight; + } + + if (attrString == null) return; + tkPos = 0; + + while (tkPos < attrString.length()) { + parseOption(); + } + + // We have checked the syntax, now check the semantics + + if (isTableAttributes) { + if (columns == 0) { + reportSemanticError("cols=0"); + } + } + else { + if (rSpan == 0) { + reportSemanticError("rspan=0"); + } + if (cSpan == 0) { + reportSemanticError("cspan=0"); + } + if (column >= tableAttributes.columns) { + reportSemanticError("col=" + column + + " (max is " + + (tableAttributes.columns - 1) + ")"); + } + } +} + +private void +parseOption() +{ + // Get the next token + + String token = getToken(); + if (token == null) return; + + boolean attributeFound = false; + for (int i = 0; i < attr.length; i++) { + if (token.equals(attr[i])) { + parseAttribute(token); + return; + } + } + + for (int i = 0; i < assgn.length; i++) { + if (token.equals(assgn[i])) { + parseAssignment(token); + return; + } + } + + reportError(token, "Unrecognized attribute"); +} + +private void +parseAttribute( + String token) +{ + // Table placement and fill + + if ("tnw".equals(token) || + "tw".equals(token) || + "tsw".equals(token)) { + tableHorizontal = LEFT; + } + + if ("tne".equals(token) || + "te".equals(token) || + "tse".equals(token)) { + tableHorizontal = RIGHT; + } + + if ("tn".equals(token) || + "tc".equals(token) || + "ts".equals(token)) { + tableHorizontal = CENTER; + } + + if ("tf".equals(token) || + "tfh".equals(token)) { + tableHorizontal = FILL; + } + + if ("tn".equals(token) || + "tnw".equals(token) || + "tne".equals(token)) { + tableVertical = TOP; + } + + if ("ts".equals(token) || + "tsw".equals(token) || + "tse".equals(token)) { + tableVertical = BOTTOM; + } + + if ("tw".equals(token) || + "tc".equals(token) || + "te".equals(token)) { + tableVertical = CENTER; + } + + if ("tf".equals(token) || + "tfv".equals(token)) { + tableVertical = FILL; + } + + // Cell placement and fill + + if ("nw".equals(token) || + "w".equals(token) || + "sw".equals(token)) { + horizontal = LEFT; + } + + if ("ne".equals(token) || + "e".equals(token) || + "se".equals(token)) { + horizontal = RIGHT; + } + + if ("n".equals(token) || + "c".equals(token) || + "s".equals(token)) { + horizontal = CENTER; + } + + if ("f".equals(token) || + "fh".equals(token)) { + horizontal = FILL; + } + + if ("n".equals(token) || + "nw".equals(token) || + "ne".equals(token)) { + vertical = TOP; + } + + if ("s".equals(token) || + "sw".equals(token) || + "se".equals(token)) { + vertical = BOTTOM; + } + + if ("w".equals(token) || + "c".equals(token) || + "e".equals(token)) { + vertical = CENTER; + } + + if ("f".equals(token) || + "fv".equals(token)) { + vertical = FILL; + } +} + +private void +parseAssignment( + String token) +{ + String attr = token; + + token = getToken(); + if (token != null) { + if ("=".equals(token)) { + token = getToken(); + if (token != null) { + int value = 0; + try { + value = Integer.parseInt(token); + } + catch (NumberFormatException e) { + reportError(token, "Expected an integer"); + } + + if ("cols".equals(attr)) + columns = value; + else if ("rgap".equals(attr)) + rGap = value; + else if ("cgap".equals(attr)) + cGap = value; + else if ("titop".equals(attr)) + tableInsets.top = value; + else if ("tibottom".equals(attr)) + tableInsets.bottom = value; + else if ("tileft".equals(attr)) + tableInsets.left = value; + else if ("tiright".equals(attr)) + tableInsets.right = value; + else if ("itop".equals(attr)) + cellInsets.top = value; + else if ("ibottom".equals(attr)) + cellInsets.bottom = value; + else if ("ileft".equals(attr)) + cellInsets.left = value; + else if ("iright".equals(attr)) + cellInsets.right = value; + else if ("rweight".equals(attr)) + rWeight = value; + else if ("cweight".equals(attr)) + cWeight = value; + else if ("rspan".equals(attr)) + rSpan = value; + else if ("cspan".equals(attr)) + originalCSpan = cSpan = value; + else if ("col".equals(attr)) + column = value; + else if ("skip".equals(attr)) + skip = value; + + return; + } + } + reportError(token, "Expected an '='"); + } + reportError(token, "Expected an '='"); +} + +private void +reportError( + String token, + String message) +{ + throw new IllegalArgumentException( + "TableLayout: " + message + "; near '" + token + + "' at position " + tkPos + " in '" + + attrString + "'"); +} + +private void +reportSemanticError( + String message) +{ + throw new IllegalArgumentException( + "TableLayout: Invalid value: " + message); +} + +} + +//********************************************************************** +// +// CompArray +// +// We'd like to use a 2-dimensional array to help us sort out the +// layout of the various components. But in order to create the array, +// we need to know the number of rows. In order to get the number of +// rows, we need to lay out the components. So we have problem. +// +// It is not obvious how to determine the number of rows from the +// component count, due to row and column spans. So we've created the +// CompArray class to help out. It makes its best guess at the size of +// the array. If we need additional rows, it expands the array as +// efficiently as it can. When we're done, we can ask it to create a +// correctly sized array to hold our data. +// +//********************************************************************** + +private class CompArray +{ + +private int nCols; +private int nRows; +private int maxRow = 0; +Component[][] compArray = null; + +CompArray( + int nCols, + int compCount) +{ + this.nRows = (compCount + (nCols - 1)) / nCols; + this.nRows = Math.max(this.nRows, 1); + this.nCols = nCols; + + compArray = new Component[nRows][]; + for (int i = 0; i < nRows; i++) { + compArray[i] = new Component[nCols]; + Arrays.fill(compArray[i], null); + } +} + +Component +get( + int row, + int col) +{ + if (row >= nRows) resize(row + 1); + return compArray[row][col]; +} + +void +set( + int row, + int col, + Component comp) +{ + if (row >= nRows) resize(row + 1); + compArray[row][col] = comp; + maxRow = Math.max(row, maxRow); +} + +Component[][] +getArray() +{ + int maxRows = maxRow + 1; + Component[][] array = new Component[maxRows][]; + for (int r = 0; r < maxRows; r++) { + array[r] = new Component[nCols]; + System.arraycopy(compArray[r], 0, array[r], 0, nCols); + } + + return array; +} + +private void +resize( + int newRows) +{ + // When we exceed a threshold, bump up the size by at least 10 + + if (newRows - nRows < 10) newRows = nRows + 10; + + // Create the new row array and copy the old one into it + + Component[][] newArray = new Component[newRows][]; + System.arraycopy(compArray, 0, newArray, 0, nRows); + + // Initialize each new row to nulls + + for (int i = nRows; i < newRows; i++) { + newArray[i] = new Component[nCols]; + Arrays.fill(newArray[i], null); + } + + compArray = newArray; + nRows = newRows; +} + +} + +//********************************************************************** +// End Inner Classes +//********************************************************************** + +} diff --git a/libs/FLib/TableLayout/project.dtd b/libs/FLib/TableLayout/project.dtd new file mode 100644 index 0000000..dee3c51 --- /dev/null +++ b/libs/FLib/TableLayout/project.dtd @@ -0,0 +1,5193 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/FLib/build.xml b/libs/FLib/build.xml new file mode 100644 index 0000000..aa926d8 --- /dev/null +++ b/libs/FLib/build.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/FLib/images/Logo.png b/libs/FLib/images/Logo.png new file mode 100644 index 0000000..935c694 Binary files /dev/null and b/libs/FLib/images/Logo.png differ diff --git a/libs/FLib/index.html b/libs/FLib/index.html new file mode 100644 index 0000000..4c76631 --- /dev/null +++ b/libs/FLib/index.html @@ -0,0 +1,56 @@ + + + + + + + +FLib - High-Quality Java Components + + + + + + + + +

+ + + + + +
+

Welcome to FLib!

+

FLib is a free, open source library of high-quality Java components. + To view the components, select a component name from the list on the left.

+

JCalendar is a calendar component. You can use it to display a date + and/or time or to allow the user to enter a date and/or time. It appears + in two forms: a panel containing a calendar and a combo box with a drop-down + calendar. Although it needs some localization, most of the localization + work is done by taking advantage of the localization in the Java Calendar + class.

+

JWizard is a wizard component, which is like a dialog that leads the + user through a series of steps to complete some task. This component + is very easy to use and contains the common features of a wizard: a logo + on the left side, a title for the wizard, a title for each wizard step, + Back Next, Finish, Cancel and Help buttons, etc. It is fully internationalized + and ready for localization.

+

TableLayout is a layout manager. It is loosely based on the HTML table + and completely replaces the hard-to-use and hard-to-understand GridBagLayout + manager. There is no layout that the GridBagLayout can generate that + cannot be equivalently laid out with the TableLayout, but the latter + is dramatically easier to use.

+

There's a lot more information behind the links on the left: features + list, screen shots, tutorials and examples as well as full API documentation.

+

Tony Freixas

+

Support This Project

+
+ + diff --git a/libs/FLib/project.dtd b/libs/FLib/project.dtd new file mode 100644 index 0000000..b8153db --- /dev/null +++ b/libs/FLib/project.dtd @@ -0,0 +1,5193 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3