From 626bb8efb0c825f332c937ffaaadc9b402079539 Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Wed, 3 Jan 2007 20:17:37 +0000 Subject: r20517: re-add cleaned-up webapps (This used to be commit 5a3d6ad0b7cf0ecf8b57b4088b19f7d4291c990b) --- .../framework/source/class/qx/ui/basic/Atom.js | 397 ++ .../source/class/qx/ui/basic/HorizontalSpacer.js | 31 + .../framework/source/class/qx/ui/basic/Image.js | 611 +++ .../framework/source/class/qx/ui/basic/Inline.js | 37 + .../framework/source/class/qx/ui/basic/Label.js | 546 ++ .../source/class/qx/ui/basic/Terminator.js | 187 + .../source/class/qx/ui/basic/VerticalSpacer.js | 31 + .../source/class/qx/ui/component/ColorPopup.js | 387 ++ .../source/class/qx/ui/component/ColorSelector.js | 1312 +++++ .../source/class/qx/ui/component/DateChooser.js | 518 ++ .../source/class/qx/ui/core/ClientDocument.js | 450 ++ .../class/qx/ui/core/ClientDocumentBlocker.js | 39 + .../framework/source/class/qx/ui/core/Parent.js | 1207 +++++ .../framework/source/class/qx/ui/core/ScrollBar.js | 260 + .../framework/source/class/qx/ui/core/Widget.js | 5703 ++++++++++++++++++++ .../framework/source/class/qx/ui/embed/Flash.js | 468 ++ .../framework/source/class/qx/ui/embed/Gallery.js | 556 ++ .../source/class/qx/ui/embed/GalleryList.js | 400 ++ .../source/class/qx/ui/embed/HtmlEmbed.js | 112 + .../source/class/qx/ui/embed/IconHtmlEmbed.js | 134 + .../framework/source/class/qx/ui/embed/Iframe.js | 430 ++ .../source/class/qx/ui/embed/LinkEmbed.js | 88 + .../source/class/qx/ui/embed/NodeEmbed.js | 48 + .../source/class/qx/ui/embed/TextEmbed.js | 121 + .../framework/source/class/qx/ui/form/Button.js | 200 + .../framework/source/class/qx/ui/form/CheckBox.js | 210 + .../framework/source/class/qx/ui/form/ComboBox.js | 826 +++ .../source/class/qx/ui/form/ComboBoxEx.js | 1044 ++++ .../source/class/qx/ui/form/InputCheckSymbol.js | 93 + .../framework/source/class/qx/ui/form/List.js | 383 ++ .../framework/source/class/qx/ui/form/ListItem.js | 115 + .../source/class/qx/ui/form/PasswordField.js | 31 + .../source/class/qx/ui/form/RadioButton.js | 185 + .../source/class/qx/ui/form/RepeatButton.js | 127 + .../framework/source/class/qx/ui/form/Spinner.js | 683 +++ .../framework/source/class/qx/ui/form/TextArea.js | 53 + .../framework/source/class/qx/ui/form/TextField.js | 538 ++ .../source/class/qx/ui/groupbox/CheckGroupBox.js | 39 + .../source/class/qx/ui/groupbox/GroupBox.js | 156 + .../source/class/qx/ui/groupbox/RadioGroupBox.js | 39 + .../source/class/qx/ui/layout/BoxLayout.js | 273 + .../source/class/qx/ui/layout/CanvasLayout.js | 45 + .../source/class/qx/ui/layout/DockLayout.js | 116 + .../source/class/qx/ui/layout/FlowLayout.js | 106 + .../source/class/qx/ui/layout/GridLayout.js | 864 +++ .../class/qx/ui/layout/HorizontalBoxLayout.js | 29 + .../source/class/qx/ui/layout/VerticalBoxLayout.js | 29 + .../source/class/qx/ui/listview/ContentCellHtml.js | 37 + .../class/qx/ui/listview/ContentCellIconHtml.js | 39 + .../class/qx/ui/listview/ContentCellImage.js | 57 + .../source/class/qx/ui/listview/ContentCellLink.js | 40 + .../source/class/qx/ui/listview/ContentCellText.js | 40 + .../source/class/qx/ui/listview/Header.js | 294 + .../source/class/qx/ui/listview/HeaderCell.js | 255 + .../source/class/qx/ui/listview/HeaderSeparator.js | 30 + .../source/class/qx/ui/listview/ListView.js | 373 ++ .../source/class/qx/ui/listview/ListViewPane.js | 556 ++ .../framework/source/class/qx/ui/menu/Button.js | 354 ++ .../framework/source/class/qx/ui/menu/CheckBox.js | 85 + .../framework/source/class/qx/ui/menu/Layout.js | 56 + .../framework/source/class/qx/ui/menu/Menu.js | 907 ++++ .../source/class/qx/ui/menu/RadioButton.js | 118 + .../framework/source/class/qx/ui/menu/Separator.js | 76 + .../framework/source/class/qx/ui/menubar/Button.js | 28 + .../source/class/qx/ui/menubar/MenuBar.js | 28 + .../source/class/qx/ui/pageview/AbstractBar.js | 129 + .../source/class/qx/ui/pageview/AbstractButton.js | 219 + .../source/class/qx/ui/pageview/AbstractPage.js | 75 + .../class/qx/ui/pageview/AbstractPageView.js | 84 + .../source/class/qx/ui/pageview/AbstractPane.js | 27 + .../source/class/qx/ui/pageview/buttonview/Bar.js | 75 + .../class/qx/ui/pageview/buttonview/Button.js | 120 + .../class/qx/ui/pageview/buttonview/ButtonView.js | 98 + .../source/class/qx/ui/pageview/buttonview/Page.js | 30 + .../source/class/qx/ui/pageview/buttonview/Pane.js | 51 + .../source/class/qx/ui/pageview/tabview/Bar.js | 33 + .../source/class/qx/ui/pageview/tabview/Button.js | 189 + .../source/class/qx/ui/pageview/tabview/Page.js | 30 + .../source/class/qx/ui/pageview/tabview/Pane.js | 33 + .../source/class/qx/ui/pageview/tabview/TabView.js | 86 + .../framework/source/class/qx/ui/popup/Popup.js | 329 ++ .../source/class/qx/ui/popup/PopupAtom.js | 51 + .../framework/source/class/qx/ui/popup/ToolTip.js | 255 + .../source/class/qx/ui/resizer/Resizer.js | 417 ++ .../class/qx/ui/splitpane/HorizontalSplitPane.js | 58 + .../source/class/qx/ui/splitpane/SplitPane.js | 759 +++ .../class/qx/ui/splitpane/VerticalSplitPane.js | 58 + .../class/qx/ui/table/AbstractDataCellRenderer.js | 127 + .../source/class/qx/ui/table/AbstractTableModel.js | 150 + .../class/qx/ui/table/BooleanDataCellRenderer.js | 48 + .../source/class/qx/ui/table/CellEditorFactory.js | 62 + .../class/qx/ui/table/CheckBoxCellEditorFactory.js | 43 + .../source/class/qx/ui/table/DataCellRenderer.js | 80 + .../source/class/qx/ui/table/DataRowRenderer.js | 54 + .../class/qx/ui/table/DefaultDataCellRenderer.js | 189 + .../class/qx/ui/table/DefaultDataRowRenderer.js | 106 + .../class/qx/ui/table/DefaultHeaderCellRenderer.js | 63 + .../source/class/qx/ui/table/HeaderCellRenderer.js | 69 + .../class/qx/ui/table/IconDataCellRenderer.js | 182 + .../class/qx/ui/table/IconHeaderCellRenderer.js | 84 + .../source/class/qx/ui/table/RemoteTableModel.js | 435 ++ .../source/class/qx/ui/table/SelectionManager.js | 163 + .../source/class/qx/ui/table/SelectionModel.js | 427 ++ .../source/class/qx/ui/table/SimpleTableModel.js | 335 ++ .../framework/source/class/qx/ui/table/Table.js | 1062 ++++ .../source/class/qx/ui/table/TableColumnModel.js | 399 ++ .../source/class/qx/ui/table/TableModel.js | 243 + .../source/class/qx/ui/table/TablePane.js | 486 ++ .../source/class/qx/ui/table/TablePaneHeader.js | 276 + .../source/class/qx/ui/table/TablePaneModel.js | 179 + .../source/class/qx/ui/table/TablePaneScroller.js | 1331 +++++ .../qx/ui/table/TextFieldCellEditorFactory.js | 58 + .../framework/source/class/qx/ui/toolbar/Button.js | 47 + .../source/class/qx/ui/toolbar/CheckBox.js | 86 + .../source/class/qx/ui/toolbar/MenuButton.js | 258 + .../framework/source/class/qx/ui/toolbar/Part.js | 82 + .../source/class/qx/ui/toolbar/PartHandle.js | 35 + .../source/class/qx/ui/toolbar/RadioButton.js | 116 + .../source/class/qx/ui/toolbar/Separator.js | 35 + .../source/class/qx/ui/toolbar/ToolBar.js | 242 + .../source/class/qx/ui/tree/AbstractTreeElement.js | 502 ++ .../framework/source/class/qx/ui/tree/Tree.js | 398 ++ .../framework/source/class/qx/ui/tree/TreeFile.js | 62 + .../source/class/qx/ui/tree/TreeFolder.js | 605 +++ .../qx/ui/treefullcontrol/AbstractTreeElement.js | 529 ++ .../source/class/qx/ui/treefullcontrol/Tree.js | 539 ++ .../source/class/qx/ui/treefullcontrol/TreeFile.js | 81 + .../class/qx/ui/treefullcontrol/TreeFolder.js | 651 +++ .../qx/ui/treefullcontrol/TreeRowStructure.js | 260 + .../framework/source/class/qx/ui/window/Window.js | 1441 +++++ 130 files changed, 39456 insertions(+) create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/basic/Atom.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/basic/HorizontalSpacer.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/basic/Image.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/basic/Inline.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/basic/Label.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/basic/Terminator.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/basic/VerticalSpacer.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/component/ColorPopup.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/component/ColorSelector.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/component/DateChooser.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/core/ClientDocument.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/core/ClientDocumentBlocker.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/core/Parent.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/core/ScrollBar.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/core/Widget.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/embed/Flash.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/embed/Gallery.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/embed/GalleryList.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/embed/HtmlEmbed.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/embed/IconHtmlEmbed.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/embed/Iframe.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/embed/LinkEmbed.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/embed/NodeEmbed.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/embed/TextEmbed.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/Button.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/CheckBox.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/ComboBox.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/ComboBoxEx.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/InputCheckSymbol.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/List.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/ListItem.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/PasswordField.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/RadioButton.js create mode 100755 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/RepeatButton.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/Spinner.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/TextArea.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/TextField.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/groupbox/CheckGroupBox.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/groupbox/GroupBox.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/groupbox/RadioGroupBox.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/layout/BoxLayout.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/layout/CanvasLayout.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/layout/DockLayout.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/layout/FlowLayout.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/layout/GridLayout.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/layout/HorizontalBoxLayout.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/layout/VerticalBoxLayout.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellHtml.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellIconHtml.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellImage.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellLink.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellText.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/Header.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/HeaderCell.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/HeaderSeparator.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/ListView.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/ListViewPane.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menu/Button.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menu/CheckBox.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menu/Layout.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menu/Menu.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menu/RadioButton.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menu/Separator.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menubar/Button.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menubar/MenuBar.js create mode 100755 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractBar.js create mode 100755 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractButton.js create mode 100755 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractPage.js create mode 100755 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractPageView.js create mode 100755 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractPane.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/Bar.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/Button.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/ButtonView.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/Page.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/Pane.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/Bar.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/Button.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/Page.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/Pane.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/TabView.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/popup/Popup.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/popup/PopupAtom.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/popup/ToolTip.js create mode 100755 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/resizer/Resizer.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/splitpane/HorizontalSplitPane.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/splitpane/SplitPane.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/splitpane/VerticalSplitPane.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/AbstractDataCellRenderer.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/AbstractTableModel.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/BooleanDataCellRenderer.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/CellEditorFactory.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/CheckBoxCellEditorFactory.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/DataCellRenderer.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/DataRowRenderer.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/DefaultDataCellRenderer.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/DefaultDataRowRenderer.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/DefaultHeaderCellRenderer.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/HeaderCellRenderer.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/IconDataCellRenderer.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/IconHeaderCellRenderer.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/RemoteTableModel.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/SelectionManager.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/SelectionModel.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/SimpleTableModel.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/Table.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/TableColumnModel.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/TableModel.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/TablePane.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/TablePaneHeader.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/TablePaneModel.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/TablePaneScroller.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/TextFieldCellEditorFactory.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/toolbar/Button.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/toolbar/CheckBox.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/toolbar/MenuButton.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/toolbar/Part.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/toolbar/PartHandle.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/toolbar/RadioButton.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/toolbar/Separator.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/toolbar/ToolBar.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/tree/AbstractTreeElement.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/tree/Tree.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/tree/TreeFile.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/tree/TreeFolder.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/treefullcontrol/AbstractTreeElement.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/treefullcontrol/Tree.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/treefullcontrol/TreeFile.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/treefullcontrol/TreeFolder.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/treefullcontrol/TreeRowStructure.js create mode 100644 webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/window/Window.js (limited to 'webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui') diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/basic/Atom.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/basic/Atom.js new file mode 100644 index 0000000000..5a1c0ae97f --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/basic/Atom.js @@ -0,0 +1,397 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_basic) +#optional(qx.ui.embed.Flash) + +************************************************************************ */ + +/*! + A multi-prupose widget used by many more complex widgets. + + The intended purpose of qx.ui.basic.Atom is to easily align the common icon-text combination in different ways. + This is useful for all types of buttons, menuentires, tooltips, ... +*/ +qx.OO.defineClass("qx.ui.basic.Atom", qx.ui.layout.BoxLayout, +function(vLabel, vIcon, vIconWidth, vIconHeight, vFlash) +{ + qx.ui.layout.BoxLayout.call(this); + + if (this.getOrientation() == null) { + this.setOrientation("horizontal"); + } + + // Prohibit selection + this.setSelectable(false); + + // Disable flex support + this.getLayoutImpl().setEnableFlexSupport(false); + + // Apply constructor arguments + if (qx.util.Validation.isValidString(vLabel)) { + this.setLabel(vLabel); + } else { + this.setLabel(""); + } + + // Simple flash wrapper + if (qx.OO.isAvailable("qx.ui.embed.Flash") && qx.util.Validation.isValidString(vFlash) && qx.util.Validation.isValidNumber(vIconWidth) && qx.util.Validation.isValidNumber(vIconHeight) && qx.ui.embed.Flash.getPlayerVersion().getMajor() > 0) + { + this._flashMode = true; + + this.setIcon(vFlash); + + // flash needs explicit dimensions! + this.setIconWidth(vIconWidth); + this.setIconHeight(vIconHeight); + } + else if (qx.util.Validation.isValidString(vIcon)) + { + this.setIcon(vIcon); + + if (qx.util.Validation.isValidNumber(vIconWidth)) { + this.setIconWidth(vIconWidth); + } + + if (qx.util.Validation.isValidNumber(vIconHeight)) { + this.setIconHeight(vIconHeight); + } + } +}); + +qx.ui.basic.Atom.SHOW_LABEL = "label"; +qx.ui.basic.Atom.SHOW_ICON = "icon"; +qx.ui.basic.Atom.SHOW_BOTH = "both"; + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + The label/caption/text of the qx.ui.basic.Atom instance +*/ +qx.OO.addProperty({ name : "label", type : "string" }); + +/*! + Any URI String supported by qx.ui.basic.Image to display a icon +*/ +qx.OO.addProperty({ name : "icon", type : "string" }); + +/** + * Any URI String supported by qx.ui.basic.Image to display a disabled icon. + *

+ * If not set the normal icon is shown transparently. + */ +qx.OO.addProperty({ name : "disabledIcon", type : "string" }); + +/*! + Configure the visibility of the sub elements/widgets. + Possible values: both, text, icon, none +*/ +qx.OO.addProperty({ name : "show", type : "string", defaultValue : "both", possibleValues : [ "both", "label", "icon", "none", null ] }); + +/*! + The position of the icon in relation to the text. + Only useful/needed if text and icon is configured and 'show' is configured as 'both' (default) +*/ +qx.OO.addProperty({ name : "iconPosition", type : "string", defaultValue : "left", possibleValues : [ "top", "right", "bottom", "left" ] }); + +/*! + The width of the icon. + If configured, this makes qx.ui.basic.Atom a little bit faster as it does not need to wait until the image loading is finished. +*/ +qx.OO.addProperty({ name : "iconWidth", type : "number" }); + +/*! + The height of the icon + If configured, this makes qx.ui.basic.Atom a little bit faster as it does not need to wait until the image loading is finished. +*/ +qx.OO.addProperty({ name : "iconHeight", type : "number" }); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "atom" }); + + + + + +/* +--------------------------------------------------------------------------- + SUB WIDGETS +--------------------------------------------------------------------------- +*/ + +qx.Proto._flashMode = false; + +qx.Proto._labelObject = null; +qx.Proto._iconObject = null; + +qx.Proto._createLabel = function() +{ + var l = this._labelObject = new qx.ui.basic.Label(this.getLabel()); + + l.setAnonymous(true); + l.setEnabled(this.getEnabled()); + l.setSelectable(false); + + this.addAt(l, this._iconObject ? 1 : 0); +} + +qx.Proto._createIcon = function() +{ + if (this._flashMode && qx.OO.isAvailable("qx.ui.embed.Flash")) + { + var i = this._iconObject = new qx.ui.embed.Flash(this.getIcon()); + } + else + { + var i = this._iconObject = new qx.ui.basic.Image(); + } + + i.setAnonymous(true); + + this._updateIcon(); + + this.addAt(i, 0); +} + +qx.Proto._updateIcon = function() { + // NOTE: We have to check whether the properties "icon" and "disabledIcon" + // exist, because some child classes remove them. + if (this._iconObject && this.getIcon && this.getDisabledIcon) { + var disabledIcon = this.getDisabledIcon(); + if (disabledIcon) { + if (this.getEnabled()) { + this._iconObject.setSource(this.getIcon()); + } else { + this._iconObject.setSource(disabledIcon); + } + this._iconObject.setEnabled(true); + } else { + this._iconObject.setSource(this.getIcon()); + this._iconObject.setEnabled(this.getEnabled()); + } + } +} + +qx.Proto.getLabelObject = function() { + return this._labelObject; +} + +qx.Proto.getIconObject = function() { + return this._iconObject; +} + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyEnabled = function(propValue, propOldValue, propData) +{ + this._updateIcon(); + + if (this._labelObject) { + this._labelObject.setEnabled(propValue); + } + + return qx.ui.layout.BoxLayout.prototype._modifyEnabled.call(this, propValue, propOldValue, propData); +} + +qx.Proto._modifyIconPosition = function(propValue, propOldValue, propData) +{ + switch(propValue) + { + case "top": + case "bottom": + this.setOrientation("vertical"); + this.setReverseChildrenOrder(propValue == "bottom"); + break; + + default: + this.setOrientation("horizontal"); + this.setReverseChildrenOrder(propValue == "right"); + break; + } + + return true; +} + +qx.Proto._modifyShow = function(propValue, propOldValue, propData) +{ + this._handleIcon(); + this._handleLabel(); + + return true; +} + +qx.Proto._modifyLabel = function(propValue, propOldValue, propData) +{ + if (this._labelObject) { + this._labelObject.setHtml(propValue); + } + + this._handleLabel(); + + return true; +} + +qx.Proto._modifyIcon = function(propValue, propOldValue, propData) +{ + this._updateIcon(); + this._handleIcon(); + + return true; +} + +qx.Proto._modifyDisabledIcon = function(propValue, propOldValue, propData) +{ + this._updateIcon(); + this._handleIcon(); + + return true; +} + +qx.Proto._modifyIconWidth = function(propValue, propOldValue, propData) +{ + this._iconObject.setWidth(propValue); + return true; +} + +qx.Proto._modifyIconHeight = function(propValue, propOldValue, propData) +{ + this._iconObject.setHeight(propValue); + return true; +} + + + + + + +/* +--------------------------------------------------------------------------- + HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._iconIsVisible = false; +qx.Proto._labelIsVisible = false; + +qx.Proto._handleLabel = function() +{ + switch(this.getShow()) + { + case qx.ui.basic.Atom.SHOW_LABEL: + case qx.ui.basic.Atom.SHOW_BOTH: + this._labelIsVisible = qx.util.Validation.isValidString(this.getLabel()); + break; + + default: + this._labelIsVisible = false; + } + + if (this._labelIsVisible) + { + this._labelObject ? this._labelObject.setDisplay(true) : this._createLabel(); + } + else if (this._labelObject) + { + this._labelObject.setDisplay(false); + } +} + +qx.Proto._handleIcon = function() +{ + switch(this.getShow()) + { + case qx.ui.basic.Atom.SHOW_ICON: + case qx.ui.basic.Atom.SHOW_BOTH: + this._iconIsVisible = qx.util.Validation.isValidString(this.getIcon()); + break; + + default: + this._iconIsVisible = false; + } + + if (this._iconIsVisible) + { + this._iconObject ? this._iconObject.setDisplay(true) : this._createIcon(); + } + else if (this._iconObject) + { + this._iconObject.setDisplay(false); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + CLONE +--------------------------------------------------------------------------- +*/ + +// Omit recursive cloning +qx.Proto._cloneRecursive = qx.util.Return.returnTrue; + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + if (this._iconObject) + { + this._iconObject.dispose(); + this._iconObject = null; + } + + if (this._labelObject) + { + this._labelObject.dispose(); + this._labelObject = null; + } + + return qx.ui.layout.BoxLayout.prototype.dispose.call(this); +} \ No newline at end of file diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/basic/HorizontalSpacer.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/basic/HorizontalSpacer.js new file mode 100644 index 0000000000..9db8f12064 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/basic/HorizontalSpacer.js @@ -0,0 +1,31 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_basic) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.basic.HorizontalSpacer", qx.ui.basic.Terminator, +function() +{ + qx.ui.basic.Terminator.call(this); + + this.setWidth("1*"); +}); diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/basic/Image.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/basic/Image.js new file mode 100644 index 0000000000..0cc25a9d5c --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/basic/Image.js @@ -0,0 +1,611 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_basic) +#resource(core:static/image) + +************************************************************************ */ + +/** + * This widget is for all images in qooxdoo projects. + * + * @event error {qx.event.type.Event} + */ +qx.OO.defineClass("qx.ui.basic.Image", qx.ui.basic.Terminator, +function(vSource, vWidth, vHeight) +{ + qx.ui.basic.Terminator.call(this); + + // Reset Alt and Title + this.setHtmlProperty("alt", ""); + this.setHtmlProperty("title", ""); + + // Apply constructor arguments + this.setSource(qx.util.Validation.isValid(vSource) ? vSource : "static/image/blank.gif"); + + // Dimensions + this.setWidth(qx.util.Validation.isValid(vWidth) ? vWidth : "auto"); + this.setHeight(qx.util.Validation.isValid(vHeight) ? vHeight : "auto"); + + // Prohibit selection + this.setSelectable(false); +}); + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + The source uri of the image. +*/ +qx.OO.addProperty({ name : "source", type : "string" }); + +/*! + The assigned preloader instance of the image. +*/ +qx.OO.addProperty({ name : "preloader", type : "object" }); + +/*! + The loading status. + + True if the image is loaded correctly. False if no image is loaded + or the one that should be loaded is currently loading or not available. +*/ +qx.OO.addProperty({ name : "loaded", type : "boolean", defaultValue : false }); + +/*! + Should the image be maxified in it's own container? +*/ +qx.OO.addProperty({ name : "resizeToInner", type : "boolean", defaultValue : false }); + +/*! + Appearance of the widget +*/ +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "image" }); + + + + + +/* +--------------------------------------------------------------------------- + EVENT MAPPERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._onload = function() { + this.setLoaded(true); +} + +qx.Proto._onerror = function() +{ + this.debug("Could not load: " + this.getSource()); + + this.setLoaded(false); + + if (this.hasEventListeners("error")) { + this.dispatchEvent(new qx.event.type.Event("error"), true); + } +} + + + + + +/* +--------------------------------------------------------------------------- + DISPLAYBLE HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._beforeAppear = function() +{ + var vSource = this.getSource(); + + if (qx.util.Validation.isValidString(vSource)) { + qx.manager.object.ImageManager.getInstance()._sources[vSource]++; + } + + return qx.ui.basic.Terminator.prototype._beforeAppear.call(this); +} + +qx.Proto._beforeDisappear = function() +{ + var vSource = this.getSource(); + + if (qx.util.Validation.isValidString(vSource)) + { + if (qx.manager.object.ImageManager.getInstance()._sources[vSource] <= 1) + { + delete qx.manager.object.ImageManager.getInstance()._sources[vSource]; + } + else + { + qx.manager.object.ImageManager.getInstance()._sources[vSource]--; + } + } + + return qx.ui.basic.Terminator.prototype._beforeDisappear.call(this); +} + + + + + +/* +--------------------------------------------------------------------------- + MODIFIERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifySource = function(propValue, propOldValue, propData) +{ + if (propValue && typeof qx.manager.object.ImageManager.getInstance()._sources[propValue] === "undefined") { + qx.manager.object.ImageManager.getInstance()._sources[propValue] = 0; + } + + if (propOldValue) + { + if (qx.manager.object.ImageManager.getInstance()._sources[propOldValue] <= 1) + { + delete qx.manager.object.ImageManager.getInstance()._sources[propOldValue]; + } + else + { + qx.manager.object.ImageManager.getInstance()._sources[propOldValue]--; + } + } + + if (this.isCreated()) + { + if (propValue) + { + this.setPreloader(qx.manager.object.ImagePreloaderManager.getInstance().create(qx.manager.object.AliasManager.getInstance().resolvePath(propValue))); + } + else if (propOldValue) + { + this._resetContent(); + this.setPreloader(null); + } + } + + return true; +} + +qx.Proto._modifyPreloader = function(propValue, propOldValue, propData) +{ + if (propOldValue) + { + // remove event connection + propOldValue.removeEventListener("load", this._onload, this); + propOldValue.removeEventListener("error", this._onerror, this); + } + + if (propValue) + { + // Register to image manager + qx.manager.object.ImageManager.getInstance().add(this); + + // Omit here, otherwise the later setLoaded(true) + // will not be executed (prevent recursion) + + // Changed: Use forceLoaded instead of setLoaded => should be faster + this.forceLoaded(false); + + if (propValue.isErroneous()) + { + this._onerror(); + } + else if (propValue.isLoaded()) + { + this.setLoaded(true); + } + else + { + propValue.addEventListener("load", this._onload, this); + propValue.addEventListener("error", this._onerror, this); + } + } + else + { + // Remove from image manager + qx.manager.object.ImageManager.getInstance().remove(this); + + this.setLoaded(false); + } + + return true; +} + +qx.Proto._modifyLoaded = function(propValue, propOldValue, propData) +{ + if (propValue && this.isCreated()) + { + this._applyContent(); + } + else if (!propValue) + { + this._invalidatePreferredInnerWidth(); + this._invalidatePreferredInnerHeight(); + } + + return true; +} + +qx.Proto._modifyElement = function(propValue, propOldValue, propData) +{ + if (propValue) + { + if (!this._image) + { + try + { + // Create Image-Node + // Webkit has problems with "new Image". Maybe related to "new Function" with + // is also not working correctly. + if (qx.sys.Client.getInstance().isWebkit()) + { + this._image = document.createElement("img"); + } + else + { + this._image = new Image; + } + + // Possible alternative for MSHTML for PNG images + // But it seems not to be faster + // this._image = document.createElement("div"); + + // this costs much performance, move setup to blank gif to error handling + // is this SSL save? + // this._image.src = qx.manager.object.AliasManager.getInstance().resolvePath("static/image/blank.gif"); + + this._image.style.border = "0 none"; + this._image.style.verticalAlign = "top"; + } + catch(ex) + { + this.error("Failed while creating image #1", ex); + } + + if (!qx.sys.Client.getInstance().isMshtml()) { + this._applyEnabled(); + } + } + + propValue.appendChild(this._image); + } + + // call widget implmentation + qx.ui.basic.Terminator.prototype._modifyElement.call(this, propValue, propOldValue, propData); + + if (propValue) + { + try + { + // initialisize preloader + var vSource = this.getSource(); + if (qx.util.Validation.isValidString(vSource)) { + this.setPreloader(qx.manager.object.ImagePreloaderManager.getInstance().create(qx.manager.object.AliasManager.getInstance().resolvePath(vSource))); + } + } + catch(ex) + { + this.error("Failed while creating image #2", ex); + } + } + + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + CLIENT OPTIMIZED MODIFIERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._postApply = function() +{ + if (!this.getLoaded()) { + this._updateContent(qx.manager.object.AliasManager.getInstance().resolvePath("static/image/blank.gif")); + return; + } + + this._postApplyDimensions(); + this._updateContent(); +} + +if (qx.sys.Client.getInstance().isMshtml()) +{ + qx.Proto._modifyEnabled = function(propValue, propOldValue, propData) + { + if (this._image) { + this._applyEnabled(); + } + + return qx.ui.basic.Terminator.prototype._modifyEnabled.call(this, propValue, propOldValue, propData); + } + + qx.Proto._updateContent = function(vSource) + { + var i = this._image; + var pl = this.getPreloader(); + + if (pl.getIsPng() && this.getEnabled()) + { + i.src = qx.manager.object.AliasManager.getInstance().resolvePath("static/image/blank.gif"); + i.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + (vSource || pl.getSource()) + "',sizingMethod='scale')"; + } + else + { + i.src = vSource || pl.getSource(); + i.style.filter = this.getEnabled() ? "" : "Gray() Alpha(Opacity=30)"; + } + } + + qx.Proto._resetContent = function() + { + var i = this._image; + + i.src = qx.manager.object.AliasManager.getInstance().resolvePath("static/image/blank.gif"); + i.style.filter = ""; + } + + qx.Proto._applyEnabled = qx.Proto._postApply; +} +else +{ + qx.Proto._updateContent = function(vSource) { + this._image.src = vSource || this.getPreloader().getSource(); + } + + qx.Proto._resetContent = function() { + this._image.src = qx.manager.object.AliasManager.getInstance().resolvePath("static/image/blank.gif"); + } + + qx.Proto._applyEnabled = function() + { + if (this._image) + { + var o = this.getEnabled() ? "" : 0.3; + var s = this._image.style; + + s.opacity = s.KhtmlOpacity = s.MozOpacity = o; + } + } + + qx.Proto._modifyEnabled = function(propValue, propOldValue, propData) + { + if (this._image) { + this._applyEnabled(); + } + + return qx.ui.basic.Terminator.prototype._modifyEnabled.call(this, propValue, propOldValue, propData); + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + PREFERRED DIMENSIONS: INNER +--------------------------------------------------------------------------- +*/ + +qx.Proto._computePreferredInnerWidth = function() +{ + if (this.getLoaded()) + { + return this.getPreloader().getWidth(); + } + else if (qx.util.Validation.isValidString(this.getSource())) + { + var vPreloader = qx.manager.object.ImagePreloaderManager.getInstance().get(qx.manager.object.AliasManager.getInstance().resolvePath(this.getSource())); + + if (vPreloader && vPreloader.isLoaded()) { + return vPreloader.getWidth(); + } + } + + return 0; +} + +qx.Proto._computePreferredInnerHeight = function() +{ + if (this.getLoaded()) + { + return this.getPreloader().getHeight(); + } + else if (qx.util.Validation.isValidString(this.getSource())) + { + var vPreloader = qx.manager.object.ImagePreloaderManager.getInstance().get(qx.manager.object.AliasManager.getInstance().resolvePath(this.getSource())); + + if (vPreloader && vPreloader.isLoaded()) { + return vPreloader.getHeight(); + } + } + + return 0; +} + + + + + + + +/* +--------------------------------------------------------------------------- + APPLY +--------------------------------------------------------------------------- +*/ + +qx.Proto._applyContent = function() +{ + qx.ui.basic.Terminator.prototype._applyContent.call(this); + + // Images load asyncron, so we need to force flushing here + // to get an up-to-date view when an image is loaded. + qx.ui.core.Widget.flushGlobalQueues(); +} + +if (qx.sys.Client.getInstance().isMshtml()) +{ + qx.Proto._postApplyDimensions = function() + { + try + { + var vImageStyle = this._image.style; + + if (this.getResizeToInner()) + { + vImageStyle.pixelWidth = this.getInnerWidth(); + vImageStyle.pixelHeight = this.getInnerHeight(); + } + else + { + vImageStyle.pixelWidth = this.getPreferredInnerWidth(); + vImageStyle.pixelHeight = this.getPreferredInnerHeight(); + } + } + catch(ex) + { + this.error("postApplyDimensions failed", ex); + } + } +} +else +{ + qx.Proto._postApplyDimensions = function() + { + try + { + var vImageNode = this._image; + + if (this.getResizeToInner()) + { + vImageNode.width = this.getInnerWidth(); + vImageNode.height = this.getInnerHeight(); + } + else + { + vImageNode.width = this.getPreferredInnerWidth(); + vImageNode.height = this.getPreferredInnerHeight(); + } + } + catch(ex) + { + this.error("postApplyDimensions failed", ex); + } + } +} + + + + +/* +--------------------------------------------------------------------------- + CHANGES IN DIMENSIONS +--------------------------------------------------------------------------- +*/ + +if (qx.sys.Client.getInstance().isMshtml()) +{ + qx.Proto._changeInnerWidth = function(vNew, vOld) + { + if (this.getResizeToInner()) { + this._image.style.pixelWidth = vNew; + } + } + + qx.Proto._changeInnerHeight = function(vNew, vOld) + { + if (this.getResizeToInner()) { + this._image.style.pixelHeight = vNew; + } + } +} +else +{ + qx.Proto._changeInnerWidth = function(vNew, vOld) + { + if (this.getResizeToInner()) { + this._image.width = vNew; + } + } + + qx.Proto._changeInnerHeight = function(vNew, vOld) + { + if (this.getResizeToInner()) { + this._image.height = vNew; + } + } +} + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + var vPreloader = this.getPreloader(); + if (vPreloader) + { + // remove event connection + vPreloader.removeEventListener("load", this._onload, this); + vPreloader.removeEventListener("error", this._onerror, this); + + this.forcePreloader(null); + } + + if (this._image) + { + // Remove leaking filter attribute before leaving page + this._image.style.filter = ""; + this._image = null; + } + + qx.manager.object.ImageManager.getInstance().remove(this); + + return qx.ui.basic.Terminator.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/basic/Inline.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/basic/Inline.js new file mode 100644 index 0000000000..f6c59cf486 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/basic/Inline.js @@ -0,0 +1,37 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_basic) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.basic.Inline", qx.ui.layout.CanvasLayout, +function(vId) +{ + qx.ui.layout.CanvasLayout.call(this); + + this.setStyleProperty("position", "relative"); + + if (qx.util.Validation.isValidString(vId)) { + this.setInlineNodeId(vId); + } +}); + +qx.OO.addProperty({ name : "inlineNodeId", type : "string" }); diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/basic/Label.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/basic/Label.js new file mode 100644 index 0000000000..a284649d98 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/basic/Label.js @@ -0,0 +1,546 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_basic) +#require(qx.renderer.font.FontCache) +#after(qx.renderer.font.FontObject) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.basic.Label", qx.ui.basic.Terminator, +function(vHtml, vMnemonic) +{ + qx.ui.basic.Terminator.call(this); + + // Apply constructor arguments + if (qx.util.Validation.isValidString(vHtml)) { + this.setHtml(vHtml); + } + + if (qx.util.Validation.isValidString(vMnemonic)) { + this.setMnemonic(vMnemonic); + } + + // Prohibit stretching through layout handler + this.setAllowStretchX(false); + this.setAllowStretchY(false); + + // Auto Sized + this.auto(); +}); + +qx.Class._measureNodes = {}; + + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "label" }); + +/*! + Any text string which can contain HTML, too +*/ +qx.OO.addProperty({ name : "html", type : "string" }); + +/*! + The alignment of the text. +*/ +qx.OO.addProperty({ name : "textAlign", type : "string", defaultValue : "left", possibleValues : [ "left", "center", "right", "justify" ] }); + +/*! + The styles which should be copied +*/ +qx.OO.addProperty({ name : "fontPropertiesProfile", type : "string", defaultValue : "default", possibleValues : [ "none", "default", "extended", "multiline", "extendedmultiline", "all" ] }); + +/*! + A single character which will be underlined inside the text. +*/ +qx.OO.addProperty({ name : "mnemonic", type : "string" }); + +/*! + The font property describes how to paint the font on the widget. +*/ +qx.OO.addProperty({ name : "font", type : "object", instance : "qx.renderer.font.Font", convert : qx.renderer.font.FontCache, allowMultipleArguments : true }); + +/*! + Wrap the text? +*/ +qx.OO.addProperty({ name : "wrap", type : "boolean", defaultValue : true }); + + + + + + + + + +/* ************************************************************************ + Class data, properties and methods +************************************************************************ */ + +/* +--------------------------------------------------------------------------- + DATA +--------------------------------------------------------------------------- +*/ + +qx.ui.basic.Label.SYMBOL_ELLIPSIS = String.fromCharCode(8230); +qx.ui.basic.Label.SUPPORT_NATIVE_ELLIPSIS = qx.sys.Client.getInstance().isMshtml(); + +// these are the properties what will be copied to the measuring frame. +qx.ui.basic.Label._fontProperties = +{ + "none" : [], + + "default" : ["fontFamily", "fontSize", "fontStyle", "fontWeight", "textDecoration"], + "extended" : ["fontFamily", "fontSize", "fontStyle", "fontWeight", "letterSpacing", "textDecoration", "textTransform", "whiteSpace", "wordSpacing"], + + "multiline" : ["fontFamily", "fontSize", "fontStyle", "fontWeight", "textDecoration", "lineHeight", "wordWrap"], + "extendedmultiline" : ["fontFamily", "fontSize", "fontStyle", "fontWeight", "letterSpacing", "textDecoration", "textTransform", "whiteSpace", "wordSpacing", "lineHeight", "wordBreak", "wordWrap", "quotes"], + + "all" : ["fontFamily", "fontSize", "fontStyle", "fontVariant", "fontWeight", "letterSpacing", "lineBreak", "lineHeight", "quotes", "textDecoration", "textIndent", "textShadow", "textTransform", "textUnderlinePosition", "whiteSpace", "wordBreak", "wordSpacing", "wordWrap"] +} + +qx.ui.basic.Label.htmlToText = function(s) { + return String(s).replace(/\s+|<([^>])+>|&|<|>|"| |&#[0-9]+;|&#x[0-9a-fA-F];]/gi, qx.ui.basic.Label._htmlToText); +} + +qx.ui.basic.Label._htmlToText = function(s) +{ + switch(s) + { + case "&": + return "&"; + + case "<": + return "<"; + + case ">": + return ">"; + + case """: + return '"'; + + case " ": + return String.fromCharCode(160); + + default: + if (s.substring(0, 3) == "&#x") { + return String.fromCharCode(parseInt("0x" + s.substring(3, s.length - 1))); + } + else if (s.substring(0, 2) == "&#") { + return String.fromCharCode(s.substring(2, s.length - 1)); + } + else if (/\s+/.test(s)) { + return " "; + } + else if (/^
|\n|\u00A0/g, qx.ui.basic.Label._textToHtml); +} + +qx.ui.basic.Label._textToHtml = function(s) +{ + switch(s) + { + case "&": + return "&"; + + case "<": + return "<"; + + case ">": + return ">"; + + case "\n": + return "
"; + + default: + return " "; + } +} + +qx.ui.basic.Label.createMeasureNode = function(vId) +{ + var vNode = qx.ui.basic.Label._measureNodes[vId]; + + if (!vNode) + { + vNode = document.createElement("div"); + var vStyle = vNode.style; + + vStyle.width = vStyle.height = "auto"; + vStyle.visibility = "hidden"; + vStyle.position = "absolute"; + vStyle.zIndex = "-1"; + + document.body.appendChild(vNode); + + qx.ui.basic.Label._measureNodes[vId] = vNode; + } + + return vNode; +} + + + + + + + + +/* ************************************************************************ + Instance data, properties and methods +************************************************************************ */ + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._htmlMode = false; +qx.Proto._hasMnemonic = false; +qx.Proto._mnemonicHtml = ""; +qx.Proto._mnemonicTest = null; + +qx.Proto._modifyHtml = function(propValue, propOldValue, propData) +{ + this._htmlMode = qx.util.Validation.isValidString(propValue) && propValue.match(/<.*>/) ? true : false; + + if (this._isCreated) { + this._applyContent(); + } + + return true; +} + +qx.Proto._modifyTextAlign = function(propValue, propOldValue, propData) +{ + this.setStyleProperty("textAlign", propValue); + return true; +} + +qx.Proto._modifyMnemonic = function(propValue, propOldValue, propData) +{ + this._hasMnemonic = qx.util.Validation.isValidString(propValue) && propValue.length == 1; + + this._mnemonicHtml = this._hasMnemonic ? "(" + propValue + ")" : ""; + this._mnemonicTest = this._hasMnemonic ? new RegExp("^(((<([^>]|" + propValue + ")+>)|(&([^;]|" + propValue + ")+;)|[^&" + propValue + "])*)(" + propValue + ")", "i") : null; + + return true; +} + +qx.Proto._modifyFont = function(propValue, propOldValue, propData) +{ + this._invalidatePreferredInnerDimensions(); + + if (propValue) { + propValue._applyWidget(this); + } else if (propOldValue) { + propOldValue._resetWidget(this); + } + + return true; +} + +qx.Proto._modifyWrap = function(propValue, propOldValue, propData) +{ + this.setStyleProperty("whiteSpace", propValue ? "normal" : "nowrap"); + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + HELPER FOR PREFERRED DIMENSION +--------------------------------------------------------------------------- +*/ + +qx.Proto._computeObjectNeededDimensions = function() +{ + // copy styles + var vNode = this._copyStyles(); + + // prepare html + var vHtml = this.getHtml(); + + // test for mnemonic and fix content + if (this._hasMnemonic && !this._mnemonicTest.test(vHtml)) { + vHtml += this._mnemonicHtml; + } + + // apply html + vNode.innerHTML = vHtml; + + // store values + this._cachedPreferredInnerWidth = vNode.scrollWidth; + this._cachedPreferredInnerHeight = vNode.scrollHeight; +} + +qx.Proto._copyStyles = function() +{ + var vProps = this.getFontPropertiesProfile(); + var vNode = qx.ui.basic.Label.createMeasureNode(vProps); + var vUseProperties=qx.ui.basic.Label._fontProperties[vProps]; + var vUsePropertiesLength=vUseProperties.length-1; + var vProperty=vUseProperties[vUsePropertiesLength--]; + + var vStyle = vNode.style; + var vTemp; + + if (!vProperty) { + return vNode; + } + + do { + vStyle[vProperty] = qx.util.Validation.isValid(vTemp = this.getStyleProperty([vProperty])) ? vTemp : ""; + } while(vProperty=vUseProperties[vUsePropertiesLength--]); + + return vNode; +} + + + + + + +/* +--------------------------------------------------------------------------- + PREFERRED DIMENSIONS +--------------------------------------------------------------------------- +*/ + +qx.Proto._computePreferredInnerWidth = function() +{ + this._computeObjectNeededDimensions(); + return this._cachedPreferredInnerWidth; +} + +qx.Proto._computePreferredInnerHeight = function() +{ + this._computeObjectNeededDimensions(); + return this._cachedPreferredInnerHeight; +} + + + + + + +/* +--------------------------------------------------------------------------- + LAYOUT APPLY +--------------------------------------------------------------------------- +*/ + +qx.Proto._postApply = function() +{ + var vHtml = this.getHtml(); + var vElement = this._getTargetNode(); + var vMnemonicMode = 0; + + if (qx.util.Validation.isInvalidString(vHtml)) { + vElement.innerHTML = ""; + return; + } + + if (this._hasMnemonic) { + vMnemonicMode = this._mnemonicTest.test(vHtml) ? 1 : 2; + } + + // works only with text, don't use when wrap is enabled + if (!this._htmlMode && !this.getWrap()) + { + switch(this._computedWidthType) + { + case qx.ui.core.Widget.TYPE_PIXEL: + case qx.ui.core.Widget.TYPE_PERCENT: + + //carstenl: enabled truncation code for flex sizing, too. Appears to work except for the + // truncation code (gecko version), which I have disabled (see below). + case qx.ui.core.Widget.TYPE_FLEX: + var vNeeded = this.getPreferredInnerWidth(); + var vInner = this.getInnerWidth(); + + if (vInner < vNeeded) + { + vElement.style.overflow = "hidden"; + + if (qx.ui.basic.Label.SUPPORT_NATIVE_ELLIPSIS) + { + vElement.style.textOverflow = "ellipsis"; + vHtml += this._mnemonicHtml; + } + else + { + var vMeasureNode = this._copyStyles(); + + var vSplitString = vHtml.split(" "); + var vSplitLength = vSplitString.length; + + var vWordIterator = 0; + var vCharaterIterator = 0; + + var vPost = qx.ui.basic.Label.SYMBOL_ELLIPSIS; + + var vUseInnerText = true; + if (vMnemonicMode == 2) + { + var vPost = this._mnemonicHtml + vPost; + vUseInnerText = false; + } + + // Measure Words (if more than one) + if (vSplitLength > 1) + { + var vSplitTemp = []; + + for (vWordIterator=0; vWordIterator vInner) + /* carstenl: The following code (truncate the text to fit in the available + * space, append ellipsis to indicate truncation) did not reliably + * work in my tests. Problem was that sometimes the measurer returned + * insanely high values for short texts, like "I..." requiring 738 px. + * + * I don't have time to examine this code in detail. Since all of my + * tests used flex width and the truncation code never was intended + * for this, I am disabling truncation if flex is active. + */ + && (this._computedWidthType != qx.ui.core.Widget.TYPE_FLEX)){ + break; + } + } + + // Remove last word which does not fit + vSplitTemp.pop(); + + // Building new temportary array + vSplitTemp = [ vSplitTemp.join(" ") ]; + + // Extracting remaining string + vCharaterString = vHtml.replace(vSplitTemp[0], ""); + } + else + { + var vSplitTemp = []; + vCharaterString = vHtml; + } + + var vCharaterLength = vCharaterString.length; + + // Measure Chars + for (var vCharaterIterator=0; vCharaterIterator vInner) { + break; + } + } + + // Remove last char which does not fit + vSplitTemp.pop(); + + // Add mnemonic and ellipsis symbol + vSplitTemp.push(vPost); + + // Building Final HTML String + vHtml = vSplitTemp.join(""); + } + + break; + } + else + { + vHtml += this._mnemonicHtml; + } + + // no break here + + default: + vElement.style.overflow = ""; + + if (qx.ui.basic.Label.SUPPORT_NATIVE_ELLIPSIS) { + vElement.style.textOverflow = ""; + } + } + } + + if (vMnemonicMode == 1) + { + // re-test: needed to make ellipsis handling correct + this._mnemonicTest.test(vHtml); + vHtml = RegExp.$1 + "" + RegExp.$7 + "" + RegExp.rightContext; + } + + return this._postApplyHtml(vElement, vHtml, vMnemonicMode); +} + + +qx.Proto._postApplyHtml = function(vElement, vHtml, vMnemonicMode) +{ + if (this._htmlMode || vMnemonicMode > 0) + { + vElement.innerHTML = vHtml; + } + else + { + try { + qx.dom.Element.setTextContent(vElement, vHtml); + } catch(ex) { + vElement.innerHTML = vHtml; + } + } +} \ No newline at end of file diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/basic/Terminator.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/basic/Terminator.js new file mode 100644 index 0000000000..2b77bb883c --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/basic/Terminator.js @@ -0,0 +1,187 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) + +************************************************************************ */ + +/*! + This widget is the last widget of the current child chain. +*/ +qx.OO.defineClass("qx.ui.basic.Terminator", qx.ui.core.Widget, +function() { + qx.ui.core.Widget.call(this); +}); + + + + + + +/* +--------------------------------------------------------------------------- + APPLY PADDING +--------------------------------------------------------------------------- +*/ + +qx.Proto._applyPaddingX = function(vParent, vChanges, vStyle) +{ + if (vChanges.paddingLeft) { + this._applyRuntimePaddingLeft(this.getPaddingLeft()); + } + + if (vChanges.paddingRight) { + this._applyRuntimePaddingRight(this.getPaddingRight()); + } +} + +qx.Proto._applyPaddingY = function(vParent, vChanges, vStyle) +{ + if (vChanges.paddingTop) { + this._applyRuntimePaddingTop(this.getPaddingTop()); + } + + if (vChanges.paddingBottom) { + this._applyRuntimePaddingBottom(this.getPaddingBottom()); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + APPLY CONTENT +--------------------------------------------------------------------------- +*/ + +qx.Proto._applyContent = function() +{ + // Small optimization: Only add innerPreferred jobs + // if we don't have a static width + if (this._computedWidthTypePixel) { + this._cachedPreferredInnerWidth = null; + } else { + this._invalidatePreferredInnerWidth(); + } + + // Small optimization: Only add innerPreferred jobs + // if we don't have a static height + if (this._computedHeightTypePixel) { + this._cachedPreferredInnerHeight = null; + } else { + this._invalidatePreferredInnerHeight(); + } + + // add load job + if (this._initialLayoutDone) { + this.addToJobQueue("load"); + } +} + +qx.Proto._layoutPost = function(vChanges) { + if (vChanges.initial || vChanges.load || vChanges.width || vChanges.height) { + this._postApply(); + } +} + +qx.Proto._postApply = qx.util.Return.returnTrue; + + + + + + + +/* +--------------------------------------------------------------------------- + BOX DIMENSION HELPERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._computeBoxWidthFallback = qx.Proto.getPreferredBoxWidth; +qx.Proto._computeBoxHeightFallback = qx.Proto.getPreferredBoxHeight; + +qx.Proto._computePreferredInnerWidth = qx.util.Return.returnZero; +qx.Proto._computePreferredInnerHeight = qx.util.Return.returnZero; + + + + + + + +/* +--------------------------------------------------------------------------- + METHODS TO GIVE THE LAYOUTERS INFORMATIONS +--------------------------------------------------------------------------- +*/ + +qx.Proto._isWidthEssential = function() +{ + if (!this._computedLeftTypeNull && !this._computedRightTypeNull) { + return true; + } + + if (!this._computedWidthTypeNull && !this._computedWidthTypeAuto) { + return true; + } + + if (!this._computedMinWidthTypeNull && !this._computedMinWidthTypeAuto) { + return true; + } + + if (!this._computedMaxWidthTypeNull && !this._computedMaxWidthTypeAuto) { + return true; + } + + if (this._borderElement) { + return true; + } + + return false; +} + +qx.Proto._isHeightEssential = function() +{ + if (!this._computedTopTypeNull && !this._computedBottomTypeNull) { + return true; + } + + if (!this._computedHeightTypeNull && !this._computedHeightTypeAuto) { + return true; + } + + if (!this._computedMinHeightTypeNull && !this._computedMinHeightTypeAuto) { + return true; + } + + if (!this._computedMaxHeightTypeNull && !this._computedMaxHeightTypeAuto) { + return true; + } + + if (this._borderElement) { + return true; + } + + return false; +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/basic/VerticalSpacer.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/basic/VerticalSpacer.js new file mode 100644 index 0000000000..6887c9d3fd --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/basic/VerticalSpacer.js @@ -0,0 +1,31 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_basic) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.basic.VerticalSpacer", qx.ui.basic.Terminator, +function() +{ + qx.ui.basic.Terminator.call(this); + + this.setHeight("1*"); +}); diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/component/ColorPopup.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/component/ColorPopup.js new file mode 100644 index 0000000000..523a98df8f --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/component/ColorPopup.js @@ -0,0 +1,387 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + + +************************************************************************ */ + +/*! + A color popup +*/ +qx.OO.defineClass("qx.ui.component.ColorPopup", qx.ui.popup.Popup, +function(tables) +{ + qx.ui.popup.Popup.call(this); + + this.setPadding(4); + this.auto(); + this.setBorder(qx.renderer.border.BorderPresets.getInstance().outset); + this.setBackgroundColor("threedface"); + + this._tables = tables; + + this._createLayout(); + this._createAutoBtn(); + this._createBoxes(); + this._createPreview(); + this._createSelectorBtn(); + + this.addEventListener("beforeAppear", this._onBeforeAppear); +}); + +qx.OO.addProperty({ name : "value", type : "object", instance : "qx.renderer.color.Color" }); + +qx.OO.addProperty({ name : "red", type : "number", defaultValue : 0 }); +qx.OO.addProperty({ name : "green", type : "number", defaultValue : 0 }); +qx.OO.addProperty({ name : "blue", type : "number", defaultValue : 0 }); + +qx.Proto._minZIndex = 1e5; + + + + + +/* +--------------------------------------------------------------------------- + CREATOR SUBS +--------------------------------------------------------------------------- +*/ + +qx.Proto._createLayout = function() +{ + this._layout = new qx.ui.layout.VerticalBoxLayout; + this._layout.setLocation(0, 0); + this._layout.auto(); + this._layout.setSpacing(2); + + this.add(this._layout); +} + +qx.Proto._createAutoBtn = function() +{ + this._automaticBtn = new qx.ui.form.Button("Automatic"); + this._automaticBtn.setWidth(null); + this._automaticBtn.setAllowStretchX(true); + this._automaticBtn.addEventListener("execute", this._onAutomaticBtnExecute, this); + + this._layout.add(this._automaticBtn); +} + +qx.Proto._recentTableId = "recent"; +qx.Proto._fieldWidth = 14; +qx.Proto._fieldHeight = 14; +qx.Proto._fieldNumber = 12; + +qx.Proto._createBoxes = function() +{ + this._boxes = {}; + + var tables = this._tables; + var table, box, boxLayout, field; + + for (var tableId in tables) + { + table = tables[tableId]; + + box = new qx.ui.groupbox.GroupBox(table.label); + box.setHeight("auto"); + + this._boxes[tableId] = box; + this._layout.add(box); + + boxLayout = new qx.ui.layout.HorizontalBoxLayout; + boxLayout.setLocation(0, 0); + boxLayout.setSpacing(1); + boxLayout.auto(); + box.add(boxLayout); + + for (var i=0; inull + * the current day (today) is shown. + * + * @event select {qx.event.type.DataEvent} Fired when a date was selected. The + * event holds the new selected date in its data property. + */ +qx.OO.defineClass("qx.ui.component.DateChooser", qx.ui.layout.BoxLayout, +function(date) { + qx.ui.layout.BoxLayout.call(this); + + this.setOrientation("vertical"); + + // Create the navigation bar + var navBar = new qx.ui.layout.BoxLayout; + navBar.set({ width:null, height:"auto", spacing:1 }); + + var lastYearBt = new qx.ui.toolbar.Button(null, "widget/datechooser/lastYear.png"); + var lastMonthBt = new qx.ui.toolbar.Button(null, "widget/datechooser/lastMonth.png"); + var monthYearLabel = new qx.ui.basic.Label; + var nextMonthBt = new qx.ui.toolbar.Button(null, "widget/datechooser/nextMonth.png"); + var nextYearBt = new qx.ui.toolbar.Button(null, "widget/datechooser/nextYear.png"); + + lastYearBt.set({ show:'icon', toolTip:new qx.ui.popup.ToolTip("Last year"), spacing:0 }); + lastMonthBt.set({ show:'icon', toolTip:new qx.ui.popup.ToolTip("Last month") }); + nextMonthBt.set({ show:'icon', toolTip:new qx.ui.popup.ToolTip("Next month") }); + nextYearBt.set({ show:'icon', toolTip:new qx.ui.popup.ToolTip("Next year") }); + + lastYearBt.setAppearance("datechooser-toolbar-button"); + lastMonthBt.setAppearance("datechooser-toolbar-button"); + nextMonthBt.setAppearance("datechooser-toolbar-button"); + nextYearBt.setAppearance("datechooser-toolbar-button"); + + lastYearBt.addEventListener("click", this._onNavButtonClicked, this); + lastMonthBt.addEventListener("click", this._onNavButtonClicked, this); + nextMonthBt.addEventListener("click", this._onNavButtonClicked, this); + nextYearBt.addEventListener("click", this._onNavButtonClicked, this); + + this._lastYearBt = lastYearBt; + this._lastMonthBt = lastMonthBt; + this._nextMonthBt = nextMonthBt; + this._nextYearBt = nextYearBt; + + monthYearLabel.setAppearance("datechooser-monthyear"); + monthYearLabel.set({ width:"1*" }); + + navBar.add(lastYearBt, lastMonthBt, monthYearLabel, nextMonthBt, nextYearBt); + this._monthYearLabel = monthYearLabel; + navBar.setHtmlAttribute("id", "navBar"); + + // Calculate the cell width and height + var testLabel = new qx.ui.basic.Label; + var testParent = new qx.ui.layout.CanvasLayout; + testParent.add(testLabel); + testLabel.setHtml("Xx"); + testLabel.set({ paddingLeft : 5, paddingRight : 5 }); + testLabel.setAppearance("datechooser-weekday"); + var cellWidth = testLabel.getBoxWidth(); + var cellHeight = testLabel.getBoxHeight(); + testLabel.dispose(); + testParent.dispose(); + + // Create the date pane + var datePane = new qx.ui.layout.GridLayout; + datePane.setAppearance("datechooser-datepane"); + datePane.set({ width:"100%", height:"auto" }); + datePane.setColumnCount(8); + datePane.setRowCount(7); + for (var i = 0; i < datePane.getColumnCount(); i++) { + datePane.setColumnWidth(i, cellWidth); + } + for (var i = 0; i < datePane.getRowCount(); i++) { + datePane.setRowHeight(i, cellHeight); + } + + // Create the weekdays + // Add an empty label as spacer for the week numbers + var label = new qx.ui.basic.Label; + label.setAppearance("datechooser-week"); + label.set({ width:"100%", height:"100%" }); + label.addState("header"); + datePane.add(label, 0, 0); + + this._weekdayLabelArr = []; + for (var i = 0; i < 7; i++) { + var label = new qx.ui.basic.Label; + label.setAppearance("datechooser-weekday"); + label.set({ width:"100%", height:"100%" }); + datePane.add(label, i + 1, 0); + this._weekdayLabelArr.push(label); + } + + // Add the days + this._dayLabelArr = []; + this._weekLabelArr = []; + for (var y = 0; y < 6; y++) { + // Add the week label + var label = new qx.ui.basic.Label; + label.setAppearance("datechooser-week"); + label.set({ width:"100%", height:"100%" }); + datePane.add(label, 0, y + 1); + this._weekLabelArr.push(label); + + // Add the day labels + for (var x = 0; x < 7; x++) { + var label = new qx.ui.basic.Label; + label.setAppearance("datechooser-day"); + label.set({ width:"100%", height:"100%" }); + label.addEventListener("mousedown", this._onDayClicked, this); + label.addEventListener("dblclick", this._onDayDblClicked, this); + datePane.add(label, x + 1, y + 1); + this._dayLabelArr.push(label); + } + } + + // Make focusable + this.setTabIndex(1); + this.addEventListener("keypress", this._onkeypress); + + // Show the right date + var shownDate = (date != null) ? date : new Date(); + this.showMonth(shownDate.getMonth(), shownDate.getFullYear()); + + // Add the main widgets + this.add(navBar); + this.add(datePane); + +}); + + +// ***** Properties ***** + +/** The start of the week. 0 = sunday, 1 = monday, and so on. */ +qx.OO.addProperty({ name:"startOfWeek", type:"number", defaultValue:1 }); +/** The currently shown month. 0 = january, 1 = february, and so on. */ +qx.OO.addProperty({ name:"shownMonth", type:"number", defaultValue:null }); +/** The currently shown year. */ +qx.OO.addProperty({ name:"shownYear", type:"number", defaultValue:null }); +/** {Date} The currently selected date. */ +qx.OO.addProperty({ name:"date", type:"object", defaultValue:null }); + + +// property checker +qx.Proto._checkDate = function(propValue, propData) { + // Use a clone of the date internally since date instances may be changed + return (propValue == null) ? null : new Date(propValue.getTime()); +} + + +// property modifier +qx.Proto._modifyDate = function(propValue, propOldValue, propData) { + var DateChooser = qx.ui.component.DateChooser; + + if ((propValue != null) && (this.getShownMonth() != propValue.getMonth() + || this.getShownYear() != propValue.getFullYear())) + { + // The new date is in another month -> Show that month + this.showMonth(propValue.getMonth(), propValue.getFullYear()); + } else { + // The new date is in the current month -> Just change the states + var newDay = (propValue == null) ? -1 : propValue.getDate(); + for (var i = 0; i < 6 * 7; i++) { + var dayLabel = this._dayLabelArr[i]; + + if (dayLabel.hasState("otherMonth")) { + if (dayLabel.hasState("selected")) { + dayLabel.removeState("selected"); + } + } else { + var day = parseInt(dayLabel.getHtml()); + if (day == newDay) { + dayLabel.addState("selected"); + } else if (dayLabel.hasState("selected")) { + dayLabel.removeState("selected"); + } + } + } + } + + return true; +} + + +/** + * Event handler. Called when a navigation button has been clicked. + * + * @param evt {Map} the event. + */ +qx.Proto._onNavButtonClicked = function(evt) { + var year = this.getShownYear(); + var month = this.getShownMonth(); + + switch(evt.getCurrentTarget()) { + case this._lastYearBt: + year--; + break; + case this._lastMonthBt: + month--; + if (month < 0) { + month = 11; + year--; + } + break; + case this._nextMonthBt: + month++; + if (month >= 12) { + month = 0; + year++; + } + break; + case this._nextYearBt: + year++; + break; + } + + this.showMonth(month, year); +} + + +/** + * Event handler. Called when a day has been clicked. + * + * @param evt {Map} the event. + */ +qx.Proto._onDayClicked = function(evt) { + var time = evt.getCurrentTarget().dateTime; + this.setDate(new Date(time)); +} + +qx.Proto._onDayDblClicked = function() { + this.createDispatchDataEvent("select", this.getDate()); +} + +/** + * Event handler. Called when a key was pressed. + * + * @param evt {Map} the event. + */ +qx.Proto._onkeypress = function(evt) { + var dayIncrement = null; + var monthIncrement = null; + var yearIncrement = null; + if (evt.getModifiers() == 0) { + switch(evt.getKeyIdentifier()) { + case "Left": + dayIncrement = -1; + break; + case "Right": + dayIncrement = 1; + break; + case "Up": + dayIncrement = -7; + break; + case "Down": + dayIncrement = 7; + break; + case "PageUp": + monthIncrement = -1; + break; + case "PageDown": + monthIncrement = 1; + break; + case "Escape": + if (this.getDate() != null) { + this.setDate(null); + return true; + } + break; + case "Enter": + case "Space": + if (this.getDate() != null) { + this.createDispatchDataEvent("select", this.getDate()); + } + return; + } + } else if (evt.getShiftKey()) { + switch(evt.getKeyIdentifier()) { + case "PageUp": + yearIncrement = -1; + break; + case "PageDown": + yearIncrement = 1; + break; + } + } + + if (dayIncrement != null || monthIncrement != null || yearIncrement != null) { + var date = this.getDate(); + if (date != null) { + date = new Date(date.getTime()); // TODO: Do cloning in getter + } + if (date == null) { + date = new Date(); + } else { + if (dayIncrement != null) date.setDate(date.getDate() + dayIncrement); + if (monthIncrement != null) date.setMonth(date.getMonth() + monthIncrement); + if (yearIncrement != null) date.setFullYear(date.getFullYear() + yearIncrement); + } + this.setDate(date); + } +} + + +// ***** Methods ***** + + +/** + * Returns whether a certain day of week belongs to the week end. + * + * @param dayOfWeek {int} the day to check. (0 = sunday, 1 = monday, ..., + * 6 = saturday) + * @return {boolean} whether the day belongs to the week end. + */ +qx.Proto._isWeekend = function(dayOfWeek) { + return (dayOfWeek == 0) || (dayOfWeek == 6); +} + + +/** + * Shows a certain month. + * + * @param month {int ? null} the month to show (0 = january). If not set the month + * will remain the same. + * @param year {int ? null} the year to show. If not set the year will remain the + * same. + */ +qx.Proto.showMonth = function(month, year) { + if ((month != null && month != this.getShownMonth()) + || (year != null && year != this.getShownYear())) + { + if (month != null) { + this.setShownMonth(month); + } + if (year != null) { + this.setShownYear(year); + } + + this._updateDatePane(); + } +} + + +/** + * Updates the date pane. + */ +qx.Proto._updateDatePane = function() { + var DateChooser = qx.ui.component.DateChooser; + + var today = new Date(); + var todayYear = today.getFullYear(); + var todayMonth = today.getMonth(); + var todayDayOfMonth = today.getDate(); + + var selDate = this.getDate(); + var selYear = (selDate == null) ? -1 : selDate.getFullYear(); + var selMonth = (selDate == null) ? -1 : selDate.getMonth(); + var selDayOfMonth = (selDate == null) ? -1 : selDate.getDate(); + + var shownMonth = this.getShownMonth(); + var shownYear = this.getShownYear(); + + var startOfWeek = this.getStartOfWeek(); + + // Create a help date that points to the first of the current month + var helpDate = new Date(this.getShownYear(), this.getShownMonth(), 1); + + this._monthYearLabel.setHtml(DateChooser.MONTH_YEAR_FORMAT.format(helpDate)); + + // Show the day names + var firstDayOfWeek = helpDate.getDay(); + var firstSundayInMonth = (1 + 7 - firstDayOfWeek) % 7; + for (var i = 0; i < 7; i++) { + var day = (i + startOfWeek) % 7; + + var dayLabel = this._weekdayLabelArr[i]; + + helpDate.setDate(firstSundayInMonth + day); + dayLabel.setHtml(DateChooser.WEEKDAY_FORMAT.format(helpDate)); + + if (this._isWeekend(day)) { + dayLabel.addState("weekend"); + } else { + dayLabel.removeState("weekend"); + } + } + + // Show the days + helpDate = new Date(shownYear, shownMonth, 1); + var nrDaysOfLastMonth = (7 + firstDayOfWeek - startOfWeek) % 7; + helpDate.setDate(helpDate.getDate() - nrDaysOfLastMonth); + for (var week = 0; week < 6; week++) { + this._weekLabelArr[week].setHtml(DateChooser.WEEK_FORMAT.format(helpDate)); + + for (var i = 0; i < 7; i++) { + var dayLabel = this._dayLabelArr[week * 7 + i]; + + var year = helpDate.getFullYear(); + var month = helpDate.getMonth(); + var dayOfMonth = helpDate.getDate(); + + var isSelectedDate = (selYear == year && selMonth == month && selDayOfMonth == dayOfMonth); + if (isSelectedDate) { + dayLabel.addState("selected"); + } else { + dayLabel.removeState("selected"); + } + + if (month != shownMonth) { + dayLabel.addState("otherMonth"); + } else { + dayLabel.removeState("otherMonth"); + } + + var isToday = (year == todayYear && month == todayMonth && dayOfMonth == todayDayOfMonth); + if (isToday) { + dayLabel.addState("today"); + } else { + dayLabel.removeState("today"); + } + + dayLabel.setHtml("" + dayOfMonth); + dayLabel.dateTime = helpDate.getTime(); + + // Go to the next day + helpDate.setDate(helpDate.getDate() + 1); + } + } +} + + +/** + * {qx.util.format.DateFormat} The format for the date year + * label at the top center. + */ +qx.Class.MONTH_YEAR_FORMAT = new qx.util.format.DateFormat("MMMM yyyy"); + +/** + * {qx.util.format.DateFormat} The format for the weekday + * labels (the headers of the date table). + */ +qx.Class.WEEKDAY_FORMAT = new qx.util.format.DateFormat("EE"); + +/** + * {qx.util.format.DateFormat} The format for the week labels. + */ +qx.Class.WEEK_FORMAT = new qx.util.format.DateFormat("ww"); + + +// overridden +qx.Proto.dispose = function() { + if (this.getDisposed()) { + return true; + } + + this._lastYearBt.removeEventListener("click", this._onNavButtonClicked, this); + this._lastMonthBt.removeEventListener("click", this._onNavButtonClicked, this); + this._nextMonthBt.removeEventListener("click", this._onNavButtonClicked, this); + this._nextYearBt.removeEventListener("click", this._onNavButtonClicked, this); + + this._lastYearBt.dispose(); + this._lastMonthBt.dispose(); + this._nextMonthBt.dispose(); + this._nextYearBt.dispose(); + + this._lastYearBt = null; + this._lastMonthBt = null; + this._nextMonthBt = null; + this._nextYearBt = null; + + this._monthYearLabel.dispose(); + this._monthYearLabel = null; + + for (var i = 0; i < this._weekdayLabelArr.length; i++) { + this._weekdayLabelArr[i].dispose(); + } + this._weekdayLabelArr = null; + + for (var i = 0; i < this._dayLabelArr.length; i++) { + this._dayLabelArr[i].dispose(); + this._dayLabelArr[i].removeEventListener("mousedown", this._onDayClicked, this); + this._dayLabelArr[i].removeEventListener("dblclick", this._onDayDblClicked, this); + } + this._dayLabelArr = null; + + for (var i = 0; i < this._weekLabelArr.length; i++) { + this._weekLabelArr[i].dispose(); + } + this._weekLabelArr = null; + + this.removeEventListener("keypress", this._onkeypress); + + return qx.ui.layout.BoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/core/ClientDocument.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/core/ClientDocument.js new file mode 100644 index 0000000000..f65edcb32e --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/core/ClientDocument.js @@ -0,0 +1,450 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#require(qx.dom.StyleSheet) +#require(qx.event.handler.EventHandler) +#optional(qx.client.NativeWindow) +#optional(qx.ui.window.Window) +#optional(qx.manager.object.PopupManager) + +************************************************************************ */ + +/** + * This is the basic widget of all qooxdoo applications. + * + * qx.ui.core.ClientDocument is the parent of all children inside your application. It + * also handles their resizing and focus navigation. + * + * @event windowblur {qx.event.type.Event} Fired when the window looses the + * focus. (Fired by {@link qx.event.handler.EventHandler}) + * @event windowfocus {qx.event.type.Event} Fired when the window gets the + * focus. (Fired by {@link qx.event.handler.EventHandler}) + * @event windowresize {qx.event.type.Event} Fired when the window has been + * resized. (Fired by {@link qx.event.handler.EventHandler}) + */ +qx.OO.defineClass("qx.ui.core.ClientDocument", qx.ui.layout.CanvasLayout, +function() +{ + this._window = window; + this._document = window.document; + + // Init element + this.setElement(this._document.body); + + // Needed hard-coded because otherwise the client document + // would not be added initially to the state queue + this.addToStateQueue(); + + qx.ui.layout.CanvasLayout.call(this); + + // Don't use widget styles + this._styleProperties = {}; + + // Configure as focus root + this.activateFocusRoot(); + + // Cache current size + this._cachedInnerWidth = this._document.body.offsetWidth; + this._cachedInnerHeight = this._document.body.offsetHeight; + + // Add Resize Handler + this.addEventListener("windowresize", this._onwindowresize); + + // Dialog Support + this._modalWidgets = []; + this._modalNativeWindow = null; + + // Register as focus root + qx.event.handler.EventHandler.getInstance().setFocusRoot(this); + + + // Init Resize Helper + /* + if (qx.sys.Client.getInstance().isGecko()) + { + var o = this; + this._resizeHelper = window.setInterval(function() { o._onresizehelper() }, 100); + } + */ +}); + +qx.OO.addProperty({ name : "globalCursor", type : "string" }); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "client-document" }); + + + +/* +--------------------------------------------------------------------------- + DEFAULT SETTINGS +--------------------------------------------------------------------------- +*/ + +qx.Settings.setDefault("enableApplicationLayout", true); +qx.Settings.setDefault("boxModelCorrection", true); + + + + + + +/* +--------------------------------------------------------------------------- + OVERWRITE WIDGET FUNCTIONS/PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyParent = qx.util.Return.returnTrue; +qx.Proto._modifyVisible = qx.util.Return.returnTrue; + +qx.Proto._modifyElement = function(propValue, propOldValue, propData) +{ + this._isCreated = qx.util.Validation.isValidElement(propValue); + + if (propOldValue) + { + propOldValue.qx_Widget = null; + } + + if (propValue) + { + // add reference to widget instance + propValue.qx_Widget = this; + + // link element and style reference + this._element = propValue; + this._style = propValue.style; + } + else + { + this._element = null; + this._style = null; + } + + return true; +} + +qx.Proto.getTopLevelWidget = qx.util.Return.returnThis; +qx.Proto.getWindowElement = function() { return this._window; } +qx.Proto.getDocumentElement = function() { return this._document; } + +qx.Proto.getParent = qx.Proto.getToolTip = qx.util.Return.returnNull; +qx.Proto.isMaterialized = qx.Proto.isSeeable = qx.util.Return.returnTrue; + +qx.Proto._isDisplayable = true; +qx.Proto._hasParent = false; +qx.Proto._initialLayoutDone = true; + + + + + + + + + +/* +--------------------------------------------------------------------------- + BLOCKER AND DIALOG SUPPORT +--------------------------------------------------------------------------- +*/ + +/** + * Returns the blocker widget if already created; otherwise create it first + * + * @return {ClientDocumentBlocker} the blocker widget. + */ +qx.Proto._getBlocker = function() +{ + if (!this._blocker) + { + // Create blocker instance + this._blocker = new qx.ui.core.ClientDocumentBlocker; + + // Add blocker events + this._blocker.addEventListener("mousedown", this.blockHelper, this); + this._blocker.addEventListener("mouseup", this.blockHelper, this); + + // Add blocker to client document + this.add(this._blocker); + } + + return this._blocker; +}; + +qx.Proto.blockHelper = function(e) +{ + if (this._modalNativeWindow) + { + try + { + this._modalNativeWindow._window.focus(); + } + catch(ex) + { + this.debug("Window seems to be closed already! => Releasing Blocker: (" + e.getType() + ")", ex); + this.release(this._modalNativeWindow); + } + } +} + +qx.Proto.block = function(vActiveChild) +{ + // this.debug("BLOCK: " + vActiveChild.toHashCode()); + + this._getBlocker().show(); + + if (qx.OO.isAvailable("qx.ui.window.Window") && vActiveChild instanceof qx.ui.window.Window) + { + this._modalWidgets.push(vActiveChild); + + var vOrigIndex = vActiveChild.getZIndex(); + this._getBlocker().setZIndex(vOrigIndex); + vActiveChild.setZIndex(vOrigIndex+1); + } + else if (qx.OO.isAvailable("qx.client.NativeWindow") && vActiveChild instanceof qx.client.NativeWindow) + { + this._modalNativeWindow = vActiveChild; + this._getBlocker().setZIndex(1e7); + } +} + +qx.Proto.release = function(vActiveChild) +{ + // this.debug("RELEASE: " + vActiveChild.toHashCode()); + + if (vActiveChild) + { + if (qx.OO.isAvailable("qx.client.NativeWindow") && vActiveChild instanceof qx.client.NativeWindow) + { + this._modalNativeWindow = null; + } + else + { + qx.lang.Array.remove(this._modalWidgets, vActiveChild); + } + } + + var l = this._modalWidgets.length; + if (l == 0) + { + this._getBlocker().hide(); + } + else + { + var oldActiveChild = this._modalWidgets[l-1]; + + var o = oldActiveChild.getZIndex(); + this._getBlocker().setZIndex(o); + oldActiveChild.setZIndex(o+1); + } +} + + + + + + + + +/* +--------------------------------------------------------------------------- + CSS API +--------------------------------------------------------------------------- +*/ + +qx.Proto.createStyleElement = function(vCssText) { + return qx.dom.StyleSheet.createElement(vCssText); +} + +qx.Proto.addCssRule = function(vSheet, vSelector, vStyle) { + return qx.dom.StyleSheet.addRule(vSheet, vSelector, vStyle); +} + +qx.Proto.removeCssRule = function(vSheet, vSelector) { + return qx.dom.StyleSheet.removeRule(vSheet, vSelector); +} + +qx.Proto.removeAllCssRules = function(vSheet) { + return qx.dom.StyleSheet.removeAllRules(vSheet); +} + + + + + + +/* +--------------------------------------------------------------------------- + CSS FIX +--------------------------------------------------------------------------- +*/ +if (qx.Settings.getValueOfClass("qx.ui.core.ClientDocument", "boxModelCorrection")) { + qx.dom.StyleSheet.createElement("html,body{margin:0;border:0;padding:0;}" + + " html{border:0 none;} *{" + qx.sys.Client.getInstance().getEngineBoxSizingAttribute() + + ":border-box;} img{" + qx.sys.Client.getInstance().getEngineBoxSizingAttribute() + + ":content-box;}"); +} +if (qx.Settings.getValueOfClass("qx.ui.core.ClientDocument", "enableApplicationLayout")) { + qx.dom.StyleSheet.createElement("html,body{width:100%;height:100%;overflow:hidden;}"); +} + + + + + +/* +--------------------------------------------------------------------------- + GLOBAL CURSOR SUPPORT +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyGlobalCursor = function(propValue, propOldValue, propData) +{ + if (!this._globalCursorStyleSheet) { + this._globalCursorStyleSheet = this.createStyleElement(); + } + + // Selector based remove does not work with the "*" selector in mshtml + // this.removeCssRule(this._globalCursorStyleSheet, "*"); + + this.removeAllCssRules(this._globalCursorStyleSheet); + + if (propValue) { + this.addCssRule(this._globalCursorStyleSheet, "*", "cursor:" + propValue + " !important"); + } + + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + WINDOW RESIZE HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._onwindowresize = function(e) +{ + // Hide popups, tooltips, ... + if (qx.OO.isAvailable("qx.manager.object.PopupManager")) { + qx.manager.object.PopupManager.getInstance().update(); + } + + // Update children + this._recomputeInnerWidth(); + this._recomputeInnerHeight(); + + // Flush queues + qx.ui.core.Widget.flushGlobalQueues(); +} + +// This was an idea to allow mozilla more realtime document resize updates +// but it seems so, that mozilla stops javascript execution while the user +// resize windows. Bad. + +/* +qx.Proto._onwindowresizehelper = function() +{ + // Test for changes + var t1 = this._recomputeInnerWidth(); + var t2 = this._recomputeInnerHeight(); + + // Flush queues + if (t1 || t2) { + qx.ui.core.Widget.flushGlobalQueues(); + } +} +*/ + +qx.Proto._computeInnerWidth = function() { + return this._document.body.offsetWidth; +} + +qx.Proto._computeInnerHeight = function() { + return this._document.body.offsetHeight; +} + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + delete this._document; + delete this._modalWidgets; + delete this._modalNativeWindow; + + // Remove Resize Handler + this.removeEventListener("windowresize", this._onwindowresize); + + this._globalCursorStyleSheet = null; + + if (this._blocker) + { + this._blocker.removeEventListener("mousedown", this.blockHelper, this); + this._blocker.removeEventListener("mouseup", this.blockHelper, this); + + this._blocker.dispose(); + this._blocker = null; + } + + /* + if (this._resizeHelper) + { + window.clearInterval(this._resizeHelper); + this._resizeHelper = null; + } + */ + + return qx.ui.layout.CanvasLayout.prototype.dispose.call(this); +} + + + + + + +/* +--------------------------------------------------------------------------- + DEFER SINGLETON INSTANCE +--------------------------------------------------------------------------- +*/ + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.util.Return.returnInstance; diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/core/ClientDocumentBlocker.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/core/ClientDocumentBlocker.js new file mode 100644 index 0000000000..5acbb85e12 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/core/ClientDocumentBlocker.js @@ -0,0 +1,39 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) + +************************************************************************ */ + +/*! + qx.ui.core.ClientDocumentBlocker blocks the inputs from the user. + This will be used internally to allow better modal dialogs for example. +*/ +qx.OO.defineClass("qx.ui.core.ClientDocumentBlocker", qx.ui.basic.Terminator, +function() +{ + qx.ui.basic.Terminator.call(this); + + this.setEdge(0); + this.setZIndex(1e8); + this.setDisplay(false); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "blocker" }); diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/core/Parent.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/core/Parent.js new file mode 100644 index 0000000000..29e886170a --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/core/Parent.js @@ -0,0 +1,1207 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#optional(qx.event.handler.FocusHandler) +#optional(qx.manager.object.ToolTipManager) +#optional(qx.manager.object.PopupManager) +#optional(qx.dom.ElementFromPoint) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.core.Parent", qx.ui.core.Widget, +function() +{ + if (this.classname == qx.ui.core.Parent.ABSTRACT_CLASS) { + throw new Error("Please omit the usage of qx.ui.core.Parent directly. Choose between any widget which inherits from qx.ui.core.Parent and so comes with a layout implementation!"); + } + + qx.ui.core.Widget.call(this); + + // Contains all children + this._children = []; + + // Create instanceof layout implementation + this._layoutImpl = this._createLayoutImpl(); +}); + +qx.ui.core.Parent.ABSTRACT_CLASS = "qx.ui.core.Parent"; + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + Individual focus handler for all child elements. +*/ +qx.OO.addProperty({ name : "focusHandler", type : "object", instance : "qx.event.handler.FocusHandler" }); + +/*! + The current active child. +*/ +qx.OO.addProperty({ name : "activeChild", type : "object", instance : "qx.ui.core.Widget" }); + +/*! + The current focused child. +*/ +qx.OO.addProperty({ name : "focusedChild", type : "object", instance : "qx.ui.core.Widget" }); + + + + + +/* +--------------------------------------------------------------------------- + CACHED PRIVATE PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.addCachedProperty({ name : "visibleChildren", defaultValue : null }); + + + + + + +/* +--------------------------------------------------------------------------- + FOCUS HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto.isFocusRoot = function() { + return this.getFocusHandler() != null; +} + +qx.Proto.getFocusRoot = function() +{ + if (this.isFocusRoot()) { + return this; + } + + if(this._hasParent) { + return this.getParent().getFocusRoot(); + } + + return null; +} + +qx.Proto.activateFocusRoot = function() { + this.setFocusHandler(new qx.event.handler.FocusHandler(this)); +} + +qx.Proto._onfocuskeyevent = function(e) { + this.getFocusHandler()._onkeyevent(this, e); +} + +qx.Proto._modifyFocusHandler = function(propValue, propOldValue, propData) +{ + if (propValue) + { + // Add Key Handler + this.addEventListener("keydown", this._onfocuskeyevent); + this.addEventListener("keypress", this._onfocuskeyevent); + + // Activate focus handling (but keep already configured tabIndex) + if (this.getTabIndex() < 1) { + this.setTabIndex(1); + } + + // But hide the focus outline + this.setHideFocus(true); + + // Make myself the default + this.setActiveChild(this); + } + else + { + // Remove Key Handler + this.removeEventListener("keydown", this._onfocuskeyevent); + this.removeEventListener("keypress", this._onfocuskeyevent); + + // Deactivate focus handling + this.setTabIndex(-1); + + // Don't hide focus outline + this.setHideFocus(false); + } + + return true; +} + +qx.Proto._modifyFocusedChild = function(propValue, propOldValue, propData) +{ + // this.debug("FocusedChild: " + propValue); + + var vFocusValid = qx.util.Validation.isValidObject(propValue); + var vBlurValid = qx.util.Validation.isValidObject(propOldValue); + + if (qx.OO.isAvailable("qx.manager.object.PopupManager") && vFocusValid) + { + var vMgr = qx.manager.object.PopupManager.getInstance(); + if (vMgr) { + vMgr.update(propValue); + } + } + + if (vBlurValid) + { + // Dispatch FocusOut + if (propOldValue.hasEventListeners("focusout")) + { + var vEventObject = new qx.event.type.FocusEvent("focusout", propOldValue); + + if (vFocusValid) { + vEventObject.setRelatedTarget(propValue); + } + + propOldValue.dispatchEvent(vEventObject); + vEventObject.dispose(); + } + } + + if (vFocusValid) + { + if (propValue.hasEventListeners("focusin")) + { + // Dispatch FocusIn + var vEventObject = new qx.event.type.FocusEvent("focusin", propValue); + + if (vBlurValid) { + vEventObject.setRelatedTarget(propOldValue); + } + + propValue.dispatchEvent(vEventObject); + vEventObject.dispose(); + } + } + + if (vBlurValid) + { + if (this.getActiveChild() == propOldValue) { + this.setActiveChild(null); + } + + propOldValue.setFocused(false); + + // Dispatch Blur + var vEventObject = new qx.event.type.FocusEvent("blur", propOldValue); + + if (vFocusValid) { + vEventObject.setRelatedTarget(propValue); + } + + propOldValue.dispatchEvent(vEventObject); + + if (qx.OO.isAvailable("qx.manager.object.ToolTipManager")) + { + var vMgr = qx.manager.object.ToolTipManager.getInstance(); + if (vMgr) { + vMgr.handleBlur(vEventObject); + } + } + + vEventObject.dispose(); + } + + if (vFocusValid) + { + this.setActiveChild(propValue); + propValue.setFocused(true); + qx.event.handler.EventHandler.getInstance().setFocusRoot(this); + + // Dispatch Focus + var vEventObject = new qx.event.type.FocusEvent("focus", propValue); + + if (vBlurValid) { + vEventObject.setRelatedTarget(propOldValue); + } + + propValue.dispatchEvent(vEventObject); + + if (qx.OO.isAvailable("qx.manager.object.ToolTipManager")) + { + var vMgr = qx.manager.object.ToolTipManager.getInstance(); + if (vMgr) { + vMgr.handleFocus(vEventObject); + } + } + + vEventObject.dispose(); + } + + // Flush Queues + // Do we really need this? + // qx.ui.core.Widget.flushGlobalQueues(); + + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + LAYOUT IMPLEMENTATION +--------------------------------------------------------------------------- +*/ + +qx.Proto._layoutImpl = null; + +qx.Proto._createLayoutImpl = function() { + return null; +} + +qx.Proto.getLayoutImpl = function() { + return this._layoutImpl; +} + + + + + + + +/* +--------------------------------------------------------------------------- + CHILDREN MANAGMENT: MANAGE ALL +--------------------------------------------------------------------------- +*/ + +/*! + Return the array of all children +*/ +qx.Proto.getChildren = function() { + return this._children; +} + +/*! + Get children count +*/ +qx.Proto.getChildrenLength = function() { + return this.getChildren().length; +} + +/*! + Check if the widget has a children +*/ +qx.Proto.hasChildren = function() { + return this.getChildrenLength() > 0; +} + +/*! + Check if there are any childrens inside +*/ +qx.Proto.isEmpty = function() { + return this.getChildrenLength() == 0; +} + +/*! + Get the position of a children. +*/ +qx.Proto.indexOf = function(vChild) { + return this.getChildren().indexOf(vChild); +} + +/*! +Check if the given qx.ui.core.Widget is a children. + +#param des[qx.ui.core.Widget]: The widget which should be checked. +*/ +qx.Proto.contains = function(vWidget) +{ + switch(vWidget) + { + case null: + return false; + + case this: + return true; + + default: + // try the next parent of the widget (recursive until found) + return this.contains(vWidget.getParent()); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + CHILDREN MANAGMENT: MANAGE VISIBLE ONES + + uses a cached private property +--------------------------------------------------------------------------- +*/ + +/*! + Return the array of all visible children + (which are configured as visible=true) +*/ +qx.Proto._computeVisibleChildren = function() +{ + var vVisible = []; + var vChildren = this.getChildren(); + var vLength = vChildren.length; + + for (var i=0; i 0; +} + +/*! + Check if there are any visible childrens inside +*/ +qx.Proto.isVisibleEmpty = function() { + return this.getVisibleChildrenLength() == 0; +} + + + + + + +/* +--------------------------------------------------------------------------- + CHILDREN MANAGMENT: ADD +--------------------------------------------------------------------------- +*/ + +/*! + Add/Append another widget. Allows to add multiple at + one, a parameter could be a widget. +*/ +qx.Proto.add = function() +{ + var vWidget; + + for (var i=0, l=arguments.length; i vTargetIndex) { + vTargetIndex++; + } + + return this.addAt(vChild, Math.max(0, vTargetIndex-1)); +} + +/*! + Add a widget after another already inserted child +*/ +qx.Proto.addAfter = function(vChild, vAfter) +{ + var vChildren = this.getChildren(); + var vTargetIndex = vChildren.indexOf(vAfter); + + if (vTargetIndex == -1) { + throw new Error("Child to add after: " + vAfter + " is not inside this parent."); + } + + var vSourceIndex = vChildren.indexOf(vChild); + + if (vSourceIndex != -1 && vSourceIndex < vTargetIndex) { + vTargetIndex--; + } + + return this.addAt(vChild, Math.min(vChildren.length, vTargetIndex+1)); +} + + + + + + + +/* +--------------------------------------------------------------------------- + CHILDREN MANAGMENT: REMOVE +--------------------------------------------------------------------------- +*/ + +/*! + Remove one or multiple childrens. +*/ +qx.Proto.remove = function() +{ + var vWidget; + + for (var i=0, l=arguments.length; i omitting!"); + return; + } + + // APPLY LAYOUT + var vChanges = vChild._layoutChanges; + + // this.debug("Layouting " + vChild + ": " + qx.lang.Object.getKeysAsString(vChanges)); + + try + { + if (vChanges.borderX) { + this._applyBorderX(vChild, vChanges); + } + + if (vChanges.borderY) { + this._applyBorderY(vChild, vChanges); + } + } + catch(ex) + { + this.error("Could not apply border to child " + vChild, ex); + } + + try + { + if (vChanges.paddingLeft || vChanges.paddingRight) { + vChild._applyPaddingX(this, vChanges); + } + + if (vChanges.paddingTop || vChanges.paddingBottom) { + vChild._applyPaddingY(this, vChanges); + } + } + catch(ex) + { + this.error("Could not apply padding to child " + vChild, ex); + } + + + // WRAP TO LAYOUT ENGINE + try + { + this.getLayoutImpl().layoutChild(vChild, vChanges); + } + catch(ex) + { + this.error("Could not layout child " + vChild + " through layout handler", ex); + } + + + // POST LAYOUT + try + { + vChild._layoutPost(vChanges); + } + catch(ex) + { + this.error("Could not post layout child " + vChild, ex); + } + + + // DISPLAY DOM NODE + try + { + // insert dom node (if initial flag enabled) + if (vChanges.initial) + { + vChild._initialLayoutDone = true; + qx.ui.core.Widget.addToGlobalDisplayQueue(vChild); + } + } + catch(ex) + { + this.error("Could not handle display updates from layout flush for child " + vChild, ex); + } + + + // CLEANUP + vChild._layoutChanges = {}; + + delete vChild._isInParentLayoutQueue; + delete this._childrenQueue[vChild.toHashCode()]; +} + +qx.Proto._layoutPost = qx.util.Return.returnTrue; + +/*! + Fix Operas Rendering Bugs +*/ +if (qx.sys.Client.getInstance().isOpera()) +{ + qx.Proto._layoutChildOrig = qx.Proto._layoutChild; + + qx.Proto._layoutChild = function(vChild) + { + if (!vChild._initialLayoutDone || !vChild._layoutChanges.borderX || !vChild._layoutChanges.borderY) { + return this._layoutChildOrig(vChild); + } + + var vStyle = vChild.getElement().style; + + var vOldDisplay = vStyle.display; + vStyle.display = "none"; + var vRet = this._layoutChildOrig(vChild); + vStyle.display = vOldDisplay; + + return vRet; + } +} + + + + + + +/* +--------------------------------------------------------------------------- + DIMENSION CACHE +--------------------------------------------------------------------------- +*/ + +qx.Proto._computePreferredInnerWidth = function() { + return this.getLayoutImpl().computeChildrenNeededWidth(); +} + +qx.Proto._computePreferredInnerHeight = function() { + return this.getLayoutImpl().computeChildrenNeededHeight(); +} + +qx.Proto._changeInnerWidth = function(vNew, vOld) +{ + var vLayout = this.getLayoutImpl(); + + if (vLayout.invalidateChildrenFlexWidth) { + vLayout.invalidateChildrenFlexWidth(); + } + + this.forEachVisibleChild(function() + { + if (vLayout.updateChildOnInnerWidthChange(this) && this._recomputeBoxWidth()) + { + this._recomputeOuterWidth(); + this._recomputeInnerWidth(); + } + }); +} + +qx.Proto._changeInnerHeight = function(vNew, vOld) +{ + var vLayout = this.getLayoutImpl(); + + if (vLayout.invalidateChildrenFlexHeight) { + vLayout.invalidateChildrenFlexHeight(); + } + + this.forEachVisibleChild(function() + { + if (vLayout.updateChildOnInnerHeightChange(this) && this._recomputeBoxHeight()) + { + this._recomputeOuterHeight(); + this._recomputeInnerHeight(); + } + }); +} + +qx.Proto.getInnerWidthForChild = function(vChild) { + return this.getInnerWidth(); +} + +qx.Proto.getInnerHeightForChild = function(vChild) { + return this.getInnerHeight(); +} + + + + + + + +/* +--------------------------------------------------------------------------- + WIDGET FROM POINT SUPPORT +--------------------------------------------------------------------------- +*/ + +qx.Proto.getWidgetFromPointHelper = function(x, y) +{ + var ch = this.getChildren(); + + for (var chl=ch.length, i=0; i=0; i--) + { + this._children[i].dispose(); + this._children[i] = null; + } + + this._children = null; + } + + delete this._cachedVisibleChildren; + + // Remove Key Handler + if (this.getFocusHandler()) + { + this.removeEventListener("keydown", this._onfocuskeyevent); + this.removeEventListener("keypress", this._onfocuskeyevent); + + this.forceFocusHandler(null); + } + + return qx.ui.core.Widget.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/core/ScrollBar.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/core/ScrollBar.js new file mode 100644 index 0000000000..c4630fba87 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/core/ScrollBar.js @@ -0,0 +1,260 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 by STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +/** + * A scroll bar. + * + * @param horizontal {boolean ? false} whether the scroll bar should be + * horizontal. If false it will be vertical. + */ +qx.OO.defineClass("qx.ui.core.ScrollBar", qx.ui.layout.BoxLayout, +function(horizontal) { + qx.ui.layout.BoxLayout.call(this, horizontal ? "horizontal" : "vertical"); + + this._horizontal = (horizontal == true); + + this._scrollBar = new qx.ui.layout.CanvasLayout; + if (qx.sys.Client.getInstance().isGecko()) { + // NOTE: We have to force not using position:absolute, because this causes + // strange looking scrollbars in some cases (e.g. in Firefox under + // Linux the horizontal scrollbar is too high) + this._scrollBar.setStyleProperty("position", ""); + } + this._scrollBar.setOverflow(horizontal ? "scrollX" : "scrollY"); + this._scrollBar.enableInlineEvent("scroll"); + this._scrollBar.addEventListener("scroll", this._onscroll, this); + + this._scrollContent = new qx.ui.basic.Terminator; + if (qx.sys.Client.getInstance().isGecko()) { + this._scrollContent.setStyleProperty("position", ""); + } + this._scrollBar.add(this._scrollContent); + + if (this._horizontal) { + this._scrollContent.setHeight(5); + this._scrollBar.setWidth("100%"); + this._scrollBar.setHeight(this._getScrollBarWidth()); + + // IE needs that the scrollbar element has a width of +1 + if (qx.sys.Client.getInstance().isMshtml()) { + this.setHeight(this._getScrollBarWidth()); + this.setOverflow("hidden"); + this._scrollBar.setHeight(this._getScrollBarWidth() + 1); + this._scrollBar.setTop(-1); + } + } else { + this._scrollContent.setWidth(5); + this._scrollBar.setHeight("100%"); + this._scrollBar.setWidth(this._getScrollBarWidth()); + + // IE needs that the scrollbar element has a width of +1 + if (qx.sys.Client.getInstance().isMshtml()) { + this.setWidth(this._getScrollBarWidth()); + this.setOverflow("hidden"); + this._scrollBar.setWidth(this._getScrollBarWidth() + 1); + this._scrollBar.setLeft(-1); + } + } + + this.add(this._scrollBar); + + this.setMaximum(0); +}); + +/** + * The current value of the scroll bar. This value is between 0 and + * (maxium - size), where size is the width of a horizontal resp. the height of + * a vertical scroll bar in pixels. + * + * @see #maximum + */ +qx.OO.addProperty({ name:"value", type:"number", defaultValue:0, allowNull:false }); + +/** + * The maximum value of the scroll bar. Note that the size of the scroll bar is + * substracted. + * + * @see #value + */ +qx.OO.addProperty({ name:"maximum", type:"number", allowNull:false }); + +/** + * Whether to merge consecutive scroll event. If true, events will be collected + * until the user stops scrolling, so the scroll bar itself will move smoothly + * and the scrolled content will update asynchroniously. + */ +qx.OO.addProperty({ name:"mergeEvents", type:"boolean", defaultValue:false, allowNull:false }); + + +// property checker +qx.Proto._checkValue = function(propValue, propData) { + var innerSize = !this.getElement() ? 0 : + (this._horizontal ? this.getInnerWidth() : this.getInnerHeight()); + + // NOTE: We can't use Number.limit here because our maximum may get negative + // (when the scrollbar isn't needed). In this case Number.limit returns + // this negative maximum instead of 0. But we need that the minimum is + // stronger than the maximum. + // -> We use Math.max and Math.min + return Math.max(0, Math.min(this.getMaximum() - innerSize, propValue)); +} + + +// property modifier +qx.Proto._modifyValue = function(propValue, propOldValue, propData) { + if (! this._internalValueChange && this._isCreated) { + this._positionKnob(propValue); + } + return true; +} + + +// property modifier +qx.Proto._modifyMaximum = function(propValue, propOldValue, propData) { + if (this._horizontal) { + this._scrollContent.setWidth(propValue); + } else { + this._scrollContent.setHeight(propValue); + } + + // recheck the value + this.setValue(this._checkValue(this.getValue())); + + return true; +} + + +// property modifier +qx.Proto._modifyVisibility = function(propValue, propOldValue, propData) { + if (! propValue) { + this._positionKnob(0); + } else { + this._positionKnob(this.getValue()); + } + + return qx.ui.layout.BoxLayout.prototype._modifyVisibility.call(this, propValue, propOldValue, propData); +}; + + +// overridden +qx.Proto._computePreferredInnerWidth = function() { + return this._horizontal ? 0 : this._getScrollBarWidth(); +} + + +// overridden +qx.Proto._computePreferredInnerHeight = function() { + return this._horizontal ? this._getScrollBarWidth() : 0; +} + + +/** + * Gets the width of vertical scroll bar. + * + * @return {int} the width in pixels. + */ +qx.Proto._getScrollBarWidth = function() { + // Auto-detect the scrollbar width + if (qx.ui.core.ScrollBar._scrollBarWidth == null) { + var dummy = document.createElement("div"); + dummy.style.width = "100px"; + dummy.style.height = "100px"; + dummy.style.overflow = "scroll"; + dummy.style.visibility = "hidden"; + document.body.appendChild(dummy); + qx.ui.core.ScrollBar._scrollBarWidth = dummy.offsetWidth - dummy.clientWidth; + document.body.removeChild(dummy); + } + return qx.ui.core.ScrollBar._scrollBarWidth; +} + + +/** + * Event handler. Called when the user scrolled. + * + * @param evt {Map} the event. + */ +qx.Proto._onscroll = function(evt) { + var value = this._horizontal ? this._scrollBar.getScrollLeft() : this._scrollBar.getScrollTop(); + if (this.getMergeEvents()) { + this._lastScrollEventValue = value; + window.clearTimeout(this._setValueTimerId); + var self = this; + this._setValueTimerId = window.setTimeout(function() { + self._internalValueChange = true; + self.setValue(self._lastScrollEventValue); + self._internalValueChange = false; + qx.ui.core.Widget.flushGlobalQueues(); + }, qx.ui.core.ScrollBar.EVENT_DELAY); + } else { + this._internalValueChange = true; + this.setValue(value); + this._internalValueChange = false; + qx.ui.core.Widget.flushGlobalQueues(); + } +} + + +/** + * Positions the scroll bar knob at a certain value. + * + * @param value {int} The value where to postion the scroll bar. + */ +qx.Proto._positionKnob = function(value) { + if (this._horizontal) { + this._scrollBar.setScrollLeft(value); + } else { + this._scrollBar.setScrollTop(value); + } +} + + +// overridden +qx.Proto._afterAppear = function() { + qx.ui.layout.BoxLayout.prototype._afterAppear.call(this); + + //this.debug("Setting to value: " + this.getValue()); + this._positionKnob(this.getValue()); +} + + +// overridden +qx.Proto.dispose = function() { + if (this.getDisposed()) { + return; + } + + if (this._scrollContent) { + this._scrollContent.dispose(); + this._scrollContent = null; + } + + return qx.ui.layout.BoxLayout.prototype.dispose.call(this); +} + + +/** + * The delay when to update the scroll bar value after a scroll event if + * {@link #mergeEvents} is true (in milliseconds). All scroll events that arrive + * in shorter time will be merged. + */ +qx.Class.EVENT_DELAY = 250; diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/core/Widget.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/core/Widget.js new file mode 100644 index 0000000000..de775ac97b --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/core/Widget.js @@ -0,0 +1,5703 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_core) +#require(qx.renderer.color.ColorCache) +#require(qx.renderer.border.BorderCache) +#require(qx.manager.object.AppearanceManager) +#after(qx.component.init.InterfaceInitComponent) +#optional(qx.ui.core.Parent) +#optional(qx.ui.form.Button) +#optional(qx.client.Timer) +#optional(qx.client.Command) +#optional(qx.ui.popup.ToolTip) +#optional(qx.ui.menu.Menu) +#optional(qx.ui.basic.Inline) + +************************************************************************ */ + +/** + * This is the main widget, all visible objects in the application extend this. + * + * @event beforeAppear {qx.event.type.Event} + * @event appear {qx.event.type.Event} + * @event beforeDisappear {qx.event.type.Event} + * @event disappear {qx.event.type.Event} + * @event beforeInsertDom {qx.event.type.Event} + * @event insertDom {qx.event.type.Event} + * @event beforeRemoveDom {qx.event.type.Event} + * @event removeDom {qx.event.type.Event} + * @event create {qx.event.type.Event} + * @event execute {qx.event.type.Event} + * @event FADE_FINISHED {qx.event.type.DataEvent} + * @event mouseover {qx.event.type.MouseEvent} (Fired by {@link qx.event.handler.EventHandler}) + * @event mousemove {qx.event.type.MouseEvent} (Fired by {@link qx.event.handler.EventHandler}) + * @event mouseout {qx.event.type.MouseEvent} (Fired by {@link qx.event.handler.EventHandler}) + * @event mousedown {qx.event.type.MouseEvent} (Fired by {@link qx.event.handler.EventHandler}) + * @event mouseup {qx.event.type.MouseEvent} (Fired by {@link qx.event.handler.EventHandler}) + * @event mousewheel {qx.event.type.MouseEvent} (Fired by {@link qx.event.handler.EventHandler}) + * @event click {qx.event.type.MouseEvent} (Fired by {@link qx.event.handler.EventHandler}) + * @event dblclick {qx.event.type.MouseEvent} (Fired by {@link qx.event.handler.EventHandler}) + * @event contextmenu {qx.event.type.MouseEvent} (Fired by {@link qx.event.handler.EventHandler}) + * @event keydown {qx.event.type.KeyEvent} (Fired by {@link qx.event.handler.EventHandler}) + * @event keypress {qx.event.type.KeyEvent} (Fired by {@link qx.event.handler.EventHandler}) + * @event keyinput {qx.event.type.KeyEvent} (Fired by {@link qx.event.handler.EventHandler}) + * @event keyup {qx.event.type.KeyEvent} (Fired by {@link qx.event.handler.EventHandler}) + * @event focusout {qx.event.type.FocusEvent} (Fired by {@link qx.ui.core.Parent}) + * @event focusin {qx.event.type.FocusEvent} (Fired by {@link qx.ui.core.Parent}) + * @event blur {qx.event.type.FocusEvent} (Fired by {@link qx.ui.core.Parent}) + * @event focus {qx.event.type.FocusEvent} (Fired by {@link qx.ui.core.Parent}) + */ +qx.OO.defineClass("qx.ui.core.Widget", qx.core.Target, +function() +{ + if (this.classname == qx.ui.core.Widget.ABSTRACT_CLASS) { + throw new Error("Please omit the usage of qx.ui.core.Widget directly. Choose between qx.ui.core.Parent and qx.ui.basic.Terminator instead!"); + } + + qx.core.Target.call(this, true); + + + // ************************************************************************ + // HTML MAPPING DATA STRUCTURES + // ************************************************************************ + // Allows the user to setup styles and attributes without a + // need to have the target element created already. + /* + this._htmlProperties = { className : this.classname } + this._htmlAttributes = { qxhashcode : this._hashCode } + */ + this._styleProperties = { position : "absolute" } + + + // ************************************************************************ + // LAYOUT CHANGES + // ************************************************************************ + this._layoutChanges = {}; + + + // ************************************************************************ + // APPEARANCE + // ************************************************************************ + this._states = {}; + this._applyInitialAppearance(); +}); + +qx.Class.ABSTRACT_CLASS = "qx.ui.core.Widget"; + +// Will be calculated later (TODO: Move to qx.Dom?) +qx.Class.SCROLLBAR_SIZE = 16; + + + + + +/* +--------------------------------------------------------------------------- + DEFAULT SETTINGS +--------------------------------------------------------------------------- +*/ + +qx.Settings.setDefault("enableQueueDebug", false); + + + + + + +/* +--------------------------------------------------------------------------- + BASIC PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + The parent widget (the real object, no ID or something) +*/ +qx.OO.addProperty({ name : "parent", type : "object", instance : "qx.ui.core.Parent", defaultValue : null }); + +/*! + The element node (if the widget is created, otherwise null) +*/ +qx.OO.addProperty({ name : "element" }); + +/*! + Simple and fast switch of the visibility of a widget. +*/ +qx.OO.addProperty({ name : "visibility", type : "boolean", defaultValue : true }); + +/*! + If the widget should be displayed. Use this property instead of visibility if the change + in visibility should have effects on the parent widget. +*/ +qx.OO.addProperty({ name : "display", type : "boolean", defaultValue : true }); + +/*! + If you switch this to true, the widget doesn't handle + events directly. It will redirect them to the parent + widget. +*/ +qx.OO.addProperty({ name : "anonymous", type : "boolean", defaultValue : false, getAlias : "isAnonymous" }); + +/*! + The tagname of the element which should automatically be created +*/ +qx.OO.addProperty({ name : "tagName", type : "string", defaultValue : "div" }); + +/*! + This is used by many layout managers to control the individual horizontal alignment of this widget inside this parent. + + This should be used with caution since in some cases + this might give unrespected results. +*/ +qx.OO.addProperty({ name : "horizontalAlign", type : "string" }); + +/*! + This is used by many layout managers to control the individual vertical alignment of this widget inside this parent. + + This should be used with caution since in some cases + this might give unrespected results. +*/ +qx.OO.addProperty({ name : "verticalAlign", type : "string" }); + +/*! + Should this widget be stretched on the x-axis if the layout handler will do this? + Used by some layout handlers (qx.ui.layout.BoxLayout, ...). +*/ +qx.OO.addProperty({ name : "allowStretchX", type : "boolean", defaultValue : true }); + +/*! + Should this widget be stretched on the y-axis if the layout handler will do this? + Used by some layout handlers (qx.ui.layout.BoxLayout, ...). +*/ +qx.OO.addProperty({ name : "allowStretchY", type : "boolean", defaultValue : true }); + + + + + + +/* +--------------------------------------------------------------------------- + STYLE PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + Mapping to native style property z-index. + + This should be used with caution since in some cases + this might give unrespected results. +*/ +qx.OO.addProperty({ name : "zIndex", type : "number" }); + +/*! + The backgroundColor style property of the rendered widget. + As input are allowed any instance of qx.renderer.color.Color or a string which defines the color itself. +*/ +qx.OO.addProperty({ name : "backgroundColor", type : "object", instance : "qx.renderer.color.Color", convert : qx.renderer.color.ColorCache, allowMultipleArguments : true }); + +/*! + The color style property of the rendered widget. + As input are allowed any instance of qx.renderer.color.Color or a string which defines the color itself. +*/ +qx.OO.addProperty({ name : "color", type : "object", instance : "qx.renderer.color.Color", convert : qx.renderer.color.ColorCache, allowMultipleArguments : true }); + +/*! + The border property describes how to paint the border on the widget. + + This should be used with caution since in some cases (mostly complex widgets) + this might give unrespected results. +*/ +qx.OO.addProperty({ name : "border", type : "object", instance : "qx.renderer.border.Border", convert : qx.renderer.border.BorderCache, allowMultipleArguments : true }); + +/*! + Mapping to native style property opacity. + + The uniform opacity setting to be applied across an entire object. Behaves like the new CSS-3 Property. + Any values outside the range 0.0 (fully transparent) to 1.0 (fully opaque) will be clamped to this range. +*/ +qx.OO.addProperty({ name : "opacity", type : "number" }); + +/*! + Mapping to native style property cursor. + + The name of the cursor to show when the mouse pointer is over the widget. + This is any valid CSS2 cursor name defined by W3C. + + The following values are possible: +

+*/ +qx.OO.addProperty({ name : "cursor", type : "string" }); + +/*! + Mapping to native style property background-image. + + The URI of the image file to use as background image. +*/ +qx.OO.addProperty({ name : "backgroundImage", type : "string" }); + +/** + * Describes how to handle content that is too large to fit inside the widget. + * + * Overflow modes: + * * hidden: The content is clipped + * * auto: Scroll bars are shown as needed + * * scroll: Scroll bars are always shown. Even if there is enough room for the content inside the widget. + * * scrollX: Scroll bars for the X-Axis are always shown. Even if there is enough room for the content inside the widget. + * * scrollY: Scroll bars for the Y-Axis are always shown. Even if there is enough room for the content inside the widget. + */ +qx.OO.addProperty({ name : "overflow", type : "string", addToQueue : true }); + +/*! + Clipping of the widget (left) +*/ +qx.OO.addProperty({ name : "clipLeft", type : "number", impl : "clip" }); + +/*! + Clipping of the widget (top) +*/ +qx.OO.addProperty({ name : "clipTop", type : "number", impl : "clip" }); + +/*! + Clipping of the widget (width) +*/ +qx.OO.addProperty({ name : "clipWidth", type : "number", impl : "clip" }); + +/*! + Clipping of the widget (height) +*/ +qx.OO.addProperty({ name : "clipHeight", type : "number", impl : "clip" }); + + + + + + + +/* +--------------------------------------------------------------------------- + MANAGMENT PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + Set this to a positive value makes the widget able to get the focus. + It even is reachable through the usage of the tab-key. + + Widgets with the same tabIndex are handled through there position + in the document. +*/ +qx.OO.addProperty({ name : "tabIndex", type : "number", defaultValue : -1 }); + +/*! + If the focus outline should be hidden. +*/ +qx.OO.addProperty({ name : "hideFocus", type : "boolean", defaultValue : false }); + +/*! + Use DOM focussing (focus() and blur() methods of DOM nodes) +*/ +qx.OO.addProperty({ name : "enableElementFocus", type : "boolean", defaultValue : true }); + +/*! + Handle focus state of this widget. + + someWidget.setFocused(true) set the current focus to this widget. + someWidget.setFocused(false) remove the current focus and leave it blank. + + Normally you didn't need to set this directly. +*/ +qx.OO.addProperty({ name : "focused", type : "boolean", defaultValue : false }); + +/*! + Toggle the possibility to select the element of this widget. +*/ +qx.OO.addProperty({ name : "selectable", type : "boolean", defaultValue : true, getAlias : "isSelectable" }); + +/*! + Contains the tooltip object connected to the widget. +*/ +qx.OO.addProperty({ name : "toolTip", type : "object", instance : "qx.ui.popup.ToolTip" }); + +/*! + Contains the context menu object connected to the widget. (Need real implementation) +*/ +qx.OO.addProperty({ name : "contextMenu", type : "object", instance : "qx.ui.menu.Menu" }); + +/*! + Capture all events and map them to this widget +*/ +qx.OO.addProperty({ name : "capture", type : "boolean", defaultValue : false }); + +/*! + Contains the support drop types for drag and drop support +*/ +qx.OO.addProperty({ name : "dropDataTypes" }); + +/*! + A command called if the widget should be excecuted (a placeholder for buttons, ...) +*/ +qx.OO.addProperty({ name : "command", type : "object", instance : "qx.client.Command" }); + +/*! + Appearance of the widget +*/ +qx.OO.addProperty({ name : "appearance", type : "string" }); + + + + + + +/* +--------------------------------------------------------------------------- + MARGIN/PADDING PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + Margin of the widget (top) +*/ +qx.OO.addProperty({ name : "marginTop", type : "number", addToQueue : true, impl : "marginY" }); + +/*! + Margin of the widget (right) +*/ +qx.OO.addProperty({ name : "marginRight", type : "number", addToQueue : true, impl : "marginX" }); + +/*! + Margin of the widget (bottom) +*/ +qx.OO.addProperty({ name : "marginBottom", type : "number", addToQueue : true, impl : "marginY" }); + +/*! + Margin of the widget (left) +*/ +qx.OO.addProperty({ name : "marginLeft", type : "number", addToQueue : true, impl : "marginX" }); + + +/*! + Padding of the widget (top) +*/ +qx.OO.addProperty({ name : "paddingTop", type : "number", addToQueue : true, impl : "paddingY" }); + +/*! + Padding of the widget (right) +*/ +qx.OO.addProperty({ name : "paddingRight", type : "number", addToQueue : true, impl : "paddingX" }); + +/*! + Padding of the widget (bottom) +*/ +qx.OO.addProperty({ name : "paddingBottom", type : "number", addToQueue : true, impl : "paddingY" }); + +/*! + Padding of the widget (left) +*/ +qx.OO.addProperty({ name : "paddingLeft", type : "number", addToQueue : true, impl : "paddingX" }); + + + + + + + +/* +--------------------------------------------------------------------------- + HORIZONAL DIMENSION PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + The distance from the outer left border to the parent left area edge. + + You could only set two of the three horizonal dimension properties (boxLeft, boxRight, boxWidth) + at the same time. This will be omitted during the setup of the new third value. To reset a value + you didn't want anymore, set it to null. +*/ +qx.OO.addProperty({ name : "left", addToQueue : true, unitDetection : "pixelPercent" }); + +/*! + The distance from the outer right border to the parent right area edge. + + You could only set two of the three horizonal dimension properties (boxLeft, boxRight, boxWidth) + at the same time. This will be omitted during the setup of the new third value. To reset a value + you didn't want anymore, set it to null. +*/ +qx.OO.addProperty({ name : "right", addToQueue : true, unitDetection : "pixelPercent" }); + +/*! + The width of the box (including padding and border). + + You could only set two of the three horizonal dimension properties (boxLeft, boxRight, boxWidth) + at the same time. This will be omitted during the setup of the new third value. To reset a value + you didn't want anymore, set it to null. +*/ +qx.OO.addProperty({ name : "width", addToQueue : true, unitDetection : "pixelPercentAutoFlex" }); + +/*! + The minimum width of the box (including padding and border). + + Set this to omit the shrinking of the box width under this value. +*/ +qx.OO.addProperty({ name : "minWidth", addToQueue : true, unitDetection : "pixelPercentAuto" }); + +/*! + The maximum width of the box (including padding and border). + + Set this to omit the expanding of the box width above this value. +*/ +qx.OO.addProperty({ name : "maxWidth", addToQueue : true, unitDetection : "pixelPercentAuto" }); + + + + + + + +/* +--------------------------------------------------------------------------- + VERTICAL DIMENSION PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + The distance from the outer top border to the parent top area edge. + + You could only set two of the three vertical dimension properties (boxTop, boxBottom, boxHeight) + at the same time. This will be omitted during the setup of the new third value. To reset a value + you didn't want anymore, set it to null. +*/ +qx.OO.addProperty({ name : "top", addToQueue : true, unitDetection : "pixelPercent" }); + +/*! + The distance from the outer bottom border to the parent bottom area edge. + + You could only set two of the three vertical dimension properties (boxTop, boxBottom, boxHeight) + at the same time. This will be omitted during the setup of the new third value. To reset a value + you didn't want anymore, set it to null. +*/ +qx.OO.addProperty({ name : "bottom", addToQueue : true, unitDetection : "pixelPercent" }); + +/*! + The height of the box (including padding and border). + + You could only set two of the three vertical dimension properties (boxTop, boxBottom, boxHeight) + at the same time. This will be omitted during the setup of the new third value. To reset a value + you didn't want anymore, set it to null. +*/ +qx.OO.addProperty({ name : "height", addToQueue : true, unitDetection : "pixelPercentAutoFlex" }); + +/*! + The minimum height of the box (including padding and border). + + Set this to omit the shrinking of the box height under this value. +*/ +qx.OO.addProperty({ name : "minHeight", addToQueue : true, unitDetection : "pixelPercentAuto" }); + +/*! + The maximum height of the box (including padding and border). + + Set this to omit the expanding of the box height above this value. +*/ +qx.OO.addProperty({ name : "maxHeight", addToQueue : true, unitDetection : "pixelPercentAuto" }); + + + + + + + +/* +--------------------------------------------------------------------------- + PROPERTY GROUPS +--------------------------------------------------------------------------- +*/ + +qx.OO.addPropertyGroup({ name : "location", members : [ "left", "top" ]}); +qx.OO.addPropertyGroup({ name : "dimension", members : [ "width", "height" ]}); + +qx.OO.addPropertyGroup({ name : "space", members : [ "left", "width", "top", "height" ]}); +qx.OO.addPropertyGroup({ name : "edge", members : [ "top", "right", "bottom", "left" ], mode : "shorthand" }); + +qx.OO.addPropertyGroup({ name : "padding", members : [ "paddingTop", "paddingRight", "paddingBottom", "paddingLeft" ], mode: "shorthand" }); +qx.OO.addPropertyGroup({ name : "margin", members : [ "marginTop", "marginRight", "marginBottom", "marginLeft" ], mode: "shorthand" }); + +qx.OO.addPropertyGroup({ name : "heights", members : [ "minHeight", "height", "maxHeight" ]}); +qx.OO.addPropertyGroup({ name : "widths", members : [ "minWidth", "width", "maxWidth" ]}); + +qx.OO.addPropertyGroup({ name : "align", members : [ "horizontalAlign", "verticalAlign" ]}); +qx.OO.addPropertyGroup({ name : "stretch", members : [ "stretchX", "stretchY" ]}); + +qx.OO.addPropertyGroup({ name : "clipLocation", members : [ "clipLeft", "clipTop" ]}); +qx.OO.addPropertyGroup({ name : "clipDimension", members : [ "clipWidth", "clipHeight" ]}); +qx.OO.addPropertyGroup({ name : "clip", members : [ "clipLeft", "clipTop", "clipWidth", "clipHeight" ]}); + + + + + + + + +/* ************************************************************************ + Class data, properties and methods +************************************************************************ */ + +/* +--------------------------------------------------------------------------- + ALL QUEUES +--------------------------------------------------------------------------- +*/ + +if (qx.Settings.getValueOfClass("qx.ui.core.Widget", "enableQueueDebug")) +{ + qx.ui.core.Widget.flushGlobalQueues = function() + { + if (qx.ui.core.Widget._inFlushGlobalQueues || !qx.core.Init.getInstance().getComponent().isUiReady()) { + return; + } + + if (!(qx.ui.core.Widget._globalWidgetQueue.length > 0 || qx.ui.core.Widget._globalElementQueue.length > 0 || + qx.ui.core.Widget._globalStateQueue.length > 0 || qx.ui.core.Widget._globalJobQueue.length > 0 || + qx.ui.core.Widget._globalLayoutQueue.length > 0 || qx.ui.core.Widget._fastGlobalDisplayQueue.length > 0 || + !qx.lang.Object.isEmpty(qx.ui.core.Widget._lazyGlobalDisplayQueue))) { + return; + } + + var globalWidgetQueueLength = qx.ui.core.Widget._globalWidgetQueue.length; + var globalElementQueueLength = qx.ui.core.Widget._globalElementQueue.length; + var globalStateQueueLength = qx.ui.core.Widget._globalStateQueue.length; + var globalJobQueueLength = qx.ui.core.Widget._globalJobQueue.length; + var globalLayoutQueueLength = qx.ui.core.Widget._globalLayoutQueue.length; + var fastGlobalDisplayQueueLength = qx.ui.core.Widget._fastGlobalDisplayQueue.length; + var lazyGlobalDisplayQueueLength = qx.ui.core.Widget._lazyGlobalDisplayQueue ? qx.ui.core.Widget._lazyGlobalDisplayQueue.length : 0; + + // Also used for inline event handling to seperate 'real' events + qx.ui.core.Widget._inFlushGlobalQueues = true; + + var vStart; + + vStart = (new Date).valueOf(); + qx.ui.core.Widget.flushGlobalWidgetQueue(); + var vWidgetDuration = (new Date).valueOf() - vStart; + + vStart = (new Date).valueOf(); + qx.ui.core.Widget.flushGlobalStateQueue(); + var vStateDuration = (new Date).valueOf() - vStart; + + vStart = (new Date).valueOf(); + qx.ui.core.Widget.flushGlobalElementQueue(); + var vElementDuration = (new Date).valueOf() - vStart; + + vStart = (new Date).valueOf(); + qx.ui.core.Widget.flushGlobalJobQueue(); + var vJobDuration = (new Date).valueOf() - vStart; + + vStart = (new Date).valueOf(); + qx.ui.core.Widget.flushGlobalLayoutQueue(); + var vLayoutDuration = (new Date).valueOf() - vStart; + + vStart = (new Date).valueOf(); + qx.ui.core.Widget.flushGlobalDisplayQueue(); + var vDisplayDuration = (new Date).valueOf() - vStart; + + var vSum = vWidgetDuration + vStateDuration + vElementDuration + vJobDuration + vLayoutDuration + vDisplayDuration; + + if (vSum > 0) + { + var logger = qx.dev.log.Logger.getClassLogger(qx.ui.core.Widget); + logger.debug("Flush Global Queues"); + logger.debug("Widgets: " + vWidgetDuration + "ms (" + globalWidgetQueueLength + ")"); + logger.debug("State: " + vStateDuration + "ms (" + globalStateQueueLength + ")"); + logger.debug("Element: " + vElementDuration + "ms (" + globalElementQueueLength + ")"); + logger.debug("Job: " + vJobDuration + "ms (" + globalJobQueueLength + ")"); + logger.debug("Layout: " + vLayoutDuration + "ms (" + globalLayoutQueueLength + ")"); + logger.debug("Display: " + vDisplayDuration + "ms (fast:" + fastGlobalDisplayQueueLength + ",lazy:" + lazyGlobalDisplayQueueLength + ")"); + + window.status = "Flush: Widget:" + vWidgetDuration + " State:" + vStateDuration + " Element:" + vElementDuration + " Job:" + vJobDuration + " Layout:" + vLayoutDuration + " Display:" + vDisplayDuration; + } + + delete qx.ui.core.Widget._inFlushGlobalQueues; + } +} +else +{ + qx.ui.core.Widget.flushGlobalQueues = function() + { + if (qx.ui.core.Widget._inFlushGlobalQueues || !qx.core.Init.getInstance().getComponent().isUiReady()) { + return; + } + + // Also used for inline event handling to seperate 'real' events + qx.ui.core.Widget._inFlushGlobalQueues = true; + + qx.ui.core.Widget.flushGlobalWidgetQueue(); + qx.ui.core.Widget.flushGlobalStateQueue(); + qx.ui.core.Widget.flushGlobalElementQueue(); + qx.ui.core.Widget.flushGlobalJobQueue(); + qx.ui.core.Widget.flushGlobalLayoutQueue(); + qx.ui.core.Widget.flushGlobalDisplayQueue(); + + delete qx.ui.core.Widget._inFlushGlobalQueues; + } +} + + + + + + +/* +--------------------------------------------------------------------------- + WIDGET QUEUE + + Allows widgets to register to the widget queue to do multiple things + before the other queues will be flushed +--------------------------------------------------------------------------- +*/ + +qx.ui.core.Widget._globalWidgetQueue = []; + +qx.ui.core.Widget.addToGlobalWidgetQueue = function(vWidget) +{ + if (!vWidget._isInGlobalWidgetQueue && vWidget._isDisplayable) + { + qx.ui.core.Widget._globalWidgetQueue.push(vWidget); + vWidget._isInGlobalWidgetQueue = true; + } +} + +qx.ui.core.Widget.removeFromGlobalWidgetQueue = function(vWidget) +{ + if (vWidget._isInGlobalWidgetQueue) + { + qx.lang.Array.remove(qx.ui.core.Widget._globalWidgetQueue, vWidget); + delete vWidget._isInGlobalWidgetQueue; + } +} + +qx.ui.core.Widget.flushGlobalWidgetQueue = function() +{ + var vQueue=qx.ui.core.Widget._globalWidgetQueue, vLength, vWidget; + + while ((vLength=vQueue.length) > 0) + { + for (var i=0; i 0) + { + for (var i=0; i 0) + { + for (var i=0; i 0) + { + for (var i=0; i 0) + { + for (var i=0; i= 3) + { + // creating new document fragment + vFragment = document.createDocumentFragment(); + + // appending all widget elements to fragment + for (var i=0, l=vLazyQueue.length; i 0 && el.offsetHeight > 0); +} + +/*! + A single setup to the current preferred pixel values of the widget +*/ +qx.Proto.pack = function() +{ + this.setWidth(this.getPreferredBoxWidth()); + this.setHeight(this.getPreferredBoxHeight()); +} + +/*! + A bounded setup to the preferred width/height of the widget. Keeps in + sync if the content or requirements of the widget changes +*/ +qx.Proto.auto = function() +{ + this.setWidth("auto"); + this.setHeight("auto"); +} + + + + + +/* +--------------------------------------------------------------------------- + CHILDREN HANDLING: ALL +--------------------------------------------------------------------------- +*/ + +/*! + Get an array of the current children +*/ +qx.Proto.getChildren = qx.util.Return.returnNull; + +/*! + Get the number of children +*/ +qx.Proto.getChildrenLength = qx.util.Return.returnZero; + +/*! + Get if the widget has any children +*/ +qx.Proto.hasChildren = qx.util.Return.returnFalse; + +/*! + Get if the widget has no children +*/ +qx.Proto.isEmpty = qx.util.Return.returnTrue; + +/*! + Return the position of the child inside +*/ +qx.Proto.indexOf = qx.util.Return.returnNegativeIndex; + +/*! + Test if this widget contains the given widget +*/ +qx.Proto.contains = qx.util.Return.returnFalse; + + + + + + +/* +--------------------------------------------------------------------------- + CHILDREN HANDLING: VISIBLE ONES +--------------------------------------------------------------------------- +*/ + +/*! + Get an array of the current visible children +*/ +qx.Proto.getVisibleChildren = qx.util.Return.returnNull; + +/*! + Get the number of children +*/ +qx.Proto.getVisibleChildrenLength = qx.util.Return.returnZero; + +/*! + If this widget has visible children +*/ +qx.Proto.hasVisibleChildren = qx.util.Return.returnFalse; + +/*! + Check if there are any visible children inside +*/ +qx.Proto.isVisibleEmpty = qx.util.Return.returnTrue; + + + + + +/* +--------------------------------------------------------------------------- + CORE MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._hasParent = false; +qx.Proto._isDisplayable = false; + +qx.Proto.isDisplayable = function() { + return this._isDisplayable; +} + +qx.Proto._checkParent = function(propValue, propOldValue, propData) +{ + if (this.contains(propValue)) { + throw new Error("Could not insert myself into a child " + propValue + "!"); + } + + return propValue; +} + +qx.Proto._modifyParent = function(propValue, propOldValue, propData) +{ + if (propOldValue) + { + var vOldIndex = propOldValue.getChildren().indexOf(this); + + // Reset cached dimension and location values + this._computedWidthValue = this._computedMinWidthValue = this._computedMaxWidthValue = this._computedLeftValue = this._computedRightValue = null; + this._computedHeightValue = this._computedMinHeightValue = this._computedMaxHeightValue = this._computedTopValue = this._computedBottomValue = null; + + this._cachedBoxWidth = this._cachedInnerWidth = this._cachedOuterWidth = null; + this._cachedBoxHeight = this._cachedInnerHeight = this._cachedOuterHeight = null; + + // Finally remove from children array + qx.lang.Array.removeAt(propOldValue.getChildren(), vOldIndex); + + // Invalidate visible children cache + propOldValue._invalidateVisibleChildren(); + + // Remove child from old parent's children queue + propOldValue._removeChildFromChildrenQueue(this); + + // The layouter adds some layout jobs + propOldValue.getLayoutImpl().updateChildrenOnRemoveChild(this, vOldIndex); + + // Inform job queue + propOldValue.addToJobQueue("removeChild"); + + // Invalidate inner preferred dimensions + propOldValue._invalidatePreferredInnerDimensions(); + + // Store old parent (needed later by _handleDisplayable) + this._oldParent = propOldValue; + } + + if (propValue) + { + this._hasParent = true; + + if (qx.util.Validation.isValidNumber(this._insertIndex)) + { + qx.lang.Array.insertAt(propValue.getChildren(), this, this._insertIndex); + delete this._insertIndex; + } + else + { + propValue.getChildren().push(this); + } + } + else + { + this._hasParent = false; + } + + return this._handleDisplayable("parent"); +} + +qx.Proto._modifyDisplay = function(propValue, propOldValue, propData) { + return this._handleDisplayable("display"); +} + + + + + + + +/* +--------------------------------------------------------------------------- + DISPLAYBLE HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._handleDisplayable = function(vHint) +{ + // Detect changes. Return if there is no change. + // Also handle the case if the displayable keeps true and the parent + // was changed then we must not return here. + var vDisplayable = this._computeDisplayable(); + if (this._isDisplayable == vDisplayable && !(vDisplayable && vHint == "parent")) { + return true; + } + + this._isDisplayable = vDisplayable; + + var vParent = this.getParent(); + + // Invalidate visible children + if (vParent) + { + vParent._invalidateVisibleChildren(); + vParent._invalidatePreferredInnerDimensions(); + } + + // Remove old parent's elements from DOM and delete old parent + if (vHint && this._oldParent && this._oldParent._initialLayoutDone) + { + var vElement = this.getElement(); + if(vElement) + { + if (this.getVisibility()) { + this._beforeDisappear(); + } + + this._beforeRemoveDom(); + + this._oldParent._getTargetNode().removeChild(vElement); + + this._afterRemoveDom(); + + if (this.getVisibility()) { + this._afterDisappear(); + } + } + + delete this._oldParent; + } + + // Handle 'show' + if (vDisplayable) + { + /* -------------------------------- + Update current parent + -------------------------------- */ + + // The layouter added some layout jobs + if (vParent._initialLayoutDone) + { + vParent.getLayoutImpl().updateChildrenOnAddChild(this, vParent.getChildren().indexOf(this)); + + // Inform parents job queue + vParent.addToJobQueue("addChild"); + } + + // Add to parents children queue + // (indirectly with a new layout request) + this.addToLayoutChanges("initial"); + + // Add to custom queues + this.addToCustomQueues(vHint); + + // Handle beforeAppear signals + if (this.getVisibility()) { + this._beforeAppear(); + } + + + + /* -------------------------------- + Add to global Queues + -------------------------------- */ + + // Add element (and create if not ready) + if (!this._isCreated) { + qx.ui.core.Widget.addToGlobalElementQueue(this); + } + + // Add to global queues + qx.ui.core.Widget.addToGlobalStateQueue(this); + + if (!qx.lang.Object.isEmpty(this._jobQueue)) { + qx.ui.core.Widget.addToGlobalJobQueue(this); + } + + if (!qx.lang.Object.isEmpty(this._childrenQueue)) { + qx.ui.core.Widget.addToGlobalLayoutQueue(this); + } + } + + // Handle 'hide' + else + { + // Removing from global queues + qx.ui.core.Widget.removeFromGlobalElementQueue(this); + qx.ui.core.Widget.removeFromGlobalStateQueue(this); + qx.ui.core.Widget.removeFromGlobalJobQueue(this); + qx.ui.core.Widget.removeFromGlobalLayoutQueue(this); + + // Add to top-level tree queue + this.removeFromCustomQueues(vHint); + + // only remove when itself want to be removed + // through a property change - not a parent signal + if (vParent && vHint) + { + if (this.getVisibility()) { + this._beforeDisappear(); + } + + // The layouter added some layout jobs + if (vParent._initialLayoutDone && this._initialLayoutDone) + { + vParent.getLayoutImpl().updateChildrenOnRemoveChild(this, vParent.getChildren().indexOf(this)); + + // Inform parent's job queue + vParent.addToJobQueue("removeChild"); + + // Before Remove DOM Event + this._beforeRemoveDom(); + + // DOM action + vParent._getTargetNode().removeChild(this.getElement()); + + // After Remove DOM Event + this._afterRemoveDom(); + } + + // Remove from parents children queue + vParent._removeChildFromChildrenQueue(this); + + if (this.getVisibility()) { + this._afterDisappear(); + } + } + } + + this._handleDisplayableCustom(vDisplayable, vParent, vHint); + + return true; +} + +qx.Proto.addToCustomQueues = qx.util.Return.returnTrue; +qx.Proto.removeFromCustomQueues = qx.util.Return.returnTrue; + +qx.Proto._handleDisplayableCustom = qx.util.Return.returnTrue; + +qx.Proto._computeDisplayable = function() { + return this.getDisplay() && this._hasParent && this.getParent()._isDisplayable ? true : false; +} + +qx.Proto._beforeAppear = function() +{ + // this.debug("_beforeAppear"); + this.createDispatchEvent("beforeAppear"); +} + +qx.Proto._afterAppear = function() +{ + // this.debug("_afterAppear"); + this._isSeeable = true; + this.createDispatchEvent("appear"); +} + +qx.Proto._beforeDisappear = function() +{ + // this.debug("_beforeDisappear"); + + // Remove any hover/pressed styles + this.removeState("over"); + + if (qx.OO.isAvailable("qx.ui.form.Button")) + { + this.removeState("pressed"); + this.removeState("abandoned"); + } + + // this.debug("_beforeDisappear"); + this.createDispatchEvent("beforeDisappear"); +} + +qx.Proto._afterDisappear = function() +{ + // this.debug("_afterDisappear"); + this._isSeeable = false; + this.createDispatchEvent("disappear"); +} + +qx.Proto._isSeeable = false; + +/** + * If the widget is currently seeable which means that it: + * + * * has a also seeable parent + * * visibility is true + * * display is true + */ +qx.Proto.isSeeable = function() { + return this._isSeeable; +} + +qx.Proto.isAppearRelevant = function() { + return this.getVisibility() && this._isDisplayable; +} + + + + + +/* +--------------------------------------------------------------------------- + DOM SIGNAL HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._beforeInsertDom = function() +{ + // this.debug("_beforeInsertDom"); + this.createDispatchEvent("beforeInsertDom"); +} + +qx.Proto._afterInsertDom = function() +{ + // this.debug("_afterInsertDom"); + this.createDispatchEvent("insertDom"); +} + +qx.Proto._beforeRemoveDom = function() +{ + // this.debug("_beforeRemoveDom"); + this.createDispatchEvent("beforeRemoveDom"); +} + +qx.Proto._afterRemoveDom = function() +{ + // this.debug("_afterRemoveDom"); + this.createDispatchEvent("removeDom"); +} + + + + + + +/* +--------------------------------------------------------------------------- + VISIBILITY HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyVisibility = function(propValue, propOldValue, propData) +{ + if (propValue) + { + if (this._isDisplayable) { + this._beforeAppear(); + } + + this.removeStyleProperty("display"); + + if (this._isDisplayable) { + this._afterAppear(); + } + } + else + { + if (this._isDisplayable) { + this._beforeDisappear(); + } + + this.setStyleProperty("display", "none"); + + if (this._isDisplayable) { + this._afterDisappear(); + } + } + + return true; +} + +qx.Proto.show = function() +{ + this.setVisibility(true); + this.setDisplay(true); +} + +qx.Proto.hide = function() { + this.setVisibility(false); +} + +qx.Proto.connect = function() { + this.setDisplay(true); +} + +qx.Proto.disconnect = function() { + this.setDisplay(false); +} + + + + + +/* +--------------------------------------------------------------------------- + ENHANCED BORDER SUPPORT +--------------------------------------------------------------------------- +*/ + +if (qx.sys.Client.getInstance().isGecko()) +{ + qx.Proto._createElementForEnhancedBorder = qx.util.Return.returnTrue; +} +else +{ + qx.Proto._createElementForEnhancedBorder = function() + { + // Enhanced Border Test (for IE and Opera) + if (qx.renderer.border.Border.enhancedCrossBrowserMode && + this.getTagName() == "div" && + !this._borderElement) + { + var el = this.getElement(); + var cl = this._borderElement = document.createElement("div"); + + var es = el.style; + var cs = this._borderStyle = cl.style; + + cs.width = cs.height = "100%"; + cs.position = "absolute"; + + for (var i in this._styleProperties) + { + switch(i) + { + case "position": + case "zIndex": + case "filter": + case "display": + break; + + default: + cs[i] = this._styleProperties[i]; + es[i] = ""; + } + } + + // Move existing children + while(el.firstChild) { + cl.appendChild(el.firstChild); + } + + el.appendChild(cl); + } + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + DOM ELEMENT HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._isCreated = false; + +if (qx.sys.Client.getInstance().isGecko()) +{ + qx.Proto._getTargetNode = function() { + return this._element; + } +} +else +{ + qx.Proto._getTargetNode = function() { + return this._borderElement || this._element; + } +} + +qx.Proto.addToDocument = function() { + qx.ui.core.ClientDocument.getInstance().add(this); +} + +/*! + Check if the widget is created (or the element is already available). +*/ +qx.Proto.isCreated = function() { + return this._isCreated; +} + +/*! + Create widget with empty element (of specified tagname). +*/ +qx.Proto._createElementImpl = function() { + this.setElement(this.getTopLevelWidget().getDocumentElement().createElement(this.getTagName())); +} + +qx.Proto._modifyElement = function(propValue, propOldValue, propData) +{ + this._isCreated = qx.util.Validation.isValidElement(propValue); + + if (propOldValue) + { + // reset reference to widget instance + propOldValue.qx_Widget = null; + + // remove events + this._removeInlineEvents(propOldValue); + } + + if (propValue) + { + // add reference to widget instance + propValue.qx_Widget = this; + + // link element and style reference + this._element = propValue; + this._style = propValue.style; + + this._applyStyleProperties(propValue); + this._applyHtmlProperties(propValue); + this._applyHtmlAttributes(propValue); + this._applyElementData(propValue); + + // attach inline events + this._addInlineEvents(propValue); + + // send out create event + this.createDispatchEvent("create"); + } + else + { + this._element = this._style = null; + } + + return true; +} + + + + + + + +/* +--------------------------------------------------------------------------- + JOBS QUEUE +--------------------------------------------------------------------------- +*/ + +qx.Proto.addToJobQueue = function(p) +{ + if (this._hasParent) { + qx.ui.core.Widget.addToGlobalJobQueue(this); + } + + if (!this._jobQueue) { + this._jobQueue = {}; + } + + this._jobQueue[p] = true; + return true; +} + +qx.Proto._flushJobQueue = function(q) +{ + /* -------------------------------------------------------------------------------- + 1. Pre checks + -------------------------------------------------------------------------------- */ + + try + { + var vQueue = this._jobQueue; + var vParent = this.getParent(); + + if (!vParent || qx.lang.Object.isEmpty(vQueue)) { + return; + } + + var vLayoutImpl = this instanceof qx.ui.core.Parent ? this.getLayoutImpl() : null; + + if (vLayoutImpl) { + vLayoutImpl.updateSelfOnJobQueueFlush(vQueue); + } + } + catch(ex) + { + this.error("Flushing job queue (prechecks#1) failed", ex); + } + + + + + + /* -------------------------------------------------------------------------------- + 2. Recompute dimensions + -------------------------------------------------------------------------------- */ + + try + { + var vFlushParentJobQueue = false; + var vRecomputeOuterWidth = vQueue.marginLeft || vQueue.marginRight; + var vRecomputeOuterHeight = vQueue.marginTop || vQueue.marginBottom; + var vRecomputeInnerWidth = vQueue.frameWidth; + var vRecomputeInnerHeight = vQueue.frameHeight; + var vRecomputeParentPreferredInnerWidth = (vQueue.frameWidth || vQueue.preferredInnerWidth) && this._recomputePreferredBoxWidth(); + var vRecomputeParentPreferredInnerHeight = (vQueue.frameHeight || vQueue.preferredInnerHeight) && this._recomputePreferredBoxHeight(); + + if (vRecomputeParentPreferredInnerWidth) + { + var vPref = this.getPreferredBoxWidth(); + + if (this._computedWidthTypeAuto) + { + this._computedWidthValue = vPref; + vQueue.width = true; + } + + if (this._computedMinWidthTypeAuto) + { + this._computedMinWidthValue = vPref; + vQueue.minWidth = true; + } + + if (this._computedMaxWidthTypeAuto) + { + this._computedMaxWidthValue = vPref; + vQueue.maxWidth = true; + } + } + + if (vRecomputeParentPreferredInnerHeight) + { + var vPref = this.getPreferredBoxHeight(); + + if (this._computedHeightTypeAuto) + { + this._computedHeightValue = vPref; + vQueue.height = true; + } + + if (this._computedMinHeightTypeAuto) + { + this._computedMinHeightValue = vPref; + vQueue.minHeight = true; + } + + if (this._computedMaxHeightTypeAuto) + { + this._computedMaxHeightValue = vPref; + vQueue.maxHeight = true; + } + } + + if ((vQueue.width || vQueue.minWidth || vQueue.maxWidth || vQueue.left || vQueue.right) && this._recomputeBoxWidth()) { + vRecomputeOuterWidth = vRecomputeInnerWidth = true; + } + + if ((vQueue.height || vQueue.minHeight || vQueue.maxHeight || vQueue.top || vQueue.bottom) && this._recomputeBoxHeight()) { + vRecomputeOuterHeight = vRecomputeInnerHeight = true; + } + } + catch(ex) + { + this.error("Flushing job queue (recompute#2) failed", ex); + } + + + + + + /* -------------------------------------------------------------------------------- + 3. Signals to parent widgets + -------------------------------------------------------------------------------- */ + + try + { + if ((vRecomputeOuterWidth && this._recomputeOuterWidth()) || + vRecomputeParentPreferredInnerWidth) + { + vParent._invalidatePreferredInnerWidth(); + vParent.getLayoutImpl().updateSelfOnChildOuterWidthChange(this); + + vFlushParentJobQueue = true; + } + + if ((vRecomputeOuterHeight && this._recomputeOuterHeight()) || + vRecomputeParentPreferredInnerHeight) + { + vParent._invalidatePreferredInnerHeight(); + vParent.getLayoutImpl().updateSelfOnChildOuterHeightChange(this); + + vFlushParentJobQueue = true; + } + + if (vFlushParentJobQueue) { + vParent._flushJobQueue(); + } + } + catch(ex) + { + this.error("Flushing job queue (parentsignals#3) failed", ex); + } + + + + + + /* -------------------------------------------------------------------------------- + 4. Add layout jobs + -------------------------------------------------------------------------------- */ + + try + { + // add to layout queue + vParent._addChildToChildrenQueue(this); + + // convert jobs to layout jobs + for (var i in vQueue) { + this._layoutChanges[i] = true; + } + } + catch(ex) + { + this.error("Flushing job queue (addjobs#4) failed", ex); + } + + + + + + /* -------------------------------------------------------------------------------- + 5. Signals to children + -------------------------------------------------------------------------------- */ + + try + { + // inform children about padding change + if (this instanceof qx.ui.core.Parent && + (vQueue.paddingLeft || + vQueue.paddingRight || + vQueue.paddingTop || + vQueue.paddingBottom)) + { + var ch=this.getChildren(), chl=ch.length; + + if (vQueue.paddingLeft) { + for (var i=0; i= 0; +} + +qx.Proto.isFocusRoot = function() { + return false; +} + +qx.Proto.getFocusRoot = function() +{ + if(this._hasParent) { + return this.getParent().getFocusRoot(); + } + + return null; +} + +qx.Proto.getActiveChild = function() +{ + var vRoot = this.getFocusRoot(); + if (vRoot) { + return vRoot.getActiveChild(); + } + + return null; +} + +qx.Proto._ontabfocus = qx.util.Return.returnTrue; + +qx.Proto._modifyFocused = function(propValue, propOldValue, propData) +{ + if (!this.isCreated()) { + return true; + } + + var vFocusRoot = this.getFocusRoot(); + + // this.debug("Focused: " + propValue); + + if (vFocusRoot) + { + // may be undefined if this widget has been removed + if (propValue) + { + vFocusRoot.setFocusedChild(this); + this._visualizeFocus(); + } + else + { + if (vFocusRoot.getFocusedChild() == this) { + vFocusRoot.setFocusedChild(null); + } + + this._visualizeBlur(); + } + } + + return true; +} + +qx.Proto._visualizeBlur = function() +{ + // Force blur, even if mouseFocus is not active because we + // need to be sure that the previous focus rect gets removed. + // But this only needs to be done, if there is no new focused element. + if (this.getEnableElementFocus() && (!this.getFocusRoot().getFocusedChild() || (this.getFocusRoot().getFocusedChild() && this.getFocusRoot().getFocusedChild().getEnableElementFocus()))) + { + try { + this.getElement().blur(); + } catch(ex) {}; + } + + this.removeState("focused"); + return true; +} + +qx.Proto._visualizeFocus = function() +{ + //this.info("_visualizeFocus: " + qx.event.handler.FocusHandler.mouseFocus); + if (!qx.event.handler.FocusHandler.mouseFocus && this.getEnableElementFocus()) + { + try { + this.getElement().focus(); + } catch(ex) {}; + } + + this.addState("focused"); + return true; +} + +qx.Proto.focus = function() +{ + delete qx.event.handler.FocusHandler.mouseFocus; + this.setFocused(true); +} + +qx.Proto.blur = function() +{ + delete qx.event.handler.FocusHandler.mouseFocus; + this.setFocused(false); +} + + + + +/* +--------------------------------------------------------------------------- + CAPTURE +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyCapture = function(propValue, propOldValue, propData) +{ + var vMgr = qx.event.handler.EventHandler.getInstance(); + + if (propOldValue) + { + vMgr.setCaptureWidget(null); + } + else if (propValue) + { + vMgr.setCaptureWidget(this); + } + + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + ZINDEX +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyZIndex = function(propValue, propOldValue, propData) { + return this.setStyleProperty(propData.name, propValue); +} + + + + + + + +/* +--------------------------------------------------------------------------- + TAB INDEX +--------------------------------------------------------------------------- +*/ + +if (qx.sys.Client.getInstance().isMshtml()) +{ + qx.Proto._modifyTabIndex = function(propValue, propOldValue, propData) + { + if (propValue < 0 || !this.getEnabled()) { + this.setHtmlProperty("unselectable", + "on"); + } else { + this.removeHtmlProperty("unselectable"); + } + + this.setHtmlProperty("tabIndex", + propValue < 0 ? -1 : 1); + + return true; + } +} +else if (qx.sys.Client.getInstance().isGecko()) +{ + qx.Proto._modifyTabIndex = function(propValue, propOldValue, propData) + { + this.setStyleProperty("MozUserFocus", + (propValue < 0 + ? "ignore" + : "normal")); + + // be forward compatible (CSS 3 Draft) + this.setStyleProperty("userFocus", + (propValue < 0 + ? "ignore" + : "normal")); + + return true; + } +} +else +{ + qx.Proto._modifyTabIndex = function(propValue, propOldValue, propData) + { + // CSS 3 Draft + this.setStyleProperty("userFocus", + (propValue < 0 + ? "ignore" + : "normal")); + + // IE Backward Compatible + if (propValue < 0 || !this.getEnabled()) { + this.setHtmlProperty("unselectable", + "on"); + } else { + this.removeHtmlProperty("unselectable"); + } + + this.setHtmlProperty("tabIndex", + propValue < 0 ? -1 : 1); + + return true; + } +} + + + + + + +/* +--------------------------------------------------------------------------- + CSS CLASS NAME +--------------------------------------------------------------------------- +*/ + +qx.Proto.setCssClassName = function(propValue) { + this.setHtmlProperty("className", propValue); +} + +qx.Proto.getCssClassName = function() { + return this.getHtmlProperty("className"); +} + + + + + + + + +/* +--------------------------------------------------------------------------- + WIDGET FROM POINT +--------------------------------------------------------------------------- +*/ + +qx.Proto.getWidgetFromPoint = function(x, y) +{ + var ret = this.getWidgetFromPointHelper(x, y); + return ret && ret != this ? ret : null; +} + +qx.Proto.getWidgetFromPointHelper = function(x, y) { + return this; +} + + + + + + +/* +--------------------------------------------------------------------------- + CAN SELECT +--------------------------------------------------------------------------- +*/ + +if(qx.sys.Client.getInstance().isMshtml()) +{ + qx.Proto._modifySelectable = function(propValue, propOldValue, propData) + { + if (propValue) + { + return this.removeHtmlProperty("unselectable"); + } + else + { + return this.setHtmlProperty("unselectable", "on"); + } + } +} +else if(qx.sys.Client.getInstance().isGecko()) +{ + qx.Proto._modifySelectable = function(propValue, propOldValue, propData) + { + if (propValue) + { + this.removeStyleProperty("MozUserSelect"); + } + else + { + this.setStyleProperty("MozUserSelect", "none"); + } + + return true; + }; +} +else if (qx.sys.Client.getInstance().isOpera()) +{ + // No known method available for this client + qx.Proto._modifySelectable = function(propValue, propOldValue, propData) { + return true; + } +} +else if (qx.sys.Client.getInstance().isKhtml() || qx.sys.Client.getInstance().isWebkit()) +{ + qx.Proto._modifySelectable = function(propValue, propOldValue, propData) + { + // Be forward compatible and use both userSelect and KhtmlUserSelect + if (propValue) + { + this.removeStyleProperty("KhtmlUserSelect"); + } + else + { + this.setStyleProperty("KhtmlUserSelect", "none"); + } + + return true; + }; +} +else +{ + qx.Proto._modifySelectable = function(propValue, propOldValue, propData) + { + if (propValue) + { + return this.removeStyleProperty("userSelect"); + } + else + { + this.setStyleProperty("userSelect", "none"); + } + } +} + + + + + + +/* +--------------------------------------------------------------------------- + OPACITY +--------------------------------------------------------------------------- +*/ + +/*! +Sets the opacity for the widget. Any child widget inside the widget will also +become (semi-)transparent. The value should be a number between 0 and 1 +inclusive, where 1 means totally opaque and 0 invisible. +*/ +if(qx.sys.Client.getInstance().isMshtml()) +{ + qx.Proto._modifyOpacity = function(propValue, propOldValue, propData) + { + if(propValue == null || propValue >= 1 || propValue < 0) + { + this.removeStyleProperty("filter"); + } + else if (qx.util.Validation.isValidNumber(propValue)) + { + this.setStyleProperty("filter", + ("Alpha(Opacity=" + + Math.round(propValue * 100) + + ")")); + } + else + { + throw new Error("Unsupported opacity value: " + propValue); + } + + return true; + } +} +else +{ + qx.Proto._modifyOpacity = function(propValue, propOldValue, propData) + { + if(propValue == null || propValue > 1) + { + if (qx.sys.Client.getInstance().isGecko()) + { + this.removeStyleProperty("MozOpacity"); + } + else if (qx.sys.Client.getInstance().isKhtml()) + { + this.removeStyleProperty("KhtmlOpacity"); + } + + this.removeStyleProperty("opacity"); + } + else if (qx.util.Validation.isValidNumber(propValue)) + { + propValue = qx.lang.Number.limit(propValue, 0, 1); + + // should we omit gecko's flickering here + // and limit the max value to 0.99? + + if (qx.sys.Client.getInstance().isGecko()) + { + this.setStyleProperty("MozOpacity", propValue); + } + else if (qx.sys.Client.getInstance().isKhtml()) + { + this.setStyleProperty("KhtmlOpacity", propValue); + } + + this.setStyleProperty("opacity", propValue); + } + + return true; + } +} + + + + + + +/* +--------------------------------------------------------------------------- + CURSOR +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyCursor = function(propValue, propOldValue, propData) +{ + if (propValue) + { + if (propValue == "pointer" && + qx.sys.Client.getInstance().isMshtml()) { + this.setStyleProperty("cursor", + "hand"); + } else { + this.setStyleProperty("cursor", + propValue); + } + } + else + { + this.removeStyleProperty("cursor"); + } + + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + BACKGROUND IMAGE +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyBackgroundImage = function(propValue, propOldValue, propData) +{ + return qx.util.Validation.isValidString(propValue) ? + this.setStyleProperty("backgroundImage", + "url(" + + qx.manager.object.AliasManager.getInstance().resolvePath(propValue) + + ")") : + this.removeStyleProperty("backgroundImage"); +} + + + + + + +/* +--------------------------------------------------------------------------- + CLIPPING +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyClip = function(propValue, propOldValue, propData) { + return this._compileClipString(); +} + +qx.Proto._compileClipString = function() +{ + var vLeft = this.getClipLeft(); + var vTop = this.getClipTop(); + var vWidth = this.getClipWidth(); + var vHeight = this.getClipHeight(); + + var vRight, vBottom; + + if(vLeft == null) + { + vRight = (vWidth == null + ? "auto" + : vWidth + "px"); + vLeft = "auto"; + } + else + { + vRight = (vWidth == null + ? "auto" + : vLeft + vWidth + "px"); + vLeft = vLeft + "px"; + } + + if(vTop == null) + { + vBottom = (vHeight == null + ? "auto" + : vHeight + "px"); + vTop = "auto"; + } + else + { + vBottom = (vHeight == null + ? "auto" + : vTop + vHeight + "px"); + vTop = vTop + "px"; + } + + return this.setStyleProperty("clip", + ("rect(" + + vTop + + "," + + vRight + + "," + + vBottom + + "," + + vLeft + + ")")); +} + + + + + + +/* +--------------------------------------------------------------------------- + OVERFLOW +--------------------------------------------------------------------------- +*/ + +/* + This will measure the typical native scrollbar size in the environment +*/ +qx.ui.core.Widget.initOverflow = function() +{ + if (qx.ui.core.Widget.initOverflowDone) { + return; + } + + var t = document.createElement("div"); + var s = t.style; + + s.height = s.width = "100px"; + s.overflow = "scroll"; + + document.body.appendChild(t); + + var c = qx.dom.Dimension.getScrollBarSizeRight(t); + if (c) { + qx.ui.core.Widget.SCROLLBAR_SIZE = c; + } + + document.body.removeChild(t); + + qx.ui.core.Widget.initOverflowDone = true; +} + +if (qx.sys.Client.getInstance().isGecko()) +{ + qx.Proto._modifyOverflow = function(propValue, propOldValue, propData) + { + var pv = propValue; + var pn = propData.name; + + switch(pv) + { + case "hidden": + pv = "-moz-scrollbars-none"; + break; + + case "scrollX": + pv = "-moz-scrollbars-horizontal"; + break; + + case "scrollY": + pv = "-moz-scrollbars-vertical"; + break; + } + + return this._applyOverflow(pn, pv, propValue, propOldValue); + } +} + +// Mshtml conforms here to CSS3 Spec. Eventually there will be multiple +// browsers which support these new overflowX overflowY properties. +else if (qx.sys.Client.getInstance().isMshtml()) +{ + qx.Proto._modifyOverflow = function(propValue, propOldValue, propData) + { + var pv = propValue; + var pn = propData.name; + + switch(pv) + { + case "scrollX": + pn = "overflowX"; + pv = "scroll"; + break; + + case "scrollY": + pn = "overflowY"; + pv = "scroll"; + break; + } + + // Clear up concurrenting rules + var a = [ "overflow", + "overflowX", + "overflowY" ]; + for (var i=0; i= 0){ + this.setOpacity(this._computeFadeOpacity()); + this.getFadeTimer().restart(); + } else if(this.hasEventListeners(qx.ui.core.Widget.FADE_FINISHED)) { + this.createDispatchDataEvent(qx.ui.core.Widget.FADE_FINISHED, qx.ui.core.Widget.FADE_OUT); + }; + break; + }; + qx.ui.core.Widget.flushGlobalQueues(); +}; + +qx.Proto._modifyFadeSteps = function(propValue, propOldValue, propData) { + if(propValue < 1) return; + this.setFadeInterval(parseInt(this.getFadeTime() / propValue)); + this.setFadeUnit(Math.round(this.getFadeMax()/propValue)); + return true; +}; + +qx.Proto._modifyFadeTime = function(propValue, propOldValue, propData) { + if(propValue < 1) return; + this.setFadeInterval(parseInt(propValue / this.getFadeSteps())); + return true; +}; + +qx.Proto._modifyFadeUnit = function(propValue, propOldValue, propData) { + this.setFadeSteps(Math.round(this.getFadeMax()/propValue)); + return true; +}; + +qx.Proto._modifyFadeMax = function(propValue, propOldValue, propData) { + this.setFadeUnit(Math.round(propValue / this.getFadeSteps())); + return true; +}; + +qx.Proto._computeFadeOpacity = function() { + var op = this.getFadeUnit() * this.getFadeCounter() / 100; + return(op); +}; + + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ +qx.Proto.dispose = function() +{ + if(this.getDisposed()) { + return; + } + + var vElement = this.getElement(); + + if (vElement) + { + this._removeInlineEvents(vElement); + + delete this._isCreated; + + vElement.qx_Widget = null; + + this._element = null; + this._style = null; + } + + this._inlineEvents = null; + this._element = null; + this._style = null; + this._borderElement = null; + this._borderStyle = null; + this._oldParent = null; + + // should be enough to remove the hashTables + delete this._styleProperties; + delete this._htmlProperties; + delete this._htmlAttributes; + delete this._states; + + // remove queue content + for (var i in this._jobQueue) { + delete this._jobQueue[i]; + } + delete this._jobQueue; + + for (var i in this._layoutChanges) { + delete this._layoutChanges[i]; + } + delete this._layoutChanges; + + // dispose the fader + if(this._fadeTimer){ + this._fadeTimer.dispose(); + this._fadeTimer = null; + } + + return qx.core.Target.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/embed/Flash.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/embed/Flash.js new file mode 100644 index 0000000000..30f32319f2 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/embed/Flash.js @@ -0,0 +1,468 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +/*! + Original non qooxdoo Version by Geoff Stearns + Flash detection and embed - http://blog.deconcept.com/flashobject/ + FlashObject is (c) 2005 Geoff Stearns and is released under the MIT License + http://www.opensource.org/licenses/mit-license.php + + Modified for qooxdoo by Sebastian Werner + Based on version 1.2.3 + Relicensed under LGPL in assent of Geoff Stearns +*/ + +qx.OO.defineClass("qx.ui.embed.Flash", qx.ui.basic.Terminator, +function(vSource, vVersion) +{ + qx.ui.basic.Terminator.call(this); + + // Use background handling of qx.ui.core.Widget instead + this._params = {}; + this._variables = {}; + + if(qx.util.Validation.isValidString(vSource)) { + this.setSource(vSource); + } + + this.setVersion(qx.util.Validation.isValidString(vVersion) ? vVersion : qx.ui.embed.Flash.MINREQUIRED); +}); + +qx.OO.addProperty({ name : "source", type : "string" }); +qx.OO.addProperty({ name : "version" }); + +qx.OO.addProperty({ name : "enableExpressInstall", type : "boolean", defaultValue : false }); +qx.OO.addProperty({ name : "enableDetection", type : "boolean", defaultValue : true }); +qx.OO.addProperty({ name : "redirectUrl", type : "string" }); + +qx.OO.addProperty({ name : "quality", type : "string", impl : "param", defaultValue : "high", possibleValues : [ "low", "autolow", "autohigh", "medium", "high", "best" ] }); +qx.OO.addProperty({ name : "scale", type : "string", impl : "param", defaultValue : "showall", possibleValues : [ "showall", "noborder", "excactfit", "noscale" ] }); +qx.OO.addProperty({ name : "wmode", type : "string", impl : "param", defaultValue : "", possibleValues : [ "window", "opaque", "transparent" ] }); +qx.OO.addProperty({ name : "play", type : "boolean", impl : "param", defaultValue : true }); +qx.OO.addProperty({ name : "loop", type : "boolean", impl : "param", defaultValue : true }); +qx.OO.addProperty({ name : "menu", type : "boolean", impl : "param", defaultValue : true }); + +qx.ui.embed.Flash.EXPRESSINSTALL = [6,0,65]; +qx.ui.embed.Flash.MINREQUIRED = "1"; +qx.ui.embed.Flash.PLAYERVERSION = null; +qx.ui.embed.Flash.PLUGINKEY = "Shockwave Flash"; +qx.ui.embed.Flash.ACTIVEXKEY = "ShockwaveFlash.ShockwaveFlash"; + + + + + +/* +--------------------------------------------------------------------------- + PLAYER VERSION CACHE +--------------------------------------------------------------------------- +*/ + +qx.ui.embed.Flash.getPlayerVersion = function() +{ + if (qx.ui.embed.Flash.PLAYERVERSION != null) { + return qx.ui.embed.Flash.PLAYERVERSION; + } + + var vPlayerVersion = new qx.type.Version(0,0,0); + + if(navigator.plugins && navigator.mimeTypes.length) + { + var x = navigator.plugins[qx.ui.embed.Flash.PLUGINKEY]; + + if(x && x.description) { + vPlayerVersion = new qx.type.Version(x.description.replace(/([a-z]|[A-Z]|\s)+/, '').replace(/(\s+r|\s+b[0-9]+)/, '.')); + } + } + else if (window.ActiveXObject) + { + try { + var axo = new ActiveXObject(qx.ui.embed.Flash.ACTIVEXKEY); + vPlayerVersion = new qx.type.Version(axo.GetVariable("$version").split(" ")[1].split(",")); + } + catch (e) {} + } + + return qx.ui.embed.Flash.PLAYERVERSION = vPlayerVersion; +} + + + + + + +/* +--------------------------------------------------------------------------- + BASICS +--------------------------------------------------------------------------- +*/ + +qx.Proto._version = null; +qx.Proto._source = ""; + +qx.Proto._applyElementData = function(el) +{ + qx.ui.basic.Terminator.prototype._applyElementData.call(this, el); + + // Check for ExpressInstall + this._expressInstall = false; + + if (this.getEnableExpressInstall()) + { + // check to see if we need to do an express install + var expressInstallReqVer = new qx.type.Version(qx.ui.embed.Flash.EXPRESSINSTALL); + var installedVer = qx.ui.embed.Flash.getPlayerVersion(); + + if (installedVer.versionIsValid(expressInstallReqVer) && !installedVer.versionIsValid(this._version)) { + this._expressInstall = true; + } + } + + // this.debug("ExpressInstall Enabled: " + this._expressInstall); + + // Apply HTML + if(!this.getEnableDetection() || this._expressInstall || qx.ui.embed.Flash.getPlayerVersion().versionIsValid(this._version)) + { + el.innerHTML = this.generateHTML(); + } + else + { + var redir = this.getRedirectUrl(); + + if(redir != "") { + document.location.replace(redir); + } + } +} + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifySource = function(propValue, propOldValue, propName) +{ + this._source = qx.util.Validation.isValidString(propValue) ? qx.manager.object.AliasManager.getInstance().resolvePath(propValue) : ""; + return true; +} + +qx.Proto._modifyVersion = function(propValue, propOldValue, propData) +{ + if (this._version) + { + this._version.dispose(); + this._version = null; + } + + if (qx.util.Validation.isValidString(propValue)) { + this._version = new qx.type.Version(propValue); + } + + return true; +} + +qx.Proto._modifyParam = function(propValue, propOldValue, propData) +{ + this.setParam(propData.name, propValue.toString()); + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + OVERWRITE BACKGROUND COLOR HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyBackgroundColor = function(propValue, propOldValue, propData) +{ + if (propOldValue) { + propOldValue.remove(this); + } + + if (propValue) + { + this._applyBackgroundColor(propValue.getHex()); + propValue.add(this); + } + else + { + this._resetBackgroundColor(); + } + + return true; +} + +qx.Proto._applyBackgroundColor = function(vNewValue) { + this.setParam("bgcolor", vNewValue); +} + + + + +/* +--------------------------------------------------------------------------- + PARAMS +--------------------------------------------------------------------------- +*/ + +qx.Proto.setParam = function(name, value){ + this._params[name] = value; +} + +qx.Proto.getParam = function(name){ + return this._params[name]; +} + +qx.Proto.getParams = function() { + return this._params; +} + + + + + +/* +--------------------------------------------------------------------------- + VARIABLES +--------------------------------------------------------------------------- +*/ + +qx.Proto.setVariable = function(name, value){ + this._variables[name] = value; +} + +qx.Proto.getVariable = function(name){ + return this._variables[name]; +} + +qx.Proto.getVariables = function(){ + return this._variables; +} + + + + + +/* +--------------------------------------------------------------------------- + HTML UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.generateParamTags = function() +{ + var vParams = this.getParams(); + var vParamTags = []; + + for (var vKey in vParams) + { + vParamTags.push(""); + } + + return vParamTags.join(""); +} + +qx.Proto.getVariablePairs = function() +{ + var variables = this.getVariables(); + var variablePairs = []; + + for (var key in variables) { + variablePairs.push(key + "=" + variables[key]); + } + + return variablePairs.join("&"); +} + + + + + + +/* +--------------------------------------------------------------------------- + HTML GENERATOR +--------------------------------------------------------------------------- +*/ + +// Netscape Plugin Architecture +if (navigator.plugins && navigator.mimeTypes && navigator.mimeTypes.length) +{ + qx.Proto.generateHTML = function() + { + var html = []; + + // Express Install Handling + if (this._expressInstall) + { + document.title = document.title.slice(0, 47) + ' - Flash Player Installation'; + + this.addVariable('MMredirectURL', escape(window.location)); + this.addVariable('MMdoctitle', document.title); + this.addVariable('MMplayerType', 'PlugIn'); + } + + html.push(" 0) + { + html.push(" "); + html.push("flashvars"); + html.push("="); + html.push("'"); + html.push(pairs); + html.push("'"); + } + + html.push(">"); + + return html.join(""); + } +} + +// Internet Explorer ActiveX Architecture +else +{ + qx.Proto.generateHTML = function() + { + var html = []; + + // Express Install Handling + if (this._expressInstall) + { + document.title = document.title.slice(0, 47) + ' - Flash Player Installation'; + + this.addVariable("MMredirectURL", escape(window.location)); + this.addVariable("MMdoctitle", document.title); + this.addVariable("MMplayerType", "ActiveX"); + } + + html.push(""); + html.push(""); + + var tags = this.generateParamTags(); + + if(tags.length > 0) { + html.push(tags); + } + + var pairs = this.getVariablePairs(); + + if(pairs.length > 0) + { + html.push(""); + } + + html.push(""); + + return html.join(""); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + METHODS TO GIVE THE LAYOUTERS INFORMATIONS +--------------------------------------------------------------------------- +*/ + +qx.Proto._isWidthEssential = qx.util.Return.returnTrue; +qx.Proto._isHeightEssential = qx.util.Return.returnTrue; + + + + +/* +--------------------------------------------------------------------------- + PREFERRED DIMENSIONS +--------------------------------------------------------------------------- +*/ + +qx.Proto._computePreferredInnerWidth = qx.util.Return.returnZero; +qx.Proto._computePreferredInnerHeight = qx.util.Return.returnZero; + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + delete this._source; + delete this._params; + delete this._variables; + + if (this._version) + { + this._version.dispose(); + this._version = null; + } + + qx.ui.basic.Terminator.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/embed/Gallery.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/embed/Gallery.js new file mode 100644 index 0000000000..11a40e9046 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/embed/Gallery.js @@ -0,0 +1,556 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +/** + * @event beforeToolTipAppear {qx.event.type.Event} + * @event loadComplete {qx.event.type.Event} + */ +qx.OO.defineClass("qx.ui.embed.Gallery", qx.ui.basic.Terminator, +function(vGalleryList) +{ + qx.ui.basic.Terminator.call(this); + + this._blank = qx.manager.object.AliasManager.getInstance().resolvePath("static/image/blank.gif"); + this._list = vGalleryList; + this._listSize = vGalleryList.length; + this._processedImages = 0; + + this.setOverflow("auto"); + + this.setHtmlProperty("className", "qx_ui_embed_Gallery"); + + this._manager = new qx.manager.selection.DomSelectionManager(this); + + this._manager.setMultiColumnSupport(true); + + this.addEventListener("mousedown", this._onmousedown); + this.addEventListener("mouseup", this._onmouseup); + this.addEventListener("mousemove", this._onmousemove); + + this.addEventListener("click", this._onclick); + this.addEventListener("dblclick", this._ondblclick); + + this.addEventListener("keypress", this._onkeypress); +}); + + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.addProperty({ name : "thumbMaxWidth", type : "number", defaultValue : 100 }); +qx.OO.addProperty({ name : "thumbMaxHeight", type : "number", defaultValue : 100 }); +qx.OO.addProperty({ name : "decorHeight", type : "number", defaultValue : 40 }); +qx.OO.addProperty({ name : "showTitle", type : "boolean", defaultValue : true }); +qx.OO.addProperty({ name : "showComment", type : "boolean", defaultValue : true }); + + + + + + +/* +--------------------------------------------------------------------------- + ELEMENT HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._applyElementData = function() { + this.getElement().appendChild(this.createView()); +} + + + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getManager = function() { + return this._manager; +} + +qx.Proto.getList = function() { + return this._list; +} + +qx.Proto.update = function(vGalleryList) +{ + this._manager.deselectAll(); + + this._list = vGalleryList; + + var el = this.getElement(); + el.replaceChild(this.createView(), el.firstChild); +} + +qx.Proto.removeAll = function() +{ + this._manager.deselectAll(); + this.getElement().innerHTML = ""; +} + +qx.Proto.updateImageById = function(vId, vSrc, vWidth, vHeight) { + this.updateImageSrcById(vId, vSrc); + this.updateImageDimensionsById(vId, vWidth, vHeight); +} + +qx.Proto.updateImageDimensionsById = function(vId, vWidth, vHeight) { + this.updateImageDimensionsByPosition(this.getPositionById(vId), vWidth, vHeight); +} + +qx.Proto.updateImageDimensionsByPosition = function(vPos, vWidth, vHeight) { + // TBD: compare dimensions with max. thumb size and scale proportionally if necessary + if (vPos == -1) { + throw new Error("No valid Position: " + vPos); + } + + var cnode = this.getNodeByPosition(vPos).getElementsByTagName("img")[0]; + + cnode.width = vWidth; + cnode.height = vHeight; + + cnode.style.marginLeft = cnode.style.marginRight = Math.floor((this.getThumbMaxWidth()-vWidth)/2) + "px"; + cnode.style.marginTop = cnode.style.marginBottom = Math.floor((this.getThumbMaxHeight()-vHeight)/2) + "px"; + + this._list[vPos].thumbWidth = vWidth; + this._list[vPos].thumbHeight = vHeight; +} + +qx.Proto.updateImageSrcById = function(vId, vSrc) { + this.updateImageSrcByPosition(this.getPositionById(vId), vSrc); +} + +qx.Proto.updateImageSrcByPosition = function(vPos, vSrc) +{ + if (vPos == -1) { + throw new Error("No valid Position: " + vPos); + } + + var vNode = this.getNodeByPosition(vPos); + + vNode.getElementsByTagName("img")[0].src = vSrc; + this._list[vPos].src = vSrc; +} + +qx.Proto.deleteById = function(vId) { + this.deleteByPosition(this.getPositionById(vId)); +} + +qx.Proto.deleteByPosition = function(vPos) +{ + this._manager.deselectAll(); + + if (vPos == -1) { + throw new Error("No valid Position: " + vPos); + } + + var vNode = this.getNodeByPosition(vPos); + + if (vNode) { + vNode.parentNode.removeChild(vNode); + } + + this._list.splice(vPos, 1); +} + +qx.Proto.getPositionById = function(vId) +{ + for (var i=0, a=this._list, l=a.length; i"); + } + + if (qx.util.Validation.isValidString(this.getHtml())) { + vHtml.push(this.getHtml()); + } + + this.getElement().innerHTML = vHtml.join(""); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/embed/Iframe.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/embed/Iframe.js new file mode 100644 index 0000000000..ef10aa2730 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/embed/Iframe.js @@ -0,0 +1,430 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +/** + * @event load {qx.event.type.Event} + */ +qx.OO.defineClass("qx.ui.embed.Iframe", qx.ui.basic.Terminator, +function(vSource) +{ + // ********************************************************************** + // INIT + // ********************************************************************** + qx.ui.basic.Terminator.call(this); + + this.setSelectable(false); + this.setTabIndex(0); + + var o = this; + this.__onreadystatechange = function(e) { return o._onreadystatechange(e); } + this.__onload = function(e) { return o._onload(e); } + + if (qx.util.Validation.isValid(vSource)) { + this.setSource(vSource); + } +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "iframe" }); + + + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.addProperty({ name : "source", type : "string" }); + +qx.OO.addProperty({ name : "frameName", type : "string" }); + + + + + + +/* +--------------------------------------------------------------------------- + INTERNAL PROPERTIES +--------------------------------------------------------------------------- +*/ + + +// iframe DOM node + +qx.Proto._iframeNode = null; + +qx.Proto.getIframeNode = function() { + return this._iframeNode; +} + +qx.Proto.setIframeNode = function(vIframeNode) { + return this._iframeNode = vIframeNode; +} + + +// blocker div DOM node + +qx.Proto._blockerNode = null; + +qx.Proto.getBlockerNode = function() { + return this._blockerNode; +} + +qx.Proto.setBlockerNode = function(vBlockerNode) { + return this._blockerNode = vBlockerNode; +} + + + + +/* +--------------------------------------------------------------------------- + METHODS +--------------------------------------------------------------------------- +*/ + +qx.Proto.reload = function() { + this._applySource(); +} + + +qx.Proto.block = function() +{ + if (this._blockerNode) { + this._blockerNode.style.display = ""; + } +}; + +qx.Proto.release = function() +{ + if (this._blockerNode) { + this._blockerNode.style.display = "none"; + } +}; + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyElement = function(propValue, propOldValue, propData) +{ + + var iframeNode = this.getIframeNode(); + + if (!iframeNode) + { + + qx.ui.embed.Iframe.initIframe(this.getFrameName()); + + // clone proto element and assign iframe + iframeNode = this.setIframeNode(qx.ui.embed.Iframe._element.cloneNode(true)); + + qx.ui.embed.Iframe.initBlocker(); + + // clone proto blocker + blockerNode = this.setBlockerNode(qx.ui.embed.Iframe._blocker.cloneNode(true)); + + if (qx.sys.Client.getInstance().isMshtml()) { + iframeNode.onreadystatechange = this.__onreadystatechange; + } else { + iframeNode.onload = this.__onload; + } + } + + this._applySource(); + + propValue.appendChild(iframeNode); + propValue.appendChild(blockerNode); + + // create basic widget + qx.ui.basic.Terminator.prototype._modifyElement.call(this, propValue, propOldValue, propData); + + return true; +} + + +qx.Proto._beforeAppear = function() { + qx.ui.basic.Terminator.prototype._beforeAppear.call(this); + + // register to iframe manager as active widget + qx.manager.object.IframeManager.getInstance().add(this); +}; + + +qx.Proto._beforeDisappear = function() { + qx.ui.basic.Terminator.prototype._beforeDisappear.call(this); + + // deregister from iframe manager + qx.manager.object.IframeManager.getInstance().remove(this); +}; + + +qx.Proto._modifySource = function(propValue, propOldValue, propData) +{ + if(this.isCreated()) { + this._applySource(); + } + + return true; +} + +qx.Proto._applySource = function() +{ + var currentSource = this.getSource(); + + if (qx.util.Validation.isInvalidString(currentSource)) { + currentSource = qx.manager.object.AliasManager.getInstance().resolvePath("static/image/blank.gif"); + } + + this._isLoaded = false; + this.getIframeNode().src = currentSource; +} + +qx.Proto._modifyFrameName = function (propValue, propOldValue, propName, uniqModIds) +{ + if( this.isCreated()) { + throw new Error("Not allowed to set frame name after it has been created"); + } + + return true; +} + + + + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onreadystatechange = function() +{ + if (this.getIframeNode().readyState == "complete") { + this.dispatchEvent(new qx.event.type.Event("load"), true); + } +} + +qx.Proto._onload = function() +{ + this._isLoaded = true; + this.dispatchEvent(new qx.event.type.Event("load"), true); +} + + + + + + +/* +--------------------------------------------------------------------------- + WINDOW & DOCUMENT ACCESS +--------------------------------------------------------------------------- +*/ + +if (qx.sys.Client.getInstance().isMshtml()) +{ + qx.Proto.getContentWindow = function() + { + if (this.isCreated()) { + try { return this.getIframeNode().contentWindow; } + catch (ex) {} + } + + return null; + } + + qx.Proto.getContentDocument = function() + { + var win = this.getContentWindow(); + if (win) { + try { return win.document; } + catch (ex) {} + } + + return null; + } +} +else +{ + qx.Proto.getContentWindow = function() + { + var doc = this.getContentDocument(); + return doc ? doc.defaultView : null; + } + + qx.Proto.getContentDocument = function() + { + if (this.isCreated()) { + try { return this.getIframeNode().contentDocument; } + catch (ex) {} + } + + return null; + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + LOAD STATUS +--------------------------------------------------------------------------- +*/ + +qx.Proto._isLoaded = false; + +if (qx.sys.Client.getInstance().isMshtml()) +{ + qx.Proto.isLoaded = function() + { + var doc = this.getContentDocument(); + return doc ? doc.readyState == "complete" : false; + } +} +else +{ + qx.Proto.isLoaded = function() + { + return this._isLoaded; + } +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSE +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + this.__onreadystatechange = this.__onload = null; + + if (this._iframeNode) + { + this._iframeNode.onreadystatechange = null; + this._iframeNode.onload = null; + + this._iframeNode = null; + } + + qx.ui.basic.Terminator.prototype.dispose.call(this); +} + + + + + + +/* +--------------------------------------------------------------------------- + INIT +--------------------------------------------------------------------------- +*/ +qx.ui.embed.Iframe.initIframe = function(vFrameName) +{ + if (qx.ui.embed.Iframe._element && !vFrameName) { + return; + } + + if (vFrameName && qx.sys.Client.getInstance().isMshtml()) { + var f = qx.ui.embed.Iframe._element = document.createElement(''); + } else { + var f = qx.ui.embed.Iframe._element = document.createElement("iframe"); + if (vFrameName) { + f.name = vFrameName; + } + } + + f.frameBorder = "0"; + f.frameSpacing = "0"; + + f.marginWidth = "0"; + f.marginHeight = "0"; + + f.width = "100%"; + f.height = "100%"; + + f.hspace = "0"; + f.vspace = "0"; + + f.border = "0"; + f.scrolling = "auto"; + f.unselectable = "on"; + f.allowTransparency = "true"; + + f.style.position = "absolute"; + f.style.top = 0; + f.style.left = 0; + }; + +qx.ui.embed.Iframe.initBlocker = function() +{ + + if (qx.ui.embed.Iframe._blocker) { + return; + } + + var b = qx.ui.embed.Iframe._blocker = document.createElement("div"); + + if (qx.sys.Client.getInstance().isMshtml()) { + b.style.backgroundImage = "url(" + qx.manager.object.AliasManager.getInstance().resolvePath("static/image/blank.gif") + ")"; + } + + b.style.position = "absolute"; + b.style.top = 0; + b.style.left = 0; + b.style.width = "100%"; + b.style.height = "100%"; + b.style.zIndex = 1; + b.style.display = "none"; +}; + + diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/embed/LinkEmbed.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/embed/LinkEmbed.js new file mode 100644 index 0000000000..97bf2a0965 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/embed/LinkEmbed.js @@ -0,0 +1,88 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.embed.LinkEmbed", qx.ui.embed.HtmlEmbed, +function(vHtml, vUri, vTarget) +{ + qx.ui.embed.HtmlEmbed.call(this, vHtml); + + if (typeof vUri != "undefined") { + this.setUri(vUri); + } + + if (typeof vTarget != "undefined") { + this.setTarget(vTarget); + } +}); + + + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + Any valid html URI +*/ +qx.OO.addProperty({ name : "uri", type : "string", defaultValue : "#", impl : "html" }); + +/*! + Any valid html target +*/ +qx.OO.addProperty({ name : "target", type : "string", defaultValue : "_blank", impl : "html" }); + + + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.ui.embed.LinkEmbed.LINK_START = ""; +qx.ui.embed.LinkEmbed.LINK_STOP = ""; + +qx.Proto._syncHtml = function() +{ + var vHtml = []; + + vHtml.push(qx.ui.embed.LinkEmbed.LINK_START); + vHtml.push(this.getTarget()); + vHtml.push(qx.ui.embed.LinkEmbed.HREF_START); + vHtml.push(this.getUri()); + vHtml.push(qx.ui.embed.LinkEmbed.HREF_STOP); + vHtml.push(this.getHtml()); + vHtml.push(qx.ui.embed.LinkEmbed.LINK_STOP); + + this.getElement().innerHTML = vHtml.join(""); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/embed/NodeEmbed.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/embed/NodeEmbed.js new file mode 100644 index 0000000000..e5e9fd0d91 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/embed/NodeEmbed.js @@ -0,0 +1,48 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_basic) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.embed.NodeEmbed", qx.ui.basic.Terminator, +function(vId) +{ + qx.ui.basic.Terminator.call(this); + + if (qx.util.Validation.isValidString(vId)) { + this.setSourceNodeId(vId); + } +}); + +qx.OO.addProperty({ name : "sourceNodeId", type : "string" }); + +qx.Proto._createElementImpl = function() +{ + var vNode = document.getElementById(this.getSourceNodeId()); + + if (!vNode) { + throw new Error("Could not find source node with ID: " + this.getSourceNodeId()); + } + + vNode.style.display = ""; + + return this.setElement(vNode); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/embed/TextEmbed.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/embed/TextEmbed.js new file mode 100644 index 0000000000..d702eef789 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/embed/TextEmbed.js @@ -0,0 +1,121 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_basic) +#require(qx.renderer.font.FontCache) +#after(qx.renderer.font.FontObject) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.embed.TextEmbed", qx.ui.basic.Terminator, +function(vText) +{ + qx.ui.basic.Terminator.call(this); + + if (qx.util.Validation.isValidString(vText)) { + this.setText(vText); + } +}); + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + Any text string which can contain TEXT, too +*/ +qx.OO.addProperty({ name : "text", type : "string" }); + +/*! + The font property describes how to paint the font on the widget. +*/ +qx.OO.addProperty({ name : "font", type : "object", instance : "qx.renderer.font.Font", convert : qx.renderer.font.FontCache, allowMultipleArguments : true }); + +/*! + Wrap the text? +*/ +qx.OO.addProperty({ name : "wrap", type : "boolean", defaultValue : true }); + +/** The horizontal alignment of the text. */ +qx.OO.addProperty({ name : "textAlign", type : "string", defaultValue : "left", possibleValues : [ "left", "center", "right", "justify" ], allowNull : false }); + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyText = function() +{ + if (this._isCreated) { + this._syncText(); + } + + return true; +} + +qx.Proto._modifyFont = function(propValue, propOldValue, propData) +{ + if (propValue) { + propValue._applyWidget(this); + } else if (propOldValue) { + propOldValue._resetWidget(this); + } + + return true; +} + +qx.Proto._modifyWrap = function(propValue, propOldValue, propData) +{ + this.setStyleProperty("whiteSpace", propValue ? "normal" : "nowrap"); + return true; +} + +// property modifier +qx.Proto._modifyTextAlign = function(propValue, propOldValue, propData) { + this.setStyleProperty("textAlign", propValue); + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + ELEMENT HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._applyElementData = function() { + this.getElement().appendChild(document.createTextNode(this.getText())); +} + +qx.Proto._syncText = function() { + this.getElement().firstChild.nodeValue = this.getText(); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/Button.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/Button.js new file mode 100644 index 0000000000..29412a39d8 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/Button.js @@ -0,0 +1,200 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_form) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.form.Button", qx.ui.basic.Atom, +function(vText, vIcon, vIconWidth, vIconHeight, vFlash) +{ + // ************************************************************************ + // INIT + // ************************************************************************ + qx.ui.basic.Atom.call(this, vText, vIcon, vIconWidth, vIconHeight, vFlash); + + // Make focusable + this.setTabIndex(1); + + + // ************************************************************************ + // MOUSE EVENTS + // ************************************************************************ + this.addEventListener("mouseover", this._onmouseover); + this.addEventListener("mouseout", this._onmouseout); + this.addEventListener("mousedown", this._onmousedown); + this.addEventListener("mouseup", this._onmouseup); + + + // ************************************************************************ + // KEY EVENTS + // ************************************************************************ + this.addEventListener("keydown", this._onkeydown); + this.addEventListener("keyup", this._onkeyup); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "button" }); + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmouseover = function(e) +{ + if (e.getTarget() != this) { + return; + } + + if (this.hasState("abandoned")) + { + this.removeState("abandoned"); + this.addState("pressed"); + } + + this.addState("over"); +} + +qx.Proto._onmouseout = function(e) +{ + if (e.getTarget() != this) { + return; + } + + this.removeState("over"); + + if (this.hasState("pressed")) + { + // Activate capturing if the button get a mouseout while + // the button is pressed. + this.setCapture(true); + + this.removeState("pressed"); + this.addState("abandoned"); + } +} + +qx.Proto._onmousedown = function(e) +{ + if (e.getTarget() != this || !e.isLeftButtonPressed()) { + return; + } + + this.removeState("abandoned"); + this.addState("pressed"); +} + +qx.Proto._onmouseup = function(e) +{ + this.setCapture(false); + + // We must remove the states before executing the command + // because in cases were the window lost the focus while + // executing we get the capture phase back (mouseout). + var hasPressed = this.hasState("pressed"); + var hasAbandoned = this.hasState("abandoned"); + + if (hasPressed) { + this.removeState("pressed"); + } + + if (hasAbandoned) { + this.removeState("abandoned"); + } + + if (!hasAbandoned) + { + this.addState("over"); + + if (hasPressed) { + this.execute(); + } + } +} + +qx.Proto._onkeydown = function(e) +{ + switch(e.getKeyIdentifier()) + { + case "Enter": + case "Space": + this.removeState("abandoned"); + this.addState("pressed"); + } +} + +qx.Proto._onkeyup = function(e) +{ + switch(e.getKeyIdentifier()) + { + case "Enter": + case "Space": + if (this.hasState("pressed")) + { + this.removeState("abandoned"); + this.removeState("pressed"); + this.execute(); + } + } +} + + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + // ************************************************************************ + // MOUSE EVENTS + // ************************************************************************ + this.removeEventListener("mouseover", this._onmouseover, this); + this.removeEventListener("mouseout", this._onmouseout, this); + this.removeEventListener("mousedown", this._onmousedown, this); + this.removeEventListener("mouseup", this._onmouseup, this); + + + // ************************************************************************ + // KEY EVENTS + // ************************************************************************ + this.removeEventListener("keydown", this._onkeydown, this); + this.removeEventListener("keyup", this._onkeyup, this); + + + // ************************************************************************ + // SUPER CLASS + // ************************************************************************ + return qx.ui.basic.Atom.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/CheckBox.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/CheckBox.js new file mode 100644 index 0000000000..6e414bf30f --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/CheckBox.js @@ -0,0 +1,210 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_form) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.form.CheckBox", qx.ui.basic.Atom, +function(vText, vValue, vName, vChecked) +{ + qx.ui.basic.Atom.call(this, vText); + + this.setTabIndex(1); + this.setPadding(2, 3); + + this._createIcon(); + + if (qx.util.Validation.isValidString(vValue)) { + this.setValue(vValue); + } + + if (qx.util.Validation.isValidString(vName)) { + this.setName(vName); + } + + if (qx.util.Validation.isValidBoolean(vChecked)) { + this.setChecked(vChecked); + } else { + this.setChecked(false); + } + + this.addEventListener("click", this._onclick); + this.addEventListener("keydown", this._onkeydown); + this.addEventListener("keyup", this._onkeyup); +}); + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.OO.removeProperty({ name : "icon" }); +qx.OO.removeProperty({ name : "disabledIcon" }); + +/*! + The HTML name of the form element used by the widget +*/ +qx.OO.addProperty({ name : "name", type : "string" }); + +/*! + The HTML value of the form element used by the widget +*/ +qx.OO.addProperty({ name : "value", type : "string" }); + +/*! + If the widget is checked +*/ +qx.OO.addProperty({ name : "checked", type : "boolean", getAlias : "isChecked" }); + + + + + +/* +--------------------------------------------------------------------------- + ICON HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto.INPUT_TYPE = "checkbox"; + +qx.Proto._createIcon = function() +{ + var i = this._iconObject = new qx.ui.form.InputCheckSymbol; + + i.setType(this.INPUT_TYPE); + i.setChecked(this.isChecked()); + i.setEnabled(this.isEnabled()); + i.setAnonymous(true); + + this.addAtBegin(i); +} + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyChecked = function(propValue, propOldValue, propData) +{ + if (this._iconObject) { + this._iconObject.setChecked(propValue); + } + + return true; +} + +qx.Proto._modifyEnabled = function(propValue, propOldValue, propData) +{ + if (this._iconObject) { + this._iconObject.setEnabled(propValue); + } + + return qx.ui.basic.Atom.prototype._modifyEnabled.call(this, propValue, propOldValue, propData); +} + + + + +/* +--------------------------------------------------------------------------- + HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._handleIcon = function() +{ + switch(this.getShow()) + { + case qx.ui.basic.Atom.SHOW_ICON: + case qx.ui.basic.Atom.SHOW_BOTH: + this._iconIsVisible = true; + break; + + default: + this._iconIsVisible = false; + } + + if (this._iconIsVisible) + { + this._iconObject ? this._iconObject.setDisplay(true) : this._createIcon(); + } + else if (this._iconObject) + { + this._iconObject.setDisplay(false); + } +} + + + + +/* +--------------------------------------------------------------------------- + EVENT-HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onclick = function(e) { + this.toggleChecked(); +}; + + +qx.Proto._onkeydown = function(e) +{ + if(e.getKeyIdentifier() == "Enter" && !e.getAltKey()) { + this.toggleChecked(); + } +}; + + +qx.Proto._onkeyup = function(e) +{ + if(e.getKeyIdentifier() == "Space") { + this.toggleChecked(); + } +}; + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if(this.getDisposed()) { + return; + } + + this.removeEventListener("click", this._onclick); + this.removeEventListener("keydown", this._onkeydown); + this.removeEventListener("keyup", this._onkeyup); + + return qx.ui.basic.Atom.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/ComboBox.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/ComboBox.js new file mode 100644 index 0000000000..ad73ccbf1c --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/ComboBox.js @@ -0,0 +1,826 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_form) + +************************************************************************ */ + +/** + * A combo-box for qooxdoo. + * + * The major additional feature compared to typical select fields is that it allows + * it to be editable. Also images are supported inside the popup list. + * + * Features: + *
    + *
  • Editable text field
  • + *
  • Complete key-navigation
  • + *
  • Images inside the list
  • + *
  • Images and text inside the list
  • + *
+ * + * @event beforeInitialOpen {qx.event.type.Event} + */ +qx.OO.defineClass("qx.ui.form.ComboBox", qx.ui.layout.HorizontalBoxLayout, +function() +{ + qx.ui.layout.HorizontalBoxLayout.call(this); + + + // ************************************************************************ + // LIST + // ************************************************************************ + var l = this._list = new qx.ui.form.List; + + l.setAppearance("combo-box-list"); + + + // ************************************************************************ + // MANAGER + // ************************************************************************ + var m = this._manager = this._list.getManager(); + + m.setMultiSelection(false); + m.setDragSelection(false); + + + // ************************************************************************ + // POPUP + // ************************************************************************ + var p = this._popup = new qx.ui.popup.Popup; + + p.setAppearance("combo-box-popup"); + p.setAutoHide(false); + + p.add(l); + + + // ************************************************************************ + // TEXTFIELD + // ************************************************************************ + var f = this._field = new qx.ui.form.TextField; + + f.setAppearance("combo-box-text-field"); + f.setTabIndex(-1); + + this.add(f); + + + // ************************************************************************ + // BUTTON + // ************************************************************************ + + // Use qx.ui.basic.Atom instead of qx.ui.form.Button here to omit the registration + // of the unneeded and complex button events. + var b = this._button = new qx.ui.basic.Atom(null, "widget/arrows/down.gif"); + + b.setAppearance("combo-box-button"); + b.setTabIndex(-1); + + this.add(b); + + + // ************************************************************************ + // BEHAVIOR + // ************************************************************************ + this.setTabIndex(1); + this.setEditable(false); + + + // ************************************************************************ + // WIDGET MOUSE EVENTS + // ************************************************************************ + this.addEventListener("mousedown", this._onmousedown); + this.addEventListener("mouseup", this._onmouseup); + this.addEventListener("mouseover", this._onmouseover); + this.addEventListener("mousewheel", this._onmousewheel); + + + // ************************************************************************ + // WIDGET KEY EVENTS + // ************************************************************************ + this.addEventListener("keydown", this._onkeydown); + this.addEventListener("keypress", this._onkeypress); + this.addEventListener("keyinput", this._onkeyinput); + + + // ************************************************************************ + // WIDGET STATE EVENTS + // ************************************************************************ + this.addEventListener("beforeDisappear", this._onbeforedisappear); + + + // ************************************************************************ + // CHILDREN EVENTS + // ************************************************************************ + this._popup.addEventListener("appear", this._onpopupappear, this); + this._field.addEventListener("input", this._oninput, this); + + + // ************************************************************************ + // DOCUMENT EVENTS + // ************************************************************************ + var vDoc = qx.ui.core.ClientDocument.getInstance(); + vDoc.addEventListener("windowblur", this._onwindowblur, this); + + + // ************************************************************************ + // REMAPPING + // ************************************************************************ + this.remapChildrenHandlingTo(l); +}); + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "combo-box" }); + +qx.OO.addProperty({ name: "editable", type: "boolean", getAlias: "isEditable" }); +qx.OO.addProperty({ name: "selected", type: "object", instance : "qx.ui.form.ListItem" }); +qx.OO.addProperty({ name: "value", type : "string" }); +qx.OO.addProperty({ name: "pagingInterval", type: "number", defaultValue: 10 }); + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getManager = function() { + return this._manager; +} + +qx.Proto.getPopup = function() { + return this._popup; +} + +qx.Proto.getList = function() { + return this._list; +} + +qx.Proto.getField = function() { + return this._field; +} + +qx.Proto.getButton = function() { + return this._button; +} + + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifySelected = function(propValue, propOldValue, propData) +{ + this._fromSelected = true; + + // only do this if we called setSelected seperatly + // and not from the property "value". + if (!this._fromValue) { + this.setValue(propValue ? propValue.getLabel() : ""); + } + + // reset manager cache + this._manager.setLeadItem(propValue); + this._manager.setAnchorItem(propValue); + + // sync to manager + if (propValue) + { + this._manager.setSelectedItem(propValue); + } + else + { + this._manager.deselectAll(); + } + + // reset hint + delete this._fromSelected; + + return true; +} + +qx.Proto._modifyValue = function(propValue, propOldValue, propData) +{ + this._fromValue = true; + + // only do this if we called setValue seperatly + // and not from the event "input". + if (!this._fromInput) + { + if (this._field.getValue() == propValue) { + this._field.forceValue(null); + } + + this._field.setValue(propValue); + } + + // only do this if we called setValue seperatly + // and not from the property "selected". + if (!this._fromSelected) + { + // inform selected property + var vSelItem = this._list.findStringExact(propValue); + + // ignore disabled items + if (vSelItem != null && !vSelItem.getEnabled()) { + vSelItem = null; + } + + this.setSelected(vSelItem); + } + + // reset hint + delete this._fromValue; + + return true; +} + +qx.Proto._modifyEditable = function(propValue, propOldValue, propData) +{ + var f = this._field; + + f.setReadOnly(!propValue); + f.setCursor(propValue ? null : "default"); + f.setSelectable(propValue); + + return true; +} + +qx.Proto._modifyEnabled = function(propValue, propOldValue, propData) +{ + if (this._button) { + this._button.setEnabled(propValue); + } + + if (this._field) { + this._field.setEnabled(propValue); + } + + return qx.ui.layout.HorizontalBoxLayout.prototype._modifyEnabled.call(this, propValue, propOldValue, propData); +} + + + + + +/* +--------------------------------------------------------------------------- + POPUP HELPER +--------------------------------------------------------------------------- +*/ + +qx.Proto._oldSelected = null; + +qx.Proto._openPopup = function() +{ + var p = this._popup; + var el = this.getElement(); + + if (!p.isCreated()) { + this.createDispatchEvent("beforeInitialOpen"); + } + + if (this._list.getChildrenLength() == 0) { + return; + } + + p.positionRelativeTo(el, 1, qx.dom.Dimension.getBoxHeight(el)); + p.setWidth(this.getBoxWidth()-2); + + p.setParent(this.getTopLevelWidget()); + p.show(); + + this._oldSelected = this.getSelected(); + + this.setCapture(true); +} + +qx.Proto._closePopup = function() +{ + this._popup.hide(); + this.setCapture(false); +} + +qx.Proto._testClosePopup = function() +{ + if (this._popup.isSeeable()) { + this._closePopup(); + } +} + +qx.Proto._togglePopup = function() { + this._popup.isSeeable() ? this._closePopup() : this._openPopup(); +} + + + + + +/* +--------------------------------------------------------------------------- + OTHER EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onpopupappear = function(e) +{ + var vSelItem = this.getSelected(); + if (vSelItem) { + vSelItem.scrollIntoView(); + } +} + +qx.Proto._oninput = function(e) +{ + // Hint for modifier + this._fromInput = true; + + this.setValue(this._field.getComputedValue()); + + // be sure that the found item is in view + if (this.getPopup().isSeeable() && this.getSelected()) { + this.getSelected().scrollIntoView(); + } + + delete this._fromInput; +} + +qx.Proto._onbeforedisappear = function(e) +{ + this._testClosePopup(); +} + + + +/* +--------------------------------------------------------------------------- + MOUSE EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmousedown = function(e) +{ + var vTarget = e.getTarget(); + + switch(vTarget) + { + case this._field: + if (this.getEditable()) { + break; + } + + // no break here + + case this._button: + this._button.addState("pressed"); + this._togglePopup(); + break; + + case this: + case this._list: + break; + + default: + if (vTarget instanceof qx.ui.form.ListItem && vTarget.getParent() == this._list) + { + this._list._onmousedown(e); + this.setSelected(this._list.getSelectedItem()); + + this._closePopup(); + this.setFocused(true); + } + else if (this._popup.isSeeable()) + { + this._popup.hide(); + this.setCapture(false); + } + } +} + +qx.Proto._onmouseup = function(e) +{ + switch(e.getTarget()) + { + case this._field: + if (this.getEditable()) { + break; + } + + // no break here + + default: + this._button.removeState("pressed"); + break; + } +} + +qx.Proto._onmouseover = function(e) +{ + var vTarget = e.getTarget(); + + if (vTarget instanceof qx.ui.form.ListItem) + { + var vManager = this._manager; + + vManager.deselectAll(); + + vManager.setLeadItem(vTarget); + vManager.setAnchorItem(vTarget); + + vManager.setSelectedItem(vTarget); + } +} + +qx.Proto._onmousewheel = function(e) +{ + if (!this._popup.isSeeable()) + { + var toSelect; + + var isSelected = this.getSelected(); + + if (e.getWheelDelta() < 0) + { + toSelect = isSelected ? this._manager.getNext(isSelected) : this._manager.getFirst(); + } + else + { + toSelect = isSelected ? this._manager.getPrevious(isSelected) : this._manager.getLast(); + } + + if (toSelect) + { + this.setSelected(toSelect); + } + } + /* close the popup if the event target is not the combobox or + * not one of the list items of the popup list + */ + else { + var vTarget = e.getTarget(); + + if (vTarget!=this && vTarget.getParent()!=this._list) { + this._popup.hide(); + this.setCapture(false); + } + } +} + + + +/* +--------------------------------------------------------------------------- + KEY EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onkeydown = function(e) +{ + var vManager = this._manager; + var vVisible = this._popup.isSeeable(); + + switch(e.getKeyIdentifier()) + { + // Handle + case "Enter": + if (vVisible) + { + this.setSelected(this._manager.getSelectedItem()); + this._closePopup(); + this.setFocused(true); + } + else + { + this._openPopup(); + } + + return; + + // Handle + case "Escape": + if (vVisible) + { + vManager.setLeadItem(this._oldSelected); + vManager.setAnchorItem(this._oldSelected); + + vManager.setSelectedItem(this._oldSelected); + + this._field.setValue(this._oldSelected ? this._oldSelected.getLabel() : ""); + + this._closePopup(); + this.setFocused(true); + } + + return; + + // Handle Alt+Down + case "Down": + if (e.getAltKey()) + { + this._togglePopup(); + return; + } + + break; + } +}; + + +qx.Proto._onkeypress = function(e) +{ + var vVisible = this._popup.isSeeable(); + var vManager = this._manager; + + switch(e.getKeyIdentifier()) + { + // Handle + case "PageUp": + if (!vVisible) + { + var vPrevious; + var vTemp = this.getSelected(); + + if (vTemp) + { + var vInterval = this.getPagingInterval(); + + do { + vPrevious = vTemp; + } while(--vInterval && (vTemp = vManager.getPrevious(vPrevious))); + } + else + { + vPrevious = vManager.getLast(); + } + + this.setSelected(vPrevious); + + return; + } + + break; + + // Handle + case "PageDown": + if (!vVisible) + { + var vNext; + var vTemp = this.getSelected(); + + if (vTemp) + { + var vInterval = this.getPagingInterval(); + + do { + vNext = vTemp; + } while(--vInterval && (vTemp = vManager.getNext(vNext))); + } + else + { + vNext = vManager.getFirst(); + } + + this.setSelected(vNext); + + return; + } + + break; + } + + // Default Handling + if (!this.isEditable() || vVisible) + { + this._list._onkeypress(e); + + var vSelected = this._manager.getSelectedItem(); + + if (!vVisible) + { + this.setSelected(vSelected); + } + else if (vSelected) + { + this._field.setValue(vSelected.getLabel()); + } + } +}; + + +qx.Proto._onkeyinput = function(e) +{ + var vVisible = this._popup.isSeeable(); + if (!this.isEditable() || vVisible) + { + this._list._onkeyinput(e); + + var vSelected = this._manager.getSelectedItem(); + + if (!vVisible) + { + this.setSelected(vSelected); + } + else if (vSelected) + { + this._field.setValue(vSelected.getLabel()); + } + } +}; + + + +/* +--------------------------------------------------------------------------- + GLOBAL BLUR/FOCUS HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onwindowblur = qx.Proto._testClosePopup; + + + + + + + +/* +--------------------------------------------------------------------------- + FOCUS HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._visualizeBlur = function() +{ + // Force blur, even if mouseFocus is not active because we + // need to be sure that the previous focus rect gets removed. + // But this only needs to be done, if there is no new focused element. + if (qx.sys.Client.getInstance().isMshtml()) + { + if (this.getEnableElementFocus() && !this.getFocusRoot().getFocusedChild()) + { + try + { + if (this.getEditable()) + { + this.getField().getElement().blur(); + } + else + { + this.getElement().blur(); + } + } + catch(ex) {}; + } + } + else + { + if (this.getEnableElementFocus()) + { + try + { + if (this.getEditable()) + { + this.getField().getElement().blur(); + } + else if (!this.getFocusRoot().getFocusedChild()) + { + this.getElement().blur(); + } + } + catch(ex) {}; + } + } + + this.removeState("focused"); + return true; +} + +qx.Proto._visualizeFocus = function() +{ + if (!qx.event.handler.FocusHandler.mouseFocus && this.getEnableElementFocus()) + { + try + { + if (this.getEditable()) + { + this.getField().getElement().focus(); + this.getField()._ontabfocus(); + } + else + { + this.getElement().focus(); + } + } + catch(ex) {}; + } + + this.addState("focused"); + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + DISPOSE +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + // ************************************************************************ + // WIDGET MOUSE EVENTS + // ************************************************************************ + this.removeEventListener("mousedown", this._onmousedown); + this.removeEventListener("mouseup", this._onmouseup); + this.removeEventListener("mouseover", this._onmouseover); + this.removeEventListener("mousewheel", this._onmousewheel); + + + // ************************************************************************ + // WIDGET KEY EVENTS + // ************************************************************************ + this.removeEventListener("keydown", this._onkeydown); + this.removeEventListener("keypress", this._onkeypress); + this.removeEventListener("keyinput", this._onkeyinput); + + // ************************************************************************ + // DOCUMENT EVENTS + // ************************************************************************ + var vDoc = qx.ui.core.ClientDocument.getInstance(); + vDoc.removeEventListener("windowblur", this._onwindowblur, this); + + if (this._list) + { + this._list.dispose(); + this._list = null; + } + + if (this._manager) + { + this._manager.dispose(); + this._manager = null; + } + + if (this._popup) + { + this._popup.removeEventListener("appear", this._onpopupappear, this); + this._popup.dispose(); + this._popup = null; + } + + if (this._field) + { + this._field.removeEventListener("input", this._oninput, this); + this._field.dispose(); + this._field = null; + } + + if (this._button) + { + this._button.dispose(); + this._button = null; + } + + return qx.ui.layout.HorizontalBoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/ComboBoxEx.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/ComboBoxEx.js new file mode 100644 index 0000000000..935b2e78a7 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/ComboBoxEx.js @@ -0,0 +1,1044 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * David Perez Carmona (david-perez), based on qx.ui.form.ComboBox + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_comboboxex) +#require(qx.ui.table.Table) + +************************************************************************ */ + +/** + * An enhanced combo-box for qooxdoo. + * + *

Features:

+ *
    + *
  • Editable text field
  • + *
  • Complete key-navigation
  • + *
  • Mouse wheel navigation
  • + *
  • Multicolumn display in list
  • + *
  • If more than one column, headers are automatically shown
  • + *
  • Can show the ID and/or description of each list item
  • + *
  • Automatically calculating needed width
  • + *
  • Popup list always shows full contents, and can be wider than text field
  • + *
  • Search values through popup dialog
  • + *
  • Internationalization support of messages (through custom settings)
  • + *
+ *

Pending features:

+ *
    + *
  • Images inside the list
  • + *
  • Autocomplete on key input
  • + *
+ * + * @event beforeInitialOpen {qx.event.type.Event} + */ +qx.OO.defineClass('qx.ui.form.ComboBoxEx', qx.ui.layout.HorizontalBoxLayout, function() { + qx.ui.layout.HorizontalBoxLayout.call(this); + + // ************************************************************************ + // POPUP + // ************************************************************************ + var p = this._popup = new qx.ui.popup.Popup; + p.setAppearance('combo-box-ex-popup'); + + // ************************************************************************ + // LIST + // ************************************************************************ + this._createList([ this._getComboSetting('idHeader'), this._getComboSetting('descriptionHeader') ]); + + // ************************************************************************ + // FIELD + // ************************************************************************ + var f = this._field = new qx.ui.form.TextField; + f.setAppearance('combo-box-ex-text-field'); + f.addEventListener("input", this._oninput, this); + this.add(f); + this.setEditable(false); + + // ************************************************************************ + // BUTTON + // ************************************************************************ + + // Use qx.ui.basic.Atom instead of qx.ui.form.Button here to omit the registration + // of the unneeded and complex button events. + var b = this._button = new qx.ui.basic.Atom(null, "widget/arrows/down.gif"); + b.set({ + appearance: "combo-box-button", + tabIndex: -1 + }); + this.add(b); + + // ************************************************************************ + // BEHAVIOR + // ************************************************************************ + this.setTabIndex(1); + + // ************************************************************************ + // WIDGET MOUSE EVENTS + // ************************************************************************ + this.addEventListener("mousedown", this._onmousedown); + this.addEventListener("mouseup", this._onmouseup); + this.addEventListener("mousewheel", this._onmousewheel); + this.addEventListener("dblclick", function() { + if (this.getAllowSearch()) { + this.openSearchDialog(); + } + }); + + // ************************************************************************ + // WIDGET KEY EVENTS + // ************************************************************************ + this.addEventListener("keydown", this._onkeydown); + this.addEventListener("keypress", this._onkeypress); + + // ************************************************************************ + // WIDGET STATE EVENTS + // ************************************************************************ + this.addEventListener("beforeDisappear", this._testClosePopup); + + // ************************************************************************ + // CHILDREN EVENTS + // ************************************************************************ + this._popup.addEventListener("appear", this._onpopupappear, this); +}); + +/* +--------------------------------------------------------------------------- + LOCALIZATION SUPPORT +--------------------------------------------------------------------------- +*/ + +qx.Settings.setDefault('titleSearch', 'Search items in list'); +qx.Settings.setDefault('toolTipSearchNext', 'Search next occurrence'); +qx.Settings.setDefault('idHeader', 'ID'); +qx.Settings.setDefault('descriptionHeader', 'Description'); +qx.Settings.setDefault('caseSensitiveCaption', 'Case sensitive'); + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "combo-box-ex" }); + +/*!Is the text field component editable or the user can only select from the list?*/ +qx.OO.addProperty({ name: "editable", type: "boolean", getAlias: "isEditable" }); + +/*!0 based. -1 means no selected index. It retrieves always the value column of the selection, not the description.*/ +qx.OO.addProperty({ name: "value", type : "string" }); + +/*!How many items to transverse with PageUp and PageDn.*/ +qx.OO.addProperty({ name: "pagingInterval", type: "number", defaultValue: 10 }); + +/*!Show the ID column (column 0) of the selection data?*/ +qx.OO.addProperty({ name: "idColumnVisible", type: "boolean", getAlias: "isIdColumnVisible", defaultValue: false }); + +/*!Only used when editable is false. It determines what to show in the text field of the combo box.*/ +qx.OO.addProperty({ name: "showOnTextField", type: "string", defaultValue: 'description', possibleValues : [ 'description', 'idAndDescription' ] }); + +/*!Only used when editable is false and showOnTextField=='idAndDescription'.*/ +qx.OO.addProperty({ name: "idDescriptionSeparator", type: "string", defaultValue: '- ' }); + +/*!Ensures that always an item is selected (in case the selection isn't empty). Only used when editable is false.*/ +qx.OO.addProperty({ name: 'ensureSomethingSelected', type: "boolean", defaultValue: true }); + +/*!Allow the search dialog when double clicking the combo, or pressing special keys?.*/ +qx.OO.addProperty({ name: 'allowSearch', type: "boolean", defaultValue: true }); + +/*!Maximum number of visible rows in the popup list.*/ +qx.OO.addProperty({ name: 'maxVisibleRows', type: "number", defaultValue: 10 }); + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getPopup = function() { + return this._popup; +} + +qx.Proto.getList = function() { + return this._list; +} + +qx.Proto.getField = function() { + return this._field; +} + +qx.Proto.getButton = function() { + return this._button; +} + +qx.Proto._getComboSetting = function(key) { + return qx.Settings.getValueOfClass('qx.ui.form.ComboBoxEx', key); +} + +/**Gets the current selected row of the selection. + * @return null if nothing selected or an array*/ +qx.Proto.getSelectedRow = function() { + var ind = this.getSelectedIndex(); + return ind < 0 ? null : this._model.getData()[ind]; +} + +/**Creates the list component.*/ +qx.Proto._createList = function(columns) { + this._model = new qx.ui.table.SimpleTableModel; + // Default column titles + this._model.setColumns(columns); + var l = this._list = new qx.ui.table.Table(this._model); + l.setFocusedCell = function() {} + l.setAppearance('combo-box-ex-list'); + // We receive this: Modification of property "keepFirstVisibleRowComplete" failed with exception: TypeError - vCurrentChild has no properties or + // this: Modification of property "keepFirstVisibleRowComplete" failed with exception: TypeError - this.getParent() has no properties + l.forceKeepFirstVisibleRowComplete(false); + var selMan = l._getSelectionManager(); + var oldHandle = selMan.handleMouseUp, me = this; + selMan.handleMouseUp = function(vItem, e) { + oldHandle.apply(selMan, arguments); + if (e.isLeftButtonPressed()) { + me._testClosePopup(); + } + } + this._modifyIdColumnVisible(this.getIdColumnVisible()); + this._manager = l.getSelectionModel(); + this._manager.addEventListener('changeSelection', this._onChangeSelection, this); + // Avoid deselection from user + this._manager.removeSelectionInterval = function() {}; + this._manager.setSelectionMode(qx.ui.table.SelectionModel.SINGLE_SELECTION); + this._popup.add(l); + // Invalidate calculation of column widths + delete this._calcDimensions; +} + + +/* +--------------------------------------------------------------------------- + PSEUDO-PROPERTIES +--------------------------------------------------------------------------- +*/ + +/**Sets the header for each column. + * @param columns {String[]}*/ +qx.Proto.setColumnHeaders = function(columns) { + if (!this._list || columns.length != this._model.getColumnCount()) { + if (this._list) { + var data = this._model.getData(); + this._list.setParent(null); + this._list.dispose(); + this._list = null; + } + this._createList(columns); + if (data && data.length) { + this._model.setData(data); + } + } else { + this._model.setColumns(columns); + this._list.getTableColumnModel().init(columns.length); + delete this._calcDimensions; + } + this._modifyIdColumnVisible(this.getIdColumnVisible()); +} + +/**Getter for {@link #setColumnHeaders}. + * @return {String[]}*/ +qx.Proto.getColumnHeaders = function(propVal) { + var cols = []; + cols.length = this._model.getColumnCount(); + for (var col = 0; col < cols.length; col++) { + cols[col] = this._model.getColumnName(col); + } + return cols; +} + +/**Sets the list of selectable items. + * @param data {var[][]} Array of values. Its value is an array, with the following info:
    . + *
  • Column 0 represents the ID, i.e. the value that is stored internally and used by the app.
  • + *
  • Column 1 represents the description, the text that the end user normally sees.
  • + *
  • Columns > 1 will also be shown in the popup list, it you have set the appropiate column headers with {@link #setColumnHeaders}.
  • + *
*/ +qx.Proto.setSelection = function(data) { + // Invalidate calculation of column widths + delete this._calcDimensions; + this._model.setData(data); + // Try to preserve currently selected value + if (!this.getEditable()) { + this._modifyValue(this.getValue()); + } +} + +/**Getter for {@link #setSelection}. + * @return {Array}*/ +qx.Proto.getSelection = function() { + return this._model.getData(); +} + +/**Sets the index of the currently selected item in the list. + * @param index {Number} -1 means no selected index*/ +qx.Proto.setSelectedIndex = function(index) { + var items = this.getSelection().length; + if (items >= 0) { + if (index < 0 && !this.getEditable() && this.getEnsureSomethingSelected()) { + index = 0; + } + if (index >= 0) { + index = qx.lang.Number.limit(index, 0, items-1); + this._manager.setSelectionInterval(index, index); + if (this._popup.isSeeable()) { + this._list.scrollCellVisible(0, index); + } + } else { + this._manager.clearSelection(); + } + } + return true; +} + +/**Getter for {@link #setSelectedIndex}.*/ +qx.Proto.getSelectedIndex = function() { + var index = this._manager.getAnchorSelectionIndex(); + return this._manager.isSelectedIndex(index) ? index:-1; +} + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyShowOnTextField = function(propVal) { + if (!this.getEditable()) { + this.setSelectedIndex(this.getSelectedIndex()); + delete this._calcDimensions; // Invalidate this._neededTextFieldWidth + } + return true; +} + +qx.Proto._modifyMaxVisibleRows = function() { + delete this._calcDimensions; // Invalidate this._list.height + return true; +} + +qx.Proto._checkIdDescriptionSeparator = function(propVal) { + // For measuring widths, it is better to replace spaces with non-breakable spaces + return String(propVal).replace(/ /g, '\u00A0') +} + +qx.Proto._modifyIdDescriptionSeparator = function(propVal) { + if (!this.getEditable() && this.getShowOnTextField() == 'idAndDescription') { + this.setSelectedIndex(this.getSelectedIndex()); + delete this._calcDimensions; // Invalidate this._neededTextFieldWidth + } + return true; +} + +qx.Proto._modifyIdColumnVisible = function(propVal) { + this._list.getTableColumnModel().setColumnVisible(0, propVal); + delete this._calcDimensions; + return true; +} + +qx.Proto._modifyEditable = function(propValue/*, propOldValue, propData*/) { + var f = this._field; + f.setReadOnly(!propValue); + f.setCursor(propValue ? null : "default"); + f.setSelectable(propValue); + return true; +} + +qx.Proto._modifyValue = function(propValue/*, propOldValue, propData*/) { + this._fromValue = true; + + var values = this._model.getData(); + var i = -1; + if (propValue != null) { + for (var i = 0; i < values.length; i++) { + if (propValue == values[i][0]) { + break; + } + } + if (i == values.length) { + i = -1; + } + } + if (this.getEditable()) { + this._field.setValue(propValue); + } + // only do this if we called setValue separately + // and not from the property "selected". + if (!this._fromSelected) { + this.setSelectedIndex(i); + } + // reset hint + delete this._fromValue; + return true; +} + +qx.Proto._modifyEnabled = function(propValue/*, propOldValue, propData*/) { + if (this._button) { + this._button.setEnabled(propValue); + } + if (this._field) { + this._field.setEnabled(propValue); + } + return qx.ui.layout.HorizontalBoxLayout.prototype._modifyEnabled.apply(this, arguments); +} + + +/* +--------------------------------------------------------------------------- + POPUP HELPER +--------------------------------------------------------------------------- +*/ + +qx.Proto._oldSelected = null; + +qx.Proto._openPopup = function() { + if (this.isSearchInProgress()) { + return; + } + var p = this._popup; + p.setAutoHide(false); + var el = this.getElement(); + if (!p.isCreated()) { + this.createDispatchEvent("beforeInitialOpen"); + } + if (!this.getSelection().length) { + return; + } + p.positionRelativeTo(el, 1, qx.dom.Dimension.getBoxHeight(el)); + this._calculateDimensions(); + p.setParent(this.getTopLevelWidget()); + p.auto(); + p.show(); + this._oldSelected = this.getSelectedIndex(); + window.setInterval(function() { + p.setAutoHide(true); + }, 0); +} + +/**Hide the popup list.*/ +qx.Proto._closePopup = function() { + this._popup.hide(); +} + +/**Hide the popup list only when needed.*/ +qx.Proto._testClosePopup = function() { + if (this._popup.isSeeable()) { + this._closePopup(); + } +} + +/**Toggle the visibility of the popup list.*/ +qx.Proto._togglePopup = function() { + this._popup.isSeeable() ? this._closePopup() : this._openPopup(); +} + +/* +--------------------------------------------------------------------------- + DIMENSIONING +--------------------------------------------------------------------------- +*/ + +/**Sizes the width of the text field component to the needed value to show any selection item.*/ +qx.Proto.sizeTextFieldToContent = function() { + this._calculateDimensions(); + this._field.setWidth(this._neededTextFieldWidth); +} + +/**Calculates the needed dimensions for the text field and list components*/ +qx.Proto._calculateDimensions = function() { + if (this._calcDimensions) { + // Already calculated + return; + } + var data = this.getSelection(); + var cols = this.getColumnHeaders(), nCols = cols.length; + var columnWidths = []; + this._neededTextFieldWidth = 0; + columnWidths.length = cols.length; + for (var col = 0; col < cols.length; col++) { + columnWidths[col] = 0; + } + var withDescript = this.getShowOnTextField() == 'idAndDescription'; + for (var row = 0, rows = Math.min(data.length, 50); row < rows; row++) { + var r = data[row], wi0, wi1; + for (col = 0; col < nCols; col++) { + var wi = this._getTextWidth(r[col]); + if (col == 0) { + wi0 = wi; + } else if (col == 1) { + wi1 = wi; + } + columnWidths[col] = Math.max(wi, columnWidths[col]); + } + this._neededTextFieldWidth = Math.max(this._neededTextFieldWidth, + wi1+(withDescript ? wi0:0)); + } + if (this.getShowOnTextField() == 'idAndDescription') { + this._neededTextFieldWidth += this._getTextWidth(this.getIdDescriptionSeparator()); + } + this._neededTextFieldWidth += 8; /*Extra margins*/ + var maxRows = this.getMaxVisibleRows(), + // Only assign room for the vertical scrollbar when needed + width = data.length > maxRows ? (new qx.ui.core.ScrollBar)._getScrollBarWidth():0, + colModel = this._list.getTableColumnModel(), + countVisible = 0; + + // ##Only show headers if we have more than 1 column visible + for (col = 0; col < nCols; col++) { + if (colModel.isColumnVisible(col)) { + countVisible++; + } + } + var hasHeaders = countVisible > 1; + this._list.getPaneScroller(0).getHeader().setHeight(hasHeaders ? 'auto' : 1); + + // ##Size each column + for (col = 0; col < nCols; col++) { + if (colModel.isColumnVisible(col)) { + var w = columnWidths[col]; + if (hasHeaders) { + w = Math.max(w, this._getTextWidth(cols[col])); + } + w += 8; + this._list.setColumnWidth(col, w); + width += w; + } + } + + // ##Final width and height + this._list.set({ + width: width, + height: this._list.getRowHeight()* + Math.min(maxRows, (hasHeaders ? 1:0)+data.length)+2+(hasHeaders ? 2:0) + }); + // This denotes dimensions are already calculated + this._calcDimensions = true; +} + +/**Calculates the width of the given text. + * The default font is used. + * @return {integer}*/ +qx.Proto._getTextWidth = function(text) { + var lab = new qx.ui.basic.Label(text); + var res = lab.getPreferredBoxWidth(); + lab.dispose(); + return res; +} + + +/* +--------------------------------------------------------------------------- + SEARCHING +--------------------------------------------------------------------------- +*/ + +/**Does this combo have the searched dialog open?*/ +qx.Proto.isSearchInProgress = function() { + return !this._popup.contains(this._list); +} + +/**Searches the given text. Called from the search dialog. + * @param startIndex {Number} Start index, 0 based + * @param txt {String} Text to find + * @param caseSens {Boolean} Case sensivity flag.*/ +qx.Proto._search = function(startIndex, txt, caseSens) { + if (txt == null || !txt.length) { + return; + } + var row = startIndex, + nCols = this._model.getColumnCount(), + nRows = this.getSelection().length, + data = this._model.getData(); + if (!caseSens) { + txt = txt.toLowerCase(); + } + var colModel = this._list.getTableColumnModel(); + while (true) { + var dataRow = data[row]; + if (dataRow) { + for (var col = 0; col < nCols; col++) { + if (colModel.isColumnVisible(col)) { + var txtCol = dataRow[col]; + if (!caseSens) { + txtCol = txtCol.toLowerCase(); + } + if (txtCol.indexOf(txt) >= 0) { + this._manager.setSelectionInterval(row, row); + this._list.scrollCellVisible(1, row); + return; + } + } + } + } + row = (row+1)% nRows; + if (row == startIndex) { + break; + } + } +} + +/**Opens a popup search dialog, useful when the combo has a lot of items. + * This dialog is triggered by double clicking the combo, pressing F3 or Ctrl+F.*/ +qx.Proto.openSearchDialog = function() { + var sel = this.getSelection(); + if (!sel || !sel.length || this.isSearchInProgress()) { + return; + } + this._testClosePopup(); + + var me = this, + oldSelectedIndex = this.getSelectedIndex(), + startIndex = oldSelectedIndex; + + //###searchField + function search() { + me._search(startIndex, searchField.getComputedValue(), checkCase.isChecked()); + } + var searchField = new qx.ui.form.TextField; + searchField.set({ + minWidth: this._field.getWidth(), + width: '100%' + }); + searchField.addEventListener("input", function() { + search(); + }); + + //###checkCase + var checkCase = new qx.ui.form.CheckBox(this._getComboSetting('caseSensitiveCaption')); + checkCase.set({ + horizontalAlign: 'center', + marginBottom: 4 + }); + + //###vbox + var vbox = new qx.ui.layout.VerticalBoxLayout; + vbox.set({ + spacing: 6, + horizontalChildrenAlign: 'center', + height: '100%' + }); + vbox.auto(); + vbox.add(searchField, checkCase); + + //###list, we reuse the same list in the popup + this._calculateDimensions(); + var border = qx.renderer.border.BorderPresets.getInstance().inset; + var newListSettings = { + /*minHeight: border.getTopWidth()+this._list.getHeight()+border.getBottomWidth(), + height: '1*',*/ + height: border.getTopWidth()+this._list.getHeight()+border.getBottomWidth(), + width: border.getLeftWidth()+this._list.getWidth()+border.getRightWidth(), + border: border, + parent: vbox + }; + // Save old list settings + var oldListSettings = {}; + for (var prop in newListSettings) { + oldListSettings[prop] = this._list[qx.OO.getter[prop]](); + } + this._list.set(newListSettings); + + //###buttons + var butNext = new qx.ui.form.Button('', 'icon/16/find.png'); + butNext.set({ + toolTip: new qx.ui.popup.ToolTip(this._getComboSetting('toolTipSearchNext')) + }); + butNext.addEventListener("execute", function() { + startIndex = (this.getSelectedIndex()+1) % sel.length; + search(); + }, this); + + var butOk = new qx.ui.form.Button('', 'icon/16/button-ok.png'); + butOk.addEventListener('execute', function() { + oldSelectedIndex = null; + win.close(); + }, this); + + var butCancel = new qx.ui.form.Button('', 'icon/16/button-cancel.png'); + butCancel.addEventListener('execute', function() { + win.close(); + }, this); + + var butBox = new qx.ui.layout.VerticalBoxLayout; + butBox.auto(); + butBox.set({ + spacing: 10 + }); + butBox.add(butNext, butOk, butCancel); + + //###hbox + var hbox = new qx.ui.layout.BoxLayout; + hbox.auto(); + hbox.setPadding(10); + hbox.set({ + spacing: 8, + minHeight: 'auto', + height: '100%' + }); + hbox.add(vbox, butBox); + + //###Window + var win = new qx.ui.window.Window(this._getComboSetting('titleSearch'), 'icon/16/find.png'); + win.add(hbox); + win.positionRelativeTo(this); + win.set({ + autoHide: true, + allowMaximize: false, + showMaximize: false, + allowMinimize: false, + showMinimize: false + }); + win.addEventListener("appear", function() { + searchField.focus(); + }); + win.addEventListener("disappear", function() { + if (oldSelectedIndex != null) { + // Hit Cancel button + this.setSelectedIndex(oldSelectedIndex); + } + this._list.set(oldListSettings); + this.focus(); + }, this); + win.addEventListener("keydown", function(e) { + switch (e.getKeyIdentifier()) { + case "Enter": + butOk.createDispatchEvent('execute'); + break; + case "Escape": + butCancel.createDispatchEvent('execute'); + break; + case "F3": + butNext.createDispatchEvent('execute'); + break; + default: + return; + } + e.preventDefault(); + }, this); + win.auto(); + win.addToDocument(); + win.open(); +} + +/* +--------------------------------------------------------------------------- + OTHER EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onChangeSelection = function(e) { + this._fromSelected = true; + + // only do this if we called setValue separately + // and not from the event "input". + if (!this._fromInput) { + var index = this.getSelectedIndex(); + if (index >= 0) { + var row = this._model.getData()[index]; + } + if (row || !this.getEditable()) { + this.setValue(row && row[0]); + } + // In case of editable, this.setValue() already calls this._field.setValue() + if (!this.getEditable()) { + var val = ""; + if (row) { + val = this.getShowOnTextField() == 'description' ? + row[1] : + (row[0] != null && row[0] != '' ? row[0] + this.getIdDescriptionSeparator() + row[1]:row[1]); + } + this._field.setValue(val); + } + } + // reset hint + delete this._fromSelected; +} + +qx.Proto._onpopupappear = function(e) { + var index = this.getSelectedIndex(); + if (index >= 0) { + this._list.scrollCellVisible(0, index); + } +} + +qx.Proto._oninput = function(e) { + // Hint for modifier + this._fromInput = true; + this.setValue(this._field.getComputedValue()); + delete this._fromInput; +} + + +/* +--------------------------------------------------------------------------- + MOUSE EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmousedown = function(e) { + switch(e.getTarget()) { + case this._field: + if (this.getEditable()) { + break; + } + // no break here + case this._button: + this._button.addState("pressed"); + this._togglePopup(); + // Assure we receive the mouse up event + this.setCapture(true); + break; + } +} + +qx.Proto._onmouseup = function(e) { + switch(e.getTarget()) { + case this._field: + if (this.getEditable()) { + break; + } + // no break here + default: + this._button.removeState("pressed"); + break; + } + this.setCapture(false); +} + +qx.Proto._onmousewheel = function(e) { + if (!this._popup.isSeeable()) { + this.setSelectedIndex(Math.max(0, this.getSelectedIndex()+(e.getWheelDelta() < 0 ? -1:1))); + } +} + + +/* +--------------------------------------------------------------------------- + KEY EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onkeydown = function(e) { + var vVisible = this._popup.isSeeable(); + + switch (e.getKeyIdentifier()) { + case "Enter": + if (vVisible) { + this._closePopup(); + this.setFocused(true); + } else { + this._openPopup(); + } + break; + + case "Escape": + if (vVisible) { + this.setSelectedIndex(this._oldSelected); + this._closePopup(); + this.setFocused(true); + } + break; + + case "Home": + this.setSelectedIndex(0); + break; + + case "End": + var items = this.getSelection().length; + if (items) { + this.setSelectedIndex(items-1); + } + break; + + case "Down": + if (e.getAltKey()) { + this._togglePopup(); + } + break; + + case "F3": + if (this.getAllowSearch()) { + this.openSearchDialog(); + } + break; + + case "F": + if (e.getCtrlKey()) { + if (this.getAllowSearch()) { + this.openSearchDialog(); + } + break; + } + return; + + default: + if (vVisible) { + this._list.dispatchEvent(e); + } + return; + } + e.preventDefault(); +} + + +qx.Proto._onkeypress = function(e) { + var vVisible = this._popup.isSeeable(); + + switch (e.getKeyIdentifier()) { + case "Up": + this.setSelectedIndex(Math.max(0, this.getSelectedIndex()-1)); + break; + + case "Down": + this.setSelectedIndex(Math.max(0, this.getSelectedIndex()+1)); + break; + + case "PageUp": + this.setSelectedIndex(Math.max(0, this.getSelectedIndex()-this.getPagingInterval())); + break; + + case "PageDown": + this.setSelectedIndex(this.getSelectedIndex()+this.getPagingInterval()); + break; + + default: + if (vVisible) { + this._list.dispatchEvent(e); + } + return; + } + e.preventDefault(); + + if (!this.isEditable() && this._list.isSeeable()) { + this._list.dispatchEvent(e); + } + +} + + +/* +--------------------------------------------------------------------------- + FOCUS HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._visualizeBlur = function() { + // Force blur, even if mouseFocus is not active because we + // need to be sure that the previous focus rect gets removed. + // But this only needs to be done, if there is no new focused element. + if (qx.sys.Client.getInstance().isMshtml()) { + if (this.getEnableElementFocus() && !this.getFocusRoot().getFocusedChild()) { + try { + if (this.getEditable()) { + this.getField().getElement().blur(); + } else { + this.getElement().blur(); + } + } + catch(ex) {}; + } + } else { + if (this.getEnableElementFocus()) { + try { + if (this.getEditable()) { + this.getField().getElement().blur(); + } else if (!this.getFocusRoot().getFocusedChild()) { + this.getElement().blur(); + } + } + catch(ex) {}; + } + } + this.removeState("focused"); + return true; +} + +qx.Proto._visualizeFocus = function() { + if (!qx.event.handler.FocusHandler.mouseFocus && this.getEnableElementFocus()) { + try { + if (this.getEditable()) { + this.getField().getElement().focus(); + this.getField()._ontabfocus(); + } else { + this.getElement().focus(); + } + } catch(ex) { + } + } + this.addState("focused"); + return true; +} + +/* +--------------------------------------------------------------------------- + DISPOSE +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() { + if (this.getDisposed()) { + return; + } + + // ************************************************************************ + // WIDGET MOUSE EVENTS + // ************************************************************************ + this.removeEventListener("mousedown", this._onmousedown); + this.removeEventListener("mouseup", this._onmouseup); + this.removeEventListener("mousewheel", this._onmousewheel); + + + // ************************************************************************ + // WIDGET KEY EVENTS + // ************************************************************************ + this.removeEventListener("keydown", this._onkeydown); + this.removeEventListener("keypress", this._onkeypress); + + + this._model = null; + if (this._manager) { + this._manager.removeEventListener('changeSelection', this._onChangeSelection); + this._manager = null; + } + if (this._list) { + this._list.dispose(); + this._list = null; + } + if (this._popup) { + this._popup.removeEventListener("appear", this._onpopupappear, this); + this._popup.dispose(); + this._popup = null; + } + if (this._field) { + if (this.getEditable()) { + this._field.removeEventListener("input", this._oninput, this); + } + this._field.dispose(); + this._field = null; + } + if (this._button) { + this._button.dispose(); + this._button = null; + } + return qx.ui.layout.HorizontalBoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/InputCheckSymbol.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/InputCheckSymbol.js new file mode 100644 index 0000000000..a7acf6f65a --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/InputCheckSymbol.js @@ -0,0 +1,93 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_form) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.form.InputCheckSymbol", qx.ui.basic.Terminator, +function() +{ + qx.ui.basic.Terminator.call(this); + + this.setTagName("input"); + this.setSelectable(false); + + if (qx.sys.Client.getInstance().isMshtml()) + { + // Take control over size of element (mshtml) + this.setWidth(13); + this.setHeight(13); + } + else if (qx.sys.Client.getInstance().isGecko()) + { + // Remove gecko default margin + this.setMargin(0); + } + + // we need to be sure that the dom protection of this is added + this.forceTabIndex(1); + this.setTabIndex(-1); + this.setChecked(false); +}); + +qx.OO.addProperty({ name : "name", type : "string", impl : "apply" }); +qx.OO.addProperty({ name : "value", impl : "apply" }); +qx.OO.addProperty({ name : "type", impl : "apply" }); +qx.OO.addProperty({ name : "checked", type : "boolean", impl : "apply", getAlias : "isChecked" }); + +qx.Proto._modifyApply = function(propValue, propOldValue, propData) { + return this.setHtmlProperty(propData.name, propValue); +} + +qx.Proto.getPreferredBoxWidth = function() { + return 13; +} + +qx.Proto.getPreferredBoxHeight = function() { + return 13; +} + +qx.Proto.getBoxWidth = qx.Proto.getPreferredBoxWidth; +qx.Proto.getBoxHeight = qx.Proto.getPreferredBoxHeight; + +qx.Proto.getInnerWidth = qx.Proto.getPreferredBoxWidth; +qx.Proto.getInnerHeight = qx.Proto.getPreferredBoxHeight; + +if (qx.sys.Client.getInstance().isMshtml()) +{ + qx.Proto._afterAppear = function() + { + qx.ui.basic.Terminator.prototype._afterAppear.call(this); + + var vElement = this.getElement(); + vElement.checked = this.getChecked(); + + if (!this.getEnabled()) { + vElement.disabled = true; + } + } +} + +qx.Proto._modifyEnabled = function(propValue, propOldValue, propData) +{ + propValue ? this.removeHtmlAttribute("disabled") : this.setHtmlAttribute("disabled", "disabled"); + return qx.ui.basic.Terminator.prototype._modifyEnabled.call(this, propValue, propOldValue, propData); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/List.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/List.js new file mode 100644 index 0000000000..da58b6a960 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/List.js @@ -0,0 +1,383 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_form) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.form.List", qx.ui.layout.VerticalBoxLayout, +function() +{ + qx.ui.layout.VerticalBoxLayout.call(this); + + + // ************************************************************************ + // INITILISIZE MANAGER + // ************************************************************************ + this._manager = new qx.manager.selection.SelectionManager(this); + + + // ************************************************************************ + // BEHAVIOR + // ************************************************************************ + this.setSelectable(false); + this.setTabIndex(1); + + + // ************************************************************************ + // MOUSE EVENT LISTENER + // ************************************************************************ + this.addEventListener("mouseover", this._onmouseover); + this.addEventListener("mousedown", this._onmousedown); + this.addEventListener("mouseup", this._onmouseup); + this.addEventListener("click", this._onclick); + this.addEventListener("dblclick", this._ondblclick); + + + // ************************************************************************ + // KEY EVENT LISTENER + // ************************************************************************ + this.addEventListener("keydown", this._onkeydown); + this.addEventListener("keypress", this._onkeypress); + this.addEventListener("keyinput", this._onkeyinput); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "list" }); + +qx.OO.addProperty({ name : "enableInlineFind", type : "boolean", defaultValue : true }); +qx.OO.addProperty({ name : "markLeadingItem", type : "boolean", defaultValue : false }); + +qx.Proto._pressedString = ""; + + + + + +/* +--------------------------------------------------------------------------- + MANAGER BINDING +--------------------------------------------------------------------------- +*/ + +qx.Proto.getManager = function() { + return this._manager; +} + +qx.Proto.getListItemTarget = function(vItem) +{ + while (vItem != null && vItem.getParent() != this) { + vItem = vItem.getParent(); + } + + return vItem; +} + +qx.Proto.getSelectedItem = function() { + return this.getSelectedItems()[0]; +} + +qx.Proto.getSelectedItems = function() { + return this._manager.getSelectedItems(); +} + + + +/* +--------------------------------------------------------------------------- + MOUSE EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmouseover = function(e) +{ + var vItem = this.getListItemTarget(e.getTarget()); + + if (vItem) { + this._manager.handleMouseOver(vItem, e); + } +} + +qx.Proto._onmousedown = function(e) +{ + var vItem = this.getListItemTarget(e.getTarget()); + + if (vItem) { + this._manager.handleMouseDown(vItem, e); + } +} + +qx.Proto._onmouseup = function(e) +{ + var vItem = this.getListItemTarget(e.getTarget()); + + if (vItem) { + this._manager.handleMouseUp(vItem, e); + } +} + +qx.Proto._onclick = function(e) +{ + var vItem = this.getListItemTarget(e.getTarget()); + + if (vItem) { + this._manager.handleClick(vItem, e); + } +} + +qx.Proto._ondblclick = function(e) +{ + var vItem = this.getListItemTarget(e.getTarget()); + + if (vItem) { + this._manager.handleDblClick(vItem, e); + } +} + + + + +/* +--------------------------------------------------------------------------- + KEY EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onkeydown = function(e) +{ + // Execute action on press + if (e.getKeyIdentifier() == "Enter" && !e.getAltKey()) + { + var items = this.getSelectedItems(); + var currentItem; + + for (var i=0; i 1000) { + this._pressedString = ""; + } + + // Combine keys the user pressed to a string + this._pressedString += String.fromCharCode(e.getCharCode()); + + // Find matching item + var matchedItem = this.findString(this._pressedString, null); + + if (matchedItem) + { + var oldVal = this._manager._getChangeValue(); + + // Temporary disable change event + var oldFireChange = this._manager.getFireChange(); + this._manager.setFireChange(false); + + // Reset current selection + this._manager._deselectAll(); + + // Update manager + this._manager.setItemSelected(matchedItem, true); + this._manager.setAnchorItem(matchedItem); + this._manager.setLeadItem(matchedItem); + + // Scroll to matched item + matchedItem.scrollIntoView(); + + // Recover event status + this._manager.setFireChange(oldFireChange); + + // Dispatch event if there were any changes + if (oldFireChange && this._manager._hasChanged(oldVal)) { + this._manager._dispatchChange(); + } + } + + // Store timestamp + this._lastKeyPress = (new Date).valueOf(); + e.preventDefault(); +} + + + + +/* +--------------------------------------------------------------------------- + FIND SUPPORT +--------------------------------------------------------------------------- +*/ + +qx.Proto._findItem = function(vUserValue, vStartIndex, vType) +{ + var vAllItems = this.getChildren(); + + // If no startIndex given try to get it by current selection + if (vStartIndex == null) + { + vStartIndex = vAllItems.indexOf(this.getSelectedItem()); + + if (vStartIndex == -1) { + vStartIndex = 0; + } + } + + var methodName = "matches" + vType; + + // Mode #1: Find all items after the startIndex + for (var i=vStartIndex; i= "0" && vIdentifier <= "9") { + return; + } + + e.preventDefault(); + } + } +} + +qx.Proto._onkeydown = function(e) +{ + var vIdentifier = e.getKeyIdentifier(); + + if (this._intervalIncrease == null) + { + switch(vIdentifier) + { + case "Up": + case "Down": + this._intervalIncrease = vIdentifier == "Up"; + this._intervalMode = "single"; + + this._resetIncrements(); + this._checkValue(true, false, false); + + this._increment(); + this._timer.startWith(this.getFirstInterval()); + + break; + + case "PageUp": + case "PageDown": + this._intervalIncrease = vIdentifier == "PageUp"; + this._intervalMode = "page"; + + this._resetIncrements(); + this._checkValue(true, false, false); + + this._pageIncrement(); + this._timer.startWith(this.getFirstInterval()); + + break; + } + } +} + +qx.Proto._onkeyup = function(e) +{ + if (this._intervalIncrease != null) + { + switch(e.getKeyIdentifier()) + { + case "Up": + case "Down": + case "PageUp": + case "PageDown": + this._timer.stop(); + + this._intervalIncrease = null; + this._intervalMode = null; + } + } +} + + + + + +/* +--------------------------------------------------------------------------- + MOUSE EVENT-HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmousedown = function(e) +{ + if (!e.isLeftButtonPressed()) { + return; + } + + this._checkValue(true); + + var vButton = e.getCurrentTarget(); + + vButton.addState("pressed"); + + vButton.addEventListener("mouseup", this._onmouseup, this); + vButton.addEventListener("mouseout", this._onmouseup, this); + + this._intervalIncrease = vButton == this._upbutton; + this._resetIncrements(); + this._increment(); + + this._textfield.selectAll(); + + this._timer.setInterval(this.getFirstInterval()); + this._timer.start(); +} + +qx.Proto._onmouseup = function(e) +{ + var vButton = e.getCurrentTarget(); + + vButton.removeState("pressed"); + + vButton.removeEventListener("mouseup", this._onmouseup, this); + vButton.removeEventListener("mouseout", this._onmouseup, this); + + this._textfield.selectAll(); + this._textfield.setFocused(true); + + this._timer.stop(); + this._intervalIncrease = null; +} + +qx.Proto._onmousewheel = function(e) +{ + this._manager.setValue(this._manager.getValue() + this.getWheelIncrementAmount() * e.getWheelDelta()); + this._textfield.selectAll(); +} + + + + +/* +--------------------------------------------------------------------------- + OTHER EVENT-HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._oninput = function(e) { + this._checkValue(true, true); +} + +qx.Proto._onchange = function(e) +{ + var vValue = this._manager.getValue(); + + this._textfield.setValue(String(vValue)); + + if (vValue == this.getMin()) + { + this._downbutton.removeState("pressed"); + this._downbutton.setEnabled(false); + this._timer.stop(); + } + else + { + this._downbutton.setEnabled(true); + } + + if (vValue == this.getMax()) + { + this._upbutton.removeState("pressed"); + this._upbutton.setEnabled(false); + this._timer.stop(); + } + else + { + this._upbutton.setEnabled(true); + } + + if (this.hasEventListeners("change")) { + this.dispatchEvent(new qx.event.type.Event("change"), true); + } +} + +qx.Proto._onblur = function(e) { + this._checkValue(false); +} + + + + + + +/* +--------------------------------------------------------------------------- + MAPPING TO RANGE MANAGER +--------------------------------------------------------------------------- +*/ + +qx.Proto.setValue = function(nValue) { + this._manager.setValue(nValue); +} + +qx.Proto.getValue = function() { + this._checkValue(true); + return this._manager.getValue(); +} + +qx.Proto.resetValue = function() { + return this._manager.resetValue(); +} + +qx.Proto.setMax = function(vMax) { + return this._manager.setMax(vMax); +} + +qx.Proto.getMax = function() { + return this._manager.getMax(); +} + +qx.Proto.setMin = function(vMin) { + return this._manager.setMin(vMin); +} + +qx.Proto.getMin = function() { + return this._manager.getMin(); +} + + + + + + + + + +/* +--------------------------------------------------------------------------- + INTERVAL HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._intervalIncrease = null; + +qx.Proto._oninterval = function(e) +{ + this._timer.stop(); + this.setInterval(Math.max(this.getMinTimer(), this.getInterval()-this.getTimerDecrease())); + + if (this._intervalMode == "page") + { + this._pageIncrement(); + } + else + { + if (this.getInterval() == this.getMinTimer()) { + this.setIncrementAmount(this.getAmountGrowth() * this.getIncrementAmount()); + } + + this._increment(); + } + + switch(this._intervalIncrease) + { + case true: + if (this.getValue() == this.getMax()) { + return; + } + + case false: + if (this.getValue() == this.getMin()) { + return; + } + } + + this._timer.restartWith(this.getInterval()); +} + + + + + +/* +--------------------------------------------------------------------------- + UTILITY +--------------------------------------------------------------------------- +*/ + +qx.Proto._checkValue = function(acceptEmpty, acceptEdit) +{ + var el = this._textfield.getElement(); + + if (!el) { + return; + } + + if (el.value == "") + { + if (!acceptEmpty) + { + el.value = this.resetValue(); + this._textfield.selectAll(); + + return; + } + } + else + { + // cache working variable + var val = el.value; + + // fix leading '0' + if (val.length > 1) + { + while(val.charAt(0) == "0") { + val = val.substr(1, val.length); + } + + var f1 = parseInt(val) || 0; + + if (f1 != el.value) { + el.value = f1; + return; + } + } + + // fix for negative integer handling + if (val == "-" && acceptEmpty && this.getMin() < 0) + { + if (el.value != val) { + el.value = val; + } + + return; + } + + // parse the string + val = parseInt(val); + + // main check routine + var doFix = true; + var fixedVal = this._manager._checkValue(val); + + if (isNaN(fixedVal)) { + fixedVal = this._manager.getValue(); + } + + // handle empty string + if (acceptEmpty && val == "") + { + doFix = false; + } + else if (!isNaN(val)) + { + // check for editmode in keypress events + if (acceptEdit) + { + // fix min/max values + if (val > fixedVal && !(val > 0 && fixedVal <= 0) && String(val).length < String(fixedVal).length) + { + doFix = false; + } + else if (val < fixedVal && !(val < 0 && fixedVal >= 0) && String(val).length < String(fixedVal).length) + { + doFix = false; + } + } + } + + // apply value fix + if (doFix && el.value != fixedVal) { + el.value = fixedVal; + } + + // inform manager + if (!acceptEdit) { + this._manager.setValue(fixedVal); + } + } +} + +qx.Proto._increment = function() { + this._manager.setValue(this._manager.getValue() + ((this._intervalIncrease ? 1 : - 1) * this.getIncrementAmount())); +} + +qx.Proto._pageIncrement = function() { + this._manager.setValue(this._manager.getValue() + ((this._intervalIncrease ? 1 : - 1) * this.getPageIncrementAmount())); +} + +qx.Proto._resetIncrements = function() +{ + this.resetIncrementAmount(); + this.resetInterval(); +} + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + this.removeEventListener("keypress", this._onkeypress, this); + this.removeEventListener("keydown", this._onkeydown, this); + this.removeEventListener("keyup", this._onkeyup, this); + this.removeEventListener("mousewheel", this._onmousewheel, this); + + if (this._textfield) + { + this._textfield.removeEventListener("blur", this._onblur, this); + this._textfield.removeEventListener("input", this._oninput, this); + this._textfield.dispose(); + this._textfield = null; + } + + if (this._buttonlayout) + { + this._buttonlayout.dispose(); + this._buttonlayout = null; + } + + if (this._upbutton) + { + this._upbutton.removeEventListener("mousedown", this._onmousedown, this); + this._upbutton.dispose(); + this._upbutton = null; + } + + if (this._downbutton) + { + this._downbutton.removeEventListener("mousedown", this._onmousedown, this); + this._downbutton.dispose(); + this._downbutton = null; + } + + if (this._timer) + { + this._timer.removeEventListener("interval", this._oninterval, this); + this._timer.stop(); + this._timer.dispose(); + this._timer = null; + } + + if (this._manager) + { + this._manager.removeEventListener("change", this._onchange, this); + this._manager.dispose(); + this._manager = null; + } + + return qx.ui.layout.HorizontalBoxLayout.prototype.dispose.call(this); +} \ No newline at end of file diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/TextArea.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/TextArea.js new file mode 100644 index 0000000000..5796713417 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/TextArea.js @@ -0,0 +1,53 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_form) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.form.TextArea", qx.ui.form.TextField, +function(vValue) +{ + qx.ui.form.TextField.call(this, vValue); + + this.setTagName("textarea"); + this.removeHtmlProperty("type"); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "text-area" }); + +qx.OO.addProperty({ name : "wrap", type : "boolean" }); + +if (qx.sys.Client.getInstance().isMshtml()) +{ + qx.Proto._modifyWrap = function(propValue, propOldValue, propData) { + return this.setStyleProperty("whiteSpace", propValue ? "normal" : "nowrap"); + } +} +else +{ + qx.Proto._modifyWrap = function(propValue, propOldValue, propData) { + return this.setHtmlProperty("wrap", propValue ? "soft" : "off"); + } +} + +qx.Proto._computePreferredInnerHeight = function() { + return 60; +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/TextField.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/TextField.js new file mode 100644 index 0000000000..8ab7005128 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/form/TextField.js @@ -0,0 +1,538 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_form) +#require(qx.renderer.font.FontCache) +#after(qx.renderer.font.FontObject) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.form.TextField", qx.ui.basic.Terminator, +function(vValue) +{ + // ************************************************************************ + // INIT + // ************************************************************************ + qx.ui.basic.Terminator.call(this); + + if (typeof vValue === "string") { + this.setValue(vValue); + } + + + // ************************************************************************ + // BEHAVIOR + // ************************************************************************ + this.setTagName("input"); + this.setHtmlProperty("type", "text"); + this.setHtmlAttribute("autocomplete", "OFF"); + this.setTabIndex(1); + this.setSelectable(true); + + + // ************************************************************************ + // EVENTS + // ************************************************************************ + this.enableInlineEvent("input"); + + this.addEventListener("blur", this._onblur); + this.addEventListener("focus", this._onfocus); +}); + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "text-field" }); + +qx.OO.addProperty({ name : "value", type : "string", defaultValue : "" }); +qx.OO.addProperty({ name : "maxLength", type : "number" }); +qx.OO.addProperty({ name : "readOnly", type : "boolean" }); + +qx.OO.addProperty({ name : "selectionStart", type : "number" }); +qx.OO.addProperty({ name : "selectionLength", type : "number" }); +qx.OO.addProperty({ name : "selectionText", type : "string" }); + +qx.OO.addProperty({ name : "validator", type : "function" }); + +/*! + The font property describes how to paint the font on the widget. +*/ +qx.OO.addProperty({ name : "font", type : "object", instance : "qx.renderer.font.Font", convert : qx.renderer.font.FontCache, allowMultipleArguments : true }); + + + + +/* +--------------------------------------------------------------------------- + CLONING +--------------------------------------------------------------------------- +*/ + +// Extend ignore list with selection properties +qx.Proto._clonePropertyIgnoreList += ",selectionStart,selectionLength,selectionText"; + + + +/* +--------------------------------------------------------------------------- + MODIFIERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyEnabled = function(propValue, propOldValue, propData) +{ + propValue ? this.removeHtmlAttribute("disabled") : this.setHtmlAttribute("disabled", "disabled"); + return qx.ui.basic.Terminator.prototype._modifyEnabled.call(this, propValue, propOldValue, propData); +} + +qx.Proto._modifyValue = function(propValue, propOldValue, propData) +{ + this._inValueProperty = true; + this.setHtmlProperty(propData.name, propValue == null ? "" : propValue); + delete this._inValueProperty; + + return true; +} + +qx.Proto._modifyMaxLength = function(propValue, propOldValue, propData) { + return propValue ? this.setHtmlProperty(propData.name, propValue) : this.removeHtmlProperty(propData.name); +} + +qx.Proto._modifyReadOnly = function(propValue, propOldValue, propData) { + return propValue ? this.setHtmlProperty(propData.name, propData.name) : this.removeHtmlProperty(propData.name); +} + +qx.Proto._modifyFont = function(propValue, propOldValue, propData) +{ + this._invalidatePreferredInnerDimensions(); + + if (propValue) { + propValue._applyWidget(this); + } else if (propOldValue) { + propOldValue._resetWidget(this); + } + + return true; +} + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getComputedValue = function(e) +{ + this._visualPropertyCheck(); + return this.getElement().value; +} + + + + + +/* +--------------------------------------------------------------------------- + VALIDATION +--------------------------------------------------------------------------- +*/ + +qx.ui.form.TextField.createRegExpValidator = function(vRegExp) +{ + return function(s) { + return vRegExp.test(s); + } +} + +qx.Proto.isValid = function() +{ + var vValidator = this.getValidator(); + return !vValidator || vValidator(this.getValue()); +} + +qx.Proto.isComputedValid = function() +{ + var vValidator = this.getValidator(); + return !vValidator || vValidator(this.getComputedValue()); +} + + + + + + +/* +--------------------------------------------------------------------------- + PREFERRED DIMENSIONS +--------------------------------------------------------------------------- +*/ + +qx.Proto._computePreferredInnerWidth = function() { + return 120; +} + +qx.Proto._computePreferredInnerHeight = function() { + return 15; +} + + + + + +/* +--------------------------------------------------------------------------- + BROWSER QUIRKS +--------------------------------------------------------------------------- +*/ + +if (qx.sys.Client.getInstance().isMshtml()) +{ + qx.Proto._firstInputFixApplied = false; + + qx.Proto._afterAppear = function() + { + qx.ui.basic.Terminator.prototype._afterAppear.call(this); + + if (!this._firstInputFixApplied) { + qx.client.Timer.once(this._ieFirstInputFix, this, 1); + } + } + + /*! + Fix IE's input event for filled text fields + */ + qx.Proto._ieFirstInputFix = function() + { + this._inValueProperty = true; + this.getElement().value = this.getValue() === null ? "" : this.getValue(); + this._firstInputFixApplied = true; + delete this._inValueProperty; + } +} + + + + + + + + +/* +--------------------------------------------------------------------------- + EVENT-HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._textOnFocus = null; + +qx.Proto._ontabfocus = function(e) { + this.selectAll(); +} + +qx.Proto._onfocus = function(e) { + this._textOnFocus = this.getComputedValue(); +} + +qx.Proto._onblur = function(e) +{ + var vValue = this.getComputedValue().toString(); + + if (this._textOnFocus != vValue) { + this.setValue(vValue); + } + + this.setSelectionLength(0); +} + + + + + + + +/* +--------------------------------------------------------------------------- + CROSS-BROWSER SELECTION HANDLING +--------------------------------------------------------------------------- +*/ + +if (qx.sys.Client.getInstance().isMshtml()) +{ + /*! + Microsoft Documentation: + http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/createrange.asp + http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/obj_textrange.asp + */ + + qx.Proto._getRange = function() + { + this._visualPropertyCheck(); + return this.getElement().createTextRange(); + } + + qx.Proto._getSelectionRange = function() + { + this._visualPropertyCheck(); + return this.getTopLevelWidget().getDocumentElement().selection.createRange(); + } + + qx.Proto.setSelectionStart = function(vStart) + { + this._visualPropertyCheck(); + + var vText = this.getElement().value; + + // a bit hacky, special handling for line-breaks + var i = 0; + while (i vOldLength) + { + for (var i=vOldLength; i vNewLength) + { + vData.splice(vNewLength, vOldLength - vNewLength); + } +} + + + + + + +/* +--------------------------------------------------------------------------- + GRID SETUP: COLUMNS +--------------------------------------------------------------------------- +*/ + +qx.Proto._columnCount = 0; + +qx.Proto.setColumnCount = function(vCount) +{ + this._columnCount = vCount; + this._syncColumnDataFields(); +} + +qx.Proto.getColumnCount = function() { + return this._columnCount; +} + +qx.Proto.addColumn = function() +{ + this._columnCount++; + this._syncColumnDataFields(); +} + +qx.Proto.removeColumn = function() +{ + if (this._columnCount > 0) + { + this._columnCount--; + this._syncColumnDataFields(); + } +} + +qx.Proto._syncColumnDataFields = function() +{ + var vData = this._columnData; + var vOldLength = vData.length; + var vNewLength = this._columnCount; + + this._syncDataFields(vData, vOldLength, vNewLength); +} + + + + + +/* +--------------------------------------------------------------------------- + GRID SETUP: ROWS +--------------------------------------------------------------------------- +*/ + +qx.Proto._rowCount = 0; + +qx.Proto.setRowCount = function(vCount) +{ + this._rowCount = vCount; + this._syncRowDataFields(); +} + +qx.Proto.getRowCount = function() { + return this._rowCount; +} + +qx.Proto.addRow = function() +{ + this._rowCount++; + this._syncRowDataFields(); +} + +qx.Proto.removeRow = function() +{ + if (this._rowCount > 0) + { + this._rowCount--; + this._syncRowDataFields(); + } +} + +qx.Proto._syncRowDataFields = function() +{ + var vData = this._rowData; + var vOldLength = vData.length; + var vNewLength = this._rowCount; + + this._syncDataFields(vData, vOldLength, vNewLength); +} + + + + + + + +/* +--------------------------------------------------------------------------- + DATA HANDLING: COLUMNS +--------------------------------------------------------------------------- +*/ + +qx.Proto._getColumnProperty = function(vColumnIndex, vProperty) +{ + try + { + return this._columnData[vColumnIndex][vProperty] || null; + } + catch(ex) + { + this.error("Error while getting column property (" + vColumnIndex + "|" + vProperty + ")", ex); + return null; + } +} + +qx.Proto._setupColumnProperty = function(vColumnIndex, vProperty, vValue) +{ + this._columnData[vColumnIndex][vProperty] = vValue; + this._invalidateColumnLayout(); +} + +qx.Proto._removeColumnProperty = function(vColumnIndex, vProperty, vValue) +{ + delete this._columnData[vColumnIndex][vProperty]; + this._invalidateColumnLayout(); +} + +qx.Proto._invalidateColumnLayout = function() +{ + if (!this._initialLayoutDone || !this._isDisplayable) { + return; + } + + this.forEachVisibleChild(function() { + this.addToQueue("width"); + }); +} + + + + + + +/* +--------------------------------------------------------------------------- + DATA HANDLING: ROWS +--------------------------------------------------------------------------- +*/ + +qx.Proto._getRowProperty = function(vRowIndex, vProperty) +{ + try + { + return this._rowData[vRowIndex][vProperty] || null; + } + catch(ex) + { + this.error("Error while getting row property (" + vRowIndex + "|" + vProperty + ")", ex); + return null; + } +} + +qx.Proto._setupRowProperty = function(vRowIndex, vProperty, vValue) +{ + this._rowData[vRowIndex][vProperty] = vValue; + this._invalidateRowLayout(); +} + +qx.Proto._removeRowProperty = function(vRowIndex, vProperty, vValue) +{ + delete this._rowData[vRowIndex][vProperty]; + this._invalidateRowLayout(); +} + +qx.Proto._invalidateRowLayout = function() +{ + if (!this._initialLayoutDone || !this._isDisplayable) { + return; + } + + this.forEachVisibleChild(function() { + this.addToQueue("height"); + }); +} + + + + + + +/* +--------------------------------------------------------------------------- + UTILITIES: CELL DIMENSIONS +--------------------------------------------------------------------------- +*/ + +// SETTER + +qx.Proto.setColumnWidth = function(vIndex, vValue) +{ + this._setupColumnProperty(vIndex, "widthValue", vValue); + + var vType = qx.ui.core.Parent.prototype._evalUnitsPixelPercentAutoFlex(vValue); + + this._setupColumnProperty(vIndex, "widthType", vType); + + var vParsed, vComputed; + + switch(vType) + { + case qx.ui.core.Widget.TYPE_PIXEL: + vParsed = vComputed = Math.round(vValue); + break; + + case qx.ui.core.Widget.TYPE_PERCENT: + case qx.ui.core.Widget.TYPE_FLEX: + vParsed = parseFloat(vValue); + vComputed = null; + break; + + case qx.ui.core.Widget.TYPE_AUTO: + vParsed = vComputed = null; + break; + + default: + vParsed = vComputed = null; + } + + this._setupColumnProperty(vIndex, "widthParsed", vParsed); + this._setupColumnProperty(vIndex, "widthComputed", vComputed); +} + +qx.Proto.setRowHeight = function(vIndex, vValue) +{ + this._setupRowProperty(vIndex, "heightValue", vValue); + + var vType = qx.ui.core.Widget.prototype._evalUnitsPixelPercentAutoFlex(vValue); + this._setupRowProperty(vIndex, "heightType", vType); + + var vParsed, vComputed; + + switch(vType) + { + case qx.ui.core.Widget.TYPE_PIXEL: + vParsed = vComputed = Math.round(vValue); + break; + + case qx.ui.core.Widget.TYPE_PERCENT: + case qx.ui.core.Widget.TYPE_FLEX: + vParsed = parseFloat(vValue); + vComputed = null; + break; + + case qx.ui.core.Widget.TYPE_AUTO: + vParsed = vComputed = null; + break; + + default: + vParsed = vComputed = null; + } + + this._setupRowProperty(vIndex, "heightParsed", vParsed); + this._setupRowProperty(vIndex, "heightComputed", vComputed); +} + + + +// GETTER: BOX + +qx.Proto.getColumnBoxWidth = function(vIndex) +{ + var vComputed = this._getColumnProperty(vIndex, "widthComputed"); + + if (vComputed != null) { + return vComputed; + } + + var vType = this._getColumnProperty(vIndex, "widthType"); + var vParsed = this._getColumnProperty(vIndex, "widthParsed"); + var vComputed = null; + + switch(vType) + { + case qx.ui.core.Widget.TYPE_PIXEL: + vComputed = Math.max(0, vParsed); + break; + + case qx.ui.core.Widget.TYPE_PERCENT: + vComputed = this.getInnerWidth() * Math.max(0, vParsed) * 0.01; + break; + + case qx.ui.core.Widget.TYPE_AUTO: + // TODO + vComputed = null; + break; + + case qx.ui.core.Widget.TYPE_FLEX: + // TODO + vComputed = null; + break; + } + + this._setupColumnProperty(vIndex, "widthComputed", vComputed); + return vComputed; +} + +qx.Proto.getRowBoxHeight = function(vIndex) +{ + var vComputed = this._getRowProperty(vIndex, "heightComputed"); + + if (vComputed != null) { + return vComputed; + } + + var vType = this._getRowProperty(vIndex, "heightType"); + var vParsed = this._getRowProperty(vIndex, "heightParsed"); + var vComputed = null; + + switch(vType) + { + case qx.ui.core.Widget.TYPE_PIXEL: + vComputed = Math.max(0, vParsed); + break; + + case qx.ui.core.Widget.TYPE_PERCENT: + vComputed = this.getInnerHeight() * Math.max(0, vParsed) * 0.01; + break; + + case qx.ui.core.Widget.TYPE_AUTO: + // TODO + vComputed = null; + break; + + case qx.ui.core.Widget.TYPE_FLEX: + // TODO + vComputed = null; + break; + } + + this._setupRowProperty(vIndex, "heightComputed", vComputed); + return vComputed; +} + + +// GETTER: PADDING + +qx.Proto.getComputedCellPaddingLeft = function(vCol, vRow) { + return this.getColumnPaddingLeft(vCol) || this.getRowPaddingLeft(vRow) || this.getCellPaddingLeft() || 0; +} + +qx.Proto.getComputedCellPaddingRight = function(vCol, vRow) { + return this.getColumnPaddingRight(vCol) || this.getRowPaddingRight(vRow) || this.getCellPaddingRight() || 0; +} + +qx.Proto.getComputedCellPaddingTop = function(vCol, vRow) { + return this.getRowPaddingTop(vRow) || this.getColumnPaddingTop(vCol) || this.getCellPaddingTop() || 0; +} + +qx.Proto.getComputedCellPaddingBottom = function(vCol, vRow) { + return this.getRowPaddingBottom(vRow) || this.getColumnPaddingBottom(vCol) || this.getCellPaddingBottom() || 0; +} + + +// GETTER: INNER + +qx.Proto.getColumnInnerWidth = function(vCol, vRow) { + return this.getColumnBoxWidth(vCol) - this.getComputedCellPaddingLeft(vCol, vRow) - this.getComputedCellPaddingRight(vCol, vRow); +} + +qx.Proto.getRowInnerHeight = function(vCol, vRow) { + return this.getRowBoxHeight(vRow) - this.getComputedCellPaddingTop(vCol, vRow) - this.getComputedCellPaddingBottom(vCol, vRow); +} + + + + + + + + +/* +--------------------------------------------------------------------------- + UTILITIES: CELL ALIGNMENT +--------------------------------------------------------------------------- +*/ + +// SETTER + +qx.Proto.setColumnHorizontalAlignment = function(vIndex, vValue) { + this._setupColumnProperty(vIndex, "horizontalAlignment", vValue); +} + +qx.Proto.setColumnVerticalAlignment = function(vIndex, vValue) { + this._setupColumnProperty(vIndex, "verticalAlignment", vValue); +} + +qx.Proto.setRowHorizontalAlignment = function(vIndex, vValue) { + this._setupRowProperty(vIndex, "horizontalAlignment", vValue); +} + +qx.Proto.setRowVerticalAlignment = function(vIndex, vValue) { + this._setupRowProperty(vIndex, "verticalAlignment", vValue); +} + + + +// GETTER + +qx.Proto.getColumnHorizontalAlignment = function(vIndex) { + return this._getColumnProperty(vIndex, "horizontalAlignment"); +} + +qx.Proto.getColumnVerticalAlignment = function(vIndex) { + return this._getColumnProperty(vIndex, "verticalAlignment"); +} + +qx.Proto.getRowHorizontalAlignment = function(vIndex) { + return this._getRowProperty(vIndex, "horizontalAlignment"); +} + +qx.Proto.getRowVerticalAlignment = function(vIndex) { + return this._getRowProperty(vIndex, "verticalAlignment"); +} + + + + + + +/* +--------------------------------------------------------------------------- + UTILITIES: CELL PADDING +--------------------------------------------------------------------------- +*/ + +// SETTER + +qx.Proto.setColumnPaddingTop = function(vIndex, vValue) { + this._setupColumnProperty(vIndex, "paddingTop", vValue); +} + +qx.Proto.setColumnPaddingRight = function(vIndex, vValue) { + this._setupColumnProperty(vIndex, "paddingRight", vValue); +} + +qx.Proto.setColumnPaddingBottom = function(vIndex, vValue) { + this._setupColumnProperty(vIndex, "paddingBottom", vValue); +} + +qx.Proto.setColumnPaddingLeft = function(vIndex, vValue) { + this._setupColumnProperty(vIndex, "paddingLeft", vValue); +} + +qx.Proto.setRowPaddingTop = function(vIndex, vValue) { + this._setupRowProperty(vIndex, "paddingTop", vValue); +} + +qx.Proto.setRowPaddingRight = function(vIndex, vValue) { + this._setupRowProperty(vIndex, "paddingRight", vValue); +} + +qx.Proto.setRowPaddingBottom = function(vIndex, vValue) { + this._setupRowProperty(vIndex, "paddingBottom", vValue); +} + +qx.Proto.setRowPaddingLeft = function(vIndex, vValue) { + this._setupRowProperty(vIndex, "paddingLeft", vValue); +} + + + +// GETTER + +qx.Proto.getColumnPaddingTop = function(vIndex) { + return this._getColumnProperty(vIndex, "paddingTop"); +} + +qx.Proto.getColumnPaddingRight = function(vIndex) { + return this._getColumnProperty(vIndex, "paddingRight"); +} + +qx.Proto.getColumnPaddingBottom = function(vIndex) { + return this._getColumnProperty(vIndex, "paddingBottom"); +} + +qx.Proto.getColumnPaddingLeft = function(vIndex) { + return this._getColumnProperty(vIndex, "paddingLeft"); +} + +qx.Proto.getRowPaddingTop = function(vIndex) { + return this._getRowProperty(vIndex, "paddingTop"); +} + +qx.Proto.getRowPaddingRight = function(vIndex) { + return this._getRowProperty(vIndex, "paddingRight"); +} + +qx.Proto.getRowPaddingBottom = function(vIndex) { + return this._getRowProperty(vIndex, "paddingBottom"); +} + +qx.Proto.getRowPaddingLeft = function(vIndex) { + return this._getRowProperty(vIndex, "paddingLeft"); +} + + + + + + +/* +--------------------------------------------------------------------------- + DIMENSION CACHE +--------------------------------------------------------------------------- +*/ + +qx.Proto._changeInnerWidth = function(vNew, vOld) +{ + for (var i=0, l=this.getColumnCount(); i 0; +} + +qx.Proto.getSpanEntry = function(vCol, vRow) +{ + for (var i=0, s=this._spans, l=s.length, c; i= c.startCol && vCol <= c.endCol && vRow >= c.startRow && vRow <= c.endRow) { + return c; + } + } + + return null; +} + +qx.Proto.isSpanStart = function(vCol, vRow) +{ + for (var i=0, s=this._spans, l=s.length, c; i= c.startCol && vCol <= c.endCol && vRow >= c.startRow && vRow <= c.endRow) { + return true; + } + } + + return false; +} + +qx.Proto.isFillCell = function(vCol, vRow) +{ + for (var i=0, s=this._spans, l=s.length, c; i= c.startCol && vCol <= c.endCol && vRow >= c.startRow && vRow <= c.endRow && (vCol > c.startCol || vRow > c.startRow)) { + return true; + } + } + + return false; +} + +qx.Proto._collidesWithSpans = function(vStartCol, vStartRow, vEndCol, vEndRow) +{ + for (var i=0, s=this._spans, l=s.length, c; i= c.startCol && vStartCol <= c.endCol && vEndRow >= c.startRow && vStartRow <= c.endRow ) { + return true; + } + } + + return false; +} + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + + delete this._columnData; + delete this._rowData; + + delete this._spans; + + return qx.ui.core.Parent.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/layout/HorizontalBoxLayout.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/layout/HorizontalBoxLayout.js new file mode 100644 index 0000000000..8eb08fec65 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/layout/HorizontalBoxLayout.js @@ -0,0 +1,29 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_basic) +#module(ui_layout) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.layout.HorizontalBoxLayout", qx.ui.layout.BoxLayout, +function() { + qx.ui.layout.BoxLayout.call(this, "horizontal"); +}); diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/layout/VerticalBoxLayout.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/layout/VerticalBoxLayout.js new file mode 100644 index 0000000000..9b188f613a --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/layout/VerticalBoxLayout.js @@ -0,0 +1,29 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_basic) +#module(ui_layout) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.layout.VerticalBoxLayout", qx.ui.layout.BoxLayout, +function() { + qx.ui.layout.BoxLayout.call(this, "vertical"); +}); diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellHtml.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellHtml.js new file mode 100644 index 0000000000..ed73e294cb --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellHtml.js @@ -0,0 +1,37 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_listview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.listview.ContentCellHtml", qx.ui.embed.HtmlEmbed, +function(vHtml) +{ + qx.ui.embed.HtmlEmbed.call(this, vHtml); + + this.setSelectable(false); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "list-view-content-cell-html" }); + +qx.ui.listview.ContentCellHtml.empty = { + html : "" +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellIconHtml.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellIconHtml.js new file mode 100644 index 0000000000..7203299e38 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellIconHtml.js @@ -0,0 +1,39 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_listview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.listview.ContentCellIconHtml", qx.ui.embed.IconHtmlEmbed, +function(vHtml, vIcon, vIconWidth, vIconHeight) +{ + qx.ui.embed.IconHtmlEmbed.call(this, vHtml, vIcon, vIconWidth, vIconHeight); + + this.setSelectable(false); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "list-view-content-cell-icon-html" }); + +qx.ui.listview.ContentCellIconHtml.empty = +{ + icon : "", + html : "" +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellImage.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellImage.js new file mode 100644 index 0000000000..421f2e0f43 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellImage.js @@ -0,0 +1,57 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_listview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.listview.ContentCellImage", qx.ui.basic.Image, +function(vSource, vWidth, vHeight) { + qx.ui.basic.Image.call(this, vSource, vWidth, vHeight); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "list-view-content-cell-image" }); + +qx.ui.listview.ContentCellImage.empty = { + source : "static/image/blank.gif" +} + + + +/* +--------------------------------------------------------------------------- + CUSTOM SETTER +--------------------------------------------------------------------------- +*/ + +qx.Proto.setSource = function(vSource) +{ + if (this._initialLayoutDone) + { + return this._updateContent(qx.manager.object.AliasManager.getInstance().resolvePath(vSource == "" ? "static/image/blank.gif" : vSource)); + } + else + { + return qx.ui.basic.Image.prototype.setSource.call(this, vSource); + } +} + +// Omit dimension setup in list-view +qx.Proto._postApplyDimensions = qx.util.Return.returnTrue; diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellLink.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellLink.js new file mode 100644 index 0000000000..b53338a595 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellLink.js @@ -0,0 +1,40 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_listview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.listview.ContentCellLink", qx.ui.embed.LinkEmbed, +function(vHtml) +{ + qx.ui.embed.LinkEmbed.call(this, vHtml); + + // selectable = false will break links in gecko based browsers + this.setSelectable(true); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "list-view-content-cell-link" }); + +qx.ui.listview.ContentCellLink.empty = +{ + html : "", + uri : "#" +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellText.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellText.js new file mode 100644 index 0000000000..2d4b28544f --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/ContentCellText.js @@ -0,0 +1,40 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_listview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.listview.ContentCellText", qx.ui.embed.TextEmbed, +function(vText) +{ + qx.ui.embed.TextEmbed.call(this, vText); + + this.setStyleProperty("whiteSpace", "nowrap"); + this.setStyleProperty("textOverflow", "ellipsis"); + + this.setSelectable(false); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "list-view-content-cell-text" }); + +qx.ui.listview.ContentCellText.empty = { + text : "" +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/Header.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/Header.js new file mode 100644 index 0000000000..5d11d5bdc0 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/Header.js @@ -0,0 +1,294 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_listview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.listview.Header", qx.ui.layout.HorizontalBoxLayout, +function(vColumns) +{ + qx.ui.layout.HorizontalBoxLayout.call(this); + + // This fixes the innerWidth calculation difference between the grid(pane) and the head. + this.setPaddingRight(qx.ui.core.Widget.SCROLLBAR_SIZE); + + + // ************************************************************************ + // STORE REFERENCE TO CONFIG ENTRY + // ************************************************************************ + this._columns = vColumns; + + + // ************************************************************************ + // CREATE HEADER CELLS + // ************************************************************************ + var vHeadCell, vHeadSeparator; + + for (var vCol in vColumns) + { + vHeadCell = new qx.ui.listview.HeaderCell(vColumns[vCol], vCol); + vHeadSeparator = new qx.ui.listview.HeaderSeparator; + + this.add(vHeadCell, vHeadSeparator); + + if (vColumns[vCol].align) { + vHeadCell.setHorizontalChildrenAlign(vColumns[vCol].align); + + if (vColumns[vCol].align == "right") { + vHeadCell.setReverseChildrenOrder(true); + } + } + + // store some additional data + vColumns[vCol].contentClass = qx.OO.classes["qx.ui.listview.ContentCell" + qx.lang.String.toFirstUp(vColumns[vCol].type || "text")]; + vColumns[vCol].headerCell = vHeadCell; + } + + + // ************************************************************************ + // ADD EVENT LISTENERS + // ************************************************************************ + this.addEventListener("mousemove", this._onmousemove); + this.addEventListener("mousedown", this._onmousedown); + this.addEventListener("mouseup", this._onmouseup); + this.addEventListener("mouseout", this._onmouseout); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "list-view-header" }); + + + +/* +--------------------------------------------------------------------------- + RESIZE SYNC +--------------------------------------------------------------------------- +*/ + +qx.Proto._syncColumnWidth = function(vWidth) +{ + var vChildren = this.getChildren(); + var vColumn = Math.ceil(vChildren.indexOf(this._resizeCell) / 2); + + this.getParent().getPane().setColumnWidth(vColumn, vWidth); +} + +qx.Proto._syncResizeLine = function() +{ + qx.ui.core.Widget.flushGlobalQueues(); + + var vParent = this.getParent(); + var vLine = vParent.getResizeLine(); + var vLeft = qx.dom.Location.getPageBoxLeft(this._resizeSeparator.getElement()) - qx.dom.Location.getPageInnerLeft(this.getElement()); + var vTop = qx.dom.Dimension.getBoxHeight(vParent.getHeader().getElement()); + var vHeight = qx.dom.Dimension.getBoxHeight(vParent.getElement()) - vTop; + + vLine._applyRuntimeTop(vTop); + vLine._applyRuntimeHeight(vHeight); + vLine._applyRuntimeLeft(vLeft); + + vLine.removeStyleProperty("visibility"); +} + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._mshtml = qx.sys.Client.getInstance().isMshtml(); + +qx.Proto._onmousemove = function(e) +{ + if (!this.getParent().getResizable()) { + return; + } + + if (this._resizingActive) + { + // Slow down mshtml a bit + if (this._mshtml) + { + if ((new Date).valueOf() - this._last < 50) { + return; + } + + this._last = (new Date).valueOf(); + } + + var vNewLeft = e.getPageX(); + var vSizeDiff = vNewLeft - this._resizeStart; + var vCell = this._resizeCell; + + vCell.setWidth(Math.max(4, vCell.getWidth() + vSizeDiff)); + this._resizeStart = vNewLeft; + + if (this.getParent().getLiveResize()) + { + this._syncColumnWidth(vCell._computeBoxWidth()); + } + else + { + this._syncResizeLine(); + } + } + else + { + var vTarget = e.getTarget(); + var vEventPos = e.getPageX(); + var vTargetPosLeft = qx.dom.Location.getPageBoxLeft(vTarget.getElement()); + var vTargetPosRight = vTargetPosLeft + qx.dom.Dimension.getBoxWidth(vTarget.getElement()); + + var vResizeCursor = false; + var vResizeSeparator = null; + + if (vTarget instanceof qx.ui.listview.HeaderSeparator) + { + vResizeCursor = true; + vResizeSeparator = vTarget; + } + else if ((vEventPos - vTargetPosLeft) <= 10) + { + // Ignore first column + if (!vTarget.isFirstChild()) + { + vResizeCursor = true; + vResizeSeparator = vTarget.getPreviousSibling(); + } + } + else if ((vTargetPosRight - vEventPos) <= 10) + { + vResizeCursor = true; + vResizeSeparator = vTarget.getNextSibling(); + } + + if (!(vResizeSeparator instanceof qx.ui.listview.HeaderSeparator)) + { + vResizeSeparator = vTarget = vResizeCursor = null; + } + + // Check if child is marked as resizable + else if (vResizeSeparator) + { + var vResizeCell = vResizeSeparator.getPreviousSibling(); + + if (vResizeCell && (vResizeCell._computedWidthTypePercent || vResizeCell._config.resizable == false)) { + vResizeSeparator = vTarget = vResizeCursor = null; + } + } + + // Apply global cursor + this.getTopLevelWidget().setGlobalCursor(vResizeCursor ? "e-resize" : null); + + // Store data for mousedown + this._resizeSeparator = vResizeSeparator; + this._resizeTarget = vTarget; + } +} + +qx.Proto._onmousedown = function(e) +{ + if (!this._resizeSeparator) { + return; + } + + this._resizingActive = true; + this._resizeStart = e.getPageX(); + this._resizeCell = this._resizeSeparator.getPreviousSibling(); + + if (!this.getParent().getLiveResize()) { + this._syncResizeLine(); + } + + this.setCapture(true); +} + +qx.Proto._onmouseup = function(e) +{ + if (!this._resizingActive) { + return; + } + + this._syncColumnWidth(this._resizeCell.getBoxWidth()); + + this.setCapture(false); + this.getTopLevelWidget().setGlobalCursor(null); + + // Remove hover effect + this._resizeTarget.removeState("over"); + + // Hide resize line + this.getParent().getResizeLine().setStyleProperty("visibility", "hidden"); + + this._cleanupResizing(); +} + +qx.Proto._onmouseout = function(e) +{ + if (!this.getCapture()) { + this.getTopLevelWidget().setGlobalCursor(null); + } +} + +qx.Proto._cleanupResizing = function() +{ + delete this._resizingActive; + + delete this._resizeSeparator; + delete this._resizeTarget; + delete this._resizeStart; + delete this._resizeCell; +} + + + + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + this._cleanupResizing(); + + this.removeEventListener("mousemove", this._onmousemove); + this.removeEventListener("mousedown", this._onmousedown); + this.removeEventListener("mouseup", this._onmouseup); + this.removeEventListener("mouseout", this._onmouseout); + + this._columns = null; + + return qx.ui.layout.HorizontalBoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/HeaderCell.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/HeaderCell.js new file mode 100644 index 0000000000..46e198b02b --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/HeaderCell.js @@ -0,0 +1,255 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_listview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.listview.HeaderCell", qx.ui.basic.Atom, +function(vConfig, vId) +{ + qx.ui.basic.Atom.call(this, vConfig.label, vConfig.icon, vConfig.iconWidth, vConfig.iconHeight, vConfig.flash); + + // Text Overflow + this.setStyleProperty("textOverflow", "ellipsis"); + + + // ************************************************************************ + // STORE REFERENCE TO CONFIG ENTRY + // ************************************************************************ + this._config = vConfig; + this._id = vId; + + + // ************************************************************************ + // ARGUMENTS + // ************************************************************************ + this.setWidth(typeof vConfig.width === "undefined" ? "auto" : vConfig.width); + + if (qx.util.Validation.isValid(vConfig.minWidth)) { + this.setMinWidth(vConfig.minWidth); + } + + if (qx.util.Validation.isValid(vConfig.maxWidth)) { + this.setMaxWidth(vConfig.maxWidth); + } + + + // ************************************************************************ + // ADDITIONAL CHILDREN + // ************************************************************************ + + // Re-Enable flex support + this.getLayoutImpl().setEnableFlexSupport(true); + + this._spacer = new qx.ui.basic.HorizontalSpacer; + + this._arrowup = new qx.ui.basic.Image("widget/arrows/up.gif"); + this._arrowup.setVerticalAlign("middle"); + this._arrowup.setDisplay(false); + + this._arrowdown = new qx.ui.basic.Image("widget/arrows/down.gif"); + this._arrowdown.setVerticalAlign("middle"); + this._arrowdown.setDisplay(false); + + this.add(this._spacer, this._arrowup, this._arrowdown); + + + // ************************************************************************ + // EVENTS + // ************************************************************************ + + this.addEventListener("mouseup", this._onmouseup); + this.addEventListener("mouseover", this._onmouseover); + this.addEventListener("mouseout", this._onmouseout); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "list-view-header-cell" }); +qx.OO.addProperty({ name : "sortOrder", type : "string", allowNull : true, possibleValues : [ "ascending", "descending" ] }); + +qx.Class.C_SORT_ASCENDING = "ascending"; +qx.Class.C_SORT_DESCENDING = "descending"; + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getView = function() { + return this.getParent().getParent(); +} + +qx.Proto.getNextSortOrder = function() +{ + var vCurrentSortOrder = this.getSortOrder(); + + switch(vCurrentSortOrder) + { + case qx.ui.listview.HeaderCell.C_SORT_ASCENDING: + return qx.ui.listview.HeaderCell.C_SORT_DESCENDING; + + default: + return qx.ui.listview.HeaderCell.C_SORT_ASCENDING; + } +} + +qx.Proto.updateSort = function() +{ + + var vListView = this.getView(); + var vData = vListView.getData(); + var vFieldId = this._id; + var vSortProp = this._config.sortProp || "text"; + var vSortMethod = this._config.sortMethod || qx.util.Compare.byString; + + vData.sort(function(a, b) { + return vSortMethod(a[vFieldId][vSortProp], b[vFieldId][vSortProp]); + }); + + if (this.getSortOrder() == qx.ui.listview.HeaderCell.C_SORT_DESCENDING) { + vData.reverse(); + } +} + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifySortOrder = function(propValue, propOldValue, propData) +{ + var vListView = this.getView(); + + switch(propValue) + { + case qx.ui.listview.HeaderCell.C_SORT_ASCENDING: + this._arrowup.setDisplay(true); + this._arrowdown.setDisplay(false); + + vListView.setSortBy(this._id); + break; + + case qx.ui.listview.HeaderCell.C_SORT_DESCENDING: + this._arrowup.setDisplay(false); + this._arrowdown.setDisplay(true); + + vListView.setSortBy(this._id); + break; + + default: + this._arrowup.setDisplay(false); + this._arrowdown.setDisplay(false); + + if (vListView.getSortBy() == this._id) { + vListView.setSortBy(null); + } + } + + if (propValue) + { + this.updateSort(); + vListView.update(); + } + + return true; +} + + + + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmouseover = function(e) { + this.addState("over"); +} + +qx.Proto._onmouseout = function(e) { + this.removeState("over"); +} + +qx.Proto._onmouseup = function(e) +{ + if (!this._config.sortable || this.getParent()._resizeSeparator) { + return; + } + + this.setSortOrder(this.getNextSortOrder()); + e.stopPropagation(); +} + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + delete this._config; + + if (this._spacer) + { + this._spacer.dispose(); + this._spacer = null; + } + + if (this._arrowup) + { + this._arrowup.dispose(); + this._arrowup = null; + } + + if (this._arrowdown) + { + this._arrowdown.dispose(); + this._arrowdown = null; + } + + this.removeEventListener("mouseup", this._onmouseup); + this.removeEventListener("mouseover", this._onmouseover); + this.removeEventListener("mouseout", this._onmouseout); + + return qx.ui.basic.Atom.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/HeaderSeparator.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/HeaderSeparator.js new file mode 100644 index 0000000000..c2058db5d2 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/HeaderSeparator.js @@ -0,0 +1,30 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_listview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.listview.HeaderSeparator", qx.ui.basic.Terminator, +function() { + qx.ui.basic.Terminator.call(this); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "list-view-header-separator" }); diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/ListView.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/ListView.js new file mode 100644 index 0000000000..567df4075e --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/ListView.js @@ -0,0 +1,373 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_listview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.listview.ListView", qx.ui.layout.VerticalBoxLayout, +function(vData, vColumns) +{ + // ************************************************************************ + // REFERENCES + // ************************************************************************ + + this._data = vData; + this._columns = vColumns; + + + + // ************************************************************************ + // OBJECTS + // ************************************************************************ + + this._header = new qx.ui.listview.Header(vColumns); + this._frame = new qx.ui.layout.HorizontalBoxLayout; + this._pane = new qx.ui.listview.ListViewPane(vData, vColumns); + this._scroll = new qx.ui.layout.CanvasLayout; + this._scrollContent = new qx.ui.basic.Terminator; + this._resizeLine = new qx.ui.basic.Terminator; + + + + // ************************************************************************ + // SUPERCLASS CONSTRUCTOR + // ************************************************************************ + + qx.ui.layout.VerticalBoxLayout.call(this); + + + + // ************************************************************************ + // HEADER + // ************************************************************************ + + this._header.setParent(this); + + + + // ************************************************************************ + // FRAME + // ************************************************************************ + + this._frame.setParent(this); + this._frame.setHeight("1*"); + this._frame.setWidth(null); + + + + // ************************************************************************ + // PANE + // ************************************************************************ + + this._pane.setParent(this._frame); + + + + // ************************************************************************ + // SCROLL AREA + // ************************************************************************ + + this._scroll.setWidth("auto"); + this._scroll.setOverflow("scrollY"); + this._scroll.setParent(this._frame); + this._scroll.enableInlineEvent("scroll"); + this._scroll.addEventListener("scroll", this._onscroll, this); + + + + // ************************************************************************ + // SCROLL CONTENT + // ************************************************************************ + + this._scrollContent.setWidth(1); + this._scrollContent.setParent(this._scroll); + + + + + // ************************************************************************ + // RESIZE LINE + // ************************************************************************ + + this._resizeLine.setBackgroundColor("#D6D5D9"); + this._resizeLine.setWidth(1); + this._resizeLine.setParent(this); + + + + // ************************************************************************ + // EVENTS + // ************************************************************************ + + this.addEventListener("mousedown", this._onmousedown); +}); + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "list-view" }); + +qx.OO.addProperty({ name : "resizable", type : "boolean", defaultValue : true }); +qx.OO.addProperty({ name : "liveResize", type : "boolean", defaultValue : false }); +qx.OO.addProperty({ name : "sortBy", type : "string" }); + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getData = function() { + return this._data; +} + +qx.Proto.getColumns = function() { + return this._columns; +} + +qx.Proto.getHeader = function() { + return this._header; +} + +qx.Proto.getFrame = function() { + return this._frame; +} + +qx.Proto.getPane = function() { + return this._pane; +} + +qx.Proto.getScroll = function() { + return this._scroll; +} + +qx.Proto.getScrollContent = function() { + return this._scrollContent; +} + +qx.Proto.getResizeLine = function() { + return this._resizeLine; +} + +qx.Proto.update = function() +{ + this.updateScrollBar(); + this.updateContent(); + + // ignore updateLayout here, as it is mostly initially used +} + +qx.Proto.updateScrollBar = function() { + this._scrollContent.setHeight((this._data.length * this._pane._rowHeight) + this._pane._rowHeight); +} + +/*! + Bugfix for gecko 1.8 (the one released with firefox 1.5) + Overflow updates if content gets smaller are problematic + https://bugzilla.mozilla.org/show_bug.cgi?id=320106 +*/ +if (qx.sys.Client.getInstance().isGecko() && qx.sys.Client.getInstance().getVersion() >= 1.8) +{ + qx.Proto._updateScrollBar = qx.Proto.updateScrollBar; + + qx.Proto.updateScrollBar = function() + { + this._updateScrollBar(); + + this._scroll.setStyleProperty("height", "0px"); + this._scroll.forceHeight(0); + this._scroll.setHeight(null); + } +} + +qx.Proto.updateContent = function() { + this.getPane()._updateRendering(true); +} + +qx.Proto.updateLayout = function() { + this.getPane()._updateLayout(); +} + +qx.Proto.updateSort = function() +{ + var vSortBy = this.getSortBy(); + + if (!vSortBy) { + return; + } + + var vCell = this._getHeaderCell(vSortBy); + + if (vCell) { + vCell.updateSort(); + } +} + +qx.Proto._getHeaderCell = function(vCellId) +{ + var vNewEntry = this._columns[vCellId]; + return vNewEntry ? vNewEntry.headerCell : null; +} + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifySortBy = function(propValue, propOldValue, propData) +{ + if (propOldValue) + { + var vOldCell = this._getHeaderCell(propOldValue); + + if (vOldCell) { + vOldCell.setSortOrder(null); + } + } + + if (propValue) + { + var vNewCell = this._getHeaderCell(propValue); + + if (vNewCell && vNewCell.getSortOrder() == null) { + vNewCell.setSortOrder(qx.ui.listview.HeaderCell.C_SORT_ASCENDING); + } + } + + return true; +} + + + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onscroll = function(e) { + this._pane._onscroll(e); +} + +qx.Proto._onmousedown = function(e) { + this.getFocusRoot().setActiveChild(this.getPane()); +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPLAYBLE HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._handleDisplayableCustom = function(vDisplayable, vParent, vHint) +{ + qx.ui.layout.VerticalBoxLayout.prototype._handleDisplayableCustom.call(this, vDisplayable, vParent, vHint); + + if (vDisplayable) + { + this.updateLayout(); + this.updateScrollBar(); + this.updateContent(); + } +} + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + if (this._header) + { + this._header.dispose(); + this._header = null; + } + + if (this._frame) + { + this._frame.dispose(); + this._frame = null; + } + + if (this._pane) + { + this._pane.dispose(); + this._pane = null; + } + + if (this._scroll) + { + this._scroll.dispose(); + this._scroll = null; + } + + if (this._scrollContent) + { + this._scrollContent.dispose(); + this._scrollContent = null; + } + + if (this._resizeLine) + { + this._resizeLine.dispose(); + this._resizeLine = null; + } + + delete this._columns; + delete this._data; + + this.removeEventListener("mousedown", this._onmousedown); + + return qx.ui.layout.VerticalBoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/ListViewPane.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/ListViewPane.js new file mode 100644 index 0000000000..89ae3c6fea --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/listview/ListViewPane.js @@ -0,0 +1,556 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_listview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.listview.ListViewPane", qx.ui.layout.GridLayout, +function(vData, vColumns) +{ + qx.ui.layout.GridLayout.call(this); + + // ************************************************************************ + // DATA + // ************************************************************************ + // Add aliases for data tables + this._data = vData; + this._columns = vColumns; + + + // ************************************************************************ + // INITIALIZE MANAGER + // ************************************************************************ + this._manager = new qx.manager.selection.VirtualSelectionManager(this); + + + // ************************************************************************ + // MOUSE EVENT LISTENER + // ************************************************************************ + // Add handling for mouse wheel events + // Needed because the virtual scroll area does not fire browser + // understandable events above this pane. + this.addEventListener("mousewheel", this._onmousewheel); + + this.addEventListener("mouseover", this._onmouseover); + this.addEventListener("mousedown", this._onmousedown); + this.addEventListener("mouseup", this._onmouseup); + this.addEventListener("click", this._onclick); + this.addEventListener("dblclick", this._ondblclick); + + + // ************************************************************************ + // KEY EVENT LISTENER + // ************************************************************************ + this.addEventListener("keypress", this._onkeypress); +}); + +qx.OO.changeProperty({ name : "appearance", + type : "string", + defaultValue : "list-view-pane" + }); + +qx.Proto._rowHeight = 16; + + + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getView = function() { + return this.getParent().getParent(); +} + + + + + + +/* +--------------------------------------------------------------------------- + UPDATER +--------------------------------------------------------------------------- +*/ + +qx.Proto._lastRowCount = 0; + +qx.Proto._updateLayout = function(vUpdate) +{ + // this.debug("InnerHeight: " + this._computeInnerHeight()); + // this.debug("BoxHeight: " + this._computeBoxHeight()); + // return + + var vColumns = this._columns; + var vRowCount = Math.ceil(this.getInnerHeight() / this._rowHeight); + var vData = this._data; + var vCell; + + // this.debug("Row-Count: " + this._lastRowCount + " => " + vRowCount); + + // Sync cells: Add new ones and configure them + if (vRowCount > this._lastRowCount) + { + for (var i=this._lastRowCount, j=0; i vRowCount) + { + var vChildren = this.getChildren(); + var vChildrenLength = vChildren.length - 1; + + for (var i=this._lastRowCount; i>vRowCount; i--) + { + for (var vCol in vColumns) + { + vCell = vChildren[vChildrenLength--]; + this.remove(vCell); + vCell.dispose(); + } + } + } + + // Update row and column count + this.setRowCount(vRowCount); + if (!vUpdate) { + this.setColumnCount(qx.lang.Object.getLength(vColumns)); + } + + // Apply height to all rows + for (var i=0; i vParentHeight || vOffset < vParentScrollTop) + { + vNewScrollTop = vOffset; + } + else if ((vOffset + vHeight) > (vParentScrollTop + vParentHeight)) + { + vNewScrollTop = vOffset + vHeight - vParentHeight; + } + + if (vNewScrollTop != null) { + this.getView().getScroll().setScrollTop(vNewScrollTop); + } +} + +qx.Proto.setScrollTop = function(vScrollTop) +{ + this.getView().getScroll().setScrollTop(vScrollTop); + this._updateRendering(); +} + +qx.Proto.getScrollTop = function() { + return this._currentScrollTop; +} + +qx.Proto.setScrollLeft = function() { + this.error("Not implemented in qx.ui.listview.ListViewPane!"); +} + +qx.Proto.getScrollLeft = function() { + return 0; +} + +qx.Proto.isItemVisible = function(vItem) +{ + var vIndex = this._data.indexOf(vItem); + var vRowStart = Math.floor(this._currentScrollTop / this._rowHeight); + var vRowLength = Math.ceil(this.getClientHeight() / this._rowHeight); + + return vIndex >= vRowStart && vIndex <= (vRowStart + vRowLength); +} + +qx.Proto.getRelativeItemPosition = function(vItem) +{ + var vIndex = this._data.indexOf(vItem); + var vRowStart = Math.floor(this._currentScrollTop / this._rowHeight); + + return vIndex - vRowStart; +} + +qx.Proto._updateItem = function(vItem) +{ + var vIndex = this._data.indexOf(vItem); + var vRowStart = Math.floor(this._currentScrollTop / this._rowHeight); + var vRowLength = Math.ceil(this.getClientHeight() / this._rowHeight); + + if (vIndex < vRowStart || vIndex > (vRowStart + vRowLength)) { + return; + } + + this._updateRow(vIndex - vRowStart); +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + + // ************************************************************************ + // MOUSE EVENT LISTENER + // ************************************************************************ + this.removeEventListener("mousewheel", this._onmousewheel); + this.removeEventListener("mouseover", this._onmouseover); + this.removeEventListener("mousedown", this._onmousedown); + this.removeEventListener("mouseup", this._onmouseup); + this.removeEventListener("click", this._onclick); + this.removeEventListener("dblclick", this._ondblclick); + + + // ************************************************************************ + // KEY EVENT LISTENER + // ************************************************************************ + this.removeEventListener("keypress", this._onkeypress); + + + // ************************************************************************ + // DATA + // ************************************************************************ + delete this._data; + delete this._columns; + + + // ************************************************************************ + // MANAGER + // ************************************************************************ + if (this._manager) + { + this._manager.dispose(); + this._manager = null; + } + + return qx.ui.layout.GridLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menu/Button.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menu/Button.js new file mode 100644 index 0000000000..569419b566 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menu/Button.js @@ -0,0 +1,354 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_menu) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.menu.Button", qx.ui.layout.HorizontalBoxLayout, +function(vLabel, vIcon, vCommand, vMenu) +{ + qx.ui.layout.HorizontalBoxLayout.call(this); + + + // ************************************************************************ + // LAYOUT + // ************************************************************************ + + var io = this._iconObject = new qx.ui.basic.Image; + io.setWidth(16); + io.setAnonymous(true); + + var lo = this._labelObject = new qx.ui.basic.Label; + lo.setAnonymous(true); + lo.setSelectable(false); + + var so = this._shortcutObject = new qx.ui.basic.Label; + so.setAnonymous(true); + so.setSelectable(false); + + var ao = this._arrowObject = new qx.ui.basic.Image("widget/arrows/next.gif"); + ao.setAnonymous(true); + + + // ************************************************************************ + // INIT + // ************************************************************************ + + if (qx.util.Validation.isValidString(vLabel)) { + this.setLabel(vLabel); + } + + if (qx.util.Validation.isValidString(vIcon)) { + this.setIcon(vIcon); + } + + if (qx.util.Validation.isValid(vCommand)) { + this.setCommand(vCommand); + } + + if (qx.util.Validation.isValid(vMenu)) { + this.setMenu(vMenu); + } + + + // ************************************************************************ + // EVENTS + // ************************************************************************ + + this.addEventListener("mouseup", this._onmouseup); +}); + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "menu-button" }); + +qx.OO.addProperty({ name : "icon", type : "string" }); +qx.OO.addProperty({ name : "label", type : "string" }); +qx.OO.addProperty({ name : "menu", type : "object" }); + + + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto._hasIcon = false; +qx.Proto._hasLabel = false; +qx.Proto._hasShortcut = false; +qx.Proto._hasMenu = false; + +qx.Proto.hasIcon = function() { + return this._hasIcon; +} + +qx.Proto.hasLabel = function() { + return this._hasLabel; +} + +qx.Proto.hasShortcut = function() { + return this._hasShortcut; +} + +qx.Proto.hasMenu = function() { + return this._hasMenu; +} + +qx.Proto.getIconObject = function() { + return this._iconObject; +} + +qx.Proto.getLabelObject = function() { + return this._labelObject; +} + +qx.Proto.getShortcutObject = function() { + return this._shortcutObject; +} + +qx.Proto.getArrowObject = function() { + return this._arrowObject; +} + +qx.Proto.getParentMenu = function() +{ + var vParent = this.getParent(); + if (vParent) + { + vParent = vParent.getParent(); + + if (vParent && vParent instanceof qx.ui.menu.Menu) { + return vParent; + } + } + + return null; +} + + + + + +/* +--------------------------------------------------------------------------- + INIT LAYOUT IMPL +--------------------------------------------------------------------------- +*/ + +/*! + This creates an new instance of the layout impl this widget uses +*/ +qx.Proto._createLayoutImpl = function() { + return new qx.renderer.layout.MenuButtonLayoutImpl(this); +} + + + + + +/* +--------------------------------------------------------------------------- + MODIFIERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyEnabled = function(propValue, propOldValue, propData) +{ + if (this._iconObject) { + this._iconObject.setEnabled(propValue); + } + + if (this._labelObject) { + this._labelObject.setEnabled(propValue); + } + + if (this._shortcutObject) { + this._shortcutObject.setEnabled(propValue); + } + + return qx.ui.layout.HorizontalBoxLayout.prototype._modifyEnabled.call(this, propValue, propOldValue, propData); +} + +qx.Proto._modifyIcon = function(propValue, propOldValue, propData) +{ + this._iconObject.setSource(propValue); + + if (qx.util.Validation.isValidString(propValue)) + { + this._hasIcon = true; + + if (qx.util.Validation.isInvalidString(propOldValue)) { + this.addAtBegin(this._iconObject); + } + } + else + { + this._hasIcon = false; + this.remove(this._iconObject); + } + + return true; +} + +qx.Proto._modifyLabel = function(propValue, propOldValue, propData) +{ + this._labelObject.setHtml(propValue); + + if (qx.util.Validation.isValidString(propValue)) + { + this._hasLabel = true; + + if (qx.util.Validation.isInvalidString(propOldValue)) { + this.addAt(this._labelObject, this.getFirstChild() == this._iconObject ? 1 : 0); + } + } + else + { + this._hasLabel = false; + this.remove(this._labelObject); + } + + return true; +} + +qx.Proto._modifyCommand = function(propValue, propOldValue, propData) +{ + var vHtml = propValue ? propValue.getShortcut() : ""; + + this._shortcutObject.setHtml(vHtml); + + if (qx.util.Validation.isValidString(vHtml)) + { + this._hasShortcut = true; + + var vOldHtml = propOldValue ? propOldValue.getShortcut() : ""; + + if (qx.util.Validation.isInvalidString(vOldHtml)) + { + if (this.getLastChild() == this._arrowObject) + { + this.addBefore(this._shortcutObject, this._arrowObject); + } + else + { + this.addAtEnd(this._shortcutObject); + } + } + } + else + { + this._hasShortcut = false; + this.remove(this._shortcutObject); + } + + return true; +} + +qx.Proto._modifyMenu = function(propValue, propOldValue, propData) +{ + if (qx.util.Validation.isValidObject(propValue)) + { + this._hasMenu = true; + + if (qx.util.Validation.isInvalidObject(propOldValue)) { + this.addAtEnd(this._arrowObject); + } + } + else + { + this._hasMenu = false; + this.remove(this._arrowObject); + } + + return true; +} + + + + + + +/* +--------------------------------------------------------------------------- + EVENTS +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmouseup = function(e) { + this.execute(); +} + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + // Dispose children + if (this._iconObject) + { + this._iconObject.dispose(); + this._iconObject = null; + } + + if (this._labelObject) + { + this._labelObject.dispose(); + this._labelObject = null; + } + + if (this._shortcutObject) + { + this._shortcutObject.dispose(); + this._shortcutObject = null; + } + + if (this._arrowObject) + { + this._arrowObject.dispose(); + this._arrowObject = null; + } + + // Remove event listeners + this.removeEventListener("mouseup", this._onmouseup); + + return qx.ui.layout.HorizontalBoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menu/CheckBox.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menu/CheckBox.js new file mode 100644 index 0000000000..a6380f8fd2 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menu/CheckBox.js @@ -0,0 +1,85 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_menu) + +************************************************************************ */ + +/*! + A checkbox for the menu system. +*/ +qx.OO.defineClass("qx.ui.menu.CheckBox", qx.ui.menu.Button, +function(vLabel, vCommand, vChecked) +{ + qx.ui.menu.Button.call(this, vLabel, "static/image/blank.gif", vCommand); + + if (qx.util.Validation.isValidBoolean(vChecked)) { + this.setChecked(vChecked); + } + + qx.manager.object.ImageManager.getInstance().preload("widget/menu/checkbox.gif"); +}); + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "menu-check-box" }); +qx.OO.addProperty({ name : "name", type : "string" }); +qx.OO.addProperty({ name : "value", type : "string" }); +qx.OO.addProperty({ name : "checked", type : "boolean", defaultValue : false, getAlias : "isChecked" }); + + + + + +/* +--------------------------------------------------------------------------- + MODIFIERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyChecked = function(propValue, propOldValue, propData) +{ + propValue ? this.addState("checked") : this.removeState("checked"); + this.getIconObject().setSource(propValue ? "widget/menu/checkbox.gif" : "static/image/blank.gif"); + + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + EXECUTE +--------------------------------------------------------------------------- +*/ + +qx.Proto.execute = function() +{ + this.setChecked(!this.getChecked()); + qx.ui.menu.Button.prototype.execute.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menu/Layout.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menu/Layout.js new file mode 100644 index 0000000000..3f06492782 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menu/Layout.js @@ -0,0 +1,56 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_menu) + +************************************************************************ */ + +/*! + A small helper class to create a special layout handler for qx.ui.menu.Menus +*/ +qx.OO.defineClass("qx.ui.menu.Layout", qx.ui.layout.VerticalBoxLayout, +function() +{ + qx.ui.layout.VerticalBoxLayout.call(this); + + this.setAnonymous(true); +}); + + +/*! + Appearance of the widget +*/ +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "menu-layout" }); + + + + +/* +--------------------------------------------------------------------------- + INIT LAYOUT IMPL +--------------------------------------------------------------------------- +*/ + +/*! + This creates an new instance of the layout impl this widget uses +*/ +qx.Proto._createLayoutImpl = function() { + return new qx.renderer.layout.MenuLayoutImpl(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menu/Menu.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menu/Menu.js new file mode 100644 index 0000000000..7006c95336 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menu/Menu.js @@ -0,0 +1,907 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_menu) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.menu.Menu", qx.ui.popup.Popup, +function() +{ + qx.ui.popup.Popup.call(this); + + + // ************************************************************************ + // LAYOUT + // ************************************************************************ + + var l = this._layout = new qx.ui.menu.Layout; + this.add(l); + + + // ************************************************************************ + // TIMER + // ************************************************************************ + this._openTimer = new qx.client.Timer(this.getOpenInterval()); + this._openTimer.addEventListener("interval", this._onopentimer, this); + + this._closeTimer = new qx.client.Timer(this.getCloseInterval()); + this._closeTimer.addEventListener("interval", this._onclosetimer, this); + + + // ************************************************************************ + // EVENTS + // ************************************************************************ + + this.addEventListener("mouseover", this._onmouseover); + this.addEventListener("mousemove", this._onmouseover); + this.addEventListener("mouseout", this._onmouseout); + + this.addEventListener("keydown", this._onkeydown); + this.addEventListener("keypress", this._onkeypress); + + + // ************************************************************************ + // REMAPPING + // ************************************************************************ + + this.remapChildrenHandlingTo(this._layout); +}); + +qx.Proto._remappingChildTable = [ "add", "remove", "addAt", "addAtBegin", "addAtEnd", "removeAt", "addBefore", "addAfter", "removeAll", "getFirstChild", "getFirstActiveChild", "getLastChild", "getLastActiveChild" ]; + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "menu" }); + +qx.OO.addProperty({ name : "iconContentGap", type : "number", defaultValue : 4 }); +qx.OO.addProperty({ name : "labelShortcutGap", type : "number", defaultValue : 10 }); +qx.OO.addProperty({ name : "contentArrowGap", type : "number", defaultValue : 8 }); +qx.OO.addProperty({ name : "contentNonIconPadding", type : "number", defaultValue : 20 }); +qx.OO.addProperty({ name : "contentNonArrowPadding", type : "number", defaultValue : 8 }); + +qx.OO.addProperty({ name : "hoverItem", type : "object" }); +qx.OO.addProperty({ name : "openItem", type : "object" }); +qx.OO.addProperty({ name : "opener", type : "object" }); +qx.OO.addProperty({ name : "parentMenu", type : "object" }); + +qx.OO.addProperty({ name : "fastReopen", type : "boolean", defaultValue : false }); +qx.OO.addProperty({ name : "openInterval", type : "number", defaultValue : 250 }); +qx.OO.addProperty({ name : "closeInterval", type : "number", defaultValue : 250 }); + +qx.OO.addProperty({ name : "subMenuHorizontalOffset", type : "number", defaultValue : -3 }); +qx.OO.addProperty({ name : "subMenuVerticalOffset", type : "number", defaultValue : -2 }); + +qx.OO.addProperty({ name : "indentShortcuts", type : "boolean", defaultValue : true }); + + + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getLayout = function() { + return this._layout; +} + +qx.Proto.isSubButton = function(vButton) +{ + if (vButton.getParent() === this._layout) { + return true; + } + + for (var a=this._layout.getChildren(), l=a.length, i=0; i 0) { + vTemp += this.getLabelShortcutGap(); + } + + vSum = Math.max(lw, vTemp); + } + else + { + vSum = lw + sw; + + if (lw > 0 && sw > 0) { + vSum += this.getLabelShortcutGap(); + } + } + + return vSum; +} + + + + + + + +/* +--------------------------------------------------------------------------- + LOCATIONS AND DIMENSIONS OF CHILDRENS CHILDREN: + POSITION COMPUTERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._computeIconPosition = function() { + return 0; +} + +qx.Proto._computeLabelPosition = function() +{ + var v = this.getMaxIconWidth(); + return v > 0 ? v + this.getIconContentGap() : this.getContentNonIconPadding(); +} + +qx.Proto._computeShortcutPosition = function() { + return this.getLabelPosition() + this.getMaxContentWidth() - this.getMaxShortcutWidth(); +} + +qx.Proto._computeArrowPosition = function() +{ + var v = this.getMaxContentWidth(); + return this.getLabelPosition() + (v > 0 ? v + this.getContentArrowGap() : v); +} + + + + + + + +/* +--------------------------------------------------------------------------- + LOCATIONS AND DIMENSIONS OF CHILDRENS CHILDREN: + INVALIDATION OF CACHE +--------------------------------------------------------------------------- +*/ + +qx.Proto._invalidateMaxIconWidth = function() +{ + this._cachedMaxIconWidth = null; + + this._invalidateLabelPosition(); + this._invalidateMenuButtonNeededWidth(); +} + +qx.Proto._invalidateMaxLabelWidth = function() +{ + this._cachedMaxLabelWidth = null; + + this._invalidateShortcutPosition(); + this._invalidateMaxLabelWidthIncShortcut(); + this._invalidateMaxContentWidth(); + this._invalidateMenuButtonNeededWidth(); +} + +qx.Proto._invalidateMaxShortcutWidth = function() +{ + this._cachedMaxShortcutWidth = null; + + this._invalidateArrowPosition(); + this._invalidateMaxContentWidth(); + this._invalidateMenuButtonNeededWidth(); +} + +qx.Proto._invalidateMaxLabelWidth = function() +{ + this._cachedMaxArrowWidth = null; + this._invalidateMenuButtonNeededWidth(); +} + +qx.Proto._invalidateLabelPosition = function() +{ + this._cachedLabelPosition = null; + this._invalidateShortcutPosition(); +} + +qx.Proto._invalidateShortcutPosition = function() +{ + this._cachedShortcutPosition = null; + this._invalidateArrowPosition(); +} + + + + + + +/* +--------------------------------------------------------------------------- + LOCATIONS AND DIMENSIONS OF CHILDRENS CHILDREN: + NEEDED WIDTH COMPUTERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._computeMenuButtonNeededWidth = function() +{ + var vSum = 0; + + var vMaxIcon = this.getMaxIconWidth(); + var vMaxContent = this.getMaxContentWidth(); + var vMaxArrow = this.getMaxArrowWidth(); + + if (vMaxIcon > 0) + { + vSum += vMaxIcon; + } + else + { + vSum += this.getContentNonIconPadding(); + } + + if (vMaxContent > 0) + { + if (vMaxIcon > 0) { + vSum += this.getIconContentGap(); + } + + vSum += vMaxContent; + } + + if (vMaxArrow > 0) + { + if (vMaxIcon > 0 || vMaxContent > 0) { + vSum += this.getContentArrowGap(); + } + + vSum += vMaxArrow; + } + else + { + vSum += this.getContentNonArrowPadding(); + } + + return vSum; +} + + + + + + + + +/* +--------------------------------------------------------------------------- + EVENT-HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmouseover = function(e) +{ + /* ------------------------------ + HANDLE PARENT MENU + ------------------------------ */ + + // look if we have a parent menu + // if so we need to stop the close event started there + var vParent = this.getParentMenu(); + + if (vParent) + { + // stop the close event + vParent._closeTimer.stop(); + + // look if we have a opener, too (normally this should be) + var vOpener = this.getOpener(); + + // then setup it to look hovered + if (vOpener) { + vParent.setHoverItem(vOpener); + } + } + + + + + /* ------------------------------ + HANDLING FOR HOVERING MYSELF + ------------------------------ */ + + var t = e.getTarget(); + + if (t == this) + { + this._openTimer.stop(); + this._closeTimer.start(); + + this.setHoverItem(null); + + return; + } + + + + + /* ------------------------------ + HANDLING FOR HOVERING ITEMS + ------------------------------ */ + + var vOpen = this.getOpenItem(); + + // if we have a open item + if (vOpen) + { + this.setHoverItem(t); + this._openTimer.stop(); + + // if the new one has also a sub menu + if (t.hasMenu()) + { + // check if we should use fast reopen (this will open the menu instantly) + if (this.getFastReopen()) + { + this.setOpenItem(t); + this._closeTimer.stop(); + } + + // otherwise we use the default timer interval + else + { + this._openTimer.start(); + } + } + + // otherwise start the close timer for the old menu + else + { + this._closeTimer.start(); + } + } + + // otherwise handle the mouseover and restart the timer + else + { + this.setHoverItem(t); + + // stop timer for the last open request + this._openTimer.stop(); + + // and restart it if the new one has a menu, too + if (t.hasMenu()) { + this._openTimer.start(); + } + } +} + +qx.Proto._onmouseout = function(e) +{ + // stop the open timer (for any previous open requests) + this._openTimer.stop(); + + // start the close timer to hide a menu if needed + var t = e.getTarget(); + if (t != this && t.hasMenu()) { + this._closeTimer.start(); + } + + // reset the current hover item + this.setHoverItem(null); +} + +qx.Proto._onopentimer = function(e) +{ + // stop the open timer (we need only the first interval) + this._openTimer.stop(); + + // if we have a item which is currently hovered, open it + var vHover = this.getHoverItem(); + if (vHover && vHover.hasMenu()) { + this.setOpenItem(vHover); + } +} + +qx.Proto._onclosetimer = function(e) +{ + // stop the close timer (we need only the first interval) + this._closeTimer.stop(); + + // reset the current opened item + this.setOpenItem(null); +} + +/*! + Wraps key events to target functions +*/ +qx.Proto._onkeydown = function(e) +{ + if (e.getKeyIdentifier() == "Enter") { + this._onkeydown_enter(e); + } + e.preventDefault(); +}; + + +qx.Proto._onkeypress = function(e) +{ + switch(e.getKeyIdentifier()) + { + case "Up": + this._onkeypress_up(e); + break; + + case "Down": + this._onkeypress_down(e); + break; + + case "Left": + this._onkeypress_left(e); + break; + + case "Right": + this._onkeypress_right(e); + break; + + default: + return; + } + + // Stop all matching events + e.preventDefault(); +}; + + +qx.Proto._onkeypress_up = function(e) +{ + var vHover = this.getHoverItem(); + var vPrev = vHover ? vHover.isFirstChild() ? this.getLastActiveChild() : vHover.getPreviousActiveSibling([qx.ui.menu.Separator]) : this.getLastActiveChild(); + + this.setHoverItem(vPrev); +}; + +qx.Proto._onkeypress_down = function(e) +{ + var vHover = this.getHoverItem(); + var vNext = vHover ? vHover.isLastChild() ? this.getFirstActiveChild() : vHover.getNextActiveSibling([qx.ui.menu.Separator]) : this.getFirstActiveChild(); + + this.setHoverItem(vNext); +}; + + +qx.Proto._onkeypress_left = function(e) +{ + var vOpener = this.getOpener(); + + // Jump to the "parent" qx.ui.menu.Menu + if (vOpener instanceof qx.ui.menu.Button) + { + var vOpenerParent = this.getOpener().getParentMenu(); + + vOpenerParent.setOpenItem(null); + vOpenerParent.setHoverItem(vOpener); + + vOpenerParent._makeActive(); + } + + // Jump to the previous ToolBarMenuButton + else if (vOpener instanceof qx.ui.toolbar.MenuButton) + { + var vToolBar = vOpener.getParentToolBar(); + + // change active widget to new button + this.getFocusRoot().setActiveChild(vToolBar); + + // execute toolbars keydown implementation + vToolBar._onkeypress(e); + } +}; + + +qx.Proto._onkeypress_right = function(e) +{ + var vHover = this.getHoverItem(); + + if (vHover) + { + var vMenu = vHover.getMenu(); + + if (vMenu) + { + this.setOpenItem(vHover); + + // mark first item in new submenu + vMenu.setHoverItem(vMenu.getFirstActiveChild()); + + return; + } + } + else if (!this.getOpenItem()) + { + var vFirst = this.getLayout().getFirstActiveChild(); + + if (vFirst) { + vFirst.hasMenu() ? this.setOpenItem(vFirst) : this.setHoverItem(vFirst); + } + } + + // Jump to the next ToolBarMenuButton + var vOpener = this.getOpener(); + + if (vOpener instanceof qx.ui.toolbar.MenuButton) + { + var vToolBar = vOpener.getParentToolBar(); + + // change active widget to new button + this.getFocusRoot().setActiveChild(vToolBar); + + // execute toolbars keydown implementation + vToolBar._onkeypress(e); + } + else if (vOpener instanceof qx.ui.menu.Button && vHover) + { + // search for menubar if existing + // menu -> button -> menu -> button -> menu -> menubarbutton -> menubar + + var vOpenerParent = vOpener.getParentMenu(); + + while (vOpenerParent && vOpenerParent instanceof qx.ui.menu.Menu) + { + vOpener = vOpenerParent.getOpener(); + + if (vOpener instanceof qx.ui.menu.Button) + { + vOpenerParent = vOpener.getParentMenu(); + } + else + { + if (vOpener) { + vOpenerParent = vOpener.getParent(); + } + + break; + } + } + + if (vOpenerParent instanceof qx.ui.toolbar.Part) { + vOpenerParent = vOpenerParent.getParent(); + } + + if (vOpenerParent instanceof qx.ui.toolbar.ToolBar) + { + // jump to next menubarbutton + this.getFocusRoot().setActiveChild(vOpenerParent); + vOpenerParent._onkeypress(e); + } + } +} + +qx.Proto._onkeydown_enter = function(e) +{ + var vHover = this.getHoverItem(); + if (vHover) { + vHover.execute(); + } + + qx.manager.object.MenuManager.getInstance().update(); +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + if (this._layout) + { + this._layout.dispose(); + this._layout = null; + } + + if (this._openTimer) + { + this._openTimer.dispose(); + this._openTimer = null; + } + + if (this._closeTimer) + { + this._closeTimer.dispose(); + this._closeTimer = null; + } + + // Remove event listeners + this.removeEventListener("mouseover", this._onmouseover); + this.removeEventListener("mousemove", this._onmouseover); + this.removeEventListener("mouseout", this._onmouseout); + + this.removeEventListener("keydown", this._onkeydown); + this.removeEventListener("keypress", this._onkeypress); + + + return qx.ui.popup.Popup.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menu/RadioButton.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menu/RadioButton.js new file mode 100644 index 0000000000..b8ff7f975f --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menu/RadioButton.js @@ -0,0 +1,118 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_menu) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.menu.RadioButton", qx.ui.menu.CheckBox, +function(vLabel, vCommand, vChecked) +{ + qx.ui.menu.CheckBox.call(this, vLabel, vCommand, vChecked); + + qx.manager.object.ImageManager.getInstance().preload("widget/menu/radiobutton.gif"); +}); + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "menu-radio-button" }); + +/*! + The assigned qx.manager.selection.RadioManager which handles the switching between registered buttons +*/ +qx.OO.addProperty({ name : "manager", type : "object", instance : "qx.manager.selection.RadioManager", allowNull : true }); + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyChecked = function(propValue, propOldValue, propData) +{ + var vManager = this.getManager(); + + if (vManager) + { + if (propValue) + { + vManager.setSelected(this); + } + else if (vManager.getSelected() == this) + { + vManager.setSelected(null); + } + } + + propValue ? this.addState("checked") : this.removeState("checked"); + this.getIconObject().setSource(propValue ? "widget/menu/radiobutton.gif" : "static/image/blank.gif"); + + return true; +} + +qx.Proto._modifyManager = function(propValue, propOldValue, propData) +{ + if (propOldValue) { + propOldValue.remove(this); + } + + if (propValue) { + propValue.add(this); + } + + return true; +} + +qx.Proto._modifyName = function(propValue, propOldValue, propData) +{ + if (this.getManager()) { + this.getManager().setName(propValue); + } + + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + EXECUTE +--------------------------------------------------------------------------- +*/ + +qx.Proto.execute = function() +{ + this.setChecked(true); + + // Intentionally bypass superclass and call super.super.execute + qx.ui.menu.Button.prototype.execute.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menu/Separator.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menu/Separator.js new file mode 100644 index 0000000000..a7bce89c33 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menu/Separator.js @@ -0,0 +1,76 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_menu) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.menu.Separator", qx.ui.layout.CanvasLayout, +function() +{ + qx.ui.layout.CanvasLayout.call(this); + + // Fix IE Styling Issues + this.setStyleProperty("fontSize", "0"); + this.setStyleProperty("lineHeight", "0"); + + // ************************************************************************ + // LINE + // ************************************************************************ + + this._line = new qx.ui.basic.Terminator; + this._line.setAnonymous(true); + this._line.setAppearance("menu-separator-line"); + this.add(this._line); + + + // ************************************************************************ + // EVENTS + // ************************************************************************ + + // needed to stop the event, and keep the menu showing + this.addEventListener("mousedown", this._onmousedown); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "menu-separator" }); + +qx.Proto.hasIcon = qx.util.Return.returnFalse; +qx.Proto.hasLabel = qx.util.Return.returnFalse; +qx.Proto.hasShortcut = qx.util.Return.returnFalse; +qx.Proto.hasMenu = qx.util.Return.returnFalse; + +qx.Proto._onmousedown = function(e) { + e.stopPropagation(); +} + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + if (this._line) + { + this._line.dispose(); + this._line = null; + } + + return qx.ui.layout.CanvasLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menubar/Button.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menubar/Button.js new file mode 100644 index 0000000000..9d13967fe6 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menubar/Button.js @@ -0,0 +1,28 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_menu) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.menubar.Button", qx.ui.toolbar.MenuButton, +function(vText, vMenu, vIcon, vIconWidth, vIconHeight, vFlash) { + qx.ui.toolbar.MenuButton.call(this, vText, vMenu, vIcon, vIconWidth, vIconHeight, vFlash); +}); diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menubar/MenuBar.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menubar/MenuBar.js new file mode 100644 index 0000000000..858f1fea4f --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/menubar/MenuBar.js @@ -0,0 +1,28 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_menu) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.menubar.MenuBar", qx.ui.toolbar.ToolBar, +function() { + qx.ui.toolbar.ToolBar.call(this); +}); diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractBar.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractBar.js new file mode 100755 index 0000000000..1c10e5680b --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractBar.js @@ -0,0 +1,129 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.pageview.AbstractBar", qx.ui.layout.BoxLayout, +function() +{ + qx.ui.layout.BoxLayout.call(this); + + this._manager = new qx.manager.selection.RadioManager; + + this.addEventListener("mousewheel", this._onmousewheel); +}); + + + + +/* +--------------------------------------------------------------------------- + UTILITY +--------------------------------------------------------------------------- +*/ + +qx.Proto.getManager = function() { + return this._manager; +} + + + + + +/* +--------------------------------------------------------------------------- + EVENTS +--------------------------------------------------------------------------- +*/ + +qx.Proto._lastDate = (new Date(0)).valueOf(); + +qx.Proto._onmousewheel = function(e) +{ + // Make it a bit lazier than it could be + // Hopefully this is a better behaviour for fast scrolling users + var vDate = (new Date).valueOf(); + + if ((vDate - 50) < this._lastDate) { + return; + } + + this._lastDate = vDate; + + var vManager = this.getManager(); + var vItems = vManager.getItems(); + var vPos = vItems.indexOf(vManager.getSelected()); + + if (this.getWheelDelta(e) > 0) + { + var vNext = vItems[vPos+1]; + + if (!vNext) { + vNext = vItems[0]; + } + } + else if (vPos > 0) + { + var vNext = vItems[vPos-1]; + + if (!vNext) { + vNext = vItems[0]; + } + } + else + { + vNext = vItems[vItems.length-1]; + } + + vManager.setSelected(vNext); +} + +qx.Proto.getWheelDelta = function(e) { + return e.getWheelDelta(); +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + if (this._manager) + { + this._manager.dispose(); + this._manager = null; + } + + this.removeEventListener("mousewheel", this._onmousewheel); + + return qx.ui.layout.BoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractButton.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractButton.js new file mode 100755 index 0000000000..da590a286d --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractButton.js @@ -0,0 +1,219 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + + ************************************************************************ */ + +/* ************************************************************************ + + + ************************************************************************ */ + +qx.OO.defineClass("qx.ui.pageview.AbstractButton", qx.ui.basic.Atom, +function(vText, vIcon, vIconWidth, vIconHeight, vFlash) { + qx.ui.basic.Atom.call(this, vText, vIcon, vIconWidth, vIconHeight, vFlash); + + this.setTabIndex(1); + + // ************************************************************************ + // MOUSE EVENTS + // ************************************************************************ + this.addEventListener("mouseover", this._onmouseover); + this.addEventListener("mouseout", this._onmouseout); + this.addEventListener("mousedown", this._onmousedown); + + // ************************************************************************ + // KEY EVENTS + // ************************************************************************ + this.addEventListener("keydown", this._onkeydown); + this.addEventListener("keypress", this._onkeypress); +}); + + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- + */ + +/*! + If this tab is the currently selected/active one + */ +qx.OO.addProperty({ name : "checked", type : "boolean", defaultValue : false }); + +/*! + The attached page of this tab + */ +qx.OO.addProperty({ name : "page", type : "object" }); + +/*! + The assigned qx.manager.selection.RadioManager which handles the switching between registered buttons + */ +qx.OO.addProperty({ name : "manager", type : "object", instance : "qx.manager.selection.RadioManager", allowNull : true }); + +/*! + The name of the radio group. All the radio elements in a group (registered by the same manager) + have the same name (and could have a different value). + */ +qx.OO.addProperty({ name : "name", type : "string" }); + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- + */ + +qx.Proto.getView = function() { + return this.getParent().getParent(); +} + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- + */ + +qx.Proto._modifyManager = function(propValue, propOldValue, propData) { + if (propOldValue) { + propOldValue.remove(this); + } + + if (propValue) { + propValue.add(this); + } + + return true; +} + +qx.Proto._modifyParent = function(propValue, propOldValue, propData) { + if (propOldValue) { + propOldValue.getManager().remove(this); + } + + if (propValue) { + propValue.getManager().add(this); + } + + return qx.ui.basic.Atom.prototype._modifyParent.call(this, propValue, propOldValue, propData); +} + +qx.Proto._modifyPage = function(propValue, propOldValue, propData) { + if (propOldValue) { + propOldValue.setButton(null); + } + + if (propValue) { + propValue.setButton(this); + this.getChecked() ? propValue.show() : propValue.hide(); + } + + return true; +} + +qx.Proto._modifyChecked = function(propValue, propOldValue, propData) { + if (this._hasParent) { + var vManager = this.getManager(); + if (vManager) { + vManager.handleItemChecked(this, propValue); + } + } + + propValue ? this.addState("checked") : this.removeState("checked"); + + var vPage = this.getPage(); + if (vPage) { + this.getChecked() ? vPage.show() : vPage.hide(); + } + + return true; +} + +qx.Proto._modifyName = function(propValue, propOldValue, propData) { + if (this.getManager()) { + this.getManager().setName(propValue); + } + + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- + */ + +qx.Proto._onmousedown = function(e) { + this.setChecked(true); +} + +qx.Proto._onmouseover = function(e) { + this.addState("over"); +} + +qx.Proto._onmouseout = function(e) { + this.removeState("over"); +} + +qx.Proto._onkeydown = function(e) {} +qx.Proto._onkeypress = function(e) {} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- + */ + +qx.Proto.dispose = function() { + if (this.getDisposed()) { + return; + } + + + // ************************************************************************ + // MOUSE EVENTS + // ************************************************************************ + this.removeEventListener("mouseover", this._onmouseover); + this.removeEventListener("mouseout", this._onmouseout); + this.removeEventListener("mousedown", this._onmousedown); + + + // ************************************************************************ + // KEY EVENTS + // ************************************************************************ + this.removeEventListener("keydown", this._onkeydown); + this.removeEventListener("keypress", this._onkeypress); + + + return qx.ui.basic.Atom.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractPage.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractPage.js new file mode 100755 index 0000000000..3eed9d20b4 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractPage.js @@ -0,0 +1,75 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.pageview.AbstractPage", qx.ui.layout.CanvasLayout, +function(vButton) +{ + qx.ui.layout.CanvasLayout.call(this); + + if (qx.util.Validation.isValid(vButton)) { + this.setButton(vButton); + } +}); + + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +/*! + The attached tab of this page. +*/ +qx.OO.addProperty({ name : "button", type : "object" }); + +/*! + Make element displayed (if switched to true the widget will be created, if needed, too). + Instead of qx.ui.core.Widget, the default is false here. +*/ +qx.OO.changeProperty({ name : "display", type : "boolean", defaultValue : false }); + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyButton = function(propValue, propOldValue, propData) +{ + if (propOldValue) { + propOldValue.setPage(null); + } + + if (propValue) { + propValue.setPage(this); + } + + return true; +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractPageView.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractPageView.js new file mode 100755 index 0000000000..786bc88145 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractPageView.js @@ -0,0 +1,84 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.pageview.AbstractPageView", qx.ui.layout.BoxLayout, +function(vBarClass, vPaneClass) +{ + qx.ui.layout.BoxLayout.call(this); + + this._bar = new vBarClass; + this._pane = new vPaneClass; + + this.add(this._bar, this._pane); + this.setOrientation("vertical"); +}); + + + + + +/* +--------------------------------------------------------------------------- + UTILITY +--------------------------------------------------------------------------- +*/ + +qx.Proto.getPane = function() { + return this._pane; +} + +qx.Proto.getBar = function() { + return this._bar; +} + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + if (this._bar) + { + this._bar.dispose(); + this._bar = null; + } + + if (this._pane) + { + this._pane.dispose(); + this._pane = null; + } + + return qx.ui.layout.BoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractPane.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractPane.js new file mode 100755 index 0000000000..a026e0401e --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/AbstractPane.js @@ -0,0 +1,27 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.pageview.AbstractPane", qx.ui.layout.CanvasLayout, +function() { + qx.ui.layout.CanvasLayout.call(this); +}); diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/Bar.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/Bar.js new file mode 100644 index 0000000000..43ed8c1f85 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/Bar.js @@ -0,0 +1,75 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_buttonview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.pageview.buttonview.Bar", qx.ui.pageview.AbstractBar, +function() { + qx.ui.pageview.AbstractBar.call(this); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "bar-view-bar" }); + + + + +/* +--------------------------------------------------------------------------- + EVENTS +--------------------------------------------------------------------------- +*/ + +qx.Proto.getWheelDelta = function(e) +{ + var vWheelDelta = e.getWheelDelta(); + + switch(this.getParent().getBarPosition()) + { + case "left": + case "right": + vWheelDelta *= -1; + } + + return vWheelDelta; +} + + + + + +/* +--------------------------------------------------------------------------- + APPEARANCE ADDITIONS +--------------------------------------------------------------------------- +*/ + +qx.Proto._applyStateAppearance = function() +{ + var vPos = this.getParent().getBarPosition(); + + this._states.barLeft = vPos === "left"; + this._states.barRight = vPos === "right"; + this._states.barTop = vPos === "top"; + this._states.barBottom = vPos === "bottom"; + + qx.ui.pageview.AbstractButton.prototype._applyStateAppearance.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/Button.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/Button.js new file mode 100644 index 0000000000..2ea00867a9 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/Button.js @@ -0,0 +1,120 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_buttonview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.pageview.buttonview.Button", qx.ui.pageview.AbstractButton, +function(vText, vIcon, vIconWidth, vIconHeight, vFlash) { + qx.ui.pageview.AbstractButton.call(this, vText, vIcon, vIconWidth, vIconHeight, vFlash); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "bar-view-button" }); + + + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onkeypress = function(e) +{ + switch(this.getView().getBarPosition()) + { + case "top": + case "bottom": + switch(e.getKeyIdentifier()) + { + case "Left": + var vPrevious = true; + break; + + case "Right": + var vPrevious = false; + break; + + default: + return; + } + + break; + + case "left": + case "right": + switch(e.getKeyIdentifier()) + { + case "Up": + var vPrevious = true; + break; + + case "Down": + var vPrevious = false; + break; + + default: + return; + } + + break; + + default: + return; + } + + var vChild = vPrevious ? this.isFirstChild() ? this.getParent().getLastChild() : this.getPreviousSibling() : this.isLastChild() ? this.getParent().getFirstChild() : this.getNextSibling(); + + // focus next/previous button + vChild.setFocused(true); + + // and naturally also check it + vChild.setChecked(true); +} + + + + + + + + + +/* +--------------------------------------------------------------------------- + APPEARANCE ADDITIONS +--------------------------------------------------------------------------- +*/ + +qx.Proto._applyStateAppearance = function() +{ + var vPos = this.getView().getBarPosition(); + + this._states.barLeft = vPos === "left"; + this._states.barRight = vPos === "right"; + this._states.barTop = vPos === "top"; + this._states.barBottom = vPos === "bottom"; + + qx.ui.pageview.AbstractButton.prototype._applyStateAppearance.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/ButtonView.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/ButtonView.js new file mode 100644 index 0000000000..7521b67683 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/ButtonView.js @@ -0,0 +1,98 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_buttonview) + +************************************************************************ */ + +/*! + One of the widgets which could be used to structurize the interface. + + qx.ui.pageview.buttonview.ButtonView creates the typical apple-like tabview-replacements which could also + be found in more modern versions of the settings dialog in Mozilla Firefox. +*/ +qx.OO.defineClass("qx.ui.pageview.buttonview.ButtonView", qx.ui.pageview.AbstractPageView, +function() +{ + qx.ui.pageview.AbstractPageView.call(this, qx.ui.pageview.buttonview.Bar, qx.ui.pageview.buttonview.Pane); + + this.setOrientation("vertical"); +}); + + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.addProperty({ name : "barPosition", type : "string", defaultValue : "top", possibleValues : [ "top", "right", "bottom", "left" ] }); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "bar-view" }); + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyBarPosition = function(propValue, propOldValue, propData) +{ + var vBar = this._bar; + + // move bar around and change orientation + switch(propValue) + { + case "top": + vBar.moveSelfToBegin(); + this.setOrientation("vertical"); + break; + + case "bottom": + vBar.moveSelfToEnd(); + this.setOrientation("vertical"); + break; + + case "left": + vBar.moveSelfToBegin(); + this.setOrientation("horizontal"); + break; + + case "right": + vBar.moveSelfToEnd(); + this.setOrientation("horizontal"); + break; + } + + // force re-apply of states for bar and pane + this._addChildrenToStateQueue(); + + // force re-apply of states for all tabs + vBar._addChildrenToStateQueue(); + + return true; +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/Page.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/Page.js new file mode 100644 index 0000000000..d5d4b15d4f --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/Page.js @@ -0,0 +1,30 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_buttonview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.pageview.buttonview.Page", qx.ui.pageview.AbstractPage, +function(vButton) { + qx.ui.pageview.AbstractPage.call(this, vButton); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "bar-view-page" }); diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/Pane.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/Pane.js new file mode 100644 index 0000000000..6f8aabebc4 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/buttonview/Pane.js @@ -0,0 +1,51 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_buttonview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.pageview.buttonview.Pane", qx.ui.pageview.AbstractPane, +function() { + qx.ui.pageview.AbstractPane.call(this); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "bar-view-pane" }); + + + + + + + +/* +--------------------------------------------------------------------------- + APPEARANCE ADDITIONS +--------------------------------------------------------------------------- +*/ + +qx.Proto._applyStateAppearance = function() +{ + var vPos = this.getParent().getBarPosition(); + + this._states.barHorizontal = vPos === "top" || vPos === "bottom"; + + qx.ui.pageview.AbstractButton.prototype._applyStateAppearance.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/Bar.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/Bar.js new file mode 100644 index 0000000000..22f429dd96 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/Bar.js @@ -0,0 +1,33 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_tabview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.pageview.tabview.Bar", qx.ui.pageview.AbstractBar, +function() +{ + qx.ui.pageview.AbstractBar.call(this); + + this.setZIndex(2); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "tab-view-bar" }); diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/Button.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/Button.js new file mode 100644 index 0000000000..9566bb2a51 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/Button.js @@ -0,0 +1,189 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_tabview) + +************************************************************************ */ + +/** + * @event closetab {qx.event.type.DataEvent} + */ +qx.OO.defineClass("qx.ui.pageview.tabview.Button", qx.ui.pageview.AbstractButton, +function(vText, vIcon, vIconWidth, vIconHeight, vFlash) { + qx.ui.pageview.AbstractButton.call(this, vText, vIcon, vIconWidth, vIconHeight, vFlash); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "tab-view-button" }); + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- + */ + +/*! + default Close Tab Button + */ +qx.OO.addProperty({ name : "showCloseButton", type : "boolean", defaultValue : false }); + +/*! + Close Tab Icon + */ +qx.OO.addProperty({ name : "closeButtonImage", type : "string", defaultValue : "icon/16/cancel.png"}); + + + + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onkeydown = function(e) +{ + var identifier = e.getKeyIdentifier(); + if (identifier == "Enter" || identifier == "Space") { + // there is no toggeling, just make it checked + this.setChecked(true); + } +}; + + +qx.Proto._onkeypress = function(e) +{ + switch(e.getKeyIdentifier()) + { + case "Left": + var vPrev = this.getPreviousSibling() || this.getParent().getLastChild(); + if (vPrev && vPrev != this) + { + // we want to enable the outline border, because + // the user used the keyboard for activation + delete qx.event.handler.FocusHandler.mouseFocus; + + // focus previous tab + vPrev.setFocused(true); + + // and naturally make it also checked + vPrev.setChecked(true); + } + break; + + case "Right": + var vNext = this.getNextSibling() || this.getParent().getFirstVisibleChild(); + if (vNext && vNext != this) + { + // we want to enable the outline border, because + // the user used the keyboard for activation + delete qx.event.handler.FocusHandler.mouseFocus; + + // focus next tab + vNext.setFocused(true); + + // and naturally make it also checked + vNext.setChecked(true); + } + break; + } +}; + + +qx.Proto._ontabclose = function(e){ + this.createDispatchDataEvent("closetab", this); +} + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- + */ + +qx.Proto._modifyShowCloseButton = function(propValue, propOldValue, propData) { + + // if no image exists, then create one + if (!this._closeButtonImage) { + this._closeButtonImage = new qx.ui.basic.Image(this.getCloseButtonImage()); + } + if (propValue) { + this._closeButtonImage.addEventListener("click", this._ontabclose, this); + this.add(this._closeButtonImage); + } else { + this.remove(this._closeButtonImage); + this._closeButtonImage.removeEventListener("click", this._ontabclose); + } + + return true; +} + +qx.Proto._modifyCloseButtonImage = function(propValue, propOldValue, propData) { + if (this._closeButtonImage) { + this._closeButtonImage.setSource(propValue); + } + + return true; +} + + + +/* +--------------------------------------------------------------------------- + APPEARANCE ADDITIONS +--------------------------------------------------------------------------- +*/ + +qx.Proto._applyStateAppearance = function() +{ + this._states.firstChild = this.isFirstVisibleChild(); + this._states.lastChild = this.isLastVisibleChild(); + this._states.alignLeft = this.getView().getAlignTabsToLeft(); + this._states.barTop = this.getView().getPlaceBarOnTop(); + + qx.ui.pageview.AbstractButton.prototype._applyStateAppearance.call(this); +} + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- + */ + +qx.Proto.dispose = function() { + if (this.getDisposed()) { + return; + } + + if(this._closeButtonImage){ + this._closeButtonImage.dispose(); + this._closeButtonImage = null; + } + + return qx.ui.pageview.AbstractButton.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/Page.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/Page.js new file mode 100644 index 0000000000..8f1f654ed4 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/Page.js @@ -0,0 +1,30 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_tabview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.pageview.tabview.Page", qx.ui.pageview.AbstractPage, +function(vButton) { + qx.ui.pageview.AbstractPage.call(this, vButton); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "tab-view-page" }); diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/Pane.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/Pane.js new file mode 100644 index 0000000000..d31d4ee0ae --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/Pane.js @@ -0,0 +1,33 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_tabview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.pageview.tabview.Pane", qx.ui.pageview.AbstractPane, +function() +{ + qx.ui.pageview.AbstractPane.call(this); + + this.setZIndex(1); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "tab-view-pane" }); diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/TabView.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/TabView.js new file mode 100644 index 0000000000..b1cfe9c2b8 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/pageview/tabview/TabView.js @@ -0,0 +1,86 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_tabview) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.pageview.tabview.TabView", qx.ui.pageview.AbstractPageView, +function() { + qx.ui.pageview.AbstractPageView.call(this, qx.ui.pageview.tabview.Bar, qx.ui.pageview.tabview.Pane); +}); + + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "tab-view" }); + +qx.OO.addProperty({ name : "alignTabsToLeft", type : "boolean", defaultValue : true }); +qx.OO.addProperty({ name : "placeBarOnTop", type : "boolean", defaultValue : true }); + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyAlignTabsToLeft = function(propValue, propOldValue, propData) +{ + var vBar = this._bar; + + vBar.setHorizontalChildrenAlign(propValue ? "left" : "right"); + + // force re-apply of states for all tabs + vBar._addChildrenToStateQueue(); + + return true; +} + +qx.Proto._modifyPlaceBarOnTop = function(propValue, propOldValue, propData) +{ + // This does not work if we use flexible zones + // this.setReverseChildrenOrder(!propValue); + + var vBar = this._bar; + + // move bar around + if (propValue) { + vBar.moveSelfToBegin(); + } else { + vBar.moveSelfToEnd(); + } + + // force re-apply of states for all tabs + vBar._addChildrenToStateQueue(); + + return true; +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/popup/Popup.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/popup/Popup.js new file mode 100644 index 0000000000..171016d658 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/popup/Popup.js @@ -0,0 +1,329 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_popup) +#optional(qx.manager.object.MenuManager) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.popup.Popup", qx.ui.layout.CanvasLayout, +function() +{ + qx.ui.layout.CanvasLayout.call(this); + + this.setZIndex(this._minZIndex); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "popup" }); + +/*! + Whether to let the system decide when to hide the popup. Setting + this to false gives you better control but it also requires you + to handle the closing of the popup. +*/ +qx.OO.addProperty({ name : "autoHide", type : "boolean", defaultValue : true }); + +/*! + Make element displayed (if switched to true the widget will be created, if needed, too). + Instead of qx.ui.core.Widget, the default is false here. +*/ +qx.OO.changeProperty({ name : "display", type : "boolean", defaultValue : false }); + +/*! + Center the popup on open +*/ +qx.OO.addProperty({ name : "centered", type : "boolean", defaultValue : false }); + +/** + * Whether the popup should be restricted to the visible area of the page when opened. + */ +qx.OO.addProperty({ name : "restrictToPageOnOpen", type : "boolean", defaultValue : true }); + + +qx.Proto._showTimeStamp = (new Date(0)).valueOf(); +qx.Proto._hideTimeStamp = (new Date(0)).valueOf(); + + +/** + * The minimum offset to the left of the page too keep when + * {@link #restrictToPageOnOpen} is true (in pixels). + */ +qx.Settings.setDefault("restrictToPageLeft", "5"); + +/** + * The minimum offset to the right of the page too keep when + * {@link #restrictToPageOnOpen} is true (in pixels). + */ +qx.Settings.setDefault("restrictToPageRight", "5"); + +/** + * The minimum offset to the top of the page too keep when + * {@link #restrictToPageOnOpen} is true (in pixels). + */ +qx.Settings.setDefault("restrictToPageTop", "5"); + +/** + * The minimum offset to the bottom of the page too keep when + * {@link #restrictToPageOnOpen} is true (in pixels). + */ +qx.Settings.setDefault("restrictToPageBottom", "5"); + + + + + +/* +--------------------------------------------------------------------------- + APPEAR/DISAPPEAR +--------------------------------------------------------------------------- +*/ + +qx.Proto._beforeAppear = function() +{ + qx.ui.layout.CanvasLayout.prototype._beforeAppear.call(this); + + if (this.getRestrictToPageOnOpen()) { + this._wantedLeft = this.getLeft(); + + if (this._wantedLeft != null) { + // Move the popup out of the view so its size could be calculated before + // it is positioned. + this.setLeft(10000); + if (this.getElement() != null) { + // The popup was already visible once before + // -> Move it immediately before it gets visible again + this.getElement().style.left = 10000; + } + } + } + + qx.manager.object.PopupManager.getInstance().add(this); + qx.manager.object.PopupManager.getInstance().update(this); + + this._showTimeStamp = (new Date).valueOf(); + this.bringToFront(); +} + +qx.Proto._beforeDisappear = function() +{ + qx.ui.layout.CanvasLayout.prototype._beforeDisappear.call(this); + + qx.manager.object.PopupManager.getInstance().remove(this); + + this._hideTimeStamp = (new Date).valueOf(); +} + +qx.Proto._afterAppear = function() { + qx.ui.layout.CanvasLayout.prototype._afterAppear.call(this); + + if (this.getRestrictToPageOnOpen()) { + var doc = qx.ui.core.ClientDocument.getInstance(); + var docWidth = doc.getClientWidth(); + var docHeight = doc.getClientHeight(); + var restrictToPageLeft = parseInt(qx.Settings.getValueOfClass("qx.ui.popup.Popup", "restrictToPageLeft")); + var restrictToPageRight = parseInt(qx.Settings.getValueOfClass("qx.ui.popup.Popup", "restrictToPageRight")); + var restrictToPageTop = parseInt(qx.Settings.getValueOfClass("qx.ui.popup.Popup", "restrictToPageTop")); + var restrictToPageBottom = parseInt(qx.Settings.getValueOfClass("qx.ui.popup.Popup", "restrictToPageBottom")); + var left = (this._wantedLeft == null) ? this.getLeft() : this._wantedLeft; + var top = this.getTop(); + var width = this.getBoxWidth(); + var height = this.getBoxHeight(); + + var oldLeft = this.getLeft(); + var oldTop = top; + + // NOTE: We check right and bottom first, because top and left should have + // priority, when both sides are violated. + if (left + width > docWidth - restrictToPageRight) { + left = docWidth - restrictToPageRight - width; + } + if (top + height > docHeight - restrictToPageBottom) { + top = docHeight - restrictToPageBottom - height; + } + if (left < restrictToPageLeft) { + left = restrictToPageLeft; + } + if (top < restrictToPageTop) { + top = restrictToPageTop; + } + + if (left != oldLeft || top != oldTop) { + var self = this; + window.setTimeout(function() { + self.setLeft(left); + self.setTop(top); + qx.ui.core.Widget.flushGlobalQueues(); + }, 0); + } + } +}; + + + + + +/* +--------------------------------------------------------------------------- + ACTIVE/INACTIVE +--------------------------------------------------------------------------- +*/ + +qx.Proto._makeActive = function() { + this.getFocusRoot().setActiveChild(this); +} + +qx.Proto._makeInactive = function() +{ + var vRoot = this.getFocusRoot(); + var vCurrent = vRoot.getActiveChild(); + + if (vCurrent == this) { + vRoot.setActiveChild(vRoot); + } +} + + + + + +/* +--------------------------------------------------------------------------- + FOCUS +--------------------------------------------------------------------------- +*/ + +qx.Proto.isFocusable = function() { + return false; +} + + + + + +/* +--------------------------------------------------------------------------- + ZIndex Positioning +--------------------------------------------------------------------------- +*/ + +qx.Proto._minZIndex = 1e6; + +qx.Proto.bringToFront = function() +{ + this.forceZIndex(Infinity); + this._sendTo(); +} + +qx.Proto.sendToBack = function() +{ + this.forceZIndex(-Infinity); + this._sendTo(); +} + +qx.Proto._sendTo = function() +{ + var vPopups = qx.lang.Object.getValues(qx.manager.object.PopupManager.getInstance().getAll()); + var vMenus = qx.lang.Object.getValues(qx.manager.object.MenuManager.getInstance().getAll()); + + var vAll = vPopups.concat(vMenus).sort(qx.util.Compare.byZIndex); + var vLength = vAll.length; + var vIndex = this._minZIndex; + + for (var i=0; i (p - 5) && e < (p + 5); +} + +qx.Proto._onmousemove = function(e) +{ + var s = this._resizeSession; + + if (s) + { + if (this._resizeWest) + { + s.lastWidth = qx.lang.Number.limit(s.boxWidth + s.boxLeft - Math.max(e.getPageX(), s.parentAreaOffsetLeft), s.minWidth, s.maxWidth); + s.lastLeft = s.boxRight - s.lastWidth - s.parentAreaOffsetLeft; + } + else if (this._resizeEast) + { + s.lastWidth = qx.lang.Number.limit(Math.min(e.getPageX(), s.parentAreaOffsetRight) - s.boxLeft, s.minWidth, s.maxWidth); + } + + if (this._resizeNorth) + { + s.lastHeight = qx.lang.Number.limit(s.boxHeight + s.boxTop - Math.max(e.getPageY(), s.parentAreaOffsetTop), s.minHeight, s.maxHeight); + s.lastTop = s.boxBottom - s.lastHeight - s.parentAreaOffsetTop; + } + else if (this._resizeSouth) + { + s.lastHeight = qx.lang.Number.limit(Math.min(e.getPageY(), s.parentAreaOffsetBottom) - s.boxTop, s.minHeight, s.maxHeight); + } + + switch(this.getResizeMethod()) + { + case "opaque": + case "translucent": + if (this._resizeWest || this._resizeEast) + { + this.setWidth(s.lastWidth); + + if (this._resizeWest) { + this.setLeft(s.lastLeft); + } + } + + if (this._resizeNorth || this._resizeSouth) + { + this.setHeight(s.lastHeight); + + if (this._resizeNorth) { + this.setTop(s.lastTop); + } + } + + break; + + default: + var o = this.getResizeMethod() == "frame" ? this._frame : this; + + if (this._resizeWest || this._resizeEast) + { + o._applyRuntimeWidth(s.lastWidth); + + if (this._resizeWest) { + o._applyRuntimeLeft(s.lastLeft); + } + } + + if (this._resizeNorth || this._resizeSouth) + { + o._applyRuntimeHeight(s.lastHeight); + + if (this._resizeNorth) { + o._applyRuntimeTop(s.lastTop); + } + } + } + } + else + { + var resizeMode = ""; + var el = this.getElement(); + + this._resizeNorth = this._resizeSouth = this._resizeWest = this._resizeEast = false; + + if (this._near(qx.dom.Location.getPageBoxTop(el), e.getPageY())) + { + if (this.getResizeableNorth()) { + resizeMode = "n"; + this._resizeNorth = true; + } + } + else if (this._near(qx.dom.Location.getPageBoxBottom(el), e.getPageY())) + { + if (this.getResizeableSouth()) { + resizeMode = "s"; + this._resizeSouth = true; + } + } + + if (this._near(qx.dom.Location.getPageBoxLeft(el), e.getPageX())) + { + if (this.getResizeableWest()) { + resizeMode += "w"; + this._resizeWest = true; + } + } + else if (this._near(qx.dom.Location.getPageBoxRight(el), e.getPageX())) + { + if (this.getResizeableEast()) { + resizeMode += "e"; + this._resizeEast = true; + } + } + + if (this._resizeNorth || this._resizeSouth || this._resizeWest || this._resizeEast) + { + this.setCursor(resizeMode + "-resize"); + } + else + { + this.setCursor(null); + } + } + + // stop event + e.stopPropagation(); +} + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + if (this._frame) + { + this._frame.dispose(); + this._frame = null; + } + + return qx.ui.layout.CanvasLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/splitpane/HorizontalSplitPane.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/splitpane/HorizontalSplitPane.js new file mode 100644 index 0000000000..898ce097e4 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/splitpane/HorizontalSplitPane.js @@ -0,0 +1,58 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Volker Pauli + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_splitpane) + +************************************************************************ */ + +/** + * + * Creates a new instance of a horizontal SplitPane.

+ * + * new qx.ui.splitpane.HorizontalSplitPane()
+ * new qx.ui.splitpane.HorizontalSplitPane(firstSize, secondSize) + * + * @param firstSize {string} The size of the left pane. Allowed values are any by {@see qx.ui.core.Widget} supported unit. + * @param secondSize {string} The size of the right pane. Allowed values are any by {@see qx.ui.core.Widget} supported unit. + */ +qx.OO.defineClass("qx.ui.splitpane.HorizontalSplitPane", qx.ui.splitpane.SplitPane, +function(firstSize, secondSize) { + qx.ui.splitpane.SplitPane.call(this, "horizontal", firstSize, secondSize); +}); + + + + + +/* +------------------------------------------------------------------------------------ + DISPOSER +------------------------------------------------------------------------------------ + */ + +/** + * Garbage collection + */ +qx.Proto.dispose = function() { + if (this.getDisposed()) { + return true; + } + + return qx.ui.splitpane.SplitPane.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/splitpane/SplitPane.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/splitpane/SplitPane.js new file mode 100644 index 0000000000..b0b817f8ac --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/splitpane/SplitPane.js @@ -0,0 +1,759 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Volker Pauli (vpauli) + * Sebastian Werner (wpbasti) + * Carsten Lergenmueller (carstenL) + + ************************************************************************ */ + +/* ************************************************************************ + +#module(ui_splitpane) + + ************************************************************************ */ + + +/** + * Creates a new instance of a SplitPane. It allows the user to dynamically resize + * the areas dropping the border between. + * + * new qx.ui.splitpane.SplitPane(orientation) + * new qx.ui.splitpane.SplitPane(orientation, firstSize, secondSize) + * + * @param orientation {string} The orientation of the splitpane control. Allowed values are "horizontal" (default) and "vertical". This is the same type as used in {@link qx.ui.layout.BoxLayout#orientation}. + * @param firstSize {string} The size of the left (top) pane. Allowed values are any by {@link qx.ui.core.Widget} supported unit. + * @param secondSize {string} The size of the right (bottom) pane. Allowed values are any by {@link qx.ui.core.Widget} supported unit. + */ +qx.OO.defineClass("qx.ui.splitpane.SplitPane", qx.ui.layout.CanvasLayout, +function(orientation, firstSize, secondSize) +{ + qx.ui.layout.CanvasLayout.call(this); + + // CREATE INNER BOX LAYOUT + var box = this._box = new qx.ui.layout.BoxLayout; + box.setEdge(0); + this.add(box); + + /* + + the splitpane itself is a boxlayout resides on top of a canvas for easier computing of positional values + + --------------------------------------------------------------------------------------- + | canvas | + | ----------------------------------------------------------------------------------- | + | | box | | + | | --------------------------- --- ----------------------------------------------- | | + | | | | | | | | | | + | | | firstArea | |s| | secondArea | | | + | | | | |p| | | | | + | | | | |l| | | | | + | | | | |i| | | | | + | | | | |t| | | | | + | | | | |t| | | | | + | | | | |e| | | | | + | | | | |r| | | | | + | | | | | | | | | | + | | --------------------------- --- ----------------------------------------------- | | + | ----------------------------------------------------------------------------------- | + | | + --------------------------------------------------------------------------------------- + + */ + + // CREATE SLIDER + this._slider = new qx.ui.layout.CanvasLayout; + this._slider.setAppearance("splitpane-slider"); + this._slider.setStyleProperty("fontSize", "0px"); + this._slider.setStyleProperty("lineHeight", "0px"); + this._slider.hide(); + this._slider._pane = this; + this.add(this._slider); + + // CREATE SPLITTER + this._splitter = new qx.ui.layout.CanvasLayout; + this._splitter.setStyleProperty("fontSize", "0px"); + this._splitter.setStyleProperty("lineHeight", "0px"); + this._splitter.setAppearance("splitpane-splitter"); + this._splitter._pane = this; + + // PATCH METHODS + this._slider._applyRuntimeLeft = this._splitter._applyRuntimeLeft = this._applyRuntimeLeftWrapper; + this._slider._applyRuntimeTop = this._splitter._applyRuntimeTop = this._applyRuntimeTopWrapper; + + // CREATE KNOB + this._knob = new qx.ui.basic.Image; + this._knob.setAppearance("splitpane-knob"); + this._knob.setVisibility(false); + this.add(this._knob); + + // CREATE AREAS + this._firstArea = new qx.ui.layout.CanvasLayout; + this._secondArea = new qx.ui.layout.CanvasLayout; + + // FILL BOX + box.add(this._firstArea, this._splitter, this._secondArea); + + // APPLY DIMENSIONS + this.setFirstSize(firstSize || "1*"); + this.setSecondSize(secondSize || "1*"); + + // APPLY ORIENTATION + this.setOrientation(orientation || "horizontal"); +}); + + + + + + + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- + */ + +/** + * Appearance change + */ +qx.OO.changeProperty({ name : "appearance", defaultValue : "splitpane" }); + +/** + * Show the knob + */ +qx.OO.addProperty({ name : "showKnob", type : "boolean", allowNull : false, defaultValue : false }); + +/** + * The layout method for the splitpane. If true, the content will updated immediatly. + */ +qx.OO.addProperty({ name : "liveResize", type : "boolean", allowNull : false, defaultValue : false, getAlias : "isLiveResize"}); + +/** + * The orientation of the splitpane control. Allowed values are "horizontal" (default) and "vertical". + */ +qx.OO.addProperty({ name : "orientation", type : "string", possibleValues : [ "horizontal", "vertical" ] }); + +/** + * The size of the first (left/top) area. + */ +qx.OO.addProperty({ name : "firstSize" }); + +/** + * The size of the second (right/bottom) area. + */ +qx.OO.addProperty({ name : "secondSize" }); + +/** + * Size of the splitter + */ +qx.OO.addProperty({ name : "splitterSize", defaultValue : 4 }); + + + + + + + +/* +--------------------------------------------------------------------------- + PUBLIC METHODS +--------------------------------------------------------------------------- +*/ + + +/** + * adds one or more widget(s) to the left pane + * + *@param widget (qx.ui.core.Parent) + */ +qx.Proto.addLeft = function() { + var c = this.getFirstArea(); + return c.add.apply(c, arguments); +} + +/** + * adds one or more widget(s) to the top pane + * + *@param widget (qx.ui.core.Parent) + */ +qx.Proto.addTop = function() { + var c = this.getFirstArea(); + return c.add.apply(c, arguments); +} + +/** + * adds one or more widget(s) to the right pane + * + *@param widget (qx.ui.core.Parent) + */ +qx.Proto.addRight = function() { + var c = this.getSecondArea(); + return c.add.apply(c, arguments); +} + +/** + * adds one or more widget(s) to the bottom pane + * + *@param widget (qx.ui.core.Parent) + */ +qx.Proto.addBottom = function() { + var c = this.getSecondArea(); + return c.add.apply(c, arguments); +} + +/** + * Returns the splitter. + * + * @return {qx.ui.core.Widget} The splitter. + */ +qx.Proto.getSplitter = function() { + return this._splitter; +} + +/** + * Returns the knob. + * + * @return {qx.ui.core.Widget} The knob. + */ +qx.Proto.getKnob = function() { + return this._knob; +} + + + + + + +/** + * Returns the left area (CanvasLayout) + * + * @return {qx.ui.layout.CanvasLayout} + */ +qx.Proto.getLeftArea = function() { + return this.getFirstArea(); +} + +/** + * Returns the top area (CanvasLayout) + * + * @return {qx.ui.layout.CanvasLayout} + */ +qx.Proto.getTopArea = function() { + return this.getFirstArea(); +} + +/** + * Returns the right area (CanvasLayout) + * + * @return {qx.ui.layout.CanvasLayout} + */ +qx.Proto.getRightArea = function() { + return this.getSecondArea(); +} + +/** + * Returns the bottom area (CanvasLayout) + * + * @return {qx.ui.layout.CanvasLayout} + */ +qx.Proto.getBottomArea = function() { + return this.getSecondArea(); +} + +/** + * Returns the first area (CanvasLayout) + * + * @return {qx.ui.layout.CanvasLayout} + */ +qx.Proto.getFirstArea = function() { + return this._firstArea; +} + +/** + * Returns the second area (CanvasLayout) + * + * @return {qx.ui.layout.CanvasLayout} + */ +qx.Proto.getSecondArea = function() { + return this._secondArea; +} + + + + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyShowKnob = function(propValue, propOldValue, propData) +{ + this._knob.setVisibility(propValue); + return true; +} + +qx.Proto._modifyOrientation = function(propValue, propOldValue, propData) +{ + // sync orientation to layout + this._box.setOrientation(propValue); + + switch(propOldValue) + { + case "horizontal": + // remove old listeners + this._splitter.removeEventListener("mousedown", this._onSplitterMouseDownX, this); + this._splitter.removeEventListener("mousemove", this._onSplitterMouseMoveX, this); + this._splitter.removeEventListener("mouseup", this._onSplitterMouseUpX, this); + this._knob.removeEventListener("mousedown", this._onSplitterMouseDownX, this); + this._knob.removeEventListener("mousemove", this._onSplitterMouseMoveX, this); + this._knob.removeEventListener("mouseup", this._onSplitterMouseUpX, this); + + // reconfigure states + this._splitter.removeState("horizontal"); + this._knob.removeState("horizontal"); + + // reset old dimensions + this._firstArea.setWidth(null); + this._secondArea.setWidth(null); + this._splitter.setWidth(null); + + break; + + case "vertical": + // remove old listeners + this._splitter.removeEventListener("mousedown", this._onSplitterMouseDownY, this); + this._splitter.removeEventListener("mousemove", this._onSplitterMouseMoveY, this); + this._splitter.removeEventListener("mouseup", this._onSplitterMouseUpY, this); + this._knob.removeEventListener("mousedown", this._onSplitterMouseDownY, this); + this._knob.removeEventListener("mousemove", this._onSplitterMouseMoveY, this); + this._knob.removeEventListener("mouseup", this._onSplitterMouseUpY, this); + + // reconfigure states + this._splitter.removeState("vertical"); + this._knob.removeState("vertical"); + + // reset old dimensions + this._firstArea.setHeight(null); + this._secondArea.setHeight(null); + this._splitter.setHeight(null); + + break; + } + + switch(propValue) + { + case "horizontal": + // add new listeners + this._splitter.addEventListener("mousemove", this._onSplitterMouseMoveX, this); + this._splitter.addEventListener("mousedown", this._onSplitterMouseDownX, this); + this._splitter.addEventListener("mouseup", this._onSplitterMouseUpX, this); + this._knob.addEventListener("mousemove", this._onSplitterMouseMoveX, this); + this._knob.addEventListener("mousedown", this._onSplitterMouseDownX, this); + this._knob.addEventListener("mouseup", this._onSplitterMouseUpX, this); + + // reconfigure states + this._splitter.addState("horizontal"); + this._knob.addState("horizontal"); + + // apply images + this._knob.setSource("widget/splitpane/knob-horizontal.png"); + + break; + + case "vertical": + // add new listeners + this._splitter.addEventListener("mousedown", this._onSplitterMouseDownY, this); + this._splitter.addEventListener("mousemove", this._onSplitterMouseMoveY, this); + this._splitter.addEventListener("mouseup", this._onSplitterMouseUpY, this); + this._knob.addEventListener("mousedown", this._onSplitterMouseDownY, this); + this._knob.addEventListener("mousemove", this._onSplitterMouseMoveY, this); + this._knob.addEventListener("mouseup", this._onSplitterMouseUpY, this); + + // reconfigure states + this._splitter.addState("vertical"); + this._knob.addState("vertical"); + + // apply images + this._knob.setSource("widget/splitpane/knob-vertical.png"); + + break; + } + + // apply new dimensions + this._syncFirstSize(); + this._syncSecondSize(); + this._syncSplitterSize(); + + return true; +}; + +qx.Proto._modifyFirstSize = function(propValue, propOldValue, propData) +{ + this._syncFirstSize(); + return true; +} + +qx.Proto._modifySecondSize = function(propValue, propOldValue, propData) +{ + this._syncSecondSize(); + return true; +} + +qx.Proto._modifySplitterSize = function(propValue, propOldValue, propData) +{ + this._syncSplitterSize(); + return true; +} + +qx.Proto._syncFirstSize = function() +{ + switch(this.getOrientation()) + { + case "horizontal": + this._firstArea.setWidth(this.getFirstSize()); + break; + + case "vertical": + this._firstArea.setHeight(this.getFirstSize()); + break; + } +} + +qx.Proto._syncSecondSize = function() +{ + switch(this.getOrientation()) + { + case "horizontal": + this._secondArea.setWidth(this.getSecondSize()); + break; + + case "vertical": + this._secondArea.setHeight(this.getSecondSize()); + break; + } +} + +qx.Proto._syncSplitterSize = function() +{ + switch(this.getOrientation()) + { + case "horizontal": + this._splitter.setWidth(this.getSplitterSize()); + break; + + case "vertical": + this._splitter.setHeight(this.getSplitterSize()); + break; + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + EVENTS +--------------------------------------------------------------------------- +*/ + +/** + * Initializes drag session in case of a mousedown event on splitter in a horizontal splitpane. + * + * @param e {qx.event.MouseEvent} The event itself. + */ +qx.Proto._onSplitterMouseDownX = function(e) +{ + if (!e.isLeftButtonPressed()) { + return; + } + + this._commonMouseDown(); + + // activate global cursor + this.getTopLevelWidget().setGlobalCursor("col-resize"); + this._slider.addState("dragging"); + this._knob.addState("dragging"); + + // initialize the drag session + this._dragMin = qx.dom.Location.getPageInnerLeft(this._box.getElement()); + this._dragMax = this._dragMin + this._box.getInnerWidth() - this._splitter.getBoxWidth(); + this._dragOffset = e.getPageX() - qx.dom.Location.getPageBoxLeft(this._splitter.getElement()); +} + +/** + * Initializes drag session in case of a mousedown event on splitter in a vertical splitpane. + * + * @param e {qx.event.MouseEvent} The event itself. + */ +qx.Proto._onSplitterMouseDownY = function(e) +{ + if (!e.isLeftButtonPressed()) { + return; + } + + this._commonMouseDown(); + + // activate global cursor + this.getTopLevelWidget().setGlobalCursor("row-resize"); + this._slider.addState("dragging"); + this._knob.addState("dragging"); + + // initialize the drag session + // dragStart = position of layout + mouse offset on splitter + this._dragMin = qx.dom.Location.getPageInnerTop(this._box.getElement()); + this._dragMax = this._dragMin + this._box.getInnerHeight() - this._splitter.getBoxHeight(); + this._dragOffset = e.getPageY() - qx.dom.Location.getPageBoxTop(this._splitter.getElement()); +} + +qx.Proto._commonMouseDown = function() +{ + // enable capturing + this._splitter.setCapture(true); + + // initialize the slider + if(!this.isLiveResize()) + { + this._slider.setLeft(this._splitter.getOffsetLeft()); + this._slider.setTop(this._splitter.getOffsetTop()); + this._slider.setWidth(this._splitter.getBoxWidth()); + this._slider.setHeight(this._splitter.getBoxHeight()); + + this._slider.show(); + } +} + + + + + + + + +/** + * Move the splitter in case of a mousemove event on splitter in a horizontal splitpane. + * + * @param e {qx.event.MouseEvent} The event itself. + */ +qx.Proto._onSplitterMouseMoveX = function(e) +{ + if (!this._splitter.getCapture()) { + return; + } + + this.isLiveResize() ? this._syncX(e) : this._slider._applyRuntimeLeft(this._normalizeX(e)); + e.preventDefault(); +} + +/** + * Move the splitter in case of a mousemove event on splitter in a vertical splitpane. + * + * @param e {qx.event.MouseEvent} The event itself. + */ +qx.Proto._onSplitterMouseMoveY = function(e) +{ + if (!this._splitter.getCapture()) { + return; + } + + this.isLiveResize() ? this._syncY(e) : this._slider._applyRuntimeTop(this._normalizeY(e)); + e.preventDefault(); +} + + + + + + + +/** + * Ends the drag session and computes the new dimensions of panes in case of a mouseup event on splitter in a horizontal splitpane. + * + * @param e {qx.event.MouseEvent} The event itself. + */ +qx.Proto._onSplitterMouseUpX = function(e) +{ + if (!this._splitter.getCapture()) { + return; + } + + if(!this.isLiveResize()) { + this._syncX(e); + } + + this._commonMouseUp(); +} + +/** + * Ends the drag session and computes the new dimensions of panes in case of a mouseup event on splitter in a vertical splitpane. + * + * @param e {qx.event.MouseEvent} The event itself. + */ +qx.Proto._onSplitterMouseUpY = function(e) +{ + if (!this._splitter.getCapture()) { + return; + } + + if(!this.isLiveResize()) { + this._syncY(e); + } + + this._commonMouseUp(); +} + +qx.Proto._commonMouseUp = function() +{ + // hide helpers + this._slider.hide(); + + // disable capturing + this._splitter.setCapture(false); + + // reset the global cursor + this.getTopLevelWidget().setGlobalCursor(null); + + // cleanup dragsession + this._slider.removeState("dragging"); + this._knob.removeState("dragging"); +} + +qx.Proto._syncX = function(e) +{ + var first = this._normalizeX(e); + var second = this._box.getInnerWidth() - this._splitter.getBoxWidth() - first; + + this._syncCommon(first, second); +} + +qx.Proto._syncY = function(e) +{ + var first = this._normalizeY(e); + var second = this._box.getInnerHeight() - this._splitter.getBoxHeight() - first; + + this._syncCommon(first, second); +} + +qx.Proto._syncCommon = function(first, second) +{ + this.setFirstSize(first + "*"); + this.setSecondSize(second + "*"); +} + +qx.Proto._normalizeX = function(e) { + return qx.lang.Number.limit(e.getPageX() - this._dragOffset, this._dragMin, this._dragMax) - this._dragMin; +} + +qx.Proto._normalizeY = function(e) { + return qx.lang.Number.limit(e.getPageY() - this._dragOffset, this._dragMin, this._dragMax) - this._dragMin; +} + +qx.Proto._applyRuntimeLeftWrapper = function(v) +{ + if (this._pane.getOrientation() == "horizontal") { + this._pane._knob._applyRuntimeLeft(v); + } + + return this.constructor.prototype._applyRuntimeLeft.call(this, v); +} + +qx.Proto._applyRuntimeTopWrapper = function(v) +{ + if (this._pane.getOrientation() == "vertical") { + this._pane._knob._applyRuntimeTop(v); + } + + return this.constructor.prototype._applyRuntimeTop.call(this, v); +} + + + + + +/* +------------------------------------------------------------------------------------ + DISPOSER +------------------------------------------------------------------------------------ + */ + +/** + * Garbage collection + */ +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + if(this._firstArea) + { + this._firstArea.dispose(); + this._firstArea = null; + } + + if(this._secondArea) + { + this._secondArea.dispose(); + this._secondArea = null; + } + + if (this._splitter) + { + this._splitter.removeEventListener("mousedown", this._onSplitterMouseDownX, this); + this._splitter.removeEventListener("mouseup", this._onSplitterMouseMoveX, this); + this._splitter.removeEventListener("mousemove", this._onSplitterMouseUpX, this); + + this._splitter.removeEventListener("mousedown", this._onSplitterMouseDownY, this); + this._splitter.removeEventListener("mouseup", this._onSplitterMouseMoveY, this); + this._splitter.removeEventListener("mousemove", this._onSplitterMouseUpY, this); + + this._splitter.dispose(); + this._splitter._pane = null; + this._splitter = null; + } + + if (this._slider) + { + this._slider.dispose(); + this._slider._pane = null; + this._slider = null; + } + + if (this._knob) + { + this._knob.removeEventListener("mousedown", this._onSplitterMouseDownX, this); + this._knob.removeEventListener("mouseup", this._onSplitterMouseMoveX, this); + this._knob.removeEventListener("mousemove", this._onSplitterMouseUpX, this); + + this._knob.removeEventListener("mousedown", this._onSplitterMouseDownY, this); + this._knob.removeEventListener("mouseup", this._onSplitterMouseMoveY, this); + this._knob.removeEventListener("mousemove", this._onSplitterMouseUpY, this); + + this._knob.dispose(); + this._knob = null; + } + + return qx.ui.layout.BoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/splitpane/VerticalSplitPane.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/splitpane/VerticalSplitPane.js new file mode 100644 index 0000000000..76201484a3 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/splitpane/VerticalSplitPane.js @@ -0,0 +1,58 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Volker Pauli + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_splitpane) + +************************************************************************ */ + +/** + * + * Creates a new instance of a vertical SplitPane.

+ * + * new qx.ui.splitpane.VerticalSplitPane()
+ * new qx.ui.splitpane.VerticalSplitPane(firstSize, secondSize) + * + * @param firstSize {string} The size of the top pane. Allowed values are any by {@see qx.ui.core.Widget} supported unit. + * @param secondSize {string} The size of the bottom pane. Allowed values are any by {@see qx.ui.core.Widget} supported unit. + */ +qx.OO.defineClass("qx.ui.splitpane.VerticalSplitPane", qx.ui.splitpane.SplitPane, +function(firstSize, secondSize) { + qx.ui.splitpane.SplitPane.call(this, "vertical", firstSize, secondSize); +}); + + + + + +/* +------------------------------------------------------------------------------------ + DISPOSER +------------------------------------------------------------------------------------ + */ + +/** + * Garbage collection + */ +qx.Proto.dispose = function() { + if (this.getDisposed()) { + return true; + } + + return qx.ui.splitpane.SplitPane.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/AbstractDataCellRenderer.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/AbstractDataCellRenderer.js new file mode 100644 index 0000000000..d3d7950bd5 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/AbstractDataCellRenderer.js @@ -0,0 +1,127 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 by STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * An abstract data cell renderer that does the basic coloring + * (borders, selected look, ...). + */ +qx.OO.defineClass("qx.ui.table.AbstractDataCellRenderer", qx.ui.table.DataCellRenderer, +function() { + qx.ui.table.DataCellRenderer.call(this); +}); + + +// overridden +qx.Proto.createDataCellHtml = function(cellInfo) { + var AbstractDataCellRenderer = qx.ui.table.AbstractDataCellRenderer; + return AbstractDataCellRenderer.MAIN_DIV_START + this._getCellStyle(cellInfo) + + AbstractDataCellRenderer.MAIN_DIV_START_END + + this._getContentHtml(cellInfo) + AbstractDataCellRenderer.MAIN_DIV_END; +} + + +// overridden +qx.Proto.updateDataCellElement = function(cellInfo, cellElement) { + cellElement.innerHTML = this._getContentHtml(cellInfo); +} + + +/** + * Returns the CSS styles that should be applied to the main div of this cell. + * + * @param cellInfo {Map} The information about the cell. + * See {@link #createDataCellHtml}. + * @return the CSS styles of the main div. + */ +qx.Proto._getCellStyle = function(cellInfo) { + return cellInfo.style + qx.ui.table.AbstractDataCellRenderer.MAIN_DIV_STYLE; +} + + +/** + * Returns the HTML that should be used inside the main div of this cell. + * + * @param cellInfo {Map} The information about the cell. + * See {@link #createDataCellHtml}. + * @return {string} the inner HTML of the main div. + */ +qx.Proto._getContentHtml = function(cellInfo) { + return cellInfo.value; +} + + +qx.Proto.createDataCellHtml_array_join = function(cellInfo, htmlArr) { + var AbstractDataCellRenderer = qx.ui.table.AbstractDataCellRenderer; + + if (qx.ui.table.TablePane.USE_TABLE) { + htmlArr.push(AbstractDataCellRenderer.TABLE_TD); + htmlArr.push(cellInfo.styleHeight); + htmlArr.push("px"); + } else { + htmlArr.push(AbstractDataCellRenderer.ARRAY_JOIN_MAIN_DIV_LEFT); + htmlArr.push(cellInfo.styleLeft); + htmlArr.push(AbstractDataCellRenderer.ARRAY_JOIN_MAIN_DIV_WIDTH); + htmlArr.push(cellInfo.styleWidth); + htmlArr.push(AbstractDataCellRenderer.ARRAY_JOIN_MAIN_DIV_HEIGHT); + htmlArr.push(cellInfo.styleHeight); + htmlArr.push("px"); + } + + this._createCellStyle_array_join(cellInfo, htmlArr); + + htmlArr.push(AbstractDataCellRenderer.ARRAY_JOIN_MAIN_DIV_START_END); + + this._createContentHtml_array_join(cellInfo, htmlArr); + + if (qx.ui.table.TablePane.USE_TABLE) { + htmlArr.push(AbstractDataCellRenderer.TABLE_TD_END); + } else { + htmlArr.push(AbstractDataCellRenderer.ARRAY_JOIN_MAIN_DIV_END); + } +} + + +qx.Proto._createCellStyle_array_join = function(cellInfo, htmlArr) { + htmlArr.push(qx.ui.table.AbstractDataCellRenderer.MAIN_DIV_STYLE); +} + + +qx.Proto._createContentHtml_array_join = function(cellInfo, htmlArr) { + htmlArr.push(cellInfo.value); +} + + +qx.Class.MAIN_DIV_START = '
'; +qx.Class.MAIN_DIV_END = '
'; +qx.Class.MAIN_DIV_STYLE = ';overflow:hidden;white-space:nowrap;border-right:1px solid #eeeeee;border-bottom:1px solid #eeeeee;padding-left:2px;padding-right:2px;cursor:default' + + (qx.sys.Client.getInstance().isMshtml() ? '' : ';-moz-user-select:none;'); + +qx.Class.ARRAY_JOIN_MAIN_DIV_LEFT = '
'; +qx.Class.ARRAY_JOIN_MAIN_DIV_END = '
'; + +qx.Class.TABLE_TD = ' + * Note: This will clear previously set column names. + *

+ * + * @param columnIdArr {string[]} the IDs of the columns. + * @see #setColumns + */ +qx.Proto.setColumnIds = function(columnIdArr) { + this._columnIdArr = columnIdArr; + + // Create the reverse map + this._columnIndexMap = {}; + for (var i = 0; i < columnIdArr.length; i++) { + this._columnIndexMap[columnIdArr[i]] = i; + } + this._columnNameArr = new Array(columnIdArr.length); + + // Inform the listeners + if (!this._internalChange) { + this.createDispatchEvent(qx.ui.table.TableModel.EVENT_TYPE_META_DATA_CHANGED); + } +} + + +/** + * Sets the column names. These names will be shown to the user. + *

+ * Note: The column IDs have to be defined before. + *

+ * + * @param columnNameArr {string[]} the names of the columns. + * @see #setColumnIds + */ +qx.Proto.setColumnNamesByIndex = function(columnNameArr) { + if (this._columnIdArr.length != columnNameArr.length) { + throw new Error("this._columnIdArr and columnNameArr have different length: " + + this._columnIdArr.length + " != " + columnNameArr.length); + } + this._columnNameArr = columnNameArr; + + // Inform the listeners + this.createDispatchEvent(qx.ui.table.TableModel.EVENT_TYPE_META_DATA_CHANGED); +} + + +/** + * Sets the column names. These names will be shown to the user. + *

+ * Note: The column IDs have to be defined before. + *

+ * + * @param columnNameMap {Map} a map containing the column IDs as keys and the + * column name as values. + * @see #setColumnIds + */ +qx.Proto.setColumnNamesById = function(columnNameMap) { + this._columnNameArr = new Array(this._columnIdArr.length); + for (var i = 0; i < this._columnIdArr.length; ++i) { + this._columnNameArr[i] = columnNameMap[this._columnIdArr[i]]; + } +} + + +/** + * Sets the columns. + * + * @param columnNameArr {string[]} The column names. These names will be shown to + * the user. + * @param columnIdArr {string[] ? null} The column IDs. These IDs may be used + * internally to identify a column. If null, the column names are used as + * IDs. + */ +qx.Proto.setColumns = function(columnNameArr, columnIdArr) { + if (columnIdArr == null) { + columnIdArr = columnNameArr; + } + + if (columnIdArr.length != columnNameArr.length) { + throw new Error("columnIdArr and columnNameArr have different length: " + + columnIdArr.length + " != " + columnNameArr.length); + } + + this._internalChange = true; + this.setColumnIds(columnIdArr); + this._internalChange = false; + this.setColumnNamesByIndex(columnNameArr); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/BooleanDataCellRenderer.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/BooleanDataCellRenderer.js new file mode 100644 index 0000000000..13df2cd2f4 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/BooleanDataCellRenderer.js @@ -0,0 +1,48 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 by STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Til Schneider (til132) + * Carsten Lergenmueller (carstenl) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * A data cell renderer for boolean values. + */ +qx.OO.defineClass("qx.ui.table.BooleanDataCellRenderer", qx.ui.table.IconDataCellRenderer, +function() { + qx.ui.table.IconDataCellRenderer.call(this); + + this._iconUrlTrue = qx.manager.object.AliasManager.getInstance().resolvePath("widget/table/boolean-true.png"); + this._iconUrlFalse = qx.manager.object.AliasManager.getInstance().resolvePath("widget/table/boolean-false.png"); + this._iconUrlNull = qx.manager.object.AliasManager.getInstance().resolvePath("static/image/blank.gif"); + +}); + +//overridden +qx.Proto._identifyImage = function(cellInfo) { + var IconDataCellRenderer = qx.ui.table.IconDataCellRenderer; + var imageHints = { imageWidth:11, imageHeight:11 }; + switch (cellInfo.value) { + case true: imageHints.url = this._iconUrlTrue; break; + case false: imageHints.url = this._iconUrlFalse; break; + default: imageHints.url = this._iconUrlNull; break; + } + return imageHints; +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/CellEditorFactory.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/CellEditorFactory.js new file mode 100644 index 0000000000..817954f40f --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/CellEditorFactory.js @@ -0,0 +1,62 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 by STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * A factory creating widgets to use for editing table cells. + */ +qx.OO.defineClass("qx.ui.table.CellEditorFactory", qx.core.Object, +function() { + qx.core.Object.call(this); +}); + + +/** + * Creates a cell editor. + *

+ * The cellInfo map contains the following properties: + *

    + *
  • value (var): the cell's value.
  • + *
  • row (int): the model index of the row the cell belongs to.
  • + *
  • col (int): the model index of the column the cell belongs to.
  • + *
  • xPos (int): the x position of the cell in the table pane.
  • + *
+ * + * @param cellInfo {Map} A map containing the information about the cell to + * create. + * @return {qx.ui.core.Widget} the widget that should be used as cell editor. + */ +qx.Proto.createCellEditor = function(cellInfo) { + throw new Error("createCellEditor is abstract"); +} + + +/** + * Returns the current value of a cell editor. + * + * @param cellEditor {qx.ui.core.Widget} The cell editor formally created by + * {@link #createCellEditor}. + * @return {var} the current value from the editor. + */ +qx.Proto.getCellEditorValue = function(cellEditor) { + throw new Error("getCellEditorValue is abstract"); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/CheckBoxCellEditorFactory.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/CheckBoxCellEditorFactory.js new file mode 100644 index 0000000000..d5609a4b77 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/CheckBoxCellEditorFactory.js @@ -0,0 +1,43 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 by David Perez + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * David Perez (david-perez) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * For editing boolean data in a checkbox. It is advisable to use this in conjuntion with BooleanDataCellRenderer. + */ +qx.OO.defineClass("qx.ui.table.CheckBoxCellEditorFactory", qx.ui.table.CellEditorFactory, function() { + qx.ui.table.CellEditorFactory.call(this); +}); + +// overridden +qx.Proto.createCellEditor = function(cellInfo) { + var editor = new qx.ui.form.CheckBox; + with (editor) { + setChecked(cellInfo.value); + } + return editor; +} + +// overridden +qx.Proto.getCellEditorValue = function(cellEditor) { + return cellEditor.getChecked(); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/DataCellRenderer.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/DataCellRenderer.js new file mode 100644 index 0000000000..46f808df32 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/DataCellRenderer.js @@ -0,0 +1,80 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 by STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * A cell renderer for data cells. + */ +qx.OO.defineClass("qx.ui.table.DataCellRenderer", qx.core.Object, +function() { + qx.core.Object.call(this); +}); + + +/** + * Creates the HTML for a data cell. + *

+ * The cellInfo map contains the following properties: + *

    + *
  • value (var): the cell's value.
  • + *
  • rowData (var): contains the row data for the row, the cell belongs to. + * The kind of this object depends on the table model, see + * {@link TableModel#getRowData()}
  • + *
  • row (int): the model index of the row the cell belongs to.
  • + *
  • col (int): the model index of the column the cell belongs to.
  • + *
  • table (qx.ui.table.Table): the table the cell belongs to.
  • + *
  • xPos (int): the x position of the cell in the table pane.
  • + *
  • selected (boolean): whether the cell is selected.
  • + *
  • focusedCol (boolean): whether the cell is in the same column as the + * focused cell.
  • + *
  • focusedRow (boolean): whether the cell is in the same row as the + * focused cell.
  • + *
  • editable (boolean): whether the cell is editable.
  • + *
  • style (string): The CSS styles that should be applied to the outer HTML + * element.
  • + *
+ * + * @param cellInfo {Map} A map containing the information about the cell to + * create. + * @return {string} the HTML of the data cell. + */ +qx.Proto.createDataCellHtml = function(cellInfo) { + throw new Error("createDataCellHtml is abstract"); +} + + +/** + * Updates a data cell. + * + * @param cellInfo {Map} A map containing the information about the cell to + * create. This map has the same structure as in {@link #createDataCell}. + * @param cellElement {element} the DOM element that renders the data cell. This + * is the same element formally created by the HTML from {@link #createDataCell}. + */ +qx.Proto.updateDataCellElement = function(cellInfo, cellElement) { + throw new Error("updateDataCellElement is abstract"); +} + + +qx.Proto.createDataCellHtml_array_join = function(cellInfo, htmlArr) { + throw new Error("createDataCellHtml_array_join is abstract"); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/DataRowRenderer.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/DataRowRenderer.js new file mode 100644 index 0000000000..9cd4c86961 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/DataRowRenderer.js @@ -0,0 +1,54 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 by STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * A cell renderer for data rows. + */ +qx.OO.defineClass("qx.ui.table.DataRowRenderer", qx.core.Object, +function() { + qx.core.Object.call(this); +}); + + +/** + * Updates a data row. + *

+ * The rowInfo map contains the following properties: + *

    + *
  • rowData (var): contains the row data for the row. + * The kind of this object depends on the table model, see + * {@link TableModel#getRowData()}
  • + *
  • row (int): the model index of the row.
  • + *
  • selected (boolean): whether a cell in this row is selected.
  • + *
  • focusedRow (boolean): whether the focused cell is in this row.
  • + *
  • table (qx.ui.table.Table): the table the row belongs to.
  • + *
+ * + * @param rowInfo {Map} A map containing the information about the row to + * update. This map has the same structure as in {@link #createDataCell}. + * @param cellElement {element} the DOM element that renders the data rot. This + * is the same element formally created by the HTML from {@link #createDataCell}. + */ +qx.Proto.updateDataRowElement = function(rowInfo, rowElement) { + throw new Error("updateDataRowElement is abstract"); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/DefaultDataCellRenderer.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/DefaultDataCellRenderer.js new file mode 100644 index 0000000000..4de4341037 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/DefaultDataCellRenderer.js @@ -0,0 +1,189 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 by STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +// This is needed because of the instantiation at the end of this file. +// I don't think this is a good idea. (wpbasti) +#require(qx.util.format.NumberFormat) + +************************************************************************ */ + +/** + * The default data cell renderer. + */ +qx.OO.defineClass("qx.ui.table.DefaultDataCellRenderer", qx.ui.table.AbstractDataCellRenderer, +function() { + qx.ui.table.AbstractDataCellRenderer.call(this); +}); + + +/** + * Whether the alignment should automatically be set according to the cell value. + * If true numbers will be right-aligned. + */ +qx.OO.addProperty({ name:"useAutoAlign", type:"boolean", defaultValue:true, allowNull:false }); + + +// overridden +qx.Proto._getCellStyle = function(cellInfo) { + var style = qx.ui.table.AbstractDataCellRenderer.prototype._getCellStyle(cellInfo); + + var stylesToApply = this._getStyleFlags(cellInfo); + if (stylesToApply & qx.ui.table.DefaultDataCellRenderer.STYLEFLAG_ALIGN_RIGHT){ + style += ";text-align:right"; + } + if (stylesToApply & qx.ui.table.DefaultDataCellRenderer.STYLEFLAG_BOLD){ + style += ";font-weight:bold"; + } + if (stylesToApply & qx.ui.table.DefaultDataCellRenderer.STYLEFLAG_ITALIC){ + style += ";font-style:italic"; + } + + return style; +} + +/** + * Determines the styles to apply to the cell + * + * @param cellInfo {Object} cellInfo of the cell + * @return the sum of any of the STYLEFLAGS defined below + */ +qx.Proto._getStyleFlags = function(cellInfo) { + if (this.getUseAutoAlign()) { + if (typeof cellInfo.value == "number") { + return qx.ui.table.DefaultDataCellRenderer.STYLEFLAG_ALIGN_RIGHT; + } + } +} + + +// overridden +qx.Proto._getContentHtml = function(cellInfo) { + return qx.ui.table.DefaultDataCellRenderer.escapeHtml(this._formatValue(cellInfo)); +} + + +// overridden +qx.Proto.updateDataCellElement = function(cellInfo, cellElement) { + var style = qx.ui.table.AbstractDataCellRenderer.prototype._getCellStyle(cellInfo); + + var stylesToApply = this._getStyleFlags(cellInfo); + if (stylesToApply & qx.ui.table.DefaultDataCellRenderer.STYLEFLAG_ALIGN_RIGHT){ + cellElement.style.textAlign = "right"; + } else { + cellElement.style.textAlign = ""; + } + + if (stylesToApply & qx.ui.table.DefaultDataCellRenderer.STYLEFLAG_BOLD){ + cellElement.style.fontWeight = "bold"; + } else { + cellElement.style.fontWeight = ""; + } + + if (stylesToApply & qx.ui.table.DefaultDataCellRenderer.STYLEFLAG_ITALIC){ + cellElement.style.fontStyle = "ital"; + } else { + cellElement.style.fontStyle = ""; + } + + var textNode = cellElement.firstChild; + if (textNode != null) { + textNode.nodeValue = this._formatValue(cellInfo); + } else { + cellElement.innerHTML = qx.ui.table.DefaultDataCellRenderer.escapeHtml(this._formatValue(cellInfo)); + } +} + + +/** + * Formats a value. + * + * @param cellInfo {Map} A map containing the information about the cell to + * create. This map has the same structure as in + * {@link DataCellRenderer#createDataCell}. + * @return {string} the formatted value. + */ +qx.Proto._formatValue = function(cellInfo) { + var value = cellInfo.value; + if (value == null) { + return ""; + } else if (typeof value == "number") { + return qx.ui.table.DefaultDataCellRenderer._numberFormat.format(value); + } else if (value instanceof Date) { + return qx.util.format.DateFormat.getDateInstance().format(value); + } else { + return value; + } +} + + +qx.Proto._createCellStyle_array_join = function(cellInfo, htmlArr) { + qx.ui.table.AbstractDataCellRenderer.prototype._createCellStyle_array_join(cellInfo, htmlArr); + + var stylesToApply = this._getStyleFlags(cellInfo); + if (stylesToApply & qx.ui.table.DefaultDataCellRenderer.STYLEFLAG_ALIGN_RIGHT){ + htmlArr.push(";text-align:right"); + } + if (stylesToApply & qx.ui.table.DefaultDataCellRenderer.STYLEFLAG_BOLD){ + htmlArr.push(";font-weight:bold"); + } + if (stylesToApply & qx.ui.table.DefaultDataCellRenderer.STYLEFLAG_ITALIC){ + htmlArr.push(";font-style:italic"); + } +} + + +qx.Proto._createContentHtml_array_join = function(cellInfo, htmlArr) { + htmlArr.push(qx.ui.table.DefaultDataCellRenderer.escapeHtml(this._formatValue(cellInfo))); +} + + +/** + * Escapes special HTML characters by their entities. + * + * @param html {string} The HTML to escape. + * @return {string} The escaped string showing HTML code as plain text. + */ +qx.Class.escapeHtml = function(html) { + return html.replace(/[<>&]/gi, qx.ui.table.DefaultDataCellRenderer._escapeHtmlReplacer); +} + + +/** + * Helper method for {@link #escapeHtml}. + */ +qx.Class._escapeHtmlReplacer = function(str) { + switch(str) { + case "<": return "<"; + case ">": return ">"; + case "&": return "&"; + } +} + + +qx.Class._numberFormat = new qx.util.format.NumberFormat(); +qx.Class._numberFormat.setMaximumFractionDigits(2); + +qx.Class.STYLEFLAG_ALIGN_RIGHT = 1; +qx.Class.STYLEFLAG_BOLD = 2; +qx.Class.STYLEFLAG_ITALIC = 4; + + + diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/DefaultDataRowRenderer.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/DefaultDataRowRenderer.js new file mode 100644 index 0000000000..8fd2198cd4 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/DefaultDataRowRenderer.js @@ -0,0 +1,106 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 by STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * The default data row renderer. + */ +qx.OO.defineClass("qx.ui.table.DefaultDataRowRenderer", qx.ui.table.DataRowRenderer, +function() { + qx.ui.table.DataRowRenderer.call(this); +}); + + +/** Whether the focused row should be highlighted. */ +qx.OO.addProperty({ name:"highlightFocusRow", type:"boolean", allowNull:false, defaultValue:true}); + +/** + * Whether the focused row and the selection should be grayed out when the table + * hasn't the focus. + */ +qx.OO.addProperty({ name:"visualizeFocusedState", type:"boolean", allowNull:false, defaultValue:true}); + + +// overridden +qx.Proto.updateDataRowElement = function(rowInfo, rowElem) { + var clazz = qx.ui.table.DefaultDataRowRenderer; + + if (rowInfo.focusedRow && this.getHighlightFocusRow()) { + if (rowInfo.table.getFocused() || !this.getVisualizeFocusedState()) { + rowElem.style.backgroundColor = rowInfo.selected ? clazz.BGCOL_FOCUSED_SELECTED : clazz.BGCOL_FOCUSED; + } else { + rowElem.style.backgroundColor = rowInfo.selected ? clazz.BGCOL_FOCUSED_SELECTED_BLUR : clazz.BGCOL_FOCUSED_BLUR; + } + } else { + if (rowInfo.selected) { + if (rowInfo.table.getFocused() || !this.getVisualizeFocusedState()) { + rowElem.style.backgroundColor = clazz.BGCOL_SELECTED; + } else { + rowElem.style.backgroundColor = clazz.BGCOL_SELECTED_BLUR; + } + } else { + rowElem.style.backgroundColor = (rowInfo.row % 2 == 0) ? clazz.BGCOL_EVEN : clazz.BGCOL_ODD; + } + } + rowElem.style.color = rowInfo.selected ? clazz.COL_SELECTED : clazz.COL_NORMAL; +} + + +qx.Proto._createRowStyle_array_join = function(rowInfo, htmlArr) { + var clazz = qx.ui.table.DefaultDataRowRenderer; + + htmlArr.push(clazz.ARRAY_JOIN_BG_COLOR); + if (rowInfo.focusedRow && this.getHighlightFocusRow()) { + if (rowInfo.table.getFocused() || !this.getVisualizeFocusedState()) { + htmlArr.push(rowInfo.selected ? clazz.BGCOL_FOCUSED_SELECTED : clazz.BGCOL_FOCUSED); + } else { + htmlArr.push(rowInfo.selected ? clazz.BGCOL_FOCUSED_SELECTED_BLUR : clazz.BGCOL_FOCUSED_BLUR); + } + } else { + if (rowInfo.selected) { + if (rowInfo.table.getFocused() || !this.getVisualizeFocusedState()) { + htmlArr.push(clazz.BGCOL_SELECTED); + } else { + htmlArr.push(clazz.BGCOL_SELECTED_BLUR); + } + } else { + htmlArr.push((rowInfo.row % 2 == 0) ? clazz.BGCOL_EVEN : clazz.BGCOL_ODD); + } + } + htmlArr.push(clazz.ARRAY_JOIN_COLOR); + htmlArr.push(rowInfo.selected ? clazz.COL_SELECTED : clazz.COL); +} + + +qx.Class.BGCOL_FOCUSED_SELECTED = "#5a8ad3"; +qx.Class.BGCOL_FOCUSED_SELECTED_BLUR = "#b3bac6"; +qx.Class.BGCOL_FOCUSED = "#ddeeff"; +qx.Class.BGCOL_FOCUSED_BLUR = "#dae0e7"; +qx.Class.BGCOL_SELECTED = "#335ea8"; +qx.Class.BGCOL_SELECTED_BLUR = "#989ea8"; +qx.Class.BGCOL_EVEN = "#faf8f3"; +qx.Class.BGCOL_ODD = "white"; +qx.Class.COL_SELECTED = "white"; +qx.Class.COL_NORMAL = "black"; + +qx.Class.ARRAY_JOIN_BG_COLOR = ";background-color:"; +qx.Class.ARRAY_JOIN_COLOR = ';color:'; diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/DefaultHeaderCellRenderer.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/DefaultHeaderCellRenderer.js new file mode 100644 index 0000000000..060b095a14 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/DefaultHeaderCellRenderer.js @@ -0,0 +1,63 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 by STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * The default header cell renderer. + */ +qx.OO.defineClass("qx.ui.table.DefaultHeaderCellRenderer", qx.ui.table.HeaderCellRenderer, +function() { + qx.ui.table.HeaderCellRenderer.call(this); +}); + + +// overridden +qx.Proto.createHeaderCell = function(cellInfo) { + var widget = new qx.ui.basic.Atom(); + widget.setAppearance("table-header-cell"); + + this.updateHeaderCell(cellInfo, widget); + + return widget; +} + + +// overridden +qx.Proto.updateHeaderCell = function(cellInfo, cellWidget) { + var DefaultHeaderCellRenderer = qx.ui.table.DefaultHeaderCellRenderer; + + cellWidget.setLabel(cellInfo.name); + + cellWidget.setIcon(cellInfo.sorted ? (cellInfo.sortedAscending ? "widget/table/ascending.png" : "widget/table/descending.png") : null); + cellWidget.setState(DefaultHeaderCellRenderer.STATE_SORTED, cellInfo.sorted); + cellWidget.setState(DefaultHeaderCellRenderer.STATE_SORTED_ASCENDING, cellInfo.sortedAscending); +} + +/** + * (string) The state which will be set for header cells of sorted columns. + */ +qx.Class.STATE_SORTED = "sorted"; + +/** + * (string) The state which will be set when sorting is ascending. + */ +qx.Class.STATE_SORTED_ASCENDING = "sortedAscending"; diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/HeaderCellRenderer.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/HeaderCellRenderer.js new file mode 100644 index 0000000000..2108778efb --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/HeaderCellRenderer.js @@ -0,0 +1,69 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 by STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * A cell renderer for header cells. + */ +qx.OO.defineClass("qx.ui.table.HeaderCellRenderer", qx.core.Object, +function() { + qx.core.Object.call(this); +}); + + +/** + * Creates a header cell. + *

+ * The cellInfo map contains the following properties: + *

    + *
  • col (int): the model index of the column.
  • + *
  • xPos (int): the x position of the column in the table pane.
  • + *
  • name (string): the name of the column.
  • + *
  • editable (boolean): whether the column is editable.
  • + *
  • sorted (boolean): whether the column is sorted.
  • + *
  • sortedAscending (boolean): whether sorting is ascending.
  • + *
+ * + * @param cellInfo {Map} A map containing the information about the cell to + * create. + * @return {qx.ui.core.Widget} the widget that renders the header cell. + */ +qx.Proto.createHeaderCell = function(cellInfo) { + throw new Error("createHeaderCell is abstract"); +} + + +/** + * Updates a header cell. + * + * @param cellInfo {Map} A map containing the information about the cell to + * create. This map has the same structure as in {@link #createHeaderCell}. + * @param cellWidget {qx.ui.core.Widget} the widget that renders the header cell. This is + * the same widget formally created by {@link #createHeaderCell}. + */ +qx.Proto.updateHeaderCell = function(cellInfo, cellWidget) { + throw new Error("updateHeaderCell is abstract"); +} + + +/** The preferred height of cells created by this header renderer. */ +qx.OO.addProperty({ name:"prefferedCellHeight", type:"number", defaultValue:16, allowNull:false }); diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/IconDataCellRenderer.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/IconDataCellRenderer.js new file mode 100644 index 0000000000..b4a717527b --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/IconDataCellRenderer.js @@ -0,0 +1,182 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 by STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Til Schneider (til132) + * Carsten Lergenmueller (carstenl) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * A data cell renderer for boolean values. + */ +qx.OO.defineClass("qx.ui.table.IconDataCellRenderer", qx.ui.table.AbstractDataCellRenderer, +function() { + qx.ui.table.AbstractDataCellRenderer.call(this); + this.IMG_BLANK_URL = qx.manager.object.AliasManager.getInstance().resolvePath("static/image/blank.gif"); +}); + + +/** + * Identifies the Image to show. + * + * @param cellInfo {Map} The information about the cell. + * See {@link #createDataCellHtml}. + * @return {Map} A map having the following attributes: + *
    + *
  • "url": (type string) must be the URL of the image to show.
  • + *
  • "imageWidth": (type int) the width of the image in pixels.
  • + *
  • "imageHeight": (type int) the height of the image in pixels.
  • + *
  • "tooltip": (type string) must be the image tooltip text.
  • + *
+ */ +qx.Proto._identifyImage = function(cellInfo) { + throw new Error("_identifyImage is abstract"); +} + + +/** + * Retrieves the image infos. + * + * @param cellInfo {Map} The information about the cell. + * See {@link #createDataCellHtml}. + * @return {Map} Map with an "url" attribute (type string) + * holding the URL of the image to show + * and a "tooltip" attribute + * (type string) being the tooltip text (or null if none was specified) + * + */ +qx.Proto._getImageInfos= function(cellInfo) { + // Query the subclass about image and tooltip + var urlAndTooltipMap = this._identifyImage(cellInfo); + + // If subclass refuses to give map, construct it + if (urlAndTooltipMap == null || typeof urlAndTooltipMap == "string"){ + urlAndTooltipMap = {url:urlAndTooltipMap, tooltip:null}; + } + + // If subclass gave null as url, replace with url to empty image + if (urlAndTooltipMap.url == null){ + urlAndTooltipMap.url = this.IMG_BLANK_URL; + } + + return urlAndTooltipMap; +} + +// overridden +qx.Proto._getCellStyle = function(cellInfo) { + var style = qx.ui.table.AbstractDataCellRenderer.prototype._getCellStyle(cellInfo); + style += qx.ui.table.IconDataCellRenderer.MAIN_DIV_STYLE; + return style; +} + + +// overridden +qx.Proto._getContentHtml = function(cellInfo) { + var IconDataCellRenderer = qx.ui.table.IconDataCellRenderer; + + var urlAndToolTip = this._getImageInfos(cellInfo); + var html = IconDataCellRenderer.IMG_START; + if (qx.sys.Client.getInstance().isMshtml() && /\.png$/i.test(urlAndToolTip.url)) { + html += qx.manager.object.AliasManager.getInstance().resolvePath("static/image/blank.gif") + + '" style="filter:' + "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + urlAndToolTip.url + "',sizingMethod='scale')"; + } else { + html += urlAndToolTip.url + '" style="'; + } + + if (urlAndToolTip.imageWidth && urlAndToolTip.imageHeight) { + html += ';width:' + urlAndToolTip.imageWidth + 'px' + + ';height:' + urlAndToolTip.imageHeight + 'px'; + } + + var tooltip = urlAndToolTip.tooltip; + if (tooltip != null){ + html += IconDataCellRenderer.IMG_TITLE_START + tooltip; + } + html += IconDataCellRenderer.IMG_END; + return html; +} + + +// overridden +qx.Proto.updateDataCellElement = function(cellInfo, cellElement) { + // Set image and tooltip text + var urlAndToolTip = this._getImageInfos(cellInfo); + var img = cellElement.firstChild; + if (qx.sys.Client.getInstance().isMshtml()) { + if (/\.png$/i.test(urlAndToolTip.url)) { + img.src = qx.manager.object.AliasManager.getInstance().resolvePath("static/image/blank.gif"); + img.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + urlAndToolTip.url + "',sizingMethod='scale')"; + } else { + img.src = urlAndToolTip.url; + img.style.filter = ""; + } + } else { + img.src = urlAndToolTip.url; + } + + if (urlAndToolTip.imageWidth && urlAndToolTip.imageHeight) { + img.style.width = urlAndToolTip.imageWidth + "px"; + img.style.height = urlAndToolTip.imageHeight + "px"; + } + + if (urlAndToolTip.tooltip != null){ + img.text = urlAndToolTip.tooltip; + } +} + + +// overridden +qx.Proto._createCellStyle_array_join = function(cellInfo, htmlArr) { + qx.ui.table.AbstractDataCellRenderer.prototype._createCellStyle_array_join(cellInfo, htmlArr); + + htmlArr.push(qx.ui.table.IconDataCellRenderer.MAIN_DIV_STYLE); +} + +qx.Proto._createContentHtml_array_join = function(cellInfo, htmlArr) { + var IconDataCellRenderer = qx.ui.table.IconDataCellRenderer; + + if (qx.ui.table.TablePane.USE_TABLE) { + htmlArr.push(IconDataCellRenderer.TABLE_DIV); + htmlArr.push(cellInfo.styleHeight - 2); // -1 for the border, -1 for the padding + htmlArr.push(IconDataCellRenderer.TABLE_DIV_CLOSE); + } + + htmlArr.push(IconDataCellRenderer.IMG_START); + var urlAndToolTip = this._getImageInfos(cellInfo); + htmlArr.push(urlAndToolTip.url); + var tooltip = urlAndToolTip.tooltip; + if (tooltip != null){ + IconDataCellRenderer.IMG_TITLE_START; + htmlArr.push(tooltip); + } + htmlArr.push(IconDataCellRenderer.IMG_END); + + if (qx.ui.table.TablePane.USE_TABLE) { + htmlArr.push(IconDataCellRenderer.TABLE_DIV_END); + } +} + +qx.Class.MAIN_DIV_STYLE = ';text-align:center;padding-top:1px;'; +qx.Class.IMG_START = ''; +qx.Class.IMG_TITLE_START = '" title="'; +qx.Class.TABLE_DIV = '
'; +qx.Class.TABLE_DIV_END = '
'; + diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/IconHeaderCellRenderer.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/IconHeaderCellRenderer.js new file mode 100644 index 0000000000..51e653f5c4 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/IconHeaderCellRenderer.js @@ -0,0 +1,84 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 by STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Til Schneider (til132) + * Carsten Lergenmueller (carstenl) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * A header cell renderer which renders an icon (only). The icon cannot be combined + * with text. + * + * @param iconUrl {string} URL to the icon to show + * @param tooltip {string ? ""} Text of the tooltip to show if the mouse hovers over the + * icon + * + */ +qx.OO.defineClass("qx.ui.table.IconHeaderCellRenderer", qx.ui.table.DefaultHeaderCellRenderer, +function(iconUrl, tooltip) { + qx.ui.table.DefaultHeaderCellRenderer.call(this); + if (iconUrl == null){ + iconUrl = ""; + } + this.setIconUrl(iconUrl); + this.setToolTip(tooltip); +}); + +/** + * URL of the icon to show + */ +qx.OO.addProperty({ name:"iconUrl", type:"string", defaultValue:"", allowNull:false }); + +/** + * ToolTip to show if the mouse hovers of the icon + */ +qx.OO.addProperty({ name:"toolTip", type:"string", defaultValue:null, allowNull:true }); + +// overridden +qx.Proto.updateHeaderCell = function(cellInfo, cellWidget) { + qx.ui.table.DefaultHeaderCellRenderer.prototype.updateHeaderCell.call(this, cellInfo, cellWidget); + + // Set URL to icon + var img = cellWidget.getUserData("qx_ui_table_IconHeaderCellRenderer_icon"); + if (img == null){ + img = new qx.ui.basic.Image(); + cellWidget.setUserData("qx_ui_table_IconHeaderCellRenderer_icon", img); + cellWidget.addAtBegin(img); + } + img.setSource(this.getIconUrl()); + + // Set image tooltip if given + var widgetToolTip = cellWidget.getToolTip(); + if (this.getToolTip() != null){ + + //Create tooltip if necessary + if (true || widgetToolTip == null ){ + widgetToolTip = new qx.ui.popup.ToolTip(this.getToolTip()); + cellWidget.setToolTip(widgetToolTip); + //this.debug("Creating tooltip"); + } + + //Set tooltip text + widgetToolTip.getAtom().setLabel(this.getToolTip()); + //this.debug("Setting tooltip text " + this.getToolTip()); + } + +} + diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/RemoteTableModel.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/RemoteTableModel.js new file mode 100644 index 0000000000..ebd1be8f53 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/RemoteTableModel.js @@ -0,0 +1,435 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 by STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * A table model that loads its data from a backend. + *

+ * Only those rows are loaded that are near the area the user is currently + * viewing. If the user scrolls, the rows he will see soon are loaded + * asynchroniously in the background. All loaded data is managed in a cache that + * automatically removes the last resently used rows when it gets full. + *

+ * This class is abstract: The actual loading of row data must be done by + * subclasses. + */ +qx.OO.defineClass("qx.ui.table.RemoteTableModel", qx.ui.table.AbstractTableModel, +function() { + qx.ui.table.AbstractTableModel.call(this); + + this._sortColumnIndex = -1; + this._sortAscending = true; + this._rowCount = -1; + + this._lruCounter = 0; + this._firstLoadingBlock = -1; + this._firstRowToLoad = -1; + this._lastRowToLoad = -1; + this._ignoreCurrentRequest = false; + + this._rowBlockCache = {}; + this._rowBlockCount = 0; +}); + + +/** The number of rows that are stored in one cache block. */ +qx.OO.addProperty({ name:"blockSize", type:"number", defaultValue:50, allowNull:false }); + +/** The maximum number of row blocks kept in the cache. */ +qx.OO.addProperty({ name:"maxCachedBlockCount", type:"number", defaultValue:15, allowNull:false }); + +/** + * Whether to clear the cache when some rows are removed. + * If false the rows are removed locally in the cache. + */ +qx.OO.addProperty({ name:"clearCacheOnRemove", type:"boolean", defaultValue:false, allowNull:false }); + + +// overridden +qx.Proto.getRowCount = function() { + if (this._rowCount == -1) { + this._loadRowCount(); + + // NOTE: _loadRowCount may set this._rowCount + return (this._rowCount == -1) ? 0 : this._rowCount; + } else { + return this._rowCount; + } +} + + +/** + * Loads the row count from the server. + *

+ * Implementing classes have to call {@link _onRowDataLoaded()} when the server + * response arrived. That method has to be called! Even when there was an error. + */ +qx.Proto._loadRowCount = function() { + throw new Error("_loadRowCount is abstract"); +}; + + +/** + * Sets the row count. + *

+ * Has to be called by {@link _loadRowCount()}. + * + * @param rowCount {int} the number of rows in this model or null if loading. + */ +qx.Proto._onRowCountLoaded = function(rowCount) { + this.debug("row count loaded: " + rowCount); + if (rowCount == null) { + rowCount = 0; + } + this._rowCount = rowCount; + + // Inform the listeners + var data = { firstRow:0, lastRow:rowCount - 1, firstColumn:0, lastColumn:this.getColumnCount() - 1 }; + this.dispatchEvent(new qx.event.type.DataEvent(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED, data), true); +}; + + +/** + * Reloads the model and clears the local cache. + */ +qx.Proto.reloadData = function() { + this.clearCache(); + + // If there is currently a request on its way, then this request will bring + // obsolete data -> Ignore it + if (this._firstLoadingBlock != -1) { + this._ignoreCurrentRequest = true; + } + + // NOTE: This will inform the listeners as soon as the new row count is known + this._loadRowCount(); +}; + + +/** + * Clears the cache. + */ +qx.Proto.clearCache = function() { + this._rowBlockCache = {}; + this._rowBlockCount = 0; +}; + + +// overridden +qx.Proto.prefetchRows = function(firstRowIndex, lastRowIndex) { + // this.debug("Prefetch wanted: " + firstRowIndex + ".." + lastRowIndex); + if (this._firstLoadingBlock == -1) { + var blockSize = this.getBlockSize(); + var totalBlockCount = Math.ceil(this._rowCount / blockSize); + + // There is currently no request running -> Start a new one + // NOTE: We load one more block above and below to have a smooth + // scrolling into the next block without blank cells + var firstBlock = parseInt(firstRowIndex / blockSize) - 1; + if (firstBlock < 0) { + firstBlock = 0; + } + var lastBlock = parseInt(lastRowIndex / blockSize) + 1; + if (lastBlock >= totalBlockCount) { + lastBlock = totalBlockCount - 1; + } + + // Check which blocks we have to load + var firstBlockToLoad = -1; + var lastBlockToLoad = -1; + for (var block = firstBlock; block <= lastBlock; block++) { + if (this._rowBlockCache[block] == null || this._rowBlockCache[block].isDirty) { + // We don't have this block + if (firstBlockToLoad == -1) { + firstBlockToLoad = block; + } + lastBlockToLoad = block; + } + } + + // Load the blocks + if (firstBlockToLoad != -1) { + this._firstRowToLoad = -1; + this._lastRowToLoad = -1; + + this._firstLoadingBlock = firstBlockToLoad; + + this.debug("Starting server request. rows: " + firstRowIndex + ".." + lastRowIndex + ", blocks: " + firstBlockToLoad + ".." + lastBlockToLoad); + this._loadRowData(firstBlockToLoad * blockSize, (lastBlockToLoad + 1) * blockSize - 1); + } + } else { + // There is already a request running -> Remember this request + // so it can be executed after the current one is finished. + this._firstRowToLoad = firstRowIndex; + this._lastRowToLoad = lastRowIndex; + } +}; + + +/** + * Loads some row data from the server. + *

+ * Implementing classes have to call {@link _onRowDataLoaded()} when the server + * response arrived. That method has to be called! Even when there was an error. + * + * @param firstRow {int} The index of the first row to load. + * @param lastRow {int} The index of the last row to load. + */ +qx.Proto._loadRowData = function(firstRow, lastRow) { + throw new Error("_loadRowCount is abstract"); +}; + + +/** + * Sets row data. + *

+ * Has to be called by {@link _loadRowData()}. + * + * @param rowDataArr {Map[]} the loaded row data or null if there was an error. + */ +qx.Proto._onRowDataLoaded = function(rowDataArr) { + if (rowDataArr != null && ! this._ignoreCurrentRequest) { + var blockSize = this.getBlockSize(); + var blockCount = Math.ceil(rowDataArr.length / blockSize); + if (blockCount == 1) { + // We got one block -> Use the rowData directly + this._setRowBlockData(this._firstLoadingBlock, rowDataArr); + } else { + // We got more than one block -> We've to split the rowData + for (var i = 0; i < blockCount; i++) { + var rowOffset = i * blockSize; + var blockRowData = []; + var mailCount = Math.min(blockSize, rowDataArr.length - rowOffset); + for (var row = 0; row < mailCount; row++) { + blockRowData.push(rowDataArr[rowOffset + row]); + } + + this._setRowBlockData(this._firstLoadingBlock + i, blockRowData); + } + } + this.debug("Got server answer. blocks: " + this._firstLoadingBlock + ".." + (this._firstLoadingBlock + blockCount - 1) + ". mail count: " + rowDataArr.length + " block count:" + blockCount); + + // Inform the listeners + var data = { + firstRow:this._firstLoadingBlock * blockSize, + lastRow:(this._firstLoadingBlock + blockCount + 1) * blockSize - 1, + firstColumn:0, + lastColumn:this.getColumnCount() - 1 + }; + this.dispatchEvent(new qx.event.type.DataEvent(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED, data), true); + } + + // We're not loading any blocks any more + this._firstLoadingBlock = -1; + this._ignoreCurrentRequest = false; + + // Check whether we have to start a new request + if (this._firstRowToLoad != -1) { + this.prefetchRows(this._firstRowToLoad, this._lastRowToLoad); + } +}; + + +/** + * Sets the data of one block. + * + * @param block {int} the index of the block. + * @param rowDataArr {var[][]} the data to set. + */ +qx.Proto._setRowBlockData = function(block, rowDataArr) { + if (this._rowBlockCache[block] == null) { + // This is a new block -> Check whether we have to remove another block first + this._rowBlockCount++; + + while (this._rowBlockCount > this.getMaxCachedBlockCount()) { + // Find the last recently used block + // NOTE: We never remove block 0 and 1 + var lruBlock; + var minLru = this._lruCounter; + for (var currBlock in this._rowBlockCache) { + var currLru = this._rowBlockCache[currBlock].lru; + if (currLru < minLru && currBlock > 1) { + minLru = currLru; + lruBlock = currBlock; + } + } + + // Remove that block + this.debug("Removing block: " + lruBlock + ". current LRU: " + this._lruCounter); + delete this._rowBlockCache[lruBlock]; + this._rowBlockCount--; + } + } + + this._rowBlockCache[block] = { lru:++this._lruCounter, rowDataArr:rowDataArr }; +}; + + +/** + * Removes a rows from the model. + * + * @param rowIndex {int} the index of the row to remove. + */ +qx.Proto.removeRow = function(rowIndex) { + if (this.getClearCacheOnRemove()) { + this.clearCache(); + + // Inform the listeners + var data = { firstRow:0, lastRow:rowCount - 1, firstColumn:0, lastColumn:this.getColumnCount() - 1 }; + this.dispatchEvent(new qx.event.type.DataEvent(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED, data), true); + } else { + var blockSize = this.getBlockSize(); + var blockCount = Math.ceil(this.getRowCount() / blockSize); + var startBlock = parseInt(rowIndex / blockSize); + + // Remove the row and move the rows of all following blocks + for (var block = startBlock; block <= blockCount; block++) { + var blockData = this._rowBlockCache[block]; + if (blockData != null) { + // Remove the row in the start block + // NOTE: In the other blocks the first row is removed + // (This is the row that was) + var removeIndex = 0; + if (block == startBlock) { + removeIndex = rowIndex - block * blockSize; + } + blockData.rowDataArr.splice(removeIndex, 1); + + if (block == blockCount - 1) { + // This is the last block + if (blockData.rowDataArr.length == 0) { + // It is empty now -> Remove it + delete this._rowBlockCache[block]; + } + } else { + // Try to copy the first row of the next block to the end of this block + // so this block can stays clean + var nextBlockData = this._rowBlockCache[block + 1]; + if (nextBlockData != null) { + blockData.rowDataArr.push(nextBlockData.rowDataArr[0]); + } else { + // There is no row to move -> Mark this block as dirty + blockData.isDirty = true; + } + } + } + } + + if (this._rowCount != -1) { + this._rowCount--; + } + + // Inform the listeners + if (this.hasEventListeners(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED)) { + var data = { firstRow:rowIndex, lastRow:this.getRowCount() - 1, firstColumn:0, lastColumn:this.getColumnCount() - 1 }; + this.dispatchEvent(new qx.event.type.DataEvent(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED, data), true); + } + } +}; + + +/** + *

See overridden method for details.

+ * + * @param rowIndex {int} the model index of the row. + * @return {Object} Map containing a value for each column. + */ +qx.Proto.getRowData = function(rowIndex) { + var blockSize = this.getBlockSize(); + var block = parseInt(rowIndex / blockSize); + var blockData = this._rowBlockCache[block]; + if (blockData == null) { + // This block is not (yet) loaded + return null; + } else { + var rowData = blockData.rowDataArr[rowIndex - (block * blockSize)]; + + // Update the last recently used counter + if (blockData.lru != this._lruCounter) { + blockData.lru = ++this._lruCounter; + } + + return rowData; + } +}; + + +// overridden +qx.Proto.getValue = function(columnIndex, rowIndex) { + var rowData = this.getRowData(rowIndex); + if (rowData == null) { + return null; + } else { + var columnId = this.getColumnId(columnIndex); + return rowData[columnId]; + } +}; + + +/** + * Sets whether a column is sortable. + * + * @param columnIndex {int} the column of which to set the sortable state. + * @param sortable {boolean} whether the column should be sortable. + */ +qx.Proto.setColumnSortable = function(columnIndex, sortable) { + if (sortable != this.isColumnSortable(columnIndex)) { + if (this._sortableColArr == null) { + this._sortableColArr = []; + } + this._sortableColArr[columnIndex] = sortable; + + this.createDispatchEvent(qx.ui.table.TableModel.EVENT_TYPE_META_DATA_CHANGED); + } +} + + +// overridden +qx.Proto.isColumnSortable = function(columnIndex) { + return this._sortableColArr ? (this._sortableColArr[columnIndex] == true) : false; +} + + +// overridden +qx.Proto.sortByColumn = function(columnIndex, ascending) { + if (this._sortColumnIndex != columnIndex || this._sortAscending != ascending) { + this._sortColumnIndex = columnIndex; + this._sortAscending = ascending; + + this.clearCache(); + + // Inform the listeners + this.createDispatchEvent(qx.ui.table.TableModel.EVENT_TYPE_META_DATA_CHANGED); + } +}; + + +// overridden +qx.Proto.getSortColumnIndex = function() { + return this._sortColumnIndex; +} + + +// overridden +qx.Proto.isSortAscending = function() { + return this._sortAscending; +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/SelectionManager.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/SelectionManager.js new file mode 100644 index 0000000000..715b0d9d96 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/SelectionManager.js @@ -0,0 +1,163 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 by STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * A selection manager. This is a helper class that handles all selection + * related events and updates a SelectionModel. + *

+ * Widgets that support selection should use this manager. This way the only + * thing the widget has to do is mapping mouse or key events to indexes and + * call the corresponding handler method. + * + * @see SelectionModel + */ +qx.OO.defineClass("qx.ui.table.SelectionManager", qx.core.Object, +function() { + qx.core.Object.call(this); +}); + + +/** + * The selection model where to set the selection changes. + */ +qx.OO.addProperty({ name:"selectionModel", type:"object", instance:"qx.ui.table.SelectionModel" }); + + +/** + * Handles the mouse down event. + * + * @param index {int} the index the mouse is pointing at. + * @param evt {Map} the mouse event. + */ +qx.Proto.handleMouseDown = function(index, evt) { + if (evt.isLeftButtonPressed()) { + var selectionModel = this.getSelectionModel(); + if (!selectionModel.isSelectedIndex(index)) { + // This index is not selected -> We react when the mouse is pressed (because of drag and drop) + this._handleSelectEvent(index, evt); + this._lastMouseDownHandled = true; + } else { + // This index is already selected -> We react when the mouse is released (because of drag and drop) + this._lastMouseDownHandled = false; + } + } else if (evt.isRightButtonPressed() && evt.getModifiers() == 0) { + var selectionModel = this.getSelectionModel(); + if (!selectionModel.isSelectedIndex(index)) { + // This index is not selected -> Set the selection to this index + selectionModel.setSelectionInterval(index, index); + } + } +} + + +/** + * Handles the mouse up event. + * + * @param index {int} the index the mouse is pointing at. + * @param evt {Map} the mouse event. + */ +qx.Proto.handleMouseUp = function(index, evt) { + if (evt.isLeftButtonPressed() && !this._lastMouseDownHandled) { + this._handleSelectEvent(index, evt); + } +} + + +/** + * Handles the mouse click event. + * + * @param index {int} the index the mouse is pointing at. + * @param evt {Map} the mouse event. + */ +qx.Proto.handleClick = function(index, evt) { +} + + +/** + * Handles the key down event that is used as replacement for mouse clicks + * (Normally space). + * + * @param index {int} the index that is currently focused. + * @param evt {Map} the key event. + */ +qx.Proto.handleSelectKeyDown = function(index, evt) { + this._handleSelectEvent(index, evt); +}; + + +/** + * Handles a key down event that moved the focus (E.g. up, down, home, end, ...). + * + * @param index {int} the index that is currently focused. + * @param evt {Map} the key event. + */ +qx.Proto.handleMoveKeyDown = function(index, evt) { + var selectionModel = this.getSelectionModel(); + switch (evt.getModifiers()) { + case 0: + selectionModel.setSelectionInterval(index, index); + break; + case qx.event.type.DomEvent.SHIFT_MASK: + var anchor = selectionModel.getAnchorSelectionIndex(); + if (anchor == -1) { + selectionModel.setSelectionInterval(index, index); + } else { + selectionModel.setSelectionInterval(anchor, index); + } + break; + } +} + + +/** + * Handles a select event. + * + * @param index {int} the index the event is pointing at. + * @param evt {Map} the mouse event. + */ +qx.Proto._handleSelectEvent = function(index, evt) { + var selectionModel = this.getSelectionModel(); + if (evt.getShiftKey()) { + var leadIndex = selectionModel.getLeadSelectionIndex(); + if (index != leadIndex || selectionModel.isSelectionEmpty()) { + // The lead selection index was changed + var anchorIndex = selectionModel.getAnchorSelectionIndex(); + if (anchorIndex == -1) { + anchorIndex = index; + } + if (evt.isCtrlOrCommandPressed()) { + selectionModel.addSelectionInterval(anchorIndex, index); + } else { + selectionModel.setSelectionInterval(anchorIndex, index); + } + } + } else if (evt.isCtrlOrCommandPressed()) { + if (selectionModel.isSelectedIndex(index)) { + selectionModel.removeSelectionInterval(index, index); + } else { + selectionModel.addSelectionInterval(index, index); + } + } else { + selectionModel.setSelectionInterval(index, index); + } +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/SelectionModel.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/SelectionModel.js new file mode 100644 index 0000000000..fb0f6b7317 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/SelectionModel.js @@ -0,0 +1,427 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 by STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * A selection model. + * + * @event changeSelection {qx.event.type.Event} Fired when the selection has + * changed. + */ +qx.OO.defineClass("qx.ui.table.SelectionModel", qx.core.Target, +function() { + qx.core.Target.call(this); + + this._selectedRangeArr = []; + this._anchorSelectionIndex = -1; + this._leadSelectionIndex = -1; + this.hasBatchModeRefCount = 0; + this._hadChangeEventInBatchMode = false; +}); + + +/** {int} The selection mode "none". Nothing can ever be selected. */ +qx.Class.NO_SELECTION = 1; + +/** {int} The selection mode "single". This mode only allows one selected item. */ +qx.Class.SINGLE_SELECTION = 2; + +/** + * (int) The selection mode "single interval". This mode only allows one + * continuous interval of selected items. + */ +qx.Class.SINGLE_INTERVAL_SELECTION = 3; + +/** + * (int) The selection mode "multiple interval". This mode only allows any + * selection. + */ +qx.Class.MULTIPLE_INTERVAL_SELECTION = 4; + + +/** + * (int) the selection mode. + */ +qx.OO.addProperty({ name:"selectionMode", type:"number", + defaultValue:qx.Class.SINGLE_SELECTION, + allowNull:false, + possibleValues:[ qx.Class.NO_SELECTION, + qx.Class.SINGLE_SELECTION, + qx.Class.SINGLE_INTERVAL_SELECTION, + qx.Class.MULTIPLE_INTERVAL_SELECTION ] }); + +// selectionMode property modifier +qx.Proto._modifySelectionMode = function(selectionMode) { + if (selectionMode == qx.ui.table.SelectionModel.NO_SELECTION) { + this.clearSelection(); + } + return true; +} + + +/** + *

Activates / Deactivates batch mode. In batch mode, no change events will be thrown but + * will be collected instead. When batch mode is turned off again and any events have + * been collected, one event is thrown to inform the listeners.

+ * + *

This method supports nested calling, i. e. batch mode can be turned more than once. + * In this case, batch mode will not end until it has been turned off once for each + * turning on.

+ * + * @param batchMode {boolean} true to activate batch mode, false to deactivate + * @return {boolean} true if batch mode is active, false otherwise + * @throws Error if batch mode is turned off once more than it has been turned on + */ +qx.Proto.setBatchMode = function(batchMode) { + if (batchMode){ + this.hasBatchModeRefCount += 1; + } else { + if (this.hasBatchModeRefCount == 0){ + throw new Error("Try to turn off batch mode althoug it was not turned on.") + } + this.hasBatchModeRefCount -= 1; + if (this._hadChangeEventInBatchMode){ + this._hadChangeEventInBatchMode = false; + this._fireChangeSelection(); + } + } + return this.hasBatchMode(); +} + + +/** + *

Returns whether batch mode is active. See setter for a description of batch mode.

+ * + * @return {boolean} true if batch mode is active, false otherwise + */ +qx.Proto.hasBatchMode = function() { + return this.hasBatchModeRefCount > 0; +} + + +/** + * Returns the first argument of the last call to {@link #setSelectionInterval()}, + * {@link #addSelectionInterval()} or {@link #removeSelectionInterval()}. + * + * @return {int} the ancor selection index. + */ +qx.Proto.getAnchorSelectionIndex = function() { + return this._anchorSelectionIndex; +} + + +/** + * Returns the second argument of the last call to {@link #setSelectionInterval()}, + * {@link #addSelectionInterval()} or {@link #removeSelectionInterval()}. + * + * @return {int} the lead selection index. + */ +qx.Proto.getLeadSelectionIndex = function() { + return this._leadSelectionIndex; +} + + +/** + * Clears the selection. + */ +qx.Proto.clearSelection = function() { + if (! this.isSelectionEmpty()) { + this._clearSelection(); + this._fireChangeSelection(); + } +} + + +/** + * Returns whether the selection is empty. + * + * @return {boolean} whether the selection is empty. + */ +qx.Proto.isSelectionEmpty = function() { + return this._selectedRangeArr.length == 0; +} + + +/** + * Returns the number of selected items. + * + * @return {int} the number of selected items. + */ +qx.Proto.getSelectedCount = function() { + var selectedCount = 0; + for (var i = 0; i < this._selectedRangeArr.length; i++) { + var range = this._selectedRangeArr[i]; + selectedCount += range.maxIndex - range.minIndex + 1; + } + + return selectedCount; +} + + +/** + * Returns whether a index is selected. + * + * @param index {int} the index to check. + * @return {boolean} whether the index is selected. + */ +qx.Proto.isSelectedIndex = function(index) { + for (var i = 0; i < this._selectedRangeArr.length; i++) { + var range = this._selectedRangeArr[i]; + + if (index >= range.minIndex && index <= range.maxIndex) { + return true; + } + } + + return false; +} + + +/** + * Returns the selected ranges as an array. Each array element has a + * minIndex and a maxIndex property. + * + * @return {Map[]} the selected ranges. + */ +qx.Proto.getSelectedRanges = function() { + // clone the selection array and the individual elements - this prevents the + // caller from messing with the internal model + var retVal = []; + for (var i = 0; i < this._selectedRangeArr.length; i++) { + retVal.push({minIndex: this._selectedRangeArr[i].minIndex, + maxIndex: this._selectedRangeArr[i].maxIndex}); + } + return retVal; +} + + +/** + * Calls a iterator function for each selected index. + *

+ * Usage Example: + *

+ * var selectedRowData = [];
+ * mySelectionModel.iterateSelection(function(index) {
+ *   selectedRowData.push(myTableModel.getRowData(index));
+ * });
+ * 
+ * + * @param iterator {Function} the function to call for each selected index. + * Gets the current index as parameter. + * @param object {var ? null} the object to use when calling the handler. + * (this object will be available via "this" in the iterator) + */ +qx.Proto.iterateSelection = function(iterator, object) { + for (var i = 0; i < this._selectedRangeArr.length; i++) { + for (var j = this._selectedRangeArr[i].minIndex; j <= this._selectedRangeArr[i].maxIndex; j++) { + iterator.call(object, j); + } + } +}; + + +/** + * Sets the selected interval. This will clear the former selection. + * + * @param fromIndex {int} the first index of the selection (including). + * @param toIndex {int} the last index of the selection (including). + */ +qx.Proto.setSelectionInterval = function(fromIndex, toIndex) { + var SelectionModel = qx.ui.table.SelectionModel; + + switch(this.getSelectionMode()) { + case SelectionModel.NO_SELECTION: + return; + case SelectionModel.SINGLE_SELECTION: + fromIndex = toIndex; + break; + } + + this._clearSelection(); + this._addSelectionInterval(fromIndex, toIndex); + + this._fireChangeSelection(); +} + + +/** + * Adds a selection interval to the current selection. + * + * @param fromIndex {int} the first index of the selection (including). + * @param toIndex {int} the last index of the selection (including). + */ +qx.Proto.addSelectionInterval = function(fromIndex, toIndex) { + var SelectionModel = qx.ui.table.SelectionModel; + switch (this.getSelectionMode()) { + case SelectionModel.NO_SELECTION: + return; + case SelectionModel.MULTIPLE_INTERVAL_SELECTION: + this._addSelectionInterval(fromIndex, toIndex); + this._fireChangeSelection(); + break; + default: + this.setSelectionInterval(fromIndex, toIndex); + break; + } +} + + +/** + * Removes a interval from the current selection. + * + * @param fromIndex {int} the first index of the interval (including). + * @param toIndex {int} the last index of the interval (including). + */ +qx.Proto.removeSelectionInterval = function(fromIndex, toIndex) { + this._anchorSelectionIndex = fromIndex; + this._leadSelectionIndex = toIndex; + + var minIndex = Math.min(fromIndex, toIndex); + var maxIndex = Math.max(fromIndex, toIndex); + + // Crop the affected ranges + for (var i = 0; i < this._selectedRangeArr.length; i++) { + var range = this._selectedRangeArr[i]; + + if (range.minIndex > maxIndex) { + // We are done + break; + } else if (range.maxIndex >= minIndex) { + // This range is affected + var minIsIn = (range.minIndex >= minIndex) && (range.minIndex <= maxIndex); + var maxIsIn = (range.maxIndex >= minIndex) && (range.maxIndex <= maxIndex); + + if (minIsIn && maxIsIn) { + // This range is removed completely + this._selectedRangeArr.splice(i, 1); + + // Check this index another time + i--; + } else if (minIsIn) { + // The range is cropped from the left + range.minIndex = maxIndex + 1; + } else if (maxIsIn) { + // The range is cropped from the right + range.maxIndex = minIndex - 1; + } else { + // The range is split + var newRange = { minIndex:maxIndex + 1, maxIndex:range.maxIndex } + this._selectedRangeArr.splice(i + 1, 0, newRange); + + range.maxIndex = minIndex - 1; + + // We are done + break; + } + } + } + + //this._dumpRanges(); + + this._fireChangeSelection(); +} + + +/** + * Clears the selection, but doesn't inform the listeners. + */ +qx.Proto._clearSelection = function() { + this._selectedRangeArr = []; +} + + +/** + * Adds a selection interval to the current selection, but doesn't inform + * the listeners. + * + * @param fromIndex {int} the first index of the selection (including). + * @param toIndex {int} the last index of the selection (including). + */ +qx.Proto._addSelectionInterval = function(fromIndex, toIndex) { + this._anchorSelectionIndex = fromIndex; + this._leadSelectionIndex = toIndex; + + var minIndex = Math.min(fromIndex, toIndex); + var maxIndex = Math.max(fromIndex, toIndex); + + // Find the index where the new range should be inserted + var newRangeIndex = 0; + for (; newRangeIndex < this._selectedRangeArr.length; newRangeIndex++) { + var range = this._selectedRangeArr[newRangeIndex]; + if (range.minIndex > minIndex) { + break; + } + } + + // Add the new range + this._selectedRangeArr.splice(newRangeIndex, 0, { minIndex:minIndex, maxIndex:maxIndex }); + + // Merge overlapping ranges + var lastRange = this._selectedRangeArr[0]; + for (var i = 1; i < this._selectedRangeArr.length; i++) { + var range = this._selectedRangeArr[i]; + + if (lastRange.maxIndex + 1 >= range.minIndex) { + // The ranges are overlapping -> merge them + lastRange.maxIndex = Math.max(lastRange.maxIndex, range.maxIndex); + + // Remove the current range + this._selectedRangeArr.splice(i, 1); + + // Check this index another time + i--; + } else { + lastRange = range; + } + } + + //this._dumpRanges(); +} + + +/** + * Logs the current ranges for debug perposes. + */ +qx.Proto._dumpRanges = function() { + var text = "Ranges:"; + for (var i = 0; i < this._selectedRangeArr.length; i++) { + var range = this._selectedRangeArr[i]; + text += " [" + range.minIndex + ".." + range.maxIndex + "]"; + } + this.debug(text); +} + + +/** + * Fires the "changeSelection" event to all registered listeners. If the selection model + * currently is in batch mode, only one event will be thrown when batch mode is ended. + */ +qx.Proto._fireChangeSelection = function() { + //In batch mode, remember event but do not throw (yet) + if (this.hasBatchMode()){ + this._hadChangeEventInBatchMode = true; + + //If not in batch mode, throw event + } else if (this.hasEventListeners("changeSelection")) { + this.dispatchEvent(new qx.event.type.Event("changeSelection"), true); + } +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/SimpleTableModel.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/SimpleTableModel.js new file mode 100644 index 0000000000..ef6ef2fecc --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/SimpleTableModel.js @@ -0,0 +1,335 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 by STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * A simple table model that provides an API for changing the model data. + */ +qx.OO.defineClass("qx.ui.table.SimpleTableModel", qx.ui.table.AbstractTableModel, +function() { + qx.ui.table.AbstractTableModel.call(this); + + this._rowArr = []; + this._sortColumnIndex = -1; + this._sortAscending; + + this._editableColArr = null; +}); + + +/** + *

See overridden method for details.

+ * + * @param rowIndex {int} the model index of the row. + * @return {Array} Array containing a value for each column. + */ +qx.Proto.getRowData = function(rowIndex) { + return this._rowArr[rowIndex]; +}; + + +/** + * Returns the data of one row as map containing the column IDs as key and the + * cell values as value. + * + * @param rowIndex {int} the model index of the row. + * @return {Map} a Map containing the column values. + */ +qx.Proto.getRowDataAsMap = function(rowIndex) { + var columnArr = this._rowArr[rowIndex]; + var map = {}; + for (var col = 0; col < this.getColumnCount(); col++) { + map[this.getColumnId(col)] = columnArr[col]; + } + return map; +}; + + +/** + * Sets all columns editable or not editable. + * + * @param editable {boolean} whether all columns are editable. + */ +qx.Proto.setEditable = function(editable) { + this._editableColArr = []; + for (var col = 0; col < this.getColumnCount(); col++) { + this._editableColArr[col] = editable; + } + + this.createDispatchEvent(qx.ui.table.TableModel.EVENT_TYPE_META_DATA_CHANGED); +} + + +/** + * Sets whether a column is editable. + * + * @param columnIndex {int} the column of which to set the editable state. + * @param editable {boolean} whether the column should be editable. + */ +qx.Proto.setColumnEditable = function(columnIndex, editable) { + if (editable != this.isColumnEditable(columnIndex)) { + if (this._editableColArr == null) { + this._editableColArr = []; + } + this._editableColArr[columnIndex] = editable; + + this.createDispatchEvent(qx.ui.table.TableModel.EVENT_TYPE_META_DATA_CHANGED); + } +} + + +// overridden +qx.Proto.isColumnEditable = function(columnIndex) { + return this._editableColArr ? (this._editableColArr[columnIndex] == true) : false; +} + + +// overridden +qx.Proto.isColumnSortable = function(columnIndex) { + return true; +} + + +// overridden +qx.Proto.sortByColumn = function(columnIndex, ascending) { + // NOTE: We use different comperators for ascending and descending, + // because comperators should be really fast. + var comperator; + if (ascending) { + comperator = function(row1, row2) { + var obj1 = row1[columnIndex]; + var obj2 = row2[columnIndex]; + return (obj1 > obj2) ? 1 : ((obj1 == obj2) ? 0 : -1); + } + } else { + comperator = function(row1, row2) { + var obj1 = row1[columnIndex]; + var obj2 = row2[columnIndex]; + return (obj1 < obj2) ? 1 : ((obj1 == obj2) ? 0 : -1); + } + } + + this._rowArr.sort(comperator); + + this._sortColumnIndex = columnIndex; + this._sortAscending = ascending; + + this.createDispatchEvent(qx.ui.table.TableModel.EVENT_TYPE_META_DATA_CHANGED); +} + + +/** + * Clears the sorting. + */ +qx.Proto._clearSorting = function() { + if (this._sortColumnIndex != -1) { + this._sortColumnIndex = -1; + this._sortAscending = true; + + this.createDispatchEvent(qx.ui.table.TableModel.EVENT_TYPE_META_DATA_CHANGED); + } +} + + +// overridden +qx.Proto.getSortColumnIndex = function() { + return this._sortColumnIndex; +} + + +// overridden +qx.Proto.isSortAscending = function() { + return this._sortAscending; +} + + +// overridden +qx.Proto.getRowCount = function() { + return this._rowArr.length; +} + + +// overridden +qx.Proto.getValue = function(columnIndex, rowIndex) { + if (rowIndex < 0 || rowIndex >= this._rowArr.length) { + throw new Error("this._rowArr out of bounds: " + rowIndex + " (0.." + this._rowArr.length + ")"); + } + + return this._rowArr[rowIndex][columnIndex]; +} + + +// overridden +qx.Proto.setValue = function(columnIndex, rowIndex, value) { + if (this._rowArr[rowIndex][columnIndex] != value) { + this._rowArr[rowIndex][columnIndex] = value; + + // Inform the listeners + if (this.hasEventListeners(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED)) { + var data = { firstRow:rowIndex, lastRow:rowIndex, + firstColumn:columnIndex, lastColumn:columnIndex } + this.dispatchEvent(new qx.event.type.DataEvent(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED, data), true); + } + + if (columnIndex == this._sortColumnIndex) { + this._clearSorting(); + } + } +} + + +/** + * Sets the whole data in a bulk. + * + * @param rowArr {var[][]} An array containing an array for each row. Each + * row-array contains the values in that row in the order of the columns + * in this model. + */ +qx.Proto.setData = function(rowArr) { + this._rowArr = rowArr; + + // Inform the listeners + if (this.hasEventListeners(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED)) { + this.createDispatchEvent(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED); + } + + this._clearSorting(); +} + + +/** + * Returns the data of this model. + *

+ * Warning: Do not alter this array! If you want to change the data use + * {@link #setData}, {@link #setDataAsMapArray} or {@link #setValue} instead. + * + * @return {var[][]} An array containing an array for each row. Each + * row-array contains the values in that row in the order of the columns + * in this model. + */ +qx.Proto.getData = function() { + return this._rowArr; +}; + + +/** + * Sets the whole data in a bulk. + * + * @param mapArr {Map[]} An array containing a map for each row. Each + * row-map contains the column IDs as key and the cell values as value. + */ +qx.Proto.setDataAsMapArray = function(mapArr) { + this.setData(this._mapArray2RowArr(mapArr)); +}; + + +/** + * Adds some rows to the model. + *

+ * Warning: The given array will be altered! + * + * @param rowArr {var[][]} An array containing an array for each row. Each + * row-array contains the values in that row in the order of the columns + * in this model. + * @param startIndex {int ? null} The index where to insert the new rows. If null, + * the rows are appended to the end. + */ +qx.Proto.addRows = function(rowArr, startIndex) { + if (startIndex == null) { + startIndex = this._rowArr.length; + } + + // Prepare the rowArr so it can be used for apply + rowArr.splice(0, 0, startIndex, 0); + + // Insert the new rows + Array.prototype.splice.apply(this._rowArr, rowArr); + + // Inform the listeners + if (this.hasEventListeners(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED)) { + var data = { firstRow:startIndex, lastRow:this._rowArr.length - 1, firstColumn:0, lastColumn:this.getColumnCount() - 1 }; + this.dispatchEvent(new qx.event.type.DataEvent(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED, data), true); + } + + this._clearSorting(); +}; + + +/** + * Adds some rows to the model. + *

+ * Warning: The given array (mapArr) will be altered! + * + * @param mapArr {Map[]} An array containing a map for each row. Each + * row-map contains the column IDs as key and the cell values as value. + * @param startIndex {int ? null} The index where to insert the new rows. If null, + * the rows are appended to the end. + */ +qx.Proto.addRowsAsMapArray = function(mapArr, startIndex) { + this.addRows(this._mapArray2RowArr(mapArr), startIndex); +}; + + +/** + * Removes some rows from the model. + * + * @param startIndex {int} the index of the first row to remove. + * @param howMany {int} the number of rows to remove. + */ +qx.Proto.removeRows = function(startIndex, howMany) { + this._rowArr.splice(startIndex, howMany); + + // Inform the listeners + if (this.hasEventListeners(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED)) { + var data = { firstRow:startIndex, lastRow:this._rowArr.length - 1, firstColumn:0, lastColumn:this.getColumnCount() - 1 }; + this.dispatchEvent(new qx.event.type.DataEvent(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED, data), true); + } + + this._clearSorting(); +}; + + +/** + * Creates an array of maps to an array of arrays. + * + * @param mapArr {Map[]} An array containing a map for each row. Each + * row-map contains the column IDs as key and the cell values as value. + * @return {var[][]} An array containing an array for each row. Each + * row-array contains the values in that row in the order of the columns + * in this model. + */ +qx.Proto._mapArray2RowArr = function(mapArr) { + var rowCount = mapArr.length; + var columnCount = this.getColumnCount(); + var dataArr = new Array(rowCount); + var columnArr; + var j; + for (var i = 0; i < rowCount; ++i) { + columnArr = new Array(columnCount); + for (var j = 0; j < columnCount; ++j) { + columnArr[j] = mapArr[i][this.getColumnId(j)]; + } + dataArr[i] = columnArr; + } + + return dataArr; +}; diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/Table.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/Table.js new file mode 100644 index 0000000000..360662e718 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/Table.js @@ -0,0 +1,1062 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 by STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) +#require(qx.ui.table.DefaultDataRowRenderer) + +************************************************************************ */ + +/** + * A table. + * + * @param tableModel {qx.ui.table.TableModel} The table + * model to read the data from. + */ +qx.OO.defineClass("qx.ui.table.Table", qx.ui.layout.VerticalBoxLayout, +function(tableModel) { + qx.ui.layout.VerticalBoxLayout.call(this); + + // Create the child widgets + this._scrollerParent = new qx.ui.layout.HorizontalBoxLayout; + this._scrollerParent.setDimension("100%", "1*"); + this._scrollerParent.setSpacing(1); + + this._statusBar = new qx.ui.basic.Label; + this._statusBar.setAppearance("table-focus-statusbar"); + this._statusBar.setDimension("100%", "auto"); + + this.add(this._scrollerParent, this._statusBar); + + this._columnVisibilityBt = new qx.ui.toolbar.Button(null, "widget/table/selectColumnOrder.png"); + this._columnVisibilityBt.addEventListener("execute", this._onColumnVisibilityBtExecuted, this); + + // Create the models + this._selectionManager = new qx.ui.table.SelectionManager; + + this.setSelectionModel(new qx.ui.table.SelectionModel); + this.setTableColumnModel(new qx.ui.table.TableColumnModel); + this.setTableModel(tableModel); + + // Update the status bar + this._updateStatusBar(); + + // create the main meta column + this.setMetaColumnCounts([ -1 ]); + + // Make focusable + this.setTabIndex(1); + this.addEventListener("keydown", this._onkeydown); + this.addEventListener("keypress", this._onkeypress); + this.addEventListener("changeFocused", this._onFocusChanged); + + this._focusedCol = 0; + this._focusedRow = 0; +}); + + +/** The default row renderer to use when {@link #dataRowRenderer} is null. */ +qx.Class.DEFAULT_DATA_ROW_RENDERER = new qx.ui.table.DefaultDataRowRenderer(); + + +/** The selection model. */ +qx.OO.addProperty({ name:"selectionModel", type:"object", instance : "qx.ui.table.SelectionModel" }); + +/** The table model. */ +qx.OO.addProperty({ name:"tableModel", type:"object", instance : "qx.ui.table.TableModel" }); + +/** The table column model. */ +qx.OO.addProperty({ name:"tableColumnModel", type:"object", instance : "qx.ui.table.TableColumnModel" }); + +/** The height of the table rows. */ +qx.OO.addProperty({ name:"rowHeight", type:"number", defaultValue:15 }); + +/** Whether to show the status bar */ +qx.OO.addProperty({ name:"statusBarVisible", type:"boolean", defaultValue:true }); + +/** Whether to show the column visibility button */ +qx.OO.addProperty({ name:"columnVisibilityButtonVisible", type:"boolean", defaultValue:true }); + +/** + * {int[]} The number of columns per meta column. If the last array entry is -1, + * this meta column will get the remaining columns. + */ +qx.OO.addProperty({ name:"metaColumnCounts", type:"object" }); + +/** + * Whether the focus should moved when the mouse is moved over a cell. If false + * the focus is only moved on mouse clicks. + */ +qx.OO.addProperty({ name:"focusCellOnMouseMove", type:"boolean", defaultValue:false }); + +/** + * Whether the table should keep the first visible row complete. If set to false, + * the first row may be rendered partial, depending on the vertical scroll value. + */ +qx.OO.addProperty({ name:"keepFirstVisibleRowComplete", type:"boolean", defaultValue:true }); + +/** + * Whether the table cells should be updated when only the selection or the + * focus changed. This slows down the table update but allows to react on a + * changed selection or a changed focus in a cell renderer. + */ +qx.OO.addProperty({ name:"alwaysUpdateCells", type:"boolean", defaultValue:false }); + +/** The height of the header cells. */ +qx.OO.addProperty({ name:"headerCellHeight", type:"number", defaultValue:16, allowNull:false }); + +/** The renderer to use for styling the rows. */ +qx.OO.addProperty({ name:"dataRowRenderer", type:"object", instance:"qx.ui.table.DataRowRenderer", defaultValue:qx.Class.DEFAULT_DATA_ROW_RENDERER, allowNull:false }); + + +// property modifier +qx.Proto._modifySelectionModel = function(propValue, propOldValue, propData) { + this._selectionManager.setSelectionModel(propValue); + + if (propOldValue != null) { + propOldValue.removeEventListener("changeSelection", this._onSelectionChanged, this); + } + propValue.addEventListener("changeSelection", this._onSelectionChanged, this); + + return true; +} + + +// property modifier +qx.Proto._modifyTableModel = function(propValue, propOldValue, propData) { + this.getTableColumnModel().init(propValue.getColumnCount()); + + if (propOldValue != null) { + propOldValue.removeEventListener(qx.ui.table.TableModel.EVENT_TYPE_META_DATA_CHANGED, this._onTableModelMetaDataChanged, this); + propOldValue.removeEventListener(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED, this._onTableModelDataChanged, this); + } + propValue.addEventListener(qx.ui.table.TableModel.EVENT_TYPE_META_DATA_CHANGED, this._onTableModelMetaDataChanged, this); + propValue.addEventListener(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED, this._onTableModelDataChanged, this); + + return true; +} + + +// property modifier +qx.Proto._modifyTableColumnModel = function(propValue, propOldValue, propData) { + if (propOldValue != null) { + propOldValue.removeEventListener("visibilityChanged", this._onColVisibilityChanged, this); + propOldValue.removeEventListener("widthChanged", this._onColWidthChanged, this); + propOldValue.removeEventListener("orderChanged", this._onColOrderChanged, this); + } + propValue.addEventListener("visibilityChanged", this._onColVisibilityChanged, this); + propValue.addEventListener("widthChanged", this._onColWidthChanged, this); + propValue.addEventListener("orderChanged", this._onColOrderChanged, this); + + return true; +}; + + +// property modifier +qx.Proto._modifyStatusBarVisible = function(propValue, propOldValue, propData) { + this._statusBar.setDisplay(propValue); + + if (propValue) { + this._updateStatusBar(); + } + return true; +}; + + +// property modifier +qx.Proto._modifyColumnVisibilityButtonVisible = function(propValue, propOldValue, propData) { + this._columnVisibilityBt.setDisplay(propValue); + + return true; +}; + + +// property modifier +qx.Proto._modifyMetaColumnCounts = function(propValue, propOldValue, propData) { + var metaColumnCounts = propValue; + var scrollerArr = this._getPaneScrollerArr(); + + // Remove the panes not needed any more + this._cleanUpMetaColumns(metaColumnCounts.length); + + // Update the old panes + var leftX = 0; + for (var i = 0; i < scrollerArr.length; i++) { + var paneScroller = scrollerArr[i]; + var paneModel = paneScroller.getTablePaneModel(); + paneModel.setFirstColumnX(leftX); + paneModel.setMaxColumnCount(metaColumnCounts[i]); + leftX += metaColumnCounts[i]; + } + + // Add the new panes + if (metaColumnCounts.length > scrollerArr.length) { + var selectionModel = this.getSelectionModel(); + var tableModel = this.getTableModel(); + var columnModel = this.getTableColumnModel(); + + for (var i = scrollerArr.length; i < metaColumnCounts.length; i++) { + var paneModel = new qx.ui.table.TablePaneModel(columnModel); + paneModel.setFirstColumnX(leftX); + paneModel.setMaxColumnCount(metaColumnCounts[i]); + leftX += metaColumnCounts[i]; + + var paneScroller = new qx.ui.table.TablePaneScroller(this); + paneScroller.setTablePaneModel(paneModel); + + // Register event listener for vertical scrolling + paneScroller.addEventListener("changeScrollY", this._onScrollY, this); + + this._scrollerParent.add(paneScroller); + } + } + + // Update all meta columns + for (var i = 0; i < scrollerArr.length; i++) { + var paneScroller = scrollerArr[i]; + var isLast = (i == (scrollerArr.length - 1)); + + // Set the right header height + paneScroller.getHeader().setHeight(this.getHeaderCellHeight()); + + // Put the _columnVisibilityBt in the top right corner of the last meta column + paneScroller.setTopRightWidget(isLast ? this._columnVisibilityBt : null); + } + + this._updateScrollerWidths(); + this._updateScrollBarVisibility(); + + return true; +} + + +// property modifier +qx.Proto._modifyFocusCellOnMouseMove = function(propValue, propOldValue, propData) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i].setFocusCellOnMouseMove(propValue); + } + return true; +}; + + +// property modifier +qx.Proto._modifyKeepFirstVisibleRowComplete = function(propValue, propOldValue, propData) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i]._onKeepFirstVisibleRowCompleteChanged(); + } + return true; +}; + + +// property modifier +qx.Proto._modifyHeaderCellHeight = function(propValue, propOldValue, propData) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i].getHeader().setHeight(propValue); + } + return true; +}; + + +/** + * Returns the selection manager. + * + * @return {SelectionManager} the selection manager. + */ +qx.Proto._getSelectionManager = function() { + return this._selectionManager; +}; + + +/** + * Returns an array containing all TablePaneScrollers in this table. + * + * @return {TablePaneScroller[]} all TablePaneScrollers in this table. + */ +qx.Proto._getPaneScrollerArr = function() { + return this._scrollerParent.getChildren(); +} + + +/** + * Returns a TablePaneScroller of this table. + * + * @param metaColumn {int} the meta column to get the TablePaneScroller for. + * @return {TablePaneScroller} the TablePaneScroller. + */ +qx.Proto.getPaneScroller = function(metaColumn) { + return this._getPaneScrollerArr()[metaColumn]; +} + + +/** + * Cleans up the meta columns. + * + * @param fromMetaColumn {int} the first meta column to clean up. All following + * meta columns will be cleaned up, too. All previous meta columns will + * stay unchanged. If 0 all meta columns will be cleaned up. + */ +qx.Proto._cleanUpMetaColumns = function(fromMetaColumn) { + var scrollerArr = this._getPaneScrollerArr(); + if (scrollerArr != null) { + for (var i = scrollerArr.length - 1; i >= fromMetaColumn; i--) { + var paneScroller = scrollerArr[i]; + paneScroller.removeEventListener("changeScrollY", this._onScrollY, this); + this._scrollerParent.remove(paneScroller); + paneScroller.dispose(); + } + } +} + + +/** + * Event handler. Called when the selection has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onSelectionChanged = function(evt) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i]._onSelectionChanged(evt); + } + + this._updateStatusBar(); +} + + +/** + * Event handler. Called when the table model meta data has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onTableModelMetaDataChanged = function(evt) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i]._onTableModelMetaDataChanged(evt); + } + + this._updateStatusBar(); +} + + +/** + * Event handler. Called when the table model data has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onTableModelDataChanged = function(evt) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i]._onTableModelDataChanged(evt); + } + + var rowCount = this.getTableModel().getRowCount(); + if (rowCount != this._lastRowCount) { + this._lastRowCount = rowCount; + + this._updateScrollBarVisibility(); + this._updateStatusBar(); + } +}; + + +/** + * Event handler. Called when a TablePaneScroller has been scrolled vertically. + * + * @param evt {Map} the event. + */ +qx.Proto._onScrollY = function(evt) { + if (! this._internalChange) { + this._internalChange = true; + + // Set the same scroll position to all meta columns + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i].setScrollY(evt.getData()); + } + + this._internalChange = false; + } +} + + +/** + * Event handler. Called when a key was pressed. + * + * @param evt {Map} the event. + */ +qx.Proto._onkeydown = function(evt) { + var identifier = evt.getKeyIdentifier(); + + var consumed = false; + var oldFocusedRow = this._focusedRow; + if (this.isEditing()) { + // Editing mode + if (evt.getModifiers() == 0) { + consumed = true; + switch (identifier) { + case "Enter": + this.stopEditing(); + var oldFocusedRow = this._focusedRow; + this.moveFocusedCell(0, 1); + if (this._focusedRow != oldFocusedRow) { + this.startEditing(); + } + break; + case "Escape": + this.cancelEditing(); + this.focus(); + break; + default: + consumed = false; + break; + } + } + } else { + // No editing mode + + // Handle keys that are independant from the modifiers + consumed = true; + switch (identifier) { + case "Home": + this.setFocusedCell(this._focusedCol, 0, true); + break; + case "End": + var rowCount = this.getTableModel().getRowCount(); + this.setFocusedCell(this._focusedCol, rowCount - 1, true); + break; + default: + consumed = false; + break; + } + + // Handle keys that depend on modifiers + if (evt.getModifiers() == 0) { + consumed = true; + switch (identifier) { + case "F2": + case "Enter": + this.startEditing(); + break; + default: + consumed = false; + break; + } + } else if (evt.getCtrlKey()) { + consumed = true; + switch (identifier) { + case "A": // Ctrl + A + var rowCount = this.getTableModel().getRowCount(); + if (rowCount > 0) { + this.getSelectionModel().setSelectionInterval(0, rowCount - 1); + } + break; + default: + consumed = false; + break; + } + } + } + + if (oldFocusedRow != this._focusedRow) { + // The focus moved -> Let the selection manager handle this event + this._selectionManager.handleMoveKeyDown(this._focusedRow, evt); + } + + if (consumed) { + evt.preventDefault(); + evt.stopPropagation(); + } +}; + + +qx.Proto._onkeypress = function(evt) +{ + if (this.isEditing()) { return } + // No editing mode + var oldFocusedRow = this._focusedRow; + var consumed = true; + + // Handle keys that are independant from the modifiers + var identifier = evt.getKeyIdentifier(); + switch (identifier) { + case "Space": + this._selectionManager.handleSelectKeyDown(this._focusedRow, evt); + break; + + case "Left": + this.moveFocusedCell(-1, 0); + break; + + case "Right": + this.moveFocusedCell(1, 0); + break; + + case "Up": + this.moveFocusedCell(0, -1); + break; + + case "Down": + this.moveFocusedCell(0, 1); + break; + + case "PageUp": + case "PageDown": + var scroller = this.getPaneScroller(0); + var pane = scroller.getTablePane(); + var rowCount = pane.getVisibleRowCount() - 1; + var rowHeight = this.getRowHeight(); + var direction = (identifier == "PageUp") ? -1 : 1; + scroller.setScrollY(scroller.getScrollY() + direction * rowCount * rowHeight); + this.moveFocusedCell(0, direction * rowCount); + break; + + default: + consumed = false; + } + if (oldFocusedRow != this._focusedRow) { + // The focus moved -> Let the selection manager handle this event + this._selectionManager.handleMoveKeyDown(this._focusedRow, evt); + } + + if (consumed) { + evt.preventDefault(); + evt.stopPropagation(); + } +}; + + +/** + * Event handler. Called when the table gets the focus. + */ +qx.Proto._onFocusChanged = function(evt) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i]._onFocusChanged(evt); + } +}; + + +/** + * Event handler. Called when the visibility of a column has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onColVisibilityChanged = function(evt) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i]._onColVisibilityChanged(evt); + } + + this._updateScrollerWidths(); + this._updateScrollBarVisibility(); +} + + +/** + * Event handler. Called when the width of a column has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onColWidthChanged = function(evt) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i]._onColWidthChanged(evt); + } + + this._updateScrollerWidths(); + this._updateScrollBarVisibility(); +} + + +/** + * Event handler. Called when the column order has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onColOrderChanged = function(evt) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i]._onColOrderChanged(evt); + } + + // A column may have been moved between meta columns + this._updateScrollerWidths(); + this._updateScrollBarVisibility(); +} + + +/** + * Gets the TablePaneScroller at a certain x position in the page. If there is + * no TablePaneScroller at this postion, null is returned. + * + * @param pageX {int} the position in the page to check (in pixels). + * @return {TablePaneScroller} the TablePaneScroller or null. + * + * @see TablePaneScrollerPool + */ +qx.Proto.getTablePaneScrollerAtPageX = function(pageX) { + var metaCol = this._getMetaColumnAtPageX(pageX); + return (metaCol != -1) ? this.getPaneScroller(metaCol) : null; +} + + +/** + * Sets the currently focused cell. + * + * @param col {int} the model index of the focused cell's column. + * @param row {int} the model index of the focused cell's row. + * @param scrollVisible {boolean ? false} whether to scroll the new focused cell + * visible. + * + * @see TablePaneScrollerPool + */ +qx.Proto.setFocusedCell = function(col, row, scrollVisible) { + if (!this.isEditing() && (col != this._focusedCol || row != this._focusedRow)) { + this._focusedCol = col; + this._focusedRow = row; + + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + scrollerArr[i].setFocusedCell(col, row); + } + + if (scrollVisible) { + this.scrollCellVisible(col, row); + } + } +} + + +/** + * Returns the column of the currently focused cell. + * + * @return {int} the model index of the focused cell's column. + */ +qx.Proto.getFocusedColumn = function() { + return this._focusedCol; +}; + + +/** + * Returns the row of the currently focused cell. + * + * @return {int} the model index of the focused cell's column. + */ +qx.Proto.getFocusedRow = function() { + return this._focusedRow; +}; + + +/** + * Moves the focus. + * + * @param deltaX {int} The delta by which the focus should be moved on the x axis. + * @param deltaY {int} The delta by which the focus should be moved on the y axis. + */ +qx.Proto.moveFocusedCell = function(deltaX, deltaY) { + var col = this._focusedCol; + var row = this._focusedRow; + + if (deltaX != 0) { + var columnModel = this.getTableColumnModel(); + var x = columnModel.getVisibleX(col); + var colCount = columnModel.getVisibleColumnCount(); + x = qx.lang.Number.limit(x + deltaX, 0, colCount - 1); + col = columnModel.getVisibleColumnAtX(x); + } + + if (deltaY != 0) { + var tableModel = this.getTableModel(); + row = qx.lang.Number.limit(row + deltaY, 0, tableModel.getRowCount() - 1); + } + + this.setFocusedCell(col, row, true); +} + + +/** + * Scrolls a cell visible. + * + * @param col {int} the model index of the column the cell belongs to. + * @param row {int} the model index of the row the cell belongs to. + */ +qx.Proto.scrollCellVisible = function(col, row) { + var columnModel = this.getTableColumnModel(); + var x = columnModel.getVisibleX(col); + + var metaColumn = this._getMetaColumnAtColumnX(x); + if (metaColumn != -1) { + this.getPaneScroller(metaColumn).scrollCellVisible(col, row); + } +} + + +/** + * Returns whether currently a cell is editing. + * + * @return whether currently a cell is editing. + */ +qx.Proto.isEditing = function() { + if (this._focusedCol != null) { + var x = this.getTableColumnModel().getVisibleX(this._focusedCol); + var metaColumn = this._getMetaColumnAtColumnX(x); + return this.getPaneScroller(metaColumn).isEditing(); + } +} + + +/** + * Starts editing the currently focused cell. Does nothing if already editing + * or if the column is not editable. + * + * @return {boolean} whether editing was started + */ +qx.Proto.startEditing = function() { + if (this._focusedCol != null) { + var x = this.getTableColumnModel().getVisibleX(this._focusedCol); + var metaColumn = this._getMetaColumnAtColumnX(x); + return this.getPaneScroller(metaColumn).startEditing(); + } + return false; +} + + +/** + * Stops editing and writes the editor's value to the model. + */ +qx.Proto.stopEditing = function() { + if (this._focusedCol != null) { + var x = this.getTableColumnModel().getVisibleX(this._focusedCol); + var metaColumn = this._getMetaColumnAtColumnX(x); + this.getPaneScroller(metaColumn).stopEditing(); + } +} + + +/** + * Stops editing without writing the editor's value to the model. + */ +qx.Proto.cancelEditing = function() { + if (this._focusedCol != null) { + var x = this.getTableColumnModel().getVisibleX(this._focusedCol); + var metaColumn = this._getMetaColumnAtColumnX(x); + this.getPaneScroller(metaColumn).cancelEditing(); + } +} + + +/** + * Gets the meta column at a certain x position in the page. If there is no + * meta column at this postion, -1 is returned. + * + * @param pageX {int} the position in the page to check (in pixels). + * @return {int} the index of the meta column or -1. + */ +qx.Proto._getMetaColumnAtPageX = function(pageX) { + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + var elem = scrollerArr[i].getElement(); + if (pageX >= qx.dom.Location.getPageBoxLeft(elem) + && pageX <= qx.dom.Location.getPageBoxRight(elem)) + { + return i; + } + } + + return -1; +} + + +/** + * Returns the meta column a column is shown in. If the column is not shown at + * all, -1 is returned. + * + * @param visXPos {int} the visible x position of the column. + * @return {int} the meta column the column is shown in. + */ +qx.Proto._getMetaColumnAtColumnX = function(visXPos) { + var metaColumnCounts = this.getMetaColumnCounts(); + var rightXPos = 0; + for (var i = 0; i < metaColumnCounts.length; i++) { + var counts = metaColumnCounts[i]; + rightXPos += counts; + + if (counts == -1 || visXPos < rightXPos) { + return i; + } + } + + return -1; +} + + +/** + * Updates the text shown in the status bar. + */ +qx.Proto._updateStatusBar = function() { + if (this.getStatusBarVisible()) { + var selectedRowCount = this.getSelectionModel().getSelectedCount(); + var rowCount = this.getTableModel().getRowCount(); + + var text; + if (selectedRowCount == 0) { + text = rowCount + ((rowCount == 1) ? " row" : " rows"); + } else { + text = selectedRowCount + " of " + rowCount + + ((rowCount == 1) ? " row" : " rows") + " selected"; + } + this._statusBar.setHtml(text); + } +} + + +/** + * Updates the widths of all scrollers. + */ +qx.Proto._updateScrollerWidths = function() { +/* no longer needed, per Til, and removing it does not appear to add problems. + * qx.ui.core.Widget.flushGlobalQueues(); + */ + + // Give all scrollers except for the last one the wanted width + // (The last one has a flex with) + var scrollerArr = this._getPaneScrollerArr(); + for (var i = 0; i < scrollerArr.length; i++) { + var isLast = (i == (scrollerArr.length - 1)); + var width = isLast ? "1*" : scrollerArr[i].getTablePaneModel().getTotalWidth(); + scrollerArr[i].setWidth(width); + } +} + + +/** + * Updates the visibility of the scrollbars in the meta columns. + */ +qx.Proto._updateScrollBarVisibility = function() { + if (this.isSeeable()) { + var horBar = qx.ui.table.TablePaneScroller.HORIZONTAL_SCROLLBAR; + var verBar = qx.ui.table.TablePaneScroller.VERTICAL_SCROLLBAR; + var scrollerArr = this._getPaneScrollerArr(); + + // Check which scroll bars are needed + var horNeeded = false; + var verNeeded = false; + for (var i = 0; i < scrollerArr.length; i++) { + var isLast = (i == (scrollerArr.length - 1)); + + // Only show the last vertical scrollbar + var bars = scrollerArr[i].getNeededScrollBars(horNeeded, !isLast); + + if (bars & horBar) { + horNeeded = true; + } + if (isLast && (bars & verBar)) { + verNeeded = true; + } + } + + // Set the needed scrollbars + for (var i = 0; i < scrollerArr.length; i++) { + var isLast = (i == (scrollerArr.length - 1)); + + // Only show the last vertical scrollbar + scrollerArr[i].setHorizontalScrollBarVisible(horNeeded); + scrollerArr[i].setVerticalScrollBarVisible(isLast && verNeeded); + } + } +} + + +/** + * Event handler. Called when the column visibiliy button was executed. + */ +qx.Proto._onColumnVisibilityBtExecuted = function() { + if ((this._columnVisibilityMenuCloseTime == null) + || (new Date().getTime() > this._columnVisibilityMenuCloseTime + 200)) + { + this._toggleColumnVisibilityMenu(); + } +} + + +/** + * Toggels the visibility of the menu used to change the visibility of columns. + */ +qx.Proto._toggleColumnVisibilityMenu = function() { + if (this._columnVisibilityMenu == null || !this._columnVisibilityMenu.isSeeable()) { + // Show the menu + + // Create the new menu + var menu = new qx.ui.menu.Menu; + + menu.addEventListener("disappear", function(evt) { + this._columnVisibilityMenuCloseTime = new Date().getTime(); + }, this); + + var tableModel = this.getTableModel(); + var columnModel = this.getTableColumnModel(); + for (var x = 0; x < columnModel.getOverallColumnCount(); x++) { + var col = columnModel.getOverallColumnAtX(x); + var visible = columnModel.isColumnVisible(col); + var cmd = { col:col } + var bt = new qx.ui.menu.CheckBox(tableModel.getColumnName(col), null, visible); + + var handler = this._createColumnVisibilityCheckBoxHandler(col); + bt._handler = handler; + bt.addEventListener("execute", handler, this); + + menu.add(bt); + } + + menu.setParent(this.getTopLevelWidget()); + + this._columnVisibilityMenu = menu; + + // Show the menu + var btElem = this._columnVisibilityBt.getElement(); + menu.setRestrictToPageOnOpen(false); + menu.setTop(qx.dom.Location.getClientBoxBottom(btElem)); + menu.setLeft(-1000); + + // NOTE: We have to show the menu in a timeout, otherwise it won't be shown + // at all. + window.setTimeout(function() { + menu.show(); + qx.ui.core.Widget.flushGlobalQueues(); + + menu.setLeft(qx.dom.Location.getClientBoxRight(btElem) - menu.getOffsetWidth()); + qx.ui.core.Widget.flushGlobalQueues(); + }, 0); + } else { + // hide the menu + menu.hide(); + this._cleanupColumnVisibilityMenu(); + } +} + + +/** + * Cleans up the column visibility menu. + */ +qx.Proto._cleanupColumnVisibilityMenu = function() { + if (this._columnVisibilityMenu != null && ! this._columnVisibilityMenu.getDisposed()) { + this._columnVisibilityMenu.dispose(); + this._columnVisibilityMenu = null; + } +} + + +/** + * Creates a handler for a check box of the column visibility menu. + * + * @param col {int} the model index of column to create the handler for. + */ +qx.Proto._createColumnVisibilityCheckBoxHandler = function(col) { + return function(evt) { + var columnModel = this.getTableColumnModel(); + columnModel.setColumnVisible(col, !columnModel.isColumnVisible(col)); + } +} + + +/** + * Sets the width of a column. + * + * @param col {int} the model index of column. + * @param width {int} the new width in pixels. + */ +qx.Proto.setColumnWidth = function(col, width) { + this.getTableColumnModel().setColumnWidth(col, width); +} + + +// overridden +qx.Proto._changeInnerWidth = function(newValue, oldValue) { + var self = this; + window.setTimeout(function() { + self._updateScrollBarVisibility(); + qx.ui.core.Widget.flushGlobalQueues(); + }, 0); + + return qx.ui.layout.VerticalBoxLayout.prototype._changeInnerWidth.call(this, newValue, oldValue); +} + + +// overridden +qx.Proto._changeInnerHeight = function(newValue, oldValue) { + var self = this; + window.setTimeout(function() { + self._updateScrollBarVisibility(); + qx.ui.core.Widget.flushGlobalQueues(); + }, 0); + + return qx.ui.layout.VerticalBoxLayout.prototype._changeInnerHeight.call(this, newValue, oldValue); +} + + +// overridden +qx.Proto._afterAppear = function() { + qx.ui.layout.VerticalBoxLayout.prototype._afterAppear.call(this); + + this._updateScrollBarVisibility(); +} + + +// overridden +qx.Proto.dispose = function() { + if (this.getDisposed()) { + return true; + } + + if (this._tableModel) { + this._tableModel.removeEventListener(qx.ui.table.TableModel.EVENT_TYPE_META_DATA_CHANGED, this._onTableModelMetaDataChanged, this); + } + + this._columnVisibilityBt.removeEventListener("execute", this._onColumnVisibilityBtExecuted, this); + this._columnVisibilityBt.dispose(); + + this._cleanupColumnVisibilityMenu(); + + this._cleanUpMetaColumns(0); + + var selectionModel = this.getSelectionModel(); + if (selectionModel != null) { + selectionModel.removeEventListener("changeSelection", this._onSelectionChanged, this); + } + + var tableModel = this.getTableModel(); + if (tableModel != null) { + tableModel.removeEventListener(qx.ui.table.TableModel.EVENT_TYPE_META_DATA_CHANGED, this._onTableModelMetaDataChanged, this); + tableModel.removeEventListener(qx.ui.table.TableModel.EVENT_TYPE_DATA_CHANGED, this._onTableModelDataChanged, this); + } + + var tableColumnModel = this.getTableColumnModel(); + if (tableColumnModel) { + tableColumnModel.removeEventListener("visibilityChanged", this._onColVisibilityChanged, this); + tableColumnModel.removeEventListener("widthChanged", this._onColWidthChanged, this); + tableColumnModel.removeEventListener("orderChanged", this._onColOrderChanged, this); + } + + this.removeEventListener("keydown", this._onkeydown); + this.removeEventListener("keypress", this._onkeypress); + + return qx.ui.layout.VerticalBoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/TableColumnModel.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/TableColumnModel.js new file mode 100644 index 0000000000..334187a268 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/TableColumnModel.js @@ -0,0 +1,399 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 by STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +// These are needed because of their instantiation at bottom. I don't think this +// is a good idea. (wpbasti) +#require(qx.ui.table.DefaultHeaderCellRenderer) +#require(qx.ui.table.DefaultDataCellRenderer) +#require(qx.ui.table.TextFieldCellEditorFactory) + +************************************************************************ */ + +/** + * A model that contains all meta data about columns, such as width, renderers, + * visibility and order. + * + * @event widthChanged {qx.event.type.DataEvent} Fired when the width of a + * column has changed. The data property of the event is a map having the + * following attributes: + *

    + *
  • col: The model index of the column the width of which has changed.
  • + *
  • newWidth: The new width of the column in pixels.
  • + *
  • oldWidth: The old width of the column in pixels.
  • + *
+ * @event visibilityChangedPre {qx.event.type.DataEvent} Fired when the + * visibility of a column has changed. This event is equal to + * "visibilityChanged", but is fired right before. + * @event visibilityChanged {qx.event.type.DataEvent} Fired when the + * visibility of a column has changed. The data property of the + * event is a map having the following attributes: + *
    + *
  • col: The model index of the column the visibility of which has changed.
  • + *
  • visible: Whether the column is now visible.
  • + *
+ * @event orderChanged {qx.event.type.DataEvent} Fired when the column order + * has changed. The data property of the + * event is a map having the following attributes: + *
    + *
  • col: The model index of the column that was moved.
  • + *
  • fromOverXPos: The old overall x position of the column.
  • + *
  • toOverXPos: The new overall x position of the column.
  • + *
+ * + * @see com.ptvag.webcomponent.ui.table.TableModel + */ +qx.OO.defineClass("qx.ui.table.TableColumnModel", qx.core.Target, +function() { + qx.core.Target.call(this); +}); + + +/** + * Initializes the column model. + * + * @param colCount {int} the number of columns the model should have. + */ +qx.Proto.init = function(colCount) { + this._columnDataArr = []; + + var width = qx.ui.table.TableColumnModel.DEFAULT_WIDTH; + var headerRenderer = qx.ui.table.TableColumnModel.DEFAULT_HEADER_RENDERER; + var dataRenderer = qx.ui.table.TableColumnModel.DEFAULT_DATA_RENDERER; + var editorFactory = qx.ui.table.TableColumnModel.DEFAULT_EDITOR_FACTORY; + this._overallColumnArr = []; + this._visibleColumnArr = []; + for (var col = 0; col < colCount; col++) { + this._columnDataArr[col] = { width:width, headerRenderer:headerRenderer, + dataRenderer:dataRenderer, editorFactory:editorFactory } + this._overallColumnArr[col] = col; + this._visibleColumnArr[col] = col; + } + + this._colToXPosMap = null; +} + + +/** + * Sets the width of a column. + * + * @param col {int} the model index of the column. + * @param width {int} the new width the column should get in pixels. + */ +qx.Proto.setColumnWidth = function(col, width) { + var oldWidth = this._columnDataArr[col].width; + if (oldWidth != width) { + this._columnDataArr[col].width = width; + if (this.hasEventListeners("widthChanged")) { + var data = { col:col, newWidth:width, oldWidth:oldWidth } + this.dispatchEvent(new qx.event.type.DataEvent("widthChanged", data), true); + } + } +} + + +/** + * Returns the width of a column. + * + * @param col {int} the model index of the column. + * @return {int} the width of the column in pixels. + */ +qx.Proto.getColumnWidth = function(col) { + return this._columnDataArr[col].width; +} + + +/** + * Sets the header renderer of a column. + * + * @param col {int} the model index of the column. + * @param renderer {HeaderCellRenderer} the new header renderer the column + * should get. + */ +qx.Proto.setHeaderCellRenderer = function(col, renderer) { + this._columnDataArr[col].headerRenderer = renderer; +} + + +/** + * Returns the header renderer of a column. + * + * @param col {int} the model index of the column. + * @return {HeaderCellRenderer} the header renderer of the column. + */ +qx.Proto.getHeaderCellRenderer = function(col) { + return this._columnDataArr[col].headerRenderer; +} + + +/** + * Sets the data renderer of a column. + * + * @param col {int} the model index of the column. + * @param renderer {DataCellRenderer} the new data renderer the column should get. + */ +qx.Proto.setDataCellRenderer = function(col, renderer) { + this._columnDataArr[col].dataRenderer = renderer; +} + + +/** + * Returns the data renderer of a column. + * + * @param col {int} the model index of the column. + * @return {DataCellRenderer} the data renderer of the column. + */ +qx.Proto.getDataCellRenderer = function(col) { + return this._columnDataArr[col].dataRenderer; +} + + +/** + * Sets the cell editor factory of a column. + * + * @param col {int} the model index of the column. + * @param factory {CellEditorFactory} the new cell editor factory the column should get. + */ +qx.Proto.setCellEditorFactory = function(col, factory) { + this._columnDataArr[col].editorFactory = factory; +} + + +/** + * Returns the cell editor factory of a column. + * + * @param col {int} the model index of the column. + * @return {CellEditorFactory} the cell editor factory of the column. + */ +qx.Proto.getCellEditorFactory = function(col) { + return this._columnDataArr[col].editorFactory; +} + + +/** + * Returns the map that translates model indexes to x positions. + *

+ * The returned map contains for a model index (int) a map having two + * properties: overX (the overall x position of the column, int) and + * visX (the visible x position of the column, int). visX is missing for + * hidden columns. + * + * @return the "column to x postion" map. + */ +qx.Proto._getColToXPosMap = function() { + if (this._colToXPosMap == null) { + this._colToXPosMap = {}; + for (var overX = 0; overX < this._overallColumnArr.length; overX++) { + var col = this._overallColumnArr[overX]; + this._colToXPosMap[col] = { overX:overX } + } + for (var visX = 0; visX < this._visibleColumnArr.length; visX++) { + var col = this._visibleColumnArr[visX]; + this._colToXPosMap[col].visX = visX; + } + } + return this._colToXPosMap; +} + + +/** + * Returns the number of visible columns. + * + * @return {int} the number of visible columns. + */ +qx.Proto.getVisibleColumnCount = function() { + return this._visibleColumnArr.length; +} + + +/** + * Returns the model index of a column at a certain visible x position. + * + * @param visXPos {int} the visible x position of the column. + * @return {int} the model index of the column. + */ +qx.Proto.getVisibleColumnAtX = function(visXPos) { + return this._visibleColumnArr[visXPos]; +} + + +/** + * Returns the visible x position of a column. + * + * @param col {int} the model index of the column. + * @return {int} the visible x position of the column. + */ +qx.Proto.getVisibleX = function(col) { + return this._getColToXPosMap()[col].visX; +} + + +/** + * Returns the overall number of columns (including hidden columns). + * + * @return {int} the overall number of columns. + */ +qx.Proto.getOverallColumnCount = function() { + return this._overallColumnArr.length; +} + + +/** + * Returns the model index of a column at a certain overall x position. + * + * @param overXPos {int} the overall x position of the column. + * @return {int} the model index of the column. + */ +qx.Proto.getOverallColumnAtX = function(overXPos) { + return this._overallColumnArr[overXPos]; +} + + +/** + * Returns the overall x position of a column. + * + * @param col {int} the model index of the column. + * @return {int} the overall x position of the column. + */ +qx.Proto.getOverallX = function(col) { + return this._getColToXPosMap()[col].overX; +} + + +/** + * Returns whether a certain column is visible. + * + * @param col {int} the model index of the column. + * @return {boolean} whether the column is visible. + */ +qx.Proto.isColumnVisible = function(col) { + return (this._getColToXPosMap()[col].visX != null); +} + + +/** + * Sets whether a certain column is visible. + * + * @param col {int} the model index of the column. + * @param visible {boolean} whether the column should be visible. + */ +qx.Proto.setColumnVisible = function(col, visible) { + if (visible != this.isColumnVisible(col)) { + if (visible) { + var colToXPosMap = this._getColToXPosMap(); + + var overX = colToXPosMap[col].overX; + if (overX == null) { + throw new Error("Showing column failed: " + col + + ". The column is not added to this TablePaneModel."); + } + + // get the visX of the next visible column after the column to show + var nextVisX; + for (var x = overX + 1; x < this._overallColumnArr.length; x++) { + var currCol = this._overallColumnArr[x]; + var currVisX = colToXPosMap[currCol].visX; + if (currVisX != null) { + nextVisX = currVisX; + break; + } + } + + // If there comes no visible column any more, then show the column + // at the end + if (nextVisX == null) { + nextVisX = this._visibleColumnArr.length; + } + + // Add the column to the visible columns + this._visibleColumnArr.splice(nextVisX, 0, col); + } else { + var visX = this.getVisibleX(col); + this._visibleColumnArr.splice(visX, 1); + } + + // Invalidate the _colToXPosMap + this._colToXPosMap = null; + + // Inform the listeners + if (! this._internalChange) { + if (this.hasEventListeners("visibilityChangedPre")) { + var data = { col:col, visible:visible } + this.dispatchEvent(new qx.event.type.DataEvent("visibilityChangedPre", data), true); + } + if (this.hasEventListeners("visibilityChanged")) { + var data = { col:col, visible:visible } + this.dispatchEvent(new qx.event.type.DataEvent("visibilityChanged", data), true); + } + } + + //this.debug("setColumnVisible col:"+col+",visible:"+visible+",this._overallColumnArr:"+this._overallColumnArr+",this._visibleColumnArr:"+this._visibleColumnArr); + } +} + + +/** + * Moves a column. + * + * @param fromOverXPos {int} the overall x postion of the column to move. + * @param toOverXPos {int} the overall x postion of where the column should be + * moved to. + */ +qx.Proto.moveColumn = function(fromOverXPos, toOverXPos) { + this._internalChange = true; + + var col = this._overallColumnArr[fromOverXPos]; + var visible = this.isColumnVisible(col); + + if (visible) { + this.setColumnVisible(col, false); + } + + this._overallColumnArr.splice(fromOverXPos, 1); + this._overallColumnArr.splice(toOverXPos, 0, col); + + // Invalidate the _colToXPosMap + this._colToXPosMap = null; + + if (visible) { + this.setColumnVisible(col, true); + } + + this._internalChange = false; + + // Inform the listeners + if (this.hasEventListeners("orderChanged")) { + var data = { col:col, fromOverXPos:fromOverXPos, toOverXPos:toOverXPos } + this.dispatchEvent(new qx.event.type.DataEvent("orderChanged", data), true); + } +} + + +/** {int} the default width of a column in pixels. */ +qx.Class.DEFAULT_WIDTH = 100; + +/** {DefaultDataCellRenderer} the default header cell renderer. */ +qx.Class.DEFAULT_HEADER_RENDERER = new qx.ui.table.DefaultHeaderCellRenderer; + +/** {DefaultDataCellRenderer} the default data cell renderer. */ +qx.Class.DEFAULT_DATA_RENDERER = new qx.ui.table.DefaultDataCellRenderer; + +/** {TextFieldCellEditorFactory} the default editor factory. */ +qx.Class.DEFAULT_EDITOR_FACTORY = new qx.ui.table.TextFieldCellEditorFactory; diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/TableModel.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/TableModel.js new file mode 100644 index 0000000000..6bf4a55291 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/TableModel.js @@ -0,0 +1,243 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 by STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * The data model of a table. + * + * @event dataChanged {qx.event.type.DataEvent} Fired when the table data changed + * (the stuff shown in the table body). The data property of the event + * may be null or a map having the following attributes: + *

    + *
  • firstRow: The index of the first row that has changed.
  • + *
  • lastRow: The index of the last row that has changed.
  • + *
  • firstColumn: The model index of the first column that has changed.
  • + *
  • lastColumn: The model index of the last column that has changed.
  • + *
+ * @event metaDataChanged {qx.event.type.Event} Fired when the meta data changed + * (the stuff shown in the table header). + */ +qx.OO.defineClass("qx.ui.table.TableModel", qx.core.Target, +function() { + qx.core.Target.call(this); +}); + + +/** + * Returns the number of rows in the model. + * + * @return {int} the number of rows. + */ +qx.Proto.getRowCount = function() { + throw new Error("getRowCount is abstract"); +} + + +/** + *

Returns the data of one row. This function may be overriden by models which hold + * all data of a row in one object. By using this function, clients have a way of + * quickly retrieving the entire row data.

+ * + *

Important:Models which do not have their row data accessible in one object + * may return null.

+ * + * @param rowIndex {int} the model index of the row. + * @return {Object} the row data as an object or null if the model does not support row data + * objects. The details on the object returned are determined by the model + * implementation only. + */ +qx.Proto.getRowData = function(rowIndex) { + return null; +} + + +/** + * Returns the number of columns in the model. + * + * @return {int} the number of columns. + */ +qx.Proto.getColumnCount = function() { + throw new Error("getColumnCount is abstract"); +} + + +/** + * Returns the ID of column. The ID may be used to identify columns + * independent from their index in the model. E.g. for being aware of added + * columns when saving the width of a column. + * + * @param columnIndex {int} the index of the column. + * @return {string} the ID of the column. + */ +qx.Proto.getColumnId = function(columnIndex) { + throw new Error("getColumnId is abstract"); +} + + +/** + * Returns the index of a column. + * + * @param columnId {string} the ID of the column. + * @return {int} the index of the column. + */ +qx.Proto.getColumnIndexById = function(columnId) { + throw new Error("getColumnIndexById is abstract"); +} + + +/** + * Returns the name of a column. This name will be shown to the user in the + * table header. + * + * @param columnIndex {int} the index of the column. + * @return {string} the name of the column. + */ +qx.Proto.getColumnName = function(columnIndex) { + throw new Error("getColumnName is abstract"); +} + + +/** + * Returns whether a column is editable. + * + * @param columnIndex {int} the column to check. + * @return {boolean} whether the column is editable. + */ +qx.Proto.isColumnEditable = function(columnIndex) { + return false; +} + + +/** + * Returns whether a column is sortable. + * + * @param columnIndex {int} the column to check. + * @return {boolean} whether the column is sortable. + */ +qx.Proto.isColumnSortable = function(columnIndex) { + return false; +} + + +/** + * Sorts the model by a column. + * + * @param columnIndex {int} the column to sort by. + * @param ascending {boolean} whether to sort ascending. + */ +qx.Proto.sortByColumn = function(columnIndex, ascending) { +} + + +/** + * Returns the column index the model is sorted by. If the model is not sorted + * -1 is returned. + * + * @return {int} the column index the model is sorted by. + */ +qx.Proto.getSortColumnIndex = function() { + return -1; +} + + +/** + * Returns whether the model is sorted ascending. + * + * @return {boolean} whether the model is sorted ascending. + */ +qx.Proto.isSortAscending = function() { + return true; +} + + +/** + * Prefetches some rows. This is a hint to the model that the specified rows + * will be read soon. + * + * @param firstRowIndex {int} the index of first row. + * @param lastRowIndex {int} the index of last row. + */ +qx.Proto.prefetchRows = function(firstRowIndex, lastRowIndex) { +} + + +/** + * Returns a cell value by column index. + * + * @param columnIndex {int} the index of the column. + * @param rowIndex {int} the index of the row. + * @return {var} The value of the cell. + * @see #getValueById{} + */ +qx.Proto.getValue = function(columnIndex, rowIndex) { + throw new Error("getValue is abstract"); +} + + +/** + * Returns a cell value by column ID. + *

+ * Whenever you have the choice, use {@link #getValue()} instead, + * because this should be faster. + * + * @param columnId {string} the ID of the column. + * @param rowIndex {int} the index of the row. + * @return {var} the value of the cell. + */ +qx.Proto.getValueById = function(columnId, rowIndex) { + return this.getValue(this.getColumnIndexById(columnId), rowIndex); +} + + +/** + * Sets a cell value by column index. + * + * @param columnIndex {int} The index of the column. + * @param rowIndex {int} the index of the row. + * @param value {var} The new value. + * @see #setValueById{} + */ +qx.Proto.setValue = function(columnIndex, rowIndex, value) { + throw new Error("setValue is abstract"); +} + + +/** + * Sets a cell value by column ID. + *

+ * Whenever you have the choice, use {@link #setValue()} instead, + * because this should be faster. + * + * @param columnId {string} The ID of the column. + * @param rowIndex {int} The index of the row. + * @param value {var} The new value. + */ +qx.Proto.setValueById = function(columnId, rowIndex, value) { + return this.setValue(this.getColumnIndexById(columnId), rowIndex, value); +} + + +/** {string} The type of the event fired when the data changed. */ +qx.Class.EVENT_TYPE_DATA_CHANGED = "dataChanged"; + +/** {string} The type of the event fired when the meta data changed. */ +qx.Class.EVENT_TYPE_META_DATA_CHANGED = "metaDataChanged"; diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/TablePane.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/TablePane.js new file mode 100644 index 0000000000..41db2ab274 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/TablePane.js @@ -0,0 +1,486 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 by STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * The table pane that shows a certain section from a table. This class handles + * the display of the data part of a table and is therefore the base for virtual + * scrolling. + * + * @param paneScroller {TablePaneScroller} the TablePaneScroller the header belongs to. + */ +qx.OO.defineClass("qx.ui.table.TablePane", qx.ui.basic.Terminator, +function(paneScroller) { + qx.ui.basic.Terminator.call(this); + + this._paneScroller = paneScroller; + + this.debug("USE_ARRAY_JOIN:" + qx.ui.table.TablePane.USE_ARRAY_JOIN + ", USE_TABLE:" + qx.ui.table.TablePane.USE_TABLE); + + this._lastColCount = 0; + this._lastRowCount = 0; +}); + +/** The index of the first row to show. */ +qx.OO.addProperty({ name:"firstVisibleRow", type:"number", defaultValue:0 }); + +/** The number of rows to show. */ +qx.OO.addProperty({ name:"visibleRowCount", type:"number", defaultValue:0 }); + + +// property modifier +qx.Proto._modifyFirstVisibleRow = function(propValue, propOldValue, propData) { + this._updateContent(); + return true; +} + + +// property modifier +qx.Proto._modifyVisibleRowCount = function(propValue, propOldValue, propData) { + this._updateContent(); + return true; +} + + +// overridden +qx.Proto._afterAppear = function() { + qx.ui.basic.Terminator.prototype._afterAppear.call(this); + + if (this._updateWantedWhileInvisible) { + // We are visible now and an update was wanted while we were invisible + // -> Do the update now + this._updateContent(); + this._updateWantedWhileInvisible = false; + } +}; + + +/** + * Returns the TablePaneScroller this pane belongs to. + * + * @return {TablePaneScroller} the TablePaneScroller. + */ +qx.Proto.getPaneScroller = function() { + return this._paneScroller; +}; + + +/** + * Returns the table this pane belongs to. + * + * @return {Table} the table. + */ +qx.Proto.getTable = function() { + return this._paneScroller.getTable(); +}; + + +/** + * Sets the currently focused cell. + * + * @param col {int} the model index of the focused cell's column. + * @param row {int} the model index of the focused cell's row. + * @param massUpdate {boolean ? false} Whether other updates are planned as well. + * If true, no repaint will be done. + */ +qx.Proto.setFocusedCell = function(col, row, massUpdate) { + if (col != this._focusedCol || row != this._focusedRow) { + var oldCol = this._focusedCol; + var oldRow = this._focusedRow; + this._focusedCol = col; + this._focusedRow = row; + + // Update the focused row background + if (row != oldRow && !massUpdate) { + // NOTE: Only the old and the new row need update + this._updateContent(false, oldRow, true); + this._updateContent(false, row, true); + } + } +} + + +/** + * Event handler. Called when the selection has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onSelectionChanged = function(evt) { + this._updateContent(false, null, true); +} + + +/** + * Event handler. Called when the table gets or looses the focus. + */ +qx.Proto._onFocusChanged = function(evt) { + this._updateContent(false, null, true); +}; + + +/** + * Event handler. Called when the width of a column has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onColWidthChanged = function(evt) { + this._updateContent(true); +} + + +/** + * Event handler. Called the column order has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onColOrderChanged = function(evt) { + this._updateContent(true); +} + + +/** + * Event handler. Called when the pane model has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onPaneModelChanged = function(evt) { + this._updateContent(true); +} + + +/** + * Event handler. Called when the table model data has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onTableModelDataChanged = function(evt) { + var data = evt.getData ? evt.getData() : null; + + var firstRow = this.getFirstVisibleRow(); + var rowCount = this.getVisibleRowCount(); + if (data == null || data.lastRow == -1 + || data.lastRow >= firstRow && data.firstRow < firstRow + rowCount) + { + // The change intersects this pane + this._updateContent(); + } +} + + +/** + * Event handler. Called when the table model meta data has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onTableModelMetaDataChanged = function(evt) { + this._updateContent(); +} + + +/** + * Updates the content of the pane. + * + * @param completeUpdate {boolean ? false} if true a complete update is performed. + * On a complete update all cell widgets are recreated. + * @param onlyRow {int ? null} if set only the specified row will be updated. + * @param onlySelectionOrFocusChanged {boolean ? false} if true, cell values won't + * be updated. Only the row background will. + */ +qx.Proto._updateContent = function(completeUpdate, onlyRow, + onlySelectionOrFocusChanged) +{ + if (! this.isSeeable()) { + this._updateWantedWhileInvisible = true; + return; + } + + if (qx.ui.table.TablePane.USE_ARRAY_JOIN) { + this._updateContent_array_join(completeUpdate, onlyRow, onlySelectionOrFocusChanged); + } else { + this._updateContent_orig(completeUpdate, onlyRow, onlySelectionOrFocusChanged); + } +} + + +qx.Proto._updateContent_array_join = function(completeUpdate, onlyRow, + onlySelectionOrFocusChanged) +{ + var TablePane = qx.ui.table.TablePane; + + var table = this.getTable(); + + var selectionModel = table.getSelectionModel(); + var tableModel = table.getTableModel(); + var columnModel = table.getTableColumnModel(); + var paneModel = this.getPaneScroller().getTablePaneModel(); + var rowRenderer = table.getDataRowRenderer(); + + var colCount = paneModel.getColumnCount(); + var rowHeight = table.getRowHeight(); + + var firstRow = this.getFirstVisibleRow(); + var rowCount = this.getVisibleRowCount(); + var modelRowCount = tableModel.getRowCount(); + if (firstRow + rowCount > modelRowCount) { + rowCount = Math.max(0, modelRowCount - firstRow); + } + + var cellInfo = { table:table }; + cellInfo.styleHeight = rowHeight; + + var htmlArr = []; + var rowWidth = paneModel.getTotalWidth(); + + if (TablePane.USE_TABLE) { + htmlArr.push(''); + + for (var x = 0; x < colCount; x++) { + var col = paneModel.getColumnAtX(x); + + htmlArr.push(); + htmlArr.push(columnModel.getColumnWidth(col)); + htmlArr.push('"/>'); + } + + htmlArr.push(''); + } + + tableModel.prefetchRows(firstRow, firstRow + rowCount - 1); + for (var y = 0; y < rowCount; y++) { + var row = firstRow + y; + + cellInfo.row = row; + cellInfo.selected = selectionModel.isSelectedIndex(row); + cellInfo.focusedRow = (this._focusedRow == row); + cellInfo.rowData = tableModel.getRowData(row); + + // Update this row + if (TablePane.USE_TABLE) { + htmlArr.push(''); + + var left = 0; + for (var x = 0; x < colCount; x++) { + var col = paneModel.getColumnAtX(x); + cellInfo.xPos = x; + cellInfo.col = col; + cellInfo.editable = tableModel.isColumnEditable(col); + cellInfo.focusedCol = (this._focusedCol == col); + cellInfo.value = tableModel.getValue(col, row); + var cellWidth = columnModel.getColumnWidth(col); + + cellInfo.styleLeft = left; + cellInfo.styleWidth = cellWidth; + + var cellRenderer = columnModel.getDataCellRenderer(col); + cellRenderer.createDataCellHtml_array_join(cellInfo, htmlArr); + + left += cellWidth; + } + + if (TablePane.USE_TABLE) { + htmlArr.push(''); + } else { + htmlArr.push(''); + } + } + + if (TablePane.USE_TABLE) { + htmlArr.push('
'); + } + + var elem = this.getElement(); + // this.debug(">>>" + htmlArr.join("") + "<<<") + elem.innerHTML = htmlArr.join(""); + + this.setHeight(rowCount * rowHeight); + + this._lastColCount = colCount; + this._lastRowCount = rowCount; +} + + +qx.Proto._updateContent_orig = function(completeUpdate, onlyRow, + onlySelectionOrFocusChanged) +{ + var TablePane = qx.ui.table.TablePane; + + var table = this.getTable(); + + var alwaysUpdateCells = table.getAlwaysUpdateCells(); + + var selectionModel = table.getSelectionModel(); + var tableModel = table.getTableModel(); + var columnModel = table.getTableColumnModel(); + var paneModel = this.getPaneScroller().getTablePaneModel(); + var rowRenderer = table.getDataRowRenderer(); + + var colCount = paneModel.getColumnCount(); + var rowHeight = table.getRowHeight(); + + var firstRow = this.getFirstVisibleRow(); + var rowCount = this.getVisibleRowCount(); + var modelRowCount = tableModel.getRowCount(); + if (firstRow + rowCount > modelRowCount) { + rowCount = Math.max(0, modelRowCount - firstRow); + } + + // Remove the rows that are not needed any more + if (completeUpdate || this._lastRowCount > rowCount) { + var firstRowToRemove = completeUpdate ? 0 : rowCount; + this._cleanUpRows(firstRowToRemove); + } + + if (TablePane.USE_TABLE) { + throw new Error("Combination of USE_TABLE==true and USE_ARRAY_JOIN==false is not yet implemented"); + } + + var elem = this.getElement(); + var childNodes = elem.childNodes; + var cellInfo = { table:table }; + tableModel.prefetchRows(firstRow, firstRow + rowCount - 1); + for (var y = 0; y < rowCount; y++) { + var row = firstRow + y; + if ((onlyRow != null) && (row != onlyRow)) { + continue; + } + + cellInfo.row = row; + cellInfo.selected = selectionModel.isSelectedIndex(row); + cellInfo.focusedRow = (this._focusedRow == row); + cellInfo.rowData = tableModel.getRowData(row); + + // Update this row + var rowElem; + var recyleRowElem; + if (y < childNodes.length) { + rowElem = childNodes[y]; + recyleRowElem = true + } else { + var rowElem = document.createElement("div"); + + //rowElem.style.position = "relative"; + rowElem.style.position = "absolute"; + rowElem.style.left = "0px"; + rowElem.style.top = (y * rowHeight) + "px"; + + rowElem.style.height = rowHeight + "px"; + rowElem.style.fontFamily = TablePane.CONTENT_ROW_FONT_FAMILY; + rowElem.style.fontSize = TablePane.CONTENT_ROW_FONT_SIZE; + elem.appendChild(rowElem); + recyleRowElem = false; + } + + rowRenderer.updateDataRowElement(cellInfo, rowElem); + + if (alwaysUpdateCells || !recyleRowElem || !onlySelectionOrFocusChanged) { + var html = ""; + var left = 0; + for (var x = 0; x < colCount; x++) { + var col = paneModel.getColumnAtX(x); + cellInfo.xPos = x; + cellInfo.col = col; + cellInfo.editable = tableModel.isColumnEditable(col); + cellInfo.focusedCol = (this._focusedCol == col); + cellInfo.value = tableModel.getValue(col, row); + var width = columnModel.getColumnWidth(col); + cellInfo.style = 'position:absolute;left:' + left + + 'px;top:0px;width:' + width + + 'px; height:' + rowHeight + "px"; + + var cellRenderer = columnModel.getDataCellRenderer(col); + if (recyleRowElem) { + var cellElem = rowElem.childNodes[x]; + cellRenderer.updateDataCellElement(cellInfo, cellElem); + } else { + html += cellRenderer.createDataCellHtml(cellInfo); + } + + left += width; + } + if (! recyleRowElem) { + rowElem.style.width = left + "px"; + rowElem.innerHTML = html; + } + } + } + + this.setHeight(rowCount * rowHeight); + + this._lastColCount = colCount; + this._lastRowCount = rowCount; +} + + +/** + * Cleans up the row widgets. + * + * @param firstRowToRemove {int} the visible index of the first row to clean up. + * All following rows will be cleaned up, too. + */ +qx.Proto._cleanUpRows = function(firstRowToRemove) { + var elem = this.getElement(); + if (elem) { + var childNodes = this.getElement().childNodes; + var paneModel = this.getPaneScroller().getTablePaneModel(); + var colCount = paneModel.getColumnCount(); + for (var y = childNodes.length - 1; y >= firstRowToRemove; y--) { + elem.removeChild(childNodes[y]); + } + } +} + + +// overridden +qx.Proto.dispose = function() { + if (this.getDisposed()) { + return true; + } + + this._cleanUpRows(0); + + return qx.ui.basic.Terminator.prototype.dispose.call(this); +} + + +qx.Class.USE_ARRAY_JOIN = false; +qx.Class.USE_TABLE = false; + + +qx.Class.CONTENT_ROW_FONT_FAMILY = '"Segoe UI", Corbel, Calibri, Tahoma, "Lucida Sans Unicode", sans-serif'; +qx.Class.CONTENT_ROW_FONT_SIZE = "11px"; + diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/TablePaneHeader.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/TablePaneHeader.js new file mode 100644 index 0000000000..657950293f --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/TablePaneHeader.js @@ -0,0 +1,276 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 by STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * Shows the header of a table. + * + * @param paneScroller {TablePaneScroller} the TablePaneScroller the header belongs to. + */ +qx.OO.defineClass("qx.ui.table.TablePaneHeader", qx.ui.layout.HorizontalBoxLayout, +function(paneScroller) { + qx.ui.layout.HorizontalBoxLayout.call(this); + + this._paneScroller = paneScroller; +}); + + +/** + * Returns the TablePaneScroller this header belongs to. + * + * @return {TablePaneScroller} the TablePaneScroller. + */ +qx.Proto.getPaneScroller = function() { + return this._paneScroller; +}; + + +/** + * Returns the table this header belongs to. + * + * @return {Table} the table. + */ +qx.Proto.getTable = function() { + return this._paneScroller.getTable(); +}; + + +/** + * Event handler. Called when the width of a column has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onColWidthChanged = function(evt) { + var data = evt.getData(); + this.setColumnWidth(data.col, data.newWidth); +} + + +/** + * Event handler. Called the column order has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onColOrderChanged = function(evt) { + this._updateContent(true); +} + + +/** + * Event handler. Called when the pane model has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onPaneModelChanged = function(evt) { + this._updateContent(true); +} + + +/** + * Event handler. Called when the table model meta data has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onTableModelMetaDataChanged = function(evt) { + this._updateContent(); +} + + +/** + * Sets the column width. This overrides the width from the column model. + * + * @param col {int} the column to change the width for. + * @param width {int} the new width. + */ +qx.Proto.setColumnWidth = function(col, width) { + var x = this.getPaneScroller().getTablePaneModel().getX(col); + var children = this.getChildren(); + if (children[x] != null) { + children[x].setWidth(width); + } +} + + +/** + * Sets the column the mouse is currently over. + * + * @param col {int} the model index of the column the mouse is currently over or + * null if the mouse is over no column. + */ +qx.Proto.setMouseOverColumn = function(col) { + if (col != this._lastMouseOverColumn) { + var paneModel = this.getPaneScroller().getTablePaneModel(); + var children = this.getChildren(); + + if (this._lastMouseOverColumn != null) { + var widget = children[paneModel.getX(this._lastMouseOverColumn)]; + if (widget != null) { + widget.removeState("mouseover"); + } + } + if (col != null) { + children[paneModel.getX(col)].addState("mouseover"); + } + + this._lastMouseOverColumn = col; + } +} + + +/** + * Shows the feedback shown while a column is moved by the user. + * + * @param col {int} the model index of the column to show the move feedback for. + * @param x {int} the x position the left side of the feeback should have + * (in pixels, relative to the left side of the header). + */ +qx.Proto.showColumnMoveFeedback = function(col, x) { + var elem = this.getElement(); + if (this._moveFeedback == null) { + var xPos = this.getPaneScroller().getTablePaneModel().getX(col); + var cellWidget = this.getChildren()[xPos]; + + // Create the feedback + // Workaround: Since a cloned widget throws an exception when it is + // added to another component we have to create a new one + // using the renderer + //this._moveFeedback = cellWidget.clone(); + var tableModel = this.getTable().getTableModel(); + var columnModel = this.getTable().getTableColumnModel(); + var cellInfo = { xPos:xPos, col:col, name:tableModel.getColumnName(col) } + var cellRenderer = columnModel.getHeaderCellRenderer(col); + this._moveFeedback = cellRenderer.createHeaderCell(cellInfo); + + // Configure the feedback + with (this._moveFeedback) { + setWidth(cellWidget.getBoxWidth()); + setHeight(cellWidget.getBoxHeight()); + setZIndex(1000000); + setOpacity(0.8); + setTop(qx.dom.Location.getClientBoxTop(elem)); + } + this.getTopLevelWidget().add(this._moveFeedback); + } + + this._moveFeedback.setLeft(qx.dom.Location.getClientBoxLeft(elem) + x); +} + + +/** + * Hides the feedback shown while a column is moved by the user. + */ +qx.Proto.hideColumnMoveFeedback = function() { + if (this._moveFeedback != null) { + this.getTopLevelWidget().remove(this._moveFeedback); + this._moveFeedback.dispose(); + this._moveFeedback = null; + } +} + + +/** + * Returns whether the column move feedback is currently shown. + */ +qx.Proto.isShowingColumnMoveFeedback = function() { + return this._moveFeedback != null; +} + + +/** + * Updates the content of the header. + * + * @param completeUpdate {boolean} if true a complete update is performed. On a + * complete update all header widgets are recreated. + */ +qx.Proto._updateContent = function(completeUpdate) { + var tableModel = this.getTable().getTableModel(); + var columnModel = this.getTable().getTableColumnModel(); + var paneModel = this.getPaneScroller().getTablePaneModel(); + + var children = this.getChildren(); + var oldColCount = children.length; + var colCount = paneModel.getColumnCount(); + + var sortedColum = tableModel.getSortColumnIndex(); + + // Remove all widgets on the complete update + if (completeUpdate) { + this._cleanUpCells(); + } + + // Update the header + var cellInfo = {}; + cellInfo.sortedAscending = tableModel.isSortAscending(); + for (var x = 0; x < colCount; x++) { + var col = paneModel.getColumnAtX(x); + + var colWidth = columnModel.getColumnWidth(col); + + // TODO: Get real cell renderer + var cellRenderer = columnModel.getHeaderCellRenderer(col); + + cellInfo.xPos = x; + cellInfo.col = col; + cellInfo.name = tableModel.getColumnName(col); + cellInfo.editable = tableModel.isColumnEditable(col); + cellInfo.sorted = (col == sortedColum); + + // Get the cached widget + var cachedWidget = children[x]; + + // Create or update the widget + if (cachedWidget == null) { + // We have no cached widget -> create it + cachedWidget = cellRenderer.createHeaderCell(cellInfo); + cachedWidget.set({ width:colWidth, height:"100%" }); + + this.add(cachedWidget); + } else { + // This widget already created before -> recycle it + cellRenderer.updateHeaderCell(cellInfo, cachedWidget); + } + } +} + + +/** + * Cleans up all header cells. + */ +qx.Proto._cleanUpCells = function() { + var children = this.getChildren(); + for (var x = children.length - 1; x >= 0; x--) { + var cellWidget = children[x]; + //this.debug("disposed:" + cellWidget.getDisposed() + ",has parent: " + (cellWidget.getParent() != null) + ",x:"+x); + this.remove(cellWidget); + cellWidget.dispose(); + } +} + + +// overridden +qx.Proto.dispose = function() { + if (this.getDisposed()) { + return true; + } + + return qx.ui.layout.HorizontalBoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/TablePaneModel.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/TablePaneModel.js new file mode 100644 index 0000000000..d53da59251 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/TablePaneModel.js @@ -0,0 +1,179 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 by STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * The model of a table pane. This model works as proxy to a + * {@link TableColumnModel} and manages the visual order of the columns shown in + * a {@link TablePane}. + * + * @param tableColumnModel {TableColumnModel} The TableColumnModel of which this + * model is the proxy. + * + * @event modelChanged {qx.event.type.Event} Fired when the model changed. + */ +qx.OO.defineClass("qx.ui.table.TablePaneModel", qx.core.Target, +function(tableColumnModel) { + qx.core.Target.call(this); + + tableColumnModel.addEventListener("visibilityChangedPre", this._onColVisibilityChanged, this); + + this._tableColumnModel = tableColumnModel; +}); + + +/** The visible x position of the first column this model should contain. */ +qx.OO.addProperty({ name : "firstColumnX", type : "number", defaultValue : 0 }); + +/** + * The maximum number of columns this model should contain. If -1 this model will + * contain all remaining columns. + */ +qx.OO.addProperty({ name : "maxColumnCount", type : "number", defaultValue : -1 }); + + +// property modifier +qx.Proto._modifyFirstColumnX = function(propValue, propOldValue, propData) { + this._columnCount = null; + this.createDispatchEvent(qx.ui.table.TablePaneModel.EVENT_TYPE_MODEL_CHANGED); + return true; +} + + +// property modifier +qx.Proto._modifyMaxColumnCount = function(propValue, propOldValue, propData) { + this._columnCount = null; + this.createDispatchEvent(qx.ui.table.TablePaneModel.EVENT_TYPE_MODEL_CHANGED); + return true; +} + + +/** + * Event handler. Called when the visibility of a column has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onColVisibilityChanged = function(evt) { + this._columnCount = null; + + // TODO: Check whether the column is in this model (This is a little bit + // tricky, because the column could _have been_ in this model, but is + // not in it after the change) + this.createDispatchEvent(qx.ui.table.TablePaneModel.EVENT_TYPE_MODEL_CHANGED); +} + + +/** + * Returns the number of columns in this model. + * + * @return {int} the number of columns in this model. + */ +qx.Proto.getColumnCount = function() { + if (this._columnCount == null) { + var firstX = this.getFirstColumnX(); + var maxColCount = this.getMaxColumnCount(); + var totalColCount = this._tableColumnModel.getVisibleColumnCount(); + + if (maxColCount == -1 || (firstX + maxColCount) > totalColCount) { + this._columnCount = totalColCount - firstX; + } else { + this._columnCount = maxColCount; + } + } + return this._columnCount; +} + + +/** + * Returns the model index of the column at the position xPos. + * + * @param xPos {int} the x postion in the table pane of the column. + * @return {int} the model index of the column. + */ +qx.Proto.getColumnAtX = function(xPos) { + var firstX = this.getFirstColumnX(); + return this._tableColumnModel.getVisibleColumnAtX(firstX + xPos); +} + + +/** + * Returns the x position of the column col. + * + * @param col {int} the model index of the column. + * @return {int} the x postion in the table pane of the column. + */ +qx.Proto.getX = function(col) { + var firstX = this.getFirstColumnX(); + var maxColCount = this.getMaxColumnCount(); + + var x = this._tableColumnModel.getVisibleX(col) - firstX; + if (x >= 0 && (maxColCount == -1 || x < maxColCount)) { + return x; + } else { + return -1; + } +} + + +/** + * Gets the position of the left side of a column (in pixels, relative to the + * left side of the table pane). + *

+ * This value corresponds to the sum of the widths of all columns left of the + * column. + * + * @param col {int} the model index of the column. + * @return the position of the left side of the column. + */ +qx.Proto.getColumnLeft = function(col) { + var left = 0; + var colCount = this.getColumnCount(); + for (var x = 0; x < colCount; x++) { + var currCol = this.getColumnAtX(x); + if (currCol == col) { + return left; + } + + left += this._tableColumnModel.getColumnWidth(currCol); + } + return -1; +} + + +/** + * Returns the total width of all columns in the model. + * + * @return {int} the total width of all columns in the model. + */ +qx.Proto.getTotalWidth = function() { + var totalWidth = 0; + var colCount = this.getColumnCount(); + for (var x = 0; x < colCount; x++) { + var col = this.getColumnAtX(x); + totalWidth += this._tableColumnModel.getColumnWidth(col); + } + return totalWidth; +} + + +/** {string} The type of the event fired when the model changed. */ +qx.Class.EVENT_TYPE_MODEL_CHANGED = "modelChanged"; diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/TablePaneScroller.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/TablePaneScroller.js new file mode 100644 index 0000000000..d6f7773148 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/TablePaneScroller.js @@ -0,0 +1,1331 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 by STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * Shows a whole meta column. This includes a {@link TablePaneHeader}, + * a {@link TablePane} and the needed scroll bars. This class handles the + * virtual scrolling and does all the mouse event handling. + * + * @param table {Table} the table the scroller belongs to. + */ +qx.OO.defineClass("qx.ui.table.TablePaneScroller", qx.ui.layout.VerticalBoxLayout, +function(table) { + qx.ui.layout.VerticalBoxLayout.call(this); + + this._table = table; + + // init scrollbars + this._verScrollBar = new qx.ui.core.ScrollBar(false); + this._horScrollBar = new qx.ui.core.ScrollBar(true); + + var scrollBarWidth = this._verScrollBar.getPreferredBoxWidth(); + + this._verScrollBar.setWidth("auto"); + this._horScrollBar.setHeight("auto"); + this._horScrollBar.setPaddingRight(scrollBarWidth); + //this._verScrollBar.setMergeEvents(true); + + this._horScrollBar.addEventListener("changeValue", this._onScrollX, this); + this._verScrollBar.addEventListener("changeValue", this._onScrollY, this); + + // init header + this._header = new qx.ui.table.TablePaneHeader(this); + this._header.set({ width:"auto", height:"auto" }); + + this._headerClipper = new qx.ui.layout.CanvasLayout; + with (this._headerClipper) { + setDimension("1*", "auto"); + setOverflow("hidden"); + add(this._header); + } + + this._spacer = new qx.ui.basic.Terminator; + this._spacer.setWidth(scrollBarWidth); + + this._top = new qx.ui.layout.HorizontalBoxLayout; + with (this._top) { + setHeight("auto"); + add(this._headerClipper, this._spacer); + } + + // init pane + this._tablePane = new qx.ui.table.TablePane(this); + this._tablePane.set({ width:"auto", height:"auto" }); + + this._focusIndicator = new qx.ui.layout.HorizontalBoxLayout; + this._focusIndicator.setAppearance("table-focus-indicator"); + this._focusIndicator.hide(); + + // Workaround: If the _focusIndicator has no content if always gets a too + // high hight in IE. + var dummyContent = new qx.ui.basic.Terminator; + dummyContent.setWidth(0); + this._focusIndicator.add(dummyContent); + + this._paneClipper = new qx.ui.layout.CanvasLayout; + with (this._paneClipper) { + setWidth("1*"); + setOverflow("hidden"); + add(this._tablePane, this._focusIndicator); + addEventListener("mousewheel", this._onmousewheel, this); + } + + // add all child widgets + var scrollerBody = new qx.ui.layout.HorizontalBoxLayout; + scrollerBody.setHeight("1*"); + scrollerBody.add(this._paneClipper, this._verScrollBar); + + this.add(this._top, scrollerBody, this._horScrollBar); + + // init event handlers + this.addEventListener("mousemove", this._onmousemove, this); + this.addEventListener("mousedown", this._onmousedown, this); + this.addEventListener("mouseup", this._onmouseup, this); + this.addEventListener("click", this._onclick, this); + this.addEventListener("dblclick", this._ondblclick, this); + this.addEventListener("mouseout", this._onmouseout, this); +}); + +/** Whether to show the horizontal scroll bar */ +qx.OO.addProperty({ name:"horizontalScrollBarVisible", type:"boolean", defaultValue:true }); + +/** Whether to show the vertical scroll bar */ +qx.OO.addProperty({ name:"verticalScrollBarVisible", type:"boolean", defaultValue:true }); + +/** The table pane model. */ +qx.OO.addProperty({ name:"tablePaneModel", type:"object", instance:"qx.ui.table.TablePaneModel" }); + +/** The current position of the the horizontal scroll bar. */ +qx.OO.addProperty({ name:"scrollX", type:"number", allowNull:false, defaultValue:0 }); + +/** The current position of the the vertical scroll bar. */ +qx.OO.addProperty({ name:"scrollY", type:"number", allowNull:false, defaultValue:0 }); + +/** + * Whether column resize should be live. If false, during resize only a line is + * shown and the real resize happens when the user releases the mouse button. + */ +qx.OO.addProperty({ name:"liveResize", type:"boolean", defaultValue:false }); + +/** + * Whether the focus should moved when the mouse is moved over a cell. If false + * the focus is only moved on mouse clicks. + */ +qx.OO.addProperty({ name:"focusCellOnMouseMove", type:"boolean", defaultValue:false }); + + +// property modifier +qx.Proto._modifyHorizontalScrollBarVisible = function(propValue, propOldValue, propData) { + // Workaround: We can't use setDisplay, because the scroll bar needs its + // correct height in order to check its value. When using + // setDisplay(false) the height isn't relayouted any more + if (propValue) { + this._horScrollBar.setHeight("auto"); + } else { + this._horScrollBar.setHeight(0); + } + this._horScrollBar.setVisibility(propValue); + + // NOTE: We have to flush the queues before updating the content so the new + // layout has been applied and _updateContent is able to work with + // correct values. + qx.ui.core.Widget.flushGlobalQueues(); + this._updateContent(); + + return true; +} + + +// property modifier +qx.Proto._modifyVerticalScrollBarVisible = function(propValue, propOldValue, propData) { + // Workaround: See _modifyHorizontalScrollBarVisible + if (propValue) { + this._verScrollBar.setWidth("auto"); + } else { + this._verScrollBar.setWidth(0); + } + this._verScrollBar.setVisibility(propValue); + + var scrollBarWidth = propValue ? this._verScrollBar.getPreferredBoxWidth() : 0; + this._horScrollBar.setPaddingRight(scrollBarWidth); + this._spacer.setWidth(scrollBarWidth); + + return true; +} + + +// property modifier +qx.Proto._modifyTablePaneModel = function(propValue, propOldValue, propData) { + if (propOldValue != null) { + propOldValue.removeEventListener("modelChanged", this._onPaneModelChanged, this); + } + propValue.addEventListener("modelChanged", this._onPaneModelChanged, this); + + return true; +} + + +// property modifier +qx.Proto._modifyScrollX = function(propValue, propOldValue, propData) { + this._horScrollBar.setValue(propValue); + return true; +} + + +// property modifier +qx.Proto._modifyScrollY = function(propValue, propOldValue, propData) { + this._verScrollBar.setValue(propValue); + return true; +} + + +/** + * Returns the table this scroller belongs to. + * + * @return {Table} the table. + */ +qx.Proto.getTable = function() { + return this._table; +}; + + +/** + * Event handler. Called when the visibility of a column has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onColVisibilityChanged = function(evt) { + this._updateHorScrollBarMaximum(); + this._updateFocusIndicator(); +} + + +/** + * Event handler. Called when the width of a column has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onColWidthChanged = function(evt) { + this._header._onColWidthChanged(evt); + this._tablePane._onColWidthChanged(evt); + + var data = evt.getData(); + var paneModel = this.getTablePaneModel(); + var x = paneModel.getX(data.col); + if (x != -1) { + // The change was in this scroller + this._updateHorScrollBarMaximum(); + this._updateFocusIndicator(); + } +} + + +/** + * Event handler. Called when the column order has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onColOrderChanged = function(evt) { + this._header._onColOrderChanged(evt); + this._tablePane._onColOrderChanged(evt); + + this._updateHorScrollBarMaximum(); +} + + +/** + * Event handler. Called when the table model has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onTableModelDataChanged = function(evt) { + this._tablePane._onTableModelDataChanged(evt); + + var rowCount = this.getTable().getTableModel().getRowCount(); + if (rowCount != this._lastRowCount) { + this._lastRowCount = rowCount; + + this._updateVerScrollBarMaximum(); + if (this.getFocusedRow() >= rowCount) { + if (rowCount == 0) { + this.setFocusedCell(null, null); + } else { + this.setFocusedCell(this.getFocusedColumn(), rowCount - 1); + } + } + } +} + + +/** + * Event handler. Called when the selection has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onSelectionChanged = function(evt) { + this._tablePane._onSelectionChanged(evt); +}; + + +/** + * Event handler. Called when the table gets or looses the focus. + */ +qx.Proto._onFocusChanged = function(evt) { + this._focusIndicator.setState("tableHasFocus", this.getTable().getFocused()); + + this._tablePane._onFocusChanged(evt); +}; + + +/** + * Event handler. Called when the table model meta data has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onTableModelMetaDataChanged = function(evt) { + this._header._onTableModelMetaDataChanged(evt); + this._tablePane._onTableModelMetaDataChanged(evt); +}; + + +/** + * Event handler. Called when the pane model has changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onPaneModelChanged = function(evt) { + this._header._onPaneModelChanged(evt); + this._tablePane._onPaneModelChanged(evt); +}; + + +/** + * Updates the maximum of the horizontal scroll bar, so it corresponds to the + * total width of the columns in the table pane. + */ +qx.Proto._updateHorScrollBarMaximum = function() { + this._horScrollBar.setMaximum(this.getTablePaneModel().getTotalWidth()); +} + + +/** + * Updates the maximum of the vertical scroll bar, so it corresponds to the + * number of rows in the table. + */ +qx.Proto._updateVerScrollBarMaximum = function() { + var rowCount = this.getTable().getTableModel().getRowCount(); + var rowHeight = this.getTable().getRowHeight(); + + if (this.getTable().getKeepFirstVisibleRowComplete()) { + this._verScrollBar.setMaximum((rowCount + 1) * rowHeight); + } else { + this._verScrollBar.setMaximum(rowCount * rowHeight); + } +} + + +/** + * Event handler. Called when the table property "keepFirstVisibleRowComplete" + * changed. + */ +qx.Proto._onKeepFirstVisibleRowCompleteChanged = function() { + this._updateVerScrollBarMaximum(); + this._updateContent(); +}; + + +// overridden +qx.Proto._changeInnerHeight = function(newValue, oldValue) { + // The height has changed -> Update content + this._postponedUpdateContent(); + + return qx.ui.layout.VerticalBoxLayout.prototype._changeInnerHeight.call(this, newValue, oldValue); +} + + +// overridden +qx.Proto._afterAppear = function() { + qx.ui.layout.VerticalBoxLayout.prototype._afterAppear.call(this); + + var self = this; + this.getElement().onselectstart = qx.util.Return.returnFalse; + + this._updateContent(); + this._header._updateContent(); + this._updateHorScrollBarMaximum(); + this._updateVerScrollBarMaximum(); +} + + +/** + * Event handler. Called when the horizontal scroll bar moved. + * + * @param evt {Map} the event. + */ +qx.Proto._onScrollX = function(evt) { + // Workaround: See _updateContent + this._header.setLeft(-evt.getData()); + + this._paneClipper.setScrollLeft(evt.getData()); + this.setScrollX(evt.getData()); +} + + +/** + * Event handler. Called when the vertical scroll bar moved. + * + * @param evt {Map} the event. + */ +qx.Proto._onScrollY = function(evt) { + this._postponedUpdateContent(); + this.setScrollY(evt.getData()); +} + + +/** + * Event handler. Called when the user moved the mouse wheel. + * + * @param evt {Map} the event. + */ +qx.Proto._onmousewheel = function(evt) { + this._verScrollBar.setValue(this._verScrollBar.getValue() + - evt.getWheelDelta() * this.getTable().getRowHeight()); + + // Update the focus + if (this._lastMousePageX && this.getFocusCellOnMouseMove()) { + this._focusCellAtPagePos(this._lastMousePageX, this._lastMousePageY); + } +} + + +/** + * Event handler. Called when the user moved the mouse. + * + * @param evt {Map} the event. + */ +qx.Proto._onmousemove = function(evt) { + var tableModel = this.getTable().getTableModel(); + var columnModel = this.getTable().getTableColumnModel(); + + var useResizeCursor = false; + var mouseOverColumn = null; + + var pageX = evt.getPageX(); + var pageY = evt.getPageY(); + + // Workaround: In onmousewheel the event has wrong coordinates for pageX + // and pageY. So we remember the last move event. + this._lastMousePageX = pageX; + this._lastMousePageY = pageY; + + if (this._resizeColumn != null) { + // We are currently resizing -> Update the position + var minColumnWidth = qx.ui.table.TablePaneScroller.MIN_COLUMN_WIDTH; + var newWidth = Math.max(minColumnWidth, this._lastResizeWidth + pageX - this._lastResizeMousePageX); + + if (this.getLiveResize()) { + columnModel.setColumnWidth(this._resizeColumn, newWidth); + } else { + this._header.setColumnWidth(this._resizeColumn, newWidth); + + var paneModel = this.getTablePaneModel(); + this._showResizeLine(paneModel.getColumnLeft(this._resizeColumn) + newWidth); + } + + useResizeCursor = true; + this._lastResizeMousePageX += newWidth - this._lastResizeWidth; + this._lastResizeWidth = newWidth; + } else if (this._moveColumn != null) { + // We are moving a column + + // Check whether we moved outside the click tolerance so we can start + // showing the column move feedback + // (showing the column move feedback prevents the onclick event) + var clickTolerance = qx.ui.table.TablePaneScroller.CLICK_TOLERANCE; + if (this._header.isShowingColumnMoveFeedback() + || pageX > this._lastMoveMousePageX + clickTolerance + || pageX < this._lastMoveMousePageX - clickTolerance) + { + this._lastMoveColPos += pageX - this._lastMoveMousePageX; + + this._header.showColumnMoveFeedback(this._moveColumn, this._lastMoveColPos); + + // Get the responsible scroller + var targetScroller = this._table.getTablePaneScrollerAtPageX(pageX); + if (this._lastMoveTargetScroller && this._lastMoveTargetScroller != targetScroller) { + this._lastMoveTargetScroller.hideColumnMoveFeedback(); + } + if (targetScroller != null) { + this._lastMoveTargetX = targetScroller.showColumnMoveFeedback(pageX); + } else { + this._lastMoveTargetX = null; + } + + this._lastMoveTargetScroller = targetScroller; + this._lastMoveMousePageX = pageX; + } + } else { + // This is a normal mouse move + var row = this._getRowForPagePos(pageX, pageY); + if (row == -1) { + // The mouse is over the header + var resizeCol = this._getResizeColumnForPageX(pageX); + if (resizeCol != -1) { + // The mouse is over a resize region -> Show the right cursor + useResizeCursor = true; + } else { + var col = this._getColumnForPageX(pageX); + if (col != null && tableModel.isColumnSortable(col)) { + mouseOverColumn = col; + } + } + } else if (row != null) { + // The mouse is over the data -> update the focus + if (this.getFocusCellOnMouseMove()) { + this._focusCellAtPagePos(pageX, pageY); + } + } + } + + // Workaround: Setting the cursor to the right widget doesn't work + //this._header.setCursor(useResizeCursor ? "e-resize" : null); + this.getTopLevelWidget().setGlobalCursor(useResizeCursor ? qx.ui.table.TablePaneScroller.CURSOR_RESIZE_HORIZONTAL : null); + + this._header.setMouseOverColumn(mouseOverColumn); +} + + +/** + * Event handler. Called when the user pressed a mouse button. + * + * @param evt {Map} the event. + */ +qx.Proto._onmousedown = function(evt) { + var tableModel = this.getTable().getTableModel(); + var columnModel = this.getTable().getTableColumnModel(); + + var pageX = evt.getPageX(); + var pageY = evt.getPageY(); + var row = this._getRowForPagePos(pageX, pageY); + if (row == -1) { + // mouse is in header + var resizeCol = this._getResizeColumnForPageX(pageX); + if (resizeCol != -1) { + // The mouse is over a resize region -> Start resizing + this._resizeColumn = resizeCol; + this._lastResizeMousePageX = pageX; + this._lastResizeWidth = columnModel.getColumnWidth(this._resizeColumn); + this.setCapture(true); + } else { + // The mouse is not in a resize region + var col = this._getColumnForPageX(pageX); + if (col != null) { + // Prepare column moving + this._moveColumn = col; + this._lastMoveMousePageX = pageX; + this._lastMoveColPos = this.getTablePaneModel().getColumnLeft(col); + this.setCapture(true); + } + } + } else if (row != null) { + // The mouse is over the data -> update the focus + if (! this.getFocusCellOnMouseMove()) { + this._focusCellAtPagePos(pageX, pageY); + } + + this.getTable()._getSelectionManager().handleMouseDown(row, evt); + } +} + + +/** + * Event handler. Called when the user released a mouse button. + * + * @param evt {Map} the event. + */ +qx.Proto._onmouseup = function(evt) { + var columnModel = this.getTable().getTableColumnModel(); + var paneModel = this.getTablePaneModel(); + + if (this._resizeColumn != null) { + // We are currently resizing -> Finish resizing + if (! this.getLiveResize()) { + this._hideResizeLine(); + columnModel.setColumnWidth(this._resizeColumn, this._lastResizeWidth); + } + + this._resizeColumn = null; + this.setCapture(false); + + this.getTopLevelWidget().setGlobalCursor(null); + } else if (this._moveColumn != null) { + // We are moving a column -> Drop the column + this._header.hideColumnMoveFeedback(); + if (this._lastMoveTargetScroller) { + this._lastMoveTargetScroller.hideColumnMoveFeedback(); + } + + if (this._lastMoveTargetX != null) { + var fromVisXPos = paneModel.getFirstColumnX() + paneModel.getX(this._moveColumn); + var toVisXPos = this._lastMoveTargetX; + if (toVisXPos != fromVisXPos && toVisXPos != fromVisXPos + 1) { + // The column was really moved to another position + // (and not moved before or after itself, which is a noop) + + // Translate visible positions to overall positions + var fromCol = columnModel.getVisibleColumnAtX(fromVisXPos); + var toCol = columnModel.getVisibleColumnAtX(toVisXPos); + var fromOverXPos = columnModel.getOverallX(fromCol); + var toOverXPos = (toCol != null) ? columnModel.getOverallX(toCol) : columnModel.getOverallColumnCount(); + + if (toOverXPos > fromOverXPos) { + // Don't count the column itself + toOverXPos--; + } + + // Move the column + columnModel.moveColumn(fromOverXPos, toOverXPos); + } + } + + this._moveColumn = null; + this._lastMoveTargetX = null; + this.setCapture(false); + } else { + // This is a normal mouse up + var row = this._getRowForPagePos(evt.getPageX(), evt.getPageY()); + if (row != -1 && row != null) { + this.getTable()._getSelectionManager().handleMouseUp(row, evt); + } + } +} + + +/** + * Event handler. Called when the user clicked a mouse button. + * + * @param evt {Map} the event. + */ +qx.Proto._onclick = function(evt) { + var tableModel = this.getTable().getTableModel(); + + var pageX = evt.getPageX(); + var pageY = evt.getPageY(); + var row = this._getRowForPagePos(pageX, pageY); + if (row == -1) { + // mouse is in header + var resizeCol = this._getResizeColumnForPageX(pageX); + if (resizeCol == -1) { + // mouse is not in a resize region + var col = this._getColumnForPageX(pageX); + if (col != null && tableModel.isColumnSortable(col)) { + // Sort that column + var sortCol = tableModel.getSortColumnIndex(); + var ascending = (col != sortCol) ? true : !tableModel.isSortAscending(); + + tableModel.sortByColumn(col, ascending); + this.getTable().getSelectionModel().clearSelection(); + } + } + } else if (row != null) { + this.getTable()._getSelectionManager().handleClick(row, evt); + } +} + + +/** + * Event handler. Called when the user double clicked a mouse button. + * + * @param evt {Map} the event. + */ +qx.Proto._ondblclick = function(evt) { + if (! this.isEditing()) { + this._focusCellAtPagePos(evt.getPageX(), evt.getPageY()); + this.startEditing(); + } +} + + +/** + * Event handler. Called when the mouse moved out. + * + * @param evt {Map} the event. + */ +qx.Proto._onmouseout = function(evt) { + /* + // Workaround: See _onmousemove + this._lastMousePageX = null; + this._lastMousePageY = null; + */ + + // Reset the resize cursor when the mouse leaves the header + // If currently a column is resized then do nothing + // (the cursor will be reset on mouseup) + if (this._resizeColumn == null) { + this.getTopLevelWidget().setGlobalCursor(null); + } + + this._header.setMouseOverColumn(null); +} + + +/** + * Shows the resize line. + * + * @param x {int} the position where to show the line (in pixels, relative to + * the left side of the pane). + */ +qx.Proto._showResizeLine = function(x) { + var resizeLine = this._resizeLine; + if (resizeLine == null) { + resizeLine = new qx.ui.basic.Terminator; + resizeLine.setBackgroundColor("#D6D5D9"); + resizeLine.setWidth(3); + this._paneClipper.add(resizeLine); + qx.ui.core.Widget.flushGlobalQueues(); + + this._resizeLine = resizeLine; + } + + resizeLine._applyRuntimeLeft(x - 2); // -1 for the width + resizeLine._applyRuntimeHeight(this._paneClipper.getBoxHeight() + this._paneClipper.getScrollTop()); + + this._resizeLine.removeStyleProperty("visibility"); +} + + +/** + * Hides the resize line. + */ +qx.Proto._hideResizeLine = function() { + this._resizeLine.setStyleProperty("visibility", "hidden"); +} + + +/** + * Shows the feedback shown while a column is moved by the user. + * + * @param pageX {int} the x position of the mouse in the page (in pixels). + * @return {int} the visible x position of the column in the whole table. + */ +qx.Proto.showColumnMoveFeedback = function(pageX) { + var paneModel = this.getTablePaneModel(); + var columnModel = this.getTable().getTableColumnModel(); + var paneLeftX = qx.dom.Location.getClientBoxLeft(this._tablePane.getElement()); + var colCount = paneModel.getColumnCount(); + + var targetXPos = 0; + var targetX = 0; + var currX = paneLeftX; + for (var xPos = 0; xPos < colCount; xPos++) { + var col = paneModel.getColumnAtX(xPos); + var colWidth = columnModel.getColumnWidth(col); + + if (pageX < currX + colWidth / 2) { + break; + } + + currX += colWidth; + targetXPos = xPos + 1; + targetX = currX - paneLeftX; + } + + // Ensure targetX is visible + var clipperLeftX = qx.dom.Location.getClientBoxLeft(this._paneClipper.getElement()); + var clipperWidth = this._paneClipper.getBoxWidth(); + var scrollX = clipperLeftX - paneLeftX; + // NOTE: +2/-1 because of feedback width + targetX = qx.lang.Number.limit(targetX, scrollX + 2, scrollX + clipperWidth - 1); + + this._showResizeLine(targetX); + + // Return the overall target x position + return paneModel.getFirstColumnX() + targetXPos; +} + + +/** + * Hides the feedback shown while a column is moved by the user. + */ +qx.Proto.hideColumnMoveFeedback = function() { + this._hideResizeLine(); +} + + +/** + * Sets the focus to the cell that's located at the page position + * pageX/pageY. If there is no cell at that position, + * nothing happens. + * + * @param pageX {int} the x position in the page (in pixels). + * @param pageY {int} the y position in the page (in pixels). + */ +qx.Proto._focusCellAtPagePos = function(pageX, pageY) { + var row = this._getRowForPagePos(pageX, pageY); + if (row != -1 && row != null) { + // The mouse is over the data -> update the focus + var col = this._getColumnForPageX(pageX); + if (col != null) { + this._table.setFocusedCell(col, row); + } + } +} + + +/** + * Sets the currently focused cell. + * + * @param col {int} the model index of the focused cell's column. + * @param row {int} the model index of the focused cell's row. + */ +qx.Proto.setFocusedCell = function(col, row) { + if (!this.isEditing()) { + this._tablePane.setFocusedCell(col, row, this._updateContentPlanned); + + this._focusedCol = col; + this._focusedRow = row; + + // Move the focus indicator + if (! this._updateContentPlanned) { + this._updateFocusIndicator(); + } + } +} + + +/** + * Returns the column of currently focused cell. + * + * @return {int} the model index of the focused cell's column. + */ +qx.Proto.getFocusedColumn = function() { + return this._focusedCol; +}; + + +/** + * Returns the row of currently focused cell. + * + * @return {int} the model index of the focused cell's column. + */ +qx.Proto.getFocusedRow = function() { + return this._focusedRow; +}; + + +/** + * Scrolls a cell visible. + * + * @param col {int} the model index of the column the cell belongs to. + * @param row {int} the model index of the row the cell belongs to. + */ +qx.Proto.scrollCellVisible = function(col, row) { + var paneModel = this.getTablePaneModel(); + var xPos = paneModel.getX(col); + + if (xPos != -1) { + var columnModel = this.getTable().getTableColumnModel(); + + var colLeft = paneModel.getColumnLeft(col); + var colWidth = columnModel.getColumnWidth(col); + var rowHeight = this.getTable().getRowHeight(); + var rowTop = row * rowHeight; + + var scrollX = this.getScrollX(); + var scrollY = this.getScrollY(); + var viewWidth = this._paneClipper.getBoxWidth(); + var viewHeight = this._paneClipper.getBoxHeight(); + + // NOTE: We don't use qx.lang.Number.limit, because min should win if max < min + var minScrollX = Math.min(colLeft, colLeft + colWidth - viewWidth); + var maxScrollX = colLeft; + this.setScrollX(Math.max(minScrollX, Math.min(maxScrollX, scrollX))); + + var minScrollY = rowTop + rowHeight - viewHeight; + if (this.getTable().getKeepFirstVisibleRowComplete()) { + minScrollY += rowHeight - 1; + } + var maxScrollY = rowTop; + this.setScrollY(Math.max(minScrollY, Math.min(maxScrollY, scrollY))); + } +} + + +/** + * Returns whether currently a cell is editing. + * + * @return whether currently a cell is editing. + */ +qx.Proto.isEditing = function() { + return this._cellEditor != null; +} + + +/** + * Starts editing the currently focused cell. Does nothing if already editing + * or if the column is not editable. + * + * @return {boolean} whether editing was started + */ +qx.Proto.startEditing = function() { + var tableModel = this.getTable().getTableModel(); + var col = this._focusedCol; + + if (!this.isEditing() && (col != null) && tableModel.isColumnEditable(col)) { + var row = this._focusedRow; + var xPos = this.getTablePaneModel().getX(col); + var value = tableModel.getValue(col, row); + + this._cellEditorFactory = this.getTable().getTableColumnModel().getCellEditorFactory(col); + var cellInfo = { col:col, row:row, xPos:xPos, value:value } + this._cellEditor = this._cellEditorFactory.createCellEditor(cellInfo); + this._cellEditor.set({ width:"100%", height:"100%" }); + + this._focusIndicator.add(this._cellEditor); + this._focusIndicator.addState("editing"); + + this._cellEditor.addEventListener("changeFocused", this._onCellEditorFocusChanged, this); + + // Workaround: Calling focus() directly has no effect + var editor = this._cellEditor; + window.setTimeout(function() { + editor.focus(); + }, 0); + + return true; + } + + return false; +} + + +/** + * Stops editing and writes the editor's value to the model. + */ +qx.Proto.stopEditing = function() { + this.flushEditor(); + this.cancelEditing(); +} + + +/** + * Writes the editor's value to the model. + */ +qx.Proto.flushEditor = function() { + if (this.isEditing()) { + var value = this._cellEditorFactory.getCellEditorValue(this._cellEditor); + this.getTable().getTableModel().setValue(this._focusedCol, this._focusedRow, value); + + this._table.focus(); + } +} + + +/** + * Stops editing without writing the editor's value to the model. + */ +qx.Proto.cancelEditing = function() { + if (this.isEditing()) { + this._focusIndicator.remove(this._cellEditor); + this._focusIndicator.removeState("editing"); + this._cellEditor.dispose(); + + this._cellEditor.removeEventListener("changeFocused", this._onCellEditorFocusChanged, this); + this._cellEditor = null; + this._cellEditorFactory = null; + } +} + + +/** + * Event handler. Called when the focused state of the cell editor changed. + * + * @param evt {Map} the event. + */ +qx.Proto._onCellEditorFocusChanged = function(evt) { + if (!this._cellEditor.getFocused()) { + this.stopEditing(); + } +} + + +/** + * Returns the model index of the column the mouse is over or null if the mouse + * is not over a column. + * + * @param pageX {int} the x position of the mouse in the page (in pixels). + * @return {int} the model index of the column the mouse is over. + */ +qx.Proto._getColumnForPageX = function(pageX) { + var headerLeftX = qx.dom.Location.getClientBoxLeft(this._header.getElement()); + + var columnModel = this.getTable().getTableColumnModel(); + var paneModel = this.getTablePaneModel(); + var colCount = paneModel.getColumnCount(); + var currX = headerLeftX; + for (var x = 0; x < colCount; x++) { + var col = paneModel.getColumnAtX(x); + var colWidth = columnModel.getColumnWidth(col); + currX += colWidth; + + if (pageX < currX) { + return col; + } + } + + return null; +} + + +/** + * Returns the model index of the column that should be resized when dragging + * starts here. Returns -1 if the mouse is in no resize region of any column. + * + * @param pageX {int} the x position of the mouse in the page (in pixels). + * @return {int} the column index. + */ +qx.Proto._getResizeColumnForPageX = function(pageX) { + var headerLeftX = qx.dom.Location.getClientBoxLeft(this._header.getElement()); + + var columnModel = this.getTable().getTableColumnModel(); + var paneModel = this.getTablePaneModel(); + var colCount = paneModel.getColumnCount(); + var currX = headerLeftX; + var regionRadius = qx.ui.table.TablePaneScroller.RESIZE_REGION_RADIUS; + for (var x = 0; x < colCount; x++) { + var col = paneModel.getColumnAtX(x); + var colWidth = columnModel.getColumnWidth(col); + currX += colWidth; + + if (pageX >= (currX - regionRadius) && pageX <= (currX + regionRadius)) { + return col; + } + } + + return -1; +} + + +/** + * Returns the model index of the row the mouse is currently over. Returns -1 if + * the mouse is over the header. Returns null if the mouse is not over any + * column. + * + * @param pageX {int} the mouse x position in the page. + * @param pageY {int} the mouse y position in the page. + * @return {int} the model index of the row the mouse is currently over. + */ +qx.Proto._getRowForPagePos = function(pageX, pageY) { + var paneClipperElem = this._paneClipper.getElement(); + var paneClipperLeftX = qx.dom.Location.getClientBoxLeft(paneClipperElem); + var paneClipperRightX = qx.dom.Location.getClientBoxRight(paneClipperElem); + if (pageX < paneClipperLeftX || pageX > paneClipperRightX) { + // There was no cell or header cell hit + return null; + } + + var paneClipperTopY = qx.dom.Location.getClientBoxTop(paneClipperElem); + var paneClipperBottomY = qx.dom.Location.getClientBoxBottom(paneClipperElem); + if (pageY >= paneClipperTopY && pageY <= paneClipperBottomY) { + // This event is in the pane -> Get the row + var rowHeight = this.getTable().getRowHeight(); + + var scrollY = this._verScrollBar.getValue(); + if (this.getTable().getKeepFirstVisibleRowComplete()) { + scrollY = Math.floor(scrollY / rowHeight) * rowHeight; + } + + var tableY = scrollY + pageY - paneClipperTopY; + var row = Math.floor(tableY / rowHeight); + + var rowCount = this.getTable().getTableModel().getRowCount(); + return (row < rowCount) ? row : null; + } + + var headerElem = this._headerClipper.getElement(); + if (pageY >= qx.dom.Location.getClientBoxTop(headerElem) + && pageY <= qx.dom.Location.getClientBoxBottom(headerElem) + && pageX <= qx.dom.Location.getClientBoxRight(headerElem)) + { + // This event is in the pane -> Return -1 for the header + return -1; + } + + return null; +} + + +/** + * Sets the widget that should be shown in the top right corner. + *

+ * The widget will not be disposed, when this table scroller is disposed. So the + * caller has to dispose it. + * + * @param widget {qx.ui.core.Widget} The widget to set. May be null. + */ +qx.Proto.setTopRightWidget = function(widget) { + var oldWidget = this._topRightWidget; + if (oldWidget != null) { + this._top.remove(oldWidget); + } + + if (widget != null) { + this._top.remove(this._spacer); + this._top.add(widget); + } else if (oldWidget != null) { + this._top.add(this._spacer); + } + + this._topRightWidget = widget; +} + + +/** + * Returns the header. + * + * @return {TablePaneHeader} the header. + */ +qx.Proto.getHeader = function() { + return this._header; +} + + +/** + * Returns the table pane. + * + * @return {TablePane} the table pane. + */ +qx.Proto.getTablePane = function() { + return this._tablePane; +} + + +/** + * Returns which scrollbars are needed. + * + * @param forceHorizontal {boolean ? false} Whether to show the horizontal + * scrollbar always. + * @param preventVertical {boolean ? false} Whether tp show the vertical scrollbar + * never. + * @return {int} which scrollbars are needed. This may be any combination of + * {@link #HORIZONTAL_SCROLLBAR} or {@link #VERTICAL_SCROLLBAR} + * (combined by OR). + */ +qx.Proto.getNeededScrollBars = function(forceHorizontal, preventVertical) { + var barWidth = this._verScrollBar.getPreferredBoxWidth(); + + // Get the width and height of the view (without scroll bars) + var viewWidth = this._paneClipper.getInnerWidth(); + if (this.getVerticalScrollBarVisible()) { + viewWidth += barWidth; + } + var viewHeight = this._paneClipper.getInnerHeight(); + if (this.getHorizontalScrollBarVisible()) { + viewHeight += barWidth; + } + + // Get the (virtual) width and height of the pane + var paneWidth = this.getTablePaneModel().getTotalWidth(); + var paneHeight = this.getTable().getRowHeight() * this.getTable().getTableModel().getRowCount(); + + // Check which scrollbars are needed + var horNeeded = false; + var verNeeded = false; + if (paneWidth > viewWidth) { + horNeeded = true; + if (paneHeight > viewHeight - barWidth) { + verNeeded = true; + } + } else if (paneHeight > viewHeight) { + verNeeded = true; + if (!preventVertical && (paneWidth > viewWidth - barWidth)) { + horNeeded = true; + } + } + + // Create the mask + var horBar = qx.ui.table.TablePaneScroller.HORIZONTAL_SCROLLBAR; + var verBar = qx.ui.table.TablePaneScroller.VERTICAL_SCROLLBAR; + return ((forceHorizontal || horNeeded) ? horBar : 0) + | ((preventVertical || !verNeeded) ? 0 : verBar); +} + + +/** + * Does a postponed update of the content. + * + * @see #_updateContent + */ +qx.Proto._postponedUpdateContent = function() { + if (! this._updateContentPlanned) { + var self = this; + window.setTimeout(function() { + self._updateContent(); + self._updateContentPlanned = false; + qx.ui.core.Widget.flushGlobalQueues(); + }, 0); + this._updateContentPlanned = true; + } +} + + +/** + * Updates the content. Sets the right section the table pane should show and + * does the scrolling. + */ +qx.Proto._updateContent = function() { + var paneHeight = this._paneClipper.getInnerHeight(); + var scrollX = this._horScrollBar.getValue(); + var scrollY = this._verScrollBar.getValue(); + var rowHeight = this.getTable().getRowHeight(); + + var firstRow = Math.floor(scrollY / rowHeight); + var oldFirstRow = this._tablePane.getFirstVisibleRow(); + this._tablePane.setFirstVisibleRow(firstRow); + + var rowCount = Math.ceil(paneHeight / rowHeight); + var paneOffset = 0; + if (! this.getTable().getKeepFirstVisibleRowComplete()) { + // NOTE: We don't consider paneOffset, because this may cause alternating + // adding and deleting of one row when scolling. Instead we add one row + // in every case. + rowCount++; + paneOffset = scrollY % rowHeight; + } + this._tablePane.setVisibleRowCount(rowCount); + + if (firstRow != oldFirstRow) { + this._updateFocusIndicator(); + } + + // Workaround: We can't use scrollLeft for the header because IE + // automatically scrolls the header back, when a column is + // resized. + this._header.setLeft(-scrollX); + this._paneClipper.setScrollLeft(scrollX); + this._paneClipper.setScrollTop(paneOffset); + + //this.debug("paneHeight:"+paneHeight+",rowHeight:"+rowHeight+",firstRow:"+firstRow+",rowCount:"+rowCount+",paneOffset:"+paneOffset); +} + + +/** + * Updates the location and the visibility of the focus indicator. + */ +qx.Proto._updateFocusIndicator = function() { + if (this._focusedCol == null) { + this._focusIndicator.hide(); + } else { + var xPos = this.getTablePaneModel().getX(this._focusedCol); + if (xPos == -1) { + this._focusIndicator.hide(); + } else { + var columnModel = this.getTable().getTableColumnModel(); + var paneModel = this.getTablePaneModel(); + + var firstRow = this._tablePane.getFirstVisibleRow(); + var rowHeight = this.getTable().getRowHeight(); + + this._focusIndicator.setHeight(rowHeight + 3); + this._focusIndicator.setWidth(columnModel.getColumnWidth(this._focusedCol) + 3); + this._focusIndicator.setTop((this._focusedRow - firstRow) * rowHeight - 2); + this._focusIndicator.setLeft(paneModel.getColumnLeft(this._focusedCol) - 2); + + this._focusIndicator.show(); + } + } +} + + +// overridden +qx.Proto.dispose = function() { + if (this.getDisposed()) { + return true; + } + + if (this.getElement() != null) { + this.getElement().onselectstart = null; + } + + this._verScrollBar.dispose(); + this._horScrollBar.dispose(); + this._header.dispose(); + this._headerClipper.dispose(); + this._spacer.dispose(); + this._top.dispose(); + this._tablePane.dispose(); + this._paneClipper.dispose(); + + if (this._resizeLine != null) { + this._resizeLine.dispose(); + } + + this.removeEventListener("mousemove", this._onmousemove, this); + this.removeEventListener("mousedown", this._onmousedown, this); + this.removeEventListener("mouseup", this._onmouseup, this); + this.removeEventListener("click", this._onclick, this); + this.removeEventListener("dblclick", this._ondblclick, this); + this.removeEventListener("mouseout", this._onmouseout, this); + + var tablePaneModel = this.getTablePaneModel(); + if (tablePaneModel != null) { + tablePaneModel.removeEventListener("modelChanged", this._onPaneModelChanged, this); + } + + return qx.ui.layout.VerticalBoxLayout.prototype.dispose.call(this); +} + + +/** {int} The minimum width a colum could get in pixels. */ +qx.Class.MIN_COLUMN_WIDTH = 10; + +/** {int} The radius of the resize region in pixels. */ +qx.Class.RESIZE_REGION_RADIUS = 5; + +/** + * (int) The number of pixels the mouse may move between mouse down and mouse up + * in order to count as a click. + */ +qx.Class.CLICK_TOLERANCE = 5; + +/** + * (int) The mask for the horizontal scroll bar. + * May be combined with {@link #VERTICAL_SCROLLBAR}. + * + * @see #getNeededScrollBars + */ +qx.Class.HORIZONTAL_SCROLLBAR = 1; + +/** + * (int) The mask for the vertical scroll bar. + * May be combined with {@link #HORIZONTAL_SCROLLBAR}. + * + * @see #getNeededScrollBars + */ +qx.Class.VERTICAL_SCROLLBAR = 2; + +/** + * (string) The correct value for the CSS style attribute "cursor" for the + * horizontal resize cursor. + */ +qx.Class.CURSOR_RESIZE_HORIZONTAL = (qx.sys.Client.getInstance().isGecko() && (qx.sys.Client.getInstance().getMajor() > 1 || qx.sys.Client.getInstance().getMinor() >= 8)) ? "ew-resize" : "e-resize"; diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/TextFieldCellEditorFactory.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/TextFieldCellEditorFactory.js new file mode 100644 index 0000000000..6878ce7470 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/table/TextFieldCellEditorFactory.js @@ -0,0 +1,58 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2006 by STZ-IDA, Germany, http://www.stz-ida.de + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Til Schneider (til132) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_table) + +************************************************************************ */ + +/** + * A cell editor factory creating text fields. + */ +qx.OO.defineClass("qx.ui.table.TextFieldCellEditorFactory", qx.ui.table.CellEditorFactory, +function() { + qx.ui.table.CellEditorFactory.call(this); +}); + + +// overridden +qx.Proto.createCellEditor = function(cellInfo) { + var cellEditor = new qx.ui.form.TextField; + cellEditor.setAppearance("table-editor-textfield"); + cellEditor.originalValue = cellInfo.value; + cellEditor.setValue("" + cellInfo.value); + + cellEditor.addEventListener("appear", function() { + this.selectAll(); + }); + + return cellEditor; +} + + +// overridden +qx.Proto.getCellEditorValue = function(cellEditor) { + // Workaround: qx.ui.form.TextField.getValue() delivers the old value, so we use the + // value property of the DOM element directly + var value = cellEditor.getElement().value; + + if (typeof cellEditor.originalValue == "number") { + value = parseFloat(value); + } + return value; +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/toolbar/Button.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/toolbar/Button.js new file mode 100644 index 0000000000..a231960872 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/toolbar/Button.js @@ -0,0 +1,47 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_toolbar) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.toolbar.Button", qx.ui.form.Button, +function(vText, vIcon, vIconWidth, vIconHeight, vFlash) +{ + qx.ui.form.Button.call(this, vText, vIcon, vIconWidth, vIconHeight, vFlash); + + // Omit focus + this.setTabIndex(-1); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "toolbar-button" }); + + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onkeydown = qx.util.Return.returnTrue; +qx.Proto._onkeyup = qx.util.Return.returnTrue; diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/toolbar/CheckBox.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/toolbar/CheckBox.js new file mode 100644 index 0000000000..781a8bc794 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/toolbar/CheckBox.js @@ -0,0 +1,86 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_toolbar) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.toolbar.CheckBox", qx.ui.toolbar.Button, +function(vText, vIcon, vChecked) +{ + qx.ui.toolbar.Button.call(this, vText, vIcon); + + if (qx.util.Validation.isValid(vChecked)) { + this.setChecked(vChecked); + } +}); + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.addProperty({ name : "checked", type : "boolean", defaultValue : false, getAlias:"isChecked" }); + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyChecked = function(propValue, propOldValue, propData) +{ + propValue ? this.addState("checked") : this.removeState("checked"); + return true; +} + + + + + +/* +--------------------------------------------------------------------------- + EVENTS +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmouseup = function(e) +{ + this.setCapture(false); + + if (!this.hasState("abandoned")) + { + this.addState("over"); + this.setChecked(!this.getChecked()); + this.execute(); + } + + this.removeState("abandoned"); + this.removeState("pressed"); + + e.stopPropagation(); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/toolbar/MenuButton.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/toolbar/MenuButton.js new file mode 100644 index 0000000000..a06c26fdc1 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/toolbar/MenuButton.js @@ -0,0 +1,258 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_toolbar) +#module(ui_menu) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.toolbar.MenuButton", qx.ui.toolbar.Button, +function(vText, vMenu, vIcon, vIconWidth, vIconHeight, vFlash) +{ + qx.ui.toolbar.Button.call(this, vText, vIcon, vIconWidth, vIconHeight, vFlash); + + if (qx.util.Validation.isValidObject(vMenu)) { + this.setMenu(vMenu); + } + + /* + this._menuButton = new qx.ui.basic.Image("widget/arrows/down_small.gif"); + this._menuButton.setAnonymous(true); + this.addAtEnd(this._menuButton); + */ +}); + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.addProperty({ name : "menu", type : "object", instance : "qx.ui.menu.Menu" }); +qx.OO.addProperty({ name : "direction", type : "string", allowNull : false, possibleValues : [ "up", "down" ], defaultValue : "down" }); + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getParentToolBar = function() +{ + var vParent = this.getParent(); + + if (vParent instanceof qx.ui.toolbar.Part) { + vParent = vParent.getParent(); + } + + return vParent instanceof qx.ui.toolbar.ToolBar ? vParent : null; +} + +qx.Proto._showMenu = function(vFromKeyEvent) +{ + var vMenu = this.getMenu(); + + if (vMenu) + { + // Caching common stuff + var vMenuParent = vMenu.getParent(); + var vMenuParentElement = vMenuParent.getElement(); + var vButtonElement = this.getElement(); + var vButtonHeight = qx.dom.Dimension.getBoxHeight(vButtonElement); + + // Apply X-Location + var vMenuParentLeft = qx.dom.Location.getPageBoxLeft(vMenuParentElement); + var vButtonLeft = qx.dom.Location.getPageBoxLeft(vButtonElement); + + vMenu.setLeft(vButtonLeft - vMenuParentLeft); + + // Apply Y-Location + switch(this.getDirection()) + { + case "up": + var vBodyHeight = qx.dom.Dimension.getInnerHeight(document.body); + var vMenuParentBottom = qx.dom.Location.getPageBoxBottom(vMenuParentElement); + var vButtonBottom = qx.dom.Location.getPageBoxBottom(vButtonElement); + + vMenu.setBottom(vButtonHeight + (vBodyHeight - vButtonBottom) - (vBodyHeight - vMenuParentBottom)); + vMenu.setTop(null); + break; + + case "down": + var vButtonTop = qx.dom.Location.getPageBoxTop(vButtonElement); + + vMenu.setTop(vButtonTop + vButtonHeight); + vMenu.setBottom(null); + break; + } + + this.addState("pressed"); + + // If this show is called from a key event occured, we want to highlight + // the first menubutton inside. + if (vFromKeyEvent) { + vMenu.setHoverItem(vMenu.getFirstActiveChild()); + } + + vMenu.show(); + } +} + +qx.Proto._hideMenu = function() +{ + var vMenu = this.getMenu(); + + if (vMenu) { + vMenu.hide(); + } +} + + + + + +/* +--------------------------------------------------------------------------- + MODIFIERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyMenu = function(propValue, propOldValue, propData) +{ + if (propOldValue) + { + propOldValue.setOpener(null); + + propOldValue.removeEventListener("appear", this._onmenuappear, this); + propOldValue.removeEventListener("disappear", this._onmenudisappear, this); + } + + if (propValue) + { + propValue.setOpener(this); + + propValue.addEventListener("appear", this._onmenuappear, this); + propValue.addEventListener("disappear", this._onmenudisappear, this); + } + + return true; +} + + + + + + +/* +--------------------------------------------------------------------------- + EVENTS: MOUSE +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmousedown = function(e) +{ + if (e.getTarget() != this || !e.isLeftButtonPressed()) { + return; + } + + this.hasState("pressed") ? this._hideMenu() : this._showMenu(); +} + +qx.Proto._onmouseup = function(e) {} + +qx.Proto._onmouseout = function(e) +{ + if (e.getTarget() != this) { + return; + } + + this.removeState("over"); +} + +qx.Proto._onmouseover = function(e) +{ + var vToolBar = this.getParentToolBar(); + + if (vToolBar) + { + var vMenu = this.getMenu(); + + switch(vToolBar.getOpenMenu()) + { + case null: + case vMenu: + break; + + default: + // hide other menus + qx.manager.object.MenuManager.getInstance().update(); + + // show this menu + this._showMenu(); + } + } + + return qx.ui.toolbar.Button.prototype._onmouseover.call(this, e); +} + + + + + + +/* +--------------------------------------------------------------------------- + EVENTS: MENU +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmenuappear = function(e) +{ + var vToolBar = this.getParentToolBar(); + + if (!vToolBar) { + return; + } + + var vMenu = this.getMenu(); + + vToolBar.setOpenMenu(vMenu); +} + +qx.Proto._onmenudisappear = function(e) +{ + var vToolBar = this.getParentToolBar(); + + if (!vToolBar) { + return; + } + + var vMenu = this.getMenu(); + + if (vToolBar.getOpenMenu() == vMenu) { + vToolBar.setOpenMenu(null); + } +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/toolbar/Part.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/toolbar/Part.js new file mode 100644 index 0000000000..292a9045c4 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/toolbar/Part.js @@ -0,0 +1,82 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_toolbar) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.toolbar.Part", qx.ui.layout.HorizontalBoxLayout, +function() +{ + qx.ui.layout.HorizontalBoxLayout.call(this); + + this._handle = new qx.ui.toolbar.PartHandle; + this.add(this._handle); +}); + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "toolbar-part" }); + + + + + +/* +--------------------------------------------------------------------------- + CLONE +--------------------------------------------------------------------------- +*/ + +// Omit recursive cloning of qx.ui.toolbar.PartHandle +qx.Proto._cloneRecursive = function(cloneInstance) +{ + var vChildren = this.getChildren(); + var vLength = vChildren.length; + + for (var i=0; i=0; i--) + { + vCurrent = vChildren[i]; + + if (vCurrent instanceof qx.ui.toolbar.MenuButton && vCurrent.getEnabled()) + { + vPrevButton = vCurrent; + break; + } + } + + // If none found, try again from the begin (looping) + if (!vPrevButton) + { + for (var i=vChildrenLength-1; i>vIndex; i--) + { + vCurrent = vChildren[i]; + + if (vCurrent instanceof qx.ui.toolbar.MenuButton && vCurrent.getEnabled()) + { + vPrevButton = vCurrent; + break; + } + } + } + + if (vPrevButton) + { + // hide other menus + qx.manager.object.MenuManager.getInstance().update(); + + // show previous menu + vPrevButton._showMenu(true); + } +} + +qx.Proto._onkeypress_right = function() +{ + var vMenu = this.getOpenMenu(); + if (!vMenu) { + return; + } + + var vOpener = vMenu.getOpener(); + if (!vOpener) { + return; + } + + var vChildren = this.getAllButtons(); + var vChildrenLength = vChildren.length; + var vIndex = vChildren.indexOf(vOpener); + var vCurrent; + var vNextButton = null; + + for (var i=vIndex+1; ideselects, disconnects, removes and disposes the + * current tree element and its content. + *

+ * + *

destroys the current item (TreeFile or TreeFolder) + * and all its subitems. The destruction of the subitems + * is done by calling destroyContent. This is done if the + * subitem has the method destroyContent which is true if the + * subitem is a TreeFolder (or one of its subclasses). + *

+ * + *

The method destroyContent is defined in the TreeFolder class. + *

+ */ +qx.Proto.destroy = function() { + var manager = this.getTree() ? this.getTree().getManager() : null; + if(manager) { + + // if the current destroyed item is + // selectd deselect the item. If we are + // in single selection mode we have to + // call deselectAll because setItemSelected + // refuses to deselect in this case + if(manager.getItemSelected(this)) { + if(manager.getMultiSelection()) { + manager.setItemSelected(this,false); + } + else { + manager.deselectAll(); + } + } + + // set the leadItem to null if the current + // destroyed item is the leadItem + if(manager.getLeadItem() == this) { + manager.setLeadItem(null); + } + // set the anchorItem to null if the current + // destroyed item is the anchorItem + if(manager.getAnchorItem() == this) { + manager.setAnchorItem(null); + } + } + + // if the item has the method destroyContent defined + // then it is a TreeFolder (and it's subclasses) + // which potentially have content which also + // has to be destroyed + if(this.destroyContent) { + this.destroyContent(); + } + + // first disconnect the item so rendering + // of the tree lines can be done correctly + this.disconnect(); + + // remove the current item from + // the parent folder + var parentFolder = this.getParentFolder(); + if(parentFolder) { + parentFolder.remove(this); + } + + this.dispose(); +} + + + + + +/* +--------------------------------------------------------------------------- + QUEUE HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto.addToTreeQueue = function() +{ + var vTree = this.getTree(); + if (vTree) { + vTree.addChildToTreeQueue(this); + } +} + +qx.Proto.removeFromTreeQueue = function() +{ + var vTree = this.getTree(); + if (vTree) { + vTree.removeChildFromTreeQueue(this); + } +} + +qx.Proto.addToCustomQueues = function(vHint) +{ + this.addToTreeQueue(); + + qx.ui.layout.BoxLayout.prototype.addToCustomQueues.call(this, vHint); +} + +qx.Proto.removeFromCustomQueues = function(vHint) +{ + this.removeFromTreeQueue(); + + qx.ui.layout.BoxLayout.prototype.removeFromCustomQueues.call(this, vHint); +} + + + + + + + + +/* +--------------------------------------------------------------------------- + DISPLAYBLE HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyParent = function(propValue, propOldValue, propData) +{ + qx.ui.layout.BoxLayout.prototype._modifyParent.call(this, propValue, propOldValue, propData); + + // Be sure to update previous folder also if it is closed currently (plus/minus symbol) + if (propOldValue && !propOldValue.isDisplayable() && propOldValue.getParent() && propOldValue.getParent().isDisplayable()) { + propOldValue.getParent().addToTreeQueue(); + } + + // Be sure to update new folder also if it is closed currently (plus/minus symbol) + if (propValue && !propValue.isDisplayable() && propValue.getParent() && propValue.getParent().isDisplayable()) { + propValue.getParent().addToTreeQueue(); + } + + return true; +} + +qx.Proto._handleDisplayableCustom = function(vDisplayable, vParent, vHint) +{ + qx.ui.layout.BoxLayout.prototype._handleDisplayableCustom.call(this, vDisplayable, vParent, vHint); + + if (vHint) + { + var vParentFolder = this.getParentFolder(); + var vPreviousParentFolder = this._previousParentFolder; + + if (vPreviousParentFolder) + { + if (this._wasLastVisibleChild) + { + vPreviousParentFolder._updateIndent(); + } + else if (!vPreviousParentFolder.hasContent()) + { + vPreviousParentFolder.addToTreeQueue(); + } + } + + if (vParentFolder && vParentFolder.isDisplayable() && vParentFolder._initialLayoutDone) { + vParentFolder.addToTreeQueue(); + } + + if (this.isLastVisibleChild()) + { + var vPrev = this.getPreviousVisibleSibling(); + + if (vPrev && vPrev instanceof qx.ui.tree.AbstractTreeElement) { + vPrev._updateIndent(); + } + } + + if (vDisplayable) { + this._updateIndent(); + } + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + EVENT LISTENERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmousedown = function(e) +{ + this.getTree().getManager().handleMouseDown(this, e); + e.stopPropagation(); +} + +qx.Proto._onmouseup = qx.util.Return.returnTrue; + + + + + +/* +--------------------------------------------------------------------------- + TREE FLUSH +--------------------------------------------------------------------------- +*/ + +qx.Proto.flushTree = function() +{ + // store informations for update process + this._previousParentFolder = this.getParentFolder(); + this._wasLastVisibleChild = this.isLastVisibleChild(); + + // generate html for indent area + var vLevel = this.getLevel(); + var vTree = this.getTree(); + var vImage; + var vHtml = []; + var vCurrentObject = this; + + for (var i=0; i"); + } + + vCurrentObject = vCurrentObject.getParentFolder(); + } + + this._indentObject.setHtml(vHtml.join("")); + this._indentObject.setWidth(vLevel * 19); +} + + + + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + if (this._indentObject) + { + this._indentObject.dispose(); + this._indentObject = null; + } + + if (this._iconObject) + { + this._iconObject.dispose(); + this._iconObject = null; + } + + if (this._labelObject) + { + this._labelObject.dispose(); + this._labelObject = null; + } + + this._previousParentFolder = null; + + this.removeEventListener("mousedown", this._onmousedown); + this.removeEventListener("mouseup", this._onmouseup); + + return qx.ui.layout.BoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/tree/Tree.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/tree/Tree.js new file mode 100644 index 0000000000..18affeccb4 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/tree/Tree.js @@ -0,0 +1,398 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_tree) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.tree.Tree", qx.ui.tree.TreeFolder, +function(vLabel, vIcon, vIconSelected) +{ + qx.ui.tree.TreeFolder.call(this, vLabel, vIcon, vIconSelected); + + // ************************************************************************ + // INITILISIZE MANAGER + // ************************************************************************ + this._manager = new qx.manager.selection.TreeSelectionManager(this); + + + this._iconObject.setAppearance("tree-icon"); + this._labelObject.setAppearance("tree-label"); + + + // ************************************************************************ + // DEFAULT STATE + // ************************************************************************ + // The tree should be open by default + this.setOpen(true); + + // Fix vertical alignment of empty tree + this.addToFolder(); + + + // ************************************************************************ + // KEY EVENT LISTENER + // ************************************************************************ + this.addEventListener("keydown", this._onkeydown); + this.addEventListener("keypress", this._onkeypress); + this.addEventListener("keyup", this._onkeyup); +}); + + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.addProperty({ name : "useDoubleClick", type : "boolean", defaultValue : false, getAlias : "useDoubleClick" }); +qx.OO.addProperty({ name : "useTreeLines", type : "boolean", defaultValue : true, getAlias : "useTreeLines" }); + + + + + + +/* +--------------------------------------------------------------------------- + MANAGER BINDING +--------------------------------------------------------------------------- +*/ + +qx.Proto.getManager = function() { + return this._manager; +} + +qx.Proto.getSelectedElement = function() { + return this.getManager().getSelectedItem(); +} + + + + + + +/* +--------------------------------------------------------------------------- + QUEUE HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto.addChildToTreeQueue = function(vChild) +{ + if (!vChild._isInTreeQueue && !vChild._isDisplayable) { + this.debug("Ignoring invisible child: " + vChild); + } + + if (!vChild._isInTreeQueue && vChild._isDisplayable) + { + qx.ui.core.Widget.addToGlobalWidgetQueue(this); + + if (!this._treeQueue) { + this._treeQueue = {}; + } + + this._treeQueue[vChild.toHashCode()] = vChild; + + vChild._isInTreeQueue = true; + } +} + +qx.Proto.removeChildFromTreeQueue = function(vChild) +{ + if (vChild._isInTreeQueue) + { + if (this._treeQueue) { + delete this._treeQueue[vChild.toHashCode()]; + } + + delete vChild._isInTreeQueue; + } +} + +qx.Proto.flushWidgetQueue = function() { + this.flushTreeQueue(); +} + +qx.Proto.flushTreeQueue = function() +{ + if (!qx.lang.Object.isEmpty(this._treeQueue)) + { + for (var vHashCode in this._treeQueue) + { + // this.debug("Flushing Tree Child: " + this._treeQueue[vHashCode]); + this._treeQueue[vHashCode].flushTree(); + delete this._treeQueue[vHashCode]._isInTreeQueue; + } + + delete this._treeQueue; + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyUseTreeLines = function(propValue, propOldValue, propData) +{ + if (this._initialLayoutDone) { + this._updateIndent(); + } + + return true; +} + + + + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getTree = function() { + return this; +} + +qx.Proto.getParentFolder = function() { + return null; +} + +qx.Proto.getLevel = function() { + return 0; +} + + + + + + + + +/* +--------------------------------------------------------------------------- + COMMON CHECKERS +--------------------------------------------------------------------------- +*/ + +qx.ui.tree.Tree.isTreeFolder = function(vObject) { + return vObject && vObject instanceof qx.ui.tree.TreeFolder && !(vObject instanceof qx.ui.tree.Tree); +}; + +qx.ui.tree.Tree.isOpenTreeFolder = function(vObject) { + return vObject instanceof qx.ui.tree.TreeFolder && vObject.getOpen() && vObject.hasContent(); +}; + + + + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onkeydown = function(e) +{ + var vSelectedItem = this.getManager().getSelectedItem(); + + if (e.getKeyIdentifier() == "Enter") { + e.preventDefault(); + + if (qx.ui.tree.Tree.isTreeFolder(vSelectedItem)) { + return vSelectedItem.toggle(); + } + } +}; + + +qx.Proto._onkeypress = function(e) +{ + var vManager = this.getManager(); + var vSelectedItem = vManager.getSelectedItem(); + + switch(e.getKeyIdentifier()) + { + case "Left": + e.preventDefault(); + + if (qx.ui.tree.Tree.isTreeFolder(vSelectedItem)) + { + if (!vSelectedItem.getOpen()) + { + var vParent = vSelectedItem.getParentFolder(); + if (vParent instanceof qx.ui.tree.TreeFolder) { + if (!(vParent instanceof qx.ui.tree.Tree)) { + vParent.close(); + } + + this.setSelectedElement(vParent); + } + } + else + { + return vSelectedItem.close(); + } + } + else if (vSelectedItem instanceof qx.ui.tree.TreeFile) + { + var vParent = vSelectedItem.getParentFolder(); + if (vParent instanceof qx.ui.tree.TreeFolder) { + if (!(vParent instanceof qx.ui.tree.Tree)) { + vParent.close(); + } + + this.setSelectedElement(vParent); + } + } + + break; + + case "Right": + e.preventDefault(); + + if (qx.ui.tree.Tree.isTreeFolder(vSelectedItem)) + { + if (!vSelectedItem.getOpen()) + { + return vSelectedItem.open(); + } + else if (vSelectedItem.hasContent()) + { + var vFirst = vSelectedItem.getFirstVisibleChildOfFolder(); + this.setSelectedElement(vFirst); + + if (vFirst instanceof qx.ui.tree.TreeFolder) { + vFirst.open(); + } + + return; + } + } + + break; + + default: + if (!this._fastUpdate) + { + this._fastUpdate = true; + this._oldItem = vSelectedItem; + } + + vManager.handleKeyPress(e); + } +}; + + +qx.Proto._onkeyup = function(e) +{ + if (this._fastUpdate) + { + var vOldItem = this._oldItem; + var vNewItem = this.getManager().getSelectedItem(); + + vNewItem.getIconObject().addState("selected"); + + delete this._fastUpdate; + delete this._oldItem; + } +}; + + +qx.Proto.getLastTreeChild = function() +{ + var vLast = this; + + while (vLast instanceof qx.ui.tree.AbstractTreeElement) + { + if (!(vLast instanceof qx.ui.tree.TreeFolder) || !vLast.getOpen()) { + return vLast; + } + + vLast = vLast.getLastVisibleChildOfFolder(); + } + + return null; +}; + + +qx.Proto.getFirstTreeChild = function() { + return this; +}; + + +qx.Proto.setSelectedElement = function(vElement) +{ + var vManager = this.getManager(); + + vManager.setSelectedItem(vElement); + vManager.setLeadItem(vElement); +}; + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + this.removeEventListener("keydown", this._onkeydown); + this.removeEventListener("keypress", this._onkeypress); + this.removeEventListener("keyup", this._onkeyup); + + if (this._manager) + { + this._manager.dispose(); + this._manager = null; + } + + delete this._oldItem; + + return qx.ui.tree.TreeFolder.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/tree/TreeFile.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/tree/TreeFile.js new file mode 100644 index 0000000000..8939b18e2d --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/tree/TreeFile.js @@ -0,0 +1,62 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_tree) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.tree.TreeFile", qx.ui.tree.AbstractTreeElement, +function(vLabel, vIcon, vIconSelected) { + qx.ui.tree.AbstractTreeElement.call(this, vLabel, vIcon, vIconSelected); +}); + + + + +/* +--------------------------------------------------------------------------- + INDENT HELPER +--------------------------------------------------------------------------- +*/ + +qx.Proto.getIndentSymbol = function(vUseTreeLines, vIsLastColumn) +{ + if (vUseTreeLines) + { + if (vIsLastColumn) + { + return this.isLastChild() ? "end" : "cross"; + } + else + { + return "line"; + } + } + + return null; +} + +qx.Proto._updateIndent = function() { + this.addToTreeQueue(); +} + +qx.Proto.getItems = function() { + return [this]; +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/tree/TreeFolder.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/tree/TreeFolder.js new file mode 100644 index 0000000000..3f660867f3 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/tree/TreeFolder.js @@ -0,0 +1,605 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_tree) + +************************************************************************ */ + +qx.OO.defineClass("qx.ui.tree.TreeFolder", qx.ui.tree.AbstractTreeElement, +function(vLabel, vIcon, vIconSelected) +{ + qx.ui.tree.AbstractTreeElement.call(this, vLabel, vIcon, vIconSelected); + + this._iconObject.setAppearance("tree-folder-icon"); + this._labelObject.setAppearance("tree-folder-label"); + + this.addEventListener("dblclick", this._ondblclick); + + // Remapping of add/remove methods + this.add = this.addToFolder; + this.addBefore = this.addBeforeToFolder; + this.addAfter = this.addAfterToFolder; + this.addAt = this.addAtToFolder; + this.addAtBegin = this.addAtBeginToFolder; + this.addAtEnd = this.addAtEndToFolder; + this.remove = this.removeFromFolder; +}); + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + + +qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "tree-folder" }); +qx.OO.changeProperty({ name : "icon", type : "string" }); +qx.OO.changeProperty({ name : "iconSelected", type : "string" }); + +qx.OO.addProperty({ name : "open", type : "boolean", defaultValue : false }); +qx.OO.addProperty({ name : "alwaysShowPlusMinusSymbol", type : "boolean", defaultValue : false }); + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.hasContent = function() { + return this._containerObject && this._containerObject.getChildrenLength() > 0; +} + +qx.Proto.open = function() +{ + if (this.getOpen()) { + return; + } + + if (this.hasContent() && this.isSeeable()) + { + this.getTopLevelWidget().setGlobalCursor("progress"); + qx.client.Timer.once(this._openCallback, this, 0); + } + else + { + this.setOpen(true); + } +} + +qx.Proto.close = function() { + this.setOpen(false); +} + +qx.Proto.toggle = function() { + this.getOpen() ? this.close() : this.open(); +} + +qx.Proto._openCallback = function() +{ + this.setOpen(true); + qx.ui.core.Widget.flushGlobalQueues(); + this.getTopLevelWidget().setGlobalCursor(null); +} + + + + + + + + +/* +--------------------------------------------------------------------------- + CHILDREN HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._createChildrenStructure = function() +{ + this.setAppearance(this instanceof qx.ui.tree.Tree ? "tree-container" : "tree-folder-container"); + + if (!this._horizontalLayout) + { + this.setOrientation("vertical"); + + this._horizontalLayout = new qx.ui.layout.HorizontalBoxLayout; + this._horizontalLayout.setWidth(null); + this._horizontalLayout.setParent(this); + this._horizontalLayout.setAnonymous(true); + this._horizontalLayout.setAppearance(this instanceof qx.ui.tree.Tree ? "tree" : "tree-folder"); + + this._indentObject.setParent(this._horizontalLayout); + this._iconObject.setParent(this._horizontalLayout); + this._labelObject.setParent(this._horizontalLayout); + } + + if (!this._containerObject) + { + this._containerObject = new qx.ui.layout.VerticalBoxLayout; + this._containerObject.setWidth(null); + this._containerObject.setAnonymous(true); + + // it should be faster to first handle display, + // because the default display value is true and if we first + // setup the parent the logic do all to make the + // widget first visible and then, if the folder is not + // opened again invisible. + this._containerObject.setDisplay(this.getOpen()); + this._containerObject.setParent(this); + + // remap remove* functions + this.remapChildrenHandlingTo(this._containerObject); + } +} + +qx.Proto._handleChildMove = function(vChild, vRelationIndex, vRelationChild) +{ + if (vChild.isDisplayable()) + { + var vChildren = this._containerObject.getChildren(); + var vOldChildIndex = vChildren.indexOf(vChild); + + if (vOldChildIndex != -1) + { + if (vRelationChild) { + vRelationIndex = vChildren.indexOf(vRelationChild); + } + + if (vRelationIndex == vChildren.length-1) + { + vChild._updateIndent(); + + // Update indent of previous last child + this._containerObject.getLastVisibleChild()._updateIndent(); + } + else if (vChild._wasLastVisibleChild) + { + vChild._updateIndent(); + + // Update indent for new last child + var vPreviousSibling = vChild.getPreviousVisibleSibling(); + if (vPreviousSibling) { + vPreviousSibling._updateIndent(); + } + } + } + } +} + +qx.Proto.addToFolder = function() +{ + this._createChildrenStructure(); + + if (this._containerObject) { + return this._containerObject.add.apply(this._containerObject, arguments); + } +} + +qx.Proto.addBeforeToFolder = function(vChild, vBefore) +{ + this._createChildrenStructure(); + + if (this._containerObject) + { + this._handleChildMove(vChild, null, vBefore); + return this._containerObject.addBefore.apply(this._containerObject, arguments); + } +} + +qx.Proto.addAfterToFolder = function(vChild, vAfter) +{ + this._createChildrenStructure(); + + if (this._containerObject) + { + this._handleChildMove(vChild, null, vAfter); + return this._containerObject.addAfter.apply(this._containerObject, arguments); + } +} + +qx.Proto.addAtToFolder = function(vChild, vIndex) +{ + this._createChildrenStructure(); + + if (this._containerObject) + { + this._handleChildMove(vChild, vIndex); + return this._containerObject.addAt.apply(this._containerObject, arguments); + } +} + +qx.Proto.addAtBeginToFolder = function(vChild) { + return this.addAtToFolder(vChild, 0); +} + +qx.Proto.addAtEndToFolder = function(vChild) +{ + this._createChildrenStructure(); + + if (this._containerObject) + { + var vLast = this._containerObject.getLastChild(); + + if (vLast) + { + this._handleChildMove(vChild, null, vLast); + return this._containerObject.addAfter.call(this._containerObject, vChild, vLast); + } + else + { + return this.addAtBeginToFolder(vChild); + } + } +} + +qx.Proto._remappingChildTable = [ "remove", "removeAt", "removeAll" ]; + + + + + + +/* +--------------------------------------------------------------------------- + CHILDREN UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getContainerObject = function() { + return this._containerObject; +} + +qx.Proto.getHorizontalLayout = function() { + return this._horizontalLayout; +} + +qx.Proto.getFirstVisibleChildOfFolder = function() +{ + if (this._containerObject) { + return this._containerObject.getFirstChild(); + } +} + +qx.Proto.getLastVisibleChildOfFolder = function() +{ + if (this._containerObject) { + return this._containerObject.getLastChild(); + } +} + +qx.Proto.getItems = function(recursive, invisible) +{ + var a = [this]; + + if (this._containerObject) + { + var ch = invisible == true ? this._containerObject.getChildren() : this._containerObject.getVisibleChildren(); + + if (recursive == false) + { + a = a.concat(ch); + } + else + { + for (var i=0, chl=ch.length; ideselects, disconnects, removes and disposes the + * content of the folder and its subfolders. + *

+ * + *

the current items subitems (and the subitems of each + * subitem) are destoyed going top down the TreeFolder + * hierarchy. The current item is left as is. + *

+ */ +qx.Proto.destroyContent = function() { + if(this.hasContent()) { + + var manager = this.getTree() ? this.getTree().getManager() : null; + + var leadItem; + var anchorItem; + if(manager) { + leadItem = manager.getLeadItem(); + anchorItem = manager.getAnchorItem(); + } + + var items = this.getItems(); + var item; + + for(var i=items.length-1;i>=0;--i) { + item = items[i]; + + // this.getItems seems to also contain this. + // In order to avoid endless loops by calling + // recursively destroyContent we have to avoid + // destroying ourselves + if(item != this) { + if(manager) { + // set the leadItem to null if the current + // destroyed item is the leadItem + if(leadItem == item) { + manager.setLeadItem(null); + } + // set the anchorItem to null if the current + // destroyed item is the anchorItem + if(anchorItem == item) { + manager.setAnchorItem(null); + } + + // if the current destroyed item is + // selectd deselect the item. If we are + // in single selection mode we have to + // call deselectAll because setItemSelected + // refuses to deselect in this case + if(manager.getItemSelected(item)) { + if(manager.getMultiSelection()) { + manager.setItemSelected(item,false); + } + else { + manager.deselectAll(); + } + } + + // if the item has the method destroyContent defined + // then it is a TreeFolder (and it's subclasses) + // which potentially have content which also + // has to be destroyed + if (item.destroyContent) { + item.destroyContent(); + } + } + + // first disconnect the item so rendering + // of the tree lines can be done correctly + item.disconnect(); + this.remove(item); + item.dispose(); + } + } + } +} + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._evalCurrentIcon = function() +{ + if (this.getSelected()) { + return this.getIconSelected() || "icon/16/folder-open.png"; + } else { + return this.getIcon() || "icon/16/folder.png"; + } +} + +qx.Proto._modifyOpen = function(propValue, propOldValue, propData) +{ + this._updateLastColumn(); + + if (this._containerObject) { + this._containerObject.setDisplay(propValue); + } + + return true; +} + +qx.Proto._modifyAlwaysShowPlusMinusSymbol = function(propValue, propOldValue, propData) +{ + this._updateLastColumn(); + + return true; +} + +qx.Proto._updateLastColumn = function() +{ + if (this._indentObject) + { + var vElement = this._indentObject.getElement(); + + if (vElement && vElement.firstChild) { + vElement.firstChild.src = this.BASE_URI + this.getIndentSymbol(this.getTree().getUseTreeLines(), true) + ".gif"; + } + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + EVENT LISTENERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmousedown = function(e) +{ + var vOriginalTarget = e.getOriginalTarget(); + + switch(vOriginalTarget) + { + case this._indentObject: + if (this._indentObject.getElement().firstChild == e.getDomTarget()) + { + this.getTree().getManager().handleMouseDown(this, e); + this.toggle(); + } + + break; + + case this._containerObject: + break; + + case this: + if (this._containerObject) { + break; + } + + // no break here + + default: + this.getTree().getManager().handleMouseDown(this, e); + } + + e.stopPropagation(); +} + +qx.Proto._onmouseup = function(e) +{ + var vOriginalTarget = e.getOriginalTarget(); + + switch(vOriginalTarget) + { + case this._indentObject: + case this._containerObject: + case this: + break; + + default: + if (!this.getTree().getUseDoubleClick()) { + this.open(); + } + } +} + +qx.Proto._ondblclick = function(e) +{ + if (!this.getTree().getUseDoubleClick()) { + return; + } + + this.toggle(); + e.stopPropagation(); +} + + + + + + + +/* +--------------------------------------------------------------------------- + INDENT HELPER +--------------------------------------------------------------------------- +*/ + +qx.Proto.getIndentSymbol = function(vUseTreeLines, vIsLastColumn) +{ + if (vIsLastColumn) + { + if (this.hasContent() || this.getAlwaysShowPlusMinusSymbol()) + { + if (!vUseTreeLines) + { + return this.getOpen() ? "minus" : "plus"; + } + else if (this.isLastChild()) + { + return this.getOpen() ? "end_minus" : "end_plus"; + } + else + { + return this.getOpen() ? "cross_minus" : "cross_plus"; + } + } + else if (vUseTreeLines) + { + return this.isLastChild() ? "end" : "cross"; + } + } + else + { + return vUseTreeLines && !this.isLastChild() ? "line" : null; + } +} + +qx.Proto._updateIndent = function() +{ + // Intentionally bypass superclass; the _updateIndent we want is in TreeFile + qx.ui.tree.TreeFile.prototype._updateIndent.call(this); + + if (!this._containerObject) { + return; + } + + var ch = this._containerObject.getVisibleChildren(); + for (var i=0, l=ch.length; i"); + } + + vCurrentObject = vCurrentObject.getParentFolder(); + } + + this._indentObject.setHtml(vHtml.join("")); + this._indentObject.setWidth((vMaxLevel - vMinLevel) * 19); +} + + + + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + if (this._indentObject) + { + this._indentObject.dispose(); + this._indentObject = null; + } + + if (this._iconObject) + { + this._iconObject.dispose(); + this._iconObject = null; + } + + if (this._labelObject) + { + this._labelObject.dispose(); + this._labelObject = null; + } + + this._previousParentFolder = null; + + this.removeEventListener("mousedown", this._onmousedown); + this.removeEventListener("mouseup", this._onmouseup); + + return qx.ui.layout.BoxLayout.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/treefullcontrol/Tree.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/treefullcontrol/Tree.js new file mode 100644 index 0000000000..912ede6d60 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/treefullcontrol/Tree.js @@ -0,0 +1,539 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + 2006 by Derrell Lipman + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Derrell Lipman (derrell) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_treefullcontrol) + +************************************************************************ */ + +/** + * qx.ui.treefullcontrol.Tree objects are tree root nodes but act like + * TreeFolder. + * + * @param treeRowStructure An instance of qx.ui.treefullcontrol.TreeRowStructure, + * defining the structure of this tree row. + */ +qx.OO.defineClass("qx.ui.treefullcontrol.Tree", qx.ui.treefullcontrol.TreeFolder, +function(treeRowStructure) +{ + qx.ui.treefullcontrol.TreeFolder.call(this, treeRowStructure); + + // ************************************************************************ + // INITILISIZE MANAGER + // ************************************************************************ + this._manager = new qx.manager.selection.TreeFullControlSelectionManager(this); + + + this._iconObject.setAppearance("tree-icon"); + this._labelObject.setAppearance("tree-label"); + + + // ************************************************************************ + // DEFAULT STATE + // ************************************************************************ + // The tree should be open by default + this.setOpen(true); + + // Fix vertical alignment of empty tree + this.addToFolder(); + + + // ************************************************************************ + // KEY EVENT LISTENER + // ************************************************************************ + this.addEventListener("keydown", this._onkeydown); + this.addEventListener("keypress", this._onkeypress); + this.addEventListener("keyup", this._onkeyup); +}); + + + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + +qx.OO.addProperty({ name : "useDoubleClick", + type : "boolean", + defaultValue : false, + getAlias : "useDoubleClick" + }); + +qx.OO.addProperty({ name : "useTreeLines", + type : "boolean", + defaultValue : true, + getAlias : "useTreeLines" + }); + +/*! + In specific applications, it is desirable to omit tree lines for only + certain indentation levels. This property provides an array wherein the + index of the array corresponds to the indentation level, counted from left + to right; and the value of that element, if it contains, specifically, the + boolean value true, indicates that tree lines at that indentation + level are to be omitted. Any value of that element other than true, + or if an indentation level's index does not exist in the array, means that + tree lines should be displayed for that indentation level. (There are some + minor code efficiencies that are realized if this array is empty, so after + having set an element to true and desiring to reset the default + behavior, you should 'delete' the element rather than setting it to some + value other than true.) + + If useTreeLines is false, then all tree lines are excluded and this + property is ignored. +*/ +qx.OO.addProperty({ name : "excludeSpecificTreeLines", + type : "object", + defaultValue : [] + }); + +/*! + Hide the root (Tree) node. This differs from the visibility property in + that this property hides *only* the current node, not the node's children. +*/ +qx.OO.addProperty({ name : "hideNode", + type : "boolean", + defaultValue : false, + getAlias : "hideNode" + }); + +/*! + Whether the Root should have an open/close button. This may also be + used in conjunction with the hideNode property to provide for virtual root + nodes. In the latter case, be very sure that the virtual root nodes are + expanded programatically, since there will be no open/close button for the + user to open them. +*/ +qx.OO.addProperty({ name : "rootOpenClose", + type : "boolean", + defaultValue : true + }); + + +/* +--------------------------------------------------------------------------- + MANAGER BINDING +--------------------------------------------------------------------------- +*/ + +qx.Proto.getManager = function() { + return this._manager; +} + +qx.Proto.getSelectedElement = function() { + return this.getManager().getSelectedItems()[0]; +} + + + + + + +/* +--------------------------------------------------------------------------- + QUEUE HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto.addChildToTreeQueue = function(vChild) +{ + if (!vChild._isInTreeQueue && !vChild._isDisplayable) { + this.debug("Ignoring invisible child: " + vChild); + } + + if (!vChild._isInTreeQueue && vChild._isDisplayable) + { + qx.ui.core.Widget.addToGlobalWidgetQueue(this); + + if (!this._treeQueue) { + this._treeQueue = {}; + } + + this._treeQueue[vChild.toHashCode()] = vChild; + + vChild._isInTreeQueue = true; + } +} + +qx.Proto.removeChildFromTreeQueue = function(vChild) +{ + if (vChild._isInTreeQueue) + { + if (this._treeQueue) { + delete this._treeQueue[vChild.toHashCode()]; + } + + delete vChild._isInTreeQueue; + } +} + +qx.Proto.flushWidgetQueue = function() { + this.flushTreeQueue(); +} + +qx.Proto.flushTreeQueue = function() +{ + if (!qx.lang.Object.isEmpty(this._treeQueue)) + { + for (var vHashCode in this._treeQueue) + { + // this.debug("Flushing Tree Child: " + this._treeQueue[vHashCode]); + this._treeQueue[vHashCode].flushTree(); + delete this._treeQueue[vHashCode]._isInTreeQueue; + } + + delete this._treeQueue; + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + MODIFIER +--------------------------------------------------------------------------- +*/ + +qx.Proto._modifyUseTreeLines = function(propValue, propOldValue, propData) +{ + if (this._initialLayoutDone) { + this._updateIndent(); + } + + return true; +} + +qx.Proto._modifyHideNode = function(propValue, propOldValue, propData) +{ + if (! propValue) { + this._horizontalLayout.setHeight(this._horizontalLayout.originalHeight); + this._horizontalLayout.show(); + } else { + this._horizontalLayout.originalHeight = this._horizontalLayout.getHeight(); + this._horizontalLayout.setHeight(0); + this._horizontalLayout.hide(); + } + + if (this._initialLayoutDone) { + this._updateIndent(); + } + + return true; +} + +qx.Proto._modifyRootOpenClose = function(propValue, propOldValue, propData) +{ + if (this._initialLayoutDone) { + this._updateIndent(); + } + + return true; +} + +// Override getter so we can return a clone of the array. Otherwise, the +// setter finds the identical array (after user modifications) and the modify +// function doesn't get called. +qx.Proto.getExcludeSpecificTreeLines = function() +{ + var vName = "excludeSpecificTreeLines"; + var vUpName = qx.lang.String.toFirstUp(vName); + var vStorageField = "_value" + vUpName; + + return this[vStorageField].slice(0); +} + +qx.Proto._modifyExcludeSpecificTreeLines = function(propValue, + propOldValue, + propData) +{ + if (this._initialLayoutDone) { + this._updateIndent(); + } + + return true; +} + + + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getTree = function() { + return this; +} + +qx.Proto.getParentFolder = function() { + return null; +} + +qx.Proto.getLevel = function() { + return 0; +} + + + + + + + + +/* +--------------------------------------------------------------------------- + COMMON CHECKERS +--------------------------------------------------------------------------- +*/ + +qx.ui.treefullcontrol.Tree.isTreeFolder = function(vObject) { + return (vObject && + vObject instanceof qx.ui.treefullcontrol.TreeFolder && + !(vObject instanceof qx.ui.treefullcontrol.Tree)); +} + +qx.ui.treefullcontrol.Tree.isOpenTreeFolder = function(vObject) { + return (vObject instanceof qx.ui.treefullcontrol.TreeFolder && + vObject.getOpen() && + vObject.hasContent()); +} + + + + + + + +/* +--------------------------------------------------------------------------- + EVENT HANDLER +--------------------------------------------------------------------------- +*/ + +qx.Proto._onkeydown = function(e) +{ + var vManager = this.getManager(); + var vSelectedItem = vManager.getSelectedItem(); + + if (e.getKeyIdentifier() == "Enter") + { + e.preventDefault(); + if (qx.ui.treefullcontrol.Tree.isTreeFolder(vSelectedItem)) { + return vSelectedItem.toggle(); + } + } +} + + +qx.Proto._onkeypress = function(e) +{ + var vManager = this.getManager(); + var vSelectedItem = vManager.getSelectedItem(); + + switch(e.getKeyIdentifier()) + { + case "Left": + e.preventDefault(); + + if (qx.ui.treefullcontrol.Tree.isTreeFolder(vSelectedItem)) + { + if (!vSelectedItem.getOpen()) + { + var vParent = vSelectedItem.getParentFolder(); + if (vParent instanceof qx.ui.treefullcontrol.TreeFolder) { + if (!(vParent instanceof qx.ui.treefullcontrol.Tree)) { + vParent.close(); + } + + this.setSelectedElement(vParent); + } + } + else + { + return vSelectedItem.close(); + } + } + else if (vSelectedItem instanceof qx.ui.treefullcontrol.TreeFile) + { + var vParent = vSelectedItem.getParentFolder(); + if (vParent instanceof qx.ui.treefullcontrol.TreeFolder) { + if (!(vParent instanceof qx.ui.treefullcontrol.Tree)) { + vParent.close(); + } + + this.setSelectedElement(vParent); + } + } + + break; + + case "Right": + e.preventDefault(); + + if (qx.ui.treefullcontrol.Tree.isTreeFolder(vSelectedItem)) + { + if (!vSelectedItem.getOpen()) + { + return vSelectedItem.open(); + } + else if (vSelectedItem.hasContent()) + { + var vFirst = vSelectedItem.getFirstVisibleChildOfFolder(); + this.setSelectedElement(vFirst); + + if (vFirst instanceof qx.ui.tree.TreeFolder) { + vFirst.open(); + } + + return; + } + } + + break; + + default: + if (!this._fastUpdate) + { + this._fastUpdate = true; + this._oldItem = vSelectedItem; + } + + vManager.handleKeyPress(e); + } +}; + + +qx.Proto._onkeyup = function(e) +{ + if (this._fastUpdate) + { + var vNewItem = this.getManager().getSelectedItem(); + + if (! vNewItem) { + return; + } + + vNewItem.getIconObject().addState("selected"); + + delete this._fastUpdate; + delete this._oldItem; + } +} + +qx.Proto.getLastTreeChild = function() +{ + var vLast = this; + + while (vLast instanceof qx.ui.treefullcontrol.AbstractTreeElement) + { + if (!(vLast instanceof qx.ui.treefullcontrol.TreeFolder) || + !vLast.getOpen()) { + return vLast; + } + + vLast = vLast.getLastVisibleChildOfFolder(); + } + + return null; +} + +qx.Proto.getFirstTreeChild = function() { + return this; +} + +qx.Proto.setSelectedElement = function(vElement) +{ + var vManager = this.getManager(); + + vManager.setSelectedItem(vElement); + vManager.setLeadItem(vElement); +} + +/* Override getHierarchy: do not add label if root node is hidden */ +qx.Proto.getHierarchy = function(vArr) +{ + if (! this.hideNode() && this._labelObject) { + vArr.unshift(this._labelObject.getHtml()); + } + return vArr; +} + + +qx.Proto.getIndentSymbol = function(vUseTreeLines, vColumn, vLastColumn) +{ + if (vColumn == vLastColumn && + (this.hasContent() || this.getAlwaysShowPlusMinusSymbol())) + { + if (! vUseTreeLines) + { + return this.getOpen() ? "minus" : "plus"; + } + else + { + return this.getOpen() ? "only_minus" : "only_plus"; + } + } + else + { + return null; + } +} + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return; + } + + this.removeEventListener("keydown", this._onkeydown); + this.removeEventListener("keypress", this._onkeypress); + this.removeEventListener("keyup", this._onkeyup); + + if (this._manager) + { + this._manager.dispose(); + this._manager = null; + } + + delete this._oldItem; + + return qx.ui.treefullcontrol.TreeFolder.prototype.dispose.call(this); +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/treefullcontrol/TreeFile.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/treefullcontrol/TreeFile.js new file mode 100644 index 0000000000..bf38a87c47 --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/treefullcontrol/TreeFile.js @@ -0,0 +1,81 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + 2006 by Derrell Lipman + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Derrell Lipman (derrell) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_treefullcontrol) + +************************************************************************ */ + +/** + * qx.ui.treefullcontrol.TreeFile objects are terminal tree rows (i.e. no + * sub-trees) + * + * @param + * treeRowStructure - + * An instance of qx.ui.treefullcontrol.TreeRowStructure, defining the + * structure of this tree row. + */ +qx.OO.defineClass("qx.ui.treefullcontrol.TreeFile", qx.ui.treefullcontrol.AbstractTreeElement, +function(treeRowStructure) +{ + qx.ui.treefullcontrol.AbstractTreeElement.call(this, treeRowStructure); +}); + + + + +/* +--------------------------------------------------------------------------- + INDENT HELPER +--------------------------------------------------------------------------- +*/ + +qx.Proto.getIndentSymbol = function(vUseTreeLines, + vColumn, + vFirstColumn, + vLastColumn) +{ + var vLevel = this.getLevel(); + var vExcludeList = this.getTree().getExcludeSpecificTreeLines(); + var vExclude = vExcludeList[vLastColumn - vColumn - 1]; + + if (vUseTreeLines && ! (vExclude === true)) + { + if (vColumn == vFirstColumn) + { + return this.isLastChild() ? "end" : "cross"; + } + else + { + return "line"; + } + } + + return null; +} + +qx.Proto._updateIndent = function() { + this.addToTreeQueue(); +} + +qx.Proto.getItems = function() { + return [this]; +} diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/treefullcontrol/TreeFolder.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/treefullcontrol/TreeFolder.js new file mode 100644 index 0000000000..93a50c27bd --- /dev/null +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/ui/treefullcontrol/TreeFolder.js @@ -0,0 +1,651 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org + 2006 by Derrell Lipman + + License: + LGPL 2.1: http://www.gnu.org/licenses/lgpl.html + + Authors: + * Sebastian Werner (wpbasti) + * Andreas Ecker (ecker) + * Derrell Lipman (derrell) + +************************************************************************ */ + +/* ************************************************************************ + +#module(ui_treefullcontrol) + +************************************************************************ */ + +/** + * qx.ui.treefullcontrol.TreeFolder objects are tree rows which may contain + * sub-trees + * + * @param + * treeRowStructure - + * An instance of qx.ui.treefullcontrol.TreeRowStructure, defining the + * structure of this tree row. + * + * @event treeOpenWithContent {qx.event.type.DataEvent} + * @event treeOpenWhileEmpty {qx.event.type.DataEvent} + * @event treeClose {qx.event.type.DataEvent} + */ +qx.OO.defineClass("qx.ui.treefullcontrol.TreeFolder", qx.ui.treefullcontrol.AbstractTreeElement, +function(treeRowStructure) +{ + qx.ui.treefullcontrol.AbstractTreeElement.call(this, treeRowStructure); + + // Save the tree row field order. We'll need it to create children structure. + this._treeRowStructureFields = treeRowStructure._fields; + + this._iconObject.setAppearance("tree-folder-icon"); + this._labelObject.setAppearance("tree-folder-label"); + + this.addEventListener("dblclick", this._ondblclick); + + // Remapping of add/remove methods + this.add = this.addToFolder; + this.addBefore = this.addBeforeToFolder; + this.addAfter = this.addAfterToFolder; + this.addAt = this.addAtToFolder; + this.addAtBegin = this.addAtBeginToFolder; + this.addAtEnd = this.addAtEndToFolder; +}); + + + +/* +--------------------------------------------------------------------------- + PROPERTIES +--------------------------------------------------------------------------- +*/ + + +qx.OO.changeProperty({ name : "appearance", + type : "string", + defaultValue : "tree-folder" + }); + +qx.OO.changeProperty({ name : "icon", + type : "string" + }); + +qx.OO.changeProperty({ name : "iconSelected", + type : "string" + }); + +qx.OO.addProperty({ name : "open", + type : "boolean", + defaultValue : false + }); + +qx.OO.addProperty({ name : "alwaysShowPlusMinusSymbol", + type : "boolean", + defaultValue : false + }); + + + + +/* +--------------------------------------------------------------------------- + UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.hasContent = function() { + return (this._containerObject && + this._containerObject.getChildrenLength() > 0); +} + +qx.Proto.open = function() +{ + if (this.getOpen()) { + return; + } + + if (this.hasContent()) + { + // If there are listeners waiting for a treeOpenWithContent event... + if (this.getTree().hasEventListeners("treeOpenWithContent")) { + // ... then issue the event + this.getTree().dispatchEvent(new qx.event.type.DataEvent("treeOpenWithContent", this), true); + } + + this.getTopLevelWidget().setGlobalCursor("progress"); + qx.client.Timer.once(this._openCallback, this, 0); + } + else + { + // If there are listeners waiting for a treeOpenWithContent event... + if (this.getTree().hasEventListeners("treeOpenWhileEmpty")) { + // ... then issue the event + this.getTree().dispatchEvent(new qx.event.type.DataEvent("treeOpenWhileEmpty", this), true); + } + + this.setOpen(true); + } +} + +qx.Proto.close = function() +{ + // If there are listeners waiting for a treeClose event... + if (this.getTree().hasEventListeners("treeClose")) { + // ... then issue the event + this.getTree().dispatchEvent(new qx.event.type.DataEvent("treeClose", this), true); + } + + this.setOpen(false); +} + +qx.Proto.toggle = function() +{ + this.getOpen() ? this.close() : this.open(); +} + +qx.Proto._openCallback = function() +{ + this.setOpen(true); + qx.ui.core.Widget.flushGlobalQueues(); + this.getTopLevelWidget().setGlobalCursor(null); +} + + + + + + + + +/* +--------------------------------------------------------------------------- + CHILDREN HANDLING +--------------------------------------------------------------------------- +*/ + +qx.Proto._createChildrenStructure = function() +{ + this.setAppearance(this instanceof qx.ui.treefullcontrol.Tree + ? "tree-container" + : "tree-folder-container"); + + if (!this._horizontalLayout) + { + this.setOrientation("vertical"); + + // Create a horizontal layout for this tree row + this._horizontalLayout = new qx.ui.layout.HorizontalBoxLayout; + this._horizontalLayout.setWidth(null); + this._horizontalLayout.setParent(this); + this._horizontalLayout.setAnonymous(true); + this._horizontalLayout.setAppearance(this instanceof qx.ui.treefullcontrol.Tree + ? "tree" + : "tree-folder"); + + // Move the row fields into the horizontal layout + for (var i = 0; i < this._treeRowStructureFields.length; i++) + { + this._treeRowStructureFields[i].setParent(this._horizontalLayout); + } + + // We don't need the tree row structure any more. + this._treeRowStructureFields = null; + } + + if (!this._containerObject) + { + // Create a veritcal box layout for all of this folder's children + this._containerObject = new qx.ui.layout.VerticalBoxLayout; + this._containerObject.setWidth(null); + this._containerObject.setAnonymous(true); + + // it should be faster to first handle display, + // because the default display value is true and if we first + // setup the parent the logic do all to make the + // widget first visible and then, if the folder is not + // opened again invisible. + this._containerObject.setDisplay(this.getOpen()); + this._containerObject.setParent(this); + + // remap remove* functions + this.remapChildrenHandlingTo(this._containerObject); + } +} + +qx.Proto._handleChildMove = function(vChild, vRelationIndex, vRelationChild) +{ + if (vChild.isDisplayable()) + { + var vChildren = this._containerObject.getChildren(); + var vOldChildIndex = vChildren.indexOf(vChild); + + if (vOldChildIndex != -1) + { + if (vRelationChild) { + vRelationIndex = vChildren.indexOf(vRelationChild); + } + + if (vRelationIndex == vChildren.length-1) + { + vChild._updateIndent(); + + // Update indent of previous last child + this._containerObject.getLastVisibleChild()._updateIndent(); + } + else if (vChild._wasLastVisibleChild) + { + vChild._updateIndent(); + + // Update indent for new last child + var vPreviousSibling = vChild.getPreviousVisibleSibling(); + if (vPreviousSibling) { + vPreviousSibling._updateIndent(); + } + } + } + } +} + +qx.Proto.addToFolder = function() +{ + this._createChildrenStructure(); + + if (this._containerObject) { + return this._containerObject.add.apply(this._containerObject, arguments); + } +} + +qx.Proto.addBeforeToFolder = function(vChild, vBefore) +{ + this._createChildrenStructure(); + + if (this._containerObject) + { + this._handleChildMove(vChild, null, vBefore); + return this._containerObject.addBefore.apply(this._containerObject, + arguments); + } +} + +qx.Proto.addAfterToFolder = function(vChild, vAfter) +{ + this._createChildrenStructure(); + + if (this._containerObject) + { + this._handleChildMove(vChild, null, vAfter); + return this._containerObject.addAfter.apply(this._containerObject, + arguments); + } +} + +qx.Proto.addAtToFolder = function(vChild, vIndex) +{ + this._createChildrenStructure(); + + if (this._containerObject) + { + this._handleChildMove(vChild, vIndex); + return this._containerObject.addAt.apply(this._containerObject, arguments); + } +} + +qx.Proto.addAtBeginToFolder = function(vChild) { + return this.addAtToFolder(vChild, 0); +} + +qx.Proto.addAtEndToFolder = function(vChild) +{ + this._createChildrenStructure(); + + if (this._containerObject) + { + var vLast = this._containerObject.getLastChild(); + + if (vLast) + { + this._handleChildMove(vChild, null, vLast); + return this._containerObject.addAfter.call(this._containerObject, + vChild, + vLast); + } + else + { + return this.addAtBeginToFolder(vChild); + } + } +} + +qx.Proto._remappingChildTable = [ "remove", "removeAt", "removeAll" ]; + + + + + + +/* +--------------------------------------------------------------------------- + CHILDREN UTILITIES +--------------------------------------------------------------------------- +*/ + +qx.Proto.getContainerObject = function() +{ + return this._containerObject; +} + +qx.Proto.getHorizontalLayout = function() +{ + return this._horizontalLayout; +} + +qx.Proto.getFirstVisibleChildOfFolder = function() +{ + if (this._containerObject) { + return this._containerObject.getFirstChild(); + } +} + +qx.Proto.getLastVisibleChildOfFolder = function() +{ + if (this._containerObject) { + return this._containerObject.getLastChild(); + } +} + +qx.Proto.getItems = function() +{ + var a = [this]; + + if (this._containerObject) + { + var ch = this._containerObject.getVisibleChildren(); + + for (var i=0, chl=ch.length; i 0) { + this._updateIndent(); + } else { + this._updateLastColumn(); + } + + if (this._containerObject) { + this._containerObject.setDisplay(propValue); + } + + return true; +} + +qx.Proto._modifyAlwaysShowPlusMinusSymbol = function(propValue, propOldValue, propData) +{ + var t = this.getTree(); + if (t) { + // we need the whole indent process if only certain tree lines are to be + // excluded + if (t.getExcludeSpecificTreeLines().length > 0) { + this._updateIndent(); + } else { + this._updateLastColumn(); + } + } + + return true; +} + +qx.Proto._updateLastColumn = function() +{ + if (this._indentObject) + { + var vElement = this._indentObject.getElement(); + + if (vElement && vElement.firstChild) { + vElement.firstChild.src = + (this.BASE_URI + + this.getIndentSymbol(this.getTree().getUseTreeLines(), 0, 0, 0) + + ".gif"); + } + } +} + + + + + + + +/* +--------------------------------------------------------------------------- + EVENT LISTENERS +--------------------------------------------------------------------------- +*/ + +qx.Proto._onmousedown = function(e) +{ + var vOriginalTarget = e.getOriginalTarget(); + + switch(vOriginalTarget) + { + case this._indentObject: + if (this._indentObject.getElement().firstChild == e.getDomTarget()) + { + this.getTree().getManager().handleMouseDown(this, e); + this.toggle(); + } + + break; + + case this._containerObject: + break; + + case this: + if (this._containerObject) { + break; + } + + // no break here + + default: + this.getTree().getManager().handleMouseDown(this, e); + } + + e.stopPropagation(); +} + +qx.Proto._onmouseup = function(e) +{ + var vOriginalTarget = e.getOriginalTarget(); + + switch(vOriginalTarget) + { + case this._indentObject: + case this._containerObject: + case this: + break; + + default: + if (!this.getTree().getUseDoubleClick()) { + this.open(); + } + } +} + +qx.Proto._ondblclick = function(e) +{ + if (!this.getTree().getUseDoubleClick()) { + return; + } + + this.toggle(); + e.stopPropagation(); +} + + + + + + + +/* +--------------------------------------------------------------------------- + INDENT HELPER +--------------------------------------------------------------------------- +*/ + +qx.Proto.getIndentSymbol = function(vUseTreeLines, + vColumn, + vFirstColumn, + vLastColumn) +{ + var vLevel = this.getLevel(); + var vExcludeList = this.getTree().getExcludeSpecificTreeLines(); + var vExclude = vExcludeList[vLastColumn - vColumn - 1]; + + if (vColumn == vFirstColumn) + { + if (this.hasContent() || this.getAlwaysShowPlusMinusSymbol()) + { + // If tree lines were not requested, don't display them + if (!vUseTreeLines) + { + return this.getOpen() ? "minus" : "plus"; + } + + + // If this is the first level under the root... + if (vLevel == 1) { + // ... and the root is not being displayed and this is the first + // child... + var vParentFolder = this.getParentFolder(); + if (vParentFolder && + !vParentFolder._horizontalLayout.getVisibility() && + this.isFirstChild()) + { + //... then if this is also the last (i.e. only) child, use no tree + // lines; otherwise, use descender lines but no ascender. + if (this.isLastChild() || vExclude === true) + { + return this.getOpen() ? "only_minus" : "only_plus"; + } + else + { + return this.getOpen() ? "start_minus" : "start_plus"; + } + } + } + + if (vExclude === true) + { + return this.getOpen() ? "only_minus" : "only_plus"; + } + else if (this.isLastChild()) + { + return this.getOpen() ? "end_minus" : "end_plus"; + } + else + { + return this.getOpen() ? "cross_minus" : "cross_plus"; + } + } + else if (vUseTreeLines && ! (vExclude === true)) + { + return this.isLastChild() ? "end" : "cross"; + } + } + else + { + if (vUseTreeLines && ! this.isLastChild()) { + if (vExclude === true) { + return null; + } + return "line"; + } + return null; + } +} + +qx.Proto._updateIndent = function() +{ + // Intentionally bypass superclass; the _updateIndent we want is in TreeFile + qx.ui.treefullcontrol.TreeFile.prototype._updateIndent.call(this); + + if (!this._containerObject) { + return; + } + + var ch = this._containerObject.getVisibleChildren(); + for (var i=0, l=ch.length; i (p - 5) && e < (p + 5); +} + +qx.Proto._onwindowmousemove = function(e) +{ + if (!this.getResizeable() || this.getMode() != null) { + return; + } + + var s = this._resizeSession; + + if (s) + { + if (this._resizeWest) + { + s.lastWidth = qx.lang.Number.limit(s.boxWidth + s.boxLeft - Math.max(e.getPageX(), s.parentAreaOffsetLeft), s.minWidth, s.maxWidth); + s.lastLeft = s.boxRight - s.lastWidth - s.parentAreaOffsetLeft; + } + else if (this._resizeEast) + { + s.lastWidth = qx.lang.Number.limit(Math.min(e.getPageX(), s.parentAreaOffsetRight) - s.boxLeft, s.minWidth, s.maxWidth); + } + + if (this._resizeNorth) + { + s.lastHeight = qx.lang.Number.limit(s.boxHeight + s.boxTop - Math.max(e.getPageY(), s.parentAreaOffsetTop), s.minHeight, s.maxHeight); + s.lastTop = s.boxBottom - s.lastHeight - s.parentAreaOffsetTop; + } + else if (this._resizeSouth) + { + s.lastHeight = qx.lang.Number.limit(Math.min(e.getPageY(), s.parentAreaOffsetBottom) - s.boxTop, s.minHeight, s.maxHeight); + } + + switch(this.getResizeMethod()) + { + case "opaque": + case "translucent": + if (this._resizeWest || this._resizeEast) + { + this.setWidth(s.lastWidth); + + if (this._resizeWest) { + this.setLeft(s.lastLeft); + } + } + + if (this._resizeNorth || this._resizeSouth) + { + this.setHeight(s.lastHeight); + + if (this._resizeNorth) { + this.setTop(s.lastTop); + } + } + + break; + + default: + var o = this.getResizeMethod() == "frame" ? this._frame : this; + + if (this._resizeWest || this._resizeEast) + { + o._applyRuntimeWidth(s.lastWidth); + + if (this._resizeWest) { + o._applyRuntimeLeft(s.lastLeft); + } + } + + if (this._resizeNorth || this._resizeSouth) + { + o._applyRuntimeHeight(s.lastHeight); + + if (this._resizeNorth) { + o._applyRuntimeTop(s.lastTop); + } + } + } + } + else + { + var resizeMode = ""; + var el = this.getElement(); + + this._resizeNorth = this._resizeSouth = this._resizeWest = this._resizeEast = false; + + if (this._near(qx.dom.Location.getPageBoxTop(el), e.getPageY())) + { + resizeMode = "n"; + this._resizeNorth = true; + } + else if (this._near(qx.dom.Location.getPageBoxBottom(el), e.getPageY())) + { + resizeMode = "s"; + this._resizeSouth = true; + } + + if (this._near(qx.dom.Location.getPageBoxLeft(el), e.getPageX())) + { + resizeMode += "w"; + this._resizeWest = true; + } + else if (this._near(qx.dom.Location.getPageBoxRight(el), e.getPageX())) + { + resizeMode += "e"; + this._resizeEast = true; + } + + if (this._resizeNorth || this._resizeSouth || this._resizeWest || this._resizeEast) + { + this.setCursor(resizeMode + "-resize"); + } + else + { + this.setCursor(null); + } + } + + // stop event + e.stopPropagation(); +} + +qx.Proto._onwindowclick = function(e) +{ + // stop event + e.stopPropagation(); +}; + + + + + +/* +--------------------------------------------------------------------------- + EVENTS: BUTTONS +--------------------------------------------------------------------------- +*/ + +qx.Proto._onbuttonmousedown = function(e) { + e.stopPropagation(); +} + +qx.Proto._onminimizebuttonclick = function(e) +{ + this.minimize(); + + // we need to be sure that the button gets the right states after clicking + // because the button will move and does not get the mouseup event anymore + this._minimizeButton.removeState("pressed"); + this._minimizeButton.removeState("abandoned"); + this._minimizeButton.removeState("over"); + + e.stopPropagation(); +} + +qx.Proto._onrestorebuttonclick = function(e) +{ + this.restore(); + + // we need to be sure that the button gets the right states after clicking + // because the button will move and does not get the mouseup event anymore + this._restoreButton.removeState("pressed"); + this._restoreButton.removeState("abandoned"); + this._restoreButton.removeState("over"); + + e.stopPropagation(); +} + +qx.Proto._onmaximizebuttonclick = function(e) +{ + this.maximize(); + + // we need to be sure that the button gets the right states after clicking + // because the button will move and does not get the mouseup event anymore + this._maximizeButton.removeState("pressed"); + this._maximizeButton.removeState("abandoned"); + this._maximizeButton.removeState("over"); + + e.stopPropagation(); +} + +qx.Proto._onclosebuttonclick = function(e) +{ + this.close(); + + // we need to be sure that the button gets the right states after clicking + // because the button will move and does not get the mouseup event anymore + this._closeButton.removeState("pressed"); + this._closeButton.removeState("abandoned"); + this._closeButton.removeState("over"); + + e.stopPropagation(); +} + + + + + + + +/* +--------------------------------------------------------------------------- + EVENTS: CAPTIONBAR +--------------------------------------------------------------------------- +*/ + +qx.Proto._oncaptionmousedown = function(e) +{ + if (!e.isLeftButtonPressed() || !this.getMoveable() || this.getMode() != null) { + return; + } + + // enable capturing + this._captionBar.setCapture(true); + + // element cache + var el = this.getElement(); + + // measuring and caching of values for drag session + var pa = this.getParent(); + var pl = pa.getElement(); + + var l = qx.dom.Location.getPageAreaLeft(pl); + var t = qx.dom.Location.getPageAreaTop(pl); + var r = qx.dom.Location.getPageAreaRight(pl); + var b = qx.dom.Location.getPageAreaBottom(pl); + + this._dragSession = + { + offsetX : e.getPageX() - qx.dom.Location.getPageBoxLeft(el) + l, + offsetY : e.getPageY() - qx.dom.Location.getPageBoxTop(el) + t, + + parentAvailableAreaLeft : l + 5, + parentAvailableAreaTop : t + 5, + parentAvailableAreaRight : r - 5, + parentAvailableAreaBottom : b - 5 + } + + // handle frame and translucently + switch(this.getMoveMethod()) + { + case "translucent": + this.setOpacity(0.5); + break; + + case "frame": + var f = this._frame; + + if (f.getParent() != this.getParent()) + { + f.setParent(this.getParent()); + qx.ui.core.Widget.flushGlobalQueues(); + } + + f._applyRuntimeLeft(qx.dom.Location.getPageBoxLeft(el) - l); + f._applyRuntimeTop(qx.dom.Location.getPageBoxTop(el) - t); + + f._applyRuntimeWidth(qx.dom.Dimension.getBoxWidth(el)); + f._applyRuntimeHeight(qx.dom.Dimension.getBoxHeight(el)); + + f.setZIndex(this.getZIndex() + 1); + + break; + } +} + +qx.Proto._oncaptionmouseup = function(e) +{ + var s = this._dragSession; + + if (!s) { + return; + } + + // disable capturing + this._captionBar.setCapture(false); + + // move window to last position + if (qx.util.Validation.isValidNumber(s.lastX)) { + this.setLeft(s.lastX); + } + + if (qx.util.Validation.isValidNumber(s.lastY)) { + this.setTop(s.lastY); + } + + // handle frame and translucently + switch(this.getMoveMethod()) + { + case "translucent": + this.setOpacity(null); + break; + + case "frame": + this._frame.setParent(null); + break; + } + + // cleanup session + delete this._dragSession; +} + +qx.Proto._oncaptionmousemove = function(e) +{ + var s = this._dragSession; + + // pre check for active session and capturing + if (!s || !this._captionBar.getCapture()) { + return; + } + + // pre check if we go out of the available area + if (!qx.lang.Number.isBetweenRange(e.getPageX(), s.parentAvailableAreaLeft, s.parentAvailableAreaRight) || !qx.lang.Number.isBetweenRange(e.getPageY(), s.parentAvailableAreaTop, s.parentAvailableAreaBottom)) { + return; + } + + // use the fast and direct dom methods + var o = this.getMoveMethod() == "frame" ? this._frame : this; + + o._applyRuntimeLeft(s.lastX = e.getPageX() - s.offsetX); + o._applyRuntimeTop(s.lastY = e.getPageY() - s.offsetY); +} + +qx.Proto._oncaptiondblblick = function() +{ + if (!this._maximizeButton.getEnabled()) { + return; + } + + return this.getMode() == "maximized" ? this.restore() : this.maximize(); +} + + + + + + + + +/* +--------------------------------------------------------------------------- + DISPOSER +--------------------------------------------------------------------------- +*/ + +qx.Proto.dispose = function() +{ + if (this.getDisposed()) { + return true; + } + + if (this._layout) + { + this._layout.dispose(); + this._layout = null; + } + + if (this._frame) + { + this._frame.dispose(); + this._frame = null; + } + + if (this._captionBar) + { + this._captionBar.dispose(); + this._captionBar = null; + } + + if (this._captionIcon) + { + this._captionIcon.dispose(); + this._captionIcon = null; + } + + if (this._captionTitle) + { + this._captionTitle.dispose(); + this._captionTitle = null; + } + + if (this._captionFlex) + { + this._captionFlex.dispose(); + this._captionFlex = null; + } + + if (this._closeButton) + { + this._closeButton.dispose(); + this._closeButton = null; + } + + if (this._minimizeButton) + { + this._minimizeButton.dispose(); + this._minimizeButton = null; + } + + if (this._maximizeButton) + { + this._maximizeButton.dispose(); + this._maximizeButton = null; + } + + if (this._restoreButton) + { + this._restoreButton.dispose(); + this._restoreButton = null; + } + + if (this._pane) + { + this._pane.dispose(); + this._pane = null; + } + + if (this._statusBar) + { + this._statusBar.dispose(); + this._statusBar = null; + } + + if (this._statusText) + { + this._statusText.dispose(); + this._statusText = null; + } + + return qx.ui.popup.Popup.prototype.dispose.call(this); +} -- cgit