diff options
author | Artur Signell <artur@vaadin.com> | 2012-01-27 15:00:22 +0200 |
---|---|---|
committer | Artur Signell <artur@vaadin.com> | 2012-01-27 15:00:22 +0200 |
commit | abaf86ae9baeae094687cc289990ddeec4979c94 (patch) | |
tree | 25a44d44d7c22e9e46e8afb41831099c4ad061e5 /src | |
parent | cf138e29f13358a70c9b58c2f11728387f6747e1 (diff) | |
parent | 8cc1ee0aa018012e6644723860a353d41d6af7f8 (diff) | |
download | vaadin-framework-abaf86ae9baeae094687cc289990ddeec4979c94.tar.gz vaadin-framework-abaf86ae9baeae094687cc289990ddeec4979c94.zip |
Merge branch 'master' into contrib
Diffstat (limited to 'src')
22 files changed, 1448 insertions, 1401 deletions
diff --git a/src/com/vaadin/launcher/util/BrowserLauncher.java b/src/com/vaadin/launcher/util/BrowserLauncher.java deleted file mode 100644 index 55692cb251..0000000000 --- a/src/com/vaadin/launcher/util/BrowserLauncher.java +++ /dev/null @@ -1,127 +0,0 @@ -/*
-@VaadinApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.launcher.util;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStreamReader;
-
-/**
- * This class opens default browser for DemoLauncher class. Default browser is
- * detected by the operating system.
- *
- */
-public class BrowserLauncher {
-
- /**
- * Open browser on specified URL.
- *
- * @param url
- */
- public static void openBrowser(String url) {
-
- final Runtime runtime = Runtime.getRuntime();
- boolean started = false;
-
- final String os = System.getProperty("os.name", "windows")
- .toLowerCase();
-
- // Linux
- if (os.indexOf("linux") >= 0) {
- // See if the default browser is Konqueror by resolving the symlink.
- boolean isDefaultKonqueror = false;
- try {
- // Find out the location of the x-www-browser link from path.
- Process process = runtime.exec("which x-www-browser");
- BufferedInputStream ins = new BufferedInputStream(
- process.getInputStream());
- BufferedReader bufreader = new BufferedReader(
- new InputStreamReader(ins));
- String defaultLinkPath = bufreader.readLine();
- ins.close();
-
- // The path is null if the link did not exist.
- if (defaultLinkPath != null) {
- // See if the default browser is Konqueror.
- File file = new File(defaultLinkPath);
- String canonical = file.getCanonicalPath();
- if (canonical.indexOf("konqueror") != -1) {
- isDefaultKonqueror = true;
- }
- }
- } catch (IOException e1) {
- // The symlink was probably not found, so this is ok.
- }
-
- // Try x-www-browser, which is symlink to the default browser,
- // except if we found that it is Konqueror.
- if (!started && !isDefaultKonqueror) {
- try {
- runtime.exec("x-www-browser " + url);
- started = true;
- } catch (final IOException e) {
- }
- }
-
- // Try firefox
- if (!started) {
- try {
- runtime.exec("firefox " + url);
- started = true;
- } catch (final IOException e) {
- }
- }
-
- // Try mozilla
- if (!started) {
- try {
- runtime.exec("mozilla " + url);
- started = true;
- } catch (final IOException e) {
- }
- }
-
- // Try konqueror
- if (!started) {
- try {
- runtime.exec("konqueror " + url);
- started = true;
- } catch (final IOException e) {
- }
- }
- }
-
- // OS X
- if (os.indexOf("mac os x") >= 0) {
-
- // Try open
- if (!started) {
- try {
- runtime.exec("open " + url);
- started = true;
- } catch (final IOException e) {
- }
- }
- }
-
- // Try cmd /start command on windows
- if (os.indexOf("win") >= 0) {
- if (!started) {
- try {
- runtime.exec("cmd /c start " + url);
- started = true;
- } catch (final IOException e) {
- }
- }
- }
-
- if (!started) {
- System.out.println("Failed to open browser. Please go to " + url);
- }
- }
-
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java index 9b756382f3..e659a18477 100644 --- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java +++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java @@ -22,6 +22,8 @@ import com.google.gwt.http.client.RequestBuilder; import com.google.gwt.http.client.RequestCallback; import com.google.gwt.http.client.RequestException; import com.google.gwt.http.client.Response; +import com.google.gwt.regexp.shared.MatchResult; +import com.google.gwt.regexp.shared.RegExp; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; @@ -101,6 +103,27 @@ public class ApplicationConnection { public static final String ATTRIBUTE_DESCRIPTION = "description"; public static final String ATTRIBUTE_ERROR = "error"; + /** + * A string that, if found in a non-JSON response to a UIDL request, will + * cause the browser to refresh the page. If followed by a colon, optional + * whitespace, and a URI, causes the browser to synchronously load the URI. + * + * <p> + * This allows, for instance, a servlet filter to redirect the application + * to a custom login page when the session expires. For example: + * </p> + * + * <pre> + * if (sessionExpired) { + * response.setHeader("Content-Type", "text/html"); + * response.getWriter().write( + * myLoginPageHtml + "<!-- Vaadin-Refresh: " + * + request.getContextPath() + " -->"); + * } + * </pre> + */ + public static final String UIDL_REFRESH_TOKEN = "Vaadin-Refresh"; + // will hold the UIDL security key (for XSS protection) once received private String uidlSecurityKey = "init"; @@ -525,6 +548,25 @@ public class ApplicationConnection { return; } + String contentType = response.getHeader("Content-Type"); + if (contentType == null + || !contentType.startsWith("application/json")) { + /* + * A servlet filter or equivalent may have intercepted + * the request and served non-UIDL content (for + * instance, a login page if the session has expired.) + * If the response contains a magic substring, do a + * synchronous refresh. See #8241. + */ + MatchResult refreshToken = RegExp.compile( + UIDL_REFRESH_TOKEN + "(:\\s*(.*?))?(\\s|$)") + .exec(response.getText()); + if (refreshToken != null) { + redirect(refreshToken.getGroup(2)); + return; + } + } + // for(;;);[realjson] final String jsonText = response.getText().substring(9, response.getText().length() - 1); @@ -1651,9 +1693,68 @@ public class ApplicationConnection { fw.setEnabled(enabled); } + // Style names + component.setStyleName(getStyleName(component.getStylePrimaryName(), + uidl, component instanceof Field)); + + TooltipInfo tooltipInfo = paintableMap.getTooltipInfo(paintable, null); + // Update tooltip + if (uidl.hasAttribute(ATTRIBUTE_DESCRIPTION)) { + tooltipInfo + .setTitle(uidl.getStringAttribute(ATTRIBUTE_DESCRIPTION)); + } else { + tooltipInfo.setTitle(null); + } + + // Set captions + if (manageCaption) { + final Container parent = Util.getLayout(component); + if (parent != null) { + parent.updateCaption(paintable, uidl); + } + } + + // add error classname to components w/ error + if (uidl.hasAttribute(ATTRIBUTE_ERROR)) { + tooltipInfo.setErrorUidl(uidl.getErrors()); + } else { + tooltipInfo.setErrorUidl(null); + } + + // Set captions + if (manageCaption) { + final Container parent = Util.getLayout(component); + if (parent != null) { + parent.updateCaption(paintable, uidl); + } + } + /* + * updateComponentSize need to be after caption update so caption can be + * taken into account + */ + + updateComponentSize(paintable, uidl); + + return false; + } + + /** + * Generates the style name for the widget based on the given primary style + * name (typically returned by Widget.getPrimaryStyleName()) and the UIDL. + * An additional "modified" style name can be added if the field parameter + * is set to true. + * + * @param primaryStyleName + * @param uidl + * @param isField + * @return + */ + public static String getStyleName(String primaryStyleName, UIDL uidl, + boolean field) { + boolean enabled = !uidl.getBooleanAttribute("disabled"); + StringBuffer styleBuf = new StringBuffer(); - final String primaryName = component.getStylePrimaryName(); - styleBuf.append(primaryName); + styleBuf.append(primaryStyleName); // first disabling and read-only status if (!enabled) { @@ -1671,7 +1772,7 @@ public class ApplicationConnection { final String[] styles = uidl.getStringAttribute("style").split(" "); for (int i = 0; i < styles.length; i++) { styleBuf.append(" "); - styleBuf.append(primaryName); + styleBuf.append(primaryStyleName); styleBuf.append("-"); styleBuf.append(styles[i]); styleBuf.append(" "); @@ -1680,55 +1781,25 @@ public class ApplicationConnection { } // add modified classname to Fields - if (uidl.hasAttribute("modified") && component instanceof Field) { + if (field && uidl.hasAttribute("modified")) { styleBuf.append(" "); styleBuf.append(MODIFIED_CLASSNAME); } - TooltipInfo tooltipInfo = paintableMap.getTooltipInfo(paintable, null); - // Update tooltip - if (uidl.hasAttribute(ATTRIBUTE_DESCRIPTION)) { - tooltipInfo - .setTitle(uidl.getStringAttribute(ATTRIBUTE_DESCRIPTION)); - } else { - tooltipInfo.setTitle(null); - } - // add error classname to components w/ error if (uidl.hasAttribute(ATTRIBUTE_ERROR)) { - tooltipInfo.setErrorUidl(uidl.getErrors()); styleBuf.append(" "); - styleBuf.append(primaryName); + styleBuf.append(primaryStyleName); styleBuf.append(ERROR_CLASSNAME_EXT); - } else { - tooltipInfo.setErrorUidl(null); } - // add required style to required components if (uidl.hasAttribute("required")) { styleBuf.append(" "); - styleBuf.append(primaryName); + styleBuf.append(primaryStyleName); styleBuf.append(REQUIRED_CLASSNAME_EXT); } - // Styles + disabled & readonly - component.setStyleName(styleBuf.toString()); - - // Set captions - if (manageCaption) { - final Container parent = Util.getLayout(component); - if (parent != null) { - parent.updateCaption(paintable, uidl); - } - } - /* - * updateComponentSize need to be after caption update so caption can be - * taken into account - */ - - updateComponentSize(paintable, uidl); - - return false; + return styleBuf.toString(); } private void updateComponentSize(VPaintableWidget paintable, UIDL uidl) { @@ -1821,7 +1892,7 @@ public class ApplicationConnection { while (childWidgets.hasNext()) { final Widget child = childWidgets.next(); - if (child instanceof VPaintableWidget) { + if (getPaintableMap().isPaintable(child)) { if (handleComponentRelativeSize(child)) { /* @@ -1856,7 +1927,7 @@ public class ApplicationConnection { if (paintable == null) { return false; } - boolean debugSizes = false; + boolean debugSizes = true; FloatSize relativeSize = paintableMap.getRelativeSize(paintable); if (relativeSize == null) { diff --git a/src/com/vaadin/terminal/gwt/client/Util.java b/src/com/vaadin/terminal/gwt/client/Util.java index 2a3fc07195..0a3d83ff3d 100644 --- a/src/com/vaadin/terminal/gwt/client/Util.java +++ b/src/com/vaadin/terminal/gwt/client/Util.java @@ -964,6 +964,8 @@ public class Util { VConsole.log("\t\t" + var[1] + " (" + var[2] + ")" + " : " + var[0]); } + } else { + VConsole.log("\t" + id + ": Warning: no corresponding paintable!"); } } diff --git a/src/com/vaadin/terminal/gwt/client/VDebugConsole.java b/src/com/vaadin/terminal/gwt/client/VDebugConsole.java index 892260e6ca..fdaf944b9f 100644 --- a/src/com/vaadin/terminal/gwt/client/VDebugConsole.java +++ b/src/com/vaadin/terminal/gwt/client/VDebugConsole.java @@ -734,8 +734,10 @@ public class VDebugConsole extends VOverlay implements Console { forceLayout.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { - // TODO for each client in appconf force layout - // VDebugConsole.this.client.forceLayout(); + for (ApplicationConnection applicationConnection : ApplicationConfiguration + .getRunningApplications()) { + applicationConnection.forceLayout(); + } } }); diff --git a/src/com/vaadin/terminal/gwt/client/ui/VAbstractPaintableWidget.java b/src/com/vaadin/terminal/gwt/client/ui/VAbstractPaintableWidget.java index d4c8f79467..9a2e728454 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VAbstractPaintableWidget.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VAbstractPaintableWidget.java @@ -1,3 +1,6 @@ +/*
+@VaadinApache2LicenseForJavaFiles@
+ */
package com.vaadin.terminal.gwt.client.ui;
import com.google.gwt.user.client.ui.Widget;
@@ -10,7 +13,7 @@ public abstract class VAbstractPaintableWidget implements VPaintableWidget { private ApplicationConnection connection;
/* State variables */
-// private boolean enabled = true;
+ // private boolean enabled = true;
/**
* Default constructor
@@ -66,7 +69,7 @@ public abstract class VAbstractPaintableWidget implements VPaintableWidget { this.connection = connection;
}
-// public boolean isEnabled() {
-// return enabled;
-// }
+ // public boolean isEnabled() {
+ // return enabled;
+ // }
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java b/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java index ed05a3e67d..b318fe0af3 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java @@ -104,6 +104,8 @@ public class VCalendarPanel extends FocusableFlexTable implements private static final String CN_SELECTED = "selected";
+ private static final String CN_OFFMONTH = "offmonth";
+
/**
* Represents a click handler for when a user selects a value by using the
* mouse
@@ -118,7 +120,7 @@ public class VCalendarPanel extends FocusableFlexTable implements */
public void onClick(ClickEvent event) {
Day day = (Day) event.getSource();
- focusDay(day.getDay());
+ focusDay(day.getDate());
selectFocused();
onSubmit();
}
@@ -152,6 +154,8 @@ public class VCalendarPanel extends FocusableFlexTable implements private boolean showISOWeekNumbers;
+ private Date displayedMonth;
+
private Date focusedDate;
private Day selectedDay;
@@ -191,18 +195,18 @@ public class VCalendarPanel extends FocusableFlexTable implements * Sets the focus to given day of current time. Used when moving in the
* calender with the keyboard.
*
- * @param day
+ * @param date
* The day number from by Date.getDate()
*/
- private void focusDay(int day) {
+ private void focusDay(Date day) {
// Only used when calender body is present
if (resolution > VDateField.RESOLUTION_MONTH) {
if (focusedDay != null) {
focusedDay.removeStyleDependentName(CN_FOCUSED);
}
- if (day > 0 && focusedDate != null) {
- focusedDate.setDate(day);
+ if (day != null && focusedDate != null) {
+ focusedDate.setTime(day.getTime());
int rowCount = days.getRowCount();
for (int i = 0; i < rowCount; i++) {
int cellCount = days.getCellCount(i);
@@ -210,7 +214,7 @@ public class VCalendarPanel extends FocusableFlexTable implements Widget widget = days.getWidget(i, j);
if (widget != null && widget instanceof Day) {
Day curday = (Day) widget;
- if (curday.getDay() == day) {
+ if (curday.getDate().equals(day)) {
curday.addStyleDependentName(CN_FOCUSED);
focusedDay = curday;
focusedRow = i;
@@ -226,9 +230,9 @@ public class VCalendarPanel extends FocusableFlexTable implements /**
* Sets the selection hightlight to a given date of current time
*
- * @param day
+ * @param date
*/
- private void selectDate(int day) {
+ private void selectDate(Date date) {
if (selectedDay != null) {
selectedDay.removeStyleDependentName(CN_SELECTED);
}
@@ -240,7 +244,7 @@ public class VCalendarPanel extends FocusableFlexTable implements Widget widget = days.getWidget(i, j);
if (widget != null && widget instanceof Day) {
Day curday = (Day) widget;
- if (curday.getDay() == day) {
+ if (curday.getDate().equals(date)) {
curday.addStyleDependentName(CN_SELECTED);
selectedDay = curday;
return;
@@ -279,7 +283,7 @@ public class VCalendarPanel extends FocusableFlexTable implements // it was forced to 1 above.
value.setDate(focusedDate.getDate());
- selectDate(focusedDate.getDate());
+ selectDate(focusedDate);
} else {
VConsole.log("Trying to select a the focused date which is NULL!");
}
@@ -468,97 +472,62 @@ public class VCalendarPanel extends FocusableFlexTable implements }
}
- // The day of month that is selected, -1 if no day of this month is
- // selected (i.e, showing another month/year than selected or nothing is
- // selected)
- int dayOfMonthSelected = -1;
- // The day of month that is today, -1 if no day of this month is today
- // (i.e., showing another month/year than current)
- int dayOfMonthToday = -1;
-
- boolean initiallyNull = value == null;
-
- if (!initiallyNull && value.getMonth() == focusedDate.getMonth()
- && value.getYear() == focusedDate.getYear()) {
- dayOfMonthSelected = value.getDate();
- }
- final Date today = new Date();
- if (today.getMonth() == focusedDate.getMonth()
- && today.getYear() == focusedDate.getYear()) {
- dayOfMonthToday = today.getDate();
- }
+ // today must have zeroed hours, minutes, seconds, and milliseconds
+ final Date tmp = new Date();
+ final Date today = new Date(tmp.getYear(), tmp.getMonth(),
+ tmp.getDate());
final int startWeekDay = getDateTimeService().getStartWeekDay(
focusedDate);
- final int daysInMonth = DateTimeService
- .getNumberOfDaysInMonth(focusedDate);
-
- int dayCount = 0;
- final Date curr = new Date(focusedDate.getTime());
+ final Date curr = (Date) focusedDate.clone();
+ // Start from the first day of the week that at least partially belongs
+ // to the current month
+ curr.setDate(-startWeekDay);
// No month has more than 6 weeks so 6 is a safe maximum for rows.
for (int weekOfMonth = 1; weekOfMonth < 7; weekOfMonth++) {
- boolean weekNumberProcessed[] = new boolean[] { false, false,
- false, false, false, false, false };
-
for (int dayOfWeek = 0; dayOfWeek < 7; dayOfWeek++) {
- if (!(weekOfMonth == 1 && dayOfWeek < startWeekDay)) {
-
- if (dayCount >= daysInMonth) {
- // All days printed and we are done
- break;
- }
-
- final int dayOfMonth = ++dayCount;
-
- curr.setDate(dayCount);
- // Actually write the day of month
- Day day = new Day(dayOfMonth);
+ // Actually write the day of month
+ Day day = new Day((Date) curr.clone());
- if (dayOfMonthSelected == dayOfMonth) {
- day.addStyleDependentName(CN_SELECTED);
- selectedDay = day;
+ if (curr.equals(value)) {
+ day.addStyleDependentName(CN_SELECTED);
+ selectedDay = day;
+ }
+ if (curr.equals(today)) {
+ day.addStyleDependentName(CN_TODAY);
+ }
+ if (curr.equals(focusedDate)) {
+ focusedDay = day;
+ focusedRow = weekOfMonth;
+ if (hasFocus) {
+ day.addStyleDependentName(CN_FOCUSED);
}
+ }
+ if (curr.getMonth() != focusedDate.getMonth()) {
+ day.addStyleDependentName(CN_OFFMONTH);
+ }
- if (dayOfMonthToday == dayOfMonth) {
- day.addStyleDependentName(CN_TODAY);
- }
+ days.setWidget(weekOfMonth, firstWeekdayColumn + dayOfWeek, day);
- if (dayOfMonth == focusedDate.getDate()) {
- focusedDay = day;
- focusedRow = weekOfMonth;
- if (hasFocus) {
- day.addStyleDependentName(CN_FOCUSED);
- }
- }
+ // ISO week numbers if requested
+ days.getCellFormatter().setVisible(weekOfMonth, weekColumn,
+ isShowISOWeekNumbers());
+ if (isShowISOWeekNumbers()) {
+ final String baseCssClass = VDateField.CLASSNAME
+ + "-calendarpanel-weeknumber";
+ String weekCssClass = baseCssClass;
- days.setWidget(weekOfMonth, firstWeekdayColumn + dayOfWeek,
- day);
-
- // ISO week numbers if requested
- if (!weekNumberProcessed[weekOfMonth]) {
- days.getCellFormatter().setVisible(weekOfMonth,
- weekColumn, isShowISOWeekNumbers());
- if (isShowISOWeekNumbers()) {
- final String baseCssClass = VDateField.CLASSNAME
- + "-calendarpanel-weeknumber";
- String weekCssClass = baseCssClass;
-
- int weekNumber = DateTimeService
- .getISOWeekNumber(curr);
-
- days.setHTML(weekOfMonth, 0, "<span class=\""
- + weekCssClass + "\"" + ">" + weekNumber
- + "</span>");
- weekNumberProcessed[weekOfMonth] = true;
- }
+ int weekNumber = DateTimeService.getISOWeekNumber(curr);
- }
+ days.setHTML(weekOfMonth, 0, "<span class=\""
+ + weekCssClass + "\"" + ">" + weekNumber
+ + "</span>");
}
+ curr.setDate(curr.getDate() + 1);
}
}
-
}
/**
@@ -622,6 +591,7 @@ public class VCalendarPanel extends FocusableFlexTable implements while (focusedDate.getMonth() != requestedMonth) {
focusedDate.setDate(focusedDate.getDate() - 1);
}
+ displayedMonth.setMonth(displayedMonth.getMonth() + 1);
renderCalendar();
}
@@ -641,6 +611,7 @@ public class VCalendarPanel extends FocusableFlexTable implements while (focusedDate.getMonth() == currentMonth) {
focusedDate.setDate(focusedDate.getDate() - 1);
}
+ displayedMonth.setMonth(displayedMonth.getMonth() - 1);
renderCalendar();
}
@@ -650,6 +621,7 @@ public class VCalendarPanel extends FocusableFlexTable implements */
private void focusPreviousYear(int years) {
focusedDate.setYear(focusedDate.getYear() - years);
+ displayedMonth.setYear(displayedMonth.getYear() - years);
renderCalendar();
}
@@ -658,6 +630,7 @@ public class VCalendarPanel extends FocusableFlexTable implements */
private void focusNextYear(int years) {
focusedDate.setYear(focusedDate.getYear() + years);
+ displayedMonth.setYear(displayedMonth.getYear() + years);
renderCalendar();
}
@@ -906,7 +879,7 @@ public class VCalendarPanel extends FocusableFlexTable implements if (newCurrentDate.getMonth() == focusedDate.getMonth()) {
// Month did not change, only move the selection
- focusDay(focusedDate.getDate() + 1);
+ focusDay(newCurrentDate);
} else {
// If the month changed we need to re-render the calendar
focusedDate.setDate(focusedDate.getDate() + 1);
@@ -925,7 +898,7 @@ public class VCalendarPanel extends FocusableFlexTable implements if (newCurrentDate.getMonth() == focusedDate.getMonth()) {
// Month did not change, only move the selection
- focusDay(focusedDate.getDate() - 1);
+ focusDay(newCurrentDate);
} else {
// If the month changed we need to re-render the calendar
focusedDate.setDate(focusedDate.getDate() - 1);
@@ -945,10 +918,10 @@ public class VCalendarPanel extends FocusableFlexTable implements if (newCurrentDate.getMonth() == focusedDate.getMonth()
&& focusedRow > 1) {
// Month did not change, only move the selection
- focusDay(focusedDate.getDate() - 7);
+ focusDay(newCurrentDate);
} else {
// If the month changed we need to re-render the calendar
- focusedDate.setDate(focusedDate.getDate() - 7);
+ focusedDate = newCurrentDate;
renderCalendar();
}
@@ -964,10 +937,10 @@ public class VCalendarPanel extends FocusableFlexTable implements if (newCurrentDate.getMonth() == focusedDate.getMonth()) {
// Month did not change, only move the selection
- focusDay(focusedDate.getDate() + 7);
+ focusDay(newCurrentDate);
} else {
// If the month changed we need to re-render the calendar
- focusedDate.setDate(focusedDate.getDate() + 7);
+ focusedDate = newCurrentDate;
renderCalendar();
}
@@ -1211,27 +1184,28 @@ public class VCalendarPanel extends FocusableFlexTable implements return;
}
- Date oldFocusedValue = focusedDate;
+ Date oldDisplayedMonth = displayedMonth;
value = currentDate;
if (value == null) {
- focusedDate = null;
+ focusedDate = displayedMonth = null;
} else {
focusedDate = (Date) value.clone();
+ displayedMonth = (Date) value.clone();
}
// Re-render calendar if month or year of focused date has changed
- if (oldFocusedValue == null || value == null
- || oldFocusedValue.getYear() != value.getYear()
- || oldFocusedValue.getMonth() != value.getMonth()) {
+ if (oldDisplayedMonth == null || value == null
+ || oldDisplayedMonth.getYear() != value.getYear()
+ || oldDisplayedMonth.getMonth() != value.getMonth()) {
renderCalendar();
} else {
- focusDay(currentDate.getDate());
+ focusDay(currentDate);
selectFocused();
}
if (!hasFocus) {
- focusDay(-1);
+ focusDay((Date) null);
}
}
@@ -1512,17 +1486,17 @@ public class VCalendarPanel extends FocusableFlexTable implements private class Day extends InlineHTML {
private static final String BASECLASS = VDateField.CLASSNAME
+ "-calendarpanel-day";
- private final int day;
+ private final Date date;
- Day(int dayOfMonth) {
- super("" + dayOfMonth);
+ Day(Date date) {
+ super("" + date.getDate());
setStyleName(BASECLASS);
- day = dayOfMonth;
+ this.date = date;
addClickHandler(dayClickHandler);
}
- public int getDay() {
- return day;
+ public Date getDate() {
+ return date;
}
}
@@ -1605,7 +1579,7 @@ public class VCalendarPanel extends FocusableFlexTable implements public void onBlur(final BlurEvent event) {
if (event.getSource() instanceof VCalendarPanel) {
hasFocus = false;
- focusDay(-1);
+ focusDay(null);
}
}
@@ -1622,7 +1596,7 @@ public class VCalendarPanel extends FocusableFlexTable implements // Focuses the current day if the calendar shows the days
if (focusedDay != null) {
- focusDay(focusedDay.getDay());
+ focusDay(focusedDate);
}
}
}
@@ -1653,7 +1627,15 @@ public class VCalendarPanel extends FocusableFlexTable implements // Day, find out which dayOfMonth and use that as the identifier
Day day = Util.findWidget(subElement, Day.class);
if (day != null) {
- return SUBPART_DAY + day.getDay();
+ Date date = day.getDate();
+ int id = date.getDate();
+ if (date.getMonth() < displayedMonth.getMonth()) {
+ id -= DateTimeService.getNumberOfDaysInMonth(date);
+ } else if (date.getMonth() > displayedMonth.getMonth()) {
+ id += DateTimeService
+ .getNumberOfDaysInMonth(displayedMonth);
+ }
+ return SUBPART_DAY + id;
}
} else if (time != null) {
if (contains(time.hours, subElement)) {
@@ -1714,14 +1696,18 @@ public class VCalendarPanel extends FocusableFlexTable implements return time.ampm.getElement();
}
if (subPart.startsWith(SUBPART_DAY)) {
+ // can be less than 1 or greater than the number of days in the current month
+ // these map to the "off-month" days
int dayOfMonth = Integer.parseInt(subPart.substring(SUBPART_DAY
.length()));
+ Date date = new Date(displayedMonth.getYear(),
+ displayedMonth.getMonth(), dayOfMonth);
Iterator<Widget> iter = days.iterator();
while (iter.hasNext()) {
Widget w = iter.next();
if (w instanceof Day) {
Day day = (Day) w;
- if (day.getDay() == dayOfMonth) {
+ if (day.getDate().equals(date)) {
return day.getElement();
}
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VFormLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VFormLayout.java index 6d068dd11a..e6305b3c42 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VFormLayout.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VFormLayout.java @@ -117,8 +117,7 @@ public class VFormLayout extends SimplePanel implements Container { Widget childWidget = childPaintable.getWidgetForPaintable(); Caption caption = widgetToCaption.get(childWidget); if (caption == null) { - caption = new Caption(childPaintable, client, - getStylesFromUIDL(childUidl)); + caption = new Caption(childPaintable, client); caption.addClickHandler(this); widgetToCaption.put(childWidget, caption); } @@ -208,8 +207,7 @@ public class VFormLayout extends SimplePanel implements Container { VPaintableWidget newPaintable = paintableMap .getPaintable(newComponent); Caption oldCap = widgetToCaption.get(oldComponent); - final Caption newCap = new Caption(newPaintable, client, - null); + final Caption newCap = new Caption(newPaintable, client); newCap.addClickHandler(this); newCap.setStyleName(oldCap.getStyleName()); widgetToCaption.put(newComponent, newCap); @@ -333,29 +331,37 @@ public class VFormLayout extends SimplePanel implements Container { * return null * @param client */ - public Caption(VPaintableWidget component, - ApplicationConnection client, String[] styles) { + public Caption(VPaintableWidget component, ApplicationConnection client) { super(); this.client = client; owner = component; - String style = CLASSNAME; + sinkEvents(VTooltip.TOOLTIP_EVENTS); + } + + private void setStyles(String[] styles) { + String styleName = CLASSNAME; + if (styles != null) { - for (int i = 0; i < styles.length; i++) { - style += " " + CLASSNAME + "-" + styles[i]; + for (String style : styles) { + if (ApplicationConnection.DISABLED_CLASSNAME.equals(style)) { + // Add v-disabled also without classname prefix so + // generic v-disabled CSS rules work + styleName += " " + style; + } + + styleName += " " + CLASSNAME + "-" + style; } } - setStyleName(style); - sinkEvents(VTooltip.TOOLTIP_EVENTS); + setStyleName(styleName); } public void updateCaption(UIDL uidl) { setVisible(!uidl.getBooleanAttribute("invisible")); - setStyleName(getElement(), - ApplicationConnection.DISABLED_CLASSNAME, - uidl.hasAttribute("disabled")); + // Update styles as they might have changed when the caption changed + setStyles(getStylesFromUIDL(uidl)); boolean isEmpty = true; diff --git a/src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java b/src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java index 372ddf25d2..c39155d032 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java @@ -1420,8 +1420,4 @@ public class VMenuBar extends SimpleFocusablePanel implements return null; } - public Widget getWidgetForPaintable() { - return this; - } - } diff --git a/src/com/vaadin/terminal/gwt/client/ui/VMenuBarPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VMenuBarPaintable.java index 38b3cac358..fabc77bced 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VMenuBarPaintable.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VMenuBarPaintable.java @@ -1,3 +1,6 @@ +/*
+@VaadinApache2LicenseForJavaFiles@
+ */
package com.vaadin.terminal.gwt.client.ui;
import java.util.Iterator;
@@ -9,7 +12,6 @@ import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
-import com.vaadin.terminal.gwt.client.VPaintableMap;
import com.vaadin.terminal.gwt.client.ui.VMenuBar.CustomMenuItem;
public class VMenuBarPaintable extends VAbstractPaintableWidget {
@@ -66,12 +68,10 @@ public class VMenuBarPaintable extends VAbstractPaintableWidget { getWidgetForPaintable().moreItem = GWT.create(CustomMenuItem.class);
getWidgetForPaintable().moreItem.setHTML(itemHTML.toString());
- getWidgetForPaintable().moreItem
- .setCommand(getWidgetForPaintable().emptyCommand);
+ getWidgetForPaintable().moreItem.setCommand(VMenuBar.emptyCommand);
getWidgetForPaintable().collapsedRootItems = new VMenuBar(true,
- (VMenuBar) VPaintableMap.get(client).getPaintable(
- getWidgetForPaintable().uidlId));
+ getWidgetForPaintable());
getWidgetForPaintable().moreItem
.setSubMenu(getWidgetForPaintable().collapsedRootItems);
getWidgetForPaintable().moreItem.addStyleName(VMenuBar.CLASSNAME
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java b/src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java index 7de1658c5d..44fb9ac69c 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java @@ -1,462 +1,474 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import java.util.Date; - -import com.google.gwt.core.client.GWT; -import com.google.gwt.event.dom.client.ClickEvent; -import com.google.gwt.event.dom.client.ClickHandler; -import com.google.gwt.event.dom.client.DomEvent; -import com.google.gwt.event.dom.client.KeyCodes; -import com.google.gwt.event.logical.shared.CloseEvent; -import com.google.gwt.event.logical.shared.CloseHandler; -import com.google.gwt.user.client.DOM; -import com.google.gwt.user.client.Element; -import com.google.gwt.user.client.Event; -import com.google.gwt.user.client.Timer; -import com.google.gwt.user.client.Window; -import com.google.gwt.user.client.ui.Button; -import com.google.gwt.user.client.ui.PopupPanel; -import com.google.gwt.user.client.ui.PopupPanel.PositionCallback; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.DateTimeService; -import com.vaadin.terminal.gwt.client.VPaintableWidget; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.VConsole; -import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.FocusChangeListener; -import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.FocusOutListener; -import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.SubmitListener; -import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.TimeChangeListener; - -/** - * Represents a date selection component with a text field and a popup date - * selector. - * - * <b>Note:</b> To change the keyboard assignments used in the popup dialog you - * should extend <code>com.vaadin.terminal.gwt.client.ui.VCalendarPanel</code> - * and then pass set it by calling the - * <code>setCalendarPanel(VCalendarPanel panel)</code> method. - * - */ -public class VPopupCalendar extends VTextualDate implements VPaintableWidget, - Field, ClickHandler, CloseHandler<PopupPanel>, SubPartAware { - - private final Button calendarToggle; - - private VCalendarPanel calendar; - - private final VOverlay popup; - private boolean open = false; - private boolean parsable = true; - - public VPopupCalendar() { - super(); - - calendarToggle = new Button(); - calendarToggle.setStyleName(CLASSNAME + "-button"); - calendarToggle.setText(""); - calendarToggle.addClickHandler(this); - // -2 instead of -1 to avoid FocusWidget.onAttach to reset it - calendarToggle.getElement().setTabIndex(-2); - add(calendarToggle); - - calendar = GWT.create(VCalendarPanel.class); - calendar.setFocusOutListener(new FocusOutListener() { - public boolean onFocusOut(DomEvent<?> event) { - event.preventDefault(); - closeCalendarPanel(); - return true; - } - }); - - calendar.setSubmitListener(new SubmitListener() { - public void onSubmit() { - // Update internal value and send valuechange event if immediate - updateValue(calendar.getDate()); - - // Update text field (a must when not immediate). - buildDate(true); - - closeCalendarPanel(); - } - - public void onCancel() { - closeCalendarPanel(); - } - }); - - popup = new VOverlay(true, true, true); - popup.setStyleName(VDateField.CLASSNAME + "-popup"); - popup.setWidget(calendar); - popup.addCloseHandler(this); - - DOM.setElementProperty(calendar.getElement(), "id", - "PID_VAADIN_POPUPCAL"); - - sinkEvents(Event.ONKEYDOWN); - - } - - @SuppressWarnings("deprecation") - private void updateValue(Date newDate) { - Date currentDate = getCurrentDate(); - if (currentDate == null || newDate.getTime() != currentDate.getTime()) { - setCurrentDate((Date) newDate.clone()); - getClient().updateVariable(getId(), "year", - newDate.getYear() + 1900, false); - if (getCurrentResolution() > VDateField.RESOLUTION_YEAR) { - getClient().updateVariable(getId(), "month", - newDate.getMonth() + 1, false); - if (getCurrentResolution() > RESOLUTION_MONTH) { - getClient().updateVariable(getId(), "day", - newDate.getDate(), false); - if (getCurrentResolution() > RESOLUTION_DAY) { - getClient().updateVariable(getId(), "hour", - newDate.getHours(), false); - if (getCurrentResolution() > RESOLUTION_HOUR) { - getClient().updateVariable(getId(), "min", - newDate.getMinutes(), false); - if (getCurrentResolution() > RESOLUTION_MIN) { - getClient().updateVariable(getId(), "sec", - newDate.getSeconds(), false); - } - } - } - } - } - if (isImmediate()) { - getClient().sendPendingVariableChanges(); - } - } - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.terminal.gwt.client.ui.VTextualDate#updateFromUIDL(com.vaadin - * .terminal.gwt.client.UIDL, - * com.vaadin.terminal.gwt.client.ApplicationConnection) - */ - @Override - @SuppressWarnings("deprecation") - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - boolean lastReadOnlyState = readonly; - parsable = uidl.getBooleanAttribute("parsable"); - - super.updateFromUIDL(uidl, client); - - popup.setStyleName(VDateField.CLASSNAME + "-popup " - + VDateField.CLASSNAME + "-" - + resolutionToString(currentResolution)); - calendar.setDateTimeService(getDateTimeService()); - calendar.setShowISOWeekNumbers(isShowISOWeekNumbers()); - if (calendar.getResolution() != currentResolution) { - calendar.setResolution(currentResolution); - if (calendar.getDate() != null) { - calendar.setDate((Date) getCurrentDate().clone()); - // force re-render when changing resolution only - calendar.renderCalendar(); - } - } - calendarToggle.setEnabled(enabled); - - if (currentResolution <= RESOLUTION_MONTH) { - calendar.setFocusChangeListener(new FocusChangeListener() { - public void focusChanged(Date date) { - updateValue(date); - buildDate(); - Date date2 = calendar.getDate(); - date2.setYear(date.getYear()); - date2.setMonth(date.getMonth()); - } - }); - } else { - calendar.setFocusChangeListener(null); - } - - if (currentResolution > RESOLUTION_DAY) { - calendar.setTimeChangeListener(new TimeChangeListener() { - public void changed(int hour, int min, int sec, int msec) { - Date d = getDate(); - if (d == null) { - // date currently null, use the value from calendarPanel - // (~ client time at the init of the widget) - d = (Date) calendar.getDate().clone(); - } - d.setHours(hour); - d.setMinutes(min); - d.setSeconds(sec); - DateTimeService.setMilliseconds(d, msec); - - // Always update time changes to the server - updateValue(d); - - // Update text field - buildDate(); - } - }); - } - - if (readonly) { - calendarToggle.addStyleName(CLASSNAME + "-button-readonly"); - } else { - calendarToggle.removeStyleName(CLASSNAME + "-button-readonly"); - } - - if (lastReadOnlyState != readonly) { - updateWidth(); - } - - calendarToggle.setEnabled(true); - } - - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.user.client.ui.UIObject#setStyleName(java.lang.String) - */ - @Override - public void setStyleName(String style) { - // make sure the style is there before size calculation - super.setStyleName(style + " " + CLASSNAME + "-popupcalendar"); - } - - /** - * Opens the calendar panel popup - */ - public void openCalendarPanel() { - - if (!open && !readonly) { - open = true; - - if (getCurrentDate() != null) { - calendar.setDate((Date) getCurrentDate().clone()); - } else { - calendar.setDate(new Date()); - } - - // clear previous values - popup.setWidth(""); - popup.setHeight(""); - popup.setPopupPositionAndShow(new PositionCallback() { - public void setPosition(int offsetWidth, int offsetHeight) { - final int w = offsetWidth; - final int h = offsetHeight; - final int browserWindowWidth = Window.getClientWidth() - + Window.getScrollLeft(); - final int browserWindowHeight = Window.getClientHeight() - + Window.getScrollTop(); - int t = calendarToggle.getAbsoluteTop(); - int l = calendarToggle.getAbsoluteLeft(); - - // Add a little extra space to the right to avoid - // problems with IE7 scrollbars and to make it look - // nicer. - int extraSpace = 30; - - boolean overflowRight = false; - if (l + +w + extraSpace > browserWindowWidth) { - overflowRight = true; - // Part of the popup is outside the browser window - // (to the right) - l = browserWindowWidth - w - extraSpace; - } - - if (t + h + calendarToggle.getOffsetHeight() + 30 > browserWindowHeight) { - // Part of the popup is outside the browser window - // (below) - t = browserWindowHeight - h - - calendarToggle.getOffsetHeight() - 30; - if (!overflowRight) { - // Show to the right of the popup button unless we - // are in the lower right corner of the screen - l += calendarToggle.getOffsetWidth(); - } - } - - // fix size - popup.setWidth(w + "px"); - popup.setHeight(h + "px"); - - popup.setPopupPosition(l, - t + calendarToggle.getOffsetHeight() + 2); - - /* - * We have to wait a while before focusing since the popup - * needs to be opened before we can focus - */ - Timer focusTimer = new Timer() { - @Override - public void run() { - setFocus(true); - } - }; - - focusTimer.schedule(100); - } - }); - } else { - VConsole.error("Cannot reopen popup, it is already open!"); - } - } - - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt.event - * .dom.client.ClickEvent) - */ - public void onClick(ClickEvent event) { - if (event.getSource() == calendarToggle && isEnabled()) { - openCalendarPanel(); - } - } - - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.event.logical.shared.CloseHandler#onClose(com.google.gwt - * .event.logical.shared.CloseEvent) - */ - public void onClose(CloseEvent<PopupPanel> event) { - if (event.getSource() == popup) { - buildDate(); - if (!BrowserInfo.get().isTouchDevice()) { - /* - * Move focus to textbox, unless on touch device (avoids opening - * virtual keyboard). - */ - focus(); - } - - // TODO resolve what the "Sigh." is all about and document it here - // Sigh. - Timer t = new Timer() { - @Override - public void run() { - open = false; - } - }; - t.schedule(100); - } - } - - /** - * Sets focus to Calendar panel. - * - * @param focus - */ - public void setFocus(boolean focus) { - calendar.setFocus(focus); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.gwt.client.ui.VTextualDate#getFieldExtraWidth() - */ - @Override - protected int getFieldExtraWidth() { - if (fieldExtraWidth < 0) { - fieldExtraWidth = super.getFieldExtraWidth(); - fieldExtraWidth += calendarToggle.getOffsetWidth(); - } - return fieldExtraWidth; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.gwt.client.ui.VTextualDate#buildDate() - */ - @Override - protected void buildDate() { - // Save previous value - String previousValue = getText(); - super.buildDate(); - - // Restore previous value if the input could not be parsed - if (!parsable) { - setText(previousValue); - } - } - - /** - * Update the text field contents from the date. See {@link #buildDate()}. - * - * @param forceValid - * true to force the text field to be updated, false to only - * update if the parsable flag is true. - */ - protected void buildDate(boolean forceValid) { - if (forceValid) { - parsable = true; - } - buildDate(); - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.terminal.gwt.client.ui.VDateField#onBrowserEvent(com.google - * .gwt.user.client.Event) - */ - @Override - public void onBrowserEvent(com.google.gwt.user.client.Event event) { - super.onBrowserEvent(event); - if (DOM.eventGetType(event) == Event.ONKEYDOWN - && event.getKeyCode() == getOpenCalenderPanelKey()) { - openCalendarPanel(); - event.preventDefault(); - } - } - - /** - * Get the key code that opens the calendar panel. By default it is the down - * key but you can override this to be whatever you like - * - * @return - */ - protected int getOpenCalenderPanelKey() { - return KeyCodes.KEY_DOWN; - } - - /** - * Closes the open popup panel - */ - public void closeCalendarPanel() { - if (open) { - popup.hide(true); - } - } - - private final String CALENDAR_TOGGLE_ID = "popupButton"; - - @Override - public Element getSubPartElement(String subPart) { - if (subPart.equals(CALENDAR_TOGGLE_ID)) { - return calendarToggle.getElement(); - } - - return super.getSubPartElement(subPart); - } - - @Override - public String getSubPartName(Element subElement) { - if (calendarToggle.getElement().isOrHasChild(subElement)) { - return CALENDAR_TOGGLE_ID; - } - - return super.getSubPartName(subElement); - } - -} +/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.Date;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.DomEvent;
+import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.event.logical.shared.CloseEvent;
+import com.google.gwt.event.logical.shared.CloseHandler;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.Timer;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.PopupPanel;
+import com.google.gwt.user.client.ui.PopupPanel.PositionCallback;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.DateTimeService;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.VConsole;
+import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.FocusChangeListener;
+import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.FocusOutListener;
+import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.SubmitListener;
+import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.TimeChangeListener;
+
+/**
+ * Represents a date selection component with a text field and a popup date
+ * selector.
+ *
+ * <b>Note:</b> To change the keyboard assignments used in the popup dialog you
+ * should extend <code>com.vaadin.terminal.gwt.client.ui.VCalendarPanel</code>
+ * and then pass set it by calling the
+ * <code>setCalendarPanel(VCalendarPanel panel)</code> method.
+ *
+ */
+public class VPopupCalendar extends VTextualDate implements VPaintableWidget,
+ Field, ClickHandler, CloseHandler<PopupPanel>, SubPartAware {
+
+ private static final String POPUP_PRIMARY_STYLE_NAME = VDateField.CLASSNAME
+ + "-popup";
+
+ private final Button calendarToggle;
+
+ private VCalendarPanel calendar;
+
+ private final VOverlay popup;
+ private boolean open = false;
+ private boolean parsable = true;
+
+ public VPopupCalendar() {
+ super();
+
+ calendarToggle = new Button();
+ calendarToggle.setStyleName(CLASSNAME + "-button");
+ calendarToggle.setText("");
+ calendarToggle.addClickHandler(this);
+ // -2 instead of -1 to avoid FocusWidget.onAttach to reset it
+ calendarToggle.getElement().setTabIndex(-2);
+ add(calendarToggle);
+
+ calendar = GWT.create(VCalendarPanel.class);
+ calendar.setFocusOutListener(new FocusOutListener() {
+ public boolean onFocusOut(DomEvent<?> event) {
+ event.preventDefault();
+ closeCalendarPanel();
+ return true;
+ }
+ });
+
+ calendar.setSubmitListener(new SubmitListener() {
+ public void onSubmit() {
+ // Update internal value and send valuechange event if immediate
+ updateValue(calendar.getDate());
+
+ // Update text field (a must when not immediate).
+ buildDate(true);
+
+ closeCalendarPanel();
+ }
+
+ public void onCancel() {
+ closeCalendarPanel();
+ }
+ });
+
+ popup = new VOverlay(true, true, true);
+ popup.setStyleName(POPUP_PRIMARY_STYLE_NAME);
+ popup.setWidget(calendar);
+ popup.addCloseHandler(this);
+
+ DOM.setElementProperty(calendar.getElement(), "id",
+ "PID_VAADIN_POPUPCAL");
+
+ sinkEvents(Event.ONKEYDOWN);
+
+ }
+
+ @SuppressWarnings("deprecation")
+ private void updateValue(Date newDate) {
+ Date currentDate = getCurrentDate();
+ if (currentDate == null || newDate.getTime() != currentDate.getTime()) {
+ setCurrentDate((Date) newDate.clone());
+ getClient().updateVariable(getId(), "year",
+ newDate.getYear() + 1900, false);
+ if (getCurrentResolution() > VDateField.RESOLUTION_YEAR) {
+ getClient().updateVariable(getId(), "month",
+ newDate.getMonth() + 1, false);
+ if (getCurrentResolution() > RESOLUTION_MONTH) {
+ getClient().updateVariable(getId(), "day",
+ newDate.getDate(), false);
+ if (getCurrentResolution() > RESOLUTION_DAY) {
+ getClient().updateVariable(getId(), "hour",
+ newDate.getHours(), false);
+ if (getCurrentResolution() > RESOLUTION_HOUR) {
+ getClient().updateVariable(getId(), "min",
+ newDate.getMinutes(), false);
+ if (getCurrentResolution() > RESOLUTION_MIN) {
+ getClient().updateVariable(getId(), "sec",
+ newDate.getSeconds(), false);
+ }
+ }
+ }
+ }
+ }
+ if (isImmediate()) {
+ getClient().sendPendingVariableChanges();
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.terminal.gwt.client.ui.VTextualDate#updateFromUIDL(com.vaadin
+ * .terminal.gwt.client.UIDL,
+ * com.vaadin.terminal.gwt.client.ApplicationConnection)
+ */
+ @Override
+ @SuppressWarnings("deprecation")
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ boolean lastReadOnlyState = readonly;
+ boolean lastEnabledState = isEnabled();
+
+ parsable = uidl.getBooleanAttribute("parsable");
+
+ super.updateFromUIDL(uidl, client);
+
+ String popupStyleNames = ApplicationConnection.getStyleName(
+ POPUP_PRIMARY_STYLE_NAME, uidl, false);
+ popupStyleNames += " " + VDateField.CLASSNAME + "-"
+ + resolutionToString(currentResolution);
+ popup.setStyleName(popupStyleNames);
+
+ calendar.setDateTimeService(getDateTimeService());
+ calendar.setShowISOWeekNumbers(isShowISOWeekNumbers());
+ if (calendar.getResolution() != currentResolution) {
+ calendar.setResolution(currentResolution);
+ if (calendar.getDate() != null) {
+ calendar.setDate((Date) getCurrentDate().clone());
+ // force re-render when changing resolution only
+ calendar.renderCalendar();
+ }
+ }
+ calendarToggle.setEnabled(enabled);
+
+ if (currentResolution <= RESOLUTION_MONTH) {
+ calendar.setFocusChangeListener(new FocusChangeListener() {
+ public void focusChanged(Date date) {
+ updateValue(date);
+ buildDate();
+ Date date2 = calendar.getDate();
+ date2.setYear(date.getYear());
+ date2.setMonth(date.getMonth());
+ }
+ });
+ } else {
+ calendar.setFocusChangeListener(null);
+ }
+
+ if (currentResolution > RESOLUTION_DAY) {
+ calendar.setTimeChangeListener(new TimeChangeListener() {
+ public void changed(int hour, int min, int sec, int msec) {
+ Date d = getDate();
+ if (d == null) {
+ // date currently null, use the value from calendarPanel
+ // (~ client time at the init of the widget)
+ d = (Date) calendar.getDate().clone();
+ }
+ d.setHours(hour);
+ d.setMinutes(min);
+ d.setSeconds(sec);
+ DateTimeService.setMilliseconds(d, msec);
+
+ // Always update time changes to the server
+ updateValue(d);
+
+ // Update text field
+ buildDate();
+ }
+ });
+ }
+
+ if (readonly) {
+ calendarToggle.addStyleName(CLASSNAME + "-button-readonly");
+ } else {
+ calendarToggle.removeStyleName(CLASSNAME + "-button-readonly");
+ }
+
+ if (lastReadOnlyState != readonly || lastEnabledState != isEnabled()) {
+ // Enabled or readonly state changed. Differences in theming might
+ // affect the width (for instance if the popup button is hidden) so
+ // we have to recalculate the width (IF the width of the field is
+ // fixed)
+ updateWidth();
+ }
+
+ calendarToggle.setEnabled(true);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.google.gwt.user.client.ui.UIObject#setStyleName(java.lang.String)
+ */
+ @Override
+ public void setStyleName(String style) {
+ // make sure the style is there before size calculation
+ super.setStyleName(style + " " + CLASSNAME + "-popupcalendar");
+ }
+
+ /**
+ * Opens the calendar panel popup
+ */
+ public void openCalendarPanel() {
+
+ if (!open && !readonly) {
+ open = true;
+
+ if (getCurrentDate() != null) {
+ calendar.setDate((Date) getCurrentDate().clone());
+ } else {
+ calendar.setDate(new Date());
+ }
+
+ // clear previous values
+ popup.setWidth("");
+ popup.setHeight("");
+ popup.setPopupPositionAndShow(new PositionCallback() {
+ public void setPosition(int offsetWidth, int offsetHeight) {
+ final int w = offsetWidth;
+ final int h = offsetHeight;
+ final int browserWindowWidth = Window.getClientWidth()
+ + Window.getScrollLeft();
+ final int browserWindowHeight = Window.getClientHeight()
+ + Window.getScrollTop();
+ int t = calendarToggle.getAbsoluteTop();
+ int l = calendarToggle.getAbsoluteLeft();
+
+ // Add a little extra space to the right to avoid
+ // problems with IE7 scrollbars and to make it look
+ // nicer.
+ int extraSpace = 30;
+
+ boolean overflowRight = false;
+ if (l + +w + extraSpace > browserWindowWidth) {
+ overflowRight = true;
+ // Part of the popup is outside the browser window
+ // (to the right)
+ l = browserWindowWidth - w - extraSpace;
+ }
+
+ if (t + h + calendarToggle.getOffsetHeight() + 30 > browserWindowHeight) {
+ // Part of the popup is outside the browser window
+ // (below)
+ t = browserWindowHeight - h
+ - calendarToggle.getOffsetHeight() - 30;
+ if (!overflowRight) {
+ // Show to the right of the popup button unless we
+ // are in the lower right corner of the screen
+ l += calendarToggle.getOffsetWidth();
+ }
+ }
+
+ // fix size
+ popup.setWidth(w + "px");
+ popup.setHeight(h + "px");
+
+ popup.setPopupPosition(l,
+ t + calendarToggle.getOffsetHeight() + 2);
+
+ /*
+ * We have to wait a while before focusing since the popup
+ * needs to be opened before we can focus
+ */
+ Timer focusTimer = new Timer() {
+ @Override
+ public void run() {
+ setFocus(true);
+ }
+ };
+
+ focusTimer.schedule(100);
+ }
+ });
+ } else {
+ VConsole.error("Cannot reopen popup, it is already open!");
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt.event
+ * .dom.client.ClickEvent)
+ */
+ public void onClick(ClickEvent event) {
+ if (event.getSource() == calendarToggle && isEnabled()) {
+ openCalendarPanel();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.google.gwt.event.logical.shared.CloseHandler#onClose(com.google.gwt
+ * .event.logical.shared.CloseEvent)
+ */
+ public void onClose(CloseEvent<PopupPanel> event) {
+ if (event.getSource() == popup) {
+ buildDate();
+ if (!BrowserInfo.get().isTouchDevice()) {
+ /*
+ * Move focus to textbox, unless on touch device (avoids opening
+ * virtual keyboard).
+ */
+ focus();
+ }
+
+ // TODO resolve what the "Sigh." is all about and document it here
+ // Sigh.
+ Timer t = new Timer() {
+ @Override
+ public void run() {
+ open = false;
+ }
+ };
+ t.schedule(100);
+ }
+ }
+
+ /**
+ * Sets focus to Calendar panel.
+ *
+ * @param focus
+ */
+ public void setFocus(boolean focus) {
+ calendar.setFocus(focus);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.terminal.gwt.client.ui.VTextualDate#getFieldExtraWidth()
+ */
+ @Override
+ protected int getFieldExtraWidth() {
+ if (fieldExtraWidth < 0) {
+ fieldExtraWidth = super.getFieldExtraWidth();
+ fieldExtraWidth += calendarToggle.getOffsetWidth();
+ }
+ return fieldExtraWidth;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.terminal.gwt.client.ui.VTextualDate#buildDate()
+ */
+ @Override
+ protected void buildDate() {
+ // Save previous value
+ String previousValue = getText();
+ super.buildDate();
+
+ // Restore previous value if the input could not be parsed
+ if (!parsable) {
+ setText(previousValue);
+ }
+ }
+
+ /**
+ * Update the text field contents from the date. See {@link #buildDate()}.
+ *
+ * @param forceValid
+ * true to force the text field to be updated, false to only
+ * update if the parsable flag is true.
+ */
+ protected void buildDate(boolean forceValid) {
+ if (forceValid) {
+ parsable = true;
+ }
+ buildDate();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.terminal.gwt.client.ui.VDateField#onBrowserEvent(com.google
+ * .gwt.user.client.Event)
+ */
+ @Override
+ public void onBrowserEvent(com.google.gwt.user.client.Event event) {
+ super.onBrowserEvent(event);
+ if (DOM.eventGetType(event) == Event.ONKEYDOWN
+ && event.getKeyCode() == getOpenCalenderPanelKey()) {
+ openCalendarPanel();
+ event.preventDefault();
+ }
+ }
+
+ /**
+ * Get the key code that opens the calendar panel. By default it is the down
+ * key but you can override this to be whatever you like
+ *
+ * @return
+ */
+ protected int getOpenCalenderPanelKey() {
+ return KeyCodes.KEY_DOWN;
+ }
+
+ /**
+ * Closes the open popup panel
+ */
+ public void closeCalendarPanel() {
+ if (open) {
+ popup.hide(true);
+ }
+ }
+
+ private final String CALENDAR_TOGGLE_ID = "popupButton";
+
+ @Override
+ public Element getSubPartElement(String subPart) {
+ if (subPart.equals(CALENDAR_TOGGLE_ID)) {
+ return calendarToggle.getElement();
+ }
+
+ return super.getSubPartElement(subPart);
+ }
+
+ @Override
+ public String getSubPartName(Element subElement) {
+ if (calendarToggle.getElement().isOrHasChild(subElement)) {
+ return CALENDAR_TOGGLE_ID;
+ }
+
+ return super.getSubPartName(subElement);
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java b/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java index 41b7efcf02..de68ae96a4 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java @@ -2105,26 +2105,16 @@ public class VScrollTable extends FlowPanel implements HasWidgets, * of the caption container element by the correct amount */ public void resizeCaptionContainer(int rightSpacing) { + int captionContainerWidth = width + - colResizeWidget.getOffsetWidth() - rightSpacing; + if (td.getClassName().contains("-asc") || td.getClassName().contains("-desc")) { - /* - * Room for the sort indicator is made by subtracting the styled - * margin and width of the resizer from the width of the caption - * container. - */ - int captionContainerWidth = width - - sortIndicator.getOffsetWidth() - - colResizeWidget.getOffsetWidth() - rightSpacing; - captionContainer.getStyle().setPropertyPx("width", - captionContainerWidth); - } else { - /* - * Set the caption container element as wide as possible when - * the sorting indicator is not visible. - */ - captionContainer.getStyle().setPropertyPx("width", - width - rightSpacing); + // Leave room for the sort indicator + captionContainerWidth -= sortIndicator.getOffsetWidth(); } + captionContainer.getStyle().setPropertyPx("width", + captionContainerWidth); // Apply/Remove spacing if defined if (rightSpacing > 0) { @@ -5882,7 +5872,15 @@ public class VScrollTable extends FlowPanel implements HasWidgets, public void onScroll(ScrollEvent event) { scrollLeft = scrollBodyPanel.getElement().getScrollLeft(); scrollTop = scrollBodyPanel.getScrollPosition(); - if (!initializedAndAttached) { + /* + * #6970 - IE sometimes fires scroll events for a detached table. + * + * FIXME initializedAndAttached should probably be renamed - its name + * doesn't seem to reflect its semantics. onDetach() doesn't set it to + * false, and changing that might break something else, so we need to + * check isAttached() separately. + */ + if (!initializedAndAttached || !isAttached()) { return; } if (!enabled) { diff --git a/src/com/vaadin/terminal/gwt/client/ui/VScrollTablePaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VScrollTablePaintable.java index c747a29a21..fa7cc3d4ec 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VScrollTablePaintable.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VScrollTablePaintable.java @@ -1,3 +1,6 @@ +/*
+@VaadinApache2LicenseForJavaFiles@
+ */
package com.vaadin.terminal.gwt.client.ui;
import com.google.gwt.core.client.GWT;
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VSlider.java b/src/com/vaadin/terminal/gwt/client/ui/VSlider.java index 6b55fa0802..3632e90956 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VSlider.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VSlider.java @@ -1,573 +1,569 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -// -package com.vaadin.terminal.gwt.client.ui; - -import com.google.gwt.core.client.Scheduler; -import com.google.gwt.core.client.Scheduler.ScheduledCommand; -import com.google.gwt.event.dom.client.KeyCodes; -import com.google.gwt.user.client.Command; -import com.google.gwt.user.client.DOM; -import com.google.gwt.user.client.Element; -import com.google.gwt.user.client.Event; -import com.google.gwt.user.client.Window; -import com.google.gwt.user.client.ui.HTML; -import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.ContainerResizedListener; -import com.vaadin.terminal.gwt.client.VPaintableWidget; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.Util; -import com.vaadin.terminal.gwt.client.VConsole; - -public class VSlider extends SimpleFocusablePanel implements VPaintableWidget, - Field, ContainerResizedListener { - - public static final String CLASSNAME = "v-slider"; - - /** - * Minimum size (width or height, depending on orientation) of the slider - * base. - */ - private static final int MIN_SIZE = 50; - - ApplicationConnection client; - - String id; - - private boolean immediate; - private boolean disabled; - private boolean readonly; - - private int acceleration = 1; - private double min; - private double max; - private int resolution; - private Double value; - private boolean vertical; - - private final HTML feedback = new HTML("", false); - private final VOverlay feedbackPopup = new VOverlay(true, false, true) { - @Override - public void show() { - super.show(); - updateFeedbackPosition(); - } - }; - - /* DOM element for slider's base */ - private final Element base; - private final int BASE_BORDER_WIDTH = 1; - - /* DOM element for slider's handle */ - private final Element handle; - - /* DOM element for decrement arrow */ - private final Element smaller; - - /* DOM element for increment arrow */ - private final Element bigger; - - /* Temporary dragging/animation variables */ - private boolean dragging = false; - - private VLazyExecutor delayedValueUpdater = new VLazyExecutor(100, - new ScheduledCommand() { - - public void execute() { - updateValueToServer(); - acceleration = 1; - } - }); - - public VSlider() { - super(); - - base = DOM.createDiv(); - handle = DOM.createDiv(); - smaller = DOM.createDiv(); - bigger = DOM.createDiv(); - - setStyleName(CLASSNAME); - DOM.setElementProperty(base, "className", CLASSNAME + "-base"); - DOM.setElementProperty(handle, "className", CLASSNAME + "-handle"); - DOM.setElementProperty(smaller, "className", CLASSNAME + "-smaller"); - DOM.setElementProperty(bigger, "className", CLASSNAME + "-bigger"); - - DOM.appendChild(getElement(), bigger); - DOM.appendChild(getElement(), smaller); - DOM.appendChild(getElement(), base); - DOM.appendChild(base, handle); - - // Hide initially - DOM.setStyleAttribute(smaller, "display", "none"); - DOM.setStyleAttribute(bigger, "display", "none"); - DOM.setStyleAttribute(handle, "visibility", "hidden"); - - sinkEvents(Event.MOUSEEVENTS | Event.ONMOUSEWHEEL | Event.KEYEVENTS - | Event.FOCUSEVENTS | Event.TOUCHEVENTS); - - feedbackPopup.addStyleName(CLASSNAME + "-feedback"); - feedbackPopup.setWidget(feedback); - } - - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - - this.client = client; - id = uidl.getId(); - - // Ensure correct implementation - if (client.updateComponent(this, uidl, true)) { - return; - } - - immediate = uidl.getBooleanAttribute("immediate"); - disabled = uidl.getBooleanAttribute("disabled"); - readonly = uidl.getBooleanAttribute("readonly"); - - vertical = uidl.hasAttribute("vertical"); - - String style = ""; - if (uidl.hasAttribute("style")) { - style = uidl.getStringAttribute("style"); - } - - if (vertical) { - addStyleName(CLASSNAME + "-vertical"); - } else { - removeStyleName(CLASSNAME + "-vertical"); - } - - min = uidl.getDoubleAttribute("min"); - max = uidl.getDoubleAttribute("max"); - resolution = uidl.getIntAttribute("resolution"); - value = new Double(uidl.getDoubleVariable("value")); - - setFeedbackValue(value); - - buildBase(); - - if (!vertical) { - // Draw handle with a delay to allow base to gain maximum width - Scheduler.get().scheduleDeferred(new Command() { - public void execute() { - buildHandle(); - setValue(value, false); - } - }); - } else { - buildHandle(); - setValue(value, false); - } - } - - private void setFeedbackValue(double value) { - String currentValue = "" + value; - if (resolution == 0) { - currentValue = "" + new Double(value).intValue(); - } - feedback.setText(currentValue); - } - - private void updateFeedbackPosition() { - if (vertical) { - feedbackPopup.setPopupPosition( - DOM.getAbsoluteLeft(handle) + handle.getOffsetWidth(), - DOM.getAbsoluteTop(handle) + handle.getOffsetHeight() / 2 - - feedbackPopup.getOffsetHeight() / 2); - } else { - feedbackPopup.setPopupPosition( - DOM.getAbsoluteLeft(handle) + handle.getOffsetWidth() / 2 - - feedbackPopup.getOffsetWidth() / 2, - DOM.getAbsoluteTop(handle) - - feedbackPopup.getOffsetHeight()); - } - } - - private void buildBase() { - final String styleAttribute = vertical ? "height" : "width"; - final String domProperty = vertical ? "offsetHeight" : "offsetWidth"; - - final Element p = DOM.getParent(getElement()); - if (DOM.getElementPropertyInt(p, domProperty) > 50) { - if (vertical) { - setHeight(); - } else { - DOM.setStyleAttribute(base, styleAttribute, ""); - } - } else { - // Set minimum size and adjust after all components have - // (supposedly) been drawn completely. - DOM.setStyleAttribute(base, styleAttribute, MIN_SIZE + "px"); - Scheduler.get().scheduleDeferred(new Command() { - public void execute() { - final Element p = DOM.getParent(getElement()); - if (DOM.getElementPropertyInt(p, domProperty) > (MIN_SIZE + 5)) { - if (vertical) { - setHeight(); - } else { - DOM.setStyleAttribute(base, styleAttribute, ""); - } - // Ensure correct position - setValue(value, false); - } - } - }); - } - - // TODO attach listeners for focusing and arrow keys - } - - private void buildHandle() { - final String handleAttribute = vertical ? "marginTop" : "marginLeft"; - - DOM.setStyleAttribute(handle, handleAttribute, "0"); - - // Restore visibility - DOM.setStyleAttribute(handle, "visibility", "visible"); - - } - - private void setValue(Double value, boolean updateToServer) { - if (value == null) { - return; - } - - if (value < min) { - value = min; - } else if (value > max) { - value = max; - } - - // Update handle position - final String styleAttribute = vertical ? "marginTop" : "marginLeft"; - final String domProperty = vertical ? "offsetHeight" : "offsetWidth"; - final int handleSize = Integer.parseInt(DOM.getElementProperty(handle, - domProperty)); - final int baseSize = Integer.parseInt(DOM.getElementProperty(base, - domProperty)) - (2 * BASE_BORDER_WIDTH); - - final int range = baseSize - handleSize; - double v = value.doubleValue(); - - // Round value to resolution - if (resolution > 0) { - v = Math.round(v * Math.pow(10, resolution)); - v = v / Math.pow(10, resolution); - } else { - v = Math.round(v); - } - final double valueRange = max - min; - double p = 0; - if (valueRange > 0) { - p = range * ((v - min) / valueRange); - } - if (p < 0) { - p = 0; - } - if (vertical) { - p = range - p; - } - final double pos = p; - - DOM.setStyleAttribute(handle, styleAttribute, (Math.round(pos)) + "px"); - - // Update value - this.value = new Double(v); - setFeedbackValue(v); - - if (updateToServer) { - updateValueToServer(); - } - } - - @Override - public void onBrowserEvent(Event event) { - if (disabled || readonly) { - return; - } - final Element targ = DOM.eventGetTarget(event); - - if (DOM.eventGetType(event) == Event.ONMOUSEWHEEL) { - processMouseWheelEvent(event); - } else if (dragging || targ == handle) { - processHandleEvent(event); - } else if (targ == smaller) { - decreaseValue(true); - } else if (targ == bigger) { - increaseValue(true); - } else if (DOM.eventGetType(event) == Event.MOUSEEVENTS) { - processBaseEvent(event); - } else if ((BrowserInfo.get().isGecko() && DOM.eventGetType(event) == Event.ONKEYPRESS) - || (!BrowserInfo.get().isGecko() && DOM.eventGetType(event) == Event.ONKEYDOWN)) { - - if (handleNavigation(event.getKeyCode(), event.getCtrlKey(), - event.getShiftKey())) { - - feedbackPopup.show(); - - delayedValueUpdater.trigger(); - - DOM.eventPreventDefault(event); - DOM.eventCancelBubble(event, true); - } - } else if (targ.equals(getElement()) - && DOM.eventGetType(event) == Event.ONFOCUS) { - feedbackPopup.show(); - } else if (targ.equals(getElement()) - && DOM.eventGetType(event) == Event.ONBLUR) { - feedbackPopup.hide(); - } else if (DOM.eventGetType(event) == Event.ONMOUSEDOWN) { - feedbackPopup.show(); - } - if (Util.isTouchEvent(event)) { - event.preventDefault(); // avoid simulated events - event.stopPropagation(); - } - } - - private void processMouseWheelEvent(final Event event) { - final int dir = DOM.eventGetMouseWheelVelocityY(event); - - if (dir < 0) { - increaseValue(false); - } else { - decreaseValue(false); - } - - delayedValueUpdater.trigger(); - - DOM.eventPreventDefault(event); - DOM.eventCancelBubble(event, true); - } - - private void processHandleEvent(Event event) { - switch (DOM.eventGetType(event)) { - case Event.ONMOUSEDOWN: - case Event.ONTOUCHSTART: - if (!disabled && !readonly) { - focus(); - feedbackPopup.show(); - dragging = true; - DOM.setElementProperty(handle, "className", CLASSNAME - + "-handle " + CLASSNAME + "-handle-active"); - DOM.setCapture(getElement()); - DOM.eventPreventDefault(event); // prevent selecting text - DOM.eventCancelBubble(event, true); - event.stopPropagation(); - VConsole.log("Slider move start"); - } - break; - case Event.ONMOUSEMOVE: - case Event.ONTOUCHMOVE: - if (dragging) { - VConsole.log("Slider move"); - setValueByEvent(event, false); - updateFeedbackPosition(); - event.stopPropagation(); - } - break; - case Event.ONTOUCHEND: - feedbackPopup.hide(); - case Event.ONMOUSEUP: - // feedbackPopup.hide(); - VConsole.log("Slider move end"); - dragging = false; - DOM.setElementProperty(handle, "className", CLASSNAME + "-handle"); - DOM.releaseCapture(getElement()); - setValueByEvent(event, true); - event.stopPropagation(); - break; - default: - break; - } - } - - private void processBaseEvent(Event event) { - if (DOM.eventGetType(event) == Event.ONMOUSEDOWN) { - if (!disabled && !readonly && !dragging) { - setValueByEvent(event, true); - DOM.eventCancelBubble(event, true); - } - } else if (DOM.eventGetType(event) == Event.ONMOUSEDOWN && dragging) { - dragging = false; - DOM.releaseCapture(getElement()); - setValueByEvent(event, true); - } - } - - private void decreaseValue(boolean updateToServer) { - setValue(new Double(value.doubleValue() - Math.pow(10, -resolution)), - updateToServer); - } - - private void increaseValue(boolean updateToServer) { - setValue(new Double(value.doubleValue() + Math.pow(10, -resolution)), - updateToServer); - } - - private void setValueByEvent(Event event, boolean updateToServer) { - double v = min; // Fallback to min - - final int coord = getEventPosition(event); - - final int handleSize, baseSize, baseOffset; - if (vertical) { - handleSize = handle.getOffsetHeight(); - baseSize = base.getOffsetHeight(); - baseOffset = base.getAbsoluteTop() - Window.getScrollTop() - - handleSize / 2; - } else { - handleSize = handle.getOffsetWidth(); - baseSize = base.getOffsetWidth(); - baseOffset = base.getAbsoluteLeft() - Window.getScrollLeft() - + handleSize / 2; - } - - if (vertical) { - v = ((baseSize - (coord - baseOffset)) / (double) (baseSize - handleSize)) - * (max - min) + min; - } else { - v = ((coord - baseOffset) / (double) (baseSize - handleSize)) - * (max - min) + min; - } - - if (v < min) { - v = min; - } else if (v > max) { - v = max; - } - - setValue(v, updateToServer); - } - - /** - * TODO consider extracting touches support to an impl class specific for - * webkit (only browser that really supports touches). - * - * @param event - * @return - */ - protected int getEventPosition(Event event) { - if (vertical) { - return Util.getTouchOrMouseClientY(event); - } else { - return Util.getTouchOrMouseClientX(event); - } - } - - public void iLayout() { - if (vertical) { - setHeight(); - } - // Update handle position - setValue(value, false); - } - - private void setHeight() { - // Calculate decoration size - DOM.setStyleAttribute(base, "height", "0"); - DOM.setStyleAttribute(base, "overflow", "hidden"); - int h = DOM.getElementPropertyInt(getElement(), "offsetHeight"); - if (h < MIN_SIZE) { - h = MIN_SIZE; - } - DOM.setStyleAttribute(base, "height", h + "px"); - DOM.setStyleAttribute(base, "overflow", ""); - } - - private void updateValueToServer() { - client.updateVariable(id, "value", value.doubleValue(), immediate); - } - - /** - * Handles the keyboard events handled by the Slider - * - * @param event - * The keyboard event received - * @return true iff the navigation event was handled - */ - public boolean handleNavigation(int keycode, boolean ctrl, boolean shift) { - - // No support for ctrl moving - if (ctrl) { - return false; - } - - if ((keycode == getNavigationUpKey() && vertical) - || (keycode == getNavigationRightKey() && !vertical)) { - if (shift) { - for (int a = 0; a < acceleration; a++) { - increaseValue(false); - } - acceleration++; - } else { - increaseValue(false); - } - return true; - } else if (keycode == getNavigationDownKey() && vertical - || (keycode == getNavigationLeftKey() && !vertical)) { - if (shift) { - for (int a = 0; a < acceleration; a++) { - decreaseValue(false); - } - acceleration++; - } else { - decreaseValue(false); - } - return true; - } - - return false; - } - - /** - * Get the key that increases the vertical slider. By default it is the up - * arrow key but by overriding this you can change the key to whatever you - * want. - * - * @return The keycode of the key - */ - protected int getNavigationUpKey() { - return KeyCodes.KEY_UP; - } - - /** - * Get the key that decreases the vertical slider. By default it is the down - * arrow key but by overriding this you can change the key to whatever you - * want. - * - * @return The keycode of the key - */ - protected int getNavigationDownKey() { - return KeyCodes.KEY_DOWN; - } - - /** - * Get the key that decreases the horizontal slider. By default it is the - * left arrow key but by overriding this you can change the key to whatever - * you want. - * - * @return The keycode of the key - */ - protected int getNavigationLeftKey() { - return KeyCodes.KEY_LEFT; - } - - /** - * Get the key that increases the horizontal slider. By default it is the - * right arrow key but by overriding this you can change the key to whatever - * you want. - * - * @return The keycode of the key - */ - protected int getNavigationRightKey() { - return KeyCodes.KEY_RIGHT; - } - - public Widget getWidgetForPaintable() { - return this; - } -} +/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+//
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.core.client.Scheduler.ScheduledCommand;
+import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.ContainerResizedListener;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+import com.vaadin.terminal.gwt.client.VConsole;
+
+public class VSlider extends SimpleFocusablePanel implements VPaintableWidget,
+ Field, ContainerResizedListener {
+
+ public static final String CLASSNAME = "v-slider";
+
+ /**
+ * Minimum size (width or height, depending on orientation) of the slider
+ * base.
+ */
+ private static final int MIN_SIZE = 50;
+
+ ApplicationConnection client;
+
+ String id;
+
+ private boolean immediate;
+ private boolean disabled;
+ private boolean readonly;
+
+ private int acceleration = 1;
+ private double min;
+ private double max;
+ private int resolution;
+ private Double value;
+ private boolean vertical;
+
+ private final HTML feedback = new HTML("", false);
+ private final VOverlay feedbackPopup = new VOverlay(true, false, true) {
+ @Override
+ public void show() {
+ super.show();
+ updateFeedbackPosition();
+ }
+ };
+
+ /* DOM element for slider's base */
+ private final Element base;
+ private final int BASE_BORDER_WIDTH = 1;
+
+ /* DOM element for slider's handle */
+ private final Element handle;
+
+ /* DOM element for decrement arrow */
+ private final Element smaller;
+
+ /* DOM element for increment arrow */
+ private final Element bigger;
+
+ /* Temporary dragging/animation variables */
+ private boolean dragging = false;
+
+ private VLazyExecutor delayedValueUpdater = new VLazyExecutor(100,
+ new ScheduledCommand() {
+
+ public void execute() {
+ updateValueToServer();
+ acceleration = 1;
+ }
+ });
+
+ public VSlider() {
+ super();
+
+ base = DOM.createDiv();
+ handle = DOM.createDiv();
+ smaller = DOM.createDiv();
+ bigger = DOM.createDiv();
+
+ setStyleName(CLASSNAME);
+ DOM.setElementProperty(base, "className", CLASSNAME + "-base");
+ DOM.setElementProperty(handle, "className", CLASSNAME + "-handle");
+ DOM.setElementProperty(smaller, "className", CLASSNAME + "-smaller");
+ DOM.setElementProperty(bigger, "className", CLASSNAME + "-bigger");
+
+ DOM.appendChild(getElement(), bigger);
+ DOM.appendChild(getElement(), smaller);
+ DOM.appendChild(getElement(), base);
+ DOM.appendChild(base, handle);
+
+ // Hide initially
+ DOM.setStyleAttribute(smaller, "display", "none");
+ DOM.setStyleAttribute(bigger, "display", "none");
+ DOM.setStyleAttribute(handle, "visibility", "hidden");
+
+ sinkEvents(Event.MOUSEEVENTS | Event.ONMOUSEWHEEL | Event.KEYEVENTS
+ | Event.FOCUSEVENTS | Event.TOUCHEVENTS);
+
+ feedbackPopup.addStyleName(CLASSNAME + "-feedback");
+ feedbackPopup.setWidget(feedback);
+ }
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+
+ this.client = client;
+ id = uidl.getId();
+
+ // Ensure correct implementation
+ if (client.updateComponent(this, uidl, true)) {
+ return;
+ }
+
+ immediate = uidl.getBooleanAttribute("immediate");
+ disabled = uidl.getBooleanAttribute("disabled");
+ readonly = uidl.getBooleanAttribute("readonly");
+
+ vertical = uidl.hasAttribute("vertical");
+
+ String style = "";
+ if (uidl.hasAttribute("style")) {
+ style = uidl.getStringAttribute("style");
+ }
+
+ if (vertical) {
+ addStyleName(CLASSNAME + "-vertical");
+ } else {
+ removeStyleName(CLASSNAME + "-vertical");
+ }
+
+ min = uidl.getDoubleAttribute("min");
+ max = uidl.getDoubleAttribute("max");
+ resolution = uidl.getIntAttribute("resolution");
+ value = new Double(uidl.getDoubleVariable("value"));
+
+ setFeedbackValue(value);
+
+ buildBase();
+
+ if (!vertical) {
+ // Draw handle with a delay to allow base to gain maximum width
+ Scheduler.get().scheduleDeferred(new Command() {
+ public void execute() {
+ buildHandle();
+ setValue(value, false);
+ }
+ });
+ } else {
+ buildHandle();
+ setValue(value, false);
+ }
+ }
+
+ private void setFeedbackValue(double value) {
+ String currentValue = "" + value;
+ if (resolution == 0) {
+ currentValue = "" + new Double(value).intValue();
+ }
+ feedback.setText(currentValue);
+ }
+
+ private void updateFeedbackPosition() {
+ if (vertical) {
+ feedbackPopup.setPopupPosition(
+ DOM.getAbsoluteLeft(handle) + handle.getOffsetWidth(),
+ DOM.getAbsoluteTop(handle) + handle.getOffsetHeight() / 2
+ - feedbackPopup.getOffsetHeight() / 2);
+ } else {
+ feedbackPopup.setPopupPosition(
+ DOM.getAbsoluteLeft(handle) + handle.getOffsetWidth() / 2
+ - feedbackPopup.getOffsetWidth() / 2,
+ DOM.getAbsoluteTop(handle)
+ - feedbackPopup.getOffsetHeight());
+ }
+ }
+
+ private void buildBase() {
+ final String styleAttribute = vertical ? "height" : "width";
+ final String domProperty = vertical ? "offsetHeight" : "offsetWidth";
+
+ final Element p = DOM.getParent(getElement());
+ if (DOM.getElementPropertyInt(p, domProperty) > 50) {
+ if (vertical) {
+ setHeight();
+ } else {
+ DOM.setStyleAttribute(base, styleAttribute, "");
+ }
+ } else {
+ // Set minimum size and adjust after all components have
+ // (supposedly) been drawn completely.
+ DOM.setStyleAttribute(base, styleAttribute, MIN_SIZE + "px");
+ Scheduler.get().scheduleDeferred(new Command() {
+ public void execute() {
+ final Element p = DOM.getParent(getElement());
+ if (DOM.getElementPropertyInt(p, domProperty) > (MIN_SIZE + 5)) {
+ if (vertical) {
+ setHeight();
+ } else {
+ DOM.setStyleAttribute(base, styleAttribute, "");
+ }
+ // Ensure correct position
+ setValue(value, false);
+ }
+ }
+ });
+ }
+
+ // TODO attach listeners for focusing and arrow keys
+ }
+
+ private void buildHandle() {
+ final String handleAttribute = vertical ? "marginTop" : "marginLeft";
+
+ DOM.setStyleAttribute(handle, handleAttribute, "0");
+
+ // Restore visibility
+ DOM.setStyleAttribute(handle, "visibility", "visible");
+
+ }
+
+ private void setValue(Double value, boolean updateToServer) {
+ if (value == null) {
+ return;
+ }
+
+ if (value < min) {
+ value = min;
+ } else if (value > max) {
+ value = max;
+ }
+
+ // Update handle position
+ final String styleAttribute = vertical ? "marginTop" : "marginLeft";
+ final String domProperty = vertical ? "offsetHeight" : "offsetWidth";
+ final int handleSize = Integer.parseInt(DOM.getElementProperty(handle,
+ domProperty));
+ final int baseSize = Integer.parseInt(DOM.getElementProperty(base,
+ domProperty)) - (2 * BASE_BORDER_WIDTH);
+
+ final int range = baseSize - handleSize;
+ double v = value.doubleValue();
+
+ // Round value to resolution
+ if (resolution > 0) {
+ v = Math.round(v * Math.pow(10, resolution));
+ v = v / Math.pow(10, resolution);
+ } else {
+ v = Math.round(v);
+ }
+ final double valueRange = max - min;
+ double p = 0;
+ if (valueRange > 0) {
+ p = range * ((v - min) / valueRange);
+ }
+ if (p < 0) {
+ p = 0;
+ }
+ if (vertical) {
+ p = range - p;
+ }
+ final double pos = p;
+
+ DOM.setStyleAttribute(handle, styleAttribute, (Math.round(pos)) + "px");
+
+ // Update value
+ this.value = new Double(v);
+ setFeedbackValue(v);
+
+ if (updateToServer) {
+ updateValueToServer();
+ }
+ }
+
+ @Override
+ public void onBrowserEvent(Event event) {
+ if (disabled || readonly) {
+ return;
+ }
+ final Element targ = DOM.eventGetTarget(event);
+
+ if (DOM.eventGetType(event) == Event.ONMOUSEWHEEL) {
+ processMouseWheelEvent(event);
+ } else if (dragging || targ == handle) {
+ processHandleEvent(event);
+ } else if (targ == smaller) {
+ decreaseValue(true);
+ } else if (targ == bigger) {
+ increaseValue(true);
+ } else if (DOM.eventGetType(event) == Event.MOUSEEVENTS) {
+ processBaseEvent(event);
+ } else if ((BrowserInfo.get().isGecko() && DOM.eventGetType(event) == Event.ONKEYPRESS)
+ || (!BrowserInfo.get().isGecko() && DOM.eventGetType(event) == Event.ONKEYDOWN)) {
+
+ if (handleNavigation(event.getKeyCode(), event.getCtrlKey(),
+ event.getShiftKey())) {
+
+ feedbackPopup.show();
+
+ delayedValueUpdater.trigger();
+
+ DOM.eventPreventDefault(event);
+ DOM.eventCancelBubble(event, true);
+ }
+ } else if (targ.equals(getElement())
+ && DOM.eventGetType(event) == Event.ONFOCUS) {
+ feedbackPopup.show();
+ } else if (targ.equals(getElement())
+ && DOM.eventGetType(event) == Event.ONBLUR) {
+ feedbackPopup.hide();
+ } else if (DOM.eventGetType(event) == Event.ONMOUSEDOWN) {
+ feedbackPopup.show();
+ }
+ if (Util.isTouchEvent(event)) {
+ event.preventDefault(); // avoid simulated events
+ event.stopPropagation();
+ }
+ }
+
+ private void processMouseWheelEvent(final Event event) {
+ final int dir = DOM.eventGetMouseWheelVelocityY(event);
+
+ if (dir < 0) {
+ increaseValue(false);
+ } else {
+ decreaseValue(false);
+ }
+
+ delayedValueUpdater.trigger();
+
+ DOM.eventPreventDefault(event);
+ DOM.eventCancelBubble(event, true);
+ }
+
+ private void processHandleEvent(Event event) {
+ switch (DOM.eventGetType(event)) {
+ case Event.ONMOUSEDOWN:
+ case Event.ONTOUCHSTART:
+ if (!disabled && !readonly) {
+ focus();
+ feedbackPopup.show();
+ dragging = true;
+ DOM.setElementProperty(handle, "className", CLASSNAME
+ + "-handle " + CLASSNAME + "-handle-active");
+ DOM.setCapture(getElement());
+ DOM.eventPreventDefault(event); // prevent selecting text
+ DOM.eventCancelBubble(event, true);
+ event.stopPropagation();
+ VConsole.log("Slider move start");
+ }
+ break;
+ case Event.ONMOUSEMOVE:
+ case Event.ONTOUCHMOVE:
+ if (dragging) {
+ VConsole.log("Slider move");
+ setValueByEvent(event, false);
+ updateFeedbackPosition();
+ event.stopPropagation();
+ }
+ break;
+ case Event.ONTOUCHEND:
+ feedbackPopup.hide();
+ case Event.ONMOUSEUP:
+ // feedbackPopup.hide();
+ VConsole.log("Slider move end");
+ dragging = false;
+ DOM.setElementProperty(handle, "className", CLASSNAME + "-handle");
+ DOM.releaseCapture(getElement());
+ setValueByEvent(event, true);
+ event.stopPropagation();
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void processBaseEvent(Event event) {
+ if (DOM.eventGetType(event) == Event.ONMOUSEDOWN) {
+ if (!disabled && !readonly && !dragging) {
+ setValueByEvent(event, true);
+ DOM.eventCancelBubble(event, true);
+ }
+ }
+ }
+
+ private void decreaseValue(boolean updateToServer) {
+ setValue(new Double(value.doubleValue() - Math.pow(10, -resolution)),
+ updateToServer);
+ }
+
+ private void increaseValue(boolean updateToServer) {
+ setValue(new Double(value.doubleValue() + Math.pow(10, -resolution)),
+ updateToServer);
+ }
+
+ private void setValueByEvent(Event event, boolean updateToServer) {
+ double v = min; // Fallback to min
+
+ final int coord = getEventPosition(event);
+
+ final int handleSize, baseSize, baseOffset;
+ if (vertical) {
+ handleSize = handle.getOffsetHeight();
+ baseSize = base.getOffsetHeight();
+ baseOffset = base.getAbsoluteTop() - Window.getScrollTop()
+ - handleSize / 2;
+ } else {
+ handleSize = handle.getOffsetWidth();
+ baseSize = base.getOffsetWidth();
+ baseOffset = base.getAbsoluteLeft() - Window.getScrollLeft()
+ + handleSize / 2;
+ }
+
+ if (vertical) {
+ v = ((baseSize - (coord - baseOffset)) / (double) (baseSize - handleSize))
+ * (max - min) + min;
+ } else {
+ v = ((coord - baseOffset) / (double) (baseSize - handleSize))
+ * (max - min) + min;
+ }
+
+ if (v < min) {
+ v = min;
+ } else if (v > max) {
+ v = max;
+ }
+
+ setValue(v, updateToServer);
+ }
+
+ /**
+ * TODO consider extracting touches support to an impl class specific for
+ * webkit (only browser that really supports touches).
+ *
+ * @param event
+ * @return
+ */
+ protected int getEventPosition(Event event) {
+ if (vertical) {
+ return Util.getTouchOrMouseClientY(event);
+ } else {
+ return Util.getTouchOrMouseClientX(event);
+ }
+ }
+
+ public void iLayout() {
+ if (vertical) {
+ setHeight();
+ }
+ // Update handle position
+ setValue(value, false);
+ }
+
+ private void setHeight() {
+ // Calculate decoration size
+ DOM.setStyleAttribute(base, "height", "0");
+ DOM.setStyleAttribute(base, "overflow", "hidden");
+ int h = DOM.getElementPropertyInt(getElement(), "offsetHeight");
+ if (h < MIN_SIZE) {
+ h = MIN_SIZE;
+ }
+ DOM.setStyleAttribute(base, "height", h + "px");
+ DOM.setStyleAttribute(base, "overflow", "");
+ }
+
+ private void updateValueToServer() {
+ client.updateVariable(id, "value", value.doubleValue(), immediate);
+ }
+
+ /**
+ * Handles the keyboard events handled by the Slider
+ *
+ * @param event
+ * The keyboard event received
+ * @return true iff the navigation event was handled
+ */
+ public boolean handleNavigation(int keycode, boolean ctrl, boolean shift) {
+
+ // No support for ctrl moving
+ if (ctrl) {
+ return false;
+ }
+
+ if ((keycode == getNavigationUpKey() && vertical)
+ || (keycode == getNavigationRightKey() && !vertical)) {
+ if (shift) {
+ for (int a = 0; a < acceleration; a++) {
+ increaseValue(false);
+ }
+ acceleration++;
+ } else {
+ increaseValue(false);
+ }
+ return true;
+ } else if (keycode == getNavigationDownKey() && vertical
+ || (keycode == getNavigationLeftKey() && !vertical)) {
+ if (shift) {
+ for (int a = 0; a < acceleration; a++) {
+ decreaseValue(false);
+ }
+ acceleration++;
+ } else {
+ decreaseValue(false);
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Get the key that increases the vertical slider. By default it is the up
+ * arrow key but by overriding this you can change the key to whatever you
+ * want.
+ *
+ * @return The keycode of the key
+ */
+ protected int getNavigationUpKey() {
+ return KeyCodes.KEY_UP;
+ }
+
+ /**
+ * Get the key that decreases the vertical slider. By default it is the down
+ * arrow key but by overriding this you can change the key to whatever you
+ * want.
+ *
+ * @return The keycode of the key
+ */
+ protected int getNavigationDownKey() {
+ return KeyCodes.KEY_DOWN;
+ }
+
+ /**
+ * Get the key that decreases the horizontal slider. By default it is the
+ * left arrow key but by overriding this you can change the key to whatever
+ * you want.
+ *
+ * @return The keycode of the key
+ */
+ protected int getNavigationLeftKey() {
+ return KeyCodes.KEY_LEFT;
+ }
+
+ /**
+ * Get the key that increases the horizontal slider. By default it is the
+ * right arrow key but by overriding this you can change the key to whatever
+ * you want.
+ *
+ * @return The keycode of the key
+ */
+ protected int getNavigationRightKey() {
+ return KeyCodes.KEY_RIGHT;
+ }
+
+ public Widget getWidgetForPaintable() {
+ return this;
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java b/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java index 32a9cf3e11..74ff328710 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java @@ -54,7 +54,7 @@ public class VTabsheet extends VTabsheetBase { /** * Representation of a single "tab" shown in the TabBar - * + * */ private static class Tab extends SimplePanel { private static final String TD_CLASSNAME = CLASSNAME + "-tabitemcell"; @@ -64,6 +64,8 @@ public class VTabsheet extends VTabsheetBase { + "-selected"; private static final String TD_SELECTED_FIRST_CLASSNAME = TD_SELECTED_CLASSNAME + "-first"; + private static final String TD_DISABLED_CLASSNAME = TD_CLASSNAME + + "-disabled"; private static final String DIV_CLASSNAME = CLASSNAME + "-tabitem"; private static final String DIV_SELECTED_CLASSNAME = DIV_CLASSNAME @@ -116,6 +118,7 @@ public class VTabsheet extends VTabsheetBase { public void setEnabledOnServer(boolean enabled) { enabledOnServer = enabled; + setStyleName(td, TD_DISABLED_CLASSNAME, !enabled); } public void addClickHandler(ClickHandler handler) { diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTextArea.java b/src/com/vaadin/terminal/gwt/client/ui/VTextArea.java index a74fd9f5dc..cd09e24d67 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTextArea.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VTextArea.java @@ -69,4 +69,11 @@ public class VTextArea extends VTextField { super.onBrowserEvent(event);
}
+ @Override
+ public int getCursorPos() {
+ // This is needed so that TextBoxImplIE6 is used to return the correct
+ // position for old Internet Explorer versions where it has to be
+ // detected in a different way.
+ return getImpl().getTextAreaCursorPos(getElement());
+ }
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTextualDate.java b/src/com/vaadin/terminal/gwt/client/ui/VTextualDate.java index ed4953d463..a522c79736 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTextualDate.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VTextualDate.java @@ -20,12 +20,12 @@ import com.vaadin.terminal.gwt.client.EventId; import com.vaadin.terminal.gwt.client.Focusable; import com.vaadin.terminal.gwt.client.LocaleNotLoadedException; import com.vaadin.terminal.gwt.client.LocaleService; -import com.vaadin.terminal.gwt.client.VPaintableWidget; import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.VConsole; +import com.vaadin.terminal.gwt.client.VPaintableWidget; -public class VTextualDate extends VDateField implements VPaintableWidget, Field, - ChangeHandler, ContainerResizedListener, Focusable, SubPartAware { +public class VTextualDate extends VDateField implements VPaintableWidget, + Field, ChangeHandler, ContainerResizedListener, Focusable, SubPartAware { private static final String PARSE_ERROR_CLASSNAME = CLASSNAME + "-parseerror"; @@ -331,7 +331,8 @@ public class VTextualDate extends VDateField implements VPaintableWidget, Field, @Override public void setWidth(String newWidth) { - if (!"".equals(newWidth) && (width == null || !newWidth.equals(width))) { + if (!"".equals(newWidth) + && (isUndefinedWidth() || !newWidth.equals(width))) { needLayout = true; width = newWidth; super.setWidth(width); @@ -340,16 +341,18 @@ public class VTextualDate extends VDateField implements VPaintableWidget, Field, needLayout = false; } } else { - if ("".equals(newWidth) && width != null && !"".equals(width)) { + if ("".equals(newWidth) && !isUndefinedWidth()) { super.setWidth(""); - needLayout = true; - iLayout(); - needLayout = false; + iLayout(true); width = null; } } } + protected boolean isUndefinedWidth() { + return width == null || "".equals(width); + } + /** * Returns pixels in x-axis reserved for other than textfield content. * @@ -363,14 +366,26 @@ public class VTextualDate extends VDateField implements VPaintableWidget, Field, return fieldExtraWidth; } + /** + * Force an recalculation of the width of the component IF the width has + * been defined. Does nothing if width is undefined as the width will be + * automatically adjusted by the browser. + */ public void updateWidth() { + if (isUndefinedWidth()) { + return; + } needLayout = true; fieldExtraWidth = -1; - iLayout(); + iLayout(true); } public void iLayout() { - if (needLayout) { + iLayout(false); + } + + public void iLayout(boolean force) { + if (needLayout || force) { int textFieldWidth = getOffsetWidth() - getFieldExtraWidth(); if (textFieldWidth < 0) { // Field can never be smaller than 0 (causes exception in IE) diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTreeTablePaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VTreeTablePaintable.java index 8fec0558ec..9b6f03f612 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTreeTablePaintable.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VTreeTablePaintable.java @@ -1,3 +1,6 @@ +/*
+@VaadinApache2LicenseForJavaFiles@
+ */
package com.vaadin.terminal.gwt.client.ui;
import com.google.gwt.core.client.GWT;
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VView.java b/src/com/vaadin/terminal/gwt/client/ui/VView.java index 8eabf6c625..e3aba21096 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VView.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VView.java @@ -640,6 +640,11 @@ public class VView extends SimplePanel implements Container, ResizeHandler, String ownAppId = connection.getConfiguration().getRootPanelId(); + // Hiding elements causes browser to forget scroll position -> must + // save values and restore when the elements are visible again #7976 + int originalScrollTop = Window.getScrollTop(); + int originalScrollLeft = Window.getScrollLeft(); + // Set display: none for all Vaadin apps for (int i = 0; i < vaadinApps.size(); i++) { String appId = vaadinApps.get(i); @@ -678,6 +683,9 @@ public class VView extends SimplePanel implements Container, ResizeHandler, } } + // Scroll back to original location + Window.scrollTo(originalScrollLeft, originalScrollTop); + return w; } diff --git a/src/com/vaadin/terminal/gwt/client/ui/VWindow.java b/src/com/vaadin/terminal/gwt/client/ui/VWindow.java index c1ef2bbac4..95ab0dc773 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VWindow.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VWindow.java @@ -140,6 +140,7 @@ public class VWindow extends VOverlay implements Container, private Element modalityCurtain; private Element draggingCurtain; + private Element resizingCurtain; private Element headerText; @@ -568,12 +569,17 @@ public class VWindow extends VOverlay implements Container, this.draggable = draggable; + setCursorProperties(); + } + + private void setCursorProperties() { if (!this.draggable) { header.getStyle().setProperty("cursor", "default"); + footer.getStyle().setProperty("cursor", "default"); } else { header.getStyle().setProperty("cursor", ""); + footer.getStyle().setProperty("cursor", ""); } - } private void setNaturalWidth() { @@ -703,28 +709,62 @@ public class VWindow extends VOverlay implements Container, } /* - * Shows (or hides) an empty div on top of all other content; used when - * resizing or moving, so that iframes (etc) do not steal event. + * Shows an empty div on top of all other content; used when moving, so that + * iframes (etc) do not steal event. */ - private void showDraggingCurtain(boolean show) { - if (show && draggingCurtain == null) { + private void showDraggingCurtain() { + DOM.appendChild(RootPanel.getBodyElement(), getDraggingCurtain()); + } - draggingCurtain = DOM.createDiv(); - DOM.setStyleAttribute(draggingCurtain, "position", "absolute"); - DOM.setStyleAttribute(draggingCurtain, "top", "0px"); - DOM.setStyleAttribute(draggingCurtain, "left", "0px"); - DOM.setStyleAttribute(draggingCurtain, "width", "100%"); - DOM.setStyleAttribute(draggingCurtain, "height", "100%"); - DOM.setStyleAttribute(draggingCurtain, "zIndex", "" - + VOverlay.Z_INDEX); + private void hideDraggingCurtain() { + if (draggingCurtain != null) { + DOM.removeChild(RootPanel.getBodyElement(), draggingCurtain); + } + } - DOM.appendChild(RootPanel.getBodyElement(), draggingCurtain); - } else if (!show && draggingCurtain != null) { + /* + * Shows an empty div on top of all other content; used when resizing, so + * that iframes (etc) do not steal event. + */ + private void showResizingCurtain() { + DOM.appendChild(RootPanel.getBodyElement(), getResizingCurtain()); + } - DOM.removeChild(RootPanel.getBodyElement(), draggingCurtain); - draggingCurtain = null; + private void hideResizingCurtain() { + if (resizingCurtain != null) { + DOM.removeChild(RootPanel.getBodyElement(), resizingCurtain); } + } + + private Element getDraggingCurtain() { + if (draggingCurtain == null) { + draggingCurtain = createCurtain(); + draggingCurtain.setClassName(CLASSNAME + "-draggingCurtain"); + } + + return draggingCurtain; + } + + private Element getResizingCurtain() { + if (resizingCurtain == null) { + resizingCurtain = createCurtain(); + resizingCurtain.setClassName(CLASSNAME + "-resizingCurtain"); + } + + return resizingCurtain; + } + + private Element createCurtain() { + Element curtain = DOM.createDiv(); + + DOM.setStyleAttribute(curtain, "position", "absolute"); + DOM.setStyleAttribute(curtain, "top", "0px"); + DOM.setStyleAttribute(curtain, "left", "0px"); + DOM.setStyleAttribute(curtain, "width", "100%"); + DOM.setStyleAttribute(curtain, "height", "100%"); + DOM.setStyleAttribute(curtain, "zIndex", "" + VOverlay.Z_INDEX); + return curtain; } private void setResizable(boolean resizability) { @@ -844,7 +884,7 @@ public class VWindow extends VOverlay implements Container, if (!isActive()) { bringToFront(); } - showDraggingCurtain(true); + showResizingCurtain(); if (BrowserInfo.get().isIE()) { DOM.setStyleAttribute(resizeBox, "visibility", "hidden"); } @@ -862,7 +902,7 @@ public class VWindow extends VOverlay implements Container, case Event.ONTOUCHCANCEL: DOM.releaseCapture(getElement()); case Event.ONLOSECAPTURE: - showDraggingCurtain(false); + hideResizingCurtain(); if (BrowserInfo.get().isIE()) { DOM.setStyleAttribute(resizeBox, "visibility", ""); } @@ -1097,7 +1137,7 @@ public class VWindow extends VOverlay implements Container, private void beginMovingWindow(Event event) { if (draggable) { - showDraggingCurtain(true); + showDraggingCurtain(); dragging = true; startX = Util.getTouchOrMouseClientX(event); startY = Util.getTouchOrMouseClientY(event); @@ -1110,7 +1150,7 @@ public class VWindow extends VOverlay implements Container, private void stopMovingWindow() { dragging = false; - showDraggingCurtain(false); + hideDraggingCurtain(); DOM.releaseCapture(getElement()); } diff --git a/src/com/vaadin/ui/Component.java b/src/com/vaadin/ui/Component.java index 53fdfdb4ff..1289b57bd9 100644 --- a/src/com/vaadin/ui/Component.java +++ b/src/com/vaadin/ui/Component.java @@ -11,7 +11,6 @@ import java.util.EventObject; import java.util.Locale; import com.vaadin.Application; -import com.vaadin.data.Property; import com.vaadin.event.FieldEvents; import com.vaadin.terminal.ErrorMessage; import com.vaadin.terminal.Paintable; @@ -363,12 +362,6 @@ public interface Component extends Paintable, VariableOwner, Sizeable, * </p> * * <p> - * The read-only status affects only the user; the value can still be - * changed programmatically, for example, with - * {@link Property#setValue(Object)}. - * </p> - * - * <p> * The method will return {@code true} if the component or any of its * parents is in the read-only mode. * </p> @@ -396,12 +389,6 @@ public interface Component extends Paintable, VariableOwner, Sizeable, * </p> * * <p> - * The read-only status affects only the user; the value can still be - * changed programmatically, for example, with - * {@link Property#setValue(Object)}. - * </p> - * - * <p> * This method will trigger a * {@link com.vaadin.terminal.Paintable.RepaintRequestEvent * RepaintRequestEvent}. diff --git a/src/com/vaadin/ui/CssLayout.java b/src/com/vaadin/ui/CssLayout.java index b952609b20..b9432df6b6 100644 --- a/src/com/vaadin/ui/CssLayout.java +++ b/src/com/vaadin/ui/CssLayout.java @@ -125,7 +125,7 @@ public class CssLayout extends AbstractLayout implements LayoutClickNotifier { // see ticket #7668 if (c.getParent() == this) { // When c is removed, all components after it are shifted down - if (index > components.indexOf(c)) { + if (index > getComponentIndex(c)) { index--; } removeComponent(c); @@ -275,4 +275,28 @@ public class CssLayout extends AbstractLayout implements LayoutClickNotifier { removeListener(CLICK_EVENT, LayoutClickEvent.class, listener); } + /** + * Returns the index of the given component. + * + * @param component + * The component to look up. + * @return The index of the component or -1 if the component is not a child. + */ + public int getComponentIndex(Component component) { + return components.indexOf(component); + } + + /** + * Returns the component at the given position. + * + * @param index + * The position of the component. + * @return The component at the given index. + * @throws IndexOutOfBoundsException + * If the index is out of range. + */ + public Component getComponent(int index) throws IndexOutOfBoundsException { + return components.get(index); + } + } diff --git a/src/com/vaadin/ui/Table.java b/src/com/vaadin/ui/Table.java index 914a1a8037..003ef6978c 100644 --- a/src/com/vaadin/ui/Table.java +++ b/src/com/vaadin/ui/Table.java @@ -3159,6 +3159,9 @@ public class Table extends AbstractSelect implements Action.Container, if (start > cells[CELL_ITEMID].length || start < 0) { start = 0; } + if (end > cells[CELL_ITEMID].length) { + end = cells[CELL_ITEMID].length; + } for (int indexInRowbuffer = start; indexInRowbuffer < end; indexInRowbuffer++) { final Object itemId = cells[CELL_ITEMID][indexInRowbuffer]; @@ -5295,4 +5298,13 @@ public class Table extends AbstractSelect implements Action.Container, return propertyValueConverters.get(propertyId); } + @Override + public void setVisible(boolean visible) { + if (!isVisible() && visible) { + // We need to ensure that the rows are sent to the client when the + // Table is made visible if it has been rendered as invisible. + setRowCacheInvalidated(true); + } + super.setVisible(visible); + } } |