You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Panel.java 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. /*
  2. @ITMillApache2LicenseForJavaFiles@
  3. */
  4. package com.vaadin.ui;
  5. import java.util.Iterator;
  6. import java.util.Map;
  7. import com.vaadin.event.Action;
  8. import com.vaadin.event.Action.Handler;
  9. import com.vaadin.event.ActionManager;
  10. import com.vaadin.event.MouseEvents.ClickEvent;
  11. import com.vaadin.event.MouseEvents.ClickListener;
  12. import com.vaadin.terminal.PaintException;
  13. import com.vaadin.terminal.PaintTarget;
  14. import com.vaadin.terminal.Scrollable;
  15. import com.vaadin.terminal.gwt.client.MouseEventDetails;
  16. import com.vaadin.terminal.gwt.client.ui.VPanel;
  17. import com.vaadin.ui.themes.Reindeer;
  18. import com.vaadin.ui.themes.Runo;
  19. /**
  20. * Panel - a simple single component container.
  21. *
  22. * @author IT Mill Ltd.
  23. * @version
  24. * @VERSION@
  25. * @since 3.0
  26. */
  27. @SuppressWarnings("serial")
  28. @ClientWidget(VPanel.class)
  29. public class Panel extends AbstractComponentContainer implements Scrollable,
  30. ComponentContainer.ComponentAttachListener,
  31. ComponentContainer.ComponentDetachListener, Action.Notifier {
  32. private static final String CLICK_EVENT = VPanel.CLICK_EVENT_IDENTIFIER;
  33. /**
  34. * Removes extra decorations from the Panel.
  35. *
  36. * @deprecated this style is no longer part of the core framework and this
  37. * component, even though most built-in themes implement this
  38. * style. Use the constant specified in the theme class file
  39. * that you're using, if it provides one, e.g.
  40. * {@link Reindeer#PANEL_LIGHT} or {@link Runo#PANEL_LIGHT} .
  41. */
  42. @Deprecated
  43. public static final String STYLE_LIGHT = "light";
  44. /**
  45. * Content of the panel.
  46. */
  47. private ComponentContainer content;
  48. /**
  49. * Scroll X position.
  50. */
  51. private int scrollOffsetX = 0;
  52. /**
  53. * Scroll Y position.
  54. */
  55. private int scrollOffsetY = 0;
  56. /**
  57. * Scrolling mode.
  58. */
  59. private boolean scrollable = false;
  60. /**
  61. * Keeps track of the Actions added to this component, and manages the
  62. * painting and handling as well.
  63. */
  64. protected ActionManager actionManager;
  65. /**
  66. * Creates a new empty panel. A VerticalLayout is used as content.
  67. */
  68. public Panel() {
  69. this((ComponentContainer) null);
  70. }
  71. /**
  72. * Creates a new empty panel which contains the given content. The content
  73. * cannot be null.
  74. *
  75. * @param content
  76. * the content for the panel.
  77. */
  78. public Panel(ComponentContainer content) {
  79. setContent(content);
  80. setWidth(100, UNITS_PERCENTAGE);
  81. }
  82. /**
  83. * Creates a new empty panel with caption. Default layout is used.
  84. *
  85. * @param caption
  86. * the caption used in the panel.
  87. */
  88. public Panel(String caption) {
  89. this(caption, null);
  90. }
  91. /**
  92. * Creates a new empty panel with the given caption and content.
  93. *
  94. * @param caption
  95. * the caption of the panel.
  96. * @param content
  97. * the content used in the panel.
  98. */
  99. public Panel(String caption, ComponentContainer content) {
  100. this(content);
  101. setCaption(caption);
  102. }
  103. /**
  104. * Gets the current layout of the panel.
  105. *
  106. * @return the Current layout of the panel.
  107. * @deprecated A Panel can now contain a ComponentContainer which is not
  108. * necessarily a Layout. Use {@link #getContent()} instead.
  109. */
  110. @Deprecated
  111. public Layout getLayout() {
  112. if (content instanceof Layout) {
  113. return (Layout) content;
  114. } else if (content == null) {
  115. return null;
  116. }
  117. throw new IllegalStateException(
  118. "Panel does not contain a Layout. Use getContent() instead of getLayout().");
  119. }
  120. /**
  121. * Sets the layout of the panel.
  122. *
  123. * If given layout is null, a VerticalLayout with margins set is used as a
  124. * default.
  125. *
  126. * Components from old layout are not moved to new layout by default
  127. * (changed in 5.2.2). Use function in Layout interface manually.
  128. *
  129. * @param newLayout
  130. * the New layout of the panel.
  131. * @deprecated A Panel can now contain a ComponentContainer which is not
  132. * necessarily a Layout. Use
  133. * {@link #setContent(ComponentContainer)} instead.
  134. */
  135. @Deprecated
  136. public void setLayout(Layout newLayout) {
  137. setContent(newLayout);
  138. }
  139. /**
  140. * Returns the content of the Panel.
  141. *
  142. * @return
  143. */
  144. public ComponentContainer getContent() {
  145. return content;
  146. }
  147. /**
  148. *
  149. * Set the content of the Panel. If null is given as the new content then a
  150. * layout is automatically created and set as the content.
  151. *
  152. * @param content
  153. * The new content
  154. */
  155. public void setContent(ComponentContainer newContent) {
  156. // If the content is null we create the default content
  157. if (newContent == null) {
  158. newContent = createDefaultContent();
  159. }
  160. // if (newContent == null) {
  161. // throw new IllegalArgumentException("Content cannot be null");
  162. // }
  163. if (newContent == content) {
  164. // don't set the same content twice
  165. return;
  166. }
  167. // detach old content if present
  168. if (content != null) {
  169. content.setParent(null);
  170. content.removeListener((ComponentContainer.ComponentAttachListener) this);
  171. content.removeListener((ComponentContainer.ComponentDetachListener) this);
  172. }
  173. // Sets the panel to be parent for the content
  174. newContent.setParent(this);
  175. // Sets the new content
  176. content = newContent;
  177. // Adds the event listeners for new content
  178. newContent
  179. .addListener((ComponentContainer.ComponentAttachListener) this);
  180. newContent
  181. .addListener((ComponentContainer.ComponentDetachListener) this);
  182. content = newContent;
  183. }
  184. /**
  185. * Create a ComponentContainer which is added by default to the Panel if
  186. * user does not specify any content.
  187. *
  188. * @return
  189. */
  190. private ComponentContainer createDefaultContent() {
  191. VerticalLayout layout = new VerticalLayout();
  192. // Force margins by default
  193. layout.setMargin(true);
  194. return layout;
  195. }
  196. /*
  197. * (non-Javadoc)
  198. *
  199. * @see
  200. * com.vaadin.ui.AbstractComponent#paintContent(com.vaadin.terminal.PaintTarget
  201. * )
  202. */
  203. @Override
  204. public void paintContent(PaintTarget target) throws PaintException {
  205. content.paint(target);
  206. if (isScrollable()) {
  207. target.addVariable(this, "scrollLeft", getScrollLeft());
  208. target.addVariable(this, "scrollTop", getScrollTop());
  209. }
  210. if (actionManager != null) {
  211. actionManager.paintActions(null, target);
  212. }
  213. }
  214. @Override
  215. public void requestRepaintAll() {
  216. // Panel has odd structure, delegate to layout
  217. requestRepaint();
  218. if (getContent() != null) {
  219. getContent().requestRepaintAll();
  220. }
  221. }
  222. /**
  223. * Adds the component into this container.
  224. *
  225. * @param c
  226. * the component to be added.
  227. * @see com.vaadin.ui.AbstractComponentContainer#addComponent(com.vaadin.ui.Component)
  228. */
  229. @Override
  230. public void addComponent(Component c) {
  231. content.addComponent(c);
  232. // No repaint request is made as we except the underlying container to
  233. // request repaints
  234. }
  235. /**
  236. * Removes the component from this container.
  237. *
  238. * @param c
  239. * The component to be added.
  240. * @see com.vaadin.ui.AbstractComponentContainer#removeComponent(com.vaadin.ui.Component)
  241. */
  242. @Override
  243. public void removeComponent(Component c) {
  244. content.removeComponent(c);
  245. // No repaint request is made as we except the underlying container to
  246. // request repaints
  247. }
  248. /**
  249. * Gets the component container iterator for going trough all the components
  250. * in the container.
  251. *
  252. * @return the Iterator of the components inside the container.
  253. * @see com.vaadin.ui.ComponentContainer#getComponentIterator()
  254. */
  255. public Iterator<Component> getComponentIterator() {
  256. return content.getComponentIterator();
  257. }
  258. /**
  259. * Called when one or more variables handled by the implementing class are
  260. * changed.
  261. *
  262. * @see com.vaadin.terminal.VariableOwner#changeVariables(Object, Map)
  263. */
  264. @Override
  265. public void changeVariables(Object source, Map variables) {
  266. super.changeVariables(source, variables);
  267. if (variables.containsKey(CLICK_EVENT)) {
  268. fireClick((Map<String, Object>) variables.get(CLICK_EVENT));
  269. }
  270. // Get new size
  271. final Integer newWidth = (Integer) variables.get("width");
  272. final Integer newHeight = (Integer) variables.get("height");
  273. if (newWidth != null && newWidth.intValue() != getWidth()) {
  274. setWidth(newWidth.intValue(), UNITS_PIXELS);
  275. }
  276. if (newHeight != null && newHeight.intValue() != getHeight()) {
  277. setHeight(newHeight.intValue(), UNITS_PIXELS);
  278. }
  279. // Scrolling
  280. final Integer newScrollX = (Integer) variables.get("scrollLeft");
  281. final Integer newScrollY = (Integer) variables.get("scrollTop");
  282. if (newScrollX != null && newScrollX.intValue() != getScrollLeft()) {
  283. // set internally, not to fire request repaint
  284. scrollOffsetX = newScrollX.intValue();
  285. }
  286. if (newScrollY != null && newScrollY.intValue() != getScrollTop()) {
  287. // set internally, not to fire request repaint
  288. scrollOffsetY = newScrollY.intValue();
  289. }
  290. // Actions
  291. if (actionManager != null) {
  292. actionManager.handleActions(variables, this);
  293. }
  294. }
  295. /* Scrolling functionality */
  296. /*
  297. * (non-Javadoc)
  298. *
  299. * @see com.vaadin.terminal.Scrollable#setScrollable(boolean)
  300. */
  301. public int getScrollLeft() {
  302. return scrollOffsetX;
  303. }
  304. /**
  305. * @deprecated use {@link #getScrollLeft()} instead
  306. */
  307. @Deprecated
  308. public int getScrollOffsetX() {
  309. return getScrollLeft();
  310. }
  311. /*
  312. * (non-Javadoc)
  313. *
  314. * @see com.vaadin.terminal.Scrollable#setScrollable(boolean)
  315. */
  316. public int getScrollTop() {
  317. return scrollOffsetY;
  318. }
  319. /**
  320. * @deprecated use {@link #getScrollTop()} instead
  321. */
  322. @Deprecated
  323. public int getScrollOffsetY() {
  324. return getScrollTop();
  325. }
  326. /*
  327. * (non-Javadoc)
  328. *
  329. * @see com.vaadin.terminal.Scrollable#setScrollable(boolean)
  330. */
  331. public boolean isScrollable() {
  332. return scrollable;
  333. }
  334. /*
  335. * (non-Javadoc)
  336. *
  337. * @see com.vaadin.terminal.Scrollable#setScrollable(boolean)
  338. */
  339. public void setScrollable(boolean isScrollingEnabled) {
  340. if (scrollable != isScrollingEnabled) {
  341. scrollable = isScrollingEnabled;
  342. requestRepaint();
  343. }
  344. }
  345. /*
  346. * (non-Javadoc)
  347. *
  348. * @see com.vaadin.terminal.Scrollable#setScrollLeft(int)
  349. */
  350. public void setScrollLeft(int pixelsScrolled) {
  351. if (pixelsScrolled < 0) {
  352. throw new IllegalArgumentException(
  353. "Scroll offset must be at least 0");
  354. }
  355. if (scrollOffsetX != pixelsScrolled) {
  356. scrollOffsetX = pixelsScrolled;
  357. requestRepaint();
  358. }
  359. }
  360. /**
  361. * @deprecated use setScrollLeft() method instead
  362. */
  363. @Deprecated
  364. public void setScrollOffsetX(int pixels) {
  365. setScrollLeft(pixels);
  366. }
  367. /* Documented in interface */
  368. public void setScrollTop(int pixelsScrolledDown) {
  369. if (pixelsScrolledDown < 0) {
  370. throw new IllegalArgumentException(
  371. "Scroll offset must be at least 0");
  372. }
  373. if (scrollOffsetY != pixelsScrolledDown) {
  374. scrollOffsetY = pixelsScrolledDown;
  375. requestRepaint();
  376. }
  377. }
  378. /**
  379. * @deprecated use setScrollTop() method instead
  380. */
  381. @Deprecated
  382. public void setScrollOffsetY(int pixels) {
  383. setScrollTop(pixels);
  384. }
  385. /* Documented in superclass */
  386. public void replaceComponent(Component oldComponent, Component newComponent) {
  387. content.replaceComponent(oldComponent, newComponent);
  388. }
  389. /**
  390. * A new component is attached to container.
  391. *
  392. * @see com.vaadin.ui.ComponentContainer.ComponentAttachListener#componentAttachedToContainer(com.vaadin.ui.ComponentContainer.ComponentAttachEvent)
  393. */
  394. public void componentAttachedToContainer(ComponentAttachEvent event) {
  395. if (event.getContainer() == content) {
  396. fireComponentAttachEvent(event.getAttachedComponent());
  397. }
  398. }
  399. /**
  400. * A component has been detached from container.
  401. *
  402. * @see com.vaadin.ui.ComponentContainer.ComponentDetachListener#componentDetachedFromContainer(com.vaadin.ui.ComponentContainer.ComponentDetachEvent)
  403. */
  404. public void componentDetachedFromContainer(ComponentDetachEvent event) {
  405. if (event.getContainer() == content) {
  406. fireComponentDetachEvent(event.getDetachedComponent());
  407. }
  408. }
  409. /**
  410. * Notifies the component that it is connected to an application.
  411. *
  412. * @see com.vaadin.ui.Component#attach()
  413. */
  414. @Override
  415. public void attach() {
  416. // can't call parent here as this is Panels hierarchy is a hack
  417. requestRepaint();
  418. if (content != null) {
  419. content.attach();
  420. }
  421. }
  422. /**
  423. * Notifies the component that it is detached from the application.
  424. *
  425. * @see com.vaadin.ui.Component#detach()
  426. */
  427. @Override
  428. public void detach() {
  429. // can't call parent here as this is Panels hierarchy is a hack
  430. if (content != null) {
  431. content.detach();
  432. }
  433. }
  434. /**
  435. * Removes all components from this container.
  436. *
  437. * @see com.vaadin.ui.ComponentContainer#removeAllComponents()
  438. */
  439. @Override
  440. public void removeAllComponents() {
  441. content.removeAllComponents();
  442. }
  443. /*
  444. * ACTIONS
  445. */
  446. protected ActionManager getActionManager() {
  447. if (actionManager == null) {
  448. actionManager = new ActionManager(this);
  449. }
  450. return actionManager;
  451. }
  452. public <T extends Action & com.vaadin.event.Action.Listener> void addAction(
  453. T action) {
  454. getActionManager().addAction(action);
  455. }
  456. public <T extends Action & com.vaadin.event.Action.Listener> void removeAction(
  457. T action) {
  458. if (actionManager != null) {
  459. actionManager.removeAction(action);
  460. }
  461. }
  462. public void addActionHandler(Handler actionHandler) {
  463. getActionManager().addActionHandler(actionHandler);
  464. }
  465. public void removeActionHandler(Handler actionHandler) {
  466. if (actionManager != null) {
  467. actionManager.removeActionHandler(actionHandler);
  468. }
  469. }
  470. /**
  471. * Removes all action handlers
  472. */
  473. public void removeAllActionHandlers() {
  474. if (actionManager != null) {
  475. actionManager.removeAllActionHandlers();
  476. }
  477. }
  478. /**
  479. * Add a click listener to the Panel. The listener is called whenever the
  480. * user clicks inside the Panel. Also when the click targets a component
  481. * inside the Panel, provided the targeted component does not prevent the
  482. * click event from propagating.
  483. *
  484. * Use {@link #removeListener(ClickListener)} to remove the listener.
  485. *
  486. * @param listener
  487. * The listener to add
  488. */
  489. public void addListener(ClickListener listener) {
  490. addListener(CLICK_EVENT, ClickEvent.class, listener,
  491. ClickListener.clickMethod);
  492. }
  493. /**
  494. * Remove a click listener from the Panel. The listener should earlier have
  495. * been added using {@link #addListener(ClickListener)}.
  496. *
  497. * @param listener
  498. * The listener to remove
  499. */
  500. public void removeListener(ClickListener listener) {
  501. removeListener(CLICK_EVENT, ClickEvent.class, listener);
  502. }
  503. /**
  504. * Fire a click event to all click listeners.
  505. *
  506. * @param object
  507. * The raw "value" of the variable change from the client side.
  508. */
  509. private void fireClick(Map<String, Object> parameters) {
  510. MouseEventDetails mouseDetails = MouseEventDetails
  511. .deSerialize((String) parameters.get("mouseDetails"));
  512. fireEvent(new ClickEvent(this, mouseDetails));
  513. }
  514. }