[7128] Fixes to merge tool. [7129] Merge from branches/manual_2009_03 to versions/5.3 (multiple changesets) [7131] Fixed language problems in the section on layout cell spacing. [7132] Use 24 hour format instead of 12 hour for Eclipse Manual plugin timestamp. svn changeset:7169/svn branch:6.0tags/6.7.0.beta1
@@ -135,7 +135,7 @@ | |||
<h4>Eclipse IDE QuickStart</h4> | |||
<p>The easiest way to start working with IT Mill Toolkit is to | |||
use Eclipse IDE with the Toolkit QuickStart project. | |||
<a href="doc/manual/intro.quickstart.html" class="more">Instant Toolkit workspace for Eclipse</a></p> | |||
<a href="doc/manual/getting-started.quickstart.html" class="more">Instant Toolkit workspace for Eclipse</a></p> | |||
</div> <!-- /getting-started --> | |||
@@ -25,7 +25,7 @@ def help(exitvalue = 0): | |||
print "\t-author\tHTML output. (Include author in HTML log.)" | |||
print "\t-milestone <ms>\tList tickets in milestone (For 'log' command.)" | |||
print "\nCommands:" | |||
print "massmerge <cfg> <src> <trg> [<from>] " | |||
print "massmerge <cfg> <src> [<from>] " | |||
print " - Merges changesets listed in the configuration" | |||
print " file. The file is in svn log (text) format." | |||
print " You can comment out unwanted changesets." | |||
@@ -370,9 +370,26 @@ class Configuration: | |||
if currentChange: | |||
currentChange.addCommentLine(line) | |||
def massMerge(self, trunkURI, dryrun=0): | |||
for change in self.changes: | |||
change.merge(trunkURI, dryrun=dryrun) | |||
def massMerge(self, trunkURI, dryrun=0, allatonce=0): | |||
if not allatonce: | |||
# Merge one changeset at a time | |||
for change in self.changes: | |||
change.merge(trunkURI, dryrun=dryrun) | |||
else: | |||
# What is the first changeset in the merge? | |||
smallest = 99999999 | |||
for change in self.changes: | |||
if change.getNumber() < smallest: | |||
smallest = change.getNumber() | |||
drycmd = "" | |||
if dryrun: | |||
drycmd = "--dry-run" | |||
# Merge from the first changeset to HEAD | |||
cmd = "svn merge --non-interactive %s -r %d:HEAD %s" % (drycmd, smallest, trunkURI) | |||
print cmd | |||
command(cmd) | |||
def createLogComment(self): | |||
# Create a log comment that lists all merged changesets with | |||
@@ -563,9 +580,9 @@ def commandRevert(): | |||
print "Nothing to do." | |||
# Command: massmerge | |||
def commandMassmerge(cfgfilename, sourceuri, startfrom, dryrun=0): | |||
def commandMassmerge(cfgfilename, sourceuri, startfrom, dryrun=0, allatonce=0): | |||
cfg = Configuration(cfgfilename, startfrom=startfrom) | |||
cfg.massMerge(sourceuri, dryrun=dryrun) | |||
cfg.massMerge(sourceuri, dryrun=dryrun, allatonce=allatonce) | |||
# Command: single | |||
def commandSingle(trunkuri, changeset, sourcebranch, targetbranch, onlymerge=0, onlycommit=0): | |||
@@ -612,6 +629,7 @@ html_author = 0 | |||
html_milestone = None | |||
onlymerge = 0 | |||
onlycommit = 0 | |||
all = 0 | |||
while len(sys.argv)>1 and sys.argv[1][0] == '-': | |||
if sys.argv[1] == "-d": | |||
dryrun = 1 | |||
@@ -637,6 +655,10 @@ while len(sys.argv)>1 and sys.argv[1][0] == '-': | |||
onlycommit = 1 | |||
del sys.argv[1:2] | |||
elif sys.argv[1] == "-all": | |||
all = 1 | |||
del sys.argv[1:2] | |||
else: | |||
print "Invalid option '%s'." % (sys.argv[1]) | |||
sys.exit(1) | |||
@@ -654,7 +676,7 @@ elif (len(sys.argv) == 4 or len(sys.argv)==5) and sys.argv[1] == "massmerge": | |||
startfrom = None | |||
if len(sys.argv)>4: | |||
startfrom = int(sys.argv[4]) | |||
commandMassmerge(cfgfilename, sourceuri=REPOSITORY+sourcebranch, startfrom=startfrom, dryrun=dryrun) | |||
commandMassmerge(cfgfilename, sourceuri=REPOSITORY+sourcebranch, startfrom=startfrom, dryrun=dryrun, allatonce=all) | |||
elif len(sys.argv) == 5 and sys.argv[1] == "single": | |||
changeset = int(sys.argv[2]) |
@@ -1008,6 +1008,14 @@ | |||
<tstamp> | |||
<format property="manual.pubdate" pattern="yyyy-MM-dd"/> | |||
</tstamp> | |||
<!-- Classpath for running the XSLT processor. --> | |||
<path id="docbook-xsl.classpath"> | |||
<pathelement path="build/lib/fserializer.jar" /> | |||
<pathelement path="build/lib/xalan.jar" /> | |||
<pathelement path="build/lib/xercesImpl.jar" /> | |||
<pathelement path="build/lib/xml-apis.jar" /> | |||
</path> | |||
</target> | |||
<!-- Build PDF manual from sources or just copy it. --> | |||
@@ -1059,11 +1067,7 @@ | |||
<arg value="-param" /> | |||
<arg value="manual.version" /> | |||
<arg value="${version}" /> | |||
<classpath> | |||
<pathelement location="build/lib/xalan.jar" /> | |||
<pathelement location="build/lib/xercesImpl.jar" /> | |||
<pathelement location="build/lib/xml-apis.jar" /> | |||
</classpath> | |||
<classpath refid="docbook-xsl.classpath" /> | |||
</java> | |||
<echo>PDF Manual: converting fo to pdf</echo> | |||
<!-- Run XEP FO processor to convert FO to PDF --> | |||
@@ -1078,10 +1082,18 @@ | |||
</java> | |||
</target> | |||
<target name="manual-html" depends="init, init-manual, preprocess-src"> | |||
<echo>Manual: HTML</echo> | |||
<delete file="build/docbook/conf/temp.xsl" /> | |||
<copy file="build/docbook/conf/custom-html-docbook.xsl" tofile="build/docbook/conf/temp.xsl"> | |||
<!-- Common initialization tasks for a HTML manual. --> | |||
<!-- Some properties must be defined in the more specific HTML manual initialization. --> | |||
<target name="init-manual-html-common" depends="preprocess-src"> | |||
<!-- Create the manual output directory if it doesn't already exist. --> | |||
<mkdir dir="${manual.html.output.dir}"/> | |||
<property name="manual.html.xsl.template" value="build/docbook/conf/custom-html-template.xsl"/> | |||
<property name="manual.html.xsl.processed" value="build/docbook/conf/custom-html-processed.xsl"/> | |||
<!-- Replace tags in the HTML stylesheet template. --> | |||
<delete file="${manual.html.xsl.processed}" /> | |||
<copy file="${manual.html.xsl.template}" tofile="${manual.html.xsl.processed}"> | |||
<filterchain> | |||
<replacetokens> | |||
<token key="BODYHEADER" value="${html.body.start1}${docbook.head.title}${html.body.start2}" /> | |||
@@ -1089,19 +1101,17 @@ | |||
</replacetokens> | |||
</filterchain> | |||
</copy> | |||
<path id="docbook-xsl.classpath"> | |||
<pathelement path="build/lib/fserializer.jar" /> | |||
<pathelement path="build/lib/xalan.jar" /> | |||
<pathelement path="build/lib/xercesImpl.jar" /> | |||
<pathelement path="build/lib/xml-apis.jar" /> | |||
</path> | |||
</target> | |||
<target name="manual-html-build" depends="init-manual-html, init-manual-html-common"> | |||
<java classname="org.apache.xalan.xslt.Process" failonerror="yes" fork="yes" maxmemory="512m"> | |||
<arg value="-in" /> | |||
<arg value="doc/manual/book.xml" /> | |||
<arg value="-xsl" /> | |||
<arg value="build/docbook/conf/temp.xsl" /> | |||
<arg value="${manual.html.xsl}" /> | |||
<!-- The output file will be empty for eclipse plugin. --> | |||
<arg value="-out" /> | |||
<arg value="${output-dir}/WebContent/doc/manual/index.html" /> | |||
<arg value="${manual.html.output.index}" /> | |||
<arg value="-param" /> | |||
<arg value="section.autolabel" /> | |||
<arg value="1" /> | |||
@@ -1120,14 +1130,34 @@ | |||
<arg value="-param" /> | |||
<arg value="manual.version" /> | |||
<arg value="${version}" /> | |||
<!-- This is needed only for the Eclipse Help plugin. --> | |||
<arg value="-param" /> | |||
<arg value="eclipse.plugin.version" /> | |||
<arg value="${eclipse.plugin.manual.version}" /> | |||
<classpath refid="docbook-xsl.classpath" /> | |||
</java> | |||
<delete file="build/docbook/conf/temp.xsl" /> | |||
<copy todir="${output-dir}/WebContent/doc/manual/img"> | |||
<delete file="${manual.html.xsl.processed}" /> | |||
<copy todir="${output-dir}/WebContent/doc/eclipse/img"> | |||
<fileset dir="doc/manual/img"> | |||
<exclude name="**/.svn" /> | |||
</fileset> | |||
</copy> | |||
</target> | |||
<!-- Configuration for building the regular HTML manual. --> | |||
<target name="init-manual-html" depends="init, init-manual"> | |||
<property name="manual.html.xsl" value="build/docbook/conf/manual-html.xsl"/> | |||
<property name="manual.html.output.dir" value="${output-dir}/WebContent/doc/manual"/> | |||
<property name="manual.html.output.index" value="${manual.html.output.dir}/index.html"/> | |||
<property name="output-dir-manual" value="${output-dir}/WebContent/doc/manual" /> | |||
<echo>Manual: HTML</echo> | |||
<echo>Published: ${manual.pubdate}</echo> | |||
</target> | |||
<target name="manual-html" depends="init, init-manual, init-manual-html, init-manual-html-common, manual-html-build"> | |||
</target> | |||
<!-- ant contrib required for flow control (for loop, if, property override) --> | |||
@@ -1140,6 +1170,49 @@ | |||
<!-- java2html converter --> | |||
<taskdef name="java2html" classname="de.java2html.anttasks.Java2HtmlTask" classpath="build/lib/java2html.jar" /> | |||
<target name="init-manual-eclipse" depends=""> | |||
<!-- Timestamp in YYYYMMDDHHMM format for plugin version number. --> | |||
<tstamp> | |||
<format property="eclipse.plugin.manual.pubtime" pattern="yyyyMMddkkmm"/> | |||
</tstamp> | |||
<property name="eclipse.plugin.manual.version" value="${version}.v${eclipse.plugin.manual.pubtime}" /> | |||
<echo>Manual: Eclipse Help Plugin (version ${eclipse.plugin.manual.version})</echo> | |||
<property name="manual.html.xsl" value="build/docbook/conf/manual-eclipse-plugin.xsl"/> | |||
<property name="manual.html.output.dir" value="${output-dir}/WebContent/doc/eclipse"/> | |||
<property name="manual.html.output.index" value="${manual.html.output.dir}/index-eclipse.html"/> | |||
<property name="output-dir-manual" value="${output-dir}/WebContent/doc/manual" /> | |||
</target> | |||
<!-- Builds Eclipse Help plugin. Uses the manual-html-build target --> | |||
<!-- to build the HTML content of the manual. --> | |||
<target name="manual-eclipse" depends="init, init-manual, init-manual-eclipse, init-manual-html-common, manual-html-build"> | |||
<!-- The index-eclipse.html file is empty. --> | |||
<delete file="${manual.html.output.index}" /> | |||
<!-- Plugin JAR filename --> | |||
<property name="eclipse.plugin.manual.jar-name" | |||
value="com.itmill.toolkit.manual_${eclipse.plugin.manual.version}.jar" /> | |||
<!-- Package the JAR. --> | |||
<jar jarfile="${output-dir}/${eclipse.plugin.manual.jar-name}" compress="true"> | |||
<fileset dir="${manual.html.output.dir}"> | |||
<patternset> | |||
<include name="**/*" /> | |||
</patternset> | |||
</fileset> | |||
<manifest> | |||
<attribute name="Built-By" value="${user.name}"/> | |||
<attribute name="Bundle-Name" value="IT Mill Toolkit Reference Manual"/> | |||
<attribute name="Bundle-SymbolicName" value="com.itmill.toolkit.manual"/> | |||
<attribute name="Bundle-Version" value="${eclipse.plugin.manual.version}"/> | |||
<attribute name="Bundle-Vendor" value="IT Mill Inc."/> | |||
</manifest> | |||
</jar> | |||
</target> | |||
<!-- ================================================================== --> | |||
<!-- Build Application Tutorial. --> | |||
<!-- ================================================================== --> |
@@ -1096,7 +1096,7 @@ public abstract class Application implements URIHandler, Terminal.ErrorListener | |||
* @see com.itmill.toolkit.terminal.Terminal.ErrorListener#terminalError(com.itmill.toolkit.terminal.Terminal.ErrorEvent) | |||
*/ | |||
public void terminalError(Terminal.ErrorEvent event) { | |||
Throwable t = event.getThrowable(); | |||
final Throwable t = event.getThrowable(); | |||
if (t instanceof SocketException) { | |||
// Most likely client browser closed socket | |||
System.err | |||
@@ -1119,21 +1119,16 @@ public abstract class Application implements URIHandler, Terminal.ErrorListener | |||
// Shows the error in AbstractComponent | |||
if (owner instanceof AbstractComponent) { | |||
final Throwable e = event.getThrowable(); | |||
if (e instanceof ErrorMessage) { | |||
((AbstractComponent) owner).setComponentError((ErrorMessage) e); | |||
if (t instanceof ErrorMessage) { | |||
((AbstractComponent) owner).setComponentError((ErrorMessage) t); | |||
} else { | |||
((AbstractComponent) owner) | |||
.setComponentError(new SystemError(e)); | |||
.setComponentError(new SystemError(t)); | |||
} | |||
} else { | |||
/* | |||
* Can't show it to the user in any way so we print to standard | |||
* error | |||
*/ | |||
t.printStackTrace(); | |||
} | |||
// also print the error on console | |||
t.printStackTrace(); | |||
} | |||
/** |
@@ -259,15 +259,9 @@ public class PropertysetItem implements Item, Item.PropertySetChangeNotifier, | |||
return npsi; | |||
} | |||
/** | |||
* Returns <code>true</code> if and only if the argument is not | |||
* <code>null</code> and is a Boolean object that represents the same | |||
* boolean value as this object. | |||
/* | |||
* (non-Javadoc) | |||
* | |||
* @param obj | |||
* the object to compare with. | |||
* @return <code>true</code> if the Boolean objects represent the same value | |||
* otherwise <code>false</code>. | |||
* @see java.lang.Object#equals(java.lang.Object) | |||
*/ | |||
@Override | |||
@@ -308,10 +302,9 @@ public class PropertysetItem implements Item, Item.PropertySetChangeNotifier, | |||
return true; | |||
} | |||
/** | |||
* Returns the hash code value for this list. | |||
/* | |||
* (non-Javadoc) | |||
* | |||
* @return the hash code value. | |||
* @see java.lang.Object#hashCode() | |||
*/ | |||
@Override |
@@ -2,7 +2,7 @@ package com.itmill.toolkit.demo.sampler; | |||
/** | |||
* A NamedExternalResource pointing to the javadoc for the given class. Knows | |||
* where the javadocs are located for som common APIs, but one can also specify | |||
* where the javadocs are located for some common APIs, but one can also specify | |||
* a javadoc baseurl. The name will be set to the class simpleName. | |||
* | |||
*/ |
@@ -577,7 +577,8 @@ public class ApplicationServlet extends HttpServlet { | |||
.getInternalErrorCaption(), ci | |||
.getInternalErrorMessage(), ci.getInternalErrorURL()); | |||
if (application != null) { | |||
application.terminalError(new RequestError(e)); | |||
application.getErrorHandler().terminalError( | |||
new RequestError(e)); | |||
} else { | |||
throw new ServletException(e); | |||
} |
@@ -1473,7 +1473,8 @@ public class CommunicationManager implements Paintable.RepaintRequestListener { | |||
} | |||
} catch (final Throwable t) { | |||
application.terminalError(new URIHandlerErrorImpl(application, t)); | |||
application.getErrorHandler().terminalError( | |||
new URIHandlerErrorImpl(application, t)); | |||
return null; | |||
} | |||
} |
@@ -41,292 +41,292 @@ import com.itmill.toolkit.ui.UriFragmentUtility.FragmentChangedEvent; | |||
* | |||
*/ | |||
public class TestBench extends com.itmill.toolkit.Application implements | |||
Property.ValueChangeListener { | |||
// Add here packages which are used for finding testable classes | |||
String[] testablePackages = { "com.itmill.toolkit.tests", | |||
"com.itmill.toolkit.demo", "com.itmill.toolkit.demo.colorpicker", | |||
"com.itmill.toolkit.demo.reservation", | |||
"com.itmill.toolkit.demo.features", | |||
"com.itmill.toolkit.tests.tickets" }; | |||
HierarchicalContainer testables = new HierarchicalContainer(); | |||
Window mainWindow = new Window("TestBench window"); | |||
// Main layout consists of tree menu and body layout | |||
SplitPanel mainLayout = new SplitPanel(SplitPanel.ORIENTATION_HORIZONTAL); | |||
Tree menu; | |||
Panel bodyLayout = new Panel(); | |||
HashMap itemCaptions = new HashMap(); | |||
@Override | |||
public void init() { | |||
// Add testable classes to hierarchical container | |||
for (int p = 0; p < testablePackages.length; p++) { | |||
testables.addItem(testablePackages[p]); | |||
try { | |||
final List testableClasses = getTestableClassesForPackage(testablePackages[p]); | |||
for (final Iterator it = testableClasses.iterator(); it | |||
.hasNext();) { | |||
final Class t = (Class) it.next(); | |||
// ignore TestBench itself | |||
if (t.equals(TestBench.class)) { | |||
continue; | |||
} | |||
try { | |||
testables.addItem(t); | |||
itemCaptions.put(t, t.getName()); | |||
testables.setParent(t, testablePackages[p]); | |||
testables.setChildrenAllowed(t, false); | |||
continue; | |||
} catch (final Exception e) { | |||
try { | |||
testables.addItem(t); | |||
itemCaptions.put(t, t.getName()); | |||
testables.setParent(t, testablePackages[p]); | |||
testables.setChildrenAllowed(t, false); | |||
continue; | |||
} catch (final Exception e1) { | |||
e1.printStackTrace(); | |||
} | |||
} | |||
} | |||
} catch (final Exception e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
menu = new Tree("Testables", testables); | |||
for (final Iterator i = itemCaptions.keySet().iterator(); i.hasNext();) { | |||
final Class testable = (Class) i.next(); | |||
// simplify captions | |||
final String name = testable.getName().substring( | |||
testable.getName().lastIndexOf('.') + 1); | |||
menu.setItemCaption(testable, name); | |||
} | |||
// expand all root items | |||
for (final Iterator i = menu.rootItemIds().iterator(); i.hasNext();) { | |||
menu.expandItemsRecursively(i.next()); | |||
} | |||
menu.addListener(this); | |||
menu.setImmediate(true); | |||
menu.setNullSelectionAllowed(false); | |||
VerticalLayout lo = new VerticalLayout(); | |||
lo.addComponent(menu); | |||
UriFragmentUtility uri = new UriFragmentUtility(); | |||
lo.addComponent(uri); | |||
uri.addListener(new UriFragmentUtility.FragmentChangedListener() { | |||
public void fragmentChanged(FragmentChangedEvent source) { | |||
String fragment = source.getUriFragmentUtility().getFragment(); | |||
if (fragment != null && !"".equals(fragment)) { | |||
// try to find a proper test class | |||
// exact match | |||
Iterator iterator = menu.getItemIds().iterator(); | |||
while (iterator.hasNext()) { | |||
Object next = iterator.next(); | |||
if (next instanceof Class) { | |||
Class c = (Class) next; | |||
String string = c.getName(); | |||
if (string.equals(fragment)) { | |||
menu.setValue(c); | |||
mainLayout.setSplitPosition(0); | |||
return; | |||
} | |||
} | |||
} | |||
// simple name match | |||
iterator = menu.getItemIds().iterator(); | |||
while (iterator.hasNext()) { | |||
Object next = iterator.next(); | |||
if (next instanceof Class) { | |||
Class c = (Class) next; | |||
String string = c.getSimpleName(); | |||
if (string.equals(fragment)) { | |||
menu.setValue(c); | |||
mainLayout.setSplitPosition(0); | |||
return; | |||
} | |||
} | |||
} | |||
// ticket match | |||
iterator = menu.getItemIds().iterator(); | |||
while (iterator.hasNext()) { | |||
Object next = iterator.next(); | |||
if (next instanceof Class) { | |||
Class c = (Class) next; | |||
String string = c.getSimpleName(); | |||
if (string.startsWith("Ticket" + fragment)) { | |||
menu.setValue(c); | |||
mainLayout.setSplitPosition(0); | |||
return; | |||
} | |||
} | |||
} | |||
// just partly mach lowercase | |||
iterator = menu.getItemIds().iterator(); | |||
while (iterator.hasNext()) { | |||
Object next = iterator.next(); | |||
if (next instanceof Class) { | |||
Class c = (Class) next; | |||
String string = c.getSimpleName(); | |||
if (string.toLowerCase().contains( | |||
fragment.toLowerCase())) { | |||
menu.setValue(c); | |||
mainLayout.setSplitPosition(0); | |||
return; | |||
} | |||
} | |||
} | |||
getMainWindow().showNotification( | |||
"No potential matc for #" + fragment); | |||
} | |||
} | |||
}); | |||
mainLayout.addComponent(lo); | |||
bodyLayout.addStyleName("light"); | |||
bodyLayout.setSizeFull(); | |||
bodyLayout.setLayout(new ExpandLayout()); | |||
mainLayout.addComponent(bodyLayout); | |||
mainLayout.setSplitPosition(30); | |||
mainWindow.setLayout(mainLayout); | |||
setMainWindow(mainWindow); | |||
} | |||
private Component createTestable(Class c) { | |||
try { | |||
final Application app = (Application) c.newInstance(); | |||
app.init(); | |||
Layout lo = app.getMainWindow().getLayout(); | |||
lo.setParent(null); | |||
return lo; | |||
} catch (final Exception e) { | |||
try { | |||
final CustomComponent cc = (CustomComponent) c.newInstance(); | |||
cc.setSizeFull(); | |||
return cc; | |||
} catch (final Exception e1) { | |||
e1.printStackTrace(); | |||
VerticalLayout lo = new VerticalLayout(); | |||
lo.addComponent(new Label( | |||
"Cannot create application / custom component: " | |||
+ e1.toString())); | |||
Link l = new Link("Try opening via app runner", | |||
new ExternalResource("../run/" + c.getName())); | |||
lo.addComponent(l); | |||
return lo; | |||
} | |||
} | |||
} | |||
// Handle menu selection and update body | |||
public void valueChange(Property.ValueChangeEvent event) { | |||
bodyLayout.removeAllComponents(); | |||
bodyLayout.setCaption(null); | |||
final Object o = menu.getValue(); | |||
if (o != null && o instanceof Class) { | |||
final Class c = (Class) o; | |||
final String title = c.getName(); | |||
bodyLayout.setCaption(title); | |||
bodyLayout.addComponent(createTestable(c)); | |||
} else { | |||
// NOP node selected or deselected tree item | |||
} | |||
} | |||
/** | |||
* Return all testable classes within given package. Class is considered | |||
* testable if it's superclass is Application or CustomComponent. | |||
* | |||
* @param packageName | |||
* @return | |||
* @throws ClassNotFoundException | |||
*/ | |||
public static List getTestableClassesForPackage(String packageName) | |||
throws Exception { | |||
final ArrayList directories = new ArrayList(); | |||
try { | |||
final ClassLoader cld = Thread.currentThread() | |||
.getContextClassLoader(); | |||
if (cld == null) { | |||
throw new ClassNotFoundException("Can't get class loader."); | |||
} | |||
final String path = packageName.replace('.', '/'); | |||
// Ask for all resources for the path | |||
final Enumeration resources = cld.getResources(path); | |||
while (resources.hasMoreElements()) { | |||
final URL url = (URL) resources.nextElement(); | |||
directories.add(new File(url.getFile())); | |||
} | |||
} catch (final Exception x) { | |||
throw new Exception(packageName | |||
+ " does not appear to be a valid package."); | |||
} | |||
final ArrayList classes = new ArrayList(); | |||
// For every directory identified capture all the .class files | |||
for (final Iterator it = directories.iterator(); it.hasNext();) { | |||
final File directory = (File) it.next(); | |||
if (directory.exists()) { | |||
// Get the list of the files contained in the package | |||
final String[] files = directory.list(); | |||
for (int j = 0; j < files.length; j++) { | |||
// we are only interested in .class files | |||
if (files[j].endsWith(".class")) { | |||
// removes the .class extension | |||
final String p = packageName + '.' | |||
+ files[j].substring(0, files[j].length() - 6); | |||
final Class c = Class.forName(p); | |||
if (c.getSuperclass() != null) { | |||
if ((c.getSuperclass() | |||
.equals(com.itmill.toolkit.Application.class))) { | |||
classes.add(c); | |||
} else if ((c.getSuperclass() | |||
.equals(com.itmill.toolkit.ui.CustomComponent.class))) { | |||
classes.add(c); | |||
} | |||
} | |||
// for (int i = 0; i < c.getInterfaces().length; i++) { | |||
// Class cc = c.getInterfaces()[i]; | |||
// if (c.getInterfaces()[i].equals(Testable.class)) { | |||
// // Class is testable | |||
// classes.add(c); | |||
// } | |||
// } | |||
} | |||
} | |||
} else { | |||
throw new ClassNotFoundException(packageName + " (" | |||
+ directory.getPath() | |||
+ ") does not appear to be a valid package"); | |||
} | |||
} | |||
return classes; | |||
} | |||
Property.ValueChangeListener { | |||
// Add here packages which are used for finding testable classes | |||
String[] testablePackages = { "com.itmill.toolkit.tests", | |||
"com.itmill.toolkit.demo", "com.itmill.toolkit.demo.colorpicker", | |||
"com.itmill.toolkit.demo.reservation", | |||
"com.itmill.toolkit.demo.features", | |||
"com.itmill.toolkit.tests.tickets", "com.itmill.toolkit.tests.book" }; | |||
HierarchicalContainer testables = new HierarchicalContainer(); | |||
Window mainWindow = new Window("TestBench window"); | |||
// Main layout consists of tree menu and body layout | |||
SplitPanel mainLayout = new SplitPanel(SplitPanel.ORIENTATION_HORIZONTAL); | |||
Tree menu; | |||
Panel bodyLayout = new Panel(); | |||
HashMap itemCaptions = new HashMap(); | |||
@Override | |||
public void init() { | |||
// Add testable classes to hierarchical container | |||
for (int p = 0; p < testablePackages.length; p++) { | |||
testables.addItem(testablePackages[p]); | |||
try { | |||
final List testableClasses = getTestableClassesForPackage(testablePackages[p]); | |||
for (final Iterator it = testableClasses.iterator(); it | |||
.hasNext();) { | |||
final Class t = (Class) it.next(); | |||
// ignore TestBench itself | |||
if (t.equals(TestBench.class)) { | |||
continue; | |||
} | |||
try { | |||
testables.addItem(t); | |||
itemCaptions.put(t, t.getName()); | |||
testables.setParent(t, testablePackages[p]); | |||
testables.setChildrenAllowed(t, false); | |||
continue; | |||
} catch (final Exception e) { | |||
try { | |||
testables.addItem(t); | |||
itemCaptions.put(t, t.getName()); | |||
testables.setParent(t, testablePackages[p]); | |||
testables.setChildrenAllowed(t, false); | |||
continue; | |||
} catch (final Exception e1) { | |||
e1.printStackTrace(); | |||
} | |||
} | |||
} | |||
} catch (final Exception e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
menu = new Tree("Testables", testables); | |||
for (final Iterator i = itemCaptions.keySet().iterator(); i.hasNext();) { | |||
final Class testable = (Class) i.next(); | |||
// simplify captions | |||
final String name = testable.getName().substring( | |||
testable.getName().lastIndexOf('.') + 1); | |||
menu.setItemCaption(testable, name); | |||
} | |||
// expand all root items | |||
for (final Iterator i = menu.rootItemIds().iterator(); i.hasNext();) { | |||
menu.expandItemsRecursively(i.next()); | |||
} | |||
menu.addListener(this); | |||
menu.setImmediate(true); | |||
menu.setNullSelectionAllowed(false); | |||
VerticalLayout lo = new VerticalLayout(); | |||
lo.addComponent(menu); | |||
UriFragmentUtility uri = new UriFragmentUtility(); | |||
lo.addComponent(uri); | |||
uri.addListener(new UriFragmentUtility.FragmentChangedListener() { | |||
public void fragmentChanged(FragmentChangedEvent source) { | |||
String fragment = source.getUriFragmentUtility().getFragment(); | |||
if (fragment != null && !"".equals(fragment)) { | |||
// try to find a proper test class | |||
// exact match | |||
Iterator iterator = menu.getItemIds().iterator(); | |||
while (iterator.hasNext()) { | |||
Object next = iterator.next(); | |||
if (next instanceof Class) { | |||
Class c = (Class) next; | |||
String string = c.getName(); | |||
if (string.equals(fragment)) { | |||
menu.setValue(c); | |||
mainLayout.setSplitPosition(0); | |||
return; | |||
} | |||
} | |||
} | |||
// simple name match | |||
iterator = menu.getItemIds().iterator(); | |||
while (iterator.hasNext()) { | |||
Object next = iterator.next(); | |||
if (next instanceof Class) { | |||
Class c = (Class) next; | |||
String string = c.getSimpleName(); | |||
if (string.equals(fragment)) { | |||
menu.setValue(c); | |||
mainLayout.setSplitPosition(0); | |||
return; | |||
} | |||
} | |||
} | |||
// ticket match | |||
iterator = menu.getItemIds().iterator(); | |||
while (iterator.hasNext()) { | |||
Object next = iterator.next(); | |||
if (next instanceof Class) { | |||
Class c = (Class) next; | |||
String string = c.getSimpleName(); | |||
if (string.startsWith("Ticket" + fragment)) { | |||
menu.setValue(c); | |||
mainLayout.setSplitPosition(0); | |||
return; | |||
} | |||
} | |||
} | |||
// just partly mach lowercase | |||
iterator = menu.getItemIds().iterator(); | |||
while (iterator.hasNext()) { | |||
Object next = iterator.next(); | |||
if (next instanceof Class) { | |||
Class c = (Class) next; | |||
String string = c.getSimpleName(); | |||
if (string.toLowerCase().contains( | |||
fragment.toLowerCase())) { | |||
menu.setValue(c); | |||
mainLayout.setSplitPosition(0); | |||
return; | |||
} | |||
} | |||
} | |||
getMainWindow().showNotification( | |||
"No potential matc for #" + fragment); | |||
} | |||
} | |||
}); | |||
mainLayout.addComponent(lo); | |||
bodyLayout.addStyleName("light"); | |||
bodyLayout.setSizeFull(); | |||
bodyLayout.setLayout(new ExpandLayout()); | |||
mainLayout.addComponent(bodyLayout); | |||
mainLayout.setSplitPosition(30); | |||
mainWindow.setLayout(mainLayout); | |||
setMainWindow(mainWindow); | |||
} | |||
private Component createTestable(Class c) { | |||
try { | |||
final Application app = (Application) c.newInstance(); | |||
app.init(); | |||
Layout lo = app.getMainWindow().getLayout(); | |||
lo.setParent(null); | |||
return lo; | |||
} catch (final Exception e) { | |||
try { | |||
final CustomComponent cc = (CustomComponent) c.newInstance(); | |||
cc.setSizeFull(); | |||
return cc; | |||
} catch (final Exception e1) { | |||
e1.printStackTrace(); | |||
VerticalLayout lo = new VerticalLayout(); | |||
lo.addComponent(new Label( | |||
"Cannot create application / custom component: " | |||
+ e1.toString())); | |||
Link l = new Link("Try opening via app runner", | |||
new ExternalResource("../run/" + c.getName())); | |||
lo.addComponent(l); | |||
return lo; | |||
} | |||
} | |||
} | |||
// Handle menu selection and update body | |||
public void valueChange(Property.ValueChangeEvent event) { | |||
bodyLayout.removeAllComponents(); | |||
bodyLayout.setCaption(null); | |||
final Object o = menu.getValue(); | |||
if (o != null && o instanceof Class) { | |||
final Class c = (Class) o; | |||
final String title = c.getName(); | |||
bodyLayout.setCaption(title); | |||
bodyLayout.addComponent(createTestable(c)); | |||
} else { | |||
// NOP node selected or deselected tree item | |||
} | |||
} | |||
/** | |||
* Return all testable classes within given package. Class is considered | |||
* testable if it's superclass is Application or CustomComponent. | |||
* | |||
* @param packageName | |||
* @return | |||
* @throws ClassNotFoundException | |||
*/ | |||
public static List getTestableClassesForPackage(String packageName) | |||
throws Exception { | |||
final ArrayList directories = new ArrayList(); | |||
try { | |||
final ClassLoader cld = Thread.currentThread() | |||
.getContextClassLoader(); | |||
if (cld == null) { | |||
throw new ClassNotFoundException("Can't get class loader."); | |||
} | |||
final String path = packageName.replace('.', '/'); | |||
// Ask for all resources for the path | |||
final Enumeration resources = cld.getResources(path); | |||
while (resources.hasMoreElements()) { | |||
final URL url = (URL) resources.nextElement(); | |||
directories.add(new File(url.getFile())); | |||
} | |||
} catch (final Exception x) { | |||
throw new Exception(packageName | |||
+ " does not appear to be a valid package."); | |||
} | |||
final ArrayList classes = new ArrayList(); | |||
// For every directory identified capture all the .class files | |||
for (final Iterator it = directories.iterator(); it.hasNext();) { | |||
final File directory = (File) it.next(); | |||
if (directory.exists()) { | |||
// Get the list of the files contained in the package | |||
final String[] files = directory.list(); | |||
for (int j = 0; j < files.length; j++) { | |||
// we are only interested in .class files | |||
if (files[j].endsWith(".class")) { | |||
// removes the .class extension | |||
final String p = packageName + '.' | |||
+ files[j].substring(0, files[j].length() - 6); | |||
final Class c = Class.forName(p); | |||
if (c.getSuperclass() != null) { | |||
if ((c.getSuperclass() | |||
.equals(com.itmill.toolkit.Application.class))) { | |||
classes.add(c); | |||
} else if ((c.getSuperclass() | |||
.equals(com.itmill.toolkit.ui.CustomComponent.class))) { | |||
classes.add(c); | |||
} | |||
} | |||
// for (int i = 0; i < c.getInterfaces().length; i++) { | |||
// Class cc = c.getInterfaces()[i]; | |||
// if (c.getInterfaces()[i].equals(Testable.class)) { | |||
// // Class is testable | |||
// classes.add(c); | |||
// } | |||
// } | |||
} | |||
} | |||
} else { | |||
throw new ClassNotFoundException(packageName + " (" | |||
+ directory.getPath() | |||
+ ") does not appear to be a valid package"); | |||
} | |||
} | |||
return classes; | |||
} | |||
} |
@@ -10,94 +10,85 @@ import com.itmill.toolkit.event.Action.Handler; | |||
import com.itmill.toolkit.ui.Button; | |||
import com.itmill.toolkit.ui.CustomComponent; | |||
import com.itmill.toolkit.ui.FormLayout; | |||
import com.itmill.toolkit.ui.HorizontalLayout; | |||
import com.itmill.toolkit.ui.Label; | |||
import com.itmill.toolkit.ui.OrderedLayout; | |||
import com.itmill.toolkit.ui.Panel; | |||
import com.itmill.toolkit.ui.TextField; | |||
import com.itmill.toolkit.ui.Window; | |||
public class DefaultButtonExample extends CustomComponent implements Handler { | |||
// Define and create user interface components | |||
Panel panel = new Panel("Login"); | |||
OrderedLayout formlayout = new FormLayout(); | |||
TextField username = new TextField("Username"); | |||
TextField password = new TextField("Password"); | |||
OrderedLayout buttons = new FormLayout(); | |||
// Define and create user interface components | |||
Panel panel = new Panel("Login"); | |||
FormLayout formlayout = new FormLayout(); | |||
TextField username = new TextField("Username"); | |||
TextField password = new TextField("Password"); | |||
HorizontalLayout buttons = new HorizontalLayout(); | |||
// Create buttons and define their listener methods. Here we use | |||
// parameterless | |||
// methods so that we can use same methods for both click events and | |||
// keyboard actions. | |||
Button ok = new Button("OK", this, "okHandler"); | |||
Button cancel = new Button("Cancel", this, "cancelHandler"); | |||
// Create buttons and define their listener methods. | |||
Button ok = new Button("OK", this, "okHandler"); | |||
Button cancel = new Button("Cancel", this, "cancelHandler"); | |||
// Have the unmodified Enter key cause an event | |||
Action action_ok = new ShortcutAction("Default key", | |||
ShortcutAction.KeyCode.ENTER, null); | |||
// Have the unmodified Enter key cause an event | |||
Action action_ok = new ShortcutAction("Default key", | |||
ShortcutAction.KeyCode.ENTER, null); | |||
// Have the C key modified with Alt cause an event | |||
Action action_cancel = new ShortcutAction("Alt+C", | |||
ShortcutAction.KeyCode.C, | |||
new int[] { ShortcutAction.ModifierKey.ALT }); | |||
// Have the C key modified with Alt cause an event | |||
Action action_cancel = new ShortcutAction("Alt+C", | |||
ShortcutAction.KeyCode.C, | |||
new int[] { ShortcutAction.ModifierKey.ALT }); | |||
Window window = null; | |||
public DefaultButtonExample() { | |||
// Set up the user interface | |||
setCompositionRoot(panel); | |||
panel.addComponent(formlayout); | |||
formlayout.addComponent(username); | |||
formlayout.addComponent(password); | |||
formlayout.addComponent(buttons); | |||
buttons.addComponent(ok); | |||
buttons.addComponent(cancel); | |||
public DefaultButtonExample(Window win) { | |||
// Set up the user interface | |||
setCompositionRoot(panel); | |||
panel.addComponent(formlayout); | |||
formlayout.setOrientation(OrderedLayout.ORIENTATION_VERTICAL); | |||
formlayout.addComponent(username); | |||
formlayout.addComponent(password); | |||
formlayout.addComponent(buttons); | |||
buttons.setOrientation(OrderedLayout.ORIENTATION_HORIZONTAL); | |||
buttons.addComponent(ok); | |||
buttons.addComponent(cancel); | |||
// Set focus to username | |||
username.focus(); | |||
// Set focus to username | |||
username.focus(); | |||
// Set this object as the action handler | |||
System.out.println("adding ah"); | |||
panel.addActionHandler(this); | |||
// Set this object as the action handler | |||
System.out.println("adding ah"); | |||
win.addActionHandler(this); | |||
window = win; | |||
System.out.println("start done."); | |||
} | |||
System.out.println("start done."); | |||
} | |||
/** | |||
* Retrieve actions for a specific component. This method will be called for | |||
* each object that has a handler; in this example just for login panel. The | |||
* returned action list might as well be static list. | |||
*/ | |||
public Action[] getActions(Object target, Object sender) { | |||
System.out.println("getActions()"); | |||
return new Action[] { action_ok, action_cancel }; | |||
} | |||
/** | |||
* Retrieve actions for a specific component. This method will be called for | |||
* each object that has a handler; in this example the Ok and Cancel | |||
* buttons. | |||
*/ | |||
public Action[] getActions(Object target, Object sender) { | |||
System.out.println("getActions()"); | |||
return new Action[] { action_ok, action_cancel }; | |||
} | |||
/** | |||
* Handle actions received from keyboard. This simply directs the actions to | |||
* the same listener methods that are called with ButtonClick events. | |||
*/ | |||
public void handleAction(Action action, Object sender, Object target) { | |||
if (action == action_ok) { | |||
okHandler(); | |||
} | |||
if (action == action_cancel) { | |||
cancelHandler(); | |||
} | |||
} | |||
/** | |||
* Handle actions received from keyboard. This simply directs the actions to | |||
* the same listener methods that are called with ButtonClick events. | |||
*/ | |||
public void handleAction(Action action, Object sender, Object target) { | |||
if (action == action_ok) { | |||
okHandler(); | |||
} | |||
if (action == action_cancel) { | |||
cancelHandler(); | |||
} | |||
} | |||
public void okHandler() { | |||
// Do something: report the click | |||
formlayout.addComponent(new Label("OK clicked. " + "User=" | |||
+ username.getValue() + ", password=" + password.getValue())); | |||
// | |||
} | |||
public void okHandler() { | |||
// Do something: report the click | |||
formlayout.addComponent(new Label("OK clicked. " + "User=" | |||
+ username.getValue() + ", password=" + password.getValue())); | |||
// | |||
} | |||
public void cancelHandler() { | |||
// Do something: report the click | |||
formlayout.addComponent(new Label("Cancel clicked. User=" | |||
+ username.getValue() + ", password=" + password.getValue())); | |||
} | |||
public void cancelHandler() { | |||
// Do something: report the click | |||
formlayout.addComponent(new Label("Cancel clicked. User=" | |||
+ username.getValue() + ", password=" + password.getValue())); | |||
} | |||
} |
@@ -133,7 +133,7 @@ public class ProgressIndicator extends AbstractField implements Property, | |||
@Override | |||
public Object getValue() { | |||
if (dataSource == null) { | |||
throw new IllegalStateException("Datasource must be se"); | |||
throw new IllegalStateException("Datasource must be set"); | |||
} | |||
return dataSource.getValue(); | |||
} | |||
@@ -149,7 +149,7 @@ public class ProgressIndicator extends AbstractField implements Property, | |||
@Override | |||
public void setValue(Object newValue) { | |||
if (dataSource == null) { | |||
throw new IllegalStateException("Datasource must be se"); | |||
throw new IllegalStateException("Datasource must be set"); | |||
} | |||
dataSource.setValue(newValue); | |||
} | |||
@@ -160,7 +160,7 @@ public class ProgressIndicator extends AbstractField implements Property, | |||
@Override | |||
public String toString() { | |||
if (dataSource == null) { | |||
throw new IllegalStateException("Datasource must be se"); | |||
throw new IllegalStateException("Datasource must be set"); | |||
} | |||
return dataSource.toString(); | |||
} | |||
@@ -171,7 +171,7 @@ public class ProgressIndicator extends AbstractField implements Property, | |||
@Override | |||
public Class getType() { | |||
if (dataSource == null) { | |||
throw new IllegalStateException("Datasource must be se"); | |||
throw new IllegalStateException("Datasource must be set"); | |||
} | |||
return dataSource.getType(); | |||
} |
@@ -10,7 +10,9 @@ import com.itmill.toolkit.terminal.PaintException; | |||
import com.itmill.toolkit.terminal.PaintTarget; | |||
/** | |||
* TODO comment | |||
* A component for selecting a numerical value within a range. A Slider | |||
* can have the appearance of a scroll bar or e.g. look like an Adobe Photoshop | |||
* style of a slider. | |||
* | |||
* Example code: <code> | |||
* class MyPlayer extends CustomComponent implements ValueChangeListener { | |||
@@ -42,6 +44,7 @@ import com.itmill.toolkit.terminal.PaintTarget; | |||
* | |||
* </code> | |||
* | |||
* @author IT Mill Ltd. | |||
*/ | |||
public class Slider extends AbstractField { | |||