T getValue() {
diff --git a/modules/desktop/src/com/haulmont/cuba/desktop/gui/components/DesktopWindow.java b/modules/desktop/src/com/haulmont/cuba/desktop/gui/components/DesktopWindow.java
index 836c0c5868..030afc521c 100644
--- a/modules/desktop/src/com/haulmont/cuba/desktop/gui/components/DesktopWindow.java
+++ b/modules/desktop/src/com/haulmont/cuba/desktop/gui/components/DesktopWindow.java
@@ -992,37 +992,33 @@ public class DesktopWindow implements Window, Component.Disposable,
remove(component);
}
- int implIndex = getActualIndex(index);
-
- ComponentCaption caption = null;
- boolean haveDescription = false;
- if (DesktopContainerHelper.hasExternalCaption(component)) {
- caption = new ComponentCaption(component);
- captions.put(component, caption);
- getContainer().add(caption, layoutAdapter.getCaptionConstraints(component), implIndex); // CAUTION this dramatically wrong
- implIndex++;
- } else if (DesktopContainerHelper.hasExternalDescription(component)) {
- caption = new ComponentCaption(component);
- captions.put(component, caption);
- haveDescription = true;
- }
-
JComponent composition = DesktopComponentsHelper.getComposition(component);
- // if component have description without caption, we need to wrap
- // component to view Description button horizontally after component
- if (haveDescription) {
+ boolean hasExternalCaption = DesktopContainerHelper.hasExternalCaption(component);
+ if (hasExternalCaption
+ || DesktopContainerHelper.hasExternalContextHelp(component)) {
+ ComponentCaption caption = new ComponentCaption(component);
+ captions.put(component, caption);
+
JPanel wrapper = new JPanel();
BoxLayoutAdapter adapter = BoxLayoutAdapter.create(wrapper);
adapter.setExpandLayout(true);
adapter.setSpacing(false);
adapter.setMargin(false);
wrapper.add(composition);
- wrapper.add(caption, new CC().alignY("top"));
- getContainer().add(wrapper, layoutAdapter.getConstraints(component), implIndex);
+
+ if (hasExternalCaption) {
+ adapter.setFlowDirection(BoxLayoutAdapter.FlowDirection.Y);
+ wrapper.add(caption, 0);
+ } else {
+ wrapper.add(caption, new CC().alignY("top"));
+ }
+
+ getContainer().add(wrapper, layoutAdapter.getConstraints(component), index);
wrappers.put(component, new Pair<>(wrapper, adapter));
} else {
- getContainer().add(composition, layoutAdapter.getConstraints(component), implIndex);
+ getContainer().add(composition, layoutAdapter.getConstraints(component), index);
}
+
if (component.getId() != null) {
componentByIds.put(component.getId(), component);
}
@@ -1126,17 +1122,6 @@ public class DesktopWindow implements Window, Component.Disposable,
requestRepaint();
}
- protected int getActualIndex(int originalIndex) {
- int index = originalIndex;
- Object[] components = ownComponents.toArray();
- for (int i = 0; i < originalIndex; i++) {
- if (DesktopContainerHelper.hasExternalCaption((Component) components[i])) {
- index++;
- }
- }
- return index;
- }
-
@Override
public Component getOwnComponent(String id) {
return componentByIds.get(id);
@@ -1378,15 +1363,16 @@ public class DesktopWindow implements Window, Component.Disposable,
@Override
public void updateComponent(Component child) {
boolean componentReAdded = false;
- if (DesktopContainerHelper.mayHaveExternalCaption(child)) {
+ if (DesktopContainerHelper.mayHaveExternalCaption(child)
+ || DesktopContainerHelper.mayHaveExternalContextHelp(child)) {
if (captions.containsKey(child)
&& !DesktopContainerHelper.hasExternalCaption(child)
- && !DesktopContainerHelper.hasExternalDescription(child)) {
+ && !DesktopContainerHelper.hasExternalContextHelp(child)) {
reAddChild(child);
componentReAdded = true;
} else if (!captions.containsKey(child)
&& (DesktopContainerHelper.hasExternalCaption(child)
- || DesktopContainerHelper.hasExternalDescription(child))) {
+ || DesktopContainerHelper.hasExternalContextHelp(child))) {
reAddChild(child);
componentReAdded = true;
} else if (captions.containsKey(child)) {
@@ -1404,6 +1390,19 @@ public class DesktopWindow implements Window, Component.Disposable,
JComponent composition;
if (wrappers.containsKey(child)) {
composition = wrappers.get(child).getFirst();
+ CC constraints = MigLayoutHelper.getConstraints(child);
+ if (child.getHeight() == -1.0) {
+ MigLayoutHelper.applyHeight(constraints, -1, UNITS_PIXELS, false);
+ } else {
+ MigLayoutHelper.applyHeight(constraints, 100, UNITS_PERCENTAGE, false);
+ }
+ if (child.getWidth() == -1.0) {
+ MigLayoutHelper.applyWidth(constraints, -1, UNITS_PIXELS, false);
+ } else {
+ MigLayoutHelper.applyWidth(constraints, 100, UNITS_PERCENTAGE, false);
+ }
+ BoxLayoutAdapter adapter = wrappers.get(child).getSecond();
+ adapter.updateConstraints(DesktopComponentsHelper.getComposition(child), constraints);
} else {
composition = DesktopComponentsHelper.getComposition(child);
}
diff --git a/modules/desktop/src/com/haulmont/cuba/desktop/gui/data/DesktopContainerHelper.java b/modules/desktop/src/com/haulmont/cuba/desktop/gui/data/DesktopContainerHelper.java
index 00ed87a09e..6361d13b11 100644
--- a/modules/desktop/src/com/haulmont/cuba/desktop/gui/data/DesktopContainerHelper.java
+++ b/modules/desktop/src/com/haulmont/cuba/desktop/gui/data/DesktopContainerHelper.java
@@ -21,6 +21,7 @@ import com.haulmont.cuba.desktop.gui.components.DesktopCheckBox;
import com.haulmont.cuba.desktop.gui.components.DesktopComponent;
import com.haulmont.cuba.desktop.gui.components.DesktopContainer;
import com.haulmont.cuba.gui.components.Component;
+import com.haulmont.cuba.gui.components.Component.HasContextHelp;
import com.haulmont.cuba.gui.components.Field;
import org.apache.commons.lang.StringUtils;
@@ -56,6 +57,18 @@ public class DesktopContainerHelper {
return false;
}
+ public static boolean mayHaveExternalContextHelp(Component component) {
+ return component instanceof HasContextHelp;
+ }
+
+ public static boolean hasExternalContextHelp(Component component) {
+ if (component instanceof HasContextHelp) {
+ final String contextHelp = ((HasContextHelp) component).getContextHelpText();
+ return StringUtils.isNotEmpty(contextHelp);
+ }
+ return false;
+ }
+
public static void assignContainer(Component component, DesktopContainer container) {
if (component instanceof DesktopComponent) {
((DesktopComponent) component).setContainer(container);
diff --git a/modules/desktop/src/com/haulmont/cuba/desktop/res/nimbus/nimbus.xml b/modules/desktop/src/com/haulmont/cuba/desktop/res/nimbus/nimbus.xml
index 683f04a954..c980d99f76 100644
--- a/modules/desktop/src/com/haulmont/cuba/desktop/res/nimbus/nimbus.xml
+++ b/modules/desktop/src/com/haulmont/cuba/desktop/res/nimbus/nimbus.xml
@@ -41,6 +41,8 @@
+
+
diff --git a/modules/desktop/src/com/haulmont/cuba/desktop/sys/DesktopToolTipManager.java b/modules/desktop/src/com/haulmont/cuba/desktop/sys/DesktopToolTipManager.java
index ebbbbf50e0..f4d43fcf3b 100644
--- a/modules/desktop/src/com/haulmont/cuba/desktop/sys/DesktopToolTipManager.java
+++ b/modules/desktop/src/com/haulmont/cuba/desktop/sys/DesktopToolTipManager.java
@@ -17,9 +17,16 @@
package com.haulmont.cuba.desktop.sys;
+import com.haulmont.cuba.core.global.AppBeans;
+import com.haulmont.cuba.core.global.Configuration;
+import com.haulmont.cuba.desktop.DesktopConfig;
+import com.haulmont.cuba.desktop.gui.components.DesktopComponentsHelper;
import com.haulmont.cuba.desktop.sys.vcl.ToolTipButton;
+import com.haulmont.cuba.gui.components.KeyCombination;
+import org.apache.commons.lang.StringUtils;
import javax.swing.*;
+import javax.swing.text.StyleContext;
import java.awt.*;
import java.awt.event.*;
@@ -28,24 +35,23 @@ import java.awt.event.*;
*/
public class DesktopToolTipManager extends MouseAdapter {
- public static final int F1_CODE = 112;
+ protected static int CLOSE_TIME = 500;
+ protected static int SHOW_TIME = 1000;
- private static int CLOSE_TIME = 500;
- private static int SHOW_TIME = 1000;
+ protected boolean tooltipShowing = false;
- private boolean tooltipShowing = false;
+ protected JToolTip toolTipWindow;
+ protected Popup window;
+ protected JComponent component;
- private JToolTip toolTipWindow;
- private Popup window;
- private JComponent component;
+ protected Timer showTimer = new Timer(SHOW_TIME, null);
+ protected Timer closeTimer;
- private Timer showTimer = new Timer(SHOW_TIME, null);
- private Timer closeTimer;
-
- private MouseListener componentMouseListener = new ComponentMouseListener();
- private KeyListener fieldKeyListener = new FieldKeyListener();
- private ActionListener btnActionListener = new ButtonClickListener();
+ protected Configuration configuration = AppBeans.get(Configuration.NAME);
+ protected MouseListener componentMouseListener = new ComponentMouseListener();
+ protected KeyListener fieldKeyListener = new FieldKeyListener();
+ protected ActionListener btnActionListener = new ButtonClickListener();
private static DesktopToolTipManager instance;
@@ -61,23 +67,20 @@ public class DesktopToolTipManager extends MouseAdapter {
return instance;
}
- private DesktopToolTipManager() {
+ protected DesktopToolTipManager() {
closeTimer = new Timer(CLOSE_TIME, null);
closeTimer.setRepeats(false);
- closeTimer.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- window.hide();
- window = null;
- tooltipShowing = false;
- toolTipWindow.removeMouseListener(DesktopToolTipManager.this);
- component.removeMouseListener(DesktopToolTipManager.this);
+ closeTimer.addActionListener(e -> {
+ window.hide();
+ window = null;
+ tooltipShowing = false;
+ toolTipWindow.removeMouseListener(DesktopToolTipManager.this);
+ component.removeMouseListener(DesktopToolTipManager.this);
- }
});
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
- private MouseEvent event;
+ protected MouseEvent event;
@Override
public void eventDispatched(AWTEvent e) {
@@ -96,7 +99,7 @@ public class DesktopToolTipManager extends MouseAdapter {
}, AWTEvent.MOUSE_EVENT_MASK);
}
- private boolean isPointInComponent(Point point, JComponent component) {
+ protected boolean isPointInComponent(Point point, JComponent component) {
if (!component.isShowing())
return false;
@@ -108,7 +111,7 @@ public class DesktopToolTipManager extends MouseAdapter {
/**
* Register tooltip for component.
- * Tooltip is displayed when user press F1 on focused component
+ * The tooltip is displayed when a user either presses F1 on a focused component or hovers over it.
* ToolTip text is taken from {@link javax.swing.JComponent#getToolTipText()}.
*
* @param component component to register
@@ -116,6 +119,9 @@ public class DesktopToolTipManager extends MouseAdapter {
public void registerTooltip(final JComponent component) {
component.removeKeyListener(fieldKeyListener);
component.addKeyListener(fieldKeyListener);
+
+ component.removeMouseListener(componentMouseListener);
+ component.addMouseListener(componentMouseListener);
}
/**
@@ -154,7 +160,7 @@ public class DesktopToolTipManager extends MouseAdapter {
btn.addActionListener(btnActionListener);
}
- private void hideTooltip() {
+ protected void hideTooltip() {
closeTimer.stop();
if (window != null) {
window.hide();
@@ -165,10 +171,14 @@ public class DesktopToolTipManager extends MouseAdapter {
}
}
- private void showTooltip(JComponent field, String text) {
+ protected void showTooltip(JComponent field, String text) {
if (!field.isShowing())
return;
+ if (StringUtils.isEmpty(text)) {
+ return;
+ }
+
PointerInfo pointerInfo = MouseInfo.getPointerInfo();
if (pointerInfo == null) {
return;
@@ -198,21 +208,43 @@ public class DesktopToolTipManager extends MouseAdapter {
}
component = field;
- final JToolTip toolTip = new JToolTip();
- toolTip.setTipText("" + text + "");
+ final JToolTip toolTip = new CubaToolTip();
+ toolTip.setTipText(text);
final Popup tooltipContainer = PopupFactory.getSharedInstance().getPopup(field, toolTip, x, y);
tooltipContainer.show();
window = tooltipContainer;
toolTipWindow = toolTip;
tooltipShowing = true;
- if ((!(field instanceof ToolTipButton)) && ((field instanceof AbstractButton) || (field instanceof JLabel))) {
+ if (!(field instanceof ToolTipButton)) {
toolTip.addMouseListener(this);
field.addMouseListener(this);
}
}
+ protected class CubaToolTip extends JToolTip {
+ @Override
+ public void setTipText(String tipText) {
+ UIDefaults lafDefaults = UIManager.getLookAndFeelDefaults();
+ int maxTooltipWidth = lafDefaults.getInt("Tooltip.maxWidth");
+ if (maxTooltipWidth == 0) {
+ maxTooltipWidth = DesktopComponentsHelper.TOOLTIP_WIDTH;
+ }
+
+ FontMetrics fontMetrics = StyleContext.getDefaultStyleContext().getFontMetrics(getFont());
+ int actualWidth = SwingUtilities.computeStringWidth(fontMetrics, tipText);
+
+ if (actualWidth < maxTooltipWidth) {
+ tipText = "" + tipText + "";
+ } else {
+ tipText = "" + tipText + "";
+ }
+
+ super.setTipText(tipText);
+ }
+ }
+
@Override
public void mouseExited(MouseEvent e) {
closeTimer.start();
@@ -225,9 +257,9 @@ public class DesktopToolTipManager extends MouseAdapter {
}
}
- private class ComponentMouseListener extends MouseAdapter {
+ protected class ComponentMouseListener extends MouseAdapter {
- private JComponent cmp;
+ protected JComponent cmp;
{
showTimer.setRepeats(false);
@@ -243,7 +275,7 @@ public class DesktopToolTipManager extends MouseAdapter {
@Override
public void mouseEntered(MouseEvent e) {
if (window != null) {
- if (e.getSource() != component && e.getSource() != toolTipWindow && component instanceof AbstractButton) {
+ if (e.getSource() != component && e.getSource() != toolTipWindow) {
hideTooltip();
cmp = (JComponent) e.getSource();
showTimer.start();
@@ -272,10 +304,14 @@ public class DesktopToolTipManager extends MouseAdapter {
}
}
- private class FieldKeyListener extends KeyAdapter {
+ protected class FieldKeyListener extends KeyAdapter {
@Override
public void keyPressed(KeyEvent e) {
- if (e.getKeyCode() == F1_CODE) {
+ String showTooltipShortcut = configuration.getConfig(DesktopConfig.class).getShowTooltipShortcut();
+ KeyStroke keyStroke = DesktopComponentsHelper
+ .convertKeyCombination(KeyCombination.create(showTooltipShortcut));
+
+ if (KeyStroke.getKeyStrokeForEvent(e).equals(keyStroke)) {
hideTooltip();
JComponent field = (JComponent) e.getSource();
showTooltip(field, field.getToolTipText());
@@ -287,7 +323,7 @@ public class DesktopToolTipManager extends MouseAdapter {
}
}
- private class ButtonClickListener implements ActionListener {
+ protected class ButtonClickListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
diff --git a/modules/desktop/src/com/haulmont/cuba/desktop/theme/impl/DesktopThemeLoaderImpl.java b/modules/desktop/src/com/haulmont/cuba/desktop/theme/impl/DesktopThemeLoaderImpl.java
index c50298e90c..746014e474 100644
--- a/modules/desktop/src/com/haulmont/cuba/desktop/theme/impl/DesktopThemeLoaderImpl.java
+++ b/modules/desktop/src/com/haulmont/cuba/desktop/theme/impl/DesktopThemeLoaderImpl.java
@@ -393,6 +393,8 @@ public class DesktopThemeLoaderImpl implements DesktopThemeLoader {
return loadInsets(element);
} else if ("dimension".equals(elementName)) {
return loadDimension(element);
+ } else if ("int".equals(elementName)) {
+ return Integer.parseInt(element.attributeValue("value"));
} else {
log.error("Uknown UI property value: " + elementName);
return null;
diff --git a/modules/global/src/com/haulmont/cuba/bom.properties b/modules/global/src/com/haulmont/cuba/bom.properties
index 2207f1218e..5a089cca1d 100644
--- a/modules/global/src/com/haulmont/cuba/bom.properties
+++ b/modules/global/src/com/haulmont/cuba/bom.properties
@@ -89,7 +89,7 @@ org.javassist/javassist = 3.21.0-GA
org.hibernate/hibernate-validator = 5.4.2.Final
org.glassfish.web/javax.el = 2.2.6
-com.vaadin = 7.7.11.cuba.1
+com.vaadin = 7.7.11.cuba.3
com.vaadin/vaadin-shared = ${com.vaadin}
com.vaadin/vaadin-server = ${com.vaadin}
com.vaadin/vaadin-client = ${com.vaadin}
diff --git a/modules/gui/src/com/haulmont/cuba/gui/components/Component.java b/modules/gui/src/com/haulmont/cuba/gui/components/Component.java
index 05800c4569..cd849bfece 100644
--- a/modules/gui/src/com/haulmont/cuba/gui/components/Component.java
+++ b/modules/gui/src/com/haulmont/cuba/gui/components/Component.java
@@ -346,6 +346,35 @@ public interface Component {
void setDescription(String description);
}
+ /**
+ * A sub-interface implemented by components that can provide a context help.
+ */
+ interface HasContextHelp {
+ /**
+ * @return context help text
+ */
+ String getContextHelpText();
+
+ /**
+ * Sets context help text. If set, then a special icon will be added for a field.
+ *
+ * @param contextHelpText context help text to be set
+ */
+ void setContextHelpText(String contextHelpText);
+
+ /**
+ * @return true if field accepts context help text in HTML format, false otherwise
+ */
+ boolean isContextHelpTextHtmlEnabled();
+
+ /**
+ * Defines if context help text can be presented as HTML.
+ *
+ * @param enabled true if field accepts context help text in HTML format, false otherwise
+ */
+ void setContextHelpTextHtmlEnabled(boolean enabled);
+ }
+
/**
* Layout having a mouse click listener.
*/
diff --git a/modules/gui/src/com/haulmont/cuba/gui/components/Field.java b/modules/gui/src/com/haulmont/cuba/gui/components/Field.java
index d1023dadf1..952c67270a 100644
--- a/modules/gui/src/com/haulmont/cuba/gui/components/Field.java
+++ b/modules/gui/src/com/haulmont/cuba/gui/components/Field.java
@@ -22,7 +22,8 @@ import java.util.Collection;
* Base interface for "fields" - components intended to display and edit value of a certain entity attribute.
*/
public interface Field extends DatasourceComponent, Component.HasCaption, Component.HasValue, Component.Editable,
- Component.BelongToFrame, Component.Validatable, Component.HasIcon {
+ Component.BelongToFrame, Component.Validatable, Component.HasIcon,
+ Component.HasContextHelp {
/**
* @return whether the field must contain a non-null value
*/
diff --git a/modules/gui/src/com/haulmont/cuba/gui/components/FieldGroup.java b/modules/gui/src/com/haulmont/cuba/gui/components/FieldGroup.java
index 56e8ceb538..83ca306bca 100644
--- a/modules/gui/src/com/haulmont/cuba/gui/components/FieldGroup.java
+++ b/modules/gui/src/com/haulmont/cuba/gui/components/FieldGroup.java
@@ -441,6 +441,36 @@ public interface FieldGroup extends Component, Component.BelongToFrame, Componen
* @return options datasource
*/
CollectionDatasource getOptionsDatasource();
+
+ /**
+ * @return context help text
+ */
+ String getContextHelpText();
+
+ /**
+ * Set context help text for declarative field.
+ *
+ * If {@link #isBound()} is true and Component implements {@link Field} then sets context help text
+ * to the connected Component.
+ *
+ * @param contextHelpText context help text to be set
+ */
+ void setContextHelpText(String contextHelpText);
+
+ /**
+ * @return true if field accepts context help text in HTML format, null if not set for a declarative field
+ */
+ Boolean isContextHelpTextHtmlEnabled();
+
+ /**
+ * Defines if context help text can be presented as HTML.
+ *
+ * If {@link #isBound()} is true and Component implements {@link Field} then sets this attribute
+ * to the connected Component.
+ *
+ * @param enabled true if field accepts context help text in HTML format
+ */
+ void setContextHelpTextHtmlEnabled(Boolean enabled);
}
/**
diff --git a/modules/gui/src/com/haulmont/cuba/gui/window.xsd b/modules/gui/src/com/haulmont/cuba/gui/window.xsd
index 27f365ae61..8f66fa790c 100644
--- a/modules/gui/src/com/haulmont/cuba/gui/window.xsd
+++ b/modules/gui/src/com/haulmont/cuba/gui/window.xsd
@@ -887,6 +887,11 @@
+
+
+
+
+
@@ -1157,6 +1162,7 @@
+