diff --git a/zxing.appspot.com/app.yaml b/zxing.appspot.com/app.yaml new file mode 100644 index 000000000..9f125b59e --- /dev/null +++ b/zxing.appspot.com/app.yaml @@ -0,0 +1,16 @@ +application: zxing +version: 1 +runtime: python +api_version: 1 + +handlers: +- url: /generator + script: redirect.py + +- url: (.*)/ + static_files: static\1/index.html + upload: static/index.html + +- url: / + static_dir: static + diff --git a/zxing.appspot.com/generator/.classpath b/zxing.appspot.com/generator/.classpath new file mode 100644 index 000000000..018b040e0 --- /dev/null +++ b/zxing.appspot.com/generator/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/zxing.appspot.com/generator/.project b/zxing.appspot.com/generator/.project new file mode 100644 index 000000000..9eada68e6 --- /dev/null +++ b/zxing.appspot.com/generator/.project @@ -0,0 +1,27 @@ + + + BarcodeGenerator + BarcodeGenerator project + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.jdt.core.javanature + + + + gwt-user.jar + 1 + GWT_HOME/gwt-user.jar + + + gwt.jar + 1 + GWT_JAR + + + diff --git a/zxing.appspot.com/generator/Generator.launch b/zxing.appspot.com/generator/Generator.launch new file mode 100644 index 000000000..8e6da460c --- /dev/null +++ b/zxing.appspot.com/generator/Generator.launch @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/zxing.appspot.com/generator/README b/zxing.appspot.com/generator/README new file mode 100644 index 000000000..cb9891bcb --- /dev/null +++ b/zxing.appspot.com/generator/README @@ -0,0 +1,11 @@ + + +To develop with Eclipse. + +Before importing the project, you need to define some variables. +- In Eclipse Preferences, go to General->Workspace->Linked Resources. +- Click New and add the 2 following variables: + - GWT_HOME that point to the directory containing gwt-user.jar + - GWT_JAR that point to the gwt-dev-XXX.jar file directly. (XXX will be linux, mac, etc) +- then you can import the project by File->Import...->Existing project into workspace. + diff --git a/zxing.appspot.com/generator/libs/gwt-incubator.jar b/zxing.appspot.com/generator/libs/gwt-incubator.jar new file mode 100644 index 000000000..4a9d73d71 Binary files /dev/null and b/zxing.appspot.com/generator/libs/gwt-incubator.jar differ diff --git a/zxing.appspot.com/generator/src/com/google/zxing/web/generator/Generator.gwt.xml b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/Generator.gwt.xml new file mode 100644 index 000000000..6508ee889 --- /dev/null +++ b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/Generator.gwt.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/CalendarEventGenerator.java b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/CalendarEventGenerator.java new file mode 100644 index 000000000..ddd3b3b97 --- /dev/null +++ b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/CalendarEventGenerator.java @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.web.generator.client; + +import com.google.gwt.i18n.client.DateTimeFormat; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.ui.ChangeListener; +import com.google.gwt.user.client.ui.CheckBox; +import com.google.gwt.user.client.ui.ClickListener; +import com.google.gwt.user.client.ui.Grid; +import com.google.gwt.user.client.ui.ListBox; +import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.Widget; +import com.google.gwt.widgetideas.client.event.ChangeEvent; +import com.google.gwt.widgetideas.client.event.ChangeHandler; +import com.google.gwt.widgetideas.datepicker.client.DateBox; +import com.google.gwt.widgetideas.datepicker.client.TimePicker; +import com.google.zxing.web.generator.client.TimeZoneList.TimeZoneInfo; + +import java.util.Date; + +/** + * A Generator for calendar events. Output is in VCal format. + * + * @author Yohann Coppel + */ +public class CalendarEventGenerator implements GeneratorSource { + public final static String[] FULL_DAY_ONLY_IDS = { "fullDayOnlyInfo1", + "fullDayOnlyInfo2", "fullDayOnlyInfo3", "fullDayOnlyInfo4" }; + private final static long ONE_HOUR = 60 * 60 * 1000; + + Grid table = null; + TextBox eventName = new TextBox(); + CheckBox fullDay = new CheckBox(); + DateBox datePicker1 = new DateBox(); + DateBox datePicker2 = new DateBox(); + TimePicker timePicker1 = new TimePicker(new Date(), DateTimeFormat + .getFormat("a"), DateTimeFormat.getFormat("hh"), DateTimeFormat + .getFormat("mm"), null); + TimePicker timePicker2 = new TimePicker(new Date(), DateTimeFormat + .getFormat("a"), DateTimeFormat.getFormat("hh"), DateTimeFormat + .getFormat("mm"), null); + CheckBox summerTime = new CheckBox(); + ListBox timeZones = new ListBox(); + Date timePicker1PreviousDate = null; + + public CalendarEventGenerator(final ChangeListener listener) { + eventName.addStyleName(StylesDefs.INPUT_FIELD_REQUIRED); + eventName.addChangeListener(listener); + datePicker1.setAnimationEnabled(true); + datePicker2.setAnimationEnabled(true); + timePicker2 + .setDateTime(addMilliseconds(timePicker1.getDateTime(), ONE_HOUR)); + timePicker1PreviousDate = timePicker1.getDateTime(); + + buildTimeZoneList(); + timeZones.setSelectedIndex(25); + timePicker1.addChangeHandler(new ChangeHandler() { + public void onChange(ChangeEvent event) { + Date time = timePicker1PreviousDate; + Date time1 = timePicker1.getDateTime(); + Date time2 = timePicker2.getDateTime(); + if (time2.after(time)) { + // keep the same time difference if the interval is valid. + long diff = timeDifference(time, time2); + timePicker2.setDateTime(addMilliseconds(time1, diff)); + } else { + // otherwise erase the end date and set it to startdate + one hour. + timePicker2.setDateTime(addMilliseconds(time, ONE_HOUR)); + } + // no need to call onChange for timePicker1, since it will be called + // for timePicker2 when changes are made. + // listener.onChange(timePicker1); + timePicker1PreviousDate = time1; + } + }); + timePicker2.addChangeHandler(new ChangeHandler() { + public void onChange(ChangeEvent event) { + listener.onChange(timePicker2); + } + }); + } + + private void buildTimeZoneList() { + for (TimeZoneInfo info : TimeZoneList.TIMEZONES) { + timeZones.addItem(info.GMTRelative + " " + info.abreviation, "" + + info.gmtDiff); + } + } + + public String getName() { + return "Calendar event"; + } + + public Grid getWidget() { + if (table != null) { + return table; + } + datePicker1.getDatePicker().setSelectedDate(new Date()); + datePicker2.getDatePicker().setSelectedDate(new Date()); + table = new Grid(8, 2); + + table.setText(0, 0, "All day event"); + table.setWidget(0, 1, fullDay); + + table.setText(1, 0, "Event title"); + table.setWidget(1, 1, eventName); + + table.setText(2, 0, "Start date"); + table.setWidget(2, 1, datePicker1); + + table.setText(3, 0, "Time"); + table.setWidget(3, 1, timePicker1); + + table.setText(4, 0, "End date"); + table.setWidget(4, 1, datePicker2); + + table.setText(5, 0, "Time"); + table.setWidget(5, 1, timePicker2); + + table.setText(6, 0, "Time zone"); + table.setWidget(6, 1, timeZones); + + table.setText(7, 0, "Daylight savings"); + table.setWidget(7, 1, summerTime); + + table.getRowFormatter().getElement(3).setId(FULL_DAY_ONLY_IDS[0]); + table.getRowFormatter().getElement(5).setId(FULL_DAY_ONLY_IDS[1]); + table.getRowFormatter().getElement(6).setId(FULL_DAY_ONLY_IDS[2]); + table.getRowFormatter().getElement(7).setId(FULL_DAY_ONLY_IDS[3]); + + fullDay.addClickListener(new ClickListener() { + public void onClick(Widget sender) { + CheckBox cb = (CheckBox) sender; + setFullDay(cb.isChecked()); + } + }); + + return table; + } + + private void setFullDay(boolean fullDay) { + for (String s : FULL_DAY_ONLY_IDS) { + Element element = DOM.getElementById(s); + String style = ""; + if (fullDay) { + style = "none"; + } + DOM.setStyleAttribute(element, "display", style); + } + } + + public String getText() throws GeneratorException { + String eventName = getEventNameField(); + String dates = getDateTimeFields(); + + String output = ""; + output += "BEGIN:VEVENT\n"; + output += eventName; + output += dates; + output += "END:VEVENT\n"; + return output; + } + + private String getEventNameField() throws GeneratorException { + String inputName = eventName.getText(); + if (inputName.length() < 1) { + throw new GeneratorException("Event name must be at least 1 character."); + } + if (inputName.contains("\n")) { + throw new GeneratorException( + "Event name should not contain \\n characters."); + } + return "SUMMARY:" + inputName + "\n"; + } + + private String getDateTimeFields() throws GeneratorException { + if (fullDay.isChecked()) { + return getFullDayDateFields(); + } + return getDateTimeValues(); + } + + private String getFullDayDateFields() throws GeneratorException { + Date date1 = datePicker1.getDatePicker().getSelectedDate(); + Date date2 = datePicker2.getDatePicker().getSelectedDate(); + if (null == date1 || null == date2) { + throw new GeneratorException("Start and end dates must be set."); + } + if (date1.after(date2)) { + throw new GeneratorException("Ending date is after starting date."); + } + DateTimeFormat isoFormatter = DateTimeFormat.getFormat("yyyyMMdd"); + String output = ""; + output += "DTSTART:" + isoFormatter.format(date1) + "\n"; + output += "DTEND:" + isoFormatter.format(date2) + "\n"; + return output; + } + + private String getDateTimeValues() throws GeneratorException { + Date date1 = datePicker1.getDatePicker().getSelectedDate(); + Date date2 = datePicker2.getDatePicker().getSelectedDate(); + Date time1 = timePicker1.getDateTime(); + Date time2 = timePicker2.getDateTime(); + if (null == date1 || null == date2 || null == time1 || null == time2) { + throw new GeneratorException("Start and end dates/times must be set."); + } + String timezoneDelta = timeZones.getValue(timeZones.getSelectedIndex()); + long diffTimeZone = Long.parseLong(timezoneDelta); + if (summerTime.isChecked()) { + diffTimeZone += ONE_HOUR; + } + Date dateTime1 = addMilliseconds(mergeDateAndTime(date1, time1), + -diffTimeZone); + Date dateTime2 = addMilliseconds(mergeDateAndTime(date2, time2), + -diffTimeZone); + if (dateTime1.after(dateTime2)) { + throw new GeneratorException("Ending date is after starting date."); + } + DateTimeFormat isoFormatter = DateTimeFormat + .getFormat("yyyyMMdd'T'kkmmss'Z'"); + String output = ""; + output += "DTSTART:" + isoFormatter.format(dateTime1) + "\n"; + output += "DTEND:" + isoFormatter.format(dateTime2) + "\n"; + return output; + } + + private Date mergeDateAndTime(Date date, Date time) { + // Is that the only ugly way to do with GWT ? given that we don't + // have java.util.Calendar for instance + DateTimeFormat extractDate = DateTimeFormat.getFormat("yyyyMMdd"); + DateTimeFormat extractTime = DateTimeFormat.getFormat("kkmm"); + DateTimeFormat merger = DateTimeFormat.getFormat("yyyyMMddkkmmss"); + String d = extractDate.format(date); + String t = extractTime.format(time) + "00"; + return merger.parse(d + t); + } + + public void validate(Widget widget) throws GeneratorException { + if (widget == eventName) + getEventNameField(); + if (widget == datePicker1 || widget == timePicker1 || widget == datePicker2 + || widget == timePicker2) + getDateTimeFields(); + } + + private static Date addMilliseconds(Date time1, long milliseconds) { + return new Date(time1.getTime() + milliseconds); + } + + private static long timeDifference(Date time1, Date time2) { + return time2.getTime() - time1.getTime(); + } + + public void setFocus() { + eventName.setFocus(true); + } +} diff --git a/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/ContactInfoGenerator.java b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/ContactInfoGenerator.java new file mode 100644 index 000000000..fd4029bdb --- /dev/null +++ b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/ContactInfoGenerator.java @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.web.generator.client; + +import com.google.gwt.user.client.ui.ChangeListener; +import com.google.gwt.user.client.ui.Grid; +import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.Widget; + +/** + * A Generator for contact informations, output is in MeCard format. + * + * @author Yohann Coppel + */ +public class ContactInfoGenerator implements GeneratorSource { + Grid table = null; + TextBox name = new TextBox(); + TextBox company = new TextBox(); + TextBox tel = new TextBox(); + TextBox url = new TextBox(); + TextBox email = new TextBox(); + TextBox address = new TextBox(); + TextBox memo = new TextBox(); + TextBox[] widgets = {name, company, tel, url, email, address, memo}; + + public ContactInfoGenerator(ChangeListener changeListener) { + for (TextBox w: widgets) { + w.addChangeListener(changeListener); + } + } + + public String getName() { + return "Contact information"; + } + + public String getText() throws GeneratorException { + String name = getNameField(); + String company = getCompanyField(); + String tel = getTelField(); + String url = getUrlField(); + String email = getEmailField(); + String address = getAddressField(); + String memo = getMemoField(); + + // Build the output with obtained data. + // note that some informations may just be "" if they were not specified. + //return getVCard(name, company, tel, url, email, address, memo); + return getMeCard(name, company, tel, url, email, address, memo); + } + + private String getMeCard(String name, String company, String tel, String url, + String email, String address, String memo) { + String output = "MECARD:"; + output += "N:" + name + ";"; + output += company.length() > 0 ? "ORG:" + company + ";" : ""; + output += tel.length() > 0 ? "TEL:" + tel + ";" : ""; + output += url.length() > 0 ? "URL:" + url + ";" : ""; + output += email.length() > 0 ? "EMAIL:" + email + ";" : ""; + output += address.length() > 0 ? "ADR:" + address + ";" : ""; + output += memo.length() > 0 ? "NOTE:" + memo + ";" : ""; + output += ";"; + return output; + } + + /*// VCARD GENERATION. Keep this in case we want to go back to vcard format + // or have the option. + private String getVCard(String name, String company, String tel, String url, + String email, String address, String memo) { + String output = "BEGIN:VCARD\n"; + output += "N:" + name + "\n"; + output += company.length() > 0 ? "ORG:" + company + "\n" : ""; + output += tel.length() > 0 ? "TEL:" + tel + "\n" : ""; + output += url.length() > 0 ? "URL:" + url + "\n" : ""; + output += email.length() > 0 ? "EMAIL:" + email + "\n" : ""; + output += address.length() > 0 ? "ADR:" + address + "\n" : ""; + output += memo.length() > 0 ? "NOTE:" + memo + "\n" : ""; + output += "END:VCARD"; + + return output; + } + */ + + private String getNameField() throws GeneratorException { + String inputName = name.getText(); + if (inputName.length() < 1) { + throw new GeneratorException("Name must be at least 1 character."); + } + if (inputName.contains("\n")) { + throw new GeneratorException("Name should not contanains \\n characters."); + } + if (inputName.contains(";")) { + throw new GeneratorException("Name must not contains ; characters"); + } + return inputName; + } + + private String getCompanyField() throws GeneratorException { + String input = company.getText(); + if (input.length() < 1) { + return ""; + } + if (input.contains("\n")) { + throw new GeneratorException("Company should not contanains \\n characters."); + } + if (input.contains(";")) { + throw new GeneratorException("Company must not contains ; characters"); + } + // the input contains some informations. + return input; + } + + private String getTelField() throws GeneratorException { + String input = Validators.filterNumber(tel.getText()); + if (input.length() < 1) { + return ""; + } + Validators.validateNumber(input); + if (input.contains(";")) { + throw new GeneratorException("Tel must not contains ; characters"); + } + return input; + } + + private String getUrlField() throws GeneratorException { + String input = url.getText(); + if (input.length() < 1) { + return ""; + } + Validators.validateUrl(input); + if (input.contains(";")) { + throw new GeneratorException("URL must not contains ; characters"); + } + return input; + } + + private String getEmailField() throws GeneratorException { + String input = email.getText(); + if (input.length() < 1) { + return ""; + } + Validators.validateEmail(input); + if (input.contains(";")) { + throw new GeneratorException("Email must not contains ; characters"); + } + return input; + } + + private String getAddressField() throws GeneratorException { + String input = address.getText(); + if (input.length() < 1) { + return ""; + } + if (input.contains("\n")) { + throw new GeneratorException("Address must not contain \\n characters."); + } + if (input.contains(";")) { + throw new GeneratorException("Address must not contains ; characters"); + } + return input; + } + + private String getMemoField() throws GeneratorException { + String input = memo.getText(); + if (input.length() < 1) { + return ""; + } + if (input.contains("\n")) { + throw new GeneratorException("Memo must not contain \\n characters."); + } + if (input.contains(";")) { + throw new GeneratorException("Memo must not contains ; characters"); + } + return input; + } + + public Grid getWidget() { + if (table != null) { + // early termination if the table has already been constructed + return table; + } + table = new Grid(7, 2); + + table.setText(0, 0, "Name"); + table.setWidget(0, 1, name); + table.setText(1, 0, "Company"); + table.setWidget(1, 1, company); + table.setText(2, 0, "Phone number"); + table.setWidget(2, 1, tel); + table.setText(3, 0, "Email"); + table.setWidget(3, 1, email); + table.setText(4, 0, "Address"); + table.setWidget(4, 1, address); + table.setText(5, 0, "Website"); + table.setWidget(5, 1, url); + table.setText(6, 0, "Memo"); + table.setWidget(6, 1, memo); + + name.addStyleName(StylesDefs.INPUT_FIELD_REQUIRED); + return table; + } + + public void validate(Widget widget) throws GeneratorException { + if (widget == name) getNameField(); + if (widget == company) getCompanyField(); + if (widget == tel) getTelField(); + if (widget == email) getEmailField(); + if (widget == address) getAddressField(); + if (widget == url) getUrlField(); + if (widget == memo) getMemoField(); + } + + public void setFocus() { + name.setFocus(true); + } +} diff --git a/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/EmailGenerator.java b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/EmailGenerator.java new file mode 100644 index 000000000..cf160d3dd --- /dev/null +++ b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/EmailGenerator.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.web.generator.client; + +import com.google.gwt.user.client.ui.ChangeListener; +import com.google.gwt.user.client.ui.Grid; +import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.Widget; + +/** + * Generator for email address. + * + * @author Yohann Coppel + */ +public class EmailGenerator implements GeneratorSource { + Grid table = null; + TextBox email = new TextBox(); + + public EmailGenerator(ChangeListener listener) { + email.addStyleName(StylesDefs.INPUT_FIELD_REQUIRED); + email.addChangeListener(listener); + } + + public String getName() { + return "Email address"; + } + + public String getText() throws GeneratorException { + String email = getEmailField(); + return "mailto:"+email; + } + + private String getEmailField() throws GeneratorException { + String input = email.getText(); + if (input.length() < 1) { + throw new GeneratorException("Email must be present."); + } + Validators.validateEmail(input); + return input; + } + + public Grid getWidget() { + if (table != null) { + return table; + } + table = new Grid(1, 2); + + table.setText(0, 0, "Address"); + table.setWidget(0, 1, email); + + return table; + } + + public void validate(Widget widget) throws GeneratorException { + if (widget == email) getEmailField(); + } + + public void setFocus() { + email.setFocus(true); + } +} diff --git a/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/Generator.java b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/Generator.java new file mode 100644 index 000000000..94b066263 --- /dev/null +++ b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/Generator.java @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.web.generator.client; + +import com.google.gwt.core.client.EntryPoint; +import com.google.gwt.dom.client.Element; +import com.google.gwt.http.client.URL; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.ChangeListener; +import com.google.gwt.user.client.ui.ClickListener; +import com.google.gwt.user.client.ui.Grid; +import com.google.gwt.user.client.ui.HTML; +import com.google.gwt.user.client.ui.HorizontalPanel; +import com.google.gwt.user.client.ui.Image; +import com.google.gwt.user.client.ui.ListBox; +import com.google.gwt.user.client.ui.RootPanel; +import com.google.gwt.user.client.ui.SimplePanel; +import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.VerticalPanel; +import com.google.gwt.user.client.ui.Widget; +import com.google.gwt.user.client.ui.HTMLTable.CellFormatter; + +import java.util.ArrayList; +import java.util.List; + +/** + * Entry point classes define onModuleLoad(). Setup the page, and loads + * all different generators. + * + * @author Yohann Coppel + */ +public class Generator implements EntryPoint { +// public static final StringConstants S = GWT.create(StringConstants.class); + private final List generators = new ArrayList(); + ListBox genList = new ListBox(); + ListBox sizeList = new ListBox(); + Image result = new Image("");//http://chart.apis.google.com/chart?cht=qr&chs=300x300&chl=http://google.com"); + Grid topPanel = new Grid(5, 1); + GeneratorSource selectedGenerator = null; + private Button generateButton; + VerticalPanel rightPanel = new VerticalPanel(); + TextBox urlResult = new TextBox(); + HTML downloadText = new HTML("Download or embed with this URL:"); + //Element errorElement = null; + + public void onModuleLoad() { + loadGenerators(); + + HorizontalPanel mainPanel = new HorizontalPanel(); + setupLeftPanel(); + topPanel.getElement().setId("leftpanel"); + Widget leftPanel = topPanel; + + mainPanel.add(leftPanel); + + SimplePanel div = new SimplePanel(); + SimplePanel div2 = new SimplePanel(); + div2.add(result); + div2.getElement().setId("innerresult"); + div.add(div2); + div.getElement().setId("imageresult"); + + urlResult.getElement().setId("urlresult"); + downloadText.getElement().setId("downloadText"); + rightPanel.add(div); + rightPanel.add(downloadText); + rightPanel.add(urlResult); + mainPanel.add(rightPanel); + mainPanel.getElement().setId("mainpanel"); + RootPanel.get("ui").add(mainPanel); + //RootPanel.get().add(output); + //output.setHeight("200px"); + //output.setWidth("500px"); + setWidget(1); + invalidateBarcode(); + } + + private void setWidget(int id) { + if (id >= 0 && id < generators.size()) { + topPanel.setWidget(1, 0, generators.get(id).getWidget()); + genList.setSelectedIndex(id); + selectedGenerator = generators.get(id); + eraseErrorMessage(); + invalidateBarcode(); + genList.setFocus(false); + selectedGenerator.setFocus(); + } + } + + private void loadGenerators() { + generators.add(new CalendarEventGenerator(changeListener)); + generators.add(new ContactInfoGenerator(changeListener)); + generators.add(new EmailGenerator(changeListener)); + generators.add(new GeoLocationGenerator(changeListener)); + generators.add(new PhoneNumberGenerator(changeListener)); + generators.add(new SmsAddressGenerator(changeListener)); + generators.add(new TextGenerator(changeListener)); + generators.add(new UrlGenerator(changeListener)); + } + + public void setupLeftPanel() { + topPanel.setHTML(2, 0, + ""); + + // fills up the list of generators + for(GeneratorSource generator: generators) { + genList.addItem(generator.getName()); + setGridStyle(generator.getWidget()); + } + + sizeList.addItem("S", "120"); + sizeList.addItem("M", "230"); + sizeList.addItem("L", "350"); + sizeList.setSelectedIndex(2); + + // updates the second row of the table with the content of the selected + // generator + genList.addChangeListener(new ChangeListener() { + public void onChange(Widget sender) { + int i = genList.getSelectedIndex(); + setWidget(i); + } + }); + + // grid for the generator picker + Grid selectionTable = new Grid(1, 2); + selectionTable.setText(0, 0, "Contents"); + selectionTable.setWidget(0, 1, genList); + setGridStyle(selectionTable); + + topPanel.setWidget(0, 0, selectionTable); + + // grid for the generate button + Grid generateGrid = new Grid(1, 2); + setGridStyle(generateGrid); + + generateButton = new Button("Generate →"); + generateButton.addClickListener(new ClickListener() { + public void onClick(Widget sender) { + generate(); + } + }); + generateGrid.setWidget(0,1,generateButton); + topPanel.setWidget(4, 0, generateGrid); + + Grid sizeTable = new Grid(1, 2); + sizeTable.setText(0, 0, "Barcode size"); + sizeTable.setWidget(0, 1, sizeList); + setGridStyle(sizeTable); + topPanel.setWidget(3, 0, sizeTable); + } + + protected void setGridStyle(Grid grid) { + grid.getColumnFormatter().addStyleName(0, "firstColumn"); + grid.getColumnFormatter().addStyleName(1, "secondColumn"); + CellFormatter cellFormatter = grid.getCellFormatter(); + for(int i = 0; i < grid.getRowCount(); ++i) { + cellFormatter.addStyleName(i, 0, "firstColumn"); + cellFormatter.addStyleName(i, 1, "secondColumn"); + } + } + + protected String getUrl(int sizeX, int sizeY, String content) { + String result = "http://chart.apis.google.com/chart?cht=qr&chs="; + result += sizeX; + result += "x"; + result += sizeY; + result += "&chl="; + result += URL.encode(content); + return result; + } + + private void generate() { + try { + String text = selectedGenerator.getText(); + eraseErrorMessage(); + int size = Integer.parseInt(sizeList + .getValue(sizeList.getSelectedIndex())); + String url = getUrl(size, size, text); + result.setUrl(url); + result.setVisible(true); + urlResult.setText(url); + urlResult.setVisible(true); + Element linkElement = DOM.getElementById("downloadlink"); + linkElement.setAttribute("href", url); + downloadText.setVisible(true); + } catch (GeneratorException ex) { + invalidateBarcode(); + String error = ex.getMessage(); + showErrorMessage(error); + } + } + + public void invalidateBarcode() { + result.setVisible(false); + urlResult.setText(""); + urlResult.setVisible(false); + Element linkElement = DOM.getElementById("downloadlink"); + linkElement.setAttribute("href", ""); + downloadText.setVisible(false); + } + + public void showErrorMessage(String error) { + Element errorElement = DOM.getElementById("errorMessageID"); + errorElement.setInnerHTML(error); + } + + public void eraseErrorMessage() { + Element errorElement = DOM.getElementById("errorMessageID"); + errorElement.setInnerHTML(" "); + } + + public ChangeListener changeListener = new ChangeListener() { + public void onChange(Widget sender) { + try { + selectedGenerator.validate(sender); + eraseErrorMessage(); + } catch (GeneratorException ex) { + String error = ex.getMessage(); + showErrorMessage(error); + invalidateBarcode(); + } + } + }; + +} diff --git a/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/GeneratorException.java b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/GeneratorException.java new file mode 100644 index 000000000..d6f127f80 --- /dev/null +++ b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/GeneratorException.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.web.generator.client; + +/** + * An exception that can be raised by a generator when the input data contains + * errors. The getMessage() method should be used to get the error message to + * display to the user. + * + * @author Yohann Coppel + */ +public class GeneratorException extends Exception { + private static final long serialVersionUID = 1L; + + public GeneratorException(String message) { + super(message); + } +} diff --git a/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/GeneratorSource.java b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/GeneratorSource.java new file mode 100644 index 000000000..00a277d11 --- /dev/null +++ b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/GeneratorSource.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.web.generator.client; + +import com.google.gwt.user.client.ui.Grid; +import com.google.gwt.user.client.ui.Widget; + +/** + * Base interface for any generator. + * + * @author Yohann Coppel + */ +public interface GeneratorSource { + /** + * @return a GWT Grid object, containing the GUI. + */ + public Grid getWidget(); + /** + * @return the name of the generator to be used in the GUI. + */ + public String getName(); + /** + * @return the text to be encoded into the QR code. + * @throws GeneratorException if the input data contains errors. + */ + public String getText() throws GeneratorException; + /** + * @param widget the widget that was last modified, and that we want to + * validate the content. + * @throws GeneratorException if the widget contains errors. + */ + public void validate(Widget widget) throws GeneratorException; + /** + * Called when the generator is selected in the list. Using this method, + * the generator should set the focus to the first widget it defines. + */ + public void setFocus(); +} diff --git a/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/GeoLocationGenerator.java b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/GeoLocationGenerator.java new file mode 100644 index 000000000..6d9b97f3e --- /dev/null +++ b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/GeoLocationGenerator.java @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.web.generator.client; + +import com.google.gwt.http.client.URL; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.ChangeListener; +import com.google.gwt.user.client.ui.ClickListener; +import com.google.gwt.user.client.ui.Grid; +import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.Widget; + +/** + * A generator for geo location. It also accepts a google maps links and + * extracts the coordinates and query from the URL. + * + * @author Yohann Coppel + */ +public class GeoLocationGenerator implements GeneratorSource { + private static final String LON_REGEXP = "[+-]?[0-9]+(.[0-9]+)?"; + private static final String LAT_REGEXP = "[+-]?[0-9]+(.[0-9]+)?"; + + Grid table = null; + TextBox latitude = new TextBox(); + TextBox longitude = new TextBox(); + TextBox query = new TextBox(); + TextBox mapsLink = new TextBox(); + + public GeoLocationGenerator(ChangeListener listener) { + latitude.addStyleName(StylesDefs.INPUT_FIELD_REQUIRED); + longitude.addStyleName(StylesDefs.INPUT_FIELD_REQUIRED); + latitude.addChangeListener(listener); + longitude.addChangeListener(listener); + query.addChangeListener(listener); + } + + public String getName() { + return "Geo location"; + } + + public String getText() throws GeneratorException { + String que = getQueryField(); + if (null != que && que.length() > 0) { + if (null == getLatitudeField()) { + latitude.setText("0"); + } + if (null == getLongitudeField()) { + longitude.setText("0"); + } + } + String lat = getLatitudeField(); + String lon = getLongitudeField(); + + if (que.length() > 0) { + return "geo:"+lat+","+lon+"?q="+que; + } + + return "geo:"+lat+","+lon; + } + + private String getQueryField() { + String que = query.getText(); + que = que.replace("&", "%26"); + return que; + } + + private String getLongitudeField() throws GeneratorException { + String lon = longitude.getText(); + if (!lon.matches(LON_REGEXP)) { + throw new GeneratorException("Longitude is not a correct value."); + } + double val = Double.parseDouble(lon); + if (val < -180 || val > 180) { + throw new GeneratorException("Longitude must be in [-180:180]"); + } + return lon; + } + + private String getLatitudeField() throws GeneratorException { + String lat = latitude.getText(); + if (!lat.matches(LAT_REGEXP)) { + throw new GeneratorException("Latitude is not a correct value."); + } + double val = Double.parseDouble(lat); + if (val < -90 || val > 90) { + throw new GeneratorException("Latitude must be in [-90:90]"); + } + return lat; + } + + public Grid getWidget() { + if (table != null) { + return table; + } + table = new Grid(5, 2); + + table.setText(0, 0, "Latitude"); + table.setWidget(0, 1, latitude); + table.setText(1, 0, "Longitude"); + table.setWidget(1, 1, longitude); + table.setText(2, 0, "Query"); + table.setWidget(2, 1, query); + table.setText(3, 0, "OR"); + table.setText(3, 1, "enter a Google Maps link and click Fill:"); + // looks like this: + // http://maps.google.com/?ie=UTF8&ll=40.741404,-74.00322&spn=0.001484,0.003101&z=18 + Button fill = new Button("Fill ↑"); + fill.addClickListener(new ClickListener() { + public void onClick(Widget sender) { + fillWithMaps(); + } + }); + table.setWidget(4, 0, fill); + table.setWidget(4, 1, mapsLink); + + return table; + } + + protected void fillWithMaps() { + String link = mapsLink.getText(); + if (!link.matches("http://maps.google.com/.*")) { + return; + } + String q = ""; + if (link.matches(".*&q=[^&]*&.*")) { + for (int i = link.indexOf("&q=") + 3; + i < link.length() && link.charAt(i) != '&'; ++i) { + q += link.charAt(i); + } + // special cases: + q = q.replace("+", " "); + q = q.replace("%26", "&"); + } + + String lat = ""; + String lon = ""; + if (link.matches(".*&s?ll=[^&]*&.*")) { + boolean beforeComa = true; + int start = 0; + if (link.indexOf("&sll=") == -1) { + start = link.indexOf("&ll=") + 4; + } else { + start = link.indexOf("&sll=") + 5; + } + for (int i = start; i < link.length() && link.charAt(i) != '&'; ++i) { + if (beforeComa) { + if (link.charAt(i) == ',') { + beforeComa = false; + } else { + lat += link.charAt(i); + } + } else { + lon += link.charAt(i); + } + } + } + + query.setText(URL.decode(q)); + latitude.setText(lat); + longitude.setText(lon); + } + + public void validate(Widget widget) throws GeneratorException { + if (widget == latitude) getLatitudeField(); + if (widget == longitude) getLongitudeField(); + } + + public void setFocus() { + latitude.setFocus(true); + } +} diff --git a/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/PhoneNumberGenerator.java b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/PhoneNumberGenerator.java new file mode 100644 index 000000000..9792fd9b7 --- /dev/null +++ b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/PhoneNumberGenerator.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.web.generator.client; + +import com.google.gwt.user.client.ui.ChangeListener; +import com.google.gwt.user.client.ui.Grid; +import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.Widget; + +/** + * A generator for a phone number. + * + * @author Yohann Coppel + */ +public class PhoneNumberGenerator implements GeneratorSource { + Grid table = null; + TextBox number = new TextBox(); + + public PhoneNumberGenerator(ChangeListener listener) { + number.addStyleName(StylesDefs.INPUT_FIELD_REQUIRED); + number.addChangeListener(listener); + } + + public String getName() { + return "Phone number"; + } + + public String getText() throws GeneratorException { + String tel = getTelField(); + return "tel:" + tel; + } + + private String getTelField() throws GeneratorException { + String input = number.getText(); + if (input.length() < 1) { + throw new GeneratorException("Phone number must be present."); + } + input = Validators.filterNumber(input); + Validators.validateNumber(input); + return input; + } + + public Grid getWidget() { + if (table != null) { + return table; + } + table = new Grid(1, 2); + + table.setText(0, 0, "Phone number"); + table.setWidget(0, 1, number); + + return table; + } + + public void validate(Widget widget) throws GeneratorException { + if (widget == number) getTelField(); + } + + public void setFocus() { + number.setFocus(true); + } +} diff --git a/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/SmsAddressGenerator.java b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/SmsAddressGenerator.java new file mode 100644 index 000000000..05fe28b0a --- /dev/null +++ b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/SmsAddressGenerator.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.web.generator.client; + +import com.google.gwt.user.client.ui.ChangeListener; +import com.google.gwt.user.client.ui.Grid; +import com.google.gwt.user.client.ui.TextArea; +import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.Widget; + +/** + * A generator for a sms address. Gives the option of filling up the content + * of the message as well. + * + * @author Yohann Coppel + */ +public class SmsAddressGenerator implements GeneratorSource { + Grid table = null; + TextBox number = new TextBox(); + TextArea message = new TextArea(); + + public SmsAddressGenerator(ChangeListener listener) { + number.addStyleName(StylesDefs.INPUT_FIELD_REQUIRED); + number.addChangeListener(listener); + message.addChangeListener(listener); + } + + public String getName() { + return "SMS"; + } + + public String getText() throws GeneratorException { + String inputNumber = getTelField(); + String inputMessage = getMessageField(); + + String output = inputNumber; + // we add the text only if there actually is something in the field. + if (inputMessage.length() > 0) { + output += ":" + inputMessage; + } + + return "smsto:" + output; + } + + private String getTelField() throws GeneratorException { + String input = number.getText(); + if (input.length() < 1) { + throw new GeneratorException("Phone number must be present."); + } + input = Validators.filterNumber(input); + Validators.validateNumber(input); + return input; + } + + private String getMessageField() throws GeneratorException { + String inputMessage = message.getText(); + if (inputMessage.length() > 150) { + throw new GeneratorException("Sms message can not be longer than 150 characters."); + } + return inputMessage; + } + + public Grid getWidget() { + if (table != null) { + return table; + } + table = new Grid(2, 2); + + table.setText(0, 0, "Phone number"); + table.setWidget(0, 1, number); + + table.setText(1, 0, "Message"); + table.setWidget(1, 1, message); + + return table; + } + + public void validate(Widget widget) throws GeneratorException { + if (widget == number) getTelField(); + if (widget == message) getMessageField(); + } + + public void setFocus() { + number.setFocus(true); + } +} diff --git a/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/StringConstants.java b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/StringConstants.java new file mode 100644 index 000000000..e690b9fe4 --- /dev/null +++ b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/StringConstants.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.web.generator.client; + +import com.google.gwt.i18n.client.Messages; + +// Not used yet. A first atempt to localization. +public interface StringConstants extends Messages { + public String codeType(); + public String generateButton(); +} diff --git a/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/StylesDefs.java b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/StylesDefs.java new file mode 100644 index 000000000..5be82ae73 --- /dev/null +++ b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/StylesDefs.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.web.generator.client; + +/** + * Contains class names of css styles to be used in HTML. + * + * @author Yohann Coppel + */ +public class StylesDefs { + public static final String INPUT_FIELD_REQUIRED = "required"; + public static final String ERROR_MESSAGE = "errorMessage"; +} diff --git a/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/TextGenerator.java b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/TextGenerator.java new file mode 100644 index 000000000..e5fccf2e4 --- /dev/null +++ b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/TextGenerator.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.web.generator.client; + +import com.google.gwt.user.client.ui.ChangeListener; +import com.google.gwt.user.client.ui.Grid; +import com.google.gwt.user.client.ui.TextArea; +import com.google.gwt.user.client.ui.Widget; + +/** + * A generator for any text content. + * + * @author Yohann Coppel + */ +public class TextGenerator implements GeneratorSource { + TextArea text = new TextArea(); + Grid table = null; + String error = ""; + + public TextGenerator(ChangeListener listener) { + text.addStyleName(StylesDefs.INPUT_FIELD_REQUIRED); + text.addChangeListener(listener); + } + + public String getName() { + return "Text"; + } + + public String getText() throws GeneratorException { + String message = getTextField(); + return message; + } + + public String getTextField() throws GeneratorException { + String input = text.getText(); + if (input.length() == 0) { + throw new GeneratorException("Text should be at least 1 character."); + } + return input; + } + + public Grid getWidget() { + if (table != null) { + // early termination if the table has already been constructed + return table; + } + + table = new Grid(1, 2); + table.getColumnFormatter().addStyleName(0, "firstColumn"); + + table.setText(0, 0, "Text content"); + table.setWidget(0, 1, text); + + return table; + } + + public String getErrorMessage() { + return error; + } + + public void validate(Widget widget) throws GeneratorException { + if (widget == text) getTextField(); + } + + public void setFocus() { + text.setFocus(true); + } +} diff --git a/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/TimeZoneList.java b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/TimeZoneList.java new file mode 100644 index 000000000..40920223b --- /dev/null +++ b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/TimeZoneList.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.web.generator.client; + +/** + * A class containing a list of timezones, with their full names, and time + * offset. + * + * @author Yohann Coppel + */ +public class TimeZoneList { + public static class TimeZoneInfo { + String abreviation; + String longName; + String GMTRelative; + long gmtDiff; + public TimeZoneInfo(String abreviation, String longName, String relative, long gmtDiff) { + super(); + GMTRelative = relative; + this.abreviation = abreviation; + this.gmtDiff = gmtDiff; + this.longName = longName; + } + } + + private final static long ONE_HOUR = 60*60*1000; + private final static long THIRTY_MIN = 30*60*1000; + + public static final TimeZoneInfo[] TIMEZONES = { + new TimeZoneInfo("GMT", "Greenwich Mean Time", "GMT", 0 * ONE_HOUR + 0 * THIRTY_MIN), // 0 + new TimeZoneInfo("UTC", "Universal Coordinated Time", "GMT", 1 * ONE_HOUR + 0 * THIRTY_MIN), + new TimeZoneInfo("ECT", "European Central Time", "GMT+1:00", 1 * ONE_HOUR + 0 * THIRTY_MIN), + new TimeZoneInfo("EET", "Eastern European Time", "GMT+2:00", 2 * ONE_HOUR + 0 * THIRTY_MIN), + new TimeZoneInfo("ART", "(Arabic) Egypt Standard Time", "GMT+2:00", 2 * ONE_HOUR + 0 * THIRTY_MIN), + new TimeZoneInfo("EAT", "Eastern African Time", "GMT+3:00", 3 * ONE_HOUR + 0 * THIRTY_MIN), // 5 + new TimeZoneInfo("MET", "Middle East Time", "GMT+3:30", 3 * ONE_HOUR + 1 * THIRTY_MIN), + new TimeZoneInfo("NET", "Near East Time", "GMT+4:00", 4 * ONE_HOUR + 0 * THIRTY_MIN), + new TimeZoneInfo("PLT", "Pakistan Lahore Time", "GMT+5:00", 5 * ONE_HOUR + 0 * THIRTY_MIN), + new TimeZoneInfo("IST", "India Standard Time", "GMT+5:30", 5 * ONE_HOUR + 1 * THIRTY_MIN), + new TimeZoneInfo("BST", "Bangladesh Standard Time", "GMT+6:00", 6 * ONE_HOUR + 0 * THIRTY_MIN), // 10 + new TimeZoneInfo("VST", "Vietnam Standard Time", "GMT+7:00", 7 * ONE_HOUR + 0 * THIRTY_MIN), + new TimeZoneInfo("CTT", "China Taiwan Time", "GMT+8:00", 8 * ONE_HOUR + 0 * THIRTY_MIN), + new TimeZoneInfo("JST", "Japan Standard Time", "GMT+9:00", 9 * ONE_HOUR + 0 * THIRTY_MIN), + new TimeZoneInfo("ACT", "Australia Central Time", "GMT+9:30", 9 * ONE_HOUR + 1 * THIRTY_MIN), + new TimeZoneInfo("AET", "Australia Eastern Time", "GMT+10:00", 10 * ONE_HOUR + 0 * THIRTY_MIN), // 15 + new TimeZoneInfo("SST", "Solomon Standard Time", "GMT+11:00", 11 * ONE_HOUR + 0 * THIRTY_MIN), + new TimeZoneInfo("NST", "New Zealand Standard Time", "GMT+12:00", 12 * ONE_HOUR + 0 * THIRTY_MIN), + new TimeZoneInfo("MIT", "Midway Islands Time", "GMT-11:00", -11 * ONE_HOUR - 0 * THIRTY_MIN), + new TimeZoneInfo("HST", "Hawaii Standard Time", "GMT-10:00", -10 * ONE_HOUR - 0 * THIRTY_MIN), + new TimeZoneInfo("AST", "Alaska Standard Time", "GMT-9:00", -9 * ONE_HOUR - 0 * THIRTY_MIN), // 20 + new TimeZoneInfo("PST", "Pacific Standard Time", "GMT-8:00", -8 * ONE_HOUR - 0 * THIRTY_MIN), + new TimeZoneInfo("PNT", "Phoenix Standard Time", "GMT-7:00", -7 * ONE_HOUR - 0 * THIRTY_MIN), + new TimeZoneInfo("MST", "Mountain Standard Time", "GMT-7:00", -7 * ONE_HOUR - 0 * THIRTY_MIN), + new TimeZoneInfo("CST", "Central Standard Time", "GMT-6:00", -6 * ONE_HOUR - 0 * THIRTY_MIN), + new TimeZoneInfo("EST", "Eastern Standard Time", "GMT-5:00", -5 * ONE_HOUR - 0 * THIRTY_MIN), // 25 + new TimeZoneInfo("IET", "Indiana Eastern Standard Time", "GMT-5:00", -5 * ONE_HOUR - 0 * THIRTY_MIN), + new TimeZoneInfo("PRT", "Puerto Rico and US Virgin Islands Time", "GMT-4:00", -4 * ONE_HOUR - 0 * THIRTY_MIN), + new TimeZoneInfo("CNT", "Canada Newfoundland Time", "GMT-3:30", -3 * ONE_HOUR - 1 * THIRTY_MIN), + new TimeZoneInfo("AGT", "Argentina Standard Time", "GMT-3:00", -3 * ONE_HOUR - 0 * THIRTY_MIN), + new TimeZoneInfo("BET", "Brazil Eastern Time", "GMT-3:00", -3 * ONE_HOUR - 0 * THIRTY_MIN), // 30 + new TimeZoneInfo("CAT", "Central African Time", "GMT-1:00", -1 * ONE_HOUR - 0 * THIRTY_MIN), + }; + +} diff --git a/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/UrlGenerator.java b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/UrlGenerator.java new file mode 100644 index 000000000..bb5d23c98 --- /dev/null +++ b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/UrlGenerator.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.web.generator.client; + +import com.google.gwt.user.client.ui.ChangeListener; +import com.google.gwt.user.client.ui.Grid; +import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.Widget; + +/** + * A generator for URL addresses. + * + * @author Yohann Coppel + */ +public class UrlGenerator implements GeneratorSource { + Grid table = null; + TextBox url = new TextBox(); + + public UrlGenerator(ChangeListener listener) { + url.addStyleName(StylesDefs.INPUT_FIELD_REQUIRED); + url.addChangeListener(listener); + } + + public Grid getWidget() { + if (table != null) { + // early termination if the table has already been constructed + return table; + } + + table = new Grid(1, 2); + table.getColumnFormatter().addStyleName(0, "firstColumn"); + + url.setText("http://"); + + table.setText(0, 0, "URL"); + table.setWidget(0, 1, url); + + return table; + } + + public String getName() { + return "URL"; + } + + public String getText() throws GeneratorException { + String input = getUrlField(); + return input; + } + + private String getUrlField() throws GeneratorException { + String input = url.getText(); + Validators.validateUrl(input); + return input; + } + + public void validate(Widget widget) throws GeneratorException { + if (widget == url) getUrlField(); + } + + public void setFocus() { + url.setFocus(true); + } +} diff --git a/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/Validators.java b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/Validators.java new file mode 100644 index 000000000..51646bfb9 --- /dev/null +++ b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/client/Validators.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.web.generator.client; + +/** + * Helpers methods to check for phone numbers, email addresses, and URL. Other + * general purpose check methods should go here as well. + * + * @author Yohann Coppel + */ +public final class Validators { + public static String filterNumber(String number) { + return number.replaceAll("[ +\\.,\\-\\(\\)]", ""); + } + + public static void validateNumber(String number) throws GeneratorException { + if (!number.matches("[0-9]+")) { + throw new GeneratorException("Phone number must be digits only."); + } + } + + public static void validateUrl(String url) throws GeneratorException { + //FIXME: url specification is a bit more complex than just that. + if (!((url.startsWith("http://") && url.length() > 7) + || (url.startsWith("https://") && url.length() > 8))) { + throw new GeneratorException("URL: http:// or https://," + + "plus at least 1 character."); + } + } + + public static void validateEmail(String email) throws GeneratorException { + //FIXME: we can have a better check for email here. + if (!email.matches("^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,6}$")) { + throw new GeneratorException("Email is not valid."); + } + } + +} diff --git a/zxing.appspot.com/generator/src/com/google/zxing/web/generator/public/DatePickerDemo.css b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/public/DatePickerDemo.css new file mode 100644 index 000000000..ec89bf3b4 --- /dev/null +++ b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/public/DatePickerDemo.css @@ -0,0 +1,180 @@ +/** +Date picker styles, most of these will eventually move into a default resource bundle. +*/ +.gwt-DatePicker { + width: 150px; + border: 1px solid #f1f1f1; + border-bottom: 2px solid #f1f1f1; + color: 6b6b6b; + cursor: default; + +} + +.gwt-DatePicker td { + font-family: Arial; + font-size: 65%; + padding: 2px; + text-align: center; + padding: 2px; + outline: none; + -moz-outline: none; + cursor: default; +} + +.gwt-DatePicker td,.month-selector td :focus { + outline: none +} + +.gwt-DateBox input { + width: 8em; +} + +/** +Calendar styles +*/ +.calendar-view { + background-color: white; + width: 100%; +} + +.calendar-view .filler-cell { + color: #bfbfbf; + padding: 1px; + cursor: hand; +} + +.calendar-view .date-cell { + padding: 1px; + cursor:hand; +} + +.calendar-view .selected-cell { + background: #aaccee; +} + +.calendar-view .day-title { + background: #dbe6de; +} + +.gwt-DatePicker .calendar-view .highlighted-cell { + border: 1px solid #eeeeee; + padding: 0px; +} + +.calendar-view .today-cell { + border: 1px solid black; + padding: 0px; +} + +.gwt-DatePicker .calendar-view .weekend { + background: #f1f1f1; +} + +.calendar-view .disabled-cell { + color: graytext; +} + +/* +Month selector styles +*/ +.month-selector { + background: #dbe6de; + width: 100%; + text-align: center; +} + +.month-selector td { + font-weight: bold; + font-size: 70%; +} + +.month-selector .month-label { + text-align: center; + background: #dbe6de; +} + +.month-selector .month-backward { + padding-right: 2em; +} + +.month-selector .month-forward { + padding-left: 2em; +} + +/**************************** +helper styles +******************************/ +.log-panel { + position: relative; + float: right; + border: 1px solid black; + margin-left: 30px; +} + +.gwt-TabPanel { + margin-top: 4px; +} + +.gwt-TabPanelBottom { + background-color: #E8EEF7; +} + +.gwt-TabBar { + padding-top: 2px; + border-bottom: 4px solid #87B3FF; + background-color: #fff; +} + +.gwt-TabBar .gwt-TabBarItem { + padding: 4px; + cursor: pointer; + cursor: hand; + background-color: #e8eef7; + border-bottom: 2px solid white; + margin-right: 2px; +} + +.gwt-TabBar .gwt-TabBarItem-selected { + padding: 4px; + font-weight: bold; + cursor: default; + background-color: #87b3ff; + border-bottom: 2px solid #87b3ff; + margin-right: 2px; +} + +/* Styles demo*/ +.gwt-DatePicker .red-date { + background-color: red; +} + +.gwt-DatePicker .blue-background { + background-color: blue; +} + +.gwt-DatePicker .red-text { + color: red; +} + +.gwt-DatePicker .green-border { + border: 5px solid green; +} + +.gwt-DatePicker .big-text { + font-size: x-large; +} + +.gwt-DatePicker .underlined-and-bold-text { + font-weight: bold; + text-decoration: underline; +} + +.gwt-DatePicker .yellow-background { + background-color: yellow; +} + +/* date range styles */ +.filler { + width: 30px; + text-align: center; +} diff --git a/zxing.appspot.com/generator/src/com/google/zxing/web/generator/public/Generator.css b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/public/Generator.css new file mode 100644 index 000000000..8d650d465 --- /dev/null +++ b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/public/Generator.css @@ -0,0 +1,123 @@ +/** CSS by Wain. */ +body { + background-color: #e9eef3; + margin: 0; + padding: 0; + font-family: Arial, sans-serif; + font-size: 11px; +} + +#header { + background-color: #dde3e9; + border-bottom: 1px solid #f2f7fc; +} + +#header h1 { + font-size: 15px; + font-weight: bold; + margin: 0; + padding: 12px; + border-bottom: 1px solid #c8d0d9; +} + +#header span { + font-weight: normal; + color: #5e6b75; +} + +#footer { + width: 100%; + text-align:center; + padding-top: 12px; +} + +#footer a { + text-decoration:none; + color: #5e6b75; +} + +/****************************************/ +#mainpanel { + width: 800px; + margin: 0 auto; + padding: 12px; + font-size: 11px; +} + +#imageresult { + background-color: #dde3e9; + height: 350px; + width: 350px; + vertical-align: middle; + text-align:center; + padding: 10px; + + position: relative; + display: table; + #position: relative; +} + +#innerresult { + display: table-cell; + vertical-align: middle; + width: 100%; + #position: absolute; + #top: 50%; +} + +#innerresult img { + #position: relative; + #top: -50%; +} + +#downloadText { + font-size: 11px; +} + +#urlresult { + width: 350px; +} + +.firstColumn { + width: 100px; + text-align: right; + vertical-align: top; + padding: 4px 0 4px 0; + color: #5e6b75; + font-weight: bold; + font-size: 11px; +} + +.secondColumn { + width: 270px; + font-size: 11px; + color: #5e6b75; + font-weight: bold; +} + +/*.inputfield,*/ +.gwt-TextBox, +.gwt-TextArea { + border: 1px solid #c8d0d9; + padding: 4px; + width: 256px; + font-family: Arial, sans-serif; + font-size: 13px; + color: #000; + font-weight: normal; +} + +/*.inputfield:focus,*/ +.gwt-TextBox:focus { + background-color: #fffbcc; +} + +.required { + background: #ffffff url(required-field-bg.png) repeat-y; +} + +.errorMessage { + padding-left: 110px; + font-size: 11px; + color: red; +} diff --git a/zxing.appspot.com/generator/src/com/google/zxing/web/generator/public/Generator.html b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/public/Generator.html new file mode 100644 index 000000000..5466e6405 --- /dev/null +++ b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/public/Generator.html @@ -0,0 +1,20 @@ + + + + + QR Code Generator + + + + + + +
+ + + + diff --git a/zxing.appspot.com/generator/src/com/google/zxing/web/generator/public/required-field-bg.png b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/public/required-field-bg.png new file mode 100644 index 000000000..49e272577 Binary files /dev/null and b/zxing.appspot.com/generator/src/com/google/zxing/web/generator/public/required-field-bg.png differ diff --git a/zxing.appspot.com/redirect.py b/zxing.appspot.com/redirect.py new file mode 100644 index 000000000..ed1cccb61 --- /dev/null +++ b/zxing.appspot.com/redirect.py @@ -0,0 +1,17 @@ +from google.appengine.ext import webapp +from google.appengine.ext.webapp.util import run_wsgi_app + +class BlogHandler(webapp.RequestHandler): + def get(self, tail = ''): + self.redirect('/generator/'+tail, permanent = True) + +application = webapp.WSGIApplication( + [ + (r'^/generator$', BlogHandler) + ]) + +def main(): + run_wsgi_app(application) + +if __name__ == "__main__": + main()