From dea9725dfc39a675db52aa3e68d9ae2ce47b98d0 Mon Sep 17 00:00:00 2001 From: fanis <fanis@theophaniss-macbook-pro-2.home> Date: Fri, 18 Sep 2020 17:37:56 +0200 Subject: [PATCH] Removed not used files. --- .../META-INF/MANIFEST.MF | 2 - .../org.controlsfx.glyphfont.GlyphFont | 1 - src/impl/build/transifex/JSON.java | 140 -- src/impl/build/transifex/Transifex.java | 179 -- src/impl/org/controlsfx/ImplUtils.java | 149 -- .../AutoCompletionTextFieldBinding.java | 161 -- .../autocompletion/SuggestionProvider.java | 199 -- .../behavior/RangeSliderBehavior.java | 339 --- .../controlsfx/behavior/RatingBehavior.java | 41 - .../behavior/SnapshotViewBehavior.java | 783 ------- .../control/validation/decoration-error.png | Bin 3158 -> 0 bytes .../control/validation/decoration-warning.png | Bin 3120 -> 0 bytes .../control/validation/required-indicator.png | Bin 2955 -> 0 bytes .../org/controlsfx/i18n/Localization.java | 125 -- .../i18n/SimpleLocalizedStringProperty.java | 58 - src/impl/org/controlsfx/i18n/Translation.java | 74 - .../org/controlsfx/i18n/Translations.java | 129 -- .../controlsfx/skin/AutoCompletePopup.java | 233 -- .../skin/AutoCompletePopupSkin.java | 115 - .../controlsfx/skin/BreadCrumbBarSkin.java | 381 ---- .../controlsfx/skin/CheckComboBoxSkin.java | 193 -- .../controlsfx/skin/CustomTextFieldSkin.java | 156 -- .../org/controlsfx/skin/DecorationPane.java | 122 -- .../skin/ExpandableTableRowSkin.java | 109 - .../org/controlsfx/skin/GridCellSkin.java | 43 - src/impl/org/controlsfx/skin/GridRow.java | 104 - src/impl/org/controlsfx/skin/GridRowSkin.java | 179 -- .../org/controlsfx/skin/GridViewSkin.java | 230 -- .../controlsfx/skin/HiddenSidesPaneSkin.java | 336 --- .../controlsfx/skin/HyperlinkLabelSkin.java | 156 -- .../org/controlsfx/skin/InfoOverlaySkin.java | 248 --- .../skin/ListSelectionViewSkin.java | 474 ---- .../org/controlsfx/skin/MaskerPaneSkin.java | 79 - .../controlsfx/skin/MasterDetailPaneSkin.java | 473 ---- .../org/controlsfx/skin/NotificationBar.java | 309 --- .../controlsfx/skin/NotificationPaneSkin.java | 201 -- .../controlsfx/skin/PlusMinusSliderSkin.java | 160 -- src/impl/org/controlsfx/skin/PopOverSkin.java | 717 ------ .../controlsfx/skin/PropertySheetSkin.java | 350 --- .../org/controlsfx/skin/RangeSliderSkin.java | 580 ----- src/impl/org/controlsfx/skin/RatingSkin.java | 329 --- .../controlsfx/skin/SegmentedButtonSkin.java | 117 - .../org/controlsfx/skin/SnapshotViewSkin.java | 566 ----- .../org/controlsfx/skin/StatusBarSkin.java | 100 - .../controlsfx/skin/TaskProgressViewSkin.java | 167 -- .../org/controlsfx/skin/ToggleSwitchSkin.java | 242 --- .../org/controlsfx/spreadsheet/CellView.java | 659 ------ .../controlsfx/spreadsheet/CellViewSkin.java | 224 -- .../spreadsheet/FocusModelListener.java | 142 -- .../spreadsheet/GridCellEditor.java | 271 --- .../org/controlsfx/spreadsheet/GridRow.java | 161 -- .../controlsfx/spreadsheet/GridRowSkin.java | 615 ------ .../spreadsheet/GridViewBehavior.java | 509 ----- .../controlsfx/spreadsheet/GridViewSkin.java | 1138 ---------- .../spreadsheet/GridVirtualFlow.java | 426 ---- .../spreadsheet/HorizontalHeader.java | 349 --- .../spreadsheet/HorizontalHeaderColumn.java | 149 -- .../spreadsheet/HorizontalPicker.java | 152 -- .../spreadsheet/RectangleSelection.java | 436 ---- .../spreadsheet/SelectedCellsMapTemp.java | 205 -- .../spreadsheet/SpreadsheetGridView.java | 77 - .../spreadsheet/SpreadsheetHandle.java | 44 - .../TableViewSpanSelectionModel.java | 912 -------- .../spreadsheet/VerticalHeader.java | 675 ------ .../org/controlsfx/table/ColumnFilter.java | 308 --- .../org/controlsfx/table/DupeCounter.java | 52 - .../org/controlsfx/table/FilterPanel.java | 275 --- .../org/controlsfx/table/FilterValue.java | 68 - src/impl/org/controlsfx/table/filter.png | Bin 4700 -> 0 bytes src/impl/org/controlsfx/table/no_filter.png | Bin 7021 -> 0 bytes src/impl/org/controlsfx/table/tablefilter.css | 7 - src/impl/org/controlsfx/tools/MathTools.java | 96 - .../tools/PrefixSelectionCustomizer.java | 221 -- .../tools/rectangle/CoordinatePosition.java | 84 - .../tools/rectangle/CoordinatePositions.java | 222 -- .../controlsfx/tools/rectangle/Edge2D.java | 249 --- .../tools/rectangle/Rectangles2D.java | 796 ------- ...bstractBeginEndCheckingChangeStrategy.java | 149 -- .../AbstractFixedEdgeChangeStrategy.java | 137 -- .../AbstractFixedPointChangeStrategy.java | 139 -- ...stractPreviousRectangleChangeStrategy.java | 77 - ...AbstractRatioRespectingChangeStrategy.java | 86 - .../rectangle/change/MoveChangeStrategy.java | 166 -- .../rectangle/change/NewChangeStrategy.java | 82 - .../change/Rectangle2DChangeStrategy.java | 73 - .../change/ToEastChangeStrategy.java | 104 - .../change/ToNorthChangeStrategy.java | 104 - .../change/ToNortheastChangeStrategy.java | 80 - .../change/ToNorthwestChangeStrategy.java | 80 - .../change/ToSouthChangeStrategy.java | 104 - .../change/ToSoutheastChangeStrategy.java | 80 - .../change/ToSouthwestChangeStrategy.java | 82 - .../change/ToWestChangeStrategy.java | 104 - .../controlsfx/version/VersionChecker.java | 222 -- src/org/controlsfx/control/BreadCrumbBar.java | 343 --- .../control/CheckBitSetModelBase.java | 315 --- src/org/controlsfx/control/CheckComboBox.java | 297 --- src/org/controlsfx/control/CheckListView.java | 264 --- src/org/controlsfx/control/CheckModel.java | 66 - src/org/controlsfx/control/CheckTreeView.java | 327 --- .../controlsfx/control/ControlsFXControl.java | 63 - src/org/controlsfx/control/GridCell.java | 125 -- src/org/controlsfx/control/GridView.java | 560 ----- .../controlsfx/control/HiddenSidesPane.java | 426 ---- .../controlsfx/control/HyperlinkLabel.java | 211 -- .../controlsfx/control/IndexedCheckModel.java | 68 - src/org/controlsfx/control/InfoOverlay.java | 220 -- .../controlsfx/control/ListSelectionView.java | 370 ---- src/org/controlsfx/control/MaskerPane.java | 117 - .../controlsfx/control/MasterDetailPane.java | 386 ---- .../controlsfx/control/NotificationPane.java | 630 ------ src/org/controlsfx/control/Notifications.java | 645 ------ .../controlsfx/control/PlusMinusSlider.java | 345 --- src/org/controlsfx/control/PopOver.java | 1011 --------- .../control/PrefixSelectionChoiceBox.java | 77 - .../control/PrefixSelectionComboBox.java | 81 - src/org/controlsfx/control/PropertySheet.java | 452 ---- src/org/controlsfx/control/RangeSlider.java | 1102 ---------- src/org/controlsfx/control/Rating.java | 317 --- .../controlsfx/control/SegmentedButton.java | 241 --- src/org/controlsfx/control/SnapshotView.java | 1733 --------------- src/org/controlsfx/control/StatusBar.java | 211 -- .../controlsfx/control/TaskProgressView.java | 158 -- src/org/controlsfx/control/ToggleSwitch.java | 171 -- src/org/controlsfx/control/action/Action.java | 430 ---- .../control/action/ActionCheck.java | 21 - .../control/action/ActionGroup.java | 167 -- .../controlsfx/control/action/ActionMap.java | 224 -- .../control/action/ActionProxy.java | 138 -- .../control/action/ActionUtils.java | 890 -------- .../control/action/AnnotatedAction.java | 115 - .../action/AnnotatedActionFactory.java | 46 - .../control/action/AnnotatedCheckAction.java | 19 - .../control/action/DefaultActionFactory.java | 114 - .../control/action/package-info.java | 7 - src/org/controlsfx/control/breadcrumbbar.css | 3 - .../control/cell/ColorGridCell.java | 82 - .../control/cell/ImageGridCell.java | 85 - .../control/cell/MediaImageCell.java | 106 - .../controlsfx/control/cell/package-info.java | 9 - src/org/controlsfx/control/collapse.png | Bin 912 -> 0 bytes .../control/decoration/Decoration.java | 92 - .../control/decoration/Decorator.java | 241 --- .../control/decoration/GraphicDecoration.java | 193 -- .../decoration/StyleClassDecoration.java | 81 - .../control/decoration/package-info.java | 5 - src/org/controlsfx/control/expand.png | Bin 933 -> 0 bytes .../controlsfx/control/format-indent-more.png | Bin 532 -> 0 bytes .../control/format-line-spacing-triple.png | Bin 499 -> 0 bytes src/org/controlsfx/control/gridview.css | 7 - src/org/controlsfx/control/info-overlay.css | 15 - .../controlsfx/control/listselectionview.css | 13 - src/org/controlsfx/control/maskerpane.css | 17 - .../controlsfx/control/masterdetailpane.css | 14 - .../controlsfx/control/notificationpane.css | 103 - .../controlsfx/control/notificationpopup.css | 79 - src/org/controlsfx/control/open-editor.png | Bin 238 -> 0 bytes src/org/controlsfx/control/package-info.java | 5 - .../controlsfx/control/plusminusslider.css | 57 - src/org/controlsfx/control/popover.css | 36 - src/org/controlsfx/control/propertysheet.css | 15 - src/org/controlsfx/control/rangeslider.css | 86 - src/org/controlsfx/control/rating.css | 15 - .../controlsfx/control/segmentedbutton.css | 79 - src/org/controlsfx/control/selected-star.png | Bin 2118 -> 0 bytes src/org/controlsfx/control/snapshot-view.css | 4 - .../controlsfx/control/spreadsheet/Grid.java | 200 -- .../control/spreadsheet/GridBase.java | 414 ---- .../control/spreadsheet/GridChange.java | 126 -- .../control/spreadsheet/Picker.java | 93 - .../control/spreadsheet/SpreadsheetCell.java | 333 --- .../spreadsheet/SpreadsheetCellBase.java | 643 ------ .../spreadsheet/SpreadsheetCellEditor.java | 927 -------- .../spreadsheet/SpreadsheetCellType.java | 858 -------- .../spreadsheet/SpreadsheetColumn.java | 372 ---- .../control/spreadsheet/SpreadsheetView.java | 1928 ----------------- .../SpreadsheetViewSelectionModel.java | 237 -- .../StringConverterWithFormat.java | 77 - .../control/spreadsheet/comment.png | Bin 673 -> 0 bytes .../spreadsheet/copySpreadsheetView.png | Bin 518 -> 0 bytes .../control/spreadsheet/package-info.java | 5 - .../spreadsheet/pasteSpreadsheetView.png | Bin 639 -> 0 bytes .../controlsfx/control/spreadsheet/picker.png | Bin 382 -> 0 bytes .../spreadsheet/pinSpreadsheetView.png | Bin 525 -> 0 bytes .../control/spreadsheet/spreadsheet.css | 150 -- src/org/controlsfx/control/statusbar.css | 6 - .../controlsfx/control/table/TableFilter.java | 225 -- .../control/table/TableRowExpanderColumn.java | 325 --- .../control/table/TableViewUtils.java | 138 -- .../control/table/model/JavaFXTableModel.java | 47 - .../table/model/JavaFXTableModels.java | 100 - .../control/table/model/TableModelRow.java | 60 - .../table/model/TableModelTableView.java | 66 - .../table/model/TableModelValueFactory.java | 55 - .../controlsfx/control/taskprogressview.css | 53 - .../textfield/AutoCompletionBinding.java | 558 ----- .../textfield/CustomPasswordField.java | 171 -- .../control/textfield/CustomTextField.java | 178 -- .../control/textfield/TextFields.java | 190 -- .../control/textfield/autocompletion.css | 31 - .../control/textfield/customtextfield.css | 89 - .../control/textfield/package-info.java | 4 - src/org/controlsfx/control/toggleswitch.css | 51 - .../controlsfx/control/unselected-star.png | Bin 2252 -> 0 bytes .../controlsfx/dialog/CommandLinksDialog.java | 298 --- src/org/controlsfx/dialog/DialogUtils.java | 61 - .../controlsfx/dialog/ExceptionDialog.java | 84 - .../controlsfx/dialog/FontSelectorDialog.java | 367 ---- src/org/controlsfx/dialog/LoginDialog.java | 152 -- src/org/controlsfx/dialog/ProgressDialog.java | 215 -- src/org/controlsfx/dialog/Wizard.java | 737 ------- src/org/controlsfx/dialog/WizardPane.java | 64 - .../controlsfx/dialog/arrow-green-right.png | Bin 3526 -> 0 bytes src/org/controlsfx/dialog/commandlink.css | 71 - src/org/controlsfx/dialog/dialog-confirm.png | Bin 3901 -> 0 bytes src/org/controlsfx/dialog/dialog-error.png | Bin 2561 -> 0 bytes .../controlsfx/dialog/dialog-information.png | Bin 3594 -> 0 bytes src/org/controlsfx/dialog/dialog-warning.png | Bin 2443 -> 0 bytes src/org/controlsfx/dialog/dialogs.css | 13 - src/org/controlsfx/dialog/fewer-details.png | Bin 933 -> 0 bytes src/org/controlsfx/dialog/license.txt | 7 - src/org/controlsfx/dialog/lock.png | Bin 242 -> 0 bytes src/org/controlsfx/dialog/more-details.png | Bin 912 -> 0 bytes src/org/controlsfx/dialog/package-info.java | 5 - src/org/controlsfx/dialog/user.png | Bin 420 -> 0 bytes src/org/controlsfx/dialog/wizard-page.png | Bin 5830 -> 0 bytes src/org/controlsfx/dialog/wizard.css | 3 - src/org/controlsfx/glyphfont/FontAwesome.java | 723 ------- src/org/controlsfx/glyphfont/Glyph.java | 350 --- src/org/controlsfx/glyphfont/GlyphFont.java | 245 --- .../glyphfont/GlyphFontRegistry.java | 127 -- .../controlsfx/glyphfont/INamedCharacter.java | 44 - src/org/controlsfx/glyphfont/glyphfont.css | 16 - .../controlsfx/glyphfont/package-info.java | 5 - src/org/controlsfx/property/BeanProperty.java | 208 -- .../property/BeanPropertyUtils.java | 96 - .../property/editor/AbstractObjectField.java | 91 - .../editor/AbstractPropertyEditor.java | 139 -- .../editor/DefaultPropertyEditorFactory.java | 115 - .../controlsfx/property/editor/Editors.java | 232 -- .../property/editor/NumericField.java | 150 -- .../property/editor/PropertyEditor.java | 57 - .../property/editor/package-info.java | 5 - src/org/controlsfx/property/package-info.java | 5 - src/org/controlsfx/tools/Borders.java | 807 ------- src/org/controlsfx/tools/Duplicatable.java | 42 - src/org/controlsfx/tools/Platform.java | 84 - src/org/controlsfx/tools/SVGLoader.java | 227 -- src/org/controlsfx/tools/Utils.java | 113 - src/org/controlsfx/tools/ValueExtractor.java | 170 -- src/org/controlsfx/tools/package-info.java | 4 - src/org/controlsfx/validation/Severity.java | 37 - .../validation/SimpleValidationMessage.java | 95 - .../validation/ValidationMessage.java | 91 - .../validation/ValidationResult.java | 276 --- .../validation/ValidationSupport.java | 329 --- src/org/controlsfx/validation/Validator.java | 158 -- .../AbstractValidationDecoration.java | 105 - .../CompoundValidationDecoration.java | 93 - .../GraphicValidationDecoration.java | 127 -- .../StyleClassValidationDecoration.java | 80 - .../decoration/ValidationDecoration.java | 59 - .../validation/decoration/package-info.java | 4 - .../controlsfx/validation/package-info.java | 5 - 264 files changed, 52486 deletions(-) delete mode 100644 lib/controlsfx-8.40.12-sources/META-INF/MANIFEST.MF delete mode 100644 lib/controlsfx-8.40.12-sources/META-INF/services/org.controlsfx.glyphfont.GlyphFont delete mode 100644 src/impl/build/transifex/JSON.java delete mode 100644 src/impl/build/transifex/Transifex.java delete mode 100644 src/impl/org/controlsfx/ImplUtils.java delete mode 100644 src/impl/org/controlsfx/autocompletion/AutoCompletionTextFieldBinding.java delete mode 100644 src/impl/org/controlsfx/autocompletion/SuggestionProvider.java delete mode 100644 src/impl/org/controlsfx/behavior/RangeSliderBehavior.java delete mode 100644 src/impl/org/controlsfx/behavior/RatingBehavior.java delete mode 100644 src/impl/org/controlsfx/behavior/SnapshotViewBehavior.java delete mode 100644 src/impl/org/controlsfx/control/validation/decoration-error.png delete mode 100644 src/impl/org/controlsfx/control/validation/decoration-warning.png delete mode 100644 src/impl/org/controlsfx/control/validation/required-indicator.png delete mode 100644 src/impl/org/controlsfx/i18n/Localization.java delete mode 100644 src/impl/org/controlsfx/i18n/SimpleLocalizedStringProperty.java delete mode 100644 src/impl/org/controlsfx/i18n/Translation.java delete mode 100644 src/impl/org/controlsfx/i18n/Translations.java delete mode 100644 src/impl/org/controlsfx/skin/AutoCompletePopup.java delete mode 100644 src/impl/org/controlsfx/skin/AutoCompletePopupSkin.java delete mode 100644 src/impl/org/controlsfx/skin/BreadCrumbBarSkin.java delete mode 100644 src/impl/org/controlsfx/skin/CheckComboBoxSkin.java delete mode 100644 src/impl/org/controlsfx/skin/CustomTextFieldSkin.java delete mode 100644 src/impl/org/controlsfx/skin/DecorationPane.java delete mode 100644 src/impl/org/controlsfx/skin/ExpandableTableRowSkin.java delete mode 100644 src/impl/org/controlsfx/skin/GridCellSkin.java delete mode 100644 src/impl/org/controlsfx/skin/GridRow.java delete mode 100644 src/impl/org/controlsfx/skin/GridRowSkin.java delete mode 100644 src/impl/org/controlsfx/skin/GridViewSkin.java delete mode 100644 src/impl/org/controlsfx/skin/HiddenSidesPaneSkin.java delete mode 100644 src/impl/org/controlsfx/skin/HyperlinkLabelSkin.java delete mode 100644 src/impl/org/controlsfx/skin/InfoOverlaySkin.java delete mode 100644 src/impl/org/controlsfx/skin/ListSelectionViewSkin.java delete mode 100644 src/impl/org/controlsfx/skin/MaskerPaneSkin.java delete mode 100644 src/impl/org/controlsfx/skin/MasterDetailPaneSkin.java delete mode 100644 src/impl/org/controlsfx/skin/NotificationBar.java delete mode 100644 src/impl/org/controlsfx/skin/NotificationPaneSkin.java delete mode 100644 src/impl/org/controlsfx/skin/PlusMinusSliderSkin.java delete mode 100644 src/impl/org/controlsfx/skin/PopOverSkin.java delete mode 100644 src/impl/org/controlsfx/skin/PropertySheetSkin.java delete mode 100644 src/impl/org/controlsfx/skin/RangeSliderSkin.java delete mode 100644 src/impl/org/controlsfx/skin/RatingSkin.java delete mode 100644 src/impl/org/controlsfx/skin/SegmentedButtonSkin.java delete mode 100644 src/impl/org/controlsfx/skin/SnapshotViewSkin.java delete mode 100644 src/impl/org/controlsfx/skin/StatusBarSkin.java delete mode 100644 src/impl/org/controlsfx/skin/TaskProgressViewSkin.java delete mode 100644 src/impl/org/controlsfx/skin/ToggleSwitchSkin.java delete mode 100644 src/impl/org/controlsfx/spreadsheet/CellView.java delete mode 100644 src/impl/org/controlsfx/spreadsheet/CellViewSkin.java delete mode 100644 src/impl/org/controlsfx/spreadsheet/FocusModelListener.java delete mode 100644 src/impl/org/controlsfx/spreadsheet/GridCellEditor.java delete mode 100644 src/impl/org/controlsfx/spreadsheet/GridRow.java delete mode 100644 src/impl/org/controlsfx/spreadsheet/GridRowSkin.java delete mode 100644 src/impl/org/controlsfx/spreadsheet/GridViewBehavior.java delete mode 100644 src/impl/org/controlsfx/spreadsheet/GridViewSkin.java delete mode 100644 src/impl/org/controlsfx/spreadsheet/GridVirtualFlow.java delete mode 100644 src/impl/org/controlsfx/spreadsheet/HorizontalHeader.java delete mode 100644 src/impl/org/controlsfx/spreadsheet/HorizontalHeaderColumn.java delete mode 100644 src/impl/org/controlsfx/spreadsheet/HorizontalPicker.java delete mode 100644 src/impl/org/controlsfx/spreadsheet/RectangleSelection.java delete mode 100644 src/impl/org/controlsfx/spreadsheet/SelectedCellsMapTemp.java delete mode 100644 src/impl/org/controlsfx/spreadsheet/SpreadsheetGridView.java delete mode 100644 src/impl/org/controlsfx/spreadsheet/SpreadsheetHandle.java delete mode 100644 src/impl/org/controlsfx/spreadsheet/TableViewSpanSelectionModel.java delete mode 100644 src/impl/org/controlsfx/spreadsheet/VerticalHeader.java delete mode 100644 src/impl/org/controlsfx/table/ColumnFilter.java delete mode 100644 src/impl/org/controlsfx/table/DupeCounter.java delete mode 100644 src/impl/org/controlsfx/table/FilterPanel.java delete mode 100644 src/impl/org/controlsfx/table/FilterValue.java delete mode 100644 src/impl/org/controlsfx/table/filter.png delete mode 100644 src/impl/org/controlsfx/table/no_filter.png delete mode 100644 src/impl/org/controlsfx/table/tablefilter.css delete mode 100644 src/impl/org/controlsfx/tools/MathTools.java delete mode 100644 src/impl/org/controlsfx/tools/PrefixSelectionCustomizer.java delete mode 100644 src/impl/org/controlsfx/tools/rectangle/CoordinatePosition.java delete mode 100644 src/impl/org/controlsfx/tools/rectangle/CoordinatePositions.java delete mode 100644 src/impl/org/controlsfx/tools/rectangle/Edge2D.java delete mode 100644 src/impl/org/controlsfx/tools/rectangle/Rectangles2D.java delete mode 100644 src/impl/org/controlsfx/tools/rectangle/change/AbstractBeginEndCheckingChangeStrategy.java delete mode 100644 src/impl/org/controlsfx/tools/rectangle/change/AbstractFixedEdgeChangeStrategy.java delete mode 100644 src/impl/org/controlsfx/tools/rectangle/change/AbstractFixedPointChangeStrategy.java delete mode 100644 src/impl/org/controlsfx/tools/rectangle/change/AbstractPreviousRectangleChangeStrategy.java delete mode 100644 src/impl/org/controlsfx/tools/rectangle/change/AbstractRatioRespectingChangeStrategy.java delete mode 100644 src/impl/org/controlsfx/tools/rectangle/change/MoveChangeStrategy.java delete mode 100644 src/impl/org/controlsfx/tools/rectangle/change/NewChangeStrategy.java delete mode 100644 src/impl/org/controlsfx/tools/rectangle/change/Rectangle2DChangeStrategy.java delete mode 100644 src/impl/org/controlsfx/tools/rectangle/change/ToEastChangeStrategy.java delete mode 100644 src/impl/org/controlsfx/tools/rectangle/change/ToNorthChangeStrategy.java delete mode 100644 src/impl/org/controlsfx/tools/rectangle/change/ToNortheastChangeStrategy.java delete mode 100644 src/impl/org/controlsfx/tools/rectangle/change/ToNorthwestChangeStrategy.java delete mode 100644 src/impl/org/controlsfx/tools/rectangle/change/ToSouthChangeStrategy.java delete mode 100644 src/impl/org/controlsfx/tools/rectangle/change/ToSoutheastChangeStrategy.java delete mode 100644 src/impl/org/controlsfx/tools/rectangle/change/ToSouthwestChangeStrategy.java delete mode 100644 src/impl/org/controlsfx/tools/rectangle/change/ToWestChangeStrategy.java delete mode 100644 src/impl/org/controlsfx/version/VersionChecker.java delete mode 100644 src/org/controlsfx/control/BreadCrumbBar.java delete mode 100644 src/org/controlsfx/control/CheckBitSetModelBase.java delete mode 100644 src/org/controlsfx/control/CheckComboBox.java delete mode 100644 src/org/controlsfx/control/CheckListView.java delete mode 100644 src/org/controlsfx/control/CheckModel.java delete mode 100644 src/org/controlsfx/control/CheckTreeView.java delete mode 100644 src/org/controlsfx/control/ControlsFXControl.java delete mode 100644 src/org/controlsfx/control/GridCell.java delete mode 100644 src/org/controlsfx/control/GridView.java delete mode 100644 src/org/controlsfx/control/HiddenSidesPane.java delete mode 100644 src/org/controlsfx/control/HyperlinkLabel.java delete mode 100644 src/org/controlsfx/control/IndexedCheckModel.java delete mode 100644 src/org/controlsfx/control/InfoOverlay.java delete mode 100644 src/org/controlsfx/control/ListSelectionView.java delete mode 100644 src/org/controlsfx/control/MaskerPane.java delete mode 100644 src/org/controlsfx/control/MasterDetailPane.java delete mode 100644 src/org/controlsfx/control/NotificationPane.java delete mode 100644 src/org/controlsfx/control/Notifications.java delete mode 100644 src/org/controlsfx/control/PlusMinusSlider.java delete mode 100644 src/org/controlsfx/control/PopOver.java delete mode 100644 src/org/controlsfx/control/PrefixSelectionChoiceBox.java delete mode 100644 src/org/controlsfx/control/PrefixSelectionComboBox.java delete mode 100644 src/org/controlsfx/control/PropertySheet.java delete mode 100644 src/org/controlsfx/control/RangeSlider.java delete mode 100644 src/org/controlsfx/control/Rating.java delete mode 100644 src/org/controlsfx/control/SegmentedButton.java delete mode 100644 src/org/controlsfx/control/SnapshotView.java delete mode 100644 src/org/controlsfx/control/StatusBar.java delete mode 100644 src/org/controlsfx/control/TaskProgressView.java delete mode 100644 src/org/controlsfx/control/ToggleSwitch.java delete mode 100644 src/org/controlsfx/control/action/Action.java delete mode 100644 src/org/controlsfx/control/action/ActionCheck.java delete mode 100644 src/org/controlsfx/control/action/ActionGroup.java delete mode 100644 src/org/controlsfx/control/action/ActionMap.java delete mode 100644 src/org/controlsfx/control/action/ActionProxy.java delete mode 100644 src/org/controlsfx/control/action/ActionUtils.java delete mode 100644 src/org/controlsfx/control/action/AnnotatedAction.java delete mode 100644 src/org/controlsfx/control/action/AnnotatedActionFactory.java delete mode 100644 src/org/controlsfx/control/action/AnnotatedCheckAction.java delete mode 100644 src/org/controlsfx/control/action/DefaultActionFactory.java delete mode 100644 src/org/controlsfx/control/action/package-info.java delete mode 100644 src/org/controlsfx/control/breadcrumbbar.css delete mode 100644 src/org/controlsfx/control/cell/ColorGridCell.java delete mode 100644 src/org/controlsfx/control/cell/ImageGridCell.java delete mode 100644 src/org/controlsfx/control/cell/MediaImageCell.java delete mode 100644 src/org/controlsfx/control/cell/package-info.java delete mode 100644 src/org/controlsfx/control/collapse.png delete mode 100644 src/org/controlsfx/control/decoration/Decoration.java delete mode 100644 src/org/controlsfx/control/decoration/Decorator.java delete mode 100644 src/org/controlsfx/control/decoration/GraphicDecoration.java delete mode 100644 src/org/controlsfx/control/decoration/StyleClassDecoration.java delete mode 100644 src/org/controlsfx/control/decoration/package-info.java delete mode 100644 src/org/controlsfx/control/expand.png delete mode 100644 src/org/controlsfx/control/format-indent-more.png delete mode 100644 src/org/controlsfx/control/format-line-spacing-triple.png delete mode 100644 src/org/controlsfx/control/gridview.css delete mode 100644 src/org/controlsfx/control/info-overlay.css delete mode 100644 src/org/controlsfx/control/listselectionview.css delete mode 100644 src/org/controlsfx/control/maskerpane.css delete mode 100644 src/org/controlsfx/control/masterdetailpane.css delete mode 100644 src/org/controlsfx/control/notificationpane.css delete mode 100644 src/org/controlsfx/control/notificationpopup.css delete mode 100644 src/org/controlsfx/control/open-editor.png delete mode 100644 src/org/controlsfx/control/package-info.java delete mode 100644 src/org/controlsfx/control/plusminusslider.css delete mode 100644 src/org/controlsfx/control/popover.css delete mode 100644 src/org/controlsfx/control/propertysheet.css delete mode 100644 src/org/controlsfx/control/rangeslider.css delete mode 100644 src/org/controlsfx/control/rating.css delete mode 100644 src/org/controlsfx/control/segmentedbutton.css delete mode 100644 src/org/controlsfx/control/selected-star.png delete mode 100644 src/org/controlsfx/control/snapshot-view.css delete mode 100644 src/org/controlsfx/control/spreadsheet/Grid.java delete mode 100644 src/org/controlsfx/control/spreadsheet/GridBase.java delete mode 100644 src/org/controlsfx/control/spreadsheet/GridChange.java delete mode 100644 src/org/controlsfx/control/spreadsheet/Picker.java delete mode 100644 src/org/controlsfx/control/spreadsheet/SpreadsheetCell.java delete mode 100644 src/org/controlsfx/control/spreadsheet/SpreadsheetCellBase.java delete mode 100644 src/org/controlsfx/control/spreadsheet/SpreadsheetCellEditor.java delete mode 100644 src/org/controlsfx/control/spreadsheet/SpreadsheetCellType.java delete mode 100644 src/org/controlsfx/control/spreadsheet/SpreadsheetColumn.java delete mode 100644 src/org/controlsfx/control/spreadsheet/SpreadsheetView.java delete mode 100644 src/org/controlsfx/control/spreadsheet/SpreadsheetViewSelectionModel.java delete mode 100644 src/org/controlsfx/control/spreadsheet/StringConverterWithFormat.java delete mode 100644 src/org/controlsfx/control/spreadsheet/comment.png delete mode 100644 src/org/controlsfx/control/spreadsheet/copySpreadsheetView.png delete mode 100644 src/org/controlsfx/control/spreadsheet/package-info.java delete mode 100644 src/org/controlsfx/control/spreadsheet/pasteSpreadsheetView.png delete mode 100644 src/org/controlsfx/control/spreadsheet/picker.png delete mode 100644 src/org/controlsfx/control/spreadsheet/pinSpreadsheetView.png delete mode 100644 src/org/controlsfx/control/spreadsheet/spreadsheet.css delete mode 100644 src/org/controlsfx/control/statusbar.css delete mode 100644 src/org/controlsfx/control/table/TableFilter.java delete mode 100644 src/org/controlsfx/control/table/TableRowExpanderColumn.java delete mode 100644 src/org/controlsfx/control/table/TableViewUtils.java delete mode 100644 src/org/controlsfx/control/table/model/JavaFXTableModel.java delete mode 100644 src/org/controlsfx/control/table/model/JavaFXTableModels.java delete mode 100644 src/org/controlsfx/control/table/model/TableModelRow.java delete mode 100644 src/org/controlsfx/control/table/model/TableModelTableView.java delete mode 100644 src/org/controlsfx/control/table/model/TableModelValueFactory.java delete mode 100644 src/org/controlsfx/control/taskprogressview.css delete mode 100644 src/org/controlsfx/control/textfield/AutoCompletionBinding.java delete mode 100644 src/org/controlsfx/control/textfield/CustomPasswordField.java delete mode 100644 src/org/controlsfx/control/textfield/CustomTextField.java delete mode 100644 src/org/controlsfx/control/textfield/TextFields.java delete mode 100644 src/org/controlsfx/control/textfield/autocompletion.css delete mode 100644 src/org/controlsfx/control/textfield/customtextfield.css delete mode 100644 src/org/controlsfx/control/textfield/package-info.java delete mode 100644 src/org/controlsfx/control/toggleswitch.css delete mode 100644 src/org/controlsfx/control/unselected-star.png delete mode 100644 src/org/controlsfx/dialog/CommandLinksDialog.java delete mode 100644 src/org/controlsfx/dialog/DialogUtils.java delete mode 100644 src/org/controlsfx/dialog/ExceptionDialog.java delete mode 100644 src/org/controlsfx/dialog/FontSelectorDialog.java delete mode 100644 src/org/controlsfx/dialog/LoginDialog.java delete mode 100644 src/org/controlsfx/dialog/ProgressDialog.java delete mode 100644 src/org/controlsfx/dialog/Wizard.java delete mode 100644 src/org/controlsfx/dialog/WizardPane.java delete mode 100644 src/org/controlsfx/dialog/arrow-green-right.png delete mode 100644 src/org/controlsfx/dialog/commandlink.css delete mode 100644 src/org/controlsfx/dialog/dialog-confirm.png delete mode 100644 src/org/controlsfx/dialog/dialog-error.png delete mode 100644 src/org/controlsfx/dialog/dialog-information.png delete mode 100644 src/org/controlsfx/dialog/dialog-warning.png delete mode 100644 src/org/controlsfx/dialog/dialogs.css delete mode 100644 src/org/controlsfx/dialog/fewer-details.png delete mode 100644 src/org/controlsfx/dialog/license.txt delete mode 100644 src/org/controlsfx/dialog/lock.png delete mode 100644 src/org/controlsfx/dialog/more-details.png delete mode 100644 src/org/controlsfx/dialog/package-info.java delete mode 100644 src/org/controlsfx/dialog/user.png delete mode 100644 src/org/controlsfx/dialog/wizard-page.png delete mode 100644 src/org/controlsfx/dialog/wizard.css delete mode 100644 src/org/controlsfx/glyphfont/FontAwesome.java delete mode 100644 src/org/controlsfx/glyphfont/Glyph.java delete mode 100644 src/org/controlsfx/glyphfont/GlyphFont.java delete mode 100644 src/org/controlsfx/glyphfont/GlyphFontRegistry.java delete mode 100644 src/org/controlsfx/glyphfont/INamedCharacter.java delete mode 100644 src/org/controlsfx/glyphfont/glyphfont.css delete mode 100644 src/org/controlsfx/glyphfont/package-info.java delete mode 100644 src/org/controlsfx/property/BeanProperty.java delete mode 100644 src/org/controlsfx/property/BeanPropertyUtils.java delete mode 100644 src/org/controlsfx/property/editor/AbstractObjectField.java delete mode 100644 src/org/controlsfx/property/editor/AbstractPropertyEditor.java delete mode 100644 src/org/controlsfx/property/editor/DefaultPropertyEditorFactory.java delete mode 100644 src/org/controlsfx/property/editor/Editors.java delete mode 100644 src/org/controlsfx/property/editor/NumericField.java delete mode 100644 src/org/controlsfx/property/editor/PropertyEditor.java delete mode 100644 src/org/controlsfx/property/editor/package-info.java delete mode 100644 src/org/controlsfx/property/package-info.java delete mode 100644 src/org/controlsfx/tools/Borders.java delete mode 100644 src/org/controlsfx/tools/Duplicatable.java delete mode 100644 src/org/controlsfx/tools/Platform.java delete mode 100644 src/org/controlsfx/tools/SVGLoader.java delete mode 100644 src/org/controlsfx/tools/Utils.java delete mode 100644 src/org/controlsfx/tools/ValueExtractor.java delete mode 100644 src/org/controlsfx/tools/package-info.java delete mode 100644 src/org/controlsfx/validation/Severity.java delete mode 100644 src/org/controlsfx/validation/SimpleValidationMessage.java delete mode 100644 src/org/controlsfx/validation/ValidationMessage.java delete mode 100644 src/org/controlsfx/validation/ValidationResult.java delete mode 100644 src/org/controlsfx/validation/ValidationSupport.java delete mode 100644 src/org/controlsfx/validation/Validator.java delete mode 100644 src/org/controlsfx/validation/decoration/AbstractValidationDecoration.java delete mode 100644 src/org/controlsfx/validation/decoration/CompoundValidationDecoration.java delete mode 100644 src/org/controlsfx/validation/decoration/GraphicValidationDecoration.java delete mode 100644 src/org/controlsfx/validation/decoration/StyleClassValidationDecoration.java delete mode 100644 src/org/controlsfx/validation/decoration/ValidationDecoration.java delete mode 100644 src/org/controlsfx/validation/decoration/package-info.java delete mode 100644 src/org/controlsfx/validation/package-info.java diff --git a/lib/controlsfx-8.40.12-sources/META-INF/MANIFEST.MF b/lib/controlsfx-8.40.12-sources/META-INF/MANIFEST.MF deleted file mode 100644 index 58630c0..0000000 --- a/lib/controlsfx-8.40.12-sources/META-INF/MANIFEST.MF +++ /dev/null @@ -1,2 +0,0 @@ -Manifest-Version: 1.0 - diff --git a/lib/controlsfx-8.40.12-sources/META-INF/services/org.controlsfx.glyphfont.GlyphFont b/lib/controlsfx-8.40.12-sources/META-INF/services/org.controlsfx.glyphfont.GlyphFont deleted file mode 100644 index 1d1eed7..0000000 --- a/lib/controlsfx-8.40.12-sources/META-INF/services/org.controlsfx.glyphfont.GlyphFont +++ /dev/null @@ -1 +0,0 @@ -org.controlsfx.glyphfont.FontAwesome \ No newline at end of file diff --git a/src/impl/build/transifex/JSON.java b/src/impl/build/transifex/JSON.java deleted file mode 100644 index 044bf30..0000000 --- a/src/impl/build/transifex/JSON.java +++ /dev/null @@ -1,140 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.build.transifex; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -class JSON { - private static final Pattern PAT_INTEGER = Pattern.compile("[-+]?[0-9]+|0[Xx][0-9]+"); //$NON-NLS-1$ - private static final Pattern PAT_DOUBLE = Pattern.compile("[+-]?[0-9]+([Ee][+-]?[0-9]+)?|[+-]?[0-9]*\\.[0-9]*([Ee][+-]?[0-9]+)?"); //$NON-NLS-1$ - private static final Pattern PAT_STRING = Pattern.compile("\"([^\\\\]+\\\\[\"'\\\\])*[^\"]*\"|'([^\\\\]+\\\\[\"'\\\\])*[^']*'"); //$NON-NLS-1$ - private static final Pattern PAT_BOOL = Pattern.compile("(true)|(false)"); //$NON-NLS-1$ - - private static Object parse(String s, int[] start, Matcher integerMatcher, Matcher doubleMatcher, Matcher stringMatcher, Matcher booleanMatcher) { - char[] c = s.toCharArray(); - skipSpace(s, start); - if (c[start[0]] == '[') { - start[0]++; - ArrayList<Object> a = new ArrayList<>(); - if (c[start[0]] == ']') { - start[0]++; - return a; - } - while (true) { - a.add(parse(s, start, integerMatcher, doubleMatcher, stringMatcher, booleanMatcher)); - boolean crlf = skipSpace(s, start); - char p = c[start[0]]; - if (p == ']') { - start[0]++; - return a; - } - if (p == ',') - start[0]++; - else if (!crlf) - throw new IllegalStateException(", or ] expected"); //$NON-NLS-1$ - } - } else if (c[start[0]] == '{') { - start[0]++; - HashMap<String, Object> a = new HashMap<>(); - while (true) { - String field = (String) parse(s, start, integerMatcher, doubleMatcher, stringMatcher, booleanMatcher); - boolean crlf = skipSpace(s, start); - if (c[start[0]] == ':') { - start[0]++; - a.put(field, parse(s, start, integerMatcher, doubleMatcher, stringMatcher, booleanMatcher)); - crlf = skipSpace(s, start); - } else - a.put(field, ""); //$NON-NLS-1$ - char p = c[start[0]]; - if (p == '}') { - start[0]++; - return a; - } - if (p == ',') - start[0]++; - else if (!crlf) { - start[0]++; -// throw new IllegalStateException(", or } expected at " + start[0]); //$NON-NLS-1$ - } - } - } - if (integerMatcher.find(start[0])) { - String substring = match(start, s, integerMatcher); - if (substring != null) return Integer.valueOf(substring); - } - if (doubleMatcher.find(start[0])) { - String substring = match(start, s, doubleMatcher); - if (substring != null) return Double.valueOf(substring); - } - if (stringMatcher.find(start[0])) { - String substring = match(start, s, stringMatcher); - if (substring != null) return substring.substring(1, substring.length() - 1); - } - if (booleanMatcher.find(start[0])) { - String substring = match(start, s, booleanMatcher); - if (substring != null) return Boolean.valueOf(substring); - } -// throw new IllegalStateException("unexpected end of data"); //$NON-NLS-1$ - return null; - } - - private static String match(int[] start, String s, Matcher matcher) { - int ms = matcher.start(); - int me = matcher.end(); - if (start[0] == ms) { - start[0] = me; - return s.substring(ms, me); - } - return null; - } - - public static boolean skipSpace(String s, int[] start) { - boolean ret = false; - while (true) { - char c = s.charAt(start[0]); - boolean crlf = (c == '\r') || (c == '\n'); - if ((c != ' ') && !crlf) - break; - if (crlf) - ret = true; - start[0]++; - } - return ret; - } - - @SuppressWarnings("unchecked") - public static <T> T parse(String json) { - Matcher integerMatcher = PAT_INTEGER.matcher(json); - Matcher doubleMatcher = PAT_DOUBLE.matcher(json); - Matcher stringMatcher = PAT_STRING.matcher(json); - Matcher booleanMatcher = PAT_BOOL.matcher(json); - return (T) parse(json, new int[]{0}, integerMatcher, doubleMatcher, stringMatcher, booleanMatcher); - } -} \ No newline at end of file diff --git a/src/impl/build/transifex/Transifex.java b/src/impl/build/transifex/Transifex.java deleted file mode 100644 index 37e4696..0000000 --- a/src/impl/build/transifex/Transifex.java +++ /dev/null @@ -1,179 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.build.transifex; -import java.io.BufferedReader; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.UnsupportedEncodingException; -import java.net.HttpURLConnection; -import java.net.URL; -import java.nio.channels.Channels; -import java.nio.channels.ReadableByteChannel; -import java.util.Base64; -import java.util.List; -import java.util.Map; -import java.util.function.Function; - -public class Transifex { - - private static final String CHARSET = "ISO-8859-1"; //$NON-NLS-1$ - private static final String FILE_NAME = "controlsfx_%1s.utf8"; //$NON-NLS-1$ - private static final String NEW_LINE = System.getProperty("line.separator"); //$NON-NLS-1$ - - private static final String BASE_URI = "https://www.transifex.com/api/2/"; //$NON-NLS-1$ - private static final String PROJECT_PATH = BASE_URI + "project/controlsfx/resource/controlsfx-core"; // list simple project details //$NON-NLS-1$ - private static final String PROJECT_DETAILS = BASE_URI + "project/controlsfx/resource/controlsfx-core?details"; // list all project details //$NON-NLS-1$ - private static final String LIST_TRANSLATIONS = BASE_URI + "project/controlsfx/languages/"; // list all translations //$NON-NLS-1$ - private static final String GET_TRANSLATION = BASE_URI + "project/controlsfx/resource/controlsfx-core/translation/%1s?file"; // gets a translation for one language //$NON-NLS-1$ - private static final String TRANSLATION_STATS = BASE_URI + "project/controlsfx/resource/controlsfx-core/stats/%1s/"; // gets a translation for one language //$NON-NLS-1$ - - private static final String USERNAME = System.getProperty("transifex.username"); //$NON-NLS-1$ - private static final String PASSWORD = System.getProperty("transifex.password"); //$NON-NLS-1$ - private static final boolean FILTER_INCOMPLETE_TRANSLATIONS = Boolean.parseBoolean(System.getProperty("transifex.filterIncompleteTranslations", "true")); - - public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException { - new Transifex().doTransifexCheck(); - } - - @SuppressWarnings("unchecked") - private void doTransifexCheck() { - System.out.println("=== Starting Transifex Check ==="); //$NON-NLS-1$ - - if (USERNAME == null || PASSWORD == null || USERNAME.isEmpty() || PASSWORD.isEmpty()) { - System.out.println(" transifex.username and transifex.password system properties must be specified"); //$NON-NLS-1$ - return; - } - - System.out.println(" Filtering out incomplete translations: " + FILTER_INCOMPLETE_TRANSLATIONS); - - Map<String,Object> projectDetails = JSON.parse(transifexRequest(PROJECT_DETAILS)); - List<Map<String, String>> availableLanguages = (List<Map<String, String>>) projectDetails.get("available_languages"); - - // main loop - availableLanguages.parallelStream() - .map(map -> map.get("code")) //$NON-NLS-1$ - .filter(this::filterOutIncompleteTranslations) - .forEach(this::downloadTranslation); - - System.out.println("Transifex Check Complete"); //$NON-NLS-1$ - } - - private String transifexRequest(String request, Object... args) { - Function<InputStream, String> consumer = inputStream -> { - StringBuilder response = new StringBuilder(); - try(BufferedReader rd = new BufferedReader(new InputStreamReader(inputStream)) ) { - String line; - while((line = rd.readLine()) != null) { - response.append(line); - response.append(NEW_LINE); - } - } catch (IOException e) { - e.printStackTrace(); - } - - return response.toString(); - }; - return performTransifexTask(consumer, request, args); - } - - private static <T> T performTransifexTask(Function<InputStream, T> consumer, String request, Object... args) { - request = String.format(request, args); - - URL url; - HttpURLConnection connection = null; - try { - url = new URL(request); - connection = (HttpURLConnection)url.openConnection(); - connection.setRequestMethod("GET"); //$NON-NLS-1$ - connection.setUseCaches(false); - connection.setDoInput(true); - - // pass in username / password - String encoded = Base64.getEncoder().encodeToString((USERNAME+":"+PASSWORD).getBytes()); //$NON-NLS-1$ - connection.setRequestProperty("Authorization", "Basic "+encoded); //$NON-NLS-1$ //$NON-NLS-2$ - connection.setRequestProperty("Accept-Charset", CHARSET); //$NON-NLS-1$ - - return consumer.apply(connection.getInputStream()); - } catch (Exception e) { - e.printStackTrace(); - } finally { - if (connection != null) { - connection.disconnect(); - } - } - - return null; - } - - private boolean filterOutIncompleteTranslations(String languageCode) { - // filter out any translation that does not have 100% completion and reviewed state. - // Returns a Map, for example: - // { - // untranslated_entities=8, - // last_commiter=eryzhikov, - // translated_entities=34, - // untranslated_words=16, - // translated_words=57, - // last_update=2014-09-12 08:44:33, - // reviewed_percentage=69%, - // reviewed=29, - // completed=80% - // } - Map<String, String> map = JSON.parse(transifexRequest(TRANSLATION_STATS, languageCode)); - String completed = map.getOrDefault("completed", "0%"); //$NON-NLS-1$ //$NON-NLS-2$ - String reviewed = map.getOrDefault("reviewed_percentage", "0%"); //$NON-NLS-1$ //$NON-NLS-2$ - boolean isAccepted = completed.equals("100%") && reviewed.equals("100%"); //$NON-NLS-1$ //$NON-NLS-2$ - - System.out.println(" Reviewing translation '" + languageCode + "'" + //$NON-NLS-1$ //$NON-NLS-2$ - "\tcompletion: " + completed + //$NON-NLS-1$ - ",\treviewed: " + reviewed + //$NON-NLS-1$ - "\t-> TRANSLATION" + (isAccepted ? " ACCEPTED" : " REJECTED")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - - return isAccepted || !FILTER_INCOMPLETE_TRANSLATIONS; - } - - private void downloadTranslation(String languageCode) { - // Now we download the translations of the completed languages - System.out.println("\tDownloading translation file..."); //$NON-NLS-1$ - - Function<InputStream, Void> consumer = inputStream -> { - final String outputFile = "build/resources/main/" + String.format(FILE_NAME, languageCode); //$NON-NLS-1$ - - ReadableByteChannel rbc = Channels.newChannel(inputStream); - try (FileOutputStream fos = new FileOutputStream(outputFile)) { - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - } catch (Exception e) { - e.printStackTrace(); - } - return null; - }; - performTransifexTask(consumer, GET_TRANSLATION, languageCode); - } -} diff --git a/src/impl/org/controlsfx/ImplUtils.java b/src/impl/org/controlsfx/ImplUtils.java deleted file mode 100644 index 08bbbee..0000000 --- a/src/impl/org/controlsfx/ImplUtils.java +++ /dev/null @@ -1,149 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx; - -import java.lang.reflect.Method; -import java.util.Collections; -import java.util.List; - -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.scene.Group; -import javafx.scene.Node; -import javafx.scene.Parent; -import javafx.scene.Scene; -import javafx.scene.control.Control; -import javafx.scene.control.Skin; -import javafx.scene.control.SkinBase; -import javafx.scene.layout.Pane; - -public class ImplUtils { - - private ImplUtils() { - // no-op - } - - public static void injectAsRootPane(Scene scene, Parent injectedParent, boolean useReflection) { - Parent originalParent = scene.getRoot(); - scene.setRoot(injectedParent); - - if (originalParent != null) { - getChildren(injectedParent, useReflection).add(0, originalParent); - - // copy in layout properties, etc, so that the dialogStack displays - // properly in (hopefully) whatever layout the owner node is in - injectedParent.getProperties().putAll(originalParent.getProperties()); - } - } - - // parent is where we want to inject the injectedParent. We then need to - // set the child of the injectedParent to include parent. - // The end result is that we've forced in the injectedParent node above parent. - public static void injectPane(Parent parent, Parent injectedParent, boolean useReflection) { - if (parent == null) { - throw new IllegalArgumentException("parent can not be null"); //$NON-NLS-1$ - } - - List<Node> ownerParentChildren = getChildren(parent.getParent(), useReflection); - - // we've got the children list, now we need to insert a temporary - // layout container holding our dialogs and opaque layer / effect - // in place of the owner (the owner will become a child of the dialog - // stack) - int ownerPos = ownerParentChildren.indexOf(parent); - ownerParentChildren.remove(ownerPos); - ownerParentChildren.add(ownerPos, injectedParent); - - // now we install the parent as a child of the injectedParent - getChildren(injectedParent, useReflection).add(0, parent); - - // copy in layout properties, etc, so that the dialogStack displays - // properly in (hopefully) whatever layout the owner node is in - injectedParent.getProperties().putAll(parent.getProperties()); - } - - public static void stripRootPane(Scene scene, Parent originalParent, boolean useReflection) { - Parent oldParent = scene.getRoot(); - getChildren(oldParent, useReflection).remove(originalParent); - originalParent.getStyleClass().remove("root"); //$NON-NLS-1$ - scene.setRoot(originalParent); - } - - public static List<Node> getChildren(Node n, boolean useReflection) { - return n instanceof Parent ? getChildren((Parent)n, useReflection) : Collections.emptyList(); - } - - public static List<Node> getChildren(Parent p, boolean useReflection) { - ObservableList<Node> children = null; - - // previously we used reflection immediately, now we try to avoid reflection - // by checking the type of the Parent. Still not great... - if (p instanceof Pane) { - // This should cover the majority of layout containers, including - // AnchorPane, FlowPane, GridPane, HBox, Pane, StackPane, TilePane, VBox - children = ((Pane)p).getChildren(); - } else if (p instanceof Group) { - children = ((Group)p).getChildren(); - } else if (p instanceof Control) { - Control c = (Control) p; - Skin<?> s = c.getSkin(); - children = s instanceof SkinBase ? ((SkinBase<?>)s).getChildren() : getChildrenReflectively(p); - } else if (useReflection) { - // we really want to avoid using this!!!! - children = getChildrenReflectively(p); - } - - if (children == null) { - throw new RuntimeException("Unable to get children for Parent of type " + p.getClass() + //$NON-NLS-1$ - ". useReflection is set to " + useReflection); //$NON-NLS-1$ - } - - return children == null ? FXCollections.emptyObservableList() : children; - } - - @SuppressWarnings("unchecked") - public static ObservableList<Node> getChildrenReflectively(Parent p) { - ObservableList<Node> children = null; - - try { - Method getChildrenMethod = Parent.class.getDeclaredMethod("getChildren"); //$NON-NLS-1$ - - if (getChildrenMethod != null) { - if (! getChildrenMethod.isAccessible()) { - getChildrenMethod.setAccessible(true); - } - children = (ObservableList<Node>) getChildrenMethod.invoke(p); - } else { - // uh oh, trouble - } - } catch (ReflectiveOperationException | IllegalArgumentException e) { - throw new RuntimeException("Unable to get children for Parent of type " + p.getClass(), e); //$NON-NLS-1$ - } - - return children; - } -} diff --git a/src/impl/org/controlsfx/autocompletion/AutoCompletionTextFieldBinding.java b/src/impl/org/controlsfx/autocompletion/AutoCompletionTextFieldBinding.java deleted file mode 100644 index 67416a6..0000000 --- a/src/impl/org/controlsfx/autocompletion/AutoCompletionTextFieldBinding.java +++ /dev/null @@ -1,161 +0,0 @@ -/** - * Copyright (c) 2014, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.autocompletion; - -import java.util.Collection; - -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.scene.control.TextField; -import javafx.util.Callback; -import javafx.util.StringConverter; - -import org.controlsfx.control.textfield.AutoCompletionBinding; - -/** - * Represents a binding between a text field and a auto-completion popup - * - * @param <T> - */ -public class AutoCompletionTextFieldBinding<T> extends AutoCompletionBinding<T>{ - - /*************************************************************************** - * * - * Static properties and methods * - * * - **************************************************************************/ - - private static <T> StringConverter<T> defaultStringConverter() { - return new StringConverter<T>() { - @Override public String toString(T t) { - return t == null ? null : t.toString(); - } - @SuppressWarnings("unchecked") - @Override public T fromString(String string) { - return (T) string; - } - }; - } - - /*************************************************************************** - * * - * Private fields * - * * - **************************************************************************/ - - /** - * String converter to be used to convert suggestions to strings. - */ - private StringConverter<T> converter; - - - /*************************************************************************** - * * - * Constructors * - * * - **************************************************************************/ - - /** - * Creates a new auto-completion binding between the given textField - * and the given suggestion provider. - * - * @param textField - * @param suggestionProvider - */ - public AutoCompletionTextFieldBinding(final TextField textField, - Callback<ISuggestionRequest, Collection<T>> suggestionProvider) { - - this(textField, suggestionProvider, AutoCompletionTextFieldBinding - .<T>defaultStringConverter()); - } - - /** - * Creates a new auto-completion binding between the given textField - * and the given suggestion provider. - * - * @param textField - * @param suggestionProvider - */ - public AutoCompletionTextFieldBinding(final TextField textField, - Callback<ISuggestionRequest, Collection<T>> suggestionProvider, - final StringConverter<T> converter) { - - super(textField, suggestionProvider, converter); - this.converter = converter; - - getCompletionTarget().textProperty().addListener(textChangeListener); - getCompletionTarget().focusedProperty().addListener(focusChangedListener); - } - - - /*************************************************************************** - * * - * Public API * - * * - **************************************************************************/ - - /** {@inheritDoc} */ - @Override public TextField getCompletionTarget(){ - return (TextField)super.getCompletionTarget(); - } - - /** {@inheritDoc} */ - @Override public void dispose(){ - getCompletionTarget().textProperty().removeListener(textChangeListener); - getCompletionTarget().focusedProperty().removeListener(focusChangedListener); - } - - /** {@inheritDoc} */ - @Override protected void completeUserInput(T completion){ - String newText = converter.toString(completion); - getCompletionTarget().setText(newText); - getCompletionTarget().positionCaret(newText.length()); - } - - - /*************************************************************************** - * * - * Event Listeners * - * * - **************************************************************************/ - - - private final ChangeListener<String> textChangeListener = new ChangeListener<String>() { - @Override public void changed(ObservableValue<? extends String> obs, String oldText, String newText) { - if (getCompletionTarget().isFocused()) { - setUserInput(newText); - } - } - }; - - private final ChangeListener<Boolean> focusChangedListener = new ChangeListener<Boolean>() { - @Override public void changed(ObservableValue<? extends Boolean> obs, Boolean oldFocused, Boolean newFocused) { - if(newFocused == false) - hidePopup(); - } - }; -} diff --git a/src/impl/org/controlsfx/autocompletion/SuggestionProvider.java b/src/impl/org/controlsfx/autocompletion/SuggestionProvider.java deleted file mode 100644 index 5c17803..0000000 --- a/src/impl/org/controlsfx/autocompletion/SuggestionProvider.java +++ /dev/null @@ -1,199 +0,0 @@ -/** - * Copyright (c) 2014, 2016 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.autocompletion; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -import javafx.util.Callback; - -import org.controlsfx.control.textfield.AutoCompletionBinding.ISuggestionRequest; - -/** - * This is a simple implementation of a generic suggestion provider callback. - * The complexity of suggestion generation is O(n) where n is the number of possible suggestions. - * - * @param <T> Type of suggestions - */ -public abstract class SuggestionProvider<T> implements Callback<ISuggestionRequest, Collection<T>>{ - - private final List<T> possibleSuggestions = new ArrayList<>(); - private final Object possibleSuggestionsLock = new Object(); - - - /** - * Add the given new possible suggestions to this SuggestionProvider - * @param newPossible - */ - public void addPossibleSuggestions(@SuppressWarnings("unchecked") T... newPossible){ - addPossibleSuggestions(Arrays.asList(newPossible)); - } - - /** - * Add the given new possible suggestions to this SuggestionProvider - * @param newPossible - */ - public void addPossibleSuggestions(Collection<T> newPossible){ - synchronized (possibleSuggestionsLock) { - possibleSuggestions.addAll(newPossible); - } - } - - /** - * Remove all current possible suggestions - */ - public void clearSuggestions(){ - synchronized (possibleSuggestionsLock) { - possibleSuggestions.clear(); - } - } - - @Override - public final Collection<T> call(final ISuggestionRequest request) { - List<T> suggestions = new ArrayList<>(); - if(!request.getUserText().isEmpty()){ - synchronized (possibleSuggestionsLock) { - for (T possibleSuggestion : possibleSuggestions) { - if(isMatch(possibleSuggestion, request)){ - suggestions.add(possibleSuggestion); - } - } - } - Collections.sort(suggestions, getComparator()); - } - return suggestions; - } - - /** - * Get the comparator to order the suggestions - * @return - */ - protected abstract Comparator<T> getComparator(); - - /** - * Check the given possible suggestion is a match (is a valid suggestion) - * @param suggestion - * @param request - * @return - */ - protected abstract boolean isMatch(T suggestion, ISuggestionRequest request); - - - /*************************************************************************** - * * - * Static methods * - * * - **************************************************************************/ - - - /** - * Create a default suggestion provider based on the toString() method of the generic objects - * @param possibleSuggestions All possible suggestions - * @return - */ - public static <T> SuggestionProvider<T> create(Collection<T> possibleSuggestions){ - return create(null, possibleSuggestions); - } - - /** - * Create a default suggestion provider based on the toString() method of the generic objects - * using the provided stringConverter - * - * @param stringConverter A stringConverter which converts generic T into a string - * @param possibleSuggestions All possible suggestions - * @return - */ - public static <T> SuggestionProvider<T> create(Callback<T, String> stringConverter, Collection<T> possibleSuggestions){ - SuggestionProviderString<T> suggestionProvider = new SuggestionProviderString<>(stringConverter); - suggestionProvider.addPossibleSuggestions(possibleSuggestions); - return suggestionProvider; - } - - - - /*************************************************************************** - * * - * Default implementations * - * * - **************************************************************************/ - - - /** - * This is a simple string based suggestion provider. - * All generic suggestions T are turned into strings for processing. - * - */ - private static class SuggestionProviderString<T> extends SuggestionProvider<T> { - - private Callback<T, String> stringConverter; - - private final Comparator<T> stringComparator = new Comparator<T>() { - @Override - public int compare(T o1, T o2) { - String o1str = stringConverter.call(o1); - String o2str = stringConverter.call(o2); - return o1str.compareTo(o2str); - } - }; - - /** - * Create a new SuggestionProviderString - * @param stringConverter - */ - public SuggestionProviderString(Callback<T, String> stringConverter){ - this.stringConverter = stringConverter; - - // In case no stringConverter was provided, use the default strategy - if(this.stringConverter == null){ - this.stringConverter = new Callback<T, String>() { - @Override - public String call(T obj) { - return obj != null ? obj.toString() : ""; //$NON-NLS-1$ - } - }; - } - } - - /**{@inheritDoc}*/ - @Override - protected Comparator<T> getComparator() { - return stringComparator; - } - - /**{@inheritDoc}*/ - @Override - protected boolean isMatch(T suggestion, ISuggestionRequest request) { - String userTextLower = request.getUserText().toLowerCase(); - String suggestionStr = suggestion.toString().toLowerCase(); - return suggestionStr.contains(userTextLower); - } - } -} diff --git a/src/impl/org/controlsfx/behavior/RangeSliderBehavior.java b/src/impl/org/controlsfx/behavior/RangeSliderBehavior.java deleted file mode 100644 index e0f1665..0000000 --- a/src/impl/org/controlsfx/behavior/RangeSliderBehavior.java +++ /dev/null @@ -1,339 +0,0 @@ -/** - * Copyright (c) 2013, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.behavior; - -import static javafx.scene.input.KeyCode.DOWN; -import static javafx.scene.input.KeyCode.END; -import static javafx.scene.input.KeyCode.F4; -import static javafx.scene.input.KeyCode.HOME; -import static javafx.scene.input.KeyCode.KP_DOWN; -import static javafx.scene.input.KeyCode.KP_LEFT; -import static javafx.scene.input.KeyCode.KP_RIGHT; -import static javafx.scene.input.KeyCode.KP_UP; -import static javafx.scene.input.KeyCode.LEFT; -import static javafx.scene.input.KeyCode.RIGHT; -import static javafx.scene.input.KeyCode.UP; -import static javafx.scene.input.KeyEvent.KEY_RELEASED; - -import java.util.ArrayList; -import java.util.List; - -import javafx.event.EventType; -import javafx.geometry.Orientation; -import javafx.scene.control.Control; -import javafx.scene.control.Skin; -import javafx.scene.input.KeyCode; -import javafx.scene.input.KeyEvent; -import javafx.scene.input.MouseEvent; -import javafx.util.Callback; - -import org.controlsfx.control.RangeSlider; -import org.controlsfx.tools.Utils; - -import com.sun.javafx.scene.control.behavior.BehaviorBase; -import com.sun.javafx.scene.control.behavior.KeyBinding; -import com.sun.javafx.scene.control.behavior.OrientedKeyBinding; - -public class RangeSliderBehavior extends BehaviorBase<RangeSlider> { - - /************************************************************************** - * Setup KeyBindings * - * * - * We manually specify the focus traversal keys because Slider has * - * different usage for up/down arrow keys. * - *************************************************************************/ - private static final List<KeyBinding> RANGESLIDER_BINDINGS = new ArrayList<>(); - static { - RANGESLIDER_BINDINGS.add(new KeyBinding(F4, "TraverseDebug").alt().ctrl().shift()); //$NON-NLS-1$ - - RANGESLIDER_BINDINGS.add(new RangeSliderKeyBinding(LEFT, "DecrementValue")); //$NON-NLS-1$ - RANGESLIDER_BINDINGS.add(new RangeSliderKeyBinding(KP_LEFT, "DecrementValue")); //$NON-NLS-1$ - RANGESLIDER_BINDINGS.add(new RangeSliderKeyBinding(UP, "IncrementValue").vertical()); //$NON-NLS-1$ - RANGESLIDER_BINDINGS.add(new RangeSliderKeyBinding(KP_UP, "IncrementValue").vertical()); //$NON-NLS-1$ - RANGESLIDER_BINDINGS.add(new RangeSliderKeyBinding(RIGHT, "IncrementValue")); //$NON-NLS-1$ - RANGESLIDER_BINDINGS.add(new RangeSliderKeyBinding(KP_RIGHT, "IncrementValue")); //$NON-NLS-1$ - RANGESLIDER_BINDINGS.add(new RangeSliderKeyBinding(DOWN, "DecrementValue").vertical()); //$NON-NLS-1$ - RANGESLIDER_BINDINGS.add(new RangeSliderKeyBinding(KP_DOWN, "DecrementValue").vertical()); //$NON-NLS-1$ - - RANGESLIDER_BINDINGS.add(new RangeSliderKeyBinding(LEFT, "TraverseLeft").vertical()); //$NON-NLS-1$ - RANGESLIDER_BINDINGS.add(new RangeSliderKeyBinding(KP_LEFT, "TraverseLeft").vertical()); //$NON-NLS-1$ - RANGESLIDER_BINDINGS.add(new RangeSliderKeyBinding(UP, "TraverseUp")); //$NON-NLS-1$ - RANGESLIDER_BINDINGS.add(new RangeSliderKeyBinding(KP_UP, "TraverseUp")); //$NON-NLS-1$ - RANGESLIDER_BINDINGS.add(new RangeSliderKeyBinding(RIGHT, "TraverseRight").vertical()); //$NON-NLS-1$ - RANGESLIDER_BINDINGS.add(new RangeSliderKeyBinding(KP_RIGHT, "TraverseRight").vertical()); //$NON-NLS-1$ - RANGESLIDER_BINDINGS.add(new RangeSliderKeyBinding(DOWN, "TraverseDown")); //$NON-NLS-1$ - RANGESLIDER_BINDINGS.add(new RangeSliderKeyBinding(KP_DOWN, "TraverseDown")); //$NON-NLS-1$ - - RANGESLIDER_BINDINGS.add(new KeyBinding(HOME, KEY_RELEASED, "Home")); //$NON-NLS-1$ - RANGESLIDER_BINDINGS.add(new KeyBinding(END, KEY_RELEASED, "End")); //$NON-NLS-1$ - } - - public RangeSliderBehavior(RangeSlider slider) { - super(slider, RANGESLIDER_BINDINGS); - } - - @Override protected void callAction(String s) { - if ("Home".equals(s) || "Home2".equals(s)) home(); //$NON-NLS-1$ //$NON-NLS-2$ - else if ("End".equals(s) || "End2".equals(s)) end(); //$NON-NLS-1$ //$NON-NLS-2$ - else if ("IncrementValue".equals(s) || "IncrementValue2".equals(s)) incrementValue(); //$NON-NLS-1$ //$NON-NLS-2$ - else if ("DecrementValue".equals(s) || "DecrementValue2".equals(s)) decrementValue(); //$NON-NLS-1$ //$NON-NLS-2$ - else super.callAction(s); - } - - /************************************************************************** - * State and Functions * - *************************************************************************/ - - private Callback<Void, FocusedChild> selectedValue; - public void setSelectedValue(Callback<Void, FocusedChild> c) { - selectedValue = c; - } - /** - * Invoked by the RangeSlider {@link Skin} implementation whenever a mouse press - * occurs on the "track" of the slider. This will cause the thumb to be - * moved by some amount. - * - * @param position The mouse position on track with 0.0 being beginning of - * track and 1.0 being the end - */ - public void trackPress(MouseEvent e, double position) { - // determine the percentage of the way between min and max - // represented by this mouse event - final RangeSlider rangeSlider = getControl(); - // If not already focused, request focus - if (!rangeSlider.isFocused()) { - rangeSlider.requestFocus(); - } - if (selectedValue != null) { - double newPosition; - if (rangeSlider.getOrientation().equals(Orientation.HORIZONTAL)) { - newPosition = position * (rangeSlider.getMax() - rangeSlider.getMin()) + rangeSlider.getMin(); - } else { - newPosition = (1 - position) * (rangeSlider.getMax() - rangeSlider.getMin()) + rangeSlider.getMin(); - } - - /** - * If the position is inferior to the current LowValue, this means - * the user clicked on the track to move the low thumb. If not, then - * it means the user wanted to move the high thumb. - */ - if (newPosition < rangeSlider.getLowValue()) { - rangeSlider.adjustLowValue(newPosition); - } else { - rangeSlider.adjustHighValue(newPosition); - } - } - } - - /** - */ - public void trackRelease(MouseEvent e, double position) { - } - - /** - * @param position The mouse position on track with 0.0 being beginning of - * track and 1.0 being the end - */ - public void lowThumbPressed(MouseEvent e, double position) { - // If not already focused, request focus - final RangeSlider rangeSlider = getControl(); - if (!rangeSlider.isFocused()) rangeSlider.requestFocus(); - rangeSlider.setLowValueChanging(true); - } - - /** - * @param position The mouse position on track with 0.0 being beginning of - * track and 1.0 being the end - */ - public void lowThumbDragged(MouseEvent e, double position) { - final RangeSlider rangeSlider = getControl(); - double newValue = Utils.clamp(rangeSlider.getMin(), - (position * (rangeSlider.getMax() - rangeSlider.getMin())) + rangeSlider.getMin(), - rangeSlider.getMax()); - rangeSlider.setLowValue(newValue); - } - - /** - * When lowThumb is released lowValueChanging should be set to false. - */ - public void lowThumbReleased(MouseEvent e) { - final RangeSlider rangeSlider = getControl(); - rangeSlider.setLowValueChanging(false); - // RT-15207 When snapToTicks is true, slider value calculated in drag - // is then snapped to the nearest tick on mouse release. - if (rangeSlider.isSnapToTicks()) { - rangeSlider.setLowValue(snapValueToTicks(rangeSlider.getLowValue())); - } - } - - void home() { - RangeSlider slider = (RangeSlider) getControl(); - slider.adjustHighValue(slider.getMin()); - } - - void decrementValue() { - RangeSlider slider = (RangeSlider) getControl(); - if (selectedValue != null) { - if (selectedValue.call(null) == FocusedChild.HIGH_THUMB) { - if (slider.isSnapToTicks()) - slider.adjustHighValue(slider.getHighValue() - computeIncrement()); - else - slider.decrementHighValue(); - } else { - if (slider.isSnapToTicks()) - slider.adjustLowValue(slider.getLowValue() - computeIncrement()); - else - slider.decrementLowValue(); - } - } - } - - void end() { - RangeSlider slider = (RangeSlider) getControl(); - slider.adjustHighValue(slider.getMax()); - } - - void incrementValue() { - RangeSlider slider = (RangeSlider) getControl(); - if (selectedValue != null) { - if (selectedValue.call(null) == FocusedChild.HIGH_THUMB) { - if (slider.isSnapToTicks()) - slider.adjustHighValue(slider.getHighValue() + computeIncrement()); - else - slider.incrementHighValue(); - } else { - if (slider.isSnapToTicks()) - slider.adjustLowValue(slider.getLowValue() + computeIncrement()); - else - slider.incrementLowValue(); - } - } - - } - - double computeIncrement() { - RangeSlider rangeSlider = (RangeSlider) getControl(); - double d = 0.0D; - if (rangeSlider.getMinorTickCount() != 0) - d = rangeSlider.getMajorTickUnit() / (double) (Math.max(rangeSlider.getMinorTickCount(), 0) + 1); - else - d = rangeSlider.getMajorTickUnit(); - if (rangeSlider.getBlockIncrement() > 0.0D && rangeSlider.getBlockIncrement() < d) - return d; - else - return rangeSlider.getBlockIncrement(); - } - - private double snapValueToTicks(double d) { - RangeSlider rangeSlider = (RangeSlider) getControl(); - double d1 = d; - double d2 = 0.0D; - if (rangeSlider.getMinorTickCount() != 0) - d2 = rangeSlider.getMajorTickUnit() / (double) (Math.max(rangeSlider.getMinorTickCount(), 0) + 1); - else - d2 = rangeSlider.getMajorTickUnit(); - int i = (int) ((d1 - rangeSlider.getMin()) / d2); - double d3 = (double) i * d2 + rangeSlider.getMin(); - double d4 = (double) (i + 1) * d2 + rangeSlider.getMin(); - d1 = Utils.nearest(d3, d1, d4); - return Utils.clamp(rangeSlider.getMin(), d1, rangeSlider.getMax()); - } - - // when high thumb is released, highValueChanging is set to false. - public void highThumbReleased(MouseEvent e) { - RangeSlider slider = (RangeSlider) getControl(); - slider.setHighValueChanging(false); - if (slider.isSnapToTicks()) - slider.setHighValue(snapValueToTicks(slider.getHighValue())); - } - - public void highThumbPressed(MouseEvent e, double position) { - RangeSlider slider = (RangeSlider) getControl(); - if (!slider.isFocused()) - slider.requestFocus(); - slider.setHighValueChanging(true); - } - - public void highThumbDragged(MouseEvent e, double position) { - RangeSlider slider = (RangeSlider) getControl(); - slider.setHighValue(Utils.clamp(slider.getMin(), position * (slider.getMax() - slider.getMin()) + slider.getMin(), slider.getMax())); - } - - public void moveRange(double position) { - RangeSlider slider = (RangeSlider) getControl(); - final double min = slider.getMin(); - final double max = slider.getMax(); - final double lowValue = slider.getLowValue(); - final double newLowValue = Utils.clamp(min, lowValue + position *(max-min) / - (slider.getOrientation() == Orientation.HORIZONTAL? slider.getWidth(): slider.getHeight()), max); - final double highValue = slider.getHighValue(); - final double newHighValue = Utils.clamp(min, highValue + position*(max-min) / - (slider.getOrientation() == Orientation.HORIZONTAL? slider.getWidth(): slider.getHeight()), max); - - if (newLowValue <= min || newHighValue >= max) return; - slider.setLowValueChanging(true); - slider.setHighValueChanging(true); - slider.setLowValue(newLowValue); - slider.setHighValue(newHighValue); - } - - public void confirmRange() { - RangeSlider slider = (RangeSlider) getControl(); - - slider.setLowValueChanging(false); - if (slider.isSnapToTicks()) { - slider.setLowValue(snapValueToTicks(slider.getLowValue())); - } - slider.setHighValueChanging(false); - if (slider.isSnapToTicks()) { - slider.setHighValue(snapValueToTicks(slider.getHighValue())); - } - - } - - public static class RangeSliderKeyBinding extends OrientedKeyBinding { - public RangeSliderKeyBinding(KeyCode code, String action) { - super(code, action); - } - - public RangeSliderKeyBinding(KeyCode code, EventType<KeyEvent> type, String action) { - super(code, type, action); - } - - public @Override boolean getVertical(Control control) { - return ((RangeSlider)control).getOrientation() == Orientation.VERTICAL; - } - } - - public enum FocusedChild { - LOW_THUMB, - HIGH_THUMB, - RANGE_BAR, - NONE - } -} - diff --git a/src/impl/org/controlsfx/behavior/RatingBehavior.java b/src/impl/org/controlsfx/behavior/RatingBehavior.java deleted file mode 100644 index 284d299..0000000 --- a/src/impl/org/controlsfx/behavior/RatingBehavior.java +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright (c) 2013, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.behavior; - -import java.util.Collections; - -import org.controlsfx.control.Rating; - -import com.sun.javafx.scene.control.behavior.BehaviorBase; -import com.sun.javafx.scene.control.behavior.KeyBinding; - -public class RatingBehavior extends BehaviorBase<Rating> { - - public RatingBehavior(Rating control) { - super(control, Collections.<KeyBinding> emptyList()); - } -} \ No newline at end of file diff --git a/src/impl/org/controlsfx/behavior/SnapshotViewBehavior.java b/src/impl/org/controlsfx/behavior/SnapshotViewBehavior.java deleted file mode 100644 index 33456ec..0000000 --- a/src/impl/org/controlsfx/behavior/SnapshotViewBehavior.java +++ /dev/null @@ -1,783 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.behavior; - -import impl.org.controlsfx.tools.rectangle.CoordinatePosition; -import impl.org.controlsfx.tools.rectangle.CoordinatePositions; -import impl.org.controlsfx.tools.rectangle.Rectangles2D; -import impl.org.controlsfx.tools.rectangle.change.MoveChangeStrategy; -import impl.org.controlsfx.tools.rectangle.change.NewChangeStrategy; -import impl.org.controlsfx.tools.rectangle.change.Rectangle2DChangeStrategy; -import impl.org.controlsfx.tools.rectangle.change.ToEastChangeStrategy; -import impl.org.controlsfx.tools.rectangle.change.ToNorthChangeStrategy; -import impl.org.controlsfx.tools.rectangle.change.ToNortheastChangeStrategy; -import impl.org.controlsfx.tools.rectangle.change.ToNorthwestChangeStrategy; -import impl.org.controlsfx.tools.rectangle.change.ToSouthChangeStrategy; -import impl.org.controlsfx.tools.rectangle.change.ToSoutheastChangeStrategy; -import impl.org.controlsfx.tools.rectangle.change.ToSouthwestChangeStrategy; -import impl.org.controlsfx.tools.rectangle.change.ToWestChangeStrategy; - -import java.util.ArrayList; -import java.util.Objects; -import java.util.function.Consumer; - -import javafx.event.EventType; -import javafx.geometry.Bounds; -import javafx.geometry.Point2D; -import javafx.geometry.Rectangle2D; -import javafx.scene.Cursor; -import javafx.scene.Node; -import javafx.scene.input.MouseButton; -import javafx.scene.input.MouseEvent; - -import org.controlsfx.control.SnapshotView; -import org.controlsfx.control.SnapshotView.Boundary; - -import com.sun.javafx.scene.control.behavior.BehaviorBase; -import com.sun.javafx.scene.control.behavior.KeyBinding; - -/** - * The behavior for the {@link SnapshotView}. It is concerned with creating and changing selections according to mouse - * events handed to {@link #handleMouseEvent(MouseEvent) handleMouseEvents}. - */ -public class SnapshotViewBehavior extends BehaviorBase<SnapshotView> { - - /** - * The percentage of the control's node's width/height used as a tolerance for determining whether the cursor is on - * an edge of the selection. - */ - private static final double RELATIVE_EDGE_TOLERANCE = 0.015; - - /* ************************************************************************ - * * - * Attributes * - * * - **************************************************************************/ - - /** - * The current selection change; might be {@code null}. - */ - private SelectionChange selectionChange; - - /** - * A function which sets the {@link SnapshotView#selectionChangingProperty() selectionChanging} property to the - * given value. - */ - private final Consumer<Boolean> setSelectionChanging; - - /* ************************************************************************ - * * - * Constructor * - * * - **************************************************************************/ - - /** - * Creates a new behavior for the specified {@link SnapshotView}. - * - * @param snapshotView - * the control which this behavior will control - */ - public SnapshotViewBehavior(SnapshotView snapshotView) { - super(snapshotView, new ArrayList<KeyBinding>()); - this.setSelectionChanging = createSetSelectionChanging(); - } - - /** - * Creates a function which sets the applied boolean to {@link SnapshotView#selectionChangingProperty()}. - * - * @return a Boolean {@link Consumer} - */ - private Consumer<Boolean> createSetSelectionChanging() { - return changing -> getControl().getProperties().put(SnapshotView.SELECTION_CHANGING_PROPERTY_KEY, changing); - } - - /* ************************************************************************ - * * - * Events * - * * - **************************************************************************/ - - /** - * Handles the specified mouse event (possibly by creating/changing/removing a selection) and returns the matching - * cursor. - * - * @param mouseEvent - * the handled {@link MouseEvent}; must not be {@code null} - * @return the cursor which will be used for this event - */ - public Cursor handleMouseEvent(MouseEvent mouseEvent) { - Objects.requireNonNull(mouseEvent, "The argument 'mouseEvent' must not be null."); //$NON-NLS-1$ - - EventType<? extends MouseEvent> eventType = mouseEvent.getEventType(); - SelectionEvent selectionEvent = createSelectionEvent(mouseEvent); - - if (eventType == MouseEvent.MOUSE_MOVED) { - return getCursor(selectionEvent); - } - if (eventType == MouseEvent.MOUSE_PRESSED) { - return handleMousePressedEvent(selectionEvent); - } - if (eventType == MouseEvent.MOUSE_DRAGGED) { - return handleMouseDraggedEvent(selectionEvent); - } - if (eventType == MouseEvent.MOUSE_RELEASED) { - return handleMouseReleasedEvent(selectionEvent); - } - - return Cursor.DEFAULT; - } - - // TRANSFORM MOUSE EVENT TO SELECTION EVENT - - /** - * Creates a selection event for the specified mouse event - * - * @param mouseEvent - * the {@link MouseEvent} for which the selection event will be created - * @return the {@link SelectionEvent} for the specified mouse event - */ - private SelectionEvent createSelectionEvent(MouseEvent mouseEvent) { - Point2D point = new Point2D(mouseEvent.getX(), mouseEvent.getY()); - Rectangle2D selectionBounds = createBoundsForCurrentBoundary(); - CoordinatePosition position = computePosition(point); - return new SelectionEvent(mouseEvent, point, selectionBounds, position); - } - - /** - * Returns the bounds according to the current {@link SnapshotView#selectionAreaBoundaryProperty() - * selectionAreaBoundary}. - * - * @return the bounds as a {@link Rectangle2D} - */ - private Rectangle2D createBoundsForCurrentBoundary() { - Boundary boundary = getControl().getSelectionAreaBoundary(); - switch (boundary) { - case CONTROL: - return new Rectangle2D(0, 0, getControlWidth(), getControlHeight()); - case NODE: - boolean nodeExists = getNode() != null; - if (nodeExists) { - Bounds nodeBounds = getNode().getBoundsInParent(); - return Rectangles2D.fromBounds(nodeBounds); - } else { - return Rectangle2D.EMPTY; - } - default: - throw new IllegalArgumentException("The boundary " + boundary + " is not fully implemented."); //$NON-NLS-1$ //$NON-NLS-2$ - } - } - - /** - * Returns the position of the specified point relative to a possible selection. - * - * @param point - * the point (in the node's preferred coordinates) whose position will be computed - * - * @return the {@link CoordinatePosition} the event's point has relative to the control's current selection; if the - * selection is inactive this always returns {@link CoordinatePosition#OUT_OF_RECTANGLE}. - */ - private CoordinatePosition computePosition(Point2D point) { - boolean noSelection = !getControl().hasSelection() || !getControl().isSelectionActive(); - boolean controlHasNoSpace = getControlWidth() == 0 || getControlHeight() == 0; - if (noSelection || controlHasNoSpace) { - return CoordinatePosition.OUT_OF_RECTANGLE; - } - - double tolerance = computeTolerance(); - return computePosition(getSelection(), point, tolerance); - } - - /** - * Computes the tolerance which is used to determine whether the cursor is on an edge. - * - * @return the absolute tolerance - */ - private double computeTolerance() { - double controlMeanLength = Math.sqrt(getControlWidth() * getControlHeight()); - return RELATIVE_EDGE_TOLERANCE * controlMeanLength; - } - - /** - * Returns the position of the specified point relative to the specified selection with the specified tolerance. - * - * @param selection - * the selection relative to which the point's position will be computed; as a {@link Rectangle2D} - * @param point - * the {@link Point2D} whose position will be computed - * @param tolerance - * the absolute tolerance used to determine whether the point is on an edge - * - * @return the {@link CoordinatePosition} the event's point has relative to the control's current selection; if the - * selection is inactive this always returns {@link CoordinatePosition#OUT_OF_RECTANGLE}. - */ - private static CoordinatePosition computePosition(Rectangle2D selection, Point2D point, double tolerance) { - CoordinatePosition onEdge = CoordinatePositions.onEdges(selection, point, tolerance); - if (onEdge != null) { - return onEdge; - } else { - return CoordinatePositions.inRectangle(selection, point); - } - } - - // HANDLE SELECTION EVENTS - - /** - * Handles {@link MouseEvent#MOUSE_PRESSED} events by creating a new {@link #selectionChange} and beginning the - * change. - * - * @param selectionEvent - * the handled {@link SelectionEvent} - * @return the cursor which will be used while the selection changes - */ - private Cursor handleMousePressedEvent(SelectionEvent selectionEvent) { - if (selectionEvent.isPointInSelectionBounds()) { - // get all necessary information to create a selection change - Cursor cursor = getCursor(selectionEvent); - Rectangle2DChangeStrategy selectionChangeStrategy = getChangeStrategy(selectionEvent); - boolean deactivateSelectionIfClick = willDeactivateSelectionIfClick(selectionEvent); - - // create and begin the selection change - selectionChange = new SelectionChangeByStrategy( - getControl(), setSelectionChanging, selectionChangeStrategy, cursor, deactivateSelectionIfClick); - selectionChange.beginSelectionChange(selectionEvent.getPoint()); - } else { - // if the mouse is outside the legal bounds, the selection will not actually change - selectionChange = NoSelectionChange.INSTANCE; - } - - return selectionChange.getCursor(); - } - /** - * Handles {@link MouseEvent#MOUSE_DRAGGED} events by continuing the current {@link #selectionChange}. - * - * @param selectionEvent - * the handled {@link SelectionEvent} - * @return the cursor which will be used while the selection changes - */ - private Cursor handleMouseDraggedEvent(SelectionEvent selectionEvent) { - selectionChange.continueSelectionChange(selectionEvent.getPoint()); - return selectionChange.getCursor(); - } - - /** - * Handles {@link MouseEvent#MOUSE_RELEASED} events by ending the current {@link #selectionChange} and setting it to - * {@code null}. - * - * @param selectionEvent - * the handled {@link SelectionEvent} - * @return the cursor which will be used after the selection change ends - */ - private Cursor handleMouseReleasedEvent(SelectionEvent selectionEvent) { - // end and deactivate the selection change - selectionChange.endSelectionChange(selectionEvent.getPoint()); - selectionChange = null; - - return getCursor(selectionEvent); - } - - // CURSOR AND SELECTION CHANGE - - /** - * Returns the cursor which will be used for the specified selection event. - * - * @param selectionEvent - * the {@link SelectionEvent} to check - * @return the {@link Cursor} which will be used for the event - */ - private Cursor getCursor(SelectionEvent selectionEvent) { - // show the default cursor if the mouse is out of the selection bounds - if (!selectionEvent.isPointInSelectionBounds()) { - return getRegularCursor(); - } - - // otherwise pick a cursor from the relative position - switch (selectionEvent.getPosition()) { - case IN_RECTANGLE: - return Cursor.MOVE; - case OUT_OF_RECTANGLE: - return getRegularCursor(); - case NORTH_EDGE: - return Cursor.N_RESIZE; - case NORTHEAST_EDGE: - return Cursor.NE_RESIZE; - case EAST_EDGE: - return Cursor.E_RESIZE; - case SOUTHEAST_EDGE: - return Cursor.SE_RESIZE; - case SOUTH_EDGE: - return Cursor.S_RESIZE; - case SOUTHWEST_EDGE: - return Cursor.SW_RESIZE; - case WEST_EDGE: - return Cursor.W_RESIZE; - case NORTHWEST_EDGE: - return Cursor.NW_RESIZE; - default: - throw new IllegalArgumentException("The position " + selectionEvent.getPosition() //$NON-NLS-1$ - + " is not fully implemented."); //$NON-NLS-1$ - } - } - - /** - * @return the cursor from the {@link #getControl() control's} current {@link SnapshotView#cursorProperty() cursor} - */ - private Cursor getRegularCursor() { - return getControl().getCursor(); - } - - /** - * Returns the selection change strategy based on the specified selection event, which must be a - * {@link MouseEvent#MOUSE_PRESSED MOUSE_PRESSED} event. - * - * @param selectionEvent - * the {@link SelectionEvent} which will be checked - * @return the {@link Rectangle2DChangeStrategy} which will be executed based on the selection event - * @throws IllegalArgumentException - * if {@link SelectionEvent#getMouseEvent()} is not of type {@link MouseEvent#MOUSE_PRESSED}. - */ - private Rectangle2DChangeStrategy getChangeStrategy(SelectionEvent selectionEvent) { - boolean mousePressed = selectionEvent.getMouseEvent().getEventType() == MouseEvent.MOUSE_PRESSED; - if (!mousePressed) { - throw new IllegalArgumentException(); - } - - Rectangle2D selectionBounds = selectionEvent.getSelectionBounds(); - - switch (selectionEvent.getPosition()) { - case IN_RECTANGLE: - return new MoveChangeStrategy(getSelection(), selectionBounds); - case OUT_OF_RECTANGLE: - return new NewChangeStrategy( - isSelectionRatioFixed(), getSelectionRatio(), selectionBounds); - case NORTH_EDGE: - return new ToNorthChangeStrategy( - getSelection(), isSelectionRatioFixed(), getSelectionRatio(), selectionBounds); - case NORTHEAST_EDGE: - return new ToNortheastChangeStrategy( - getSelection(), isSelectionRatioFixed(), getSelectionRatio(), selectionBounds); - case EAST_EDGE: - return new ToEastChangeStrategy( - getSelection(), isSelectionRatioFixed(), getSelectionRatio(), selectionBounds); - case SOUTHEAST_EDGE: - return new ToSoutheastChangeStrategy( - getSelection(), isSelectionRatioFixed(), getSelectionRatio(), selectionBounds); - case SOUTH_EDGE: - return new ToSouthChangeStrategy( - getSelection(), isSelectionRatioFixed(), getSelectionRatio(), selectionBounds); - case SOUTHWEST_EDGE: - return new ToSouthwestChangeStrategy( - getSelection(), isSelectionRatioFixed(), getSelectionRatio(), selectionBounds); - case WEST_EDGE: - return new ToWestChangeStrategy( - getSelection(), isSelectionRatioFixed(), getSelectionRatio(), selectionBounds); - case NORTHWEST_EDGE: - return new ToNorthwestChangeStrategy( - getSelection(), isSelectionRatioFixed(), getSelectionRatio(), selectionBounds); - default: - throw new IllegalArgumentException("The position " + selectionEvent.getPosition() //$NON-NLS-1$ - + " is not fully implemented."); //$NON-NLS-1$ - } - } - - /** - * Checks whether the selection will be deactivated if the mouse is clicked at the {@link SelectionEvent}. - * - * @param selectionEvent - * the selection event which will be checked - * @return {@code true} if the selection event is such that the selection will be deactivated if the mouse is only - * clicked - */ - private static boolean willDeactivateSelectionIfClick(SelectionEvent selectionEvent) { - boolean rightClick = selectionEvent.getMouseEvent().getButton() == MouseButton.SECONDARY; - boolean outOfAreaClick = selectionEvent.getPosition() == CoordinatePosition.OUT_OF_RECTANGLE; - - return rightClick || outOfAreaClick; - } - - /* ************************************************************************ - * * - * Usability Access Functions to SnapshotView Properties * - * * - **************************************************************************/ - - /** - * The control's width. - * - * @return {@link SnapshotView#getWidth()} - */ - private double getControlWidth() { - return getControl().getWidth(); - } - - /** - * The control's height. - * - * @return {@link SnapshotView#getHeight()} - */ - private double getControlHeight() { - return getControl().getHeight(); - } - - /** - * The currently displayed node. - * - * @return {@link SnapshotView#getNode()} - */ - private Node getNode() { - return getControl().getNode(); - } - - /** - * The current selection. - * - * @return {@link SnapshotView#getSelection()} - */ - private Rectangle2D getSelection() { - return getControl().getSelection(); - } - /** - * Indicates whether the current selection has a fixed ratio. - * - * @return {@link SnapshotView#isSelectionRatioFixed()} - */ - private boolean isSelectionRatioFixed() { - return getControl().isSelectionRatioFixed(); - } - - /** - * The current selection's fixed ratio. - * - * @return {@link SnapshotView#getFixedSelectionRatio()} - */ - private double getSelectionRatio() { - return getControl().getFixedSelectionRatio(); - } - - /* ************************************************************************ - * * - * Inner Classes * - * * - **************************************************************************/ - - /** - * A selection event encapsulates a {@link MouseEvent} and adds some additional information like the coordinates - * relative to the node's preferred size and its position relative to a selection. - */ - private static class SelectionEvent { - - /** - * The {@link MouseEvent} for which this selection event was created. - */ - private final MouseEvent mouseEvent; - - /** - * The coordinates of the mouse event as a {@link Point2D}. - */ - private final Point2D point; - - /** - * The {@link Rectangle2D} within which any new selection must be contained. - */ - private final Rectangle2D selectionBounds; - - /** - * The {@link #point}'s position relative to a possible selection. - */ - private final CoordinatePosition position; - - /** - * Creates a new selection event with the specified arguments. - * - * @param mouseEvent - * the {@link MouseEvent} for which this selection event is created - * @param point - * the coordinates of the mouse event as a {@link Point2D} - * @param selectionBounds - * the {@link Rectangle2D} within which any new selection must be contained - * @param position - * the point's position relative to a possible selection - */ - public SelectionEvent( - MouseEvent mouseEvent, Point2D point, Rectangle2D selectionBounds, CoordinatePosition position) { - - this.mouseEvent = mouseEvent; - this.point = point; - this.selectionBounds = selectionBounds; - this.position = position; - } - - /** - * @return the mouse event for which this selection event was created - */ - public MouseEvent getMouseEvent() { - return mouseEvent; - } - - /** - * @return the coordinates of the mouse event in the nodes' preferred coordinates - */ - public Point2D getPoint() { - return point; - } - - /** - * @return the {@link Rectangle2D} within which any new selection must be contained - */ - public Rectangle2D getSelectionBounds() { - return selectionBounds; - } - - /** - * @return {@code true} if the {@link #getSelectionBounds() selectionBounds} contains the {@link #getPoint() - * point}; otherwise {@code false} - */ - public boolean isPointInSelectionBounds() { - return selectionBounds.contains(point); - } - - /** - * @return the {@link #getPoint() point}'s position relative to a possible selection. - */ - public CoordinatePosition getPosition() { - return position; - } - - } - - /** - * Handles the actual change of a selection when the mouse is pressed, dragged and released. - */ - private static interface SelectionChange { - - /** - * Begins the selection change at the specified point. - * - * @param point - * the starting point of the selection change - */ - public abstract void beginSelectionChange(Point2D point); - - /** - * Continues the selection change to the specified point. - * - * @param point - * the next point of this selection change - */ - public abstract void continueSelectionChange(Point2D point); - - /** - * Ends the selection change at the specified point. - * - * @param point - * the final point of this selection change - */ - public abstract void endSelectionChange(Point2D point); - - /** - * The cursor for this selection change. - * - * @return the cursor for this selection change - */ - public abstract Cursor getCursor(); - - } - - /** - * Implementation of {@link SelectionChange} which does not actually change anything. - */ - private static class NoSelectionChange implements SelectionChange { - - /** - * The singleton instance. - */ - public static final NoSelectionChange INSTANCE = new NoSelectionChange(); - - /** - * Private constructor for singleton. - */ - private NoSelectionChange() { - // nothing to do - } - - @Override - public void beginSelectionChange(Point2D point) { - // nothing to do - } - - @Override - public void continueSelectionChange(Point2D point) { - // nothing to do - } - - @Override - public void endSelectionChange(Point2D point) { - // nothing to do - } - - @Override - public Cursor getCursor() { - return Cursor.DEFAULT; - } - - } - - /** - * Executes the changes from a {@link Rectangle2DChangeStrategy} on a {@link SnapshotView}'s - * {@link SnapshotView#selectionProperty() selection} property. This includes to check whether the mouse moved from - * the change's start to end and to possibly deactivate the selection if not. - */ - private static class SelectionChangeByStrategy implements SelectionChange { - - // Attributes - - /** - * The snapshot view whose selection will be changed. - */ - private final SnapshotView snapshotView; - - /** - * A function which sets the {@link SnapshotView#selectionChangingProperty() selectionChanging} property to the - * given value. - */ - private final Consumer<Boolean> setSelectionChanging; - - /** - * The executed change strategy. - */ - private final Rectangle2DChangeStrategy selectionChangeStrategy; - - /** - * The cursor during the selection change. - */ - private final Cursor cursor; - - /** - * Indicates if the selection will be deactivated if the mouse is only clicked (e.g. does not move between start - * and end). - */ - private final boolean deactivateSelectionIfClick; - - /** - * The change's starting point. Used to check whether the mouse moved. - */ - private Point2D startingPoint; - - /** - * Set to true as soon as the mouse moved away from the starting point. - */ - private boolean mouseMoved; - - // Constructor - - /** - * Creates a new selection change for the specified {@link SnapshotView} using the specified - * {@link Rectangle2DChangeStrategy}. - * - * @param snapshotView - * the {@link SnapshotView} whose selection will be changed - * @param setSelectionChanging - * a function which sets the {@link SnapshotView#selectionChangingProperty() selectionChanging} - * property to the given value - * @param selectionChangeStrategy - * the {@link Rectangle2DChangeStrategy} used to change the selection - * @param cursor - * the {@link Cursor} used during the selection change - * @param deactivateSelectionIfClick - * indicates whether the selection will be deactivated if the change is only a click - */ - public SelectionChangeByStrategy( - SnapshotView snapshotView, Consumer<Boolean> setSelectionChanging, - Rectangle2DChangeStrategy selectionChangeStrategy, Cursor cursor, boolean deactivateSelectionIfClick) { - - this.snapshotView = snapshotView; - this.setSelectionChanging = setSelectionChanging; - this.selectionChangeStrategy = selectionChangeStrategy; - this.cursor = cursor; - this.deactivateSelectionIfClick = deactivateSelectionIfClick; - } - - // Selection Change - - @Override - public void beginSelectionChange(Point2D point) { - startingPoint = point; - setSelectionChanging.accept(true); - - Rectangle2D newSelection = selectionChangeStrategy.beginChange(point); - snapshotView.setSelection(newSelection); - } - - @Override - public void continueSelectionChange(Point2D point) { - updateMouseMoved(point); - - Rectangle2D newSelection = selectionChangeStrategy.continueChange(point); - snapshotView.setSelection(newSelection); - } - - @Override - public void endSelectionChange(Point2D point) { - updateMouseMoved(point); - - Rectangle2D newSelection = selectionChangeStrategy.endChange(point); - snapshotView.setSelection(newSelection); - - boolean deactivateSelection = deactivateSelectionIfClick && !mouseMoved; - if (deactivateSelection) { - snapshotView.setSelection(null); - } - setSelectionChanging.accept(false); - } - - /** - * Updates {@link #mouseMoved} by checking whether the specified point is different from the - * {@link #startingPoint}. - * - * @param point - * the point which will be compared to the {@link #startingPoint} - */ - private void updateMouseMoved(Point2D point) { - // if the mouse already moved, do nothing - if (mouseMoved) { - return; - } - - // if the mouse did not move yet, check whether it did now - boolean mouseMovedNow = !startingPoint.equals(point); - mouseMoved = mouseMovedNow; - } - - // Attribute Access - - @Override - public Cursor getCursor() { - return cursor; - } - - } - -} diff --git a/src/impl/org/controlsfx/control/validation/decoration-error.png b/src/impl/org/controlsfx/control/validation/decoration-error.png deleted file mode 100644 index 237b39fa3d06785b37423903644f3c13c7967cb4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3158 zcmeAS@N?(olHy`uVBq!ia0y~yU;weXIM^5%7<!G)?`2?M;4JWnEM{Qf76xHPhFNnY z7#O(xGo76S0y6ST@{2R_3luz^ofQg-^3yVNQW+R3Zp{r&4+(xLX8Zl#7bowIhAH0p zL82TAK~CKbA`{iL6gdUFIusY)6b(Em=<3QMePTfeb6;OWk7%F{PZ!q>_9u#q`kEJa zbe;PBuzGR!wLRaTo&C4<y4~|NpXY8q&whY|XPSp`plJioN+&tN2hGQi9DDdg&!Le^ zrGP<zV{?jP@n2;|h97k{Hrh%D*!M9oR$S)hU^w7A`+$K=`+xpdPBUW|8(J6-luWen z=4cRMaH#5YTE^hu#@H}-hFUPg0v3jZ)5%GX83J?}64dLTU1n&Q`(tJ`BSZ8QMN!5D z6B!hQQ#)K3GOQWaoDb`AWr#3f5J~esV##nrm%+d@Jk5h)!*+%P=LEPnF>vrO7zB2- zYBI1?GbEf)R<2-ZnaLpH_9@)vqxL$1=UNO56*D*4>{PLIZH(s7Eo2W5*OSvY=P9l& zVwT91ILkrrP~}WXqec_{2cOR{Ff5oTD)^xJ^WTbdeCy7gGwa*N7q9zjKihw$q@>6H zo}OP_;K0D}u%zzdKOOzeQVrH@4Y~goslH>$h~r*R`n@}C6Tib&h6OKgg?}ypg^laN z2|I7zeEQ_c4X-0k(TS(RYyYJmia!wkH|J-a&7bdIAMAUi(r6Uh=+5%v!J#u>e3r_b zpTyacbmv*W`=9OH|NqEdRyyLDv@=3W<Z+--VV}#ap3g>0l{%d!X&zO*^grd%eVyOT zcK1ygHe}f`R!`Jj5u42X&0Ad{qU6A%?+gr|cIO|wqQSx3kkS0`eEI+P_J7?Ms4_I9 zc}^;1V2E>3(F-}X+5R{O1B1(gMy(Bw(q9fr=p0~^ImmkFAorgHvlb_nBZr&>oVZdN zWQr0r*EBh4w4L1`tCgUC#X;8OKww7O<N`juL!mqPYzz2*C34I=sIjM!lg04_hj60e ztq#Vdt_bBm4)K|-KNJsoun2XlD4gsN2~_f)XzF1Y)D@x->LL5dwus5HJ;rU<MC%g_ zMooX(_P85PY1|ZOdxdAK^Uf9KQY~(axG$uX7|!Y!TQK`V(H1G&9<zndFRaesztwN& zeB9u`3ki1PBRK|o#|}Gfw9w(4oP2tt(i)!C$D}rdtzq8X`8E0c#&Q;+M%M$JW-R4S z3W;)#9uYnfem6W;D9EUo2;Sl}=VWdPJfyBPd4=~DwOxWgk4PjL8Ma4w=qO(k>KE1* zsP1q+Vy+_8>1?FFa{`m+#w8(_gf6*V$_r9{sk3sniHDT(<de5jvNy3?PSH`&KGFJQ z?vuk$jGst9QT!CmH8;tjaLJG0M;bw=vb-dp3OqG=%9c9A$T4*Btf0Fq7KR9#_D4Cb zUAQf1ePH_vVUyBXmS>yAJiV8$T{QKwREBuQ_ssP#N_Gj}ohs)y{X+Pq(=Xj$On<@r zrJRSiO|<!VN4kdOYzcOWbjfmw^)q~yNnY-jJRV|TZuok}^O^iJ^Ft%FwrSOfPCUgm z)oZHSRB0{!kd>>Jt-800JM?qt>5%@Faly6g+(M0mAFt%RGHrF}s<{ELgQbJhS6Z)V zUzNThKg51XUF6?Rw#dUihy9(G1TNSZ|9H<a1@2_Y%@sO|*}SXUN*hg&sBJuZv!+aI z_l&=?ySr^ytz2m7Z0uzmzB%aglr($x$1@6l%qj8Xe6F#4`scc?dm`^OA8AT2Gx6DJ zm>QG4YTEQ^5vx5`2d;L1z1M8r+vRhY?RDK9`MZ(N@wk_IjJkVz|2fvV&x3CU-(AkN zT+G+j>gzhaRoP3W7w&c`-=DYq-Hdtr;u_}p<S)Nhx%c@mnOgn7A%Am!E&uAy6T!Bb zM}_S+&p8R3qo#%VHnRH1Z+{GQjy>$)yfkrY;`E0t6L(&;S$x&4*Nwj?^H|JdmB+cq za*r)mV^dR9^Y(q^`)*c{@6KhK%dCB@eU6_!b9T|$Ycow}+ZtXsdOrL4?CZ1dZ%>G- zh|<}%V%v^X&rMIFmPNkXwkNMO$})0kL}*m(X1BF-*Q#FIy>|C<!R0&sCi|_PcP;(! zhL77$Zd<usa>LUbY`52K%iUI+n4Tn_zWwOB!|x{Vom{)Cw)d|sJ8%0<zSXi(vUSB< zibSl!tnSS^H|L#w?a?pOUh1buoEJEM!}#$w;nSK&GUo=*zU-bZp1!lV`Ey5ir+3q7 zz3Fy(v!##SJ+b$RSIO7H*oRe@zRsP!dG?{VD{ilUXZ9}hUHhH+XH4d6&WkiIzHs=2 z^Mk;r7wx&{Pc_KCzoyRL*}pM;>vLuOWc`WZYp-wEzO;PR_r&+&cHiuZ=0CQ3Y-4`U z=w4*}8S?|%Pi#N!e>i_$eCvJZdgcEq|EvCAWLVyy%9zgF+3469&Gh?6RgL2QK6|U% zsoyr;eCyb=V5g&~V}H}yrl$wjDrTH`Ghwab_vbUtO+1&$*BVgw;@SoF#Ak`!hwFIM zTiaX1+wA)aIwGVl8csJYzj(*F_`b_8muW8dW~UqaTdvpjGS#wMrI%%M%Y2u~F8gD8 zX_05HM$C=y%<-17)YDpLmY1{d{-3v>+aJw+#QnHhe1`ss*n-N1=MH^oT`sm#Pe{jV znuAY=pT(39jsjXM#ClXe374z(aaA6YJ(RAbf6?q>#|`HgEjhnW9$LOtlip0+V_K<l z)Oe}R)158qD<|yn;q|#Y+iITJtTKgMBU`JzhRu^EPAGI*rRY0(Tl%Z?XK7`p*QB;? z`gb(1d%M2eRQ8kEn<uPcjnw7Z=CtfZNR-BPE%r_6so`n+&vu@&oVI$N_Sv^*HlMmZ z!F<m9`TySv9TIvtY1`5^?{Hn&h-Z7(WLa*qDXhHB^;ncuyDf}ujm?g(ZCbfk{a3#Y zpT4ecuUeIFc4OSZQ%wiAGG@Q#4&{2<TKoFW^|!J95&Dt$w<i8-n=5T6+S#>E<hJ;9 z(fS)2cPgGrx96YQKl9F%Eh|?a*_m=a?NZvyXZLjHMe|KtHT~IizC7NWx3=)!58Lwg z>o?ci`qR&9+}_>1&3WhI{Wd%Hq%J>s?yR+a$dZsRA-_V*-d(!8HSzk7yo>LotM_~} zd2{u4^q%j3?N08y9m*K$do}H9>Tl2Ao4?zy>s<Bn$F$$Mv1|Qu3*R1RzQp{OU72s& z^_^F)%3iV!3F^P5{o0-Hxct6<bKjTi@|y96_Rcx>NV&kJ^2y8ZocF)W@mk#~>#1Jz zko~fJnQXeOewNd$PqW-+2haK)ofN&x|BT(mYp?EA{c*o7&p*e+CbH7&bI8feTQ8d~ zPfq`IzGv>#xwUnAKkp>mUbL<HdGfjYS^W9$cL|g{yyW`7`?>WV>vJ)mc9eYDbo;4r z_>S;d>#gE*UzNPF`8WBp|MA^(cF$V3GbVfIyQ;lgtJA)}l%8jP?(Ubpl^@0aU%NWb z()RA&&sF)~kADApU+ivOk^0|rr+42hSAVy5kN=+dFAi@VZ#v&?ziJ=-@6L_)cj~ha zlrQ*v@s9g<w$|qJ|0aIz=XYl9pV@!9jkoRfJPSKZ%SZM_e_#Gt?tDJwyxKhRe~bQ| zUMDW5U-#qc>+9z(&bYX6`lsoW_vh9u{rl>`YsvMuj~zNDx9?<yv0>bou-|VFmftCt zeZTlVzyFgOg?f$u89z6E4Zg7a_hiY*lmD|Y&-nZ&*;w~B0|SFXvPY0F14ET614BbI z1H;e%3=9n~85l|p7#Ln9FfdrnU|<l>pA>)8je&u&(bL5-q~eyzL0|8XK!%2g-)qk7 zEq`Y*+3K)?u~^2Im)U~3Q7c)xuK8;;iz!YKaPgWbvbDn~W2VP`XN{Q)LLcbF>?lxe z@>SMzn>p)U&E4YjnO8q|{EFbaE}P(2eR$=e6U^^V9lh<xk@)?)xn<^B^`%MG6Syv@ zusxEHJhA-OudPSFTq$AHeDS0%#_0A|lVf|_B(4a*<*N9%>Hmk1-nPc#x8}FsaO9b6 z?rdpjm;3G86xk!zK~GP2XZ<;}O2Yd1i@Cdx%+#@6c|!kAa}aB3U6N((wmnNYjW=s? zl)V3}-dBHh<(_Ef2QQ8mPkJBvC&_Tb4#`fTYi@$yzOdZx{Bizh+mfq?%B&Y`xsbB? z>W-Ux9_rrVKb3#~a>X_#hsw9i$DI|I{kpoOYpL$n7oV=izO4-7?f2Q5Z8|AGddDxt zxo*r~pPO&_zpwCAyg2*k;vbp(7vJyoT9k2ebqJRe$FJVS%TBdOYn7*6{UU5)F~{&k x!HdP>ZL!ba=*omWbKf6vx^0sf;~!~;ZDuob9`-S%FfcGMc)I$ztaD0e0svi}>|_7{ diff --git a/src/impl/org/controlsfx/control/validation/decoration-warning.png b/src/impl/org/controlsfx/control/validation/decoration-warning.png deleted file mode 100644 index 0d351c5bff6d7085586d58807b006ca05e75af88..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3120 zcmeAS@N?(olHy`uVBq!ia0y~yU;weXIM^5%7<!G)?`2?M;4JWnEM{Qf76xHPhFNnY z7#O(xGo76S0y6ST@{2R_3luz^ofQg-^3yVNQW+R3Zp{r&4+(xLX8Zl#7bowIhAH0p zL82TAK~CKbA`{iL6gdUFIusY)6b(Em=<3QMePTfeb6;OWk7%F{PZ!q>_9u#q`kEJa zbe;PBuzGR!wLRaTo&C4<y4~|NpXY8q&whY|XPSp`plJioN+&tN2hGQi9DDdg&!Le^ zrGP<zV{?jP@n2;|h97k{Hrh%D*!M9oR$S)hU^w7A`+$K=`+xpdPBUW|8(J6-luWen z=4cRMaH#5YTE^hu#@H}-hFUPg0v3jZ)5%GX83J?}64dLTU1n&Q`(tJ`BSZ8QMN!5D z6B!hQQ#)K3GOQWaoDb`AWr#3f5J~esV##nrm%+d@Jk5h)!*+%P=LEPnF>vrO7zB2- zYBI1?GbEf)R<2-ZnaLpH_9@)vqxL$1=UNO56*D*4>{PLIZH(s7Eo2W5*OSvY=P9l& zVwT91ILkrrP~}WXqec_{2cOR{Ff5oTD)^xJ^WTbdeCy7gGwa*N7q9zjKihw$q@>6H zo}OP_;K0D}u%zzdKOOzeQVrH@4Y~goslH>$h~r*R`n@}C6Tib&h6OKgg?}ypg^laN z2|I7zeEQ_c4X-0k(TS(RYyYJmia!wkH|J-a&7bdIAMAUi(r6Uh=+5%v!J#u>e3r_b zpTyacbmv*W`=9OH|NqEdRyyLDv@=3W<Z+--VV}#ap3g>0l{%d!X&zO*^grd%eVyOT zcK1ygHe}f`R!`Jj5u42X&0Ad{qU6A%?+gr|cIO|wqQSx3kkS0`eEI+P_J7?Ms4_I9 zc}^;1V2E>3(F-}X+5R{O1B1(gMy(Bw(q9fr=p0~^ImmkFAorgHvlb_nBZr&>oVZdN zWQr0r*EBh4w4L1`tCgUC#X;8OKww7O<N`juL!mqPYzz2*C34I=sIjM!lg04_hj60e ztq#Vdt_bBm4)K|-KNJsoun2XlD4gsN2~_f)XzF1Y)D@x->LL5dwus5HJ;rU<MC%g_ zMooX(_P85PY1|ZOdxdAK^Uf9KQY~(axG$uX7|!Y!TQK`V(H1G&9<zndFRaesztwN& zeB9u`3ki1PBRK|o#|}Gfw9w(4oP2tt(i)!C$D}rdtzq8X`8E0c#&Q;+M%M$JW-R4S z3W;)#9uYnfem6W;D9EUo2;Sl}=VWdPJfyBPd4=~DwOxWgk4PjL8Ma4w=qO(k>KE1* zsP1q+Vy+_8>1?FFa{`m+#w8(_gf6*V$_r9{sk3sniHDT(<de5jvNy3?PSH`&KGFJQ z?vuk$jGst9QT!CmH8;tjaLJG0M;bw=vb-dp3OqG=%9c9A$T4*Btf0Fq7KR9#_D4Cb zUAQf1ePH_vVUyBXmS>yAJiV8$T{QKwREBuQ_ssP#N_Gj}ohs)y{X+Pq(=Xj$On<@r zrJRSiO|<!VN4kdOYzcOWbjfmw^)q~yNnY-jJRV|TZuok}^O^iJ^Ft%FwrSOfPCUgm z)oZHSRB0{!kd>>Jt-800JM?qt>5%@Faly6g+(M0mAFt%RGHrF}s<{ELgQbJhS6Z)V zUzNThKg51XUF6?Rw#dUihy9(G1TNSZ|9H<a1@2_Y%@sO|*}SXUN*hg&sBJuZv!+aI z_l&=?ySr^ytz2m7Z0uzmzB%aglr($x$1@6l%qj8Xe6F#4`scc?dm`^OA8AT2Gx6DJ zm>QG4YTEQ^5vx5`2d;L1z1M8r+vRhY?RDK9`MZ(N@wk_IjJkVz|2fvV&x3CU-(AkN zT+G+j>gzhaRoP3W7w&c`-=DYq-Hdtr;u_}p<S)Nhx%c@mnOgn7A%Am!E&uAy6T!Bb zM}_S+&p8R3qo#%VHnRH1Z+{GQjy>$)yfkrY;`E0t6L(&;S$x&4*Nwj?^H|JdmB+cq za*r)mV^dR9^Y(q^`)*c{@6KhK%dCB@eU6_!b9T|$Ycow}+ZtXsdOrL4?CZ1dZ%>G- zh|<}%V%v^X&rMIFmPNkXwkNMO$})0kL}*m(X1BF-*Q#FIy>|C<!R0&sCi|_PcP;(! zhL77$Zd<usa>LUbY`52K%iUI+n4Tn_zWwOB!|x{Vom{)Cw)d|sJ8%0<zSXi(vUSB< zibSl!tnSS^H|L#w?a?pOUh1buoEJEM!}#$w;nSK&GUo=*zU-bZp1!lV`Ey5ir+3q7 zz3Fy(v!##SJ+b$RSIO7H*oRe@zRsP!dG?{VD{ilUXZ9}hUHhH+XH4d6&WkiIzHs=2 z^Mk;r7wx&{Pc_KCzoyRL*}pM;>vLuOWc`WZYp-wEzO;PR_r&+&cHiuZ=0CQ3Y-4`U z=w4*}8S?|%Pi#N!e>i_$eCvJZdgcEq|EvCAWLVyy%9zgF+3469&Gh?6RgL2QK6|U% zsoyr;eCyb=V5g&~V}H}yrl$wjDrTH`Ghwab_vbUtO+1&$*BVgw;@SoF#Ak`!hwFIM zTiaX1+wA)aIwGVl8csJYzj(*F_`b_8muW8dW~UqaTdvpjGS#wMrI%%M%Y2u~F8gD8 zX_05HM$C=y%<-17)YDpLmY1{d{-3v>+aJw+#QnHhe1`ss*n-N1=MH^oT`sm#Pe{jV znuAY=pT(39jsjXM#ClXe374z(aaA6YJ(RAbf6?q>#|`HgEjhnW9$LOtlip0+V_K<l z)Oe}R)158qD<|yn;q|#Y+iITJtTKgMBU`JzhRu^EPAGI*rRY0(Tl%Z?XK7`p*QB;? z`gb(1d%M2eRQ8kEn<uPcjnw7Z=CtfZNR-BPE%r_6so`n+&vu@&oVI$N_Sv^*HlMmZ z!F<m9`TySv9TIvtY1`5^?{Hn&h-Z7(WLa*qDXhHB^;ncuyDf}ujm?g(ZCbfk{a3#Y zpT4ecuUeIFc4OSZQ%wiAGG@Q#4&{2<TKoFW^|!J95&Dt$w<i8-n=5T6+S#>E<hJ;9 z(fS)2cPgGrx96YQKl9F%Eh|?a*_m=a?NZvyXZLjHMe|KtHT~IizC7NWx3=)!58Lwg z>o?ci`qR&9+}_>1&3WhI{Wd%Hq%J>s?yR+a$dZsRA-_V*-d(!8HSzk7yo>LotM_~} zd2{u4^q%j3?N08y9m*K$do}H9>Tl2Ao4?zy>s<Bn$F$$Mv1|Qu3*R1RzQp{OU72s& z^_^F)%3iV!3F^P5{o0-Hxct6<bKjTi@|y96_Rcx>NV&kJ^2y8ZocF)W@mk#~>#1Jz zko~fJnQXeOewNd$PqW-+2haK)ofN&x|BT(mYp?EA{c*o7&p*e+CbH7&bI8feTQ8d~ zPfq`IzGv>#xwUnAKkp>mUbL<HdGfjYS^W9$cL|g{yyW`7`?>WV>vJ)mc9eYDbo;4r z_>S;d>#gE*UzNPF`8WBp|MA^(cF$V3GbVfIyQ;lgtJA)}l%8jP?(Ubpl^@0aU%NWb z()RA&&sF)~kADApU+ivOk^0|rr+42hSAVy5kN=+dFAi@VZ#v&?ziJ=-@6L_)cj~ha zlrQ*v@s9g<w$|qJ|0aIz=XYl9pV@!9jkoRfJPSKZ%SZM_e_#Gt?tDJwyxKhRe~bQ| zUMDW5U-#qc>+9z(&bYX6`lsoW_vh9u{rl>`YsvMuj~zNDx9?<yv0>bou-|VFmftCt zeZTlVzyFgOg?f$u89z6E4Zg7a_hiY*lmD|Y&-nZ&*;w~B0|SFXvPY0F14ET614BbI z1H;e%3=9n~85l|p7#Ln9FfdrnU|<l>pA>)8je&tN+SA1`q~cc2Ia?2=LYelD@BjL@ zKRI*x&<69jsVAnlbY)D;;x=k3>dNZwY2s*KwqT*-(hRGWH#0Ig*|#gLSgR<t%b;n( z2F0@?M^Ek974IzQV)r?{qT-M5>(9Pxtz`84l@#YQ2L$Twuh(?3|0ynZICSF1bqD9w zp9^16;}Fsrs2Cs8Q=0bMeuv<cvQ9mXU8Zi;w;#KdcxJzzZM|PXfMdbNrI+XW-rs+D zZgbmj7O7Wj6?eT}^xS8Y&MX~2h6k#iO$yuE-ECX<^>cHkZ+Giplijn{ljEGDZ{*wS zbLJg+9FwB{>SN!RIkPSYulb?iTz7$qA?7R>&$YZgrAMafJ>M|f_Gw(&+HE4$dnS6W zXYcD1m66rHaGk0DdU%S-$y=8HPi<N@!MnC0+TpfOPcs__?}qo4fvvuZd=jkA0jEFO zgxech+Uj>qQwwDkE_uMX;gYtUB=c17n?7#}>_3?@EZW@XXUi$~gMop8!PC{xWt~$( F695s{$6^2g diff --git a/src/impl/org/controlsfx/control/validation/required-indicator.png b/src/impl/org/controlsfx/control/validation/required-indicator.png deleted file mode 100644 index 4410d654cf218f43f5e65f2dbf29c1b03a846044..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2955 zcmeAS@N?(olHy`uVBq!ia0y~yU;weXIM^5%7<!G)?`2?MU`coMb!1@J*jMvAa54h} zgF>=LkS_y6J3j+M4?hFL-yjBtMh6Cl+DZn7m)#5uHcuHCB+nGvw3ah4a9L(LI|l@0 z<d@_ZXXF<scse^P6cpvBW#*(ZFnAoFJFPq<<hoe<`Mu>;3(p!b1-0GVeSqOo_2f9$ z#2Jza8q9pgCL0wOF$uc5%u@0QIMQ%2Kqbs&qku@r26hz=4MPdn5S@ItYu)SC?D_ub z)9=S?^51U$zVr8+z2~FE873{)pFW+<n{mP^;SbF=b6yHg3@mxW(7-5{(4fiS6Xv!n zenT~fz{%5RTjwbjF~zemeyEDr!&Gqjf^mZ%`~Ue%B45@tzL>!vID50Dq>i9?hlQ&5 z1ifwNyJkpD*GZF5P1~p8D0sTlGI1iW-EW;ui)Y+iX|t{4sO9p_!8eoMiGJMXqv(F5 zV|@p=@y<Cqg7<|sx^)>$)qZ6D=tc;iF*AdRXO4J5M5mIOpkb%H&=aLcPZ=I~aK;zj z3D<d$!hK|Vk*D|hhsDA|tR=G3^zL4{HOuk)la!?eEKG+P)U;=wOurm^Dd_UdJu(bp z@Bc&^J-T(t)peW6)@@r%OpJ~Gt_t{H`Z?e0&TZE!$saq@1=jxWe!Kq9B`Jo4Go4wR zKX>b{<7zmk%W&fE@1)BX3=K<G<jY>)zl-13M!%EEaaZrg!mzMug3}Kh35kE<|Lfnr zf8qLl=_+>b`afNWwfyLl*wvu7PFh=6)%V2m^d-iTGP@qmZ~r0B{;yPy&2dfz-~7YE zt}UI*dQN)_Y@L1l8P|?X8>{Kx=g<1VfB4^$qdUbqFZ~b<NbYI4QmW-p_m*9QOHkqB z@1wE*7w7N$VW3b~`A}<eck%!C=6}-<E`6lhJo|&?IaQ68b3&ht#lIgpFSLM>(Su2A z0{bZk*%u7X32bW`bPHJW4oLrK77*YJV;1vZS=qq9$wBT03zwte4bE>3Spn=)j>Z|R z#~sxzSkE<kKakqNnAiL}LByvaJwa>_8@B*UqN0&Y;}b<u58+GgXB5~{_;)()3lI?D zJnF<Lz%S%fc_D3ugjVyag;gsgf5};K&TU`k(0m~_gJ)J-UHiR*96n7eHwdj^l|IaK zgY#RX^MlX=raf%uTDc#{7O37~kZ-kq@cD!34>KDs`{w5Y4FZBvi@GF~c#g1sbYC=~ zqNRV0d)EZ6C5)M_yC&K_Q8Vf~qmUmcA;RkFF1aWtaNddl5$>&QTjfHVR=LT#l`g0X zG!IN(5qZVkL~?D%HTT;K_FfQt!BQf&OCYu}&uRN&{YCkU)i10!l;GiA+`I8mMUs-C z=Zvj0gwELcNI#QF6EN<Zc{pj~r-<4$ve)EKAK}{2dPD0?;G4)d0%c6U+1!t;d~l}V z-3|>I{^|Xz56B*zdyw~`S|N9Z<{q_sZ14Ni9~XaE`opcp{GU}F(|(5uY8k?BI22n{ z4yie*E}U90@k7IhNggVz1lM*py66=uZ=6)oQ!&%Rt;Tzj;>(FK9v4*<GudAXyp(yV z_fmDH&ow3MNsCV~ec~%J{>k)H@MkZJ>miRr-c7n29T&MRa!&Giv{NN6DEN|R(bkl8 zDXmX9PrjaH98{sHt0}Iz>`K*2sg;w1l!J;diDU+6*1rsSDfCkLQuvbPDI1KUjPi_f zW-`reHWE)crpe(t_mNX#pjoh#rnshX2v6wjSFXN`#De!P<_kzqO--48vh8Hr>1!wE zO_N=!XrenyT(>pM%i2$R+1}_yTaILMrl0(#y4JgG+L_b3Q;VlOJ|TK?>&d&*s@46c zmrwSec3<_r=Klc3r3;n|teCKLL;S-<ht34O3c9^?%~DtIe*L}6IkaDCvT3dhwOMgv zy~Xk+Yo08evMyw4iDRbQ%w=y@%vln%uEwo0s&!G)`a_|b;g+jEP0{l%U$p#!_RGCr zB12t6{X-XK?S0kos%h4?s1;HBqGsQ6E^V@MwvF2xv)8>g%-Qv@zq0>g*T?hJ;wCSg zxngJdX8+<i?`Z9q?A2k*uT9xDXWR6$b!FY(m}NKhHJ_83%QiQ9mqct^-llhUccrT~ z%xjHX6xVyNv^L^?(EQc={p&9<<R;`EFwQWLFjSGWl1!7@CebH(v8Sf@Q?FI;Jn3u+ zcggog?~MOtBqdHtx|C6LKjhez+a~w7-2PH-Y->C%viGKL@ur=-f3khn`z(I?%k;u& zZ{y33Hzhqx-*|P=@kh-|r>frHbhYS~*I}(|tFC3WIHs}~cu7oOd-2-2Ytn1{BlmCJ zxJB@W%=VvWuU#;^`K{yam7=##=REB_ef;f}H#5q<mM#8P@;l-;^S8x(tN47{+1iiy zz3R(3u6Ep0J$AXu^2L7V=lah1dG77G&w6HhuVc>bR9Yvu&UGDgo>AVyysLTrcdp(M zz7u^X-B!ouTGgD-F4ey(-hGn!81yNr(zN<)RdnV0&+on}{$%+b^4sRy)z43Vm;F9i zcdu^uU%53GVh%=Me98Z3@1OGD_B<E(B7{FAE2tSLY*72)IUzG3E+F1O)k5uu$A{Mf z&nH}(@Oz=v!b2D48JyhkV#BiyKMSsZ*!1Bd$K#Gt!Rtz*N;@aU2Hse)Va2i)JE!Jp ze_u1FV_Sz_k6hf+y;{{*r(We+9UL~lZ(>j4u{j;C$J>s}b=IE$l5S@3{L!9AS&!2q z_15fNlb+*VW?4Ne`MBm|pJTU=PCx3edPDV%-weMJk2M~19_}hwy;FaZ&E!{;o=yHc znP0Wui_<^T`{>eR%jP{f`C(G!-po^(H#3`G{(9N^a&dOfwKtK*r@ucmPj!%7ZM2Ie z<l^~|{Q>SfTrH+$&X1h@Q%zgvwac~=GyUE6?)vG~=Tg>HzuTT2m>rp2{VC+L+0)*& z#Zlq=<)Y-b?@Mp~)z-u-ENyEhchBX<lszw(*G&Gi=}-9V!{+7U8lpKm689f%T)H%1 z(S&%5O;^jZ@0wjPd$+Ce?X%mfx7F(;iO1@iX|B_#i$A2b^H=Xn^Qrf1ZVB#BUT|eo z$$!5ye)rBjjOE+SH{Emk(`mi$zumqY=%=r*Rlij|?flfPRMFCE&g#}`ckNp3-K$Ji zm4)qH@3&@O?BkfrVXGr{?=7p7ufBhw?)cxerCy~+OW*Sq@ZVYaeZ~8X3t1~HIxJ^Y ze(+3=NWQ<lCx7;Aky%}{?PMOwO4-Vk?AU&D)y|(Ck0xFc+u?e{sMh4yi{AG!`(J07 z=B&+Myj4`5`FP9md3Ex?|9&W(|JYVtLOrVf!k>lP=3a`s!dUvG<V=}bSznoJ8SlI= zb~i8Q-oE>9@x}gjzm@Y=S?X5r`oi<j=ip5L^y2g9=6c(k7u!AjQ{nG({x7$nc-~jG zZ+tOdc2@kH^m{3HtzT`r{_R-1(xcB#om}0sdhT_d^`&2;zij`X@-g^#!&8UjrK?}Z zny<+(;n$P5F@9oD@^9Jev)<eH<i+mZ`{>()f)^j=PJA)(qV*f=;PT*i`*uvP%zyar z82bx$SN^4PVKzZES3YchcRqLVw8hJh#~lA9&u+iZ{+v|(H}7Nm@71~HO_(3zv&zTJ zf2Qx;S!MJ0eJpu;xikIcd9gIE`l<i6e%pEOvwU6gpSAU7No9{%{~uj`-#hNqew!~@ zH&@Tw*|5`neQ><~8S%Xn>x+NrKF+<r`$PF;?#TBW-)q~ysC)76#pjO)mtXOp|Bsb< z#^*n~j=Z?cz`(#+;1OBOz`!jC!i@DP@e>&s7{p3kBT9nv(@M${i&7a15;OBk^zu?m z6ioCCtY3W1WME*J<>}%Wq7j_@Lx1@<dFeC<b{9>iOsDXUL?IuBNJTSO|GP30^CM>& z9P)Ju|FUIO)5nQZIUk>9&_DJ(@0&oY#Jhk0=YRbF|3A<7tsxTgcUv3SeJ@Envf-^~ zrKU2+|G)p|zsyXQjbP@gm^b<4k1hN9J}zuEjQEt9Y&+vv00$rA3YLz#HwlM-oVm@L qqZ)QpU#VF#p6TP|1bdNkMut?uLa9H_{0a;V3=E#GelF{r5}E)AdxcQ| diff --git a/src/impl/org/controlsfx/i18n/Localization.java b/src/impl/org/controlsfx/i18n/Localization.java deleted file mode 100644 index 59c134c..0000000 --- a/src/impl/org/controlsfx/i18n/Localization.java +++ /dev/null @@ -1,125 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.i18n; - -import java.util.Locale; -import java.util.MissingResourceException; -import java.util.ResourceBundle; - -public class Localization { - - private Localization() { - } - - public static final String KEY_PREFIX = "@@"; //$NON-NLS-1$ - - private static final String LOCALE_BUNDLE_NAME = "controlsfx"; //$NON-NLS-1$ - private static Locale locale = null; - - /** - * Returns the Locale object that is associated with ControlsFX. - * - * @return the global ControlsFX locale - */ - public static final Locale getLocale() { - // following allows us to have a "dynamic" locale based on OS/JDK - return locale == null ? Locale.getDefault() : locale; - } - - /** - * Sets locale which will be used as ControlsFX locale - * - * @param newLocale - * null is allowed and will be interpreted as default locale - */ - public static final void setLocale(final Locale newLocale) { - locale = newLocale; - } - - private static Locale resourceBundleLocale = null; // has to be null initially - private static ResourceBundle resourceBundle = null; - - private static synchronized final ResourceBundle getLocaleBundle() { - - Locale currentLocale = getLocale(); - if (!currentLocale.equals(resourceBundleLocale)) { - resourceBundleLocale = currentLocale; - resourceBundle = ResourceBundle.getBundle(LOCALE_BUNDLE_NAME, - resourceBundleLocale, Localization.class.getClassLoader()); - } - return resourceBundle; - - } - - /** - * Returns a string localized using currently set locale - * - * @param key resource bundle key - * @return localized text or formatted key if not found - */ - public static final String getString(final String key) { - try { - return getLocaleBundle().getString(key); - } catch (MissingResourceException ex) { - return String.format("<%s>", key); //$NON-NLS-1$ - } - } - - /** - * Converts text to localization key, - * currently by prepending it with the KEY_PREFIX - * - * @param text - * @return localization key - */ - public static final String asKey(String text) { - return KEY_PREFIX + text; - } - - /** - * Checks if the text is a localization key - * - * @param text - * @return true if text is a localization key - */ - public static final boolean isKey(String text) { - return text != null && text.startsWith(KEY_PREFIX); - } - - /** - * Tries to localize the text. If the text is a localization key - and attempt will be made to - * use it for localization, otherwise the text is returned as is - * - * @param text - * @return - */ - public static String localize(String text) { - return isKey(text) ? getString(text.substring(KEY_PREFIX.length()) - .trim()) : text; - } - -} diff --git a/src/impl/org/controlsfx/i18n/SimpleLocalizedStringProperty.java b/src/impl/org/controlsfx/i18n/SimpleLocalizedStringProperty.java deleted file mode 100644 index 44ce996..0000000 --- a/src/impl/org/controlsfx/i18n/SimpleLocalizedStringProperty.java +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.i18n; - -import javafx.beans.property.SimpleStringProperty; - -/** - * A special implementation of string property which assumes that its content may be a key and - * attempts to get localized text resource base on it. - * - * It is intended for internal use only and will not work for bidirectional binding. - */ -public class SimpleLocalizedStringProperty extends SimpleStringProperty { - - public SimpleLocalizedStringProperty() { - } - - public SimpleLocalizedStringProperty(String initialValue) { - super(initialValue); - } - - public SimpleLocalizedStringProperty(Object bean, String name) { - super(bean, name); - } - - public SimpleLocalizedStringProperty(Object bean, String name, - String initialValue) { - super(bean, name, initialValue); - } - - @Override public String getValue() { - return Localization.localize(super.getValue()); - } -} diff --git a/src/impl/org/controlsfx/i18n/Translation.java b/src/impl/org/controlsfx/i18n/Translation.java deleted file mode 100644 index a972bb4..0000000 --- a/src/impl/org/controlsfx/i18n/Translation.java +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.i18n; - -import java.nio.file.Path; -import java.util.Locale; - -public class Translation implements Comparable<Translation> { - - private final String localeString; - private final Locale locale; - private final Path path; - - public Translation(String locale, Path path) { - this.localeString = locale; - this.path = path; - - String[] split = localeString.split("_"); //$NON-NLS-1$ - if (split.length == 1) { - this.locale = new Locale(localeString); - } else if (split.length == 2) { - this.locale = new Locale(split[0], split[1]); - } else if (split.length == 3) { - this.locale = new Locale(split[0], split[1], split[2]); - } else { - throw new IllegalArgumentException("Unknown locale string '" + locale + "'"); //$NON-NLS-1$ //$NON-NLS-2$ - } - } - - public final String getLocaleString() { - return localeString; - } - - public final Locale getLocale() { - return locale; - } - - public final Path getPath() { - return path; - } - - @Override public String toString() { - return localeString; - } - - @Override public int compareTo(Translation o) { - if (o == null) return 1; - return localeString.compareTo(o.localeString); - } -} diff --git a/src/impl/org/controlsfx/i18n/Translations.java b/src/impl/org/controlsfx/i18n/Translations.java deleted file mode 100644 index ab90355..0000000 --- a/src/impl/org/controlsfx/i18n/Translations.java +++ /dev/null @@ -1,129 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.i18n; - -import java.io.File; -import java.io.IOException; -import java.nio.file.DirectoryIteratorException; -import java.nio.file.DirectoryStream; -import java.nio.file.FileSystem; -import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Locale; -import java.util.Optional; -import java.util.stream.Collectors; - -public class Translations { - - private static List<Translation> translations = new ArrayList<>(); - - static { - // firstly try to read from the controlsfx jar - File file = new File(Translations.class.getProtectionDomain().getCodeSource().getLocation().getPath()); - if (file.getName().endsWith(".jar")) { //$NON-NLS-1$ - Path jarFile = file.toPath(); - try (FileSystem fs = FileSystems.newFileSystem(jarFile, null)) { - fs.getRootDirectories().forEach(path -> loadFrom(path)); - } catch (IOException e) { - e.printStackTrace(); - } - } - - // look in src directory - if (translations.isEmpty()) { - // try to read the files from the local filesystem (good for when ControlsFX - // is being run from within a developers IDE) - Path srcDir = new File("src/main/resources").toPath(); //$NON-NLS-1$ - loadFrom(srcDir); - } - - // look in bin directory - if (translations.isEmpty()) { - Path binDir = new File("bin").toPath(); //$NON-NLS-1$ - loadFrom(binDir); - } - - // look in bin directory an alternative way (good for when running - // controlsfx-samples) - if (translations.isEmpty()) { - if (file.getAbsolutePath().endsWith("controlsfx" + File.separator + "bin")) { //$NON-NLS-1$ //$NON-NLS-2$ - loadFrom(file.toPath()); - } - } - - Collections.sort(translations); - } - - private static void loadFrom(Path rootPath) { - try (DirectoryStream<Path> stream = Files.newDirectoryStream(rootPath)) { - for (Path path : stream) { - String filename = path.getFileName().toString(); - - if (! filename.startsWith("controlsfx") && ! filename.endsWith(".properties")) { //$NON-NLS-1$ //$NON-NLS-2$ - continue; - } - - if ("controlsfx.properties".equals(filename)) { //$NON-NLS-1$ - translations.add(new Translation("en", path)); //$NON-NLS-1$ - } else if (filename.contains("_")) { //$NON-NLS-1$ - String locale = filename.substring(11, filename.indexOf(".properties")); //$NON-NLS-1$ - translations.add(new Translation(locale, path)); - } else { - throw new IllegalStateException("Unknown translation file '" + path + "'."); //$NON-NLS-1$ //$NON-NLS-2$ - } - - } - } catch (IOException | DirectoryIteratorException x) { - // no-op - } - } - - private Translations() { - // no-op - } - - public static Optional<Translation> getTranslation(String localeString) { - for (Translation t : translations) { - if (localeString.equals(t.getLocaleString())) { - return Optional.of(t); - } - } - return Optional.empty(); - } - - public static List<Translation> getAllTranslations() { - return translations; - } - - public static List<Locale> getAllTranslationLocales() { - return translations.stream().map((Translation t) -> t.getLocale()).collect(Collectors.toList()); - } -} diff --git a/src/impl/org/controlsfx/skin/AutoCompletePopup.java b/src/impl/org/controlsfx/skin/AutoCompletePopup.java deleted file mode 100644 index e242d02..0000000 --- a/src/impl/org/controlsfx/skin/AutoCompletePopup.java +++ /dev/null @@ -1,233 +0,0 @@ -/** - * Copyright (c) 2014, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.skin; - - -import com.sun.javafx.event.EventHandlerManager; -import javafx.beans.property.IntegerProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.ObjectPropertyBase; -import javafx.beans.property.SimpleIntegerProperty; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.event.Event; -import javafx.event.EventDispatchChain; -import javafx.event.EventHandler; -import javafx.event.EventType; -import javafx.scene.Node; -import javafx.scene.control.PopupControl; -import javafx.scene.control.Skin; -import javafx.stage.Window; -import javafx.util.StringConverter; - -/** - * The auto-complete-popup provides an list of available suggestions in order - * to complete current user input. - */ -public class AutoCompletePopup<T> extends PopupControl{ - - /*************************************************************************** - * * - * Private fields * - * * - **************************************************************************/ - - private final static int TITLE_HEIGHT = 28; // HACK: Hard-coded title-bar height - private final ObservableList<T> suggestions = FXCollections.observableArrayList(); - private StringConverter<T> converter; - /** - * The maximum number of rows to be visible in the popup when it is - * showing. By default this value is 10, but this can be changed to increase - * or decrease the height of the popup. - */ - private IntegerProperty visibleRowCount = new SimpleIntegerProperty(this, "visibleRowCount", 10); - - /*************************************************************************** - * * - * Inner classes * - * * - **************************************************************************/ - - /** - * Represents an Event which is fired when the user has selected a suggestion - * for auto-complete - * - * @param <TE> - */ - @SuppressWarnings("serial") - public static class SuggestionEvent<TE> extends Event { - @SuppressWarnings("rawtypes") - public static final EventType<SuggestionEvent> SUGGESTION = new EventType<>("SUGGESTION"); //$NON-NLS-1$ - - private final TE suggestion; - - public SuggestionEvent(TE suggestion) { - super(SUGGESTION); - this.suggestion = suggestion; - } - - /** - * Returns the suggestion which was chosen by the user - * @return - */ - public TE getSuggestion() { - return suggestion; - } - } - - - /*************************************************************************** - * * - * Constructors * - * * - **************************************************************************/ - - /** - * Creates a new AutoCompletePopup - */ - public AutoCompletePopup(){ - this.setAutoFix(true); - this.setAutoHide(true); - this.setHideOnEscape(true); - - getStyleClass().add(DEFAULT_STYLE_CLASS); - } - - - /*************************************************************************** - * * - * Public API * - * * - **************************************************************************/ - - - /** - * Get the suggestions presented by this AutoCompletePopup - * @return - */ - public ObservableList<T> getSuggestions() { - return suggestions; - } - - /** - * Show this popup right below the given Node - * @param node - */ - public void show(Node node){ - - if(node.getScene() == null || node.getScene().getWindow() == null) - throw new IllegalStateException("Can not show popup. The node must be attached to a scene/window."); //$NON-NLS-1$ - - if(isShowing()){ - return; - } - - Window parent = node.getScene().getWindow(); - this.show( - parent, - parent.getX() + node.localToScene(0, 0).getX() + - node.getScene().getX(), - parent.getY() + node.localToScene(0, 0).getY() + - node.getScene().getY() + TITLE_HEIGHT); - - } - - /** - * Set the string converter used to turn a generic suggestion into a string - */ - public void setConverter(StringConverter<T> converter) { - this.converter = converter; - } - - /** - * Get the string converter used to turn a generic suggestion into a string - */ - public StringConverter<T> getConverter() { - return converter; - } - - public final void setVisibleRowCount(int value) { - visibleRowCount.set(value); - } - - public final int getVisibleRowCount() { - return visibleRowCount.get(); - } - - public final IntegerProperty visibleRowCountProperty() { - return visibleRowCount; - } - - /*************************************************************************** - * * - * Properties * - * * - **************************************************************************/ - - - private final EventHandlerManager eventHandlerManager = new EventHandlerManager(this); - - public final ObjectProperty<EventHandler<SuggestionEvent<T>>> onSuggestionProperty() { return onSuggestion; } - public final void setOnSuggestion(EventHandler<SuggestionEvent<T>> value) { onSuggestionProperty().set(value); } - public final EventHandler<SuggestionEvent<T>> getOnSuggestion() { return onSuggestionProperty().get(); } - private ObjectProperty<EventHandler<SuggestionEvent<T>>> onSuggestion = new ObjectPropertyBase<EventHandler<SuggestionEvent<T>>>() { - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Override protected void invalidated() { - eventHandlerManager.setEventHandler(SuggestionEvent.SUGGESTION, (EventHandler<SuggestionEvent>)(Object)get()); - } - - @Override - public Object getBean() { - return AutoCompletePopup.this; - } - - @Override - public String getName() { - return "onSuggestion"; //$NON-NLS-1$ - } - }; - - /**{@inheritDoc}*/ - @Override public EventDispatchChain buildEventDispatchChain(EventDispatchChain tail) { - return super.buildEventDispatchChain(tail).append(eventHandlerManager); - } - - - /*************************************************************************** - * * - * Stylesheet Handling * - * * - **************************************************************************/ - - public static final String DEFAULT_STYLE_CLASS = "auto-complete-popup"; //$NON-NLS-1$ - - @Override - protected Skin<?> createDefaultSkin() { - return new AutoCompletePopupSkin<>(this); - } - -} diff --git a/src/impl/org/controlsfx/skin/AutoCompletePopupSkin.java b/src/impl/org/controlsfx/skin/AutoCompletePopupSkin.java deleted file mode 100644 index 0edfac6..0000000 --- a/src/impl/org/controlsfx/skin/AutoCompletePopupSkin.java +++ /dev/null @@ -1,115 +0,0 @@ -/** - * Copyright (c) 2014, 2016 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.skin; - -import javafx.beans.binding.Bindings; -import javafx.event.Event; -import javafx.scene.Node; -import javafx.scene.control.ListView; -import javafx.scene.control.Skin; -import javafx.scene.control.cell.TextFieldListCell; -import javafx.scene.input.MouseButton; -import org.controlsfx.control.textfield.AutoCompletionBinding; - - -public class AutoCompletePopupSkin<T> implements Skin<AutoCompletePopup<T>> { - - private final AutoCompletePopup<T> control; - private final ListView<T> suggestionList; - final int LIST_CELL_HEIGHT = 24; - - public AutoCompletePopupSkin(AutoCompletePopup<T> control){ - this.control = control; - suggestionList = new ListView<>(control.getSuggestions()); - - suggestionList.getStyleClass().add(AutoCompletePopup.DEFAULT_STYLE_CLASS); - - suggestionList.getStylesheets().add(AutoCompletionBinding.class - .getResource("autocompletion.css").toExternalForm()); //$NON-NLS-1$ - /** - * Here we bind the prefHeightProperty to the minimum height between the - * max visible rows and the current items list. We also add an arbitrary - * 5 number because when we have only one item we have the vertical - * scrollBar showing for no reason. - */ - suggestionList.prefHeightProperty().bind( - Bindings.min(control.visibleRowCountProperty(), Bindings.size(suggestionList.getItems())) - .multiply(LIST_CELL_HEIGHT).add(18)); - suggestionList.setCellFactory(TextFieldListCell.forListView(control.getConverter())); - - //Allowing the user to control ListView width. - suggestionList.prefWidthProperty().bind(control.prefWidthProperty()); - suggestionList.maxWidthProperty().bind(control.maxWidthProperty()); - suggestionList.minWidthProperty().bind(control.minWidthProperty()); - registerEventListener(); - } - - private void registerEventListener(){ - suggestionList.setOnMouseClicked(me -> { - if (me.getButton() == MouseButton.PRIMARY){ - onSuggestionChoosen(suggestionList.getSelectionModel().getSelectedItem()); - } - }); - - - suggestionList.setOnKeyPressed(ke -> { - switch (ke.getCode()) { - case ENTER: - onSuggestionChoosen(suggestionList.getSelectionModel().getSelectedItem()); - break; - case ESCAPE: - if (control.isHideOnEscape()) { - control.hide(); - } - break; - default: - break; - } - }); - } - - private void onSuggestionChoosen(T suggestion){ - if(suggestion != null) { - Event.fireEvent(control, new AutoCompletePopup.SuggestionEvent<>(suggestion)); - } - } - - - @Override - public Node getNode() { - return suggestionList; - } - - @Override - public AutoCompletePopup<T> getSkinnable() { - return control; - } - - @Override - public void dispose() { - } -} diff --git a/src/impl/org/controlsfx/skin/BreadCrumbBarSkin.java b/src/impl/org/controlsfx/skin/BreadCrumbBarSkin.java deleted file mode 100644 index 1bd8f98..0000000 --- a/src/impl/org/controlsfx/skin/BreadCrumbBarSkin.java +++ /dev/null @@ -1,381 +0,0 @@ -/** - * Copyright (c) 2014, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.skin; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.value.ChangeListener; -import javafx.event.Event; -import javafx.event.EventHandler; -import javafx.scene.Node; -import javafx.scene.control.Button; -import javafx.scene.control.TreeItem; -import javafx.scene.control.TreeItem.TreeModificationEvent; -import javafx.scene.paint.Color; -import javafx.scene.shape.ArcTo; -import javafx.scene.shape.ClosePath; -import javafx.scene.shape.HLineTo; -import javafx.scene.shape.LineTo; -import javafx.scene.shape.MoveTo; -import javafx.scene.shape.Path; -import javafx.util.Callback; - -import org.controlsfx.control.BreadCrumbBar; -import org.controlsfx.control.BreadCrumbBar.BreadCrumbActionEvent; - -import com.sun.javafx.scene.control.behavior.BehaviorBase; -import com.sun.javafx.scene.control.behavior.KeyBinding; -import com.sun.javafx.scene.control.skin.BehaviorSkinBase; -import com.sun.javafx.scene.traversal.Algorithm; -import com.sun.javafx.scene.traversal.Direction; -import com.sun.javafx.scene.traversal.ParentTraversalEngine; -import com.sun.javafx.scene.traversal.TraversalContext; - -/** - * Basic Skin implementation for the {@link BreadCrumbBar} - * - * @param <T> - */ -public class BreadCrumbBarSkin<T> extends BehaviorSkinBase<BreadCrumbBar<T>, BehaviorBase<BreadCrumbBar<T>>> { - - private static final String STYLE_CLASS_FIRST = "first"; //$NON-NLS-1$ - - public BreadCrumbBarSkin(final BreadCrumbBar<T> control) { - super(control, new BehaviorBase<>(control, Collections.<KeyBinding> emptyList())); - control.selectedCrumbProperty().addListener(selectedPathChangeListener); - updateSelectedPath(getSkinnable().selectedCrumbProperty().get(), null); - fixFocusTraversal(); - } - - // https://bitbucket.org/controlsfx/controlsfx/issue/453/breadcrumbbar-keyboard-focus-traversal-is - // ContainerTabOrder will fail with LEFT/RIGHT navigation, since the buttons in bread crumb overlap - private void fixFocusTraversal() { - - ParentTraversalEngine engine = new ParentTraversalEngine(getSkinnable(), new Algorithm() { - - @Override - public Node select(Node owner, Direction dir, TraversalContext context) { - Node node = null; - int idx = getChildren().indexOf(owner); - switch(dir) { - case NEXT: - case NEXT_IN_LINE: - case RIGHT: - if (idx < getChildren().size() - 1) { - node = getChildren().get(idx+1); - } - break; - case PREVIOUS: - case LEFT: - if (idx > 0) { - node = getChildren().get(idx-1); - } - break; - } - return node; - } - - @Override - public Node selectFirst(TraversalContext context) { - Node first = null; - if (!getChildren().isEmpty()) { - first = getChildren().get(0); - } - return first; - } - - @Override - public Node selectLast(TraversalContext context) { - Node last = null; - if (!getChildren().isEmpty()) { - last = getChildren().get(getChildren().size()-1); - } - return last; - } - }); - engine.setOverriddenFocusTraversability(false); - getSkinnable().setImpl_traversalEngine(engine); - - } - - private final ChangeListener<TreeItem<T>> selectedPathChangeListener = - (obs, oldItem, newItem) -> updateSelectedPath(newItem, oldItem); - - private void updateSelectedPath(TreeItem<T> newTarget, TreeItem<T> oldTarget) { - if(oldTarget != null){ - // remove old listener - oldTarget.removeEventHandler( - TreeItem.childrenModificationEvent(), treeChildrenModifiedHandler); - } - if(newTarget != null){ - // add new listener - newTarget.addEventHandler(TreeItem.childrenModificationEvent(), treeChildrenModifiedHandler); - } - updateBreadCrumbs(); - } - - - private final EventHandler<TreeModificationEvent<Object>> treeChildrenModifiedHandler = - args -> updateBreadCrumbs(); - - - private void updateBreadCrumbs() { - final BreadCrumbBar<T> buttonBar = getSkinnable(); - final TreeItem<T> pathTarget = buttonBar.getSelectedCrumb(); - final Callback<TreeItem<T>, Button> factory = buttonBar.getCrumbFactory(); - - getChildren().clear(); - - if(pathTarget != null){ - List<TreeItem<T>> crumbs = constructFlatPath(pathTarget); - - for (int i=0; i < crumbs.size(); i++) { - Button crumb = createCrumb(factory, crumbs.get(i)); - crumb.setMnemonicParsing(false); - if (i == 0) { - if (! crumb.getStyleClass().contains(STYLE_CLASS_FIRST)) { - crumb.getStyleClass().add(STYLE_CLASS_FIRST); - } - } else { - crumb.getStyleClass().remove(STYLE_CLASS_FIRST); - } - - getChildren().add(crumb); - } - } - } - - @Override protected void layoutChildren(double x, double y, double w, double h) { - for (int i = 0; i < getChildren().size(); i++) { - Node n = getChildren().get(i); - - double nw = snapSize(n.prefWidth(h)); - double nh = snapSize(n.prefHeight(-1)); - - if (i > 0) { - // We have to position the bread crumbs slightly overlapping - double ins = n instanceof BreadCrumbButton ? ((BreadCrumbButton)n).getArrowWidth() : 0; - x = snapPosition(x - ins); - } - - n.resize(nw, nh); - n.relocate(x, y); - x += nw; - } - } - - /** - * Construct a flat list for the crumbs - * @param bottomMost The crumb node at the end of the path - * @return - */ - private List<TreeItem<T>> constructFlatPath(TreeItem<T> bottomMost){ - List<TreeItem<T>> path = new ArrayList<>(); - - TreeItem<T> current = bottomMost; - do { - path.add(current); - current = current.getParent(); - } while (current != null); - - Collections.reverse(path); - return path; - } - - private Button createCrumb( - final Callback<TreeItem<T>, Button> factory, - final TreeItem<T> selectedCrumb) { - - Button crumb = factory.call(selectedCrumb); - - crumb.getStyleClass().add("crumb"); //$NON-NLS-1$ - - // We want all buttons to have the same height - // so we bind their preferred height to the enclosing container -// crumb.prefHeightProperty().bind(getSkinnable().heightProperty()); - - // listen to the action event of each bread crumb - crumb.setOnAction(ae -> onBreadCrumbAction(selectedCrumb)); - - return crumb; - } - - /** - * Occurs when a bread crumb gets the action event - * - * @param crumbModel The crumb which received the action event - */ - protected void onBreadCrumbAction(final TreeItem<T> crumbModel){ - final BreadCrumbBar<T> breadCrumbBar = getSkinnable(); - - // fire the composite event in the breadCrumbBar - Event.fireEvent(breadCrumbBar, new BreadCrumbActionEvent<>(crumbModel)); - - // navigate to the clicked crumb - if(breadCrumbBar.isAutoNavigationEnabled()){ - breadCrumbBar.setSelectedCrumb(crumbModel); - } - } - - - - - /** - * Represents a BreadCrumb Button - * - * <pre> - * ---------- - * \ \ - * / / - * ---------- - * </pre> - * - * - */ - public static class BreadCrumbButton extends Button { - - private final ObjectProperty<Boolean> first = new SimpleObjectProperty<>(this, "first"); //$NON-NLS-1$ - - private final double arrowWidth = 5; - private final double arrowHeight = 20; - - /** - * Create a BreadCrumbButton - * - * @param text Buttons text - */ - public BreadCrumbButton(String text){ - this(text, null); - } - - /** - * Create a BreadCrumbButton - * @param text Buttons text - * @param gfx Gfx of the Button - */ - public BreadCrumbButton(String text, Node gfx){ - super(text, gfx); - first.set(false); - - getStyleClass().addListener(new InvalidationListener() { - @Override public void invalidated(Observable arg0) { - updateShape(); - } - }); - - updateShape(); - } - - private void updateShape(){ - this.setShape(createButtonShape()); - } - - - /** - * Gets the crumb arrow with - * @return - */ - public double getArrowWidth(){ - return arrowWidth; - } - - /** - * Create an arrow path - * - * Based upon Uwe / Andy Till code snippet found here: - * @see http://ustesis.wordpress.com/2013/11/04/implementing-breadcrumbs-in-javafx/ - * @return - */ - private Path createButtonShape(){ - // build the following shape (or home without left arrow) - - // -------- - // \ \ - // / / - // -------- - Path path = new Path(); - - // begin in the upper left corner - MoveTo e1 = new MoveTo(0, 0); - path.getElements().add(e1); - - // draw a horizontal line that defines the width of the shape - HLineTo e2 = new HLineTo(); - // bind the width of the shape to the width of the button - e2.xProperty().bind(this.widthProperty().subtract(arrowWidth)); - path.getElements().add(e2); - - // draw upper part of right arrow - LineTo e3 = new LineTo(); - // the x endpoint of this line depends on the x property of line e2 - e3.xProperty().bind(e2.xProperty().add(arrowWidth)); - e3.setY(arrowHeight / 2.0); - path.getElements().add(e3); - - // draw lower part of right arrow - LineTo e4 = new LineTo(); - // the x endpoint of this line depends on the x property of line e2 - e4.xProperty().bind(e2.xProperty()); - e4.setY(arrowHeight); - path.getElements().add(e4); - - // draw lower horizontal line - HLineTo e5 = new HLineTo(0); - path.getElements().add(e5); - - if(! getStyleClass().contains(STYLE_CLASS_FIRST)){ - // draw lower part of left arrow - // we simply can omit it for the first Button - LineTo e6 = new LineTo(arrowWidth, arrowHeight / 2.0); - path.getElements().add(e6); - }else{ - // draw an arc for the first bread crumb - ArcTo arcTo = new ArcTo(); - arcTo.setSweepFlag(true); - arcTo.setX(0); - arcTo.setY(0); - arcTo.setRadiusX(15.0f); - arcTo.setRadiusY(15.0f); - path.getElements().add(arcTo); - } - - // close path - ClosePath e7 = new ClosePath(); - path.getElements().add(e7); - // this is a dummy color to fill the shape, it won't be visible - path.setFill(Color.BLACK); - - return path; - } - } -} diff --git a/src/impl/org/controlsfx/skin/CheckComboBoxSkin.java b/src/impl/org/controlsfx/skin/CheckComboBoxSkin.java deleted file mode 100644 index 1e7d1f7..0000000 --- a/src/impl/org/controlsfx/skin/CheckComboBoxSkin.java +++ /dev/null @@ -1,193 +0,0 @@ -/** - * Copyright (c) 2013, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.skin; - -import java.util.Collections; - -import javafx.collections.ListChangeListener; -import javafx.collections.ObservableList; -import javafx.scene.control.ComboBox; -import javafx.scene.control.ListCell; -import javafx.scene.control.ListView; -import javafx.scene.control.cell.CheckBoxListCell; -import javafx.util.Callback; - -import org.controlsfx.control.CheckComboBox; - -import com.sun.javafx.scene.control.ReadOnlyUnbackedObservableList; -import com.sun.javafx.scene.control.behavior.BehaviorBase; -import com.sun.javafx.scene.control.behavior.KeyBinding; -import com.sun.javafx.scene.control.skin.BehaviorSkinBase; -import com.sun.javafx.scene.control.skin.ComboBoxListViewSkin; - -public class CheckComboBoxSkin<T> extends BehaviorSkinBase<CheckComboBox<T>, BehaviorBase<CheckComboBox<T>>> { - - /************************************************************************** - * - * Static fields - * - **************************************************************************/ - - - - /************************************************************************** - * - * fields - * - **************************************************************************/ - - // visuals - private final ComboBox<T> comboBox; - private final ListCell<T> buttonCell; - - // data - private final CheckComboBox<T> control; - private final ObservableList<T> items; - private final ReadOnlyUnbackedObservableList<Integer> selectedIndices; - private final ReadOnlyUnbackedObservableList<T> selectedItems; - - - /************************************************************************** - * - * Constructors - * - **************************************************************************/ - - @SuppressWarnings("unchecked") - public CheckComboBoxSkin(final CheckComboBox<T> control) { - super(control, new BehaviorBase<>(control, Collections.<KeyBinding> emptyList())); - - this.control = control; - this.items = control.getItems(); - - selectedIndices = (ReadOnlyUnbackedObservableList<Integer>) control.getCheckModel().getCheckedIndices(); - selectedItems = (ReadOnlyUnbackedObservableList<T>) control.getCheckModel().getCheckedItems(); - - comboBox = new ComboBox<T>(items) { - @Override protected javafx.scene.control.Skin<?> createDefaultSkin() { - return new ComboBoxListViewSkin<T>(this) { - // overridden to prevent the popup from disappearing - @Override protected boolean isHideOnClickEnabled() { - return false; - } - }; - } - }; - comboBox.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); - - // installs a custom CheckBoxListCell cell factory - comboBox.setCellFactory(new Callback<ListView<T>, ListCell<T>>() { - @Override public ListCell<T> call(ListView<T> listView) { - CheckBoxListCell<T> result = new CheckBoxListCell<>(item -> control.getItemBooleanProperty(item)); - result.converterProperty().bind(control.converterProperty()); - return result; - }; - }); - - // we render the selection into a custom button cell, so that it can - // be pretty printed (e.g. 'Item 1, Item 2, Item 10'). - buttonCell = new ListCell<T>() { - @Override protected void updateItem(T item, boolean empty) { - // we ignore whatever item is selected, instead choosing - // to display the selected item text using commas to separate - // each item - setText(buildString()); - } - }; - comboBox.setButtonCell(buttonCell); - comboBox.setValue((T)buildString()); - - // The zero is a dummy value - it just has to be legally within the bounds of the - // item count for the CheckComboBox items list. - selectedIndices.addListener((ListChangeListener<Integer>) c -> buttonCell.updateIndex(0)); - - getChildren().add(comboBox); - } - - - /************************************************************************** - * - * Overriding public API - * - **************************************************************************/ - - @Override protected double computeMinWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) { - return comboBox.minWidth(height); - } - - @Override protected double computeMinHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { - return comboBox.minHeight(width); - } - - @Override protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) { - return comboBox.prefWidth(height); - } - - @Override protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { - return comboBox.prefHeight(width); - } - - @Override protected double computeMaxWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) { - return getSkinnable().prefWidth(height); - } - - @Override protected double computeMaxHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { - return getSkinnable().prefHeight(width); - } - - - - /************************************************************************** - * - * Implementation - * - **************************************************************************/ - - private String buildString() { - final StringBuilder sb = new StringBuilder(); - for (int i = 0, max = selectedItems.size(); i < max; i++) { - T item = selectedItems.get(i); - if (control.getConverter() == null) { - sb.append(item); - } else { - sb.append(control.getConverter().toString(item)); - } - if (i < max - 1) { - sb.append(", "); //$NON-NLS-1$ - } - } - return sb.toString(); - } - - - /************************************************************************** - * - * Support classes / enums - * - **************************************************************************/ - -} diff --git a/src/impl/org/controlsfx/skin/CustomTextFieldSkin.java b/src/impl/org/controlsfx/skin/CustomTextFieldSkin.java deleted file mode 100644 index 00aa8f6..0000000 --- a/src/impl/org/controlsfx/skin/CustomTextFieldSkin.java +++ /dev/null @@ -1,156 +0,0 @@ -/** - * Copyright (c) 2013, 2016 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.skin; - -import javafx.beans.property.ObjectProperty; -import javafx.css.PseudoClass; -import javafx.geometry.Pos; -import javafx.scene.Node; -import javafx.scene.control.TextField; -import javafx.scene.layout.StackPane; - -import com.sun.javafx.scene.control.behavior.TextFieldBehavior; -import com.sun.javafx.scene.control.skin.TextFieldSkin; -import com.sun.javafx.scene.text.HitInfo; - -public abstract class CustomTextFieldSkin extends TextFieldSkin { - - private static final PseudoClass HAS_NO_SIDE_NODE = PseudoClass.getPseudoClass("no-side-nodes"); //$NON-NLS-1$ - private static final PseudoClass HAS_LEFT_NODE = PseudoClass.getPseudoClass("left-node-visible"); //$NON-NLS-1$ - private static final PseudoClass HAS_RIGHT_NODE = PseudoClass.getPseudoClass("right-node-visible"); //$NON-NLS-1$ - - private Node left; - private StackPane leftPane; - private Node right; - private StackPane rightPane; - - private final TextField control; - - public CustomTextFieldSkin(final TextField control) { - super(control, new TextFieldBehavior(control)); - - this.control = control; - updateChildren(); - - registerChangeListener(leftProperty(), "LEFT_NODE"); //$NON-NLS-1$ - registerChangeListener(rightProperty(), "RIGHT_NODE"); //$NON-NLS-1$ - registerChangeListener(control.focusedProperty(), "FOCUSED"); //$NON-NLS-1$ - } - - public abstract ObjectProperty<Node> leftProperty(); - public abstract ObjectProperty<Node> rightProperty(); - - @Override protected void handleControlPropertyChanged(String p) { - super.handleControlPropertyChanged(p); - - if (p == "LEFT_NODE" || p == "RIGHT_NODE") { //$NON-NLS-1$ //$NON-NLS-2$ - updateChildren(); - } - } - - private void updateChildren() { - Node newLeft = leftProperty().get(); - if (newLeft != null) { - getChildren().remove(leftPane); - leftPane = new StackPane(newLeft); - leftPane.setAlignment(Pos.CENTER_LEFT); - leftPane.getStyleClass().add("left-pane"); //$NON-NLS-1$ - getChildren().add(leftPane); - left = newLeft; - } - - Node newRight = rightProperty().get(); - if (newRight != null) { - getChildren().remove(rightPane); - rightPane = new StackPane(newRight); - rightPane.setAlignment(Pos.CENTER_RIGHT); - rightPane.getStyleClass().add("right-pane"); //$NON-NLS-1$ - getChildren().add(rightPane); - right = newRight; - } - - control.pseudoClassStateChanged(HAS_LEFT_NODE, left != null); - control.pseudoClassStateChanged(HAS_RIGHT_NODE, right != null); - control.pseudoClassStateChanged(HAS_NO_SIDE_NODE, left == null && right == null); - } - - @Override protected void layoutChildren(double x, double y, double w, double h) { - final double fullHeight = h + snappedTopInset() + snappedBottomInset(); - - final double leftWidth = leftPane == null ? 0.0 : snapSize(leftPane.prefWidth(fullHeight)); - final double rightWidth = rightPane == null ? 0.0 : snapSize(rightPane.prefWidth(fullHeight)); - - final double textFieldStartX = snapPosition(x) + snapSize(leftWidth); - final double textFieldWidth = w - snapSize(leftWidth) - snapSize(rightWidth); - - super.layoutChildren(textFieldStartX, 0, textFieldWidth, fullHeight); - - if (leftPane != null) { - final double leftStartX = 0; - leftPane.resizeRelocate(leftStartX, 0, leftWidth, fullHeight); - } - - if (rightPane != null) { - final double rightStartX = rightPane == null ? 0.0 : w - rightWidth + snappedLeftInset(); - rightPane.resizeRelocate(rightStartX, 0, rightWidth, fullHeight); - } - } - - @Override - public HitInfo getIndex(double x, double y) { - /** - * This resolves https://bitbucket.org/controlsfx/controlsfx/issue/476 - * when we have a left Node and the click point is badly returned - * because we weren't considering the shift induced by the leftPane. - */ - final double leftWidth = leftPane == null ? 0.0 : snapSize(leftPane.prefWidth(getSkinnable().getHeight())); - return super.getIndex(x - leftWidth, y); - } - - @Override - protected double computePrefWidth(double h, double topInset, double rightInset, double bottomInset, double leftInset) { - final double pw = super.computePrefWidth(h, topInset, rightInset, bottomInset, leftInset); - final double leftWidth = leftPane == null ? 0.0 : snapSize(leftPane.prefWidth(h)); - final double rightWidth = rightPane == null ? 0.0 : snapSize(rightPane.prefWidth(h)); - - return pw + leftWidth + rightWidth; - } - - @Override - protected double computePrefHeight(double w, double topInset, double rightInset, double bottomInset, double leftInset) { - final double ph = super.computePrefHeight(w, topInset, rightInset, bottomInset, leftInset); - final double leftHeight = leftPane == null ? 0.0 : snapSize(leftPane.prefHeight(-1)); - final double rightHeight = rightPane == null ? 0.0 : snapSize(rightPane.prefHeight(-1)); - - return Math.max(ph, Math.max(leftHeight, rightHeight)); - } -// -// @Override -// protected double computeMinWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) { -// return computePrefWidth(height, topInset, rightInset, bottomInset, leftInset); -//} -} diff --git a/src/impl/org/controlsfx/skin/DecorationPane.java b/src/impl/org/controlsfx/skin/DecorationPane.java deleted file mode 100644 index eb8cf87..0000000 --- a/src/impl/org/controlsfx/skin/DecorationPane.java +++ /dev/null @@ -1,122 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.skin; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.WeakHashMap; - -import javafx.beans.property.BooleanProperty; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.geometry.Pos; -import javafx.scene.Node; -import javafx.scene.layout.StackPane; - -import org.controlsfx.control.decoration.Decoration; -import org.controlsfx.control.decoration.Decorator; - -public class DecorationPane extends StackPane { - - // maps from a node to a list of its decoration nodes - private final Map<Node, List<Node>> nodeDecorationMap = new WeakHashMap<>(); - - ChangeListener<Boolean> visibilityListener = new ChangeListener<Boolean>() { - @Override public void changed(ObservableValue<? extends Boolean> o, Boolean wasVisible, Boolean isVisible) { - BooleanProperty p = (BooleanProperty)o; - Node n = (Node) p.getBean(); - - removeAllDecorationsOnNode(n, Decorator.getDecorations(n)); - Decorator.removeAllDecorations(n); - } - }; - - public DecorationPane() { - // Make DecorationPane transparent - setBackground(null); - } - - public void setRoot(Node root) { - getChildren().setAll(root); - } - - public void updateDecorationsOnNode(Node targetNode, List<Decoration> added, List<Decoration> removed) { - removeAllDecorationsOnNode(targetNode, removed); - addAllDecorationsOnNode(targetNode, added); - } - - private void showDecoration(Node targetNode, Decoration decoration) { - Node decorationNode = decoration.applyDecoration(targetNode); - if (decorationNode != null) { - List<Node> decorationNodes = nodeDecorationMap.get(targetNode); - if (decorationNodes == null) { - decorationNodes = new ArrayList<>(); - nodeDecorationMap.put(targetNode, decorationNodes); - } - decorationNodes.add(decorationNode); - - if (!getChildren().contains(decorationNode)) { - getChildren().add(decorationNode); - StackPane.setAlignment(decorationNode, Pos.TOP_LEFT); // TODO support for all positions. - } - } - - targetNode.visibleProperty().addListener(visibilityListener); - } - - private void removeAllDecorationsOnNode(Node targetNode, List<Decoration> decorations) { - if (decorations == null || targetNode == null) return; - - // We need to do two things: - // 1) Remove the decoration node (if it exists) from the nodeDecorationMap - // for the targetNode, if it exists. - List<Node> decorationNodes = nodeDecorationMap.remove(targetNode); - if (decorationNodes != null) { - for (Node decorationNode : decorationNodes) { - boolean success = getChildren().remove(decorationNode); - if (! success) { - throw new IllegalStateException("Could not remove decoration " + //$NON-NLS-1$ - decorationNode + " from decoration pane children list: " + //$NON-NLS-1$ - getChildren()); - } - } - } - - // 2) Tell the decoration to remove itself from the target node (if necessary) - for (Decoration decoration : decorations) { - decoration.removeDecoration(targetNode); - } - } - - private void addAllDecorationsOnNode(Node targetNode, List<Decoration> decorations) { - if (decorations == null) return; - for (Decoration decoration : decorations) { - showDecoration(targetNode, decoration); - } - } -} diff --git a/src/impl/org/controlsfx/skin/ExpandableTableRowSkin.java b/src/impl/org/controlsfx/skin/ExpandableTableRowSkin.java deleted file mode 100644 index a8b5f83..0000000 --- a/src/impl/org/controlsfx/skin/ExpandableTableRowSkin.java +++ /dev/null @@ -1,109 +0,0 @@ -/** - * Copyright (c) 2016 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.skin; - -import com.sun.javafx.scene.control.skin.TableRowSkin; -import javafx.scene.Node; -import javafx.scene.control.TableRow; -import org.controlsfx.control.table.TableRowExpanderColumn; - -/** - * This skin is installed when you assign a {@link org.controlsfx.control.table.TableRowExpanderColumn} to a TableView. - * The skin will render the expanded node produced by the - * {@link org.controlsfx.control.table.TableRowExpanderColumn#expandedNodeCallback} whenever the expanded state is - * changed to true for a certain row. - * - * @param <S> The type of items in the TableRow - */ -public class ExpandableTableRowSkin<S> extends TableRowSkin<S> { - private final TableRow<S> tableRow; - private TableRowExpanderColumn<S> expander; - private Double tableRowPrefHeight = -1D; - - /** - * Create the ExpandableTableRowSkin and listen to changes for the item this table row represents. When the - * item is changed, the old expanded node, if any, is removed from the children list of the TableRow. - * - * @param tableRow The table row to apply this skin for - * @param expander The expander column, used to retrieve the expanded node when this row is expanded - */ - public ExpandableTableRowSkin(TableRow<S> tableRow, TableRowExpanderColumn<S> expander) { - super(tableRow); - this.tableRow = tableRow; - this.expander = expander; - tableRow.itemProperty().addListener((observable, oldValue, newValue) -> { - if (oldValue != null) { - Node expandedNode = this.expander.getExpandedNode(oldValue); - if (expandedNode != null) getChildren().remove(expandedNode); - } - }); - } - - /** - * Create the expanded content node that should represent the current table row. - * - * If the expanded content node is not currently in the children list of the TableRow it is automatically added. - * - * @return The expanded content Node - */ - private Node getContent() { - Node node = expander.getOrCreateExpandedNode(tableRow); - if (!getChildren().contains(node)) getChildren().add(node); - return node; - } - - /** - * Check if the current node is expanded. This is done by checking that there is an item for the current row, - * and that the expanded property for the row is true. - * - * @return A boolean indicating the expanded state of this row - */ - private Boolean isExpanded() { - return getSkinnable().getItem() != null && expander.getCellData(getSkinnable().getIndex()); - } - - /** - * Add the preferred height of the expanded Node whenever the expanded flag is true. - * - * @return The preferred height of the TableRow, appended with the preferred height of the expanded node - * if this row is currently expanded. - */ - @Override - protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { - tableRowPrefHeight = super.computePrefHeight(width, topInset, rightInset, bottomInset, leftInset); - return isExpanded() ? tableRowPrefHeight + getContent().prefHeight(width) : tableRowPrefHeight; - } - - /** - * Lay out the columns of the TableRow, then add the expanded content node below if this row is currently expanded. - */ - @Override - protected void layoutChildren(double x, double y, double w, double h) { - super.layoutChildren(x, y, w, h); - if (isExpanded()) getContent().resizeRelocate(0.0, tableRowPrefHeight, w, h - tableRowPrefHeight); - } -} diff --git a/src/impl/org/controlsfx/skin/GridCellSkin.java b/src/impl/org/controlsfx/skin/GridCellSkin.java deleted file mode 100644 index db10ea7..0000000 --- a/src/impl/org/controlsfx/skin/GridCellSkin.java +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (c) 2013, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.skin; - -import java.util.Collections; - -import org.controlsfx.control.GridCell; - -import com.sun.javafx.scene.control.behavior.BehaviorBase; -import com.sun.javafx.scene.control.behavior.KeyBinding; -import com.sun.javafx.scene.control.skin.CellSkinBase; - -public class GridCellSkin<T> extends CellSkinBase<GridCell<T>, BehaviorBase<GridCell<T>>> { - - public GridCellSkin(GridCell<T> control) { - super(control, new BehaviorBase<>(control, Collections.<KeyBinding> emptyList())); - } - -} diff --git a/src/impl/org/controlsfx/skin/GridRow.java b/src/impl/org/controlsfx/skin/GridRow.java deleted file mode 100644 index 548ee8e..0000000 --- a/src/impl/org/controlsfx/skin/GridRow.java +++ /dev/null @@ -1,104 +0,0 @@ -/** - * Copyright (c) 2013, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.skin; - -import org.controlsfx.control.GridView; - -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; -import javafx.beans.property.SimpleObjectProperty; -import javafx.scene.control.IndexedCell; -import javafx.scene.control.Skin; - -/** - * A GridRow is a container for {@link GridCell}, and represents a single - * row inside a {@link GridView}. - */ -class GridRow<T> extends IndexedCell<T>{ - - - /************************************************************************** - * - * Constructors - * - **************************************************************************/ - - /** - * - */ - public GridRow() { - super(); - getStyleClass().add("grid-row"); //$NON-NLS-1$ - - // we need to do this (or something similar) to allow for mouse wheel - // scrolling, as the GridRow has to report that it is non-empty (which - // is the second argument going into updateItem). - indexProperty().addListener(new InvalidationListener() { - @Override public void invalidated(Observable observable) { - updateItem(null, getIndex() == -1); - } - }); - } - - /** - * {@inheritDoc} - */ - @Override protected Skin<?> createDefaultSkin() { - return new GridRowSkin<>(this); - } - - - - /************************************************************************** - * - * Properties - * - **************************************************************************/ - - /** - * The {@link GridView} that this GridRow exists within. - */ - public SimpleObjectProperty<GridView<T>> gridViewProperty() { - return gridView; - } - private final SimpleObjectProperty<GridView<T>> gridView = - new SimpleObjectProperty<>(this, "gridView"); //$NON-NLS-1$ - - /** - * Sets the {@link GridView} that this GridRow exists within. - */ - public final void updateGridView(GridView<T> gridView) { - this.gridView.set(gridView); - } - - /** - * Returns the {@link GridView} that this GridRow exists within. - */ - public GridView<T> getGridView() { - return gridView.get(); - } -} diff --git a/src/impl/org/controlsfx/skin/GridRowSkin.java b/src/impl/org/controlsfx/skin/GridRowSkin.java deleted file mode 100644 index 2b03097..0000000 --- a/src/impl/org/controlsfx/skin/GridRowSkin.java +++ /dev/null @@ -1,179 +0,0 @@ -/** - * Copyright (c) 2013, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.skin; - -import java.util.Collections; - -import javafx.scene.Node; - -import org.controlsfx.control.GridCell; -import org.controlsfx.control.GridView; - -import com.sun.javafx.scene.control.behavior.BehaviorBase; -import com.sun.javafx.scene.control.behavior.KeyBinding; -import com.sun.javafx.scene.control.skin.CellSkinBase; - -public class GridRowSkin<T> extends CellSkinBase<GridRow<T>, BehaviorBase<GridRow<T>>> { - - public GridRowSkin(GridRow<T> control) { - super(control, new BehaviorBase<>(control, Collections.<KeyBinding> emptyList())); - - // Remove any children before creating cells (by default a LabeledText exist and we don't need it) - getChildren().clear(); - updateCells(); - - registerChangeListener(getSkinnable().indexProperty(), "INDEX"); //$NON-NLS-1$ - registerChangeListener(getSkinnable().widthProperty(), "WIDTH"); //$NON-NLS-1$ - registerChangeListener(getSkinnable().heightProperty(), "HEIGHT"); //$NON-NLS-1$ - } - - @Override protected void handleControlPropertyChanged(String p) { - super.handleControlPropertyChanged(p); - - if ("INDEX".equals(p)) { //$NON-NLS-1$ - updateCells(); - } else if ("WIDTH".equals(p)) { //$NON-NLS-1$ - updateCells(); - } else if ("HEIGHT".equals(p)) { //$NON-NLS-1$ - updateCells(); - } - } - - /** - * Returns a cell element at a desired index - * @param index The index of the wanted cell element - * @return Cell element if exist else null - */ - @SuppressWarnings("unchecked") - public GridCell<T> getCellAtIndex(int index) { - if( index < getChildren().size() ) { - return (GridCell<T>)getChildren().get(index); - } - return null; - } - - /** - * Update all cells - * <p>Cells are only created when needed and re-used when possible.</p> - */ - public void updateCells() { - int rowIndex = getSkinnable().getIndex(); - if (rowIndex >= 0) { - GridView<T> gridView = getSkinnable().getGridView(); - int maxCellsInRow = ((GridViewSkin<?>)gridView.getSkin()).computeMaxCellsInRow(); - int totalCellsInGrid = gridView.getItems().size(); - int startCellIndex = rowIndex * maxCellsInRow; - int endCellIndex = startCellIndex + maxCellsInRow - 1; - int cacheIndex = 0; - - for (int cellIndex = startCellIndex; cellIndex <= endCellIndex; cellIndex++, cacheIndex++) { - if (cellIndex < totalCellsInGrid) { - // Check if we can re-use a cell at this index or create a new one - GridCell<T> cell = getCellAtIndex(cacheIndex); - if( cell == null ) { - cell = createCell(); - getChildren().add(cell); - } - cell.updateIndex(-1); - cell.updateIndex(cellIndex); - } - // we are going out of bounds -> exist the loop - else { break; } - } - - // In case we are re-using a row that previously had more cells than - // this one, we need to remove the extra cells that remain - getChildren().remove(cacheIndex, getChildren().size()); - } - } - - private GridCell<T> createCell() { - GridView<T> gridView = getSkinnable().gridViewProperty().get(); - GridCell<T> cell; - if (gridView.getCellFactory() != null) { - cell = gridView.getCellFactory().call(gridView); - } else { - cell = createDefaultCellImpl(); - } - cell.updateGridView(gridView); - return cell; - } - - private GridCell<T> createDefaultCellImpl() { - return new GridCell<T>() { - @Override protected void updateItem(T item, boolean empty) { - super.updateItem(item, empty); - if(empty) { - setText(""); //$NON-NLS-1$ - } else { - setText(item.toString()); - } - } - }; - } - - @Override protected double computeMinHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { - return super.computePrefHeight(width, topInset, rightInset, bottomInset, leftInset); - } - - @Override protected double computeMaxHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { - return Double.MAX_VALUE; - } - - @Override protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { - GridView<T> gv = getSkinnable().gridViewProperty().get(); - return gv.getCellHeight() + gv.getVerticalCellSpacing() * 2; - } - - @Override protected void layoutChildren(double x, double y, double w, double h) { -// double currentWidth = getSkinnable().getWidth(); - double cellWidth = getSkinnable().gridViewProperty().get().getCellWidth(); - double cellHeight = getSkinnable().gridViewProperty().get().getCellHeight(); - double horizontalCellSpacing = getSkinnable().gridViewProperty().get().getHorizontalCellSpacing(); - double verticalCellSpacing = getSkinnable().gridViewProperty().get().getVerticalCellSpacing(); - - double xPos = 0; - double yPos = 0; - - // This has been commented out as I removed the API from GridView until - // a use case was created. -// HPos currentHorizontalAlignment = getSkinnable().gridViewProperty().get().getHorizontalAlignment(); -// if (currentHorizontalAlignment != null) { -// if (currentHorizontalAlignment.equals(HPos.CENTER)) { -// xPos = (currentWidth % computeCellWidth()) / 2; -// } else if (currentHorizontalAlignment.equals(HPos.RIGHT)) { -// xPos = currentWidth % computeCellWidth(); -// } -// } - - for (Node child : getChildren()) { - child.relocate(xPos + horizontalCellSpacing, yPos + verticalCellSpacing); - child.resize(cellWidth, cellHeight); - xPos = xPos + horizontalCellSpacing + cellWidth + horizontalCellSpacing; - } - } -} diff --git a/src/impl/org/controlsfx/skin/GridViewSkin.java b/src/impl/org/controlsfx/skin/GridViewSkin.java deleted file mode 100644 index 8eea039..0000000 --- a/src/impl/org/controlsfx/skin/GridViewSkin.java +++ /dev/null @@ -1,230 +0,0 @@ -/** - * Copyright (c) 2013, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.skin; - -import java.util.Collections; - -import javafx.collections.ListChangeListener; -import javafx.collections.ObservableList; -import javafx.collections.WeakListChangeListener; -import javafx.util.Callback; - -import org.controlsfx.control.GridView; - -import com.sun.javafx.scene.control.behavior.BehaviorBase; -import com.sun.javafx.scene.control.behavior.KeyBinding; -import com.sun.javafx.scene.control.skin.VirtualContainerBase; -import com.sun.javafx.scene.control.skin.VirtualFlow; - -public class GridViewSkin<T> extends VirtualContainerBase<GridView<T>, BehaviorBase<GridView<T>>, GridRow<T>> { - - private final ListChangeListener<T> gridViewItemsListener = new ListChangeListener<T>() { - @Override public void onChanged(ListChangeListener.Change<? extends T> change) { - updateRowCount(); - getSkinnable().requestLayout(); - } - }; - - private final WeakListChangeListener<T> weakGridViewItemsListener = new WeakListChangeListener<>(gridViewItemsListener); - - @SuppressWarnings("rawtypes") - public GridViewSkin(GridView<T> control) { - super(control, new BehaviorBase<>(control, Collections.<KeyBinding>emptyList())); - - updateGridViewItems(); - - flow.setId("virtual-flow"); //$NON-NLS-1$ - flow.setPannable(false); - flow.setVertical(true); - flow.setFocusTraversable(getSkinnable().isFocusTraversable()); - flow.setCreateCell(new Callback<VirtualFlow, GridRow<T>>() { - @Override public GridRow<T> call(VirtualFlow flow) { - return GridViewSkin.this.createCell(); - } - }); - getChildren().add(flow); - - updateRowCount(); - - // Register listeners - registerChangeListener(control.itemsProperty(), "ITEMS"); //$NON-NLS-1$ - registerChangeListener(control.cellFactoryProperty(), "CELL_FACTORY"); //$NON-NLS-1$ - registerChangeListener(control.parentProperty(), "PARENT"); //$NON-NLS-1$ - registerChangeListener(control.cellHeightProperty(), "CELL_HEIGHT"); //$NON-NLS-1$ - registerChangeListener(control.cellWidthProperty(), "CELL_WIDTH"); //$NON-NLS-1$ - registerChangeListener(control.horizontalCellSpacingProperty(), "HORIZONZAL_CELL_SPACING"); //$NON-NLS-1$ - registerChangeListener(control.verticalCellSpacingProperty(), "VERTICAL_CELL_SPACING"); //$NON-NLS-1$ - registerChangeListener(control.widthProperty(), "WIDTH_PROPERTY"); //$NON-NLS-1$ - registerChangeListener(control.heightProperty(), "HEIGHT_PROPERTY"); //$NON-NLS-1$ - } - - @Override protected void handleControlPropertyChanged(String p) { - super.handleControlPropertyChanged(p); - if (p == "ITEMS") { //$NON-NLS-1$ - updateGridViewItems(); - } else if (p == "CELL_FACTORY") { //$NON-NLS-1$ - flow.recreateCells(); - } else if (p == "CELL_HEIGHT") { //$NON-NLS-1$ - flow.recreateCells(); - } else if (p == "CELL_WIDTH") { //$NON-NLS-1$ - updateRowCount(); - flow.recreateCells(); - } else if (p == "HORIZONZAL_CELL_SPACING") { //$NON-NLS-1$ - updateRowCount(); - flow.recreateCells(); - } else if (p == "VERTICAL_CELL_SPACING") { //$NON-NLS-1$ - flow.recreateCells(); - } else if (p == "PARENT") { //$NON-NLS-1$ - if (getSkinnable().getParent() != null && getSkinnable().isVisible()) { - getSkinnable().requestLayout(); - } - } else if (p == "WIDTH_PROPERTY" || p == "HEIGHT_PROPERTY") { //$NON-NLS-1$ //$NON-NLS-2$ - updateRowCount(); - } - } - - // Added by Fanis!!! - public VirtualFlow<GridRow<T>> getFlow() { - return flow; - } - - public void updateGridViewItems() { - if (getSkinnable().getItems() != null) { - getSkinnable().getItems().removeListener(weakGridViewItemsListener); - } - - if (getSkinnable().getItems() != null) { - getSkinnable().getItems().addListener(weakGridViewItemsListener); - } - - updateRowCount(); - flow.recreateCells(); - getSkinnable().requestLayout(); - } - - @Override protected void updateRowCount() { - if (flow == null) - return; - - int oldCount = flow.getCellCount(); - int newCount = getItemCount(); - - if (newCount != oldCount) { - flow.setCellCount(newCount); - flow.rebuildCells(); - } else { - flow.reconfigureCells(); - } - updateRows(newCount); - } - - @Override protected void layoutChildren(double x, double y, double w, double h) { - double x1 = getSkinnable().getInsets().getLeft(); - double y1 = getSkinnable().getInsets().getTop(); - double w1 = getSkinnable().getWidth() - (getSkinnable().getInsets().getLeft() + getSkinnable().getInsets().getRight()); - double h1 = getSkinnable().getHeight() - (getSkinnable().getInsets().getTop() + getSkinnable().getInsets().getBottom()); - - flow.resizeRelocate(x1, y1, w1, h1); - } - - @Override public GridRow<T> createCell() { - GridRow<T> row = new GridRow<>(); - row.updateGridView(getSkinnable()); - return row; - } - - /** - * Returns the number of row needed to display the whole set of cells - * @return GridView row count - */ - @Override public int getItemCount() { - final ObservableList<?> items = getSkinnable().getItems(); - // Fix for #98 : int division should be cast to get the result as - // double and ceiled to get the max int of it (as we are looking for - // the max number of necessary row) - return items == null ? 0 : (int)Math.ceil((double)items.size() / computeMaxCellsInRow()); - } - - /** - * Returns the max number of cell per row - * @return Max cell number per row - */ - public int computeMaxCellsInRow() { - return Math.max((int) Math.floor(computeRowWidth() / computeCellWidth()), 1); - } - - /** - * Returns the width of a row - * (should be GridView.width - GridView.Scrollbar.width) - * @return Computed width of a row - */ - protected double computeRowWidth() { - // Fix for #98 : width calculation should take the scrollbar size - // into account - - // TODO: need to figure out how to get the real scrollbar width and - // replace the 18 value - return getSkinnable().getWidth() - 18; - } - - /** - * Returns the width of a cell - * @return Computed width of a cell - */ - protected double computeCellWidth() { - return getSkinnable().cellWidthProperty().doubleValue() + (getSkinnable().horizontalCellSpacingProperty().doubleValue() * 2); - } - - protected void updateRows(int rowCount) { - for (int i = 0; i < rowCount; i++) { - GridRow<T> row = flow.getVisibleCell(i); - if (row != null) { - // FIXME hacky - need to better understand what this is about - row.updateIndex(-1); - row.updateIndex(i); - } - } - } - - protected boolean areRowsVisible() { - if (flow == null) - return false; - - if (flow.getFirstVisibleCell() == null) - return false; - - if (flow.getLastVisibleCell() == null) - return false; - - return true; - } - - @Override protected double computeMinHeight(double height, double topInset, double rightInset, double bottomInset, - double leftInset) { - return 0; - } -} diff --git a/src/impl/org/controlsfx/skin/HiddenSidesPaneSkin.java b/src/impl/org/controlsfx/skin/HiddenSidesPaneSkin.java deleted file mode 100644 index bd040bd..0000000 --- a/src/impl/org/controlsfx/skin/HiddenSidesPaneSkin.java +++ /dev/null @@ -1,336 +0,0 @@ -/** - * Copyright (c) 2013, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.skin; - -import javafx.animation.Animation.Status; -import javafx.animation.KeyFrame; -import javafx.animation.KeyValue; -import javafx.animation.Timeline; -import javafx.beans.InvalidationListener; -import javafx.beans.property.DoubleProperty; -import javafx.beans.property.SimpleDoubleProperty; -import javafx.event.EventHandler; -import javafx.geometry.Side; -import javafx.scene.Node; -import javafx.scene.control.SkinBase; -import javafx.scene.input.MouseEvent; -import javafx.scene.layout.StackPane; -import javafx.scene.shape.Rectangle; -import javafx.util.Duration; - -import org.controlsfx.control.HiddenSidesPane; - -public class HiddenSidesPaneSkin extends SkinBase<HiddenSidesPane> { - - private final StackPane stackPane; - private final EventHandler<MouseEvent> exitedHandler; - private boolean mousePressed; - - public HiddenSidesPaneSkin(HiddenSidesPane pane) { - super(pane); - - exitedHandler = event -> { - if (isMouseEnabled() && getSkinnable().getPinnedSide() == null - && !mousePressed) { - hide(); - } - }; - - stackPane = new StackPane(); - getChildren().add(stackPane); - updateStackPane(); - - InvalidationListener rebuildListener = observable -> updateStackPane(); - pane.contentProperty().addListener(rebuildListener); - pane.topProperty().addListener(rebuildListener); - pane.rightProperty().addListener(rebuildListener); - pane.bottomProperty().addListener(rebuildListener); - pane.leftProperty().addListener(rebuildListener); - - pane.addEventFilter(MouseEvent.MOUSE_MOVED, event -> { - if (isMouseEnabled() && getSkinnable().getPinnedSide() == null) { - Side side = getSide(event); - if (side != null) { - show(side); - } else if (isMouseMovedOutsideSides(event)) { - hide(); - } - } - }); - - pane.addEventFilter(MouseEvent.MOUSE_EXITED, exitedHandler); - - pane.addEventFilter(MouseEvent.MOUSE_PRESSED, - event -> mousePressed = true); - - pane.addEventFilter(MouseEvent.MOUSE_RELEASED, event -> { - mousePressed = false; - - if (isMouseEnabled() && getSkinnable().getPinnedSide() == null) { - Side side = getSide(event); - if (side != null) { - show(side); - } else { - hide(); - } - } - }); - - for (Side side : Side.values()) { - visibility[side.ordinal()] = new SimpleDoubleProperty(0); - visibility[side.ordinal()].addListener(observable -> getSkinnable() - .requestLayout()); - } - - Side pinnedSide = getSkinnable().getPinnedSide(); - if (pinnedSide != null) { - show(pinnedSide); - } - - pane.pinnedSideProperty().addListener( - observable -> show(getSkinnable().getPinnedSide())); - - Rectangle clip = new Rectangle(); - clip.setX(0); - clip.setY(0); - clip.widthProperty().bind(getSkinnable().widthProperty()); - clip.heightProperty().bind(getSkinnable().heightProperty()); - - getSkinnable().setClip(clip); - } - - private boolean isMouseMovedOutsideSides(MouseEvent event) { - if (getSkinnable().getLeft() != null - && getSkinnable().getLeft().getBoundsInParent() - .contains(event.getX(), event.getY())) { - return false; - } - - if (getSkinnable().getTop() != null - && getSkinnable().getTop().getBoundsInParent() - .contains(event.getX(), event.getY())) { - return false; - } - - if (getSkinnable().getRight() != null - && getSkinnable().getRight().getBoundsInParent() - .contains(event.getX(), event.getY())) { - return false; - } - - if (getSkinnable().getBottom() != null - && getSkinnable().getBottom().getBoundsInParent() - .contains(event.getX(), event.getY())) { - return false; - } - - return true; - } - - private boolean isMouseEnabled() { - return getSkinnable().getTriggerDistance() > 0; - } - - private Side getSide(MouseEvent evt) { - if (stackPane.getBoundsInLocal().contains(evt.getX(), evt.getY())) { - double trigger = getSkinnable().getTriggerDistance(); - if (evt.getX() <= trigger) { - return Side.LEFT; - } else if (evt.getX() > getSkinnable().getWidth() - trigger) { - return Side.RIGHT; - } else if (evt.getY() <= trigger) { - return Side.TOP; - } else if (evt.getY() > getSkinnable().getHeight() - trigger) { - return Side.BOTTOM; - } - } - - return null; - } - - private DoubleProperty[] visibility = new SimpleDoubleProperty[Side - .values().length]; - - private Timeline showTimeline; - - private void show(Side side) { - if (hideTimeline != null) { - hideTimeline.stop(); - } - - if (showTimeline != null && showTimeline.getStatus() == Status.RUNNING) { - return; - } - - KeyValue[] keyValues = new KeyValue[Side.values().length]; - for (Side s : Side.values()) { - keyValues[s.ordinal()] = new KeyValue(visibility[s.ordinal()], - s.equals(side) ? 1 : 0); - } - - Duration delay = getSkinnable().getAnimationDelay() != null ? getSkinnable() - .getAnimationDelay() : Duration.millis(300); - Duration duration = getSkinnable().getAnimationDuration() != null ? getSkinnable() - .getAnimationDuration() : Duration.millis(200); - - KeyFrame keyFrame = new KeyFrame(duration, keyValues); - showTimeline = new Timeline(keyFrame); - showTimeline.setDelay(delay); - showTimeline.play(); - } - - private Timeline hideTimeline; - - private void hide() { - if (showTimeline != null) { - showTimeline.stop(); - } - - if (hideTimeline != null && hideTimeline.getStatus() == Status.RUNNING) { - return; - } - - boolean sideVisible = false; - for (Side side : Side.values()) { - if (visibility[side.ordinal()].get() > 0) { - sideVisible = true; - break; - } - } - - // nothing to do here - if (!sideVisible) { - return; - } - - KeyValue[] keyValues = new KeyValue[Side.values().length]; - for (Side side : Side.values()) { - keyValues[side.ordinal()] = new KeyValue( - visibility[side.ordinal()], 0); - } - - Duration delay = getSkinnable().getAnimationDelay() != null ? getSkinnable() - .getAnimationDelay() : Duration.millis(300); - Duration duration = getSkinnable().getAnimationDuration() != null ? getSkinnable() - .getAnimationDuration() : Duration.millis(200); - - KeyFrame keyFrame = new KeyFrame(duration, keyValues); - hideTimeline = new Timeline(keyFrame); - hideTimeline.setDelay(delay); - hideTimeline.play(); - } - - private void updateStackPane() { - stackPane.getChildren().clear(); - - if (getSkinnable().getContent() != null) { - stackPane.getChildren().add(getSkinnable().getContent()); - } - if (getSkinnable().getTop() != null) { - stackPane.getChildren().add(getSkinnable().getTop()); - getSkinnable().getTop().setManaged(false); - getSkinnable().getTop().removeEventFilter(MouseEvent.MOUSE_EXITED, - exitedHandler); - getSkinnable().getTop().addEventFilter(MouseEvent.MOUSE_EXITED, - exitedHandler); - } - if (getSkinnable().getRight() != null) { - stackPane.getChildren().add(getSkinnable().getRight()); - getSkinnable().getRight().setManaged(false); - getSkinnable().getRight().removeEventFilter( - MouseEvent.MOUSE_EXITED, exitedHandler); - getSkinnable().getRight().addEventFilter(MouseEvent.MOUSE_EXITED, - exitedHandler); - } - if (getSkinnable().getBottom() != null) { - stackPane.getChildren().add(getSkinnable().getBottom()); - getSkinnable().getBottom().setManaged(false); - getSkinnable().getBottom().removeEventFilter( - MouseEvent.MOUSE_EXITED, exitedHandler); - getSkinnable().getBottom().addEventFilter(MouseEvent.MOUSE_EXITED, - exitedHandler); - } - if (getSkinnable().getLeft() != null) { - stackPane.getChildren().add(getSkinnable().getLeft()); - getSkinnable().getLeft().setManaged(false); - getSkinnable().getLeft().removeEventFilter(MouseEvent.MOUSE_EXITED, - exitedHandler); - getSkinnable().getLeft().addEventFilter(MouseEvent.MOUSE_EXITED, - exitedHandler); - } - } - - @Override - protected void layoutChildren(double contentX, double contentY, - double contentWidth, double contentHeight) { - - /* - * Layout the stackpane in a normal way (equals - * "lay out the content node", the only managed node) - */ - super.layoutChildren(contentX, contentY, contentWidth, contentHeight); - - // layout the unmanaged side nodes - - Node bottom = getSkinnable().getBottom(); - if (bottom != null) { - double prefHeight = bottom.prefHeight(-1); - double offset = prefHeight - * visibility[Side.BOTTOM.ordinal()].get(); - bottom.resizeRelocate(contentX, contentY + contentHeight - offset, - contentWidth, prefHeight); - bottom.setVisible(visibility[Side.BOTTOM.ordinal()].get() > 0); - } - - Node left = getSkinnable().getLeft(); - if (left != null) { - double prefWidth = left.prefWidth(-1); - double offset = prefWidth * visibility[Side.LEFT.ordinal()].get(); - left.resizeRelocate(contentX - (prefWidth - offset), contentY, - prefWidth, contentHeight); - left.setVisible(visibility[Side.LEFT.ordinal()].get() > 0); - } - - Node right = getSkinnable().getRight(); - if (right != null) { - double prefWidth = right.prefWidth(-1); - double offset = prefWidth * visibility[Side.RIGHT.ordinal()].get(); - right.resizeRelocate(contentX + contentWidth - offset, contentY, - prefWidth, contentHeight); - right.setVisible(visibility[Side.RIGHT.ordinal()].get() > 0); - } - - Node top = getSkinnable().getTop(); - if (top != null) { - double prefHeight = top.prefHeight(-1); - double offset = prefHeight * visibility[Side.TOP.ordinal()].get(); - top.resizeRelocate(contentX, contentY - (prefHeight - offset), - contentWidth, prefHeight); - top.setVisible(visibility[Side.TOP.ordinal()].get() > 0); - } - } -} diff --git a/src/impl/org/controlsfx/skin/HyperlinkLabelSkin.java b/src/impl/org/controlsfx/skin/HyperlinkLabelSkin.java deleted file mode 100644 index 10e6681..0000000 --- a/src/impl/org/controlsfx/skin/HyperlinkLabelSkin.java +++ /dev/null @@ -1,156 +0,0 @@ -/** - * Copyright (c) 2013, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.skin; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import javafx.event.ActionEvent; -import javafx.event.EventHandler; -import javafx.geometry.Insets; -import javafx.scene.Node; -import javafx.scene.control.Hyperlink; -import javafx.scene.control.Label; -import javafx.scene.text.Text; -import javafx.scene.text.TextFlow; - -import org.controlsfx.control.HyperlinkLabel; - -import com.sun.javafx.scene.control.behavior.BehaviorBase; -import com.sun.javafx.scene.control.behavior.KeyBinding; -import com.sun.javafx.scene.control.skin.BehaviorSkinBase; - -public class HyperlinkLabelSkin extends BehaviorSkinBase<HyperlinkLabel, BehaviorBase<HyperlinkLabel>> { - - /*************************************************************************** - * - * Static fields - * - **************************************************************************/ - - // The strings used to delimit the hyperlinks - private static final String HYPERLINK_START = "["; //$NON-NLS-1$ - private static final String HYPERLINK_END = "]"; //$NON-NLS-1$ - - - - /*************************************************************************** - * - * Private fields - * - **************************************************************************/ - - private final TextFlow textFlow; - private final EventHandler<ActionEvent> eventHandler = new EventHandler<ActionEvent>() { - @Override public void handle(final ActionEvent event) { - EventHandler<ActionEvent> onActionHandler = getSkinnable().getOnAction(); - if (onActionHandler != null) { - onActionHandler.handle(event); - } - } - }; - - - - /*************************************************************************** - * - * Constructors - * - **************************************************************************/ - - public HyperlinkLabelSkin(HyperlinkLabel control) { - super(control, new BehaviorBase<>(control, Collections.<KeyBinding> emptyList())); - - this.textFlow = new TextFlow(); - getChildren().add(textFlow); - updateText(); - - registerChangeListener(control.textProperty(), "TEXT"); //$NON-NLS-1$ - } - - - - /*************************************************************************** - * - * Implementation - * - **************************************************************************/ - - @Override protected void handleControlPropertyChanged(String p) { - super.handleControlPropertyChanged(p); - - if (p == "TEXT") { //$NON-NLS-1$ - updateText(); - } - } - - // splits up the string into Text and Hyperlink nodes, and places them - // into a TextFlow instance - private void updateText() { - final String text = getSkinnable().getText(); - - if (text == null || text.isEmpty()) { - textFlow.getChildren().clear(); - return; - } - - // parse the text and put it into an array list - final List<Node> nodes = new ArrayList<>(); - - int start = 0; - final int textLength = text.length(); - while (start != -1 && start < textLength) { - int startPos = text.indexOf(HYPERLINK_START, start); - int endPos = text.indexOf(HYPERLINK_END, startPos); - - // if the startPos is -1, there are no more hyperlinks... - if (startPos == -1 || endPos == -1) { - if (textLength > start) { - // ...but there is still text to turn into one last label - Label label = new Label(text.substring(start)); - nodes.add(label); - break; - } - } - - // firstly, create a label from start to startPos - Text label = new Text(text.substring(start, startPos)); - nodes.add(label); - - // if endPos is greater than startPos, create a hyperlink - Hyperlink hyperlink = new Hyperlink(text.substring(startPos + 1, endPos)); - hyperlink.setPadding(new Insets(0, 0, 0, 0)); - hyperlink.setOnAction(eventHandler); - nodes.add(hyperlink); - - start = endPos + 1; - } - - textFlow.getChildren().setAll(nodes); - } -} diff --git a/src/impl/org/controlsfx/skin/InfoOverlaySkin.java b/src/impl/org/controlsfx/skin/InfoOverlaySkin.java deleted file mode 100644 index 71bc6ad..0000000 --- a/src/impl/org/controlsfx/skin/InfoOverlaySkin.java +++ /dev/null @@ -1,248 +0,0 @@ -/** - * Copyright (c) 2014, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package impl.org.controlsfx.skin; - -import java.util.Collections; - -import javafx.animation.Animation.Status; -import javafx.animation.Interpolator; -import javafx.animation.KeyFrame; -import javafx.animation.KeyValue; -import javafx.animation.Timeline; -import javafx.beans.binding.Bindings; -import javafx.beans.property.DoubleProperty; -import javafx.beans.property.SimpleDoubleProperty; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.event.EventHandler; -import javafx.geometry.HPos; -import javafx.geometry.Insets; -import javafx.geometry.Pos; -import javafx.geometry.VPos; -import javafx.scene.Cursor; -import javafx.scene.Node; -import javafx.scene.control.Label; -import javafx.scene.control.ToggleButton; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import javafx.scene.input.MouseEvent; -import javafx.scene.layout.HBox; -import javafx.util.Duration; - -import org.controlsfx.control.InfoOverlay; - -import com.sun.javafx.scene.control.behavior.BehaviorBase; -import com.sun.javafx.scene.control.behavior.KeyBinding; -import com.sun.javafx.scene.control.skin.BehaviorSkinBase; - -public class InfoOverlaySkin extends BehaviorSkinBase<InfoOverlay, BehaviorBase<InfoOverlay>> { - - private final ImageView EXPAND_IMAGE = new ImageView(new Image(InfoOverlay.class.getResource("expand.png").toExternalForm())); //$NON-NLS-1$ - private final ImageView COLLAPSE_IMAGE = new ImageView(new Image(InfoOverlay.class.getResource("collapse.png").toExternalForm())); //$NON-NLS-1$ - - private static final Duration TRANSITION_DURATION = new Duration(350.0); - - private Node content; - private Label infoLabel; - private HBox infoPanel; - private ToggleButton expandCollapseButton; - - // animation support - private Timeline timeline; - private DoubleProperty transition = new SimpleDoubleProperty(this, "transition", 0.0) { //$NON-NLS-1$ - @Override protected void invalidated() { - getSkinnable().requestLayout(); - } - }; - - public InfoOverlaySkin(final InfoOverlay control) { - super(control, new BehaviorBase<>(control, Collections.<KeyBinding> emptyList())); - - // content - content = control.getContent(); - control.hoverProperty().addListener(new ChangeListener<Boolean>() { - @Override public void changed(ObservableValue<? extends Boolean> o, Boolean wasHover, Boolean isHover) { - if (control.isShowOnHover()) { - if ((isHover && ! isExpanded()) || (!isHover && isExpanded())) { - doToggle(); - } - } - } - }); - - // text - infoLabel = new Label(); - infoLabel.setWrapText(true); - infoLabel.setAlignment(Pos.TOP_LEFT); - infoLabel.getStyleClass().add("info"); //$NON-NLS-1$ - infoLabel.textProperty().bind(control.textProperty()); - - // button to expand / collapse the info overlay - expandCollapseButton = new ToggleButton(); - expandCollapseButton.setMouseTransparent(true); - expandCollapseButton.visibleProperty().bind(Bindings.not(control.showOnHoverProperty())); - expandCollapseButton.managedProperty().bind(Bindings.not(control.showOnHoverProperty())); - updateToggleButton(); - - // container for the info overlay and the button - infoPanel = new HBox(infoLabel, expandCollapseButton); - infoPanel.setAlignment(Pos.TOP_LEFT); - infoPanel.setFillHeight(true); - infoPanel.getStyleClass().add("info-panel"); //$NON-NLS-1$ - infoPanel.setCursor(Cursor.HAND); - infoPanel.setOnMouseClicked(new EventHandler<MouseEvent>() { - @Override public void handle(MouseEvent e) { - if (! control.isShowOnHover()) { - doToggle(); - } - } - }); - - // adding everything to the scenegraph - getChildren().addAll(content, infoPanel); - - registerChangeListener(control.contentProperty(), "CONTENT"); //$NON-NLS-1$ - } - - @Override protected void handleControlPropertyChanged(String p) { - super.handleControlPropertyChanged(p); - - if ("CONTENT".equals(p)) { //$NON-NLS-1$ - getChildren().remove(0); - getChildren().add(0, getSkinnable().getContent()); - getSkinnable().requestLayout(); - } - } - - private void doToggle() { - // do animation to show / hide the info panel - expandCollapseButton.setSelected(!expandCollapseButton.isSelected()); - toggleInfoPanel(); - updateToggleButton(); - } - - private boolean isExpanded() { - return expandCollapseButton.isSelected(); - } - - @Override - protected void layoutChildren(double contentX, double contentY, double contentWidth, double contentHeight) { - final double contentPrefHeight = content.prefHeight(contentWidth); - - // we calculate the pref width of the expand/collapse button. We will - // ensure that the button does not get smaller than this. - final double toggleButtonPrefWidth = expandCollapseButton.prefWidth(-1); - expandCollapseButton.setMinWidth(toggleButtonPrefWidth); - - // All remaining width goes to the info label - final Insets infoPanelPadding = infoPanel.getPadding(); - final double infoLabelWidth = snapSize(contentWidth - toggleButtonPrefWidth - - infoPanelPadding.getLeft() - infoPanelPadding.getRight()); - - // we then can work out the necessary height for the info panel, based on - // whether it is expanded or not, and given the current state of the animation. - final double prefInfoPanelHeight = (snapSize(infoLabel.prefHeight(infoLabelWidth)) + - snapSpace(infoPanel.getPadding().getTop()) + - snapSpace(infoPanel.getPadding().getBottom())) * - transition.get(); - - infoLabel.setMaxWidth(infoLabelWidth); - infoLabel.setMaxHeight(prefInfoPanelHeight); - - // position the imageView - layoutInArea(content, contentX, contentY, - contentWidth, contentHeight, -1, HPos.CENTER, VPos.TOP); - - // position the infoPanel (the HBox consisting of the Label and ToggleButton) - layoutInArea(infoPanel, contentX, snapPosition(contentPrefHeight - prefInfoPanelHeight), - contentWidth, prefInfoPanelHeight, 0, HPos.CENTER, VPos.BOTTOM); - } - - private void updateToggleButton() { - if (expandCollapseButton.isSelected()) { - expandCollapseButton.getStyleClass().setAll("collapse-button"); //$NON-NLS-1$ - expandCollapseButton.setGraphic(COLLAPSE_IMAGE); - } else { - expandCollapseButton.getStyleClass().setAll("expand-button"); //$NON-NLS-1$ - expandCollapseButton.setGraphic(EXPAND_IMAGE); - } - } - - @Override protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { - double insets = topInset + bottomInset; - return insets + (content == null ? 0 : content.prefHeight(width)); - } - - @Override protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) { - double insets = leftInset + rightInset; - return insets + (content == null ? 0 : content.prefWidth(height)); - } - - @Override protected double computeMaxHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { - return computePrefHeight(width, topInset, rightInset, bottomInset, leftInset); - } - - @Override protected double computeMaxWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) { - return computePrefWidth(height, topInset, rightInset, bottomInset, leftInset); - } - - private void toggleInfoPanel() { - // animate! - // The best way I know how is to transition a number between 0.0 and 1.0 - // over a set duration, and have this request layout as it goes. Then, - // use this value and multiply it against the actualInfoPanelHeight - // variable in layoutChildren - this will give a nice smooth animation. - if (content == null) { - return; - } - - Duration duration; - if (timeline != null && (timeline.getStatus() != Status.STOPPED)) { - duration = timeline.getCurrentTime(); - timeline.stop(); - } else { - duration = TRANSITION_DURATION; - } - - timeline = new Timeline(); - timeline.setCycleCount(1); - - KeyFrame k1, k2; - - if (isExpanded()) { - k1 = new KeyFrame(Duration.ZERO, new KeyValue(transition, 0)); - k2 = new KeyFrame(duration,new KeyValue(transition, 1, Interpolator.LINEAR)); - } else { - k1 = new KeyFrame(Duration.ZERO, new KeyValue(transition, 1)); - k2 = new KeyFrame(duration, new KeyValue(transition, 0, Interpolator.LINEAR)); - } - - timeline.getKeyFrames().setAll(k1, k2); - timeline.play(); - } -} diff --git a/src/impl/org/controlsfx/skin/ListSelectionViewSkin.java b/src/impl/org/controlsfx/skin/ListSelectionViewSkin.java deleted file mode 100644 index 376fac0..0000000 --- a/src/impl/org/controlsfx/skin/ListSelectionViewSkin.java +++ /dev/null @@ -1,474 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.skin; - -import static java.util.Objects.requireNonNull; -import static javafx.scene.control.SelectionMode.MULTIPLE; -import static javafx.scene.input.MouseEvent.MOUSE_CLICKED; - -import java.util.ArrayList; -import java.util.List; - -import javafx.beans.InvalidationListener; -import javafx.beans.binding.Bindings; -import javafx.geometry.Orientation; -import javafx.geometry.Pos; -import javafx.scene.Node; -import javafx.scene.control.Button; -import javafx.scene.control.ListView; -import javafx.scene.control.SkinBase; -import javafx.scene.input.MouseButton; -import javafx.scene.layout.ColumnConstraints; -import javafx.scene.layout.GridPane; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Priority; -import javafx.scene.layout.RowConstraints; -import javafx.scene.layout.StackPane; -import javafx.scene.layout.VBox; - -import org.controlsfx.control.ListSelectionView; -import org.controlsfx.glyphfont.FontAwesome; - -public class ListSelectionViewSkin<T> extends SkinBase<ListSelectionView<T>> { - - private GridPane gridPane; - private final HBox horizontalButtonBox; - private final VBox verticalButtonBox; - private Button moveToTarget; - private Button moveToTargetAll; - private Button moveToSourceAll; - private Button moveToSource; - private ListView<T> sourceListView; - private ListView<T> targetListView; - - public ListSelectionViewSkin(ListSelectionView<T> view) { - super(view); - - sourceListView = requireNonNull(createSourceListView(), - "source list view can not be null"); - sourceListView.setId("source-list-view"); - sourceListView.setItems(view.getSourceItems()); - - targetListView = requireNonNull(createTargetListView(), - "target list view can not be null"); - targetListView.setId("target-list-view"); - targetListView.setItems(view.getTargetItems()); - - sourceListView.cellFactoryProperty().bind(view.cellFactoryProperty()); - targetListView.cellFactoryProperty().bind(view.cellFactoryProperty()); - - gridPane = createGridPane(); - horizontalButtonBox = createHorizontalButtonBox(); - verticalButtonBox = createVerticalButtonBox(); - - getChildren().add(gridPane); - - InvalidationListener updateListener = o -> updateView(); - - view.sourceHeaderProperty().addListener(updateListener); - view.sourceFooterProperty().addListener(updateListener); - view.targetHeaderProperty().addListener(updateListener); - view.targetFooterProperty().addListener(updateListener); - - updateView(); - - getSourceListView().addEventHandler( - MOUSE_CLICKED, - event -> { - if (event.getButton() == MouseButton.PRIMARY - && event.getClickCount() == 2) { - moveToTarget(); - } - }); - - getTargetListView().addEventHandler( - MOUSE_CLICKED, - event -> { - if (event.getButton() == MouseButton.PRIMARY - && event.getClickCount() == 2) { - moveToSource(); - } - }); - - view.orientationProperty().addListener(observable -> updateView()); - } - - private GridPane createGridPane() { - GridPane gridPane = new GridPane(); - gridPane.getStyleClass().add("grid-pane"); - - return gridPane; - } - - // Constraints used when view's orientation is HORIZONTAL - private void setHorizontalViewContraints() { - gridPane.getColumnConstraints().clear(); - gridPane.getRowConstraints().clear(); - - ColumnConstraints col1 = new ColumnConstraints(); - - col1.setFillWidth(true); - col1.setHgrow(Priority.ALWAYS); - col1.setMaxWidth(Double.MAX_VALUE); - col1.setPrefWidth(200); - - ColumnConstraints col2 = new ColumnConstraints(); - col2.setFillWidth(true); - col2.setHgrow(Priority.NEVER); - - ColumnConstraints col3 = new ColumnConstraints(); - col3.setFillWidth(true); - col3.setHgrow(Priority.ALWAYS); - col3.setMaxWidth(Double.MAX_VALUE); - col3.setPrefWidth(200); - - gridPane.getColumnConstraints().addAll(col1, col2, col3); - - RowConstraints row1 = new RowConstraints(); - row1.setFillHeight(true); - row1.setVgrow(Priority.NEVER); - - RowConstraints row2 = new RowConstraints(); - row2.setMaxHeight(Double.MAX_VALUE); - row2.setPrefHeight(200); - row2.setVgrow(Priority.ALWAYS); - - RowConstraints row3 = new RowConstraints(); - row3.setFillHeight(true); - row3.setVgrow(Priority.NEVER); - - gridPane.getRowConstraints().addAll(row1, row2, row3); - } - - // Constraints used when view's orientation is VERTICAL - private void setVerticalViewContraints() { - gridPane.getColumnConstraints().clear(); - gridPane.getRowConstraints().clear(); - - ColumnConstraints col1 = new ColumnConstraints(); - - col1.setFillWidth(true); - col1.setHgrow(Priority.ALWAYS); - col1.setMaxWidth(Double.MAX_VALUE); - col1.setPrefWidth(200); - - gridPane.getColumnConstraints().addAll(col1); - - RowConstraints row1 = new RowConstraints(); - row1.setFillHeight(true); - row1.setVgrow(Priority.NEVER); - - RowConstraints row2 = new RowConstraints(); - row2.setMaxHeight(Double.MAX_VALUE); - row2.setPrefHeight(200); - row2.setVgrow(Priority.ALWAYS); - - RowConstraints row3 = new RowConstraints(); - row3.setFillHeight(true); - row3.setVgrow(Priority.NEVER); - - RowConstraints row4 = new RowConstraints(); - row4.setFillHeight(true); - row4.setVgrow(Priority.NEVER); - - RowConstraints row5 = new RowConstraints(); - row5.setFillHeight(true); - row5.setVgrow(Priority.NEVER); - - RowConstraints row6 = new RowConstraints(); - row6.setMaxHeight(Double.MAX_VALUE); - row6.setPrefHeight(200); - row6.setVgrow(Priority.ALWAYS); - - RowConstraints row7 = new RowConstraints(); - row7.setFillHeight(true); - row7.setVgrow(Priority.NEVER); - - - gridPane.getRowConstraints().addAll(row1, row2, row3, row4, row5, row6, row7); - } - - // Used when view's orientation is HORIZONTAL - private VBox createVerticalButtonBox() { - VBox box = new VBox(5); - box.setFillWidth(true); - - FontAwesome fontAwesome = new FontAwesome(); - moveToTarget = new Button("", - fontAwesome.create(FontAwesome.Glyph.ANGLE_RIGHT)); - moveToTargetAll = new Button("", - fontAwesome.create(FontAwesome.Glyph.ANGLE_DOUBLE_RIGHT)); - - moveToSource = new Button("", - fontAwesome.create(FontAwesome.Glyph.ANGLE_LEFT)); - moveToSourceAll = new Button("", - fontAwesome.create(FontAwesome.Glyph.ANGLE_DOUBLE_LEFT)); - - updateButtons(); - - box.getChildren().addAll(moveToTarget, moveToTargetAll, moveToSource, - moveToSourceAll); - - return box; - } - - // Used when view's orientation is VERTICAL - private HBox createHorizontalButtonBox() { - HBox box = new HBox(5); - box.setFillHeight(true); - - FontAwesome fontAwesome = new FontAwesome(); - moveToTarget = new Button("", - fontAwesome.create(FontAwesome.Glyph.ANGLE_DOWN)); - moveToTargetAll = new Button("", - fontAwesome.create(FontAwesome.Glyph.ANGLE_DOUBLE_DOWN)); - - moveToSource = new Button("", - fontAwesome.create(FontAwesome.Glyph.ANGLE_UP)); - moveToSourceAll = new Button("", - fontAwesome.create(FontAwesome.Glyph.ANGLE_DOUBLE_UP)); - - updateButtons(); - - box.getChildren().addAll(moveToTarget, moveToTargetAll, moveToSource, - moveToSourceAll); - - return box; - } - - private void updateButtons() { - - moveToTarget.getStyleClass().add("move-to-target-button"); - moveToTargetAll.getStyleClass().add("move-to-target-all-button"); - moveToSource.getStyleClass().add("move-to-source-button"); - moveToSourceAll.getStyleClass().add("move-to-source-all-button"); - - moveToTarget.setMaxWidth(Double.MAX_VALUE); - moveToTargetAll.setMaxWidth(Double.MAX_VALUE); - moveToSource.setMaxWidth(Double.MAX_VALUE); - moveToSourceAll.setMaxWidth(Double.MAX_VALUE); - - getSourceListView().itemsProperty().addListener( - it -> bindMoveAllButtonsToDataModel()); - - getTargetListView().itemsProperty().addListener( - it -> bindMoveAllButtonsToDataModel()); - - getSourceListView().selectionModelProperty().addListener( - it -> bindMoveButtonsToSelectionModel()); - - getTargetListView().selectionModelProperty().addListener( - it -> bindMoveButtonsToSelectionModel()); - - bindMoveButtonsToSelectionModel(); - bindMoveAllButtonsToDataModel(); - - moveToTarget.setOnAction(evt -> moveToTarget()); - - moveToTargetAll.setOnAction(evt -> moveToTargetAll()); - - moveToSource.setOnAction(evt -> moveToSource()); - - moveToSourceAll.setOnAction(evt -> moveToSourceAll()); - } - - private void bindMoveAllButtonsToDataModel() { - moveToTargetAll.disableProperty().bind( - Bindings.isEmpty(getSourceListView().getItems())); - - moveToSourceAll.disableProperty().bind( - Bindings.isEmpty(getTargetListView().getItems())); - } - - private void bindMoveButtonsToSelectionModel() { - moveToTarget.disableProperty().bind( - Bindings.isEmpty(getSourceListView().getSelectionModel() - .getSelectedItems())); - - moveToSource.disableProperty().bind( - Bindings.isEmpty(getTargetListView().getSelectionModel() - .getSelectedItems())); - } - - private void updateView() { - gridPane.getChildren().clear(); - - Node sourceHeader = getSkinnable().getSourceHeader(); - Node targetHeader = getSkinnable().getTargetHeader(); - Node sourceFooter = getSkinnable().getSourceFooter(); - Node targetFooter = getSkinnable().getTargetFooter(); - - ListView<T> sourceList = getSourceListView(); - ListView<T> targetList = getTargetListView(); - - StackPane stackPane = new StackPane(); - stackPane.setAlignment(Pos.CENTER); - - Orientation orientation = getSkinnable().getOrientation(); - - if (orientation == Orientation.HORIZONTAL) { - setHorizontalViewContraints(); - - if (sourceHeader != null) { - gridPane.add(sourceHeader, 0, 0); - } - - if (targetHeader != null) { - gridPane.add(targetHeader, 2, 0); - } - - if (sourceList != null) { - gridPane.add(sourceList, 0, 1); - } - - if (targetList != null) { - gridPane.add(targetList, 2, 1); - } - - if (sourceFooter != null) { - gridPane.add(sourceFooter, 0, 2); - } - - if (targetFooter != null) { - gridPane.add(targetFooter, 2, 2); - } - - stackPane.getChildren().add(verticalButtonBox); - gridPane.add(stackPane, 1, 1); - } else { - setVerticalViewContraints(); - - if (sourceHeader != null) { - gridPane.add(sourceHeader, 0, 0); - } - - if (targetHeader != null) { - gridPane.add(targetHeader, 0, 4); - } - - if (sourceList != null) { - gridPane.add(sourceList, 0, 1); - } - - if (targetList != null) { - gridPane.add(targetList, 0, 5); - } - - if (sourceFooter != null) { - gridPane.add(sourceFooter, 0, 2); - } - - if (targetFooter != null) { - gridPane.add(targetFooter, 0, 6); - } - - stackPane.getChildren().add(horizontalButtonBox); - gridPane.add(stackPane, 0, 3); - } - } - - private void moveToTarget() { - move(getSourceListView(), getTargetListView()); - getSourceListView().getSelectionModel().clearSelection(); - } - - private void moveToTargetAll() { - move(getSourceListView(), getTargetListView(), new ArrayList<>( - getSourceListView().getItems())); - getSourceListView().getSelectionModel().clearSelection(); - } - - private void moveToSource() { - move(getTargetListView(), getSourceListView()); - getTargetListView().getSelectionModel().clearSelection(); - } - - private void moveToSourceAll() { - move(getTargetListView(), getSourceListView(), new ArrayList<>( - getTargetListView().getItems())); - getTargetListView().getSelectionModel().clearSelection(); - } - - private void move(ListView<T> viewA, ListView<T> viewB) { - List<T> selectedItems = new ArrayList<>(viewA.getSelectionModel() - .getSelectedItems()); - move(viewA, viewB, selectedItems); - } - - private void move(ListView<T> viewA, ListView<T> viewB, List<T> items) { - for (T item : items) { - viewA.getItems().remove(item); - viewB.getItems().add(item); - } - } - - /** - * Returns the source list view (shown on the left-hand side). - * - * @return the source list view - */ - public final ListView<T> getSourceListView() { - return sourceListView; - } - - /** - * Returns the target list view (shown on the right-hand side). - * - * @return the target list view - */ - public final ListView<T> getTargetListView() { - return targetListView; - } - - /** - * Creates the {@link ListView} instance used on the left-hand side as the - * source list. This method can be overridden to provide a customized list - * view control. - * - * @return the source list view - */ - protected ListView<T> createSourceListView() { - return createListView(); - } - - /** - * Creates the {@link ListView} instance used on the right-hand side as the - * target list. This method can be overridden to provide a customized list - * view control. - * - * @return the target list view - */ - protected ListView<T> createTargetListView() { - return createListView(); - } - - private ListView<T> createListView() { - ListView<T> view = new ListView<>(); - view.getSelectionModel().setSelectionMode(MULTIPLE); - return view; - } -} diff --git a/src/impl/org/controlsfx/skin/MaskerPaneSkin.java b/src/impl/org/controlsfx/skin/MaskerPaneSkin.java deleted file mode 100644 index 0e7cf61..0000000 --- a/src/impl/org/controlsfx/skin/MaskerPaneSkin.java +++ /dev/null @@ -1,79 +0,0 @@ -/** - * Copyright (c) 2014, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.skin; - -import javafx.geometry.Pos; -import javafx.scene.control.Label; -import javafx.scene.control.SkinBase; -import javafx.scene.layout.HBox; -import javafx.scene.layout.StackPane; -import javafx.scene.layout.VBox; -import org.controlsfx.control.MaskerPane; - -public class MaskerPaneSkin extends SkinBase<MaskerPane> { - - public MaskerPaneSkin(MaskerPane maskerPane) { - super(maskerPane); - getChildren().add(createMasker(maskerPane)); - } - - private StackPane createMasker(MaskerPane maskerPane) { - VBox vBox = new VBox(); - vBox.setAlignment(Pos.CENTER); - vBox.setSpacing(10.0); - vBox.getStyleClass().add("masker-center"); //$NON-NLS-1$ - - vBox.getChildren().add(createLabel()); - vBox.getChildren().add(createProgressIndicator()); - - HBox hBox = new HBox(); - hBox.setAlignment(Pos.CENTER); - hBox.getChildren().addAll(vBox); - - StackPane glass = new StackPane(); - glass.setAlignment(Pos.CENTER); - glass.getStyleClass().add("masker-glass"); //$NON-NLS-1$ - glass.getChildren().add(hBox); - - return glass; - } - - private Label createLabel() { - Label text = new Label(); - text.textProperty().bind(getSkinnable().textProperty()); - text.getStyleClass().add("masker-text"); //$NON-NLS-1$ - return text; - } - - private Label createProgressIndicator() { - Label graphic = new Label(); - graphic.setGraphic(getSkinnable().getProgressNode()); - graphic.visibleProperty().bind(getSkinnable().progressVisibleProperty()); - graphic.getStyleClass().add("masker-graphic"); //$NON-NLS-1$ - return graphic; - } -} diff --git a/src/impl/org/controlsfx/skin/MasterDetailPaneSkin.java b/src/impl/org/controlsfx/skin/MasterDetailPaneSkin.java deleted file mode 100644 index 8a954b8..0000000 --- a/src/impl/org/controlsfx/skin/MasterDetailPaneSkin.java +++ /dev/null @@ -1,473 +0,0 @@ -/** - * Copyright (c) 2014, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.skin; - -import static java.lang.Double.MAX_VALUE; -import static javafx.geometry.Orientation.HORIZONTAL; -import static javafx.geometry.Orientation.VERTICAL; - -import java.util.List; - -import javafx.animation.Animation; -import javafx.animation.KeyFrame; -import javafx.animation.KeyValue; -import javafx.animation.Timeline; -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.collections.ListChangeListener; -import javafx.geometry.Side; -import javafx.scene.Node; -import javafx.scene.control.SkinBase; -import javafx.scene.control.SplitPane; -import javafx.scene.control.SplitPane.Divider; -import javafx.scene.layout.Region; -import javafx.util.Duration; - -import org.controlsfx.control.MasterDetailPane; - -public class MasterDetailPaneSkin extends SkinBase<MasterDetailPane> { - - private boolean changing = false; - private SplitPane splitPane; - private final Timeline timeline = new Timeline(); - private BooleanProperty showDetailForTimeline = new SimpleBooleanProperty(); - - public MasterDetailPaneSkin(MasterDetailPane pane) { - super(pane); - - this.splitPane = new SplitPane(); - this.splitPane.setDividerPosition(0, pane.getDividerPosition()); - - /** - * We listen to the change of dividers (when adding or removing node), and then - * we listen to their position to update correctly the dividerPosition of - * the MasterDetailPane. - */ - this.splitPane.getDividers().addListener(new ListChangeListener<Divider>() { - - @Override - public void onChanged(ListChangeListener.Change<? extends Divider> change) { - while (change.next()) { - if (change.wasAdded()) { - change.getAddedSubList().get(0).positionProperty().addListener(updateDividerPositionListener); - } else if (change.wasRemoved()) { - change.getRemoved().get(0).positionProperty().removeListener(updateDividerPositionListener); - } - } - } - }); - - SplitPane.setResizableWithParent(getSkinnable().getDetailNode(), false); - - switch (getSkinnable().getDetailSide()) { - case BOTTOM: - case TOP: - splitPane.setOrientation(VERTICAL); - break; - case LEFT: - case RIGHT: - splitPane.setOrientation(HORIZONTAL); - break; - } - - getSkinnable().masterNodeProperty().addListener( - new ChangeListener<Node>() { - @Override - public void changed(ObservableValue<? extends Node> value, - Node oldNode, Node newNode) { - - if (oldNode != null) { - splitPane.getItems().remove(oldNode); - } - - if (newNode != null) { - - updateMinAndMaxSizes(); - - int masterIndex = 0; - switch (splitPane.getOrientation()) { - case HORIZONTAL: - switch (getSkinnable().getDetailSide()) { - case LEFT: - masterIndex = 1; - break; - case RIGHT: - masterIndex = 0; - break; - default: - throw new IllegalArgumentException( - "illegal details position " //$NON-NLS-1$ - + getSkinnable() - .getDetailSide() - + " for orientation " //$NON-NLS-1$ - + splitPane - .getOrientation()); - } - break; - case VERTICAL: - switch (getSkinnable().getDetailSide()) { - case TOP: - masterIndex = 1; - break; - case BOTTOM: - masterIndex = 0; - break; - default: - throw new IllegalArgumentException( - "illegal details position " //$NON-NLS-1$ - + getSkinnable() - .getDetailSide() - + " for orientation " //$NON-NLS-1$ - + splitPane - .getOrientation()); - } - break; - } - List<Node> items = splitPane.getItems(); - if (items.isEmpty()) { - items.add(newNode); - } else { - items.add(masterIndex, newNode); - } - } - } - }); - - getSkinnable().detailNodeProperty().addListener( - new ChangeListener<Node>() { - @Override - public void changed(ObservableValue<? extends Node> value, - Node oldNode, Node newNode) { - - if (oldNode != null) { - splitPane.getItems().remove(oldNode); - } - - /** - * If the detailNode is not showing, we do not force - * it to show. - */ - if (newNode != null && getSkinnable().isShowDetailNode()) { - - /** - * Force the divider to take the value of the Pane, - * and not compute his. - */ - splitPane.setDividerPositions(getSkinnable().getDividerPosition()); - updateMinAndMaxSizes(); - - SplitPane.setResizableWithParent(newNode, false); - - int detailsIndex = 0; - switch (splitPane.getOrientation()) { - case HORIZONTAL: - switch (getSkinnable().getDetailSide()) { - case LEFT: - detailsIndex = 0; - break; - case RIGHT: - detailsIndex = 1; - break; - default: - throw new IllegalArgumentException( - "illegal details position " //$NON-NLS-1$ - + getSkinnable() - .getDetailSide() - + " for orientation " //$NON-NLS-1$ - + splitPane - .getOrientation()); - } - break; - case VERTICAL: - switch (getSkinnable().getDetailSide()) { - case TOP: - detailsIndex = 0; - break; - case BOTTOM: - detailsIndex = 1; - break; - default: - throw new IllegalArgumentException( - "illegal details position " //$NON-NLS-1$ - + getSkinnable() - .getDetailSide() - + " for orientation " //$NON-NLS-1$ - + splitPane - .getOrientation()); - } - break; - } - List<Node> items = splitPane.getItems(); - if (items.isEmpty()) { - items.add(newNode); - } else { - items.add(detailsIndex, newNode); - } - } - } - }); - - getSkinnable().showDetailNodeProperty().addListener( - new ChangeListener<Boolean>() { - @Override - public void changed( - ObservableValue<? extends Boolean> value, - Boolean oldShow, Boolean newShow) { - /** - * https://bitbucket.org/controlsfx/controlsfx/issue/456/masterdetailpane-bug-of-adding-infinite - * - * Fixed bug - when close or show is still animated jump to last frame of animation - ** and fire finished event to complete the previous demand - * - */ - if (getSkinnable().isAnimated() && timeline.getStatus() == Animation.Status.RUNNING) { - timeline.jumpTo("endAnimation"); - timeline.getOnFinished().handle(null); - } - - if (newShow) { - open(); - } else { - close(); - } - } - }); - - getSkinnable().detailSideProperty().addListener( - new ChangeListener<Side>() { - @Override - public void changed(ObservableValue<? extends Side> value, - Side oldPos, Side newPos) { - if (getSkinnable().isShowDetailNode()) { - splitPane.getItems().clear(); - } - switch (newPos) { - case TOP: - case BOTTOM: - splitPane.setOrientation(VERTICAL); - break; - case LEFT: - case RIGHT: - splitPane.setOrientation(HORIZONTAL); - } - switch (newPos) { - case TOP: - case LEFT: - if (getSkinnable().isShowDetailNode()) { - splitPane.getItems().add( - getSkinnable().getDetailNode()); - splitPane.getItems().add( - getSkinnable().getMasterNode()); - } - switch (oldPos) { - case BOTTOM: - case RIGHT: - getSkinnable().setDividerPosition(1 - getSkinnable().getDividerPosition()); - break; - default: - break; - } - break; - case BOTTOM: - case RIGHT: - if (getSkinnable().isShowDetailNode()) { - splitPane.getItems().add( - getSkinnable().getMasterNode()); - splitPane.getItems().add( - getSkinnable().getDetailNode()); - } - switch (oldPos) { - case TOP: - case LEFT: - getSkinnable().setDividerPosition(1 - getSkinnable().getDividerPosition()); - break; - default: - break; - } - break; - } - if (getSkinnable().isShowDetailNode()) { - splitPane.setDividerPositions(getSkinnable().getDividerPosition()); - } - } - }); - - updateMinAndMaxSizes(); - - getChildren().add(splitPane); - - splitPane.getItems().add(getSkinnable().getMasterNode()); - - if (getSkinnable().isShowDetailNode()) { - switch (getSkinnable().getDetailSide()) { - case TOP: - case LEFT: - splitPane.getItems().add(0, getSkinnable().getDetailNode()); - break; - case BOTTOM: - case RIGHT: - splitPane.getItems().add(getSkinnable().getDetailNode()); - break; - } - - bindDividerPosition(); - } - - timeline.setOnFinished(evt -> { - if (!showDetailForTimeline.get()) { - unbindDividerPosition(); - splitPane.getItems().remove( - getSkinnable().getDetailNode()); - getSkinnable().getDetailNode().setOpacity(1); - } - changing = false; - }); - } - - private InvalidationListener listenersDivider = new InvalidationListener() { - @Override - public void invalidated(Observable arg0) { - changing = true; - splitPane.setDividerPosition(0, getSkinnable().getDividerPosition()); - changing = false; - } - }; - - private void bindDividerPosition() { - getSkinnable().dividerPositionProperty().addListener(listenersDivider); - } - - private void unbindDividerPosition() { - getSkinnable().dividerPositionProperty().removeListener(listenersDivider); - } - - private void updateMinAndMaxSizes() { - if (getSkinnable().getMasterNode() instanceof Region) { - ((Region) getSkinnable().getMasterNode()).setMinSize(0, 0); - ((Region) getSkinnable().getMasterNode()).setMaxSize(MAX_VALUE, - MAX_VALUE); - } - - if (getSkinnable().getDetailNode() instanceof Region) { - ((Region) getSkinnable().getDetailNode()).setMinSize(0, 0); - ((Region) getSkinnable().getDetailNode()).setMaxSize(MAX_VALUE, - MAX_VALUE); - } - } - - private void open() { - changing = true; - Node node = getSkinnable().getDetailNode(); - - switch (getSkinnable().getDetailSide()) { - case TOP: - case LEFT: - splitPane.getItems().add(0, node); - splitPane.setDividerPositions(0); - break; - case BOTTOM: - case RIGHT: - splitPane.getItems().add(node); - splitPane.setDividerPositions(1); - break; - } - - updateMinAndMaxSizes(); - maybeAnimatePositionChange(getSkinnable().getDividerPosition(), true); - } - - private void close() { - changing = true; - if (!splitPane.getDividers().isEmpty()) { - - /* - * Do we collapse by moving the divider to the left/right or - * top/bottom? - */ - double targetLocation = 0; - switch (getSkinnable().getDetailSide()) { - case BOTTOM: - case RIGHT: - targetLocation = 1; - break; - default: - break; - } - - maybeAnimatePositionChange(targetLocation, false); - } - } - - private void maybeAnimatePositionChange(final double position, - final boolean showDetail) { - showDetailForTimeline.set(showDetail); - - Divider divider = splitPane.getDividers().get(0); - - if (showDetailForTimeline.get()) { - unbindDividerPosition(); - bindDividerPosition(); - } - - if (getSkinnable().isAnimated()) { - KeyValue positionKeyValue = new KeyValue( - divider.positionProperty(), position); - KeyValue opacityKeyValue = new KeyValue(getSkinnable() - .getDetailNode().opacityProperty(), showDetailForTimeline.get() ? 1 : 0); - - KeyFrame keyFrame = new KeyFrame(Duration.seconds(.1), "endAnimation", positionKeyValue, opacityKeyValue); - - timeline.getKeyFrames().clear(); - timeline.getKeyFrames().add(keyFrame); - - timeline.playFromStart(); - } else { - getSkinnable().getDetailNode().setOpacity(1); - divider.setPosition(position); - - if (!showDetailForTimeline.get()) { - unbindDividerPosition(); - splitPane.getItems().remove(getSkinnable().getDetailNode()); - } - changing = false; - } - } - - private ChangeListener<Number> updateDividerPositionListener = new ChangeListener<Number>() { - - @Override - public void changed(ObservableValue<? extends Number> ov, Number t, Number t1) { - if (!changing) { - getSkinnable().setDividerPosition(t1.doubleValue()); - } - } - }; -} diff --git a/src/impl/org/controlsfx/skin/NotificationBar.java b/src/impl/org/controlsfx/skin/NotificationBar.java deleted file mode 100644 index 2702eba..0000000 --- a/src/impl/org/controlsfx/skin/NotificationBar.java +++ /dev/null @@ -1,309 +0,0 @@ -/** - * Copyright (c) 2014, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.skin; - -import javafx.animation.Animation.Status; -import javafx.animation.Interpolator; -import javafx.animation.KeyFrame; -import javafx.animation.KeyValue; -import javafx.animation.Timeline; -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; -import javafx.beans.property.DoubleProperty; -import javafx.beans.property.SimpleDoubleProperty; -import javafx.collections.ObservableList; -import javafx.event.ActionEvent; -import javafx.event.Event; -import javafx.event.EventHandler; -import javafx.geometry.Insets; -import javafx.geometry.Pos; -import javafx.geometry.VPos; -import javafx.scene.Node; -import javafx.scene.control.Button; -import javafx.scene.control.ButtonBar; -import javafx.scene.control.Label; -import javafx.scene.layout.GridPane; -import javafx.scene.layout.Priority; -import javafx.scene.layout.Region; -import javafx.scene.layout.StackPane; -import javafx.util.Duration; - -import org.controlsfx.control.NotificationPane; -import org.controlsfx.control.action.Action; -import org.controlsfx.control.action.ActionUtils; - -@SuppressWarnings("deprecation") -public abstract class NotificationBar extends Region { - - private static final double MIN_HEIGHT = 40; - - final Label label; - Label title; - ButtonBar actionsBar; - Button closeBtn; - - private final GridPane pane; - - public DoubleProperty transition = new SimpleDoubleProperty() { - @Override protected void invalidated() { - requestContainerLayout(); - } - }; - - - public void requestContainerLayout() { - layoutChildren(); - } - - public String getTitle() { - return ""; //$NON-NLS-1$ - } - - public boolean isCloseButtonVisible() { - return true; - } - - public abstract String getText(); - public abstract Node getGraphic(); - public abstract ObservableList<Action> getActions(); - public abstract void hide(); - public abstract boolean isShowing(); - public abstract boolean isShowFromTop(); - - public abstract double getContainerHeight(); - public abstract void relocateInParent(double x, double y); - - public NotificationBar() { - getStyleClass().add("notification-bar"); //$NON-NLS-1$ - - setVisible(isShowing()); - - pane = new GridPane(); - pane.getStyleClass().add("pane"); //$NON-NLS-1$ - pane.setAlignment(Pos.BASELINE_LEFT); - getChildren().setAll(pane); - - // initialise title area, if one is set - String titleStr = getTitle(); - if (titleStr != null && ! titleStr.isEmpty()) { - title = new Label(); - title.getStyleClass().add("title"); //$NON-NLS-1$ - title.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); - GridPane.setHgrow(title, Priority.ALWAYS); - - title.setText(titleStr); - title.opacityProperty().bind(transition); - } - - // initialise label area - label = new Label(); - label.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); - GridPane.setVgrow(label, Priority.ALWAYS); - GridPane.setHgrow(label, Priority.ALWAYS); - - label.setText(getText()); - label.setGraphic(getGraphic()); - label.opacityProperty().bind(transition); - - // initialise actions area - getActions().addListener(new InvalidationListener() { - @Override public void invalidated(Observable arg0) { - updatePane(); - } - }); - - // initialise close button area - closeBtn = new Button(); - closeBtn.setOnAction(new EventHandler<ActionEvent>() { - @Override public void handle(ActionEvent arg0) { - hide(); - } - }); - closeBtn.getStyleClass().setAll("close-button"); //$NON-NLS-1$ - StackPane graphic = new StackPane(); - graphic.getStyleClass().setAll("graphic"); //$NON-NLS-1$ - closeBtn.setGraphic(graphic); - closeBtn.setMinSize(17, 17); - closeBtn.setPrefSize(17, 17); - closeBtn.setFocusTraversable(false); - closeBtn.opacityProperty().bind(transition); - GridPane.setMargin(closeBtn, new Insets(0, 0, 0, 8)); - - // position the close button in the best place, depending on the height - double minHeight = minHeight(-1); - GridPane.setValignment(closeBtn, minHeight == MIN_HEIGHT ? VPos.CENTER : VPos.TOP); - - // put it all together - updatePane(); - } - - void updatePane() { - actionsBar = ActionUtils.createButtonBar(getActions()); - actionsBar.opacityProperty().bind(transition); - GridPane.setHgrow(actionsBar, Priority.SOMETIMES); - pane.getChildren().clear(); - - int row = 0; - - if (title != null) { - pane.add(title, 0, row++); - } - - pane.add(label, 0, row); - pane.add(actionsBar, 1, row); - - if (isCloseButtonVisible()) { - pane.add(closeBtn, 2, 0, 1, row+1); - } - } - - @Override protected void layoutChildren() { - final double w = getWidth(); - final double h = computePrefHeight(-1); - - final double notificationBarHeight = prefHeight(w); - final double notificationMinHeight = minHeight(w); - - if (isShowFromTop()) { - // place at top of area - pane.resize(w, h); - relocateInParent(0, (transition.get() - 1) * notificationMinHeight); - } else { - // place at bottom of area - pane.resize(w, notificationBarHeight); - relocateInParent(0, getContainerHeight() - notificationBarHeight); - } - } - - @Override protected double computeMinHeight(double width) { - return Math.max(super.computePrefHeight(width), MIN_HEIGHT); - } - - @Override protected double computePrefHeight(double width) { - return Math.max(pane.prefHeight(width), minHeight(width)) * transition.get(); - } - - public void doShow() { - transitionStartValue = 0; - doAnimationTransition(); - } - - public void doHide() { - transitionStartValue = 1; - doAnimationTransition(); - } - - - - // --- animation timeline code - private final Duration TRANSITION_DURATION = new Duration(350.0); - private Timeline timeline; - private double transitionStartValue; - private void doAnimationTransition() { - Duration duration; - - if (timeline != null && (timeline.getStatus() != Status.STOPPED)) { - duration = timeline.getCurrentTime(); - - // fix for #70 - the notification pane freezes up as it has zero - // duration to expand / contract - duration = duration == Duration.ZERO ? TRANSITION_DURATION : duration; - transitionStartValue = transition.get(); - // --- end of fix - - timeline.stop(); - } else { - duration = TRANSITION_DURATION; - } - - timeline = new Timeline(); - timeline.setCycleCount(1); - - KeyFrame k1, k2; - - if (isShowing()) { - k1 = new KeyFrame( - Duration.ZERO, - new EventHandler<ActionEvent>() { - @Override public void handle(ActionEvent event) { - // start expand - setCache(true); - setVisible(true); - - pane.fireEvent(new Event(NotificationPane.ON_SHOWING)); - } - }, - new KeyValue(transition, transitionStartValue) - ); - - k2 = new KeyFrame( - duration, - new EventHandler<ActionEvent>() { - @Override public void handle(ActionEvent event) { - // end expand - pane.setCache(false); - - pane.fireEvent(new Event(NotificationPane.ON_SHOWN)); - } - }, - new KeyValue(transition, 1, Interpolator.EASE_OUT) - - ); - } else { - k1 = new KeyFrame( - Duration.ZERO, - new EventHandler<ActionEvent>() { - @Override public void handle(ActionEvent event) { - // Start collapse - pane.setCache(true); - - pane.fireEvent(new Event(NotificationPane.ON_HIDING)); - } - }, - new KeyValue(transition, transitionStartValue) - ); - - k2 = new KeyFrame( - duration, - new EventHandler<ActionEvent>() { - @Override public void handle(ActionEvent event) { - // end collapse - setCache(false); - setVisible(false); - - pane.fireEvent(new Event(NotificationPane.ON_HIDDEN)); - } - }, - new KeyValue(transition, 0, Interpolator.EASE_IN) - ); - } - - timeline.getKeyFrames().setAll(k1, k2); - timeline.play(); - } -} - diff --git a/src/impl/org/controlsfx/skin/NotificationPaneSkin.java b/src/impl/org/controlsfx/skin/NotificationPaneSkin.java deleted file mode 100644 index 58d4046..0000000 --- a/src/impl/org/controlsfx/skin/NotificationPaneSkin.java +++ /dev/null @@ -1,201 +0,0 @@ -/** - * Copyright (c) 2013, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.skin; - -import java.util.Collections; - -import com.sun.javafx.scene.traversal.ParentTraversalEngine; -import javafx.collections.ObservableList; -import javafx.scene.Node; -import javafx.scene.shape.Rectangle; - -import org.controlsfx.control.NotificationPane; -import org.controlsfx.control.action.Action; - -import com.sun.javafx.scene.control.behavior.BehaviorBase; -import com.sun.javafx.scene.control.behavior.KeyBinding; -import com.sun.javafx.scene.control.skin.BehaviorSkinBase; - -public class NotificationPaneSkin extends BehaviorSkinBase<NotificationPane, BehaviorBase<NotificationPane>> { - - private NotificationBar notificationBar; - private Node content; - private Rectangle clip = new Rectangle(); - - public NotificationPaneSkin(final NotificationPane control) { - super(control, new BehaviorBase<>(control, Collections.<KeyBinding> emptyList())); - - notificationBar = new NotificationBar() { - @Override public void requestContainerLayout() { - control.requestLayout(); - } - - @Override public String getText() { - return control.getText(); - } - - @Override public Node getGraphic() { - return control.getGraphic(); - } - - @Override public ObservableList<Action> getActions() { - return control.getActions(); - } - - @Override public boolean isShowing() { - return control.isShowing(); - } - - @Override public boolean isShowFromTop() { - return control.isShowFromTop(); - } - - @Override public void hide() { - control.hide(); - } - - @Override public boolean isCloseButtonVisible() { - return control.isCloseButtonVisible(); - } - - @Override public double getContainerHeight() { - return control.getHeight(); - } - - @Override public void relocateInParent(double x, double y) { - notificationBar.relocate(x, y); - } - }; - - control.setClip(clip); - updateContent(); - - registerChangeListener(control.heightProperty(), "HEIGHT"); //$NON-NLS-1$ - registerChangeListener(control.contentProperty(), "CONTENT"); //$NON-NLS-1$ - registerChangeListener(control.textProperty(), "TEXT"); //$NON-NLS-1$ - registerChangeListener(control.graphicProperty(), "GRAPHIC"); //$NON-NLS-1$ - registerChangeListener(control.showingProperty(), "SHOWING"); //$NON-NLS-1$ - registerChangeListener(control.showFromTopProperty(), "SHOW_FROM_TOP"); //$NON-NLS-1$ - registerChangeListener(control.closeButtonVisibleProperty(), "CLOSE_BUTTON_VISIBLE"); //$NON-NLS-1$ - - // Fix for Issue #522: Prevent NotificationPane from receiving focus - ParentTraversalEngine engine = new ParentTraversalEngine(getSkinnable()); - getSkinnable().setImpl_traversalEngine(engine); - engine.setOverriddenFocusTraversability(false); - } - - @Override protected void handleControlPropertyChanged(String p) { - super.handleControlPropertyChanged(p); - - if ("CONTENT".equals(p)) { //$NON-NLS-1$ - updateContent(); - } else if ("TEXT".equals(p)) { //$NON-NLS-1$ - notificationBar.label.setText(getSkinnable().getText()); - } else if ("GRAPHIC".equals(p)) { //$NON-NLS-1$ - notificationBar.label.setGraphic(getSkinnable().getGraphic()); - } else if ("SHOWING".equals(p)) { //$NON-NLS-1$ - if (getSkinnable().isShowing()) { - notificationBar.doShow(); - } else { - notificationBar.doHide(); - } - } else if ("SHOW_FROM_TOP".equals(p)) { //$NON-NLS-1$ - if (getSkinnable().isShowing()) { - getSkinnable().requestLayout(); - } - } else if ("CLOSE_BUTTON_VISIBLE".equals(p)) { //$NON-NLS-1$ - notificationBar.updatePane(); - }else if ( "HEIGHT".equals(p)){ - // For resolving https://bitbucket.org/controlsfx/controlsfx/issue/409 - if (getSkinnable().isShowing() && !getSkinnable().isShowFromTop()) { - notificationBar.requestLayout(); - } - } - } - - private void updateContent() { - if (content != null) { - getChildren().remove(content); - } - - content = getSkinnable().getContent(); - - if (content == null) { - getChildren().setAll(notificationBar); - } else { - getChildren().setAll(content, notificationBar); - } - } - - @Override protected void layoutChildren(double x, double y, double w, double h) { - final double notificationBarHeight = notificationBar.prefHeight(w); - - notificationBar.resize(w, notificationBarHeight); - - // layout the content - if (content != null) { - content.resizeRelocate(x, y, w, h); - } - - // and update the clip so that the notification bar does not draw outside - // the bounds of the notification pane - clip.setX(x); - clip.setY(y); - clip.setWidth(w); - clip.setHeight(h); - } - - @Override - protected double computeMinWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) { - return content == null ? 0 : content.minWidth(height); - }; - - @Override - protected double computeMinHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { - return content == null ? 0 : content.minHeight(width); - }; - - @Override - protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) { - return content == null ? 0 : content.prefWidth(height); - }; - - @Override - protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { - return content == null ? 0 : content.prefHeight(width); - }; - - @Override - protected double computeMaxWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) { - return content == null ? 0 : content.maxWidth(height); - }; - - @Override - protected double computeMaxHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { - return content == null ? 0 : content.maxHeight(width); - }; -} diff --git a/src/impl/org/controlsfx/skin/PlusMinusSliderSkin.java b/src/impl/org/controlsfx/skin/PlusMinusSliderSkin.java deleted file mode 100644 index f5bf821..0000000 --- a/src/impl/org/controlsfx/skin/PlusMinusSliderSkin.java +++ /dev/null @@ -1,160 +0,0 @@ -/** - * Copyright (c) 2014, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.skin; - -import static javafx.scene.input.MouseEvent.MOUSE_PRESSED; -import static javafx.scene.input.MouseEvent.MOUSE_RELEASED; -import javafx.animation.AnimationTimer; -import javafx.animation.KeyFrame; -import javafx.animation.KeyValue; -import javafx.animation.Timeline; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.event.EventHandler; -import javafx.geometry.Orientation; -import javafx.scene.control.SkinBase; -import javafx.scene.control.Slider; -import javafx.scene.input.KeyEvent; -import javafx.scene.input.MouseEvent; -import javafx.scene.layout.BorderPane; -import javafx.scene.layout.Region; -import javafx.util.Duration; - -import org.controlsfx.control.PlusMinusSlider; -import org.controlsfx.control.PlusMinusSlider.PlusMinusEvent; - -public class PlusMinusSliderSkin extends SkinBase<PlusMinusSlider> { - - private SliderReader reader; - - private Slider slider; - - private Region plusRegion; - - private Region minusRegion; - - private BorderPane borderPane; - - public PlusMinusSliderSkin(PlusMinusSlider adjuster) { - super(adjuster); - - /* - * We are not supporting any key events, yet. Adding this filter makes - * sure the user doesn't use the standard key bindings of the slider. In - * that case the thumb would not move itself back automatically (e.g. - * after pressing "arrow right"). - */ - adjuster.addEventFilter(KeyEvent.ANY, new EventHandler<KeyEvent>() { - @Override - public void handle(KeyEvent event) { - event.consume(); - } - }); - - slider = new Slider(-1, 1, 0); - - slider.valueProperty().addListener(new ChangeListener<Number>() { - @Override - public void changed(ObservableValue<? extends Number> observable, - Number oldValue, Number newValue) { - getSkinnable().getProperties().put("plusminusslidervalue", //$NON-NLS-1$ - newValue.doubleValue()); - } - }); - - slider.orientationProperty().bind(adjuster.orientationProperty()); - - slider.addEventHandler(MOUSE_PRESSED, new EventHandler<MouseEvent>() { - - @Override - public void handle(MouseEvent evt) { - reader = new SliderReader(); - reader.start(); - } - }); - - slider.addEventHandler(MOUSE_RELEASED, new EventHandler<MouseEvent>() { - - @Override - public void handle(MouseEvent evt) { - if (reader != null) { - reader.stop(); - } - - KeyValue keyValue = new KeyValue(slider.valueProperty(), 0); - KeyFrame keyFrame = new KeyFrame(Duration.millis(100), keyValue); - Timeline timeline = new Timeline(keyFrame); - timeline.play(); - } - }); - - plusRegion = new Region(); - plusRegion.getStyleClass().add("adjust-plus"); //$NON-NLS-1$ - - minusRegion = new Region(); - minusRegion.getStyleClass().add("adjust-minus"); //$NON-NLS-1$ - - borderPane = new BorderPane(); - - updateLayout(adjuster.getOrientation()); - - getChildren().add(borderPane); - - adjuster.orientationProperty().addListener((observable, oldValue, newValue) -> updateLayout(newValue)); - } - - private void updateLayout(Orientation orientation) { - borderPane.getChildren().clear(); - - switch (orientation) { - case HORIZONTAL: - borderPane.setLeft(minusRegion); - borderPane.setCenter(slider); - borderPane.setRight(plusRegion); - break; - case VERTICAL: - borderPane.setTop(plusRegion); - borderPane.setCenter(slider); - borderPane.setBottom(minusRegion); - break; - } - } - - class SliderReader extends AnimationTimer { - private long lastTime = System.currentTimeMillis(); - - @Override - public void handle(long now) { - // max speed: 100 hundred times per second - if (now - lastTime > 10000000) { - lastTime = now; - slider.fireEvent(new PlusMinusEvent(slider, slider, - PlusMinusEvent.VALUE_CHANGED, slider.getValue())); - } - } - } -} diff --git a/src/impl/org/controlsfx/skin/PopOverSkin.java b/src/impl/org/controlsfx/skin/PopOverSkin.java deleted file mode 100644 index 0d18a86..0000000 --- a/src/impl/org/controlsfx/skin/PopOverSkin.java +++ /dev/null @@ -1,717 +0,0 @@ -/** - * Copyright (c) 2013 - 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.skin; - -import static java.lang.Double.MAX_VALUE; -import static javafx.geometry.Pos.CENTER_LEFT; -import static javafx.scene.control.ContentDisplay.GRAPHIC_ONLY; -import static javafx.scene.paint.Color.YELLOW; -import static org.controlsfx.control.PopOver.ArrowLocation.BOTTOM_CENTER; -import static org.controlsfx.control.PopOver.ArrowLocation.BOTTOM_LEFT; -import static org.controlsfx.control.PopOver.ArrowLocation.BOTTOM_RIGHT; -import static org.controlsfx.control.PopOver.ArrowLocation.LEFT_BOTTOM; -import static org.controlsfx.control.PopOver.ArrowLocation.LEFT_CENTER; -import static org.controlsfx.control.PopOver.ArrowLocation.LEFT_TOP; -import static org.controlsfx.control.PopOver.ArrowLocation.RIGHT_BOTTOM; -import static org.controlsfx.control.PopOver.ArrowLocation.RIGHT_CENTER; -import static org.controlsfx.control.PopOver.ArrowLocation.RIGHT_TOP; -import static org.controlsfx.control.PopOver.ArrowLocation.TOP_CENTER; -import static org.controlsfx.control.PopOver.ArrowLocation.TOP_LEFT; -import static org.controlsfx.control.PopOver.ArrowLocation.TOP_RIGHT; - -import java.util.ArrayList; -import java.util.List; - -import org.controlsfx.control.PopOver; -import org.controlsfx.control.PopOver.ArrowLocation; - -import javafx.beans.InvalidationListener; -import javafx.beans.binding.Bindings; -import javafx.beans.property.DoubleProperty; -import javafx.beans.property.SimpleDoubleProperty; -import javafx.event.EventHandler; -import javafx.geometry.Point2D; -import javafx.geometry.Pos; -import javafx.scene.Group; -import javafx.scene.Node; -import javafx.scene.control.Label; -import javafx.scene.control.Skin; -import javafx.scene.input.MouseEvent; -import javafx.scene.layout.BorderPane; -import javafx.scene.layout.StackPane; -import javafx.scene.shape.Circle; -import javafx.scene.shape.HLineTo; -import javafx.scene.shape.Line; -import javafx.scene.shape.LineTo; -import javafx.scene.shape.MoveTo; -import javafx.scene.shape.Path; -import javafx.scene.shape.PathElement; -import javafx.scene.shape.QuadCurveTo; -import javafx.scene.shape.VLineTo; -import javafx.stage.Window; - -public class PopOverSkin implements Skin<PopOver> { - - private static final String DETACHED_STYLE_CLASS = "detached"; //$NON-NLS-1$ - - private double xOffset; - private double yOffset; - - private boolean tornOff; - - private Label title; - private Label closeIcon; - - private Path path; - private Path clip; - - private BorderPane content; - private StackPane titlePane; - private StackPane stackPane; - - private Point2D dragStartLocation; - - private PopOver popOver; - - public PopOverSkin(final PopOver popOver) { - - this.popOver = popOver; - - stackPane = popOver.getRoot(); - stackPane.setPickOnBounds(false); - - Bindings.bindContent(stackPane.getStyleClass(), popOver.getStyleClass()); - - /* - * The min width and height equal 2 * corner radius + 2 * arrow indent + - * 2 * arrow size. - */ - stackPane.minWidthProperty().bind( - Bindings.add(Bindings.multiply(2, popOver.arrowSizeProperty()), - Bindings.add( - Bindings.multiply(2, - popOver.cornerRadiusProperty()), - Bindings.multiply(2, - popOver.arrowIndentProperty())))); - - stackPane.minHeightProperty().bind(stackPane.minWidthProperty()); - - title = new Label(); - title.textProperty().bind(popOver.titleProperty()); - title.setMaxSize(MAX_VALUE, MAX_VALUE); - title.setAlignment(Pos.CENTER); - title.getStyleClass().add("text"); //$NON-NLS-1$ - - closeIcon = new Label(); - closeIcon.setGraphic(createCloseIcon()); - closeIcon.setMaxSize(MAX_VALUE, MAX_VALUE); - closeIcon.setContentDisplay(GRAPHIC_ONLY); - closeIcon.visibleProperty().bind(popOver.detachedProperty().or(popOver.headerAlwaysVisibleProperty())); - closeIcon.getStyleClass().add("icon"); //$NON-NLS-1$ - closeIcon.setAlignment(CENTER_LEFT); - closeIcon.getGraphic().setOnMouseClicked(evt -> popOver.hide()); - - titlePane = new StackPane(); - titlePane.getChildren().add(title); - titlePane.getChildren().add(closeIcon); - titlePane.getStyleClass().add("title"); //$NON-NLS-1$ - - content = new BorderPane(); - content.setCenter(popOver.getContentNode()); - content.getStyleClass().add("content"); //$NON-NLS-1$ - - if (popOver.isDetached() || popOver.isHeaderAlwaysVisible()) { - content.setTop(titlePane); - } - - if (popOver.isDetached()) { - popOver.getStyleClass().add(DETACHED_STYLE_CLASS); - content.getStyleClass().add(DETACHED_STYLE_CLASS); - } - - popOver.headerAlwaysVisibleProperty().addListener((o, oV, isVisible) -> { - if (isVisible) { - content.setTop(titlePane); - } else if (!popOver.isDetached()) { - content.setTop(null); - } - }); - - InvalidationListener updatePathListener = observable -> updatePath(); - getPopupWindow().xProperty().addListener(updatePathListener); - getPopupWindow().yProperty().addListener(updatePathListener); - popOver.arrowLocationProperty().addListener(updatePathListener); - popOver.contentNodeProperty().addListener( - (value, oldContent, newContent) -> content - .setCenter(newContent)); - popOver.detachedProperty() - .addListener((value, oldDetached, newDetached) -> { - - if (newDetached) { - popOver.getStyleClass().add(DETACHED_STYLE_CLASS); - content.getStyleClass().add(DETACHED_STYLE_CLASS); - content.setTop(titlePane); - - switch (getSkinnable().getArrowLocation()) { - case LEFT_TOP: - case LEFT_CENTER: - case LEFT_BOTTOM: - popOver.setAnchorX( - popOver.getAnchorX() + popOver.getArrowSize()); - break; - case TOP_LEFT: - case TOP_CENTER: - case TOP_RIGHT: - popOver.setAnchorY( - popOver.getAnchorY() + popOver.getArrowSize()); - break; - default: - break; - } - } else { - popOver.getStyleClass().remove(DETACHED_STYLE_CLASS); - content.getStyleClass().remove(DETACHED_STYLE_CLASS); - - if (!popOver.isHeaderAlwaysVisible()) { - content.setTop(null); - } - } - - popOver.sizeToScene(); - - updatePath(); - }); - - path = new Path(); - path.getStyleClass().add("border"); //$NON-NLS-1$ - path.setManaged(false); - - clip = new Path(); - - /* - * The clip is a path and the path has to be filled with a color. - * Otherwise clipping will not work. - */ - clip.setFill(YELLOW); - - createPathElements(); - updatePath(); - - final EventHandler<MouseEvent> mousePressedHandler = evt -> { - if (popOver.isDetachable() || popOver.isDetached()) { - tornOff = false; - - xOffset = evt.getScreenX(); - yOffset = evt.getScreenY(); - - dragStartLocation = new Point2D(xOffset, yOffset); - } - }; - - final EventHandler<MouseEvent> mouseReleasedHandler = evt -> { - if (tornOff && !getSkinnable().isDetached()) { - tornOff = false; - getSkinnable().detach(); - } - }; - - final EventHandler<MouseEvent> mouseDragHandler = evt -> { - if (popOver.isDetachable() || popOver.isDetached()) { - double deltaX = evt.getScreenX() - xOffset; - double deltaY = evt.getScreenY() - yOffset; - - Window window = getSkinnable().getScene().getWindow(); - - window.setX(window.getX() + deltaX); - window.setY(window.getY() + deltaY); - - xOffset = evt.getScreenX(); - yOffset = evt.getScreenY(); - - if (dragStartLocation.distance(xOffset, yOffset) > 20) { - tornOff = true; - updatePath(); - } else if (tornOff) { - tornOff = false; - updatePath(); - } - } - }; - - stackPane.setOnMousePressed(mousePressedHandler); - stackPane.setOnMouseDragged(mouseDragHandler); - stackPane.setOnMouseReleased(mouseReleasedHandler); - - stackPane.getChildren().add(path); - stackPane.getChildren().add(content); - - content.setClip(clip); - } - - @Override - public Node getNode() { - return stackPane; - } - - @Override - public PopOver getSkinnable() { - return popOver; - } - - @Override - public void dispose() { - } - - private Node createCloseIcon() { - Group group = new Group(); - group.getStyleClass().add("graphics"); //$NON-NLS-1$ - - Circle circle = new Circle(); - circle.getStyleClass().add("circle"); //$NON-NLS-1$ - circle.setRadius(6); - circle.setCenterX(6); - circle.setCenterY(6); - group.getChildren().add(circle); - - Line line1 = new Line(); - line1.getStyleClass().add("line"); //$NON-NLS-1$ - line1.setStartX(4); - line1.setStartY(4); - line1.setEndX(8); - line1.setEndY(8); - group.getChildren().add(line1); - - Line line2 = new Line(); - line2.getStyleClass().add("line"); //$NON-NLS-1$ - line2.setStartX(8); - line2.setStartY(4); - line2.setEndX(4); - line2.setEndY(8); - group.getChildren().add(line2); - - return group; - } - - private MoveTo moveTo; - - private QuadCurveTo topCurveTo, rightCurveTo, bottomCurveTo, leftCurveTo; - - private HLineTo lineBTop, lineETop, lineHTop, lineKTop; - private LineTo lineCTop, lineDTop, lineFTop, lineGTop, lineITop, lineJTop; - - private VLineTo lineBRight, lineERight, lineHRight, lineKRight; - private LineTo lineCRight, lineDRight, lineFRight, lineGRight, lineIRight, - lineJRight; - - private HLineTo lineBBottom, lineEBottom, lineHBottom, lineKBottom; - private LineTo lineCBottom, lineDBottom, lineFBottom, lineGBottom, - lineIBottom, lineJBottom; - - private VLineTo lineBLeft, lineELeft, lineHLeft, lineKLeft; - private LineTo lineCLeft, lineDLeft, lineFLeft, lineGLeft, lineILeft, - lineJLeft; - - private void createPathElements() { - DoubleProperty centerYProperty = new SimpleDoubleProperty(); - DoubleProperty centerXProperty = new SimpleDoubleProperty(); - - DoubleProperty leftEdgeProperty = new SimpleDoubleProperty(); - DoubleProperty leftEdgePlusRadiusProperty = new SimpleDoubleProperty(); - - DoubleProperty topEdgeProperty = new SimpleDoubleProperty(); - DoubleProperty topEdgePlusRadiusProperty = new SimpleDoubleProperty(); - - DoubleProperty rightEdgeProperty = new SimpleDoubleProperty(); - DoubleProperty rightEdgeMinusRadiusProperty = new SimpleDoubleProperty(); - - DoubleProperty bottomEdgeProperty = new SimpleDoubleProperty(); - DoubleProperty bottomEdgeMinusRadiusProperty = new SimpleDoubleProperty(); - - DoubleProperty cornerProperty = getSkinnable().cornerRadiusProperty(); - - DoubleProperty arrowSizeProperty = getSkinnable().arrowSizeProperty(); - DoubleProperty arrowIndentProperty = getSkinnable() - .arrowIndentProperty(); - - centerYProperty.bind(Bindings.divide(stackPane.heightProperty(), 2)); - centerXProperty.bind(Bindings.divide(stackPane.widthProperty(), 2)); - - leftEdgePlusRadiusProperty.bind(Bindings.add(leftEdgeProperty, - getSkinnable().cornerRadiusProperty())); - - topEdgePlusRadiusProperty.bind(Bindings.add(topEdgeProperty, - getSkinnable().cornerRadiusProperty())); - - rightEdgeProperty.bind(stackPane.widthProperty()); - rightEdgeMinusRadiusProperty.bind(Bindings.subtract(rightEdgeProperty, - getSkinnable().cornerRadiusProperty())); - - bottomEdgeProperty.bind(stackPane.heightProperty()); - bottomEdgeMinusRadiusProperty.bind(Bindings.subtract( - bottomEdgeProperty, getSkinnable().cornerRadiusProperty())); - - // INIT - moveTo = new MoveTo(); - moveTo.xProperty().bind(leftEdgePlusRadiusProperty); - moveTo.yProperty().bind(topEdgeProperty); - - // - // TOP EDGE - // - lineBTop = new HLineTo(); - lineBTop.xProperty().bind( - Bindings.add(leftEdgePlusRadiusProperty, arrowIndentProperty)); - - lineCTop = new LineTo(); - lineCTop.xProperty().bind( - Bindings.add(lineBTop.xProperty(), arrowSizeProperty)); - lineCTop.yProperty().bind( - Bindings.subtract(topEdgeProperty, arrowSizeProperty)); - - lineDTop = new LineTo(); - lineDTop.xProperty().bind( - Bindings.add(lineCTop.xProperty(), arrowSizeProperty)); - lineDTop.yProperty().bind(topEdgeProperty); - - lineETop = new HLineTo(); - lineETop.xProperty().bind( - Bindings.subtract(centerXProperty, arrowSizeProperty)); - - lineFTop = new LineTo(); - lineFTop.xProperty().bind(centerXProperty); - lineFTop.yProperty().bind( - Bindings.subtract(topEdgeProperty, arrowSizeProperty)); - - lineGTop = new LineTo(); - lineGTop.xProperty().bind( - Bindings.add(centerXProperty, arrowSizeProperty)); - lineGTop.yProperty().bind(topEdgeProperty); - - lineHTop = new HLineTo(); - lineHTop.xProperty().bind( - Bindings.subtract(Bindings.subtract( - rightEdgeMinusRadiusProperty, arrowIndentProperty), - Bindings.multiply(arrowSizeProperty, 2))); - - lineITop = new LineTo(); - lineITop.xProperty().bind( - Bindings.subtract(Bindings.subtract( - rightEdgeMinusRadiusProperty, arrowIndentProperty), - arrowSizeProperty)); - lineITop.yProperty().bind( - Bindings.subtract(topEdgeProperty, arrowSizeProperty)); - - lineJTop = new LineTo(); - lineJTop.xProperty().bind( - Bindings.subtract(rightEdgeMinusRadiusProperty, - arrowIndentProperty)); - lineJTop.yProperty().bind(topEdgeProperty); - - lineKTop = new HLineTo(); - lineKTop.xProperty().bind(rightEdgeMinusRadiusProperty); - - // - // RIGHT EDGE - // - rightCurveTo = new QuadCurveTo(); - rightCurveTo.xProperty().bind(rightEdgeProperty); - rightCurveTo.yProperty().bind( - Bindings.add(topEdgeProperty, cornerProperty)); - rightCurveTo.controlXProperty().bind(rightEdgeProperty); - rightCurveTo.controlYProperty().bind(topEdgeProperty); - - lineBRight = new VLineTo(); - lineBRight.yProperty().bind( - Bindings.add(topEdgePlusRadiusProperty, arrowIndentProperty)); - - lineCRight = new LineTo(); - lineCRight.xProperty().bind( - Bindings.add(rightEdgeProperty, arrowSizeProperty)); - lineCRight.yProperty().bind( - Bindings.add(lineBRight.yProperty(), arrowSizeProperty)); - - lineDRight = new LineTo(); - lineDRight.xProperty().bind(rightEdgeProperty); - lineDRight.yProperty().bind( - Bindings.add(lineCRight.yProperty(), arrowSizeProperty)); - - lineERight = new VLineTo(); - lineERight.yProperty().bind( - Bindings.subtract(centerYProperty, arrowSizeProperty)); - - lineFRight = new LineTo(); - lineFRight.xProperty().bind( - Bindings.add(rightEdgeProperty, arrowSizeProperty)); - lineFRight.yProperty().bind(centerYProperty); - - lineGRight = new LineTo(); - lineGRight.xProperty().bind(rightEdgeProperty); - lineGRight.yProperty().bind( - Bindings.add(centerYProperty, arrowSizeProperty)); - - lineHRight = new VLineTo(); - lineHRight.yProperty().bind( - Bindings.subtract(Bindings.subtract( - bottomEdgeMinusRadiusProperty, arrowIndentProperty), - Bindings.multiply(arrowSizeProperty, 2))); - - lineIRight = new LineTo(); - lineIRight.xProperty().bind( - Bindings.add(rightEdgeProperty, arrowSizeProperty)); - lineIRight.yProperty().bind( - Bindings.subtract(Bindings.subtract( - bottomEdgeMinusRadiusProperty, arrowIndentProperty), - arrowSizeProperty)); - - lineJRight = new LineTo(); - lineJRight.xProperty().bind(rightEdgeProperty); - lineJRight.yProperty().bind( - Bindings.subtract(bottomEdgeMinusRadiusProperty, - arrowIndentProperty)); - - lineKRight = new VLineTo(); - lineKRight.yProperty().bind(bottomEdgeMinusRadiusProperty); - - // - // BOTTOM EDGE - // - - bottomCurveTo = new QuadCurveTo(); - bottomCurveTo.xProperty().bind(rightEdgeMinusRadiusProperty); - bottomCurveTo.yProperty().bind(bottomEdgeProperty); - bottomCurveTo.controlXProperty().bind(rightEdgeProperty); - bottomCurveTo.controlYProperty().bind(bottomEdgeProperty); - - lineBBottom = new HLineTo(); - lineBBottom.xProperty().bind( - Bindings.subtract(rightEdgeMinusRadiusProperty, - arrowIndentProperty)); - - lineCBottom = new LineTo(); - lineCBottom.xProperty().bind( - Bindings.subtract(lineBBottom.xProperty(), arrowSizeProperty)); - lineCBottom.yProperty().bind( - Bindings.add(bottomEdgeProperty, arrowSizeProperty)); - - lineDBottom = new LineTo(); - lineDBottom.xProperty().bind( - Bindings.subtract(lineCBottom.xProperty(), arrowSizeProperty)); - lineDBottom.yProperty().bind(bottomEdgeProperty); - - lineEBottom = new HLineTo(); - lineEBottom.xProperty().bind( - Bindings.add(centerXProperty, arrowSizeProperty)); - - lineFBottom = new LineTo(); - lineFBottom.xProperty().bind(centerXProperty); - lineFBottom.yProperty().bind( - Bindings.add(bottomEdgeProperty, arrowSizeProperty)); - - lineGBottom = new LineTo(); - lineGBottom.xProperty().bind( - Bindings.subtract(centerXProperty, arrowSizeProperty)); - lineGBottom.yProperty().bind(bottomEdgeProperty); - - lineHBottom = new HLineTo(); - lineHBottom.xProperty().bind( - Bindings.add(Bindings.add(leftEdgePlusRadiusProperty, - arrowIndentProperty), Bindings.multiply( - arrowSizeProperty, 2))); - - lineIBottom = new LineTo(); - lineIBottom.xProperty().bind( - Bindings.add(Bindings.add(leftEdgePlusRadiusProperty, - arrowIndentProperty), arrowSizeProperty)); - lineIBottom.yProperty().bind( - Bindings.add(bottomEdgeProperty, arrowSizeProperty)); - - lineJBottom = new LineTo(); - lineJBottom.xProperty().bind( - Bindings.add(leftEdgePlusRadiusProperty, arrowIndentProperty)); - lineJBottom.yProperty().bind(bottomEdgeProperty); - - lineKBottom = new HLineTo(); - lineKBottom.xProperty().bind(leftEdgePlusRadiusProperty); - - // - // LEFT EDGE - // - leftCurveTo = new QuadCurveTo(); - leftCurveTo.xProperty().bind(leftEdgeProperty); - leftCurveTo.yProperty().bind( - Bindings.subtract(bottomEdgeProperty, cornerProperty)); - leftCurveTo.controlXProperty().bind(leftEdgeProperty); - leftCurveTo.controlYProperty().bind(bottomEdgeProperty); - - lineBLeft = new VLineTo(); - lineBLeft.yProperty().bind( - Bindings.subtract(bottomEdgeMinusRadiusProperty, - arrowIndentProperty)); - - lineCLeft = new LineTo(); - lineCLeft.xProperty().bind( - Bindings.subtract(leftEdgeProperty, arrowSizeProperty)); - lineCLeft.yProperty().bind( - Bindings.subtract(lineBLeft.yProperty(), arrowSizeProperty)); - - lineDLeft = new LineTo(); - lineDLeft.xProperty().bind(leftEdgeProperty); - lineDLeft.yProperty().bind( - Bindings.subtract(lineCLeft.yProperty(), arrowSizeProperty)); - - lineELeft = new VLineTo(); - lineELeft.yProperty().bind( - Bindings.add(centerYProperty, arrowSizeProperty)); - - lineFLeft = new LineTo(); - lineFLeft.xProperty().bind( - Bindings.subtract(leftEdgeProperty, arrowSizeProperty)); - lineFLeft.yProperty().bind(centerYProperty); - - lineGLeft = new LineTo(); - lineGLeft.xProperty().bind(leftEdgeProperty); - lineGLeft.yProperty().bind( - Bindings.subtract(centerYProperty, arrowSizeProperty)); - - lineHLeft = new VLineTo(); - lineHLeft.yProperty().bind( - Bindings.add(Bindings.add(topEdgePlusRadiusProperty, - arrowIndentProperty), Bindings.multiply( - arrowSizeProperty, 2))); - - lineILeft = new LineTo(); - lineILeft.xProperty().bind( - Bindings.subtract(leftEdgeProperty, arrowSizeProperty)); - lineILeft.yProperty().bind( - Bindings.add(Bindings.add(topEdgePlusRadiusProperty, - arrowIndentProperty), arrowSizeProperty)); - - lineJLeft = new LineTo(); - lineJLeft.xProperty().bind(leftEdgeProperty); - lineJLeft.yProperty().bind( - Bindings.add(topEdgePlusRadiusProperty, arrowIndentProperty)); - - lineKLeft = new VLineTo(); - lineKLeft.yProperty().bind(topEdgePlusRadiusProperty); - - topCurveTo = new QuadCurveTo(); - topCurveTo.xProperty().bind(leftEdgePlusRadiusProperty); - topCurveTo.yProperty().bind(topEdgeProperty); - topCurveTo.controlXProperty().bind(leftEdgeProperty); - topCurveTo.controlYProperty().bind(topEdgeProperty); - } - - private Window getPopupWindow() { - return getSkinnable().getScene().getWindow(); - } - - private boolean showArrow(ArrowLocation location) { - ArrowLocation arrowLocation = getSkinnable().getArrowLocation(); - return location.equals(arrowLocation) && !getSkinnable().isDetached() - && !tornOff; - } - - private void updatePath() { - List<PathElement> elements = new ArrayList<>(); - elements.add(moveTo); - - if (showArrow(TOP_LEFT)) { - elements.add(lineBTop); - elements.add(lineCTop); - elements.add(lineDTop); - } - if (showArrow(TOP_CENTER)) { - elements.add(lineETop); - elements.add(lineFTop); - elements.add(lineGTop); - } - if (showArrow(TOP_RIGHT)) { - elements.add(lineHTop); - elements.add(lineITop); - elements.add(lineJTop); - } - elements.add(lineKTop); - elements.add(rightCurveTo); - - if (showArrow(RIGHT_TOP)) { - elements.add(lineBRight); - elements.add(lineCRight); - elements.add(lineDRight); - } - if (showArrow(RIGHT_CENTER)) { - elements.add(lineERight); - elements.add(lineFRight); - elements.add(lineGRight); - } - if (showArrow(RIGHT_BOTTOM)) { - elements.add(lineHRight); - elements.add(lineIRight); - elements.add(lineJRight); - } - elements.add(lineKRight); - elements.add(bottomCurveTo); - - if (showArrow(BOTTOM_RIGHT)) { - elements.add(lineBBottom); - elements.add(lineCBottom); - elements.add(lineDBottom); - } - if (showArrow(BOTTOM_CENTER)) { - elements.add(lineEBottom); - elements.add(lineFBottom); - elements.add(lineGBottom); - } - if (showArrow(BOTTOM_LEFT)) { - elements.add(lineHBottom); - elements.add(lineIBottom); - elements.add(lineJBottom); - } - elements.add(lineKBottom); - elements.add(leftCurveTo); - - if (showArrow(LEFT_BOTTOM)) { - elements.add(lineBLeft); - elements.add(lineCLeft); - elements.add(lineDLeft); - } - if (showArrow(LEFT_CENTER)) { - elements.add(lineELeft); - elements.add(lineFLeft); - elements.add(lineGLeft); - } - if (showArrow(LEFT_TOP)) { - elements.add(lineHLeft); - elements.add(lineILeft); - elements.add(lineJLeft); - } - elements.add(lineKLeft); - elements.add(topCurveTo); - - path.getElements().setAll(elements); - clip.getElements().setAll(elements); - } -} diff --git a/src/impl/org/controlsfx/skin/PropertySheetSkin.java b/src/impl/org/controlsfx/skin/PropertySheetSkin.java deleted file mode 100644 index f050288..0000000 --- a/src/impl/org/controlsfx/skin/PropertySheetSkin.java +++ /dev/null @@ -1,350 +0,0 @@ -/** - * Copyright (c) 2013, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.skin; - -import static impl.org.controlsfx.i18n.Localization.asKey; -import static impl.org.controlsfx.i18n.Localization.localize; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; - -import javafx.beans.value.ObservableValue; -import javafx.collections.ListChangeListener; -import javafx.geometry.Insets; -import javafx.scene.Node; -import javafx.scene.control.Accordion; -import javafx.scene.control.Label; -import javafx.scene.control.ScrollPane; -import javafx.scene.control.TextField; -import javafx.scene.control.TitledPane; -import javafx.scene.control.ToolBar; -import javafx.scene.control.Tooltip; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import javafx.scene.layout.BorderPane; -import javafx.scene.layout.GridPane; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Priority; -import javafx.scene.layout.Region; - -import org.controlsfx.control.PropertySheet; -import org.controlsfx.control.PropertySheet.Item; -import org.controlsfx.control.PropertySheet.Mode; -import org.controlsfx.control.SegmentedButton; -import org.controlsfx.control.action.Action; -import org.controlsfx.control.action.ActionUtils; -import org.controlsfx.control.textfield.TextFields; -import org.controlsfx.property.editor.AbstractPropertyEditor; -import org.controlsfx.property.editor.PropertyEditor; - -import com.sun.javafx.scene.control.behavior.BehaviorBase; -import com.sun.javafx.scene.control.behavior.KeyBinding; -import com.sun.javafx.scene.control.skin.BehaviorSkinBase; - -public class PropertySheetSkin extends BehaviorSkinBase<PropertySheet, BehaviorBase<PropertySheet>> { - - /************************************************************************** - * - * Static fields - * - **************************************************************************/ - - private static final int MIN_COLUMN_WIDTH = 100; - - /************************************************************************** - * - * fields - * - **************************************************************************/ - - private final BorderPane content; - private final ScrollPane scroller; - private final ToolBar toolbar; - private final SegmentedButton modeButton = ActionUtils.createSegmentedButton( - new ActionChangeMode(Mode.NAME), - new ActionChangeMode(Mode.CATEGORY) - ); - private final TextField searchField = TextFields.createClearableTextField(); - - - /************************************************************************** - * - * Constructors - * - **************************************************************************/ - - public PropertySheetSkin(final PropertySheet control) { - super(control, new BehaviorBase<>(control, Collections.<KeyBinding> emptyList())); - - scroller = new ScrollPane(); - scroller.setFitToWidth(true); - - toolbar = new ToolBar(); - toolbar.managedProperty().bind(toolbar.visibleProperty()); - toolbar.setFocusTraversable(true); - - // property sheet mode - modeButton.managedProperty().bind(modeButton.visibleProperty()); - modeButton.getButtons().get(getSkinnable().modeProperty().get().ordinal()).setSelected(true); - toolbar.getItems().add(modeButton); - - // property sheet search - searchField.setPromptText( localize(asKey("property.sheet.search.field.prompt"))); //$NON-NLS-1$ - searchField.setMinWidth(0); - HBox.setHgrow(searchField, Priority.SOMETIMES); - searchField.managedProperty().bind(searchField.visibleProperty()); - toolbar.getItems().add(searchField); - - // layout controls - content = new BorderPane(); - content.setTop(toolbar); - content.setCenter(scroller); - getChildren().add(content); - - - // setup listeners - registerChangeListener(control.modeProperty(), "MODE"); //$NON-NLS-1$ - registerChangeListener(control.propertyEditorFactory(), "EDITOR-FACTORY"); //$NON-NLS-1$ - registerChangeListener(control.titleFilter(), "FILTER"); //$NON-NLS-1$ - registerChangeListener(searchField.textProperty(), "FILTER-UI"); //$NON-NLS-1$ - registerChangeListener(control.modeSwitcherVisibleProperty(), "TOOLBAR-MODE"); //$NON-NLS-1$ - registerChangeListener(control.searchBoxVisibleProperty(), "TOOLBAR-SEARCH"); //$NON-NLS-1$ - - control.getItems().addListener((ListChangeListener<Item>) change -> refreshProperties()); - - // initialize properly - refreshProperties(); - updateToolbar(); - } - - - /************************************************************************** - * - * Overriding public API - * - **************************************************************************/ - - @Override protected void handleControlPropertyChanged(String p) { - super.handleControlPropertyChanged(p); - - if (p == "MODE" || p == "EDITOR-FACTORY" || p == "FILTER") { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - refreshProperties(); - } else if (p == "FILTER-UI") { //$NON-NLS-1$ - getSkinnable().setTitleFilter(searchField.getText()); - } else if (p == "TOOLBAR-MODE") { //$NON-NLS-1$ - updateToolbar(); - } else if (p == "TOOLBAR-SEARCH") { //$NON-NLS-1$ - updateToolbar(); - } - } - - @Override protected void layoutChildren(double x, double y, double w, double h) { - content.resizeRelocate(x, y, w, h); - } - - - - /************************************************************************** - * - * Implementation - * - **************************************************************************/ - - private void updateToolbar() { - modeButton.setVisible(getSkinnable().isModeSwitcherVisible()); - searchField.setVisible(getSkinnable().isSearchBoxVisible()); - - toolbar.setVisible(modeButton.isVisible() || searchField.isVisible()); - } - - private void refreshProperties() { - scroller.setContent(buildPropertySheetContainer()); - } - - private Node buildPropertySheetContainer() { - switch( getSkinnable().modeProperty().get() ) { - case CATEGORY: { - // group by category - Map<String, List<Item>> categoryMap = new TreeMap<>(); - for( Item p: getSkinnable().getItems()) { - String category = p.getCategory(); - List<Item> list = categoryMap.get(category); - if ( list == null ) { - list = new ArrayList<>(); - categoryMap.put( category, list); - } - list.add(p); - } - - // create category-based accordion - Accordion accordion = new Accordion(); - for( String category: categoryMap.keySet() ) { - PropertyPane props = new PropertyPane( categoryMap.get(category)); - // Only show non-empty categories - if ( props.getChildrenUnmodifiable().size() > 0 ) { - TitledPane pane = new TitledPane( category, props ); - pane.setExpanded(true); - accordion.getPanes().add(pane); - } - } - if ( accordion.getPanes().size() > 0 ) { - accordion.setExpandedPane(accordion.getPanes().get(0)); - } - return accordion; - } - - default: return new PropertyPane(getSkinnable().getItems()); - } - - } - - - /************************************************************************** - * - * Support classes / enums - * - **************************************************************************/ - - private class ActionChangeMode extends Action { - - private final Image CATEGORY_IMAGE = new Image(PropertySheetSkin.class.getResource("/org/controlsfx/control/format-indent-more.png").toExternalForm()); //$NON-NLS-1$ - private final Image NAME_IMAGE = new Image(PropertySheetSkin.class.getResource("/org/controlsfx/control/format-line-spacing-triple.png").toExternalForm()); //$NON-NLS-1$ - - public ActionChangeMode(PropertySheet.Mode mode) { - super(""); //$NON-NLS-1$ - setEventHandler(ae -> getSkinnable().modeProperty().set(mode)); - - if (mode == Mode.CATEGORY) { - setGraphic( new ImageView(CATEGORY_IMAGE)); - setLongText(localize(asKey("property.sheet.group.mode.bycategory"))); //$NON-NLS-1$ - } else if (mode == Mode.NAME) { - setGraphic(new ImageView(NAME_IMAGE)); - setLongText(localize(asKey("property.sheet.group.mode.byname"))); //$NON-NLS-1$ - } else { - setText("???"); //$NON-NLS-1$ - } - } - - } - - - private class PropertyPane extends GridPane { - - public PropertyPane( List<Item> properties ) { - this( properties, 0 ); - } - - public PropertyPane( List<Item> properties, int nestingLevel ) { - setVgap(5); - setHgap(5); - setPadding(new Insets(5, 15, 5, 15 + nestingLevel*10 )); - getStyleClass().add("property-pane"); //$NON-NLS-1$ - setItems(properties); -// setGridLinesVisible(true); - } - - public void setItems( List<Item> properties ) { - getChildren().clear(); - - String filter = getSkinnable().titleFilter().get(); - filter = filter == null? "": filter.trim().toLowerCase(); //$NON-NLS-1$ - - int row = 0; - - for (Item item : properties) { - - // filter properties - String title = item.getName(); - - if ( !filter.isEmpty() && title.toLowerCase().indexOf( filter ) < 0) continue; - - // setup property label - Label label = new Label(title); - label.setMinWidth(MIN_COLUMN_WIDTH); - - // show description as a tooltip - String description = item.getDescription(); - if ( description != null && !description.trim().isEmpty()) { - label.setTooltip(new Tooltip(description)); - } - - add(label, 0, row); - - // setup property editor - Node editor = getEditor(item); - - if (editor instanceof Region) { - ((Region)editor).setMinWidth(MIN_COLUMN_WIDTH); - ((Region)editor).setMaxWidth(Double.MAX_VALUE); - } - label.setLabelFor(editor); - add(editor, 1, row); - GridPane.setHgrow(editor, Priority.ALWAYS); - - //TODO add support for recursive properties - - row++; - } - - } - - @SuppressWarnings("unchecked") - private Node getEditor(Item item) { - @SuppressWarnings("rawtypes") - PropertyEditor editor = getSkinnable().getPropertyEditorFactory().call(item); - if (editor == null) { - editor = new AbstractPropertyEditor<Object, TextField>(item, new TextField(), true) { - { - getEditor().setEditable(false); - getEditor().setDisable(true); - } - - /** - * {@inheritDoc} - */ - @Override protected ObservableValue<Object> getObservableValue() { - return (ObservableValue<Object>)(Object)getEditor().textProperty(); - } - - /** - * {@inheritDoc} - */ - @Override public void setValue(Object value) { - getEditor().setText(value == null? "": value.toString()); //$NON-NLS-1$ - } - }; - } else if (! item.isEditable()) { - editor.getEditor().setDisable(true); - } - editor.setValue(item.getValue()); - return editor.getEditor(); - } - } -} diff --git a/src/impl/org/controlsfx/skin/RangeSliderSkin.java b/src/impl/org/controlsfx/skin/RangeSliderSkin.java deleted file mode 100644 index 2b32492..0000000 --- a/src/impl/org/controlsfx/skin/RangeSliderSkin.java +++ /dev/null @@ -1,580 +0,0 @@ -/** - * Copyright (c) 2013, 2016 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.skin; - -import static impl.org.controlsfx.behavior.RangeSliderBehavior.FocusedChild.HIGH_THUMB; -import static impl.org.controlsfx.behavior.RangeSliderBehavior.FocusedChild.LOW_THUMB; -import static impl.org.controlsfx.behavior.RangeSliderBehavior.FocusedChild.NONE; -import static impl.org.controlsfx.behavior.RangeSliderBehavior.FocusedChild.RANGE_BAR; -import impl.org.controlsfx.behavior.RangeSliderBehavior; -import impl.org.controlsfx.behavior.RangeSliderBehavior.FocusedChild; -import javafx.beans.binding.ObjectBinding; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.event.EventHandler; -import javafx.geometry.Orientation; -import javafx.geometry.Point2D; -import javafx.geometry.Side; -import javafx.scene.Cursor; -import javafx.scene.chart.NumberAxis; -import javafx.scene.input.KeyCode; -import javafx.scene.input.KeyEvent; -import javafx.scene.input.MouseEvent; -import javafx.scene.layout.StackPane; -import javafx.util.Callback; - -import org.controlsfx.control.RangeSlider; - -import com.sun.javafx.scene.control.skin.BehaviorSkinBase; -import com.sun.javafx.scene.traversal.Direction; -import com.sun.javafx.scene.traversal.ParentTraversalEngine; - -public class RangeSliderSkin extends BehaviorSkinBase<RangeSlider, RangeSliderBehavior> { - - /** Track if slider is vertical/horizontal and cause re layout */ - private NumberAxis tickLine = null; - private double trackToTickGap = 2; - - private boolean showTickMarks; - private double thumbWidth; - private double thumbHeight; - - private Orientation orientation; - - private StackPane track; - private double trackStart; - private double trackLength; - private double lowThumbPos; - private double rangeEnd; - private double rangeStart; - private ThumbPane lowThumb; - private ThumbPane highThumb; - private StackPane rangeBar; // the bar between the two thumbs, can be dragged - - // temp fields for mouse drag handling - private double preDragPos; // used as a temp value for low and high thumbs - private Point2D preDragThumbPoint; // in skin coordinates - - private FocusedChild currentFocus = LOW_THUMB; - - public RangeSliderSkin(final RangeSlider rangeSlider) { - super(rangeSlider, new RangeSliderBehavior(rangeSlider)); - orientation = getSkinnable().getOrientation(); - initFirstThumb(); - initSecondThumb(); - initRangeBar(); - registerChangeListener(rangeSlider.lowValueProperty(), "LOW_VALUE"); //$NON-NLS-1$ - registerChangeListener(rangeSlider.highValueProperty(), "HIGH_VALUE"); //$NON-NLS-1$ - registerChangeListener(rangeSlider.minProperty(), "MIN"); //$NON-NLS-1$ - registerChangeListener(rangeSlider.maxProperty(), "MAX"); //$NON-NLS-1$ - registerChangeListener(rangeSlider.orientationProperty(), "ORIENTATION"); //$NON-NLS-1$ - registerChangeListener(rangeSlider.showTickMarksProperty(), "SHOW_TICK_MARKS"); //$NON-NLS-1$ - registerChangeListener(rangeSlider.showTickLabelsProperty(), "SHOW_TICK_LABELS"); //$NON-NLS-1$ - registerChangeListener(rangeSlider.majorTickUnitProperty(), "MAJOR_TICK_UNIT"); //$NON-NLS-1$ - registerChangeListener(rangeSlider.minorTickCountProperty(), "MINOR_TICK_COUNT"); //$NON-NLS-1$ - lowThumb.focusedProperty().addListener(new ChangeListener<Boolean>() { - @Override public void changed(ObservableValue<? extends Boolean> ov, Boolean t, Boolean hasFocus) { - if (hasFocus) { - currentFocus = LOW_THUMB; - } - } - }); - highThumb.focusedProperty().addListener(new ChangeListener<Boolean>() { - @Override public void changed(ObservableValue<? extends Boolean> ov, Boolean t, Boolean hasFocus) { - if (hasFocus) { - currentFocus = HIGH_THUMB; - } - } - }); - rangeBar.focusedProperty().addListener(new ChangeListener<Boolean>() { - @Override public void changed(ObservableValue<? extends Boolean> ov, Boolean t, Boolean hasFocus) { - if (hasFocus) { - currentFocus = RANGE_BAR; - } - } - }); - rangeSlider.focusedProperty().addListener(new ChangeListener<Boolean>() { - @Override public void changed(ObservableValue<? extends Boolean> ov, Boolean t, Boolean hasFocus) { - if (hasFocus) { - lowThumb.setFocus(true); - } else { - lowThumb.setFocus(false); - highThumb.setFocus(false); - currentFocus = NONE; - } - } - }); - - EventHandler<KeyEvent> keyEventHandler = new EventHandler<KeyEvent>() { - @Override public void handle(KeyEvent event) { - if (KeyCode.TAB.equals(event.getCode())) { - if (lowThumb.isFocused()) { - if (event.isShiftDown()) { - lowThumb.setFocus(false); - new ParentTraversalEngine(rangeSlider).select(rangeSlider, Direction.PREVIOUS); - } else { - lowThumb.setFocus(false); - highThumb.setFocus(true); - } - event.consume(); - } else if (highThumb.isFocused()) { - if(event.isShiftDown()) { - highThumb.setFocus(false); - lowThumb.setFocus(true); - } else { - highThumb.setFocus(false); - new ParentTraversalEngine(rangeSlider).select(rangeSlider, Direction.NEXT); - } - event.consume(); - } - } - } - }; - getSkinnable().addEventHandler(KeyEvent.KEY_PRESSED, keyEventHandler); - // set up a callback on the behavior to indicate which thumb is currently - // selected (via enum). - getBehavior().setSelectedValue(new Callback<Void, FocusedChild>() { - @Override public FocusedChild call(Void v) { - return currentFocus; - } - }); - } - - private void initFirstThumb() { - lowThumb = new ThumbPane(); - lowThumb.getStyleClass().setAll("low-thumb"); //$NON-NLS-1$ - lowThumb.setFocusTraversable(true); - track = new StackPane(); - track.getStyleClass().setAll("track"); //$NON-NLS-1$ - - getChildren().clear(); - getChildren().addAll(track, lowThumb); - setShowTickMarks(getSkinnable().isShowTickMarks(), getSkinnable().isShowTickLabels()); - track.setOnMousePressed( new EventHandler<javafx.scene.input.MouseEvent>() { - @Override public void handle(javafx.scene.input.MouseEvent me) { - if (!lowThumb.isPressed() && !highThumb.isPressed()) { - if (isHorizontal()) { - getBehavior().trackPress(me, (me.getX() / trackLength)); - } else { - getBehavior().trackPress(me, (me.getY() / trackLength)); - } - } - } - }); - - track.setOnMouseReleased( new EventHandler<javafx.scene.input.MouseEvent>() { - @Override public void handle(javafx.scene.input.MouseEvent me) { - //Nothing being done with the second param in sliderBehavior - //So, passing a dummy value - getBehavior().trackRelease(me, 0.0f); - } - }); - - lowThumb.setOnMousePressed(new EventHandler<javafx.scene.input.MouseEvent>() { - @Override public void handle(javafx.scene.input.MouseEvent me) { - highThumb.setFocus(false); - lowThumb.setFocus(true); - getBehavior().lowThumbPressed(me, 0.0f); - preDragThumbPoint = lowThumb.localToParent(me.getX(), me.getY()); - preDragPos = (getSkinnable().getLowValue() - getSkinnable().getMin()) / - (getMaxMinusMinNoZero()); - } - }); - - lowThumb.setOnMouseReleased(new EventHandler<javafx.scene.input.MouseEvent>() { - @Override public void handle(javafx.scene.input.MouseEvent me) { - getBehavior().lowThumbReleased(me); - } - }); - - lowThumb.setOnMouseDragged(new EventHandler<javafx.scene.input.MouseEvent>() { - @Override public void handle(javafx.scene.input.MouseEvent me) { - Point2D cur = lowThumb.localToParent(me.getX(), me.getY()); - double dragPos = (isHorizontal())? - cur.getX() - preDragThumbPoint.getX() : -(cur.getY() - preDragThumbPoint.getY()); - getBehavior().lowThumbDragged(me, preDragPos + dragPos / trackLength); - } - }); - } - - private void initSecondThumb() { - highThumb = new ThumbPane(); - highThumb.getStyleClass().setAll("high-thumb"); //$NON-NLS-1$ - highThumb.setFocusTraversable(true); - if (!getChildren().contains(highThumb)) { - getChildren().add(highThumb); - } - - highThumb.setOnMousePressed(new EventHandler<MouseEvent>() { - @Override public void handle(MouseEvent e) { - lowThumb.setFocus(false); - highThumb.setFocus(true); - ((RangeSliderBehavior) getBehavior()).highThumbPressed(e, 0.0D); - preDragThumbPoint = highThumb.localToParent(e.getX(), e.getY()); - preDragPos = (((RangeSlider) getSkinnable()).getHighValue() - ((RangeSlider) getSkinnable()).getMin()) / - (getMaxMinusMinNoZero()); - } - } - ); - highThumb.setOnMouseReleased(new EventHandler<MouseEvent>() { - @Override public void handle(MouseEvent e) { - ((RangeSliderBehavior) getBehavior()).highThumbReleased(e); - } - } - ); - highThumb.setOnMouseDragged(new EventHandler<MouseEvent>() { - @Override public void handle(MouseEvent e) { - boolean orientation = ((RangeSlider) getSkinnable()).getOrientation() == Orientation.HORIZONTAL; - double trackLength = orientation ? track.getWidth() : track.getHeight(); - - Point2D point2d = highThumb.localToParent(e.getX(), e.getY()); - double d = ((RangeSlider) getSkinnable()).getOrientation() != Orientation.HORIZONTAL ? -(point2d.getY() - preDragThumbPoint.getY()) : point2d.getX() - preDragThumbPoint.getX(); - ((RangeSliderBehavior) getBehavior()).highThumbDragged(e, preDragPos + d / trackLength); - } - }); - } - - private void initRangeBar() { - rangeBar = new StackPane(); - rangeBar.cursorProperty().bind(new ObjectBinding<Cursor>() { - { bind(rangeBar.hoverProperty()); } - - @Override protected Cursor computeValue() { - return rangeBar.isHover() ? Cursor.HAND : Cursor.DEFAULT; - } - }); - rangeBar.getStyleClass().setAll("range-bar"); //$NON-NLS-1$ - - rangeBar.setOnMousePressed(new EventHandler<MouseEvent>() { - @Override public void handle(MouseEvent e) { - rangeBar.requestFocus(); - preDragPos = isHorizontal() ? e.getX() : -e.getY(); - } - }); - - rangeBar.setOnMouseDragged(new EventHandler<MouseEvent>() { - @Override public void handle(MouseEvent e) { - double delta = (isHorizontal() ? e.getX() : -e.getY()) - preDragPos; - ((RangeSliderBehavior) getBehavior()).moveRange(delta); - } - }); - - rangeBar.setOnMouseReleased(new EventHandler<MouseEvent>() { - @Override public void handle(MouseEvent e) { - ((RangeSliderBehavior) getBehavior()).confirmRange(); - } - }); - - getChildren().add(rangeBar); - } - - /** - * When ticks or labels are changing of visibility, we compute the new - * visibility and add the necessary objets. After this method, we must be - * sure to add the high Thumb and the rangeBar. - * - * @param ticksVisible - * @param labelsVisible - */ - private void setShowTickMarks(boolean ticksVisible, boolean labelsVisible) { - showTickMarks = (ticksVisible || labelsVisible); - RangeSlider rangeSlider = getSkinnable(); - if (showTickMarks) { - if (tickLine == null) { - tickLine = new NumberAxis(); - tickLine.tickLabelFormatterProperty().bind(getSkinnable().labelFormatterProperty()); - tickLine.setAnimated(false); - tickLine.setAutoRanging(false); - tickLine.setSide(isHorizontal() ? Side.BOTTOM : Side.RIGHT); - tickLine.setUpperBound(rangeSlider.getMax()); - tickLine.setLowerBound(rangeSlider.getMin()); - tickLine.setTickUnit(rangeSlider.getMajorTickUnit()); - tickLine.setTickMarkVisible(ticksVisible); - tickLine.setTickLabelsVisible(labelsVisible); - tickLine.setMinorTickVisible(ticksVisible); - // add 1 to the slider minor tick count since the axis draws one - // less minor ticks than the number given. - tickLine.setMinorTickCount(Math.max(rangeSlider.getMinorTickCount(),0) + 1); - getChildren().clear(); - getChildren().addAll(tickLine, track, lowThumb); - } else { - tickLine.setTickLabelsVisible(labelsVisible); - tickLine.setTickMarkVisible(ticksVisible); - tickLine.setMinorTickVisible(ticksVisible); - } - } - else { - getChildren().clear(); - getChildren().addAll(track, lowThumb); -// tickLine = null; - } - - getSkinnable().requestLayout(); - } - - @Override protected void handleControlPropertyChanged(String p) { - super.handleControlPropertyChanged(p); - if ("ORIENTATION".equals(p)) { //$NON-NLS-1$ - orientation = getSkinnable().getOrientation(); - if (showTickMarks && tickLine != null) { - tickLine.setSide(isHorizontal() ? Side.BOTTOM : Side.RIGHT); - } - getSkinnable().requestLayout(); - } else if ("MIN".equals(p) ) { //$NON-NLS-1$ - if (showTickMarks && tickLine != null) { - tickLine.setLowerBound(getSkinnable().getMin()); - } - getSkinnable().requestLayout(); - } else if ("MAX".equals(p)) { //$NON-NLS-1$ - if (showTickMarks && tickLine != null) { - tickLine.setUpperBound(getSkinnable().getMax()); - } - getSkinnable().requestLayout(); - } else if ("SHOW_TICK_MARKS".equals(p) || "SHOW_TICK_LABELS".equals(p)) { //$NON-NLS-1$ //$NON-NLS-2$ - setShowTickMarks(getSkinnable().isShowTickMarks(), getSkinnable().isShowTickLabels()); - if (!getChildren().contains(highThumb)) - getChildren().add(highThumb); - if (!getChildren().contains(rangeBar)) - getChildren().add(rangeBar); - } else if ("MAJOR_TICK_UNIT".equals(p)) { //$NON-NLS-1$ - if (tickLine != null) { - tickLine.setTickUnit(getSkinnable().getMajorTickUnit()); - getSkinnable().requestLayout(); - } - } else if ("MINOR_TICK_COUNT".equals(p)) { //$NON-NLS-1$ - if (tickLine != null) { - tickLine.setMinorTickCount(Math.max(getSkinnable().getMinorTickCount(),0) + 1); - getSkinnable().requestLayout(); - } - } else if ("LOW_VALUE".equals(p)) { //$NON-NLS-1$ - positionLowThumb(); - rangeBar.resizeRelocate(rangeStart, rangeBar.getLayoutY(), - rangeEnd - rangeStart, rangeBar.getHeight()); - } else if ("HIGH_VALUE".equals(p)) { //$NON-NLS-1$ - positionHighThumb(); - rangeBar.resize(rangeEnd-rangeStart, rangeBar.getHeight()); - } - super.handleControlPropertyChanged(p); - } - - /** - * - * @return the difference between max and min, but if they have the same - * value, 1 is returned instead of 0 because otherwise the division where it - * can be used will return Nan. - */ - private double getMaxMinusMinNoZero() { - RangeSlider s = getSkinnable(); - return s.getMax() - s.getMin() == 0 ? 1 : s.getMax() - s.getMin(); - } - - /** - * Called when ever either min, max or lowValue changes, so lowthumb's layoutX, Y is recomputed. - */ - private void positionLowThumb() { - RangeSlider s = getSkinnable(); - boolean horizontal = isHorizontal(); - double lx = (horizontal) ? trackStart + (((trackLength * ((s.getLowValue() - s.getMin()) / - (getMaxMinusMinNoZero()))) - thumbWidth/2)) : lowThumbPos; - double ly = (horizontal) ? lowThumbPos : - getSkinnable().getInsets().getTop() + trackLength - (trackLength * ((s.getLowValue() - s.getMin()) / - (getMaxMinusMinNoZero()))); // - thumbHeight/2 - lowThumb.setLayoutX(lx); - lowThumb.setLayoutY(ly); - if (horizontal) rangeStart = lx + thumbWidth; else rangeEnd = ly; - } - - /** - * Called when ever either min, max or highValue changes, so highthumb's layoutX, Y is recomputed. - */ - private void positionHighThumb() { - RangeSlider slider = (RangeSlider) getSkinnable(); - boolean orientation = ((RangeSlider) getSkinnable()).getOrientation() == Orientation.HORIZONTAL; - - double thumbWidth = lowThumb.getWidth(); - double thumbHeight = lowThumb.getHeight(); - highThumb.resize(thumbWidth, thumbHeight); - - double pad = 0;//track.impl_getBackgroundFills() == null || track.impl_getBackgroundFills().length <= 0 ? 0.0D : track.impl_getBackgroundFills()[0].getTopLeftCornerRadius(); - double trackStart = orientation ? track.getLayoutX() : track.getLayoutY(); - trackStart += pad; - double trackLength = orientation ? track.getWidth() : track.getHeight(); - trackLength -= 2 * pad; - - double x = orientation ? trackStart + (trackLength * ((slider.getHighValue() - slider.getMin()) / (getMaxMinusMinNoZero())) - thumbWidth / 2D) : lowThumb.getLayoutX(); - double y = orientation ? lowThumb.getLayoutY() : (getSkinnable().getInsets().getTop() + trackLength) - trackLength * ((slider.getHighValue() - slider.getMin()) / (getMaxMinusMinNoZero())); - highThumb.setLayoutX(x); - highThumb.setLayoutY(y); - if (orientation) rangeEnd = x; else rangeStart = y + thumbWidth; - } - - @Override protected void layoutChildren(final double x, final double y, - final double w, final double h) { - // resize thumb to preferred size - thumbWidth = lowThumb.prefWidth(-1); - thumbHeight = lowThumb.prefHeight(-1); - lowThumb.resize(thumbWidth, thumbHeight); - // we are assuming the is common radius's for all corners on the track - double trackRadius = track.getBackground() == null ? 0 : track.getBackground().getFills().size() > 0 ? - track.getBackground().getFills().get(0).getRadii().getTopLeftHorizontalRadius() : 0; - - if (isHorizontal()) { - double tickLineHeight = (showTickMarks) ? tickLine.prefHeight(-1) : 0; - double trackHeight = track.prefHeight(-1); - double trackAreaHeight = Math.max(trackHeight,thumbHeight); - double totalHeightNeeded = trackAreaHeight + ((showTickMarks) ? trackToTickGap+tickLineHeight : 0); - double startY = y + ((h - totalHeightNeeded)/2); // center slider in available height vertically - trackLength = w - thumbWidth; - trackStart = x + (thumbWidth/2); - double trackTop = (int)(startY + ((trackAreaHeight-trackHeight)/2)); - lowThumbPos = (int)(startY + ((trackAreaHeight-thumbHeight)/2)); - - positionLowThumb(); - // layout track - track.resizeRelocate(trackStart - trackRadius, trackTop , trackLength + trackRadius + trackRadius, trackHeight); - positionHighThumb(); - // layout range bar - rangeBar.resizeRelocate(rangeStart, trackTop, rangeEnd - rangeStart, trackHeight); - // layout tick line - if (showTickMarks) { - tickLine.setLayoutX(trackStart); - tickLine.setLayoutY(trackTop+trackHeight+trackToTickGap); - tickLine.resize(trackLength, tickLineHeight); - tickLine.requestAxisLayout(); - } else { - if (tickLine != null) { - tickLine.resize(0,0); - tickLine.requestAxisLayout(); - } - tickLine = null; - } - } else { - double tickLineWidth = (showTickMarks) ? tickLine.prefWidth(-1) : 0; - double trackWidth = track.prefWidth(-1); - double trackAreaWidth = Math.max(trackWidth,thumbWidth); - double totalWidthNeeded = trackAreaWidth + ((showTickMarks) ? trackToTickGap+tickLineWidth : 0) ; - double startX = x + ((w - totalWidthNeeded)/2); // center slider in available width horizontally - trackLength = h - thumbHeight; - trackStart = y + (thumbHeight/2); - double trackLeft = (int)(startX + ((trackAreaWidth-trackWidth)/2)); - lowThumbPos = (int)(startX + ((trackAreaWidth-thumbWidth)/2)); - - positionLowThumb(); - // layout track - track.resizeRelocate(trackLeft, trackStart - trackRadius, trackWidth, trackLength + trackRadius + trackRadius); - positionHighThumb(); - // layout range bar - rangeBar.resizeRelocate(trackLeft, rangeStart, trackWidth, rangeEnd - rangeStart); - // layout tick line - if (showTickMarks) { - tickLine.setLayoutX(trackLeft+trackWidth+trackToTickGap); - tickLine.setLayoutY(trackStart); - tickLine.resize(tickLineWidth, trackLength); - tickLine.requestAxisLayout(); - } else { - if (tickLine != null) { - tickLine.resize(0,0); - tickLine.requestAxisLayout(); - } - tickLine = null; - } - } - } - - private double minTrackLength() { - return 2*lowThumb.prefWidth(-1); - } - - @Override protected double computeMinWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) { - if (isHorizontal()) { - return (leftInset + minTrackLength() + lowThumb.minWidth(-1) + rightInset); - } else { - return (leftInset + lowThumb.prefWidth(-1) + rightInset); - } - } - - @Override protected double computeMinHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { - if (isHorizontal()) { - return (topInset + lowThumb.prefHeight(-1) + bottomInset); - } else { - return (topInset + minTrackLength() + lowThumb.prefHeight(-1) + bottomInset); - } - } - - @Override protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) { - if (isHorizontal()) { - if(showTickMarks) { - return Math.max(140, tickLine.prefWidth(-1)); - } else { - return 140; - } - } else { - //return (padding.getLeft()) + Math.max(thumb.prefWidth(-1), track.prefWidth(-1)) + padding.getRight(); - return leftInset + Math.max(lowThumb.prefWidth(-1), track.prefWidth(-1)) + - ((showTickMarks) ? (trackToTickGap+tickLine.prefWidth(-1)) : 0) + rightInset; - } - } - - @Override protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { - if (isHorizontal()) { - return getSkinnable().getInsets().getTop() + Math.max(lowThumb.prefHeight(-1), track.prefHeight(-1)) + - ((showTickMarks) ? (trackToTickGap+tickLine.prefHeight(-1)) : 0) + bottomInset; - } else { - if(showTickMarks) { - return Math.max(140, tickLine.prefHeight(-1)); - } else { - return 140; - } - } - } - - @Override protected double computeMaxWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) { - if (isHorizontal()) { - return Double.MAX_VALUE; - } else { - return getSkinnable().prefWidth(-1); - } - } - - @Override protected double computeMaxHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { - if (isHorizontal()) { - return getSkinnable().prefHeight(width); - } else { - return Double.MAX_VALUE; - } - } - - private boolean isHorizontal() { - return orientation == null || orientation == Orientation.HORIZONTAL; - } - - private static class ThumbPane extends StackPane { - public void setFocus(boolean value) { - setFocused(value); - } - } -} diff --git a/src/impl/org/controlsfx/skin/RatingSkin.java b/src/impl/org/controlsfx/skin/RatingSkin.java deleted file mode 100644 index 8c13fc3..0000000 --- a/src/impl/org/controlsfx/skin/RatingSkin.java +++ /dev/null @@ -1,329 +0,0 @@ -/** - * Copyright (c) 2013, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.skin; - -import impl.org.controlsfx.behavior.RatingBehavior; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import javafx.event.EventHandler; -import javafx.geometry.Orientation; -import javafx.geometry.Point2D; -import javafx.scene.Node; -import javafx.scene.input.MouseEvent; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Pane; -import javafx.scene.layout.Region; -import javafx.scene.layout.VBox; -import javafx.scene.shape.Rectangle; - -import org.controlsfx.control.Rating; -import org.controlsfx.tools.Utils; - -import com.sun.javafx.scene.control.skin.BehaviorSkinBase; - -/** - * - */ -public class RatingSkin extends BehaviorSkinBase<Rating, RatingBehavior> { - - /*************************************************************************** - * - * Private fields - * - **************************************************************************/ - - private static final String STRONG = "strong"; //$NON-NLS-1$ - - private boolean updateOnHover; - private boolean partialRating; - - // the container for the traditional rating control. If updateOnHover and - // partialClipping are disabled, this will show a combination of strong - // and non-strong graphics, depending on the current rating value - private Pane backgroundContainer; - - // the container for the strong graphics which may be partially clipped. - // Note that this only exists if updateOnHover or partialClipping is enabled. - private Pane foregroundContainer; - - private double rating = -1; - - private Rectangle forgroundClipRect; - - private final EventHandler<MouseEvent> mouseMoveHandler = new EventHandler<MouseEvent>() { - @Override public void handle(MouseEvent event) { - - // if we support updateOnHover, calculate the intended rating based on the mouse - // location and update the control property with it. - - if (updateOnHover) { - updateRatingFromMouseEvent(event); - } - } - }; - - private final EventHandler<MouseEvent> mouseClickHandler = new EventHandler<MouseEvent>() { - @Override public void handle(MouseEvent event) { - - // if we are not updating on hover, calculate the intended rating based on the mouse - // location and update the control property with it. - - if (! updateOnHover) { - updateRatingFromMouseEvent(event); - } - } - }; - - private void updateRatingFromMouseEvent(MouseEvent event) { - Rating control = getSkinnable(); - if (! control.ratingProperty().isBound()) { - Point2D mouseLocation = new Point2D(event.getSceneX(), event.getSceneY()); - control.setRating(calculateRating(mouseLocation)); - } - } - - /*************************************************************************** - * - * Constructors - * - **************************************************************************/ - - public RatingSkin(Rating control) { - super(control, new RatingBehavior(control)); - - this.updateOnHover = control.isUpdateOnHover(); - this.partialRating = control.isPartialRating(); - - // init - recreateButtons(); - updateRating(); - // -- end init - - registerChangeListener(control.ratingProperty(), "RATING"); //$NON-NLS-1$ - registerChangeListener(control.maxProperty(), "MAX"); //$NON-NLS-1$ - registerChangeListener(control.orientationProperty(), "ORIENTATION"); //$NON-NLS-1$ - registerChangeListener(control.updateOnHoverProperty(), "UPDATE_ON_HOVER"); //$NON-NLS-1$ - registerChangeListener(control.partialRatingProperty(), "PARTIAL_RATING"); //$NON-NLS-1$ - // added to ensure clip is correctly calculated when control is first shown: - registerChangeListener(control.boundsInLocalProperty(), "BOUNDS"); //$NON-NLS-1$ - } - - - - /*************************************************************************** - * - * Implementation - * - **************************************************************************/ - - @Override protected void handleControlPropertyChanged(String p) { - super.handleControlPropertyChanged(p); - - if (p == "RATING") { //$NON-NLS-1$ - updateRating(); - } else if (p == "MAX") { //$NON-NLS-1$ - recreateButtons(); - } else if (p == "ORIENTATION") { //$NON-NLS-1$ - recreateButtons(); - } else if (p == "PARTIAL_RATING") { //$NON-NLS-1$ - this.partialRating = getSkinnable().isPartialRating(); - recreateButtons(); - } else if (p == "UPDATE_ON_HOVER") { //$NON-NLS-1$ - this.updateOnHover = getSkinnable().isUpdateOnHover(); - recreateButtons(); - } else if (p == "BOUNDS") { //$NON-NLS-1$ - if (this.partialRating) { - updateClip(); - } - } - } - - private void recreateButtons() { - backgroundContainer = null; - foregroundContainer = null; - - backgroundContainer = isVertical() ? new VBox() : new HBox(); - backgroundContainer.getStyleClass().add("container"); //$NON-NLS-1$ - getChildren().setAll(backgroundContainer); - - if (updateOnHover || partialRating) { - foregroundContainer = isVertical() ? new VBox() : new HBox(); - foregroundContainer.getStyleClass().add("container"); //$NON-NLS-1$ - foregroundContainer.setMouseTransparent(true); - getChildren().add(foregroundContainer); - - forgroundClipRect = new Rectangle(); - foregroundContainer.setClip(forgroundClipRect); - - } - - for (int index = 0; index <= getSkinnable().getMax(); index++) { - Node backgroundNode = createButton(); - - if (index > 0) { - if (isVertical()) { - backgroundContainer.getChildren().add(0,backgroundNode); - } else { - backgroundContainer.getChildren().add(backgroundNode); - } - - if (partialRating) { - Node foregroundNode = createButton(); - foregroundNode.getStyleClass().add(STRONG); - foregroundNode.setMouseTransparent(true); - - if (isVertical()) { - foregroundContainer.getChildren().add(0,foregroundNode); - } else { - foregroundContainer.getChildren().add(foregroundNode); - } - } - } - } - - updateRating(); - } - - // Calculate the rating based on a mouse position (in Scene coordinates). - // If we support partial ratings, the value is calculated directly. - // Otherwise the ceil of the value is computed. - private double calculateRating(Point2D sceneLocation) { - final Point2D b = backgroundContainer.sceneToLocal(sceneLocation); - - final double x = b.getX(); - final double y = b.getY(); - - final Rating control = getSkinnable(); - - final int max = control.getMax(); - final double w = control.getWidth() - (snappedLeftInset() + snappedRightInset()); - final double h = control.getHeight() - (snappedTopInset() + snappedBottomInset()); - - double newRating = -1; - - if (isVertical()) { - newRating = ((h - y) / h) * max; - } else { - newRating = (x / w) * max; - } - - if (! partialRating) { - newRating = Utils.clamp(1, Math.ceil(newRating), control.getMax()); - } - - return newRating; - } - - private void updateClip() { - final Rating control = getSkinnable(); - final double h = control.getHeight() - (snappedTopInset() + snappedBottomInset()); - final double w = control.getWidth() - (snappedLeftInset() + snappedRightInset()); - - if (isVertical()) { - final double y = h * rating / control.getMax() ; - forgroundClipRect.relocate(0, h - y); - forgroundClipRect.setWidth(control.getWidth()); - forgroundClipRect.setHeight(y); - } else { - final double x = w * rating / control.getMax(); - forgroundClipRect.setWidth(x); - forgroundClipRect.setHeight(control.getHeight()); - } - - } - -// private double getSpacing() { -// return (backgroundContainer instanceof HBox) ? -// ((HBox)backgroundContainer).getSpacing() : -// ((VBox)backgroundContainer).getSpacing(); -// } - - private Node createButton() { - Region btn = new Region(); - btn.getStyleClass().add("button"); //$NON-NLS-1$ - - btn.setOnMouseMoved(mouseMoveHandler); - btn.setOnMouseClicked(mouseClickHandler); - return btn; - } - - // Update the skin based on a new value for the rating. - // If we support partial ratings, updates the clip. - // Otherwise, updates the style classes for the buttons. - - private void updateRating() { - - double newRating = getSkinnable().getRating(); - - if (newRating == rating) return; - - rating = Utils.clamp(0, newRating, getSkinnable().getMax()); - - if (partialRating) { - updateClip(); - } else { - updateButtonStyles(); - } - } - - private void updateButtonStyles() { - final int max = getSkinnable().getMax(); - - // make a copy of the buttons list so that we can reverse the order if - // the list is vertical (as the buttons are ordered bottom to top). - List<Node> buttons = new ArrayList<>(backgroundContainer.getChildren()); - if (isVertical()) { - Collections.reverse(buttons); - } - - for (int i = 0; i < max; i++) { - Node button = buttons.get(i); - - final List<String> styleClass = button.getStyleClass(); - final boolean containsStrong = styleClass.contains(STRONG); - - if (i < rating) { - if (! containsStrong) { - styleClass.add(STRONG); - } - } else if (containsStrong) { - styleClass.remove(STRONG); - } - } - } - - private boolean isVertical() { - return getSkinnable().getOrientation() == Orientation.VERTICAL; - } - - @Override protected double computeMaxWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) { - return super.computePrefWidth(height, topInset, rightInset, bottomInset, leftInset); - } -} diff --git a/src/impl/org/controlsfx/skin/SegmentedButtonSkin.java b/src/impl/org/controlsfx/skin/SegmentedButtonSkin.java deleted file mode 100644 index ebb921e..0000000 --- a/src/impl/org/controlsfx/skin/SegmentedButtonSkin.java +++ /dev/null @@ -1,117 +0,0 @@ -/** - * Copyright (c) 2013, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.skin; - -import java.util.Collections; - -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; -import javafx.collections.ObservableList; -import javafx.scene.control.ToggleButton; -import javafx.scene.control.ToggleGroup; -import javafx.scene.layout.HBox; - -import org.controlsfx.control.SegmentedButton; - -import com.sun.javafx.scene.control.behavior.BehaviorBase; -import com.sun.javafx.scene.control.behavior.KeyBinding; -import com.sun.javafx.scene.control.skin.BehaviorSkinBase; - -public class SegmentedButtonSkin extends BehaviorSkinBase<SegmentedButton, BehaviorBase<SegmentedButton>> { - - private static final String ONLY_BUTTON = "only-button"; //$NON-NLS-1$ - private static final String LEFT_PILL = "left-pill"; //$NON-NLS-1$ - private static final String CENTER_PILL = "center-pill"; //$NON-NLS-1$ - private static final String RIGHT_PILL = "right-pill"; //$NON-NLS-1$ - - private final HBox container; - - public SegmentedButtonSkin(SegmentedButton control) { - super(control, new BehaviorBase<>(control, Collections.<KeyBinding> emptyList())); - - container = new HBox(); - - getChildren().add(container); - - updateButtons(); - getButtons().addListener(new InvalidationListener() { - @Override public void invalidated(Observable observable) { - updateButtons(); - } - }); - - control.toggleGroupProperty().addListener((observable, oldValue, newValue) -> { - getButtons().forEach((button) -> { - button.setToggleGroup(newValue); - }); - }); - } - - private ObservableList<ToggleButton> getButtons() { - return getSkinnable().getButtons(); - } - - private void updateButtons() { - ObservableList<ToggleButton> buttons = getButtons(); - ToggleGroup group = getSkinnable().getToggleGroup(); - - container.getChildren().clear(); - - for (int i = 0; i < getButtons().size(); i++) { - ToggleButton t = buttons.get(i); - - if (group != null) { - t.setToggleGroup(group); - } - - t.getStyleClass().removeAll(ONLY_BUTTON, LEFT_PILL, CENTER_PILL, RIGHT_PILL); - container.getChildren().add(t); - - if (i == buttons.size() - 1) { - if (i == 0) { - t.getStyleClass().add(ONLY_BUTTON); - } else { - t.getStyleClass().add(RIGHT_PILL); - } - } else if (i == 0) { - t.getStyleClass().add(LEFT_PILL); - } else { - t.getStyleClass().add(CENTER_PILL); - } - } - } - - @Override - protected double computeMaxWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) { - return getSkinnable().prefWidth(height); - } - - @Override - protected double computeMaxHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { - return getSkinnable().prefHeight(width); - } -} diff --git a/src/impl/org/controlsfx/skin/SnapshotViewSkin.java b/src/impl/org/controlsfx/skin/SnapshotViewSkin.java deleted file mode 100644 index 5bdf23e..0000000 --- a/src/impl/org/controlsfx/skin/SnapshotViewSkin.java +++ /dev/null @@ -1,566 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.skin; - -import impl.org.controlsfx.behavior.SnapshotViewBehavior; -import javafx.beans.binding.Bindings; -import javafx.beans.binding.BooleanBinding; -import javafx.beans.property.ReadOnlyBooleanProperty; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.geometry.Bounds; -import javafx.geometry.Pos; -import javafx.geometry.Rectangle2D; -import javafx.scene.Cursor; -import javafx.scene.Node; -import javafx.scene.input.MouseEvent; -import javafx.scene.layout.GridPane; -import javafx.scene.paint.Color; -import javafx.scene.shape.Rectangle; -import javafx.scene.shape.StrokeType; - -import org.controlsfx.control.SnapshotView; -import org.controlsfx.control.SnapshotView.Boundary; - -import com.sun.javafx.scene.control.skin.BehaviorSkinBase; - -/** - * View for the {@link SnapshotView}. It displays the node and the selection and manages their positioning. Mouse events - * are handed over to the {@link SnapshotViewBehavior} which uses them to change the selection. - */ -public class SnapshotViewSkin extends BehaviorSkinBase<SnapshotView, SnapshotViewBehavior> { - - /* ************************************************************************ - * * - * Attributes & Properties * - * * - **************************************************************************/ - - /** - * The currently displayed node; when the {@link SnapshotView#nodeProperty() node} property changes - * {@link #updateNode() updateNode} will set the new one. - */ - private Node node; - - /** - * The pane displaying the {@link #node}. - */ - private final GridPane gridPane; - - /** - * The (mutable) rectangle which represents the selected area. - */ - private final Rectangle selectedArea; - - /** - * The rectangle whose stroke represents the unselected area. Binding is used to ensure that the rectangle itself - * always has the same size and position as the {@link #selectedArea}. - */ - private final Rectangle unselectedArea; - - /** - * The node capturing mouse events. - */ - private final Node mouseNode; - - /* ************************************************************************ - * * - * Constructor & Initialization * - * * - **************************************************************************/ - - /** - * Creates a new skin for the specified {@link SnapshotView}. - * - * @param snapshotView - * the {@link SnapshotView} this skin will display - */ - public SnapshotViewSkin(SnapshotView snapshotView) { - - super(snapshotView, new SnapshotViewBehavior(snapshotView)); - - this.gridPane = createGridPane(); - this.selectedArea = new Rectangle(); - this.unselectedArea = new Rectangle(); - this.mouseNode = createMouseNode(); - - buildSceneGraph(); - initializeAreas(); - - registerChangeListener(snapshotView.nodeProperty(), "NODE"); //$NON-NLS-1$ - registerChangeListener(snapshotView.selectionProperty(), "SELECTION"); //$NON-NLS-1$ - } - - @Override - protected void handleControlPropertyChanged(String p) { - super.handleControlPropertyChanged(p); - - if ("NODE".equals(p)) { //$NON-NLS-1$ - updateNode(); - } else if ("SELECTION".equals(p)) { //$NON-NLS-1$ - updateSelection(); - } - } - - /** - * Creates the grid pane which will contain the node. - * - * @return a {@link GridPane} - */ - private static GridPane createGridPane() { - GridPane pane = new GridPane(); - pane.setAlignment(Pos.CENTER); - return pane; - } - - /** - * Creates the node which will be used to capture mouse events. Events are handed over to - * {@link #handleMouseEvent(MouseEvent) handleMouseEvent}. - * - * @return a {@link Node} - */ - private Node createMouseNode() { - Rectangle mouseNode = new Rectangle(); - - // make the node transparent and make sure its size does not affect the control's size - mouseNode.setFill(Color.TRANSPARENT); - mouseNode.setManaged(false); - - // bind width and height to the control - mouseNode.widthProperty().bind(getSkinnable().widthProperty()); - mouseNode.heightProperty().bind(getSkinnable().heightProperty()); - - // let it handle the mouse events if allowed by the user - mouseNode.addEventHandler(MouseEvent.ANY, this::handleMouseEvent); - mouseNode.mouseTransparentProperty().bind(getSkinnable().selectionMouseTransparentProperty()); - - return mouseNode; - } - - /** - * Builds this skin's scene graph. - */ - private void buildSceneGraph() { - getChildren().addAll(gridPane, unselectedArea, selectedArea, mouseNode); - updateNode(); - } - - /** - * Initializes the {@link #selectedArea} and the {@link #unselectedArea}. This includes their style and their - * bindings to the {@link SnapshotView#selectionProperty() selection} property. - */ - private void initializeAreas() { - styleAreas(); - bindAreaCoordinatesTogether(); - bindAreaVisibilityToSelection(); - } - - /** - * Styles the selected and unselected area. - */ - private void styleAreas() { - selectedArea.fillProperty().bind(getSkinnable().selectionAreaFillProperty()); - selectedArea.strokeProperty().bind(getSkinnable().selectionBorderPaintProperty()); - selectedArea.strokeWidthProperty().bind(getSkinnable().selectionBorderWidthProperty()); - selectedArea.setStrokeType(StrokeType.OUTSIDE); - // if the control's layout depends on this rectangle, - // the stroke's width messes up the layout if the selection is on the pane's edge - selectedArea.setManaged(false); - selectedArea.setMouseTransparent(true); - - unselectedArea.setFill(Color.TRANSPARENT); - unselectedArea.strokeProperty().bind(getSkinnable().unselectedAreaFillProperty()); - unselectedArea.strokeWidthProperty().bind( - Bindings.max(getSkinnable().widthProperty(), getSkinnable().heightProperty())); - unselectedArea.setStrokeType(StrokeType.OUTSIDE); - // this call is crucial! it prevents the enormous unselected area from messing up the layout - unselectedArea.setManaged(false); - unselectedArea.setMouseTransparent(true); - } - - /** - * Binds the position and size of {@link #unselectedArea} to {@link #selectedArea}. - */ - private void bindAreaCoordinatesTogether() { - unselectedArea.xProperty().bind(selectedArea.xProperty()); - unselectedArea.yProperty().bind(selectedArea.yProperty()); - unselectedArea.widthProperty().bind(selectedArea.widthProperty()); - unselectedArea.heightProperty().bind(selectedArea.heightProperty()); - } - - /** - * Binds the visibility of {@link #selectedArea} and {@link #unselectedArea} to the {@code SnapshotView} 's - * {@link SnapshotView#selectionActiveProperty() selectionActive} and {@link SnapshotView#hasSelectionProperty() - * selectionValid} properties. - */ - @SuppressWarnings("unused") - private void bindAreaVisibilityToSelection() { - ReadOnlyBooleanProperty selectionExists = getSkinnable().hasSelectionProperty(); - ReadOnlyBooleanProperty selectionActive = getSkinnable().selectionActiveProperty(); - BooleanBinding existsAndActive = Bindings.and(selectionExists, selectionActive); - - selectedArea.visibleProperty().bind(existsAndActive); - unselectedArea.visibleProperty().bind(existsAndActive); - - // UGLY WORKAROUND AHEAD! - // The clipper should be created in 'styleAreas' but due to the problem explained in 'Clipper.setClip(Node)' - // it has to be created here where the visibility is determined. - - // clip the unselected area according to the view's property - this is done by a designated inner class - new Clipper(getSkinnable(), unselectedArea, () -> unselectedArea.visibleProperty().bind(existsAndActive)); - } - - /* ************************************************************************ - * * - * Node * - * * - **************************************************************************/ - - /** - * Displays the current {@link SnapshotView#nodeProperty() node}. - */ - private void updateNode() { - if (node != null) { - gridPane.getChildren().remove(node); - } - - node = getSkinnable().getNode(); - if (node != null) { - gridPane.getChildren().add(0, node); - } - } - - /* ************************************************************************ - * * - * Selection * - * * - **************************************************************************/ - - /** - * Updates the position and size of {@link #selectedArea} (and by binding that of {@link #unselectedArea}) to a - * changed selection. - */ - private void updateSelection() { - boolean showSelection = getSkinnable().hasSelection() && getSkinnable().isSelectionActive(); - - if (showSelection) { - // the selection can be properly displayed - Rectangle2D selection = getSkinnable().getSelection(); - setSelection(selection.getMinX(), selection.getMinY(), selection.getWidth(), selection.getHeight()); - } else { - // in this case the selection areas are invisible, - // so the only thing left to do is to make sure their coordinates are not all over the place - // (this is not strictly necessary but makes the skin's state cleaner) - setSelection(0, 0, 0, 0); - } - } - - /** - * Updates the position and size of {@link #selectedArea} (and by binding that of {@link #unselectedArea}) to the - * specified arguments. - * - * @param x - * the new x coordinate of the upper left corner - * @param y - * the new y coordinate of the upper left corner - * @param width - * the new width - * @param height - * the new height - */ - private void setSelection(double x, double y, double width, double height) { - selectedArea.setX(x); - selectedArea.setY(y); - selectedArea.setWidth(width); - selectedArea.setHeight(height); - } - - /* ************************************************************************ - * * - * Mouse Events * - * * - **************************************************************************/ - - /** - * Handles mouse events. - * - * @param event - * the {@link MouseEvent} to handle - */ - private void handleMouseEvent(MouseEvent event) { - Cursor newCursor = getBehavior().handleMouseEvent(event); - mouseNode.setCursor(newCursor); - } - - /* ************************************************************************ - * * - * Inner Classes * - * * - **************************************************************************/ - - /** - * Clips the unselected area to the {@link SnapshotView#unselectedAreaBoundaryProperty() unselectedAreaBoundary}. - * - */ - private static class Clipper { - - /** - * The snapshot view to whose {@link Node#boundsInLocalProperty() boundsInLocal} the {@link #clippedNode} will - * be clipped. - */ - private final SnapshotView snapshotView; - - /** - * The node to which the clips will be added. - */ - private final Node clippedNode; - - /** - * A function which rebinds the clip's visibility after it was unbound. Only necessary because of the workaround - * explained in {@link #setClip(Node) setClip}. - */ - private final Runnable rebindClippedNodeVisibility; - - /** - * The {@link Rectangle} used to clip the {@link #clippedNode} to {@link Boundary#CONTROL}. - */ - private final Rectangle controlClip; - - /** - * The {@link Rectangle} used to clip the {@link #clippedNode} to {@link Boundary#NODE}. - */ - private final Rectangle nodeClip; - - /** - * A listener which updates the {@link #controlClip} when the {@link #snapshotView}'s - * {@link Node#boundsInLocalProperty() boundsInLocal} change. - */ - private final ChangeListener<Bounds> updateControlClipToNewBoundsListener; - - /** - * A listener which updates the {@link #nodeClip} when the {@link SnapshotView#nodeProperty() node}'s - * {@link Node#boundsInParentProperty() boundsInParent} change. - */ - private final ChangeListener<Bounds> updateNodeClipToNewBoundsListener; - - /** - * Creates a new clipper with the specified arguments. - * - * @param snapshotView - * the {@link SnapshotView} to whose bounds the {@code clippedNode} will be clipped - * @param clippedNode - * the {@link Node} whose bounds will be clipped - * @param rebindClippedNodeVisibility - * a function which rebinds the {@code clippedNode}'s visibility - */ - public Clipper(SnapshotView snapshotView, Node clippedNode, Runnable rebindClippedNodeVisibility) { - this.snapshotView = snapshotView; - this.clippedNode = clippedNode; - this.rebindClippedNodeVisibility = rebindClippedNodeVisibility; - - // for 'CONTROL', clip to the control's bounds - controlClip = new Rectangle(); - updateControlClipToNewBoundsListener = - (o, oldBounds, newBounds) -> resizeRectangleToBounds(controlClip, newBounds); - - // for 'NODE', clip to the node's bounds - nodeClip = new Rectangle(); - // create the listener which will resize the rectangle - updateNodeClipToNewBoundsListener = - (o, oldBounds, newBounds) -> resizeRectangleToBounds(nodeClip, newBounds); - - // set the clipping and keep updating it - setClipping(); - snapshotView.unselectedAreaBoundaryProperty().addListener((o, oldBoundary, newBoundary) -> setClipping()); - } - - /** - * Sets clipping to the current {@link SnapshotView#unselectedAreaBoundaryProperty() unselectedAreaBoundary}. - */ - private void setClipping() { - Boundary boundary = snapshotView.getUnselectedAreaBoundary(); - switch (boundary) { - case CONTROL: - clipToControl(); - break; - case NODE: - clipToNode(); - break; - default: - throw new IllegalArgumentException("The boundary " + boundary + " is not fully implemented."); //$NON-NLS-1$ //$NON-NLS-2$ - } - } - - /** - * Clips the {@link #clippedNode} to {@link #controlClip} and keeps updating the latter when the control changes - * its bounds. - */ - private void clipToControl() { - // stop resizing the node clip - updateNodeClipToChangingNode(snapshotView.nodeProperty(), snapshotView.getNode(), null); - - // resize the control clip and keep doing so - resizeRectangleToBounds(controlClip, snapshotView.getBoundsInLocal()); - snapshotView.boundsInLocalProperty().addListener(updateControlClipToNewBoundsListener); - - // set the clip - setClip(controlClip); - } - - /** - * Clips the {@link #clippedNode} to {@link #nodeClip} and keeps updating the latter when the control changes - * its bounds. - */ - private void clipToNode() { - // update the node clip to the new bounds and whenever the node changes its bounds - updateNodeClipToChangingNode(snapshotView.nodeProperty(), null, snapshotView.getNode()); - // move that listener from old to new nodes - snapshotView.nodeProperty().addListener(this::updateNodeClipToChangingNode); - - // set the clip - setClip(nodeClip); - } - - /** - * Resizes the {@link #nodeClip} to the specified new node's {@link Node#boundsInParentProperty() - * boundsInParent} (or to an empty rectangle if it is {@code null}) and moves the - * {@link #updateNodeClipToNewBoundsListener} from the old to the new node's {@code boundInParents} property. - * <p> - * Designed to be used as a lambda method reference. - * - * @param o - * the {@link ObservableValue} which changed its value - * @param oldNode - * the old node - * @param newNode - * the new node - */ - private void updateNodeClipToChangingNode( - @SuppressWarnings("unused") ObservableValue<? extends Node> o, Node oldNode, Node newNode) { - - // resize the rectangle to match the new node - resizeRectangleToNodeBounds(nodeClip, newNode); - - // move the listener from one node to the next - if (oldNode != null) { - oldNode.boundsInParentProperty().removeListener(updateNodeClipToNewBoundsListener); - } - if (newNode != null) { - newNode.boundsInParentProperty().addListener(updateNodeClipToNewBoundsListener); - } - } - - /** - * Resizes the specified rectangle to the specified node's {@link Node#boundsInParentProperty() boundsInParent}. - * - * @param rectangle - * the {@link Rectangle} which will be resized - * @param node - * the {@link Node} to whose bounds the {@code rectangle} will be resized - */ - private static void resizeRectangleToNodeBounds(Rectangle rectangle, Node node) { - if (node == null) { - resizeRectangleToZero(rectangle); - } else { - resizeRectangleToBounds(rectangle, node.getBoundsInParent()); - } - } - - /** - * Resized the specified rectangle so that its upper left point is {@code (0, 0)} and its width and height are - * both 0. - * - * @param rectangle - * the {@link Rectangle} which will be resized - */ - private static void resizeRectangleToZero(Rectangle rectangle) { - rectangle.setX(0); - rectangle.setY(0); - rectangle.setWidth(0); - rectangle.setHeight(0); - } - - /** - * Resized the specified rectangle so that it matches the specified bounds, i.e. it will have the same upper - * left point and width and height. - * - * @param rectangle - * the {@link Rectangle} which will be resized - * @param bounds - * the {@link Bounds} to which the rectangle will be resized - */ - private static void resizeRectangleToBounds(Rectangle rectangle, Bounds bounds) { - rectangle.setX(bounds.getMinX()); - rectangle.setY(bounds.getMinY()); - rectangle.setWidth(bounds.getWidth()); - rectangle.setHeight(bounds.getHeight()); - } - - /** - * Sets the specified clip on the {@link #clippedNode}. - * - * @param clip - * the {@link Node} which is used as a clip - */ - private void setClip(Node clip) { - - /* - * UGLY WORKAROUND - * - * Setting the clip on the unselected area while it is invisible leads to either the clip having no effect - * or no area being displayed at all. Obviously I'm doing something wrong but I couldn't determine the root - * cause so I fixed the symptom. Now the area is turned visible, the clip is set and then it is made - * invisible again. - * - * Everything below but 'clippedNode.setClip(clip);' is part of that workaround. To reproduce the bug - * comment all those lines out. Then, after 'HelloSnapshotView' started, select 'NODE' for the unselected - * area boundary and draw a selection on the node. The area above the node which is not selected should be - * painted in a semi-opaque black but due to the bug it is not. Instead the area outside of the selection - * has no paint at all and is simply transparent. - * Note that if the boundary is turned back to CONTROL, a selection is made and then NODE is set again, the - * clips works properly and the preexisting selection's outer area is clipped to the node. - * - * If someone finds out what the *$#&? I've been doing wrong, please fix and be so kind to mail to - * nipa@codefx.org! :) - */ - - boolean workAroundVisibilityProblem = !clippedNode.isVisible(); - if (workAroundVisibilityProblem) { - clippedNode.visibleProperty().unbind(); - clippedNode.setVisible(true); - } - - clippedNode.setClip(clip); - - if (workAroundVisibilityProblem) { - rebindClippedNodeVisibility.run(); - } - } - - } - -} diff --git a/src/impl/org/controlsfx/skin/StatusBarSkin.java b/src/impl/org/controlsfx/skin/StatusBarSkin.java deleted file mode 100644 index 39a1b79..0000000 --- a/src/impl/org/controlsfx/skin/StatusBarSkin.java +++ /dev/null @@ -1,100 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.skin; - -import javafx.beans.Observable; -import javafx.beans.binding.Bindings; -import javafx.scene.control.Label; -import javafx.scene.control.ProgressBar; -import javafx.scene.control.SkinBase; -import javafx.scene.layout.GridPane; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Priority; - -import org.controlsfx.control.StatusBar; - -public class StatusBarSkin extends SkinBase<StatusBar> { - - private HBox leftBox; - private HBox rightBox; - private Label label; - private ProgressBar progressBar; - - public StatusBarSkin(StatusBar statusBar) { - super(statusBar); - - leftBox = new HBox(); - leftBox.getStyleClass().add("left-items"); //$NON-NLS-1$ - - rightBox = new HBox(); - rightBox.getStyleClass().add("right-items"); //$NON-NLS-1$ - - progressBar = new ProgressBar(); - progressBar.progressProperty().bind(statusBar.progressProperty()); - progressBar.visibleProperty().bind( - Bindings.notEqual(0, statusBar.progressProperty())); - - label = new Label(); - label.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); - label.textProperty().bind(statusBar.textProperty()); - label.graphicProperty().bind(statusBar.graphicProperty()); - label.getStyleClass().add("status-label"); //$NON-NLS-1$ - - leftBox.getChildren().setAll(getSkinnable().getLeftItems()); - - rightBox.getChildren().setAll(getSkinnable().getRightItems()); - - statusBar.getLeftItems().addListener( - (Observable evt) -> leftBox.getChildren().setAll( - getSkinnable().getLeftItems())); - - statusBar.getRightItems().addListener( - (Observable evt) -> rightBox.getChildren().setAll( - getSkinnable().getRightItems())); - - GridPane gridPane = new GridPane(); - - GridPane.setFillHeight(leftBox, true); - GridPane.setFillHeight(rightBox, true); - GridPane.setFillHeight(label, true); - GridPane.setFillHeight(progressBar, true); - - GridPane.setVgrow(leftBox, Priority.ALWAYS); - GridPane.setVgrow(rightBox, Priority.ALWAYS); - GridPane.setVgrow(label, Priority.ALWAYS); - GridPane.setVgrow(progressBar, Priority.ALWAYS); - - GridPane.setHgrow(label, Priority.ALWAYS); - - gridPane.add(leftBox, 0, 0); - gridPane.add(label, 1, 0); - gridPane.add(progressBar, 2, 0); - gridPane.add(rightBox, 4, 0); - - getChildren().add(gridPane); - } -} diff --git a/src/impl/org/controlsfx/skin/TaskProgressViewSkin.java b/src/impl/org/controlsfx/skin/TaskProgressViewSkin.java deleted file mode 100644 index 6e6fba6..0000000 --- a/src/impl/org/controlsfx/skin/TaskProgressViewSkin.java +++ /dev/null @@ -1,167 +0,0 @@ -/** - * Copyright (c) 2014, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.skin; - -import javafx.beans.binding.Bindings; -import javafx.concurrent.Task; -import javafx.geometry.Insets; -import javafx.geometry.Pos; -import javafx.scene.Node; -import javafx.scene.control.Button; -import javafx.scene.control.ContentDisplay; -import javafx.scene.control.Label; -import javafx.scene.control.ListCell; -import javafx.scene.control.ListView; -import javafx.scene.control.ProgressBar; -import javafx.scene.control.SkinBase; -import javafx.scene.control.Tooltip; -import javafx.scene.layout.BorderPane; -import javafx.scene.layout.VBox; -import javafx.util.Callback; - -import org.controlsfx.control.TaskProgressView; - -public class TaskProgressViewSkin<T extends Task<?>> extends - SkinBase<TaskProgressView<T>> { - - public TaskProgressViewSkin(TaskProgressView<T> monitor) { - super(monitor); - - BorderPane borderPane = new BorderPane(); - borderPane.getStyleClass().add("box"); - - // list view - ListView<T> listView = new ListView<>(); - listView.setPrefSize(500, 400); - listView.setPlaceholder(new Label("No tasks running")); - listView.setCellFactory(param -> new TaskCell()); - listView.setFocusTraversable(false); - - Bindings.bindContent(listView.getItems(), monitor.getTasks()); - borderPane.setCenter(listView); - - getChildren().add(listView); - } - - class TaskCell extends ListCell<T> { - private ProgressBar progressBar; - private Label titleText; - private Label messageText; - private Button cancelButton; - - private T task; - private BorderPane borderPane; - - public TaskCell() { - titleText = new Label(); - titleText.getStyleClass().add("task-title"); - - messageText = new Label(); - messageText.getStyleClass().add("task-message"); - - progressBar = new ProgressBar(); - progressBar.setMaxWidth(Double.MAX_VALUE); - progressBar.setMaxHeight(8); - progressBar.getStyleClass().add("task-progress-bar"); - - cancelButton = new Button("Cancel"); - cancelButton.getStyleClass().add("task-cancel-button"); - cancelButton.setTooltip(new Tooltip("Cancel Task")); - cancelButton.setOnAction(evt -> { - if (task != null) { - task.cancel(); - } - }); - - VBox vbox = new VBox(); - vbox.setSpacing(4); - vbox.getChildren().add(titleText); - vbox.getChildren().add(progressBar); - vbox.getChildren().add(messageText); - - BorderPane.setAlignment(cancelButton, Pos.CENTER); - BorderPane.setMargin(cancelButton, new Insets(0, 0, 0, 4)); - - borderPane = new BorderPane(); - borderPane.setCenter(vbox); - borderPane.setRight(cancelButton); - setContentDisplay(ContentDisplay.GRAPHIC_ONLY); - } - - @Override - public void updateIndex(int index) { - super.updateIndex(index); - - /* - * I have no idea why this is necessary but it won't work without - * it. Shouldn't the updateItem method be enough? - */ - if (index == -1) { - setGraphic(null); - getStyleClass().setAll("task-list-cell-empty"); - } - } - - @Override - protected void updateItem(T task, boolean empty) { - super.updateItem(task, empty); - - this.task = task; - - if (empty || task == null) { - getStyleClass().setAll("task-list-cell-empty"); - setGraphic(null); - } else if (task != null) { - getStyleClass().setAll("task-list-cell"); - progressBar.progressProperty().bind(task.progressProperty()); - titleText.textProperty().bind(task.titleProperty()); - messageText.textProperty().bind(task.messageProperty()); - cancelButton.disableProperty().bind( - Bindings.not(task.runningProperty())); - - Callback<T, Node> factory = getSkinnable().getGraphicFactory(); - if (factory != null) { - Node graphic = factory.call(task); - if (graphic != null) { - BorderPane.setAlignment(graphic, Pos.CENTER); - BorderPane.setMargin(graphic, new Insets(0, 4, 0, 0)); - borderPane.setLeft(graphic); - } - } else { - /* - * Really needed. The application might have used a graphic - * factory before and then disabled it. In this case the border - * pane might still have an old graphic in the left position. - */ - borderPane.setLeft(null); - } - - setGraphic(borderPane); - } - } - } -} diff --git a/src/impl/org/controlsfx/skin/ToggleSwitchSkin.java b/src/impl/org/controlsfx/skin/ToggleSwitchSkin.java deleted file mode 100644 index e752032..0000000 --- a/src/impl/org/controlsfx/skin/ToggleSwitchSkin.java +++ /dev/null @@ -1,242 +0,0 @@ -/** - * Copyright (c) 2015, 2016 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package impl.org.controlsfx.skin; - -import com.sun.javafx.css.converters.SizeConverter; -import javafx.animation.TranslateTransition; -import javafx.beans.property.DoubleProperty; -import javafx.beans.value.WritableValue; -import javafx.css.CssMetaData; -import javafx.css.Styleable; -import javafx.css.StyleableDoubleProperty; -import javafx.css.StyleableProperty; -import javafx.geometry.Pos; -import javafx.scene.control.Label; -import javafx.scene.control.SkinBase; -import javafx.scene.layout.StackPane; -import javafx.util.Duration; -import org.controlsfx.control.ToggleSwitch; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * Basic Skin implementation for the {@link ToggleSwitch} - */ -public class ToggleSwitchSkin extends SkinBase<ToggleSwitch> -{ - private final StackPane thumb; - private final StackPane thumbArea; - private final Label label; - private final StackPane labelContainer; - private final TranslateTransition transition; - - /** - * Constructor for all ToggleSwitchSkin instances. - * - * @param control The ToggleSwitch for which this Skin should attach to. - */ - public ToggleSwitchSkin(ToggleSwitch control) { - super(control); - - thumb = new StackPane(); - thumbArea = new StackPane(); - label = new Label(); - labelContainer = new StackPane(); - transition = new TranslateTransition(Duration.millis(getThumbMoveAnimationTime()), thumb); - - label.textProperty().bind(control.textProperty()); - getChildren().addAll(labelContainer, thumbArea, thumb); - labelContainer.getChildren().addAll(label); - StackPane.setAlignment(label, Pos.CENTER_LEFT); - - thumb.getStyleClass().setAll("thumb"); - thumbArea.getStyleClass().setAll("thumb-area"); - - thumbArea.setOnMouseReleased(event -> mousePressedOnToggleSwitch(control)); - thumb.setOnMouseReleased(event -> mousePressedOnToggleSwitch(control)); - control.selectedProperty().addListener((observable, oldValue, newValue) -> { - if (newValue.booleanValue() != oldValue.booleanValue()) - selectedStateChanged(); - }); - } - - private void selectedStateChanged() { - if(transition != null){ - transition.stop(); - } - - double thumbAreaWidth = snapSize(thumbArea.prefWidth(-1)); - double thumbWidth = snapSize(thumb.prefWidth(-1)); - double distance = thumbAreaWidth - thumbWidth; - /** - * If we are not selected, we need to go from right to left. - */ - if (!getSkinnable().isSelected()) { - thumb.setLayoutX(thumbArea.getLayoutX()); - transition.setFromX(distance); - transition.setToX(0); - } else { - thumb.setTranslateX(thumbArea.getLayoutX()); - transition.setFromX(0); - transition.setToX(distance); - } - transition.setCycleCount(1); - transition.play(); - } - - private void mousePressedOnToggleSwitch(ToggleSwitch toggleSwitch) { - toggleSwitch.setSelected(!toggleSwitch.isSelected()); - } - - - /** - * How many milliseconds it should take for the thumb to go from - * one edge to the other - */ - private DoubleProperty thumbMoveAnimationTime = null; - - private DoubleProperty thumbMoveAnimationTimeProperty() { - if (thumbMoveAnimationTime == null) { - thumbMoveAnimationTime = new StyleableDoubleProperty(200) { - - @Override - public Object getBean() { - return ToggleSwitchSkin.this; - } - - @Override - public String getName() { - return "thumbMoveAnimationTime"; - } - - @Override - public CssMetaData<ToggleSwitch,Number> getCssMetaData() { - return THUMB_MOVE_ANIMATION_TIME; - } - }; - } - return thumbMoveAnimationTime; - } - - private double getThumbMoveAnimationTime() { - return thumbMoveAnimationTime == null ? 200 : thumbMoveAnimationTime.get(); - } - - @Override - protected void layoutChildren(double contentX, double contentY, double contentWidth, double contentHeight) { - ToggleSwitch toggleSwitch = getSkinnable(); - double thumbWidth = snapSize(thumb.prefWidth(-1)); - double thumbHeight = snapSize(thumb.prefHeight(-1)); - thumb.resize(thumbWidth, thumbHeight); - //We must reset the TranslateX otherwise the thumb is mis-aligned when window is resized. - if (transition != null) { - transition.stop(); - } - thumb.setTranslateX(0); - - double thumbAreaY = snapPosition(contentY); - double thumbAreaWidth = snapSize(thumbArea.prefWidth(-1)); - double thumbAreaHeight = snapSize(thumbArea.prefHeight(-1)); - - thumbArea.resize(thumbAreaWidth, thumbAreaHeight); - thumbArea.setLayoutX(contentWidth - thumbAreaWidth); - thumbArea.setLayoutY(thumbAreaY); - - labelContainer.resize(contentWidth - thumbAreaWidth, thumbAreaHeight); - labelContainer.setLayoutY(thumbAreaY); - - if (!toggleSwitch.isSelected()) - thumb.setLayoutX(thumbArea.getLayoutX()); - else - thumb.setLayoutX(thumbArea.getLayoutX() + thumbAreaWidth - thumbWidth); - thumb.setLayoutY(thumbAreaY + (thumbAreaHeight - thumbHeight) / 2); - } - - - @Override protected double computeMinWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) { - return leftInset + label.prefWidth(-1) + thumbArea.prefWidth(-1) + rightInset; - } - - @Override protected double computeMinHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { - return topInset + Math.max(thumb.prefHeight(-1), label.prefHeight(-1)) + bottomInset; - } - - @Override protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) { - return leftInset + label.prefWidth(-1) + 20 + thumbArea.prefWidth(-1) + rightInset; - } - - @Override protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { - return topInset + Math.max(thumb.prefHeight(-1), label.prefHeight(-1)) + bottomInset; - } - - private static final CssMetaData<ToggleSwitch, Number> THUMB_MOVE_ANIMATION_TIME = - new CssMetaData<ToggleSwitch, Number>("-thumb-move-animation-time", - SizeConverter.getInstance(), 200) { - - @Override - public boolean isSettable(ToggleSwitch toggleSwitch) { - final ToggleSwitchSkin skin = (ToggleSwitchSkin) toggleSwitch.getSkin(); - return skin.thumbMoveAnimationTime == null || - !skin.thumbMoveAnimationTime.isBound(); - } - - @Override - public StyleableProperty<Number> getStyleableProperty(ToggleSwitch toggleSwitch) { - final ToggleSwitchSkin skin = (ToggleSwitchSkin) toggleSwitch.getSkin(); - return (StyleableProperty<Number>) (WritableValue<Number>) skin.thumbMoveAnimationTimeProperty(); - } - }; - - private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES; - - static { - final List<CssMetaData<? extends Styleable, ?>> styleables = - new ArrayList<CssMetaData<? extends Styleable, ?>>(SkinBase.getClassCssMetaData()); - styleables.add(THUMB_MOVE_ANIMATION_TIME); - STYLEABLES = Collections.unmodifiableList(styleables); - } - - /** - * @return The CssMetaData associated with this class, which may include the - * CssMetaData of its super classes. - */ - public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() { - return STYLEABLES; - } - - /** - * {@inheritDoc} - */ - @Override - public List<CssMetaData<? extends Styleable, ?>> getCssMetaData() { - return getClassCssMetaData(); - } -} - diff --git a/src/impl/org/controlsfx/spreadsheet/CellView.java b/src/impl/org/controlsfx/spreadsheet/CellView.java deleted file mode 100644 index 591e1eb..0000000 --- a/src/impl/org/controlsfx/spreadsheet/CellView.java +++ /dev/null @@ -1,659 +0,0 @@ -/** - * Copyright (c) 2013, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.spreadsheet; - -import java.util.Objects; -import java.util.Optional; -import java.util.logging.Logger; -import javafx.animation.FadeTransition; -import javafx.application.Platform; -import javafx.beans.binding.When; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.beans.value.WeakChangeListener; -import javafx.collections.ObservableList; -import javafx.collections.SetChangeListener; -import javafx.collections.WeakSetChangeListener; -import javafx.event.EventHandler; -import javafx.event.WeakEventHandler; -import javafx.scene.Node; -import javafx.scene.control.ContentDisplay; -import javafx.scene.control.Control; -import javafx.scene.control.SelectionMode; -import javafx.scene.control.TableCell; -import javafx.scene.control.TablePositionBase; -import javafx.scene.control.TableView; -import javafx.scene.control.TableView.TableViewFocusModel; -import javafx.scene.control.TableView.TableViewSelectionModel; -import javafx.scene.control.Tooltip; -import javafx.scene.image.ImageView; -import javafx.scene.input.DragEvent; -import javafx.scene.input.Dragboard; -import javafx.scene.input.MouseButton; -import javafx.scene.input.MouseEvent; -import javafx.scene.input.TransferMode; -import javafx.scene.layout.Region; -import javafx.util.Duration; -import org.controlsfx.control.spreadsheet.Grid; -import org.controlsfx.control.spreadsheet.SpreadsheetCell; -import org.controlsfx.control.spreadsheet.SpreadsheetCellEditor; -import org.controlsfx.control.spreadsheet.SpreadsheetCellType; -import org.controlsfx.control.spreadsheet.SpreadsheetView; - -/** - * - * The View cell that will be visible on screen. It holds the - * {@link SpreadsheetCell}. - */ -public class CellView extends TableCell<ObservableList<SpreadsheetCell>, SpreadsheetCell> { - private final SpreadsheetHandle handle; - /** - * Because we don't want to recreate Tooltip each time the TableCell is - * re-used. We save it properly here so we avoid recreating it each time - * since it's really time-consuming. - */ - private Tooltip tooltip; - - /*************************************************************************** - * * Static Fields * * - **************************************************************************/ - private static final String ANCHOR_PROPERTY_KEY = "table.anchor"; //$NON-NLS-1$ - private static final int TOOLTIP_MAX_WIDTH = 400; - private static final Duration FADE_DURATION = Duration.millis(200); - - static TablePositionBase<?> getAnchor(Control table, TablePositionBase<?> focusedCell) { - return hasAnchor(table) ? (TablePositionBase<?>) table.getProperties().get(ANCHOR_PROPERTY_KEY) : focusedCell; - } - - static boolean hasAnchor(Control table) { - return table.getProperties().get(ANCHOR_PROPERTY_KEY) != null; - } - - static void setAnchor(Control table, TablePositionBase anchor) { - if (table != null && anchor == null) { - removeAnchor(table); - } else { - table.getProperties().put(ANCHOR_PROPERTY_KEY, anchor); - } - } - - static void removeAnchor(Control table) { - table.getProperties().remove(ANCHOR_PROPERTY_KEY); - } - /*************************************************************************** - * * Constructor * * - **************************************************************************/ - public CellView(SpreadsheetHandle handle) { - this.handle = handle; - // When we detect a drag, we start the Full Drag so that other event - // will be fired - this.addEventHandler(MouseEvent.DRAG_DETECTED, new WeakEventHandler<>(startFullDragEventHandler)); - setOnMouseDragEntered(new WeakEventHandler<>(dragMouseEventHandler)); - - itemProperty().addListener(itemChangeListener); - - setOnMousePressed(new EventHandler<MouseEvent>() { - @Override - public void handle(MouseEvent event) { - getTableView().fireEvent(event); - } - }); - - } - - /*************************************************************************** - * * Public Methods * * - **************************************************************************/ - @Override - public void startEdit() { - if (!isEditable()) { - getTableView().edit(-1, null); - return; - } - /** - * If this CellView has no parent, this means that it was stacked into - * the cellsMap of the GridRowSkin, but the weakRef was dropped. So this - * CellView is still reacting to events, but it's not part of the - * sceneGraph! So we must deactivate this cell and let the real Cell in - * the sceneGraph take the edition. - */ - if(getParent() == null){ - updateTableView(null); - updateTableRow(null); - updateTableColumn(null); - return; - } - final int column = this.getTableView().getColumns().indexOf(this.getTableColumn()); - final int row = getIndex(); - // We start to edit only if the Cell is a normal Cell (aka visible). - final SpreadsheetView spv = handle.getView(); - final Grid grid = spv.getGrid(); - final SpreadsheetView.SpanType type = grid.getSpanType(spv, row, column); - //FIXME with the reverse algorithm in virtualFlow, is this still necessary? - if (type == SpreadsheetView.SpanType.NORMAL_CELL || type == SpreadsheetView.SpanType.ROW_VISIBLE) { - - /** - * We may come to the situation where this method is called two - * times. One time by the row inside the VirtualFlow. And another by - * the row inside myFixedCells used by our GridVirtualFlow. - * - * In that case, we have to give priority to the one used by the - * VirtualFlow. So we just check if the row is managed. If not, we - * know for sure that the our GridVirtualFlow has stepped out. - */ - if (!getTableRow().isManaged()) { - return; - } - - GridCellEditor editor = getEditor(getItem(), spv); - if (editor != null) { - super.startEdit(); - setContentDisplay(ContentDisplay.GRAPHIC_ONLY); - editor.startEdit(); - }else{ - getTableView().edit(-1, null); - } - } - } - - @Override - public void commitEdit(SpreadsheetCell newValue) { - //When commiting, we bring the value smoothly. - FadeTransition fadeTransition = new FadeTransition(FADE_DURATION, this); - fadeTransition.setFromValue(0); - fadeTransition.setToValue(1); - fadeTransition.play(); - - if (!isEditing()) { - return; - } - super.commitEdit(newValue); - - setContentDisplay(ContentDisplay.LEFT); - updateItem(newValue, false); - - if (getTableView() != null) { - getTableView().requestFocus(); - } - } - - @Override - public void cancelEdit() { - if (!isEditing()) { - return; - } - - super.cancelEdit(); - - setContentDisplay(ContentDisplay.LEFT); - updateItem(getItem(), false); - - if (getTableView() != null) { - getTableView().requestFocus(); - } - } - - @Override - public void updateItem(final SpreadsheetCell item, boolean empty) { - final boolean emptyRow = getTableView().getItems().size() < getIndex() + 1; - /** - * don't call super.updateItem() because it will trigger cancelEdit() if - * the cell is being edited. It causes calling commitEdit() ALWAYS call - * cancelEdit as well which is undesired. - * - */ - if (!isEditing()) { - super.updateItem(item, empty && emptyRow); - } - if (empty && isSelected()) { - updateSelected(false); - } - if (empty && emptyRow) { - textProperty().unbind(); - setText(null); - // do not nullify graphic here. Let the TableRow to control cell - // dislay - // setGraphic(null); - setContentDisplay(null); - } else if (!isEditing() && item != null) { - show(item); - if (item.getGraphic() == null) { - setGraphic(null); - } - } - } - - /** - * Called in the gridRowSkinBase when doing layout This allow not to - * override opacity in the row and let the cell handle itself - * @param cell - */ - public void show(final SpreadsheetCell cell) { - // We reset the settings - textProperty().bind(cell.textProperty()); - setCellGraphic(cell); - - Optional<String> tooltipText = cell.getTooltip(); - String trimTooltip = tooltipText.isPresent() ? tooltipText.get().trim() : null; - - if (trimTooltip != null && !trimTooltip.isEmpty()) { - /** - * Here we check if the Tooltip has not been created in order NOT TO - * re-create it for nothing as it is a really time-consuming - * operation. - */ - Tooltip localTooltip = getAvailableTooltip(); - if (localTooltip != null) { - if (!Objects.equals(localTooltip.getText(), trimTooltip)) { - getTooltip().setText(trimTooltip); - } - } else { - /** - * Ensure that modification of ToolTip are set on the JFX thread - * because an exception can be thrown otherwise. - */ - getValue(() -> { - Tooltip newTooltip = new Tooltip(tooltipText.get()); - newTooltip.setWrapText(true); - newTooltip.setMaxWidth(TOOLTIP_MAX_WIDTH); - setTooltip(newTooltip); - } - ); - } - } else { - //We save that tooltip - if(getTooltip() != null){ - tooltip = getTooltip(); - } - setTooltip(null); - } - - setWrapText(cell.isWrapText()); - - setEditable(cell.isEditable()); - - if (cell.getCellType().acceptDrop()) { - setOnDragOver(new EventHandler<DragEvent>() { - - @Override - public void handle(DragEvent event) { - Dragboard db = event.getDragboard(); - if (db.hasFiles()) { - event.acceptTransferModes(TransferMode.ANY); - } else { - event.consume(); - } - } - }); - // Dropping over surface - setOnDragDropped(new EventHandler<DragEvent>() { - @Override - public void handle(DragEvent event) { - Dragboard db = event.getDragboard(); - boolean success = false; - if (db.hasFiles() && db.getFiles().size() == 1) { - if (getItem().getCellType().match(db.getFiles().get(0))) { - handle.getView().getGrid().setCellValue(getItem().getRow(), getItem().getColumn(), - getItem().getCellType().convertValue(db.getFiles().get(0))); - success = true; - } - } - event.setDropCompleted(success); - event.consume(); - } - }); - } else { - setOnDragOver(null); - setOnDragDropped(null); - } - } - - /*************************************************************************** - * * Private Methods * * - **************************************************************************/ - - /** - * See if a tootlip is available (either on the TableCell already, or in the - * Stack). And then set it to the TableCell. - * - * @return - */ - private Tooltip getAvailableTooltip(){ - if(getTooltip() != null){ - return getTooltip(); - } - if(tooltip != null){ - setTooltip(tooltip); - return tooltip; - } - return null; - } - - private void setCellGraphic(SpreadsheetCell item) { - - if (isEditing()) { - return; - } - Node graphic = item.getGraphic(); - if (graphic != null) { - /** - * This workaround is added for the first row containing a graphic - * because for an unknown reason, the graphic is translated to a - * negative value so it's not fully visible. So we add those - * listener that watch those changes, and try to get the previous - * value (the right one) if the new value goes out of bounds. - */ -// if (item.getRow() == 0) { -// graphic.layoutXProperty().removeListener(firstRowLayoutXListener); -// graphic.layoutXProperty().addListener(firstRowLayoutXListener); -// -// graphic.layoutYProperty().removeListener(firstRowLayoutYListener); -// graphic.layoutYProperty().addListener(firstRowLayoutYListener); -// } - - if (graphic instanceof ImageView) { - ImageView image = (ImageView) graphic; - image.setCache(true); - image.setPreserveRatio(true); - image.setSmooth(true); - if(image.getImage() != null){ - image.fitHeightProperty().bind( - new When(heightProperty().greaterThan(image.getImage().getHeight())).then( - image.getImage().getHeight()).otherwise(heightProperty())); - image.fitWidthProperty().bind( - new When(widthProperty().greaterThan(image.getImage().getWidth())).then( - image.getImage().getWidth()).otherwise(widthProperty())); - } - /** - * If we have a Region and no text, we force it to take full - * space. But we want to impact the minSize in order to let the - * prefSize to be computed if necessary. - */ - } else if (graphic instanceof Region && item.getItem() == null) { - Region region = (Region) graphic; - region.minHeightProperty().bind(heightProperty()); - region.minWidthProperty().bind(widthProperty()); - } - setGraphic(graphic); - /** - * In case of a resize of the column, we have new cells that steal - * the image from the original TableCell. So we check here if we are - * not in that case so that the Graphic of the SpreadsheetCell will - * always be on the latest tableView and therefore fully visible. - */ - if (!getChildren().contains(graphic)) { - getChildren().add(graphic); - } - } else { - setGraphic(null); - } - } - -// private final ChangeListener<Number> firstRowLayoutXListener = new ChangeListener<Number>() { -// @Override -// public void changed(ObservableValue<? extends Number> ov, Number oldLayoutX, Number newLayoutX) { -// if (getItem() != null && getItem().getGraphic() != null && newLayoutX.doubleValue() < 0 && oldLayoutX != null) { -// getItem().getGraphic().setLayoutX(oldLayoutX.doubleValue()); -// } -// } -// }; -// -// private final ChangeListener<Number> firstRowLayoutYListener = new ChangeListener<Number>() { -// @Override -// public void changed(ObservableValue<? extends Number> ov, Number oldLayoutY, Number newLayoutY) { -// if (getItem() != null && getItem().getGraphic() != null && newLayoutY.doubleValue() < 0 && oldLayoutY != null) { -// getItem().getGraphic().setLayoutY(oldLayoutY.doubleValue()); -// } -// } -// }; - - /** - * Return an instance of Editor specific to the Cell type We are not using - * the build-in editor-Cell because we cannot know in advance which editor - * we will need. Furthermore, we want to control the behavior very closely - * in regards of the spanned cell (invisible etc). - * - * @param cell - * The SpreadsheetCell - * @param bc - * The SpreadsheetCell - * @return - */ - private GridCellEditor getEditor(final SpreadsheetCell cell, final SpreadsheetView spv) { - SpreadsheetCellType<?> cellType = cell.getCellType(); - Optional<SpreadsheetCellEditor> cellEditor = spv.getEditor(cellType); - - if (cellEditor.isPresent()) { - GridCellEditor editor = handle.getCellsViewSkin().getSpreadsheetCellEditorImpl(); - /** - * Sometimes, we end up here with the editor already editing. But - * this case should not happen. If a cell is calling startEdit, - * this means we want to edit the cell and the editor should not be - * editing another cell. So we just cancel the edition and give the - * editor to the cell because we may not be able to edit anything. - */ - if (editor.isEditing()) { - if (editor.getModelCell() != null) { - StringBuilder builder = new StringBuilder(); - builder.append("The cell at row ").append(editor.getModelCell().getRow()) - .append(" and column ").append(editor.getModelCell().getColumn()) - .append(" was in edition and cell at row ").append(cell.getRow()) - .append(" and column ").append(cell.getColumn()) - .append(" requested edition. This situation should not happen as the previous cell should not be in edition."); - Logger.getLogger("root").warning(builder.toString()); - } - - editor.endEdit(false); - } - - editor.updateSpreadsheetCell(this); - editor.updateDataCell(cell); - editor.updateSpreadsheetCellEditor(cellEditor.get()); - return editor; - } else { - return null; - } - } - - private final ChangeListener<Node> graphicListener = new ChangeListener<Node>() { - @Override - public void changed(ObservableValue<? extends Node> arg0, Node arg1, Node newGraphic) { - setCellGraphic(getItem()); - } - }; - - private final WeakChangeListener<Node> weakGraphicListener = new WeakChangeListener<>(graphicListener); - - private final SetChangeListener<String> styleClassListener = new SetChangeListener<String>() { - @Override - public void onChanged(javafx.collections.SetChangeListener.Change<? extends String> arg0) { - if (arg0.wasAdded()) { - getStyleClass().add(arg0.getElementAdded()); - } else if (arg0.wasRemoved()) { - getStyleClass().remove(arg0.getElementRemoved()); - } - } - }; - - private final WeakSetChangeListener<String> weakStyleClassListener = new WeakSetChangeListener<>(styleClassListener); - - //Listeners for the styles, not initialized by default in order not to impact performance - private ChangeListener<String> styleListener; - private WeakChangeListener<String> weakStyleListener; - - /** - * Method that will select all the cells between the drag place and that - * cell. - * - * @param e - */ - private void dragSelect(MouseEvent e) { - // If the mouse event is not contained within this tableCell, then - // we don't want to react to it. - if (!this.contains(e.getX(), e.getY())) { - return; - } - final TableView<ObservableList<SpreadsheetCell>> tableView = getTableView(); - if (tableView == null) { - return; - } - - final int count = tableView.getItems().size(); - if (getIndex() >= count) { - return; - } - - final TableViewSelectionModel<ObservableList<SpreadsheetCell>> sm = tableView.getSelectionModel(); - if (sm == null) { - return; - } - - final int row = getIndex(); - final int column = tableView.getVisibleLeafIndex(getTableColumn()); - - // For spanned Cells - final SpreadsheetCell cell = (SpreadsheetCell) getItem(); - final int rowCell = cell.getRow() + cell.getRowSpan() - 1; - final int columnCell = cell.getColumn() + cell.getColumnSpan() - 1; - - final TableViewFocusModel<?> fm = tableView.getFocusModel(); - if (fm == null) { - return; - } - - final TablePositionBase<?> focusedCell = fm.getFocusedCell(); - final MouseButton button = e.getButton(); - if (button == MouseButton.PRIMARY) { - // we add all cells/rows between the current selection focus and - // this cell/row (inclusive) to the current selection. - final TablePositionBase<?> anchor = getAnchor(tableView, focusedCell); - - /** - * FIXME We need to clarify how we want to select the cells. If a - * spanned cell is in the way, which minRow/maxRow will be taken? - * Where the mouse is exactly? Or where the "motherCell" is? This - * needs some thinking. - */ - // and then determine all row and columns which must be selected - int minRow = Math.min(anchor.getRow(), row); - minRow = Math.min(minRow, rowCell); - int maxRow = Math.max(anchor.getRow(), row); - maxRow = Math.max(maxRow, rowCell); - int minColumn = Math.min(anchor.getColumn(), column); - minColumn = Math.min(minColumn, columnCell); - int maxColumn = Math.max(anchor.getColumn(), column); - maxColumn = Math.max(maxColumn, columnCell); - - // clear selection, but maintain the anchor - if (!e.isShortcutDown()) - sm.clearSelection(); - if (minColumn != -1 && maxColumn != -1) - sm.selectRange(minRow, tableView.getColumns().get(minColumn), maxRow, - tableView.getColumns().get(maxColumn)); - setAnchor(tableView, anchor); - } - - } - - /** - * Will safely execute the request on the JFX thread by checking whether we - * are on the JFX thread or not. - * - * @param runnable - */ - public static void getValue(final Runnable runnable) { - if (Platform.isFxApplicationThread()) { - runnable.run(); - } else { - Platform.runLater(runnable); - } - } - - @Override - protected javafx.scene.control.Skin<?> createDefaultSkin() { - return new CellViewSkin(this); - }; - - private final EventHandler<MouseEvent> startFullDragEventHandler = new EventHandler<MouseEvent>() { - @Override - public void handle(MouseEvent arg0) { - if (handle.getGridView().getSelectionModel().getSelectionMode().equals(SelectionMode.MULTIPLE)) { - setAnchor(getTableView(), getTableView().getFocusModel().getFocusedCell()); - startFullDrag(); - } - } - }; - - private final EventHandler<MouseEvent> dragMouseEventHandler = new EventHandler<MouseEvent>() { - @Override - public void handle(MouseEvent arg0) { - dragSelect(arg0); - } - }; - - private final ChangeListener<SpreadsheetCell> itemChangeListener = new ChangeListener<SpreadsheetCell>() { - - @Override - public void changed(ObservableValue<? extends SpreadsheetCell> arg0, SpreadsheetCell oldItem, - SpreadsheetCell newItem) { - if (oldItem != null) { - oldItem.getStyleClass().removeListener(weakStyleClassListener); - oldItem.graphicProperty().removeListener(weakGraphicListener); - - if(oldItem.styleProperty() != null){ - oldItem.styleProperty().removeListener(weakStyleListener); - } - } - if (newItem != null) { - getStyleClass().clear(); - getStyleClass().setAll(newItem.getStyleClass()); - - newItem.getStyleClass().addListener(weakStyleClassListener); - setCellGraphic(newItem); - newItem.graphicProperty().addListener(weakGraphicListener); - - if(newItem.styleProperty() != null){ - initStyleListener(); - newItem.styleProperty().addListener(weakStyleListener); - setStyle(newItem.getStyle()); - }else{ - //We clear the previous style. - setStyle(null); - } - } - } - }; - - private void initStyleListener(){ - if(styleListener == null){ - styleListener = (ObservableValue<? extends String> observable, String oldValue, String newValue) -> { - styleProperty().set(newValue); - }; - } - weakStyleListener = new WeakChangeListener<>(styleListener); - } -} diff --git a/src/impl/org/controlsfx/spreadsheet/CellViewSkin.java b/src/impl/org/controlsfx/spreadsheet/CellViewSkin.java deleted file mode 100644 index a41ff3d..0000000 --- a/src/impl/org/controlsfx/spreadsheet/CellViewSkin.java +++ /dev/null @@ -1,224 +0,0 @@ -/** - * Copyright (c) 2013, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.spreadsheet; - -import com.sun.javafx.scene.control.skin.TableCellSkin; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.beans.value.WeakChangeListener; -import javafx.collections.ObservableList; -import javafx.event.Event; -import javafx.event.EventHandler; -import javafx.event.WeakEventHandler; -import javafx.scene.Node; -import javafx.scene.control.TableCell; -import javafx.scene.image.ImageView; -import javafx.scene.layout.Region; -import org.controlsfx.control.spreadsheet.SpreadsheetCell; -import org.controlsfx.control.spreadsheet.SpreadsheetCell.CornerPosition; - -/** - * - * This is the skin for the {@link CellView}. - * - * Its main goal is to draw an object (a triangle) on cells which have their - * {@link SpreadsheetCell#commentedProperty()} set to true. - * - */ -public class CellViewSkin extends TableCellSkin<ObservableList<SpreadsheetCell>, SpreadsheetCell> { - - private final static String TOP_LEFT_CLASS = "top-left"; //$NON-NLS-1$ - private final static String TOP_RIGHT_CLASS = "top-right"; //$NON-NLS-1$ - private final static String BOTTOM_RIGHT_CLASS = "bottom-right"; //$NON-NLS-1$ - private final static String BOTTOM_LEFT_CLASS = "bottom-left"; //$NON-NLS-1$ - /** - * The size of the edge of the triangle FIXME Handling of static variable - * will be changed. - */ - private static final int TRIANGLE_SIZE = 8; - /** - * The region we will add on the cell when necessary. - */ - private Region topLeftRegion = null; - private Region topRightRegion = null; - private Region bottomRightRegion = null; - private Region bottomLeftRegion = null; - - public CellViewSkin(TableCell<ObservableList<SpreadsheetCell>, SpreadsheetCell> tableCell) { - super(tableCell); - tableCell.itemProperty().addListener(weakItemChangeListener); - if (tableCell.getItem() != null) { - tableCell.getItem().addEventHandler(SpreadsheetCell.CORNER_EVENT_TYPE, weakTriangleEventHandler); - } - } - - @Override - protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { - /** - * If we have an Image in the Cell, its fitHeight will be affected by - * the cell height (see CellView). But during calculation for autofit - * option, we want to know the real prefHeight of this cell. Apparently, - * the fitHeight option is returned by default so we must override and - * return the Height of the image inside. - */ - Node graphic = getSkinnable().getGraphic(); - if (graphic != null && graphic instanceof ImageView) { - ImageView view = (ImageView) graphic; - if (view.getImage() != null) { - return view.getImage().getHeight(); - } - } - return super.computePrefHeight(width, topInset, rightInset, bottomInset, leftInset); - } - - @Override - protected void layoutChildren(double x, final double y, final double w, final double h) { - super.layoutChildren(x, y, w, h); - if (getSkinnable().getItem() != null) { - layoutTriangle(); - } - } - - private void layoutTriangle() { - SpreadsheetCell cell = getSkinnable().getItem(); - - handleTopLeft(cell); - handleTopRight(cell); - handleBottomLeft(cell); - handleBottomRight(cell); - - getSkinnable().requestLayout(); - } - - private void handleTopLeft(SpreadsheetCell cell) { - if (cell.isCornerActivated(CornerPosition.TOP_LEFT)) { - if (topLeftRegion == null) { - topLeftRegion = getRegion(CornerPosition.TOP_LEFT); - } - if (!getChildren().contains(topLeftRegion)) { - getChildren().add(topLeftRegion); - } - topLeftRegion.relocate(0, snappedTopInset() - 1); - } else if (topLeftRegion != null) { - getChildren().remove(topLeftRegion); - topLeftRegion = null; - } - } - - private void handleTopRight(SpreadsheetCell cell) { - if (cell.isCornerActivated(CornerPosition.TOP_RIGHT)) { - if (topRightRegion == null) { - topRightRegion = getRegion(CornerPosition.TOP_RIGHT); - } - if (!getChildren().contains(topRightRegion)) { - getChildren().add(topRightRegion); - } - topRightRegion.relocate(getSkinnable().getWidth() - TRIANGLE_SIZE, snappedTopInset() - 1); - } else if (topRightRegion != null) { - getChildren().remove(topRightRegion); - topRightRegion = null; - } - } - - private void handleBottomRight(SpreadsheetCell cell) { - if (cell.isCornerActivated(CornerPosition.BOTTOM_RIGHT)) { - if (bottomRightRegion == null) { - bottomRightRegion = getRegion(CornerPosition.BOTTOM_RIGHT); - } - if (!getChildren().contains(bottomRightRegion)) { - getChildren().add(bottomRightRegion); - } - bottomRightRegion.relocate(getSkinnable().getWidth() - TRIANGLE_SIZE, getSkinnable().getHeight() - TRIANGLE_SIZE); - } else if (bottomRightRegion != null) { - getChildren().remove(bottomRightRegion); - bottomRightRegion = null; - } - } - private void handleBottomLeft(SpreadsheetCell cell) { - if (cell.isCornerActivated(CornerPosition.BOTTOM_LEFT)) { - if (bottomLeftRegion == null) { - bottomLeftRegion = getRegion(CornerPosition.BOTTOM_LEFT); - } - if (!getChildren().contains(bottomLeftRegion)) { - getChildren().add(bottomLeftRegion); - } - bottomLeftRegion.relocate(0, getSkinnable().getHeight() - TRIANGLE_SIZE); - } else if (bottomLeftRegion != null) { - getChildren().remove(bottomLeftRegion); - bottomLeftRegion = null; - } - } - - private static Region getRegion(CornerPosition position) { - Region region = new Region(); - region.resize(TRIANGLE_SIZE, TRIANGLE_SIZE); - region.getStyleClass().add("cell-corner"); //$NON-NLS-1$ - switch (position) { - case TOP_LEFT: - region.getStyleClass().add(TOP_LEFT_CLASS); - break; - case TOP_RIGHT: - region.getStyleClass().add(TOP_RIGHT_CLASS); - break; - case BOTTOM_RIGHT: - region.getStyleClass().add(BOTTOM_RIGHT_CLASS); - break; - case BOTTOM_LEFT: - region.getStyleClass().add(BOTTOM_LEFT_CLASS); - break; - - } - - return region; - } - - private final EventHandler<Event> triangleEventHandler = new EventHandler<Event>() { - - @Override - public void handle(Event event) { - getSkinnable().requestLayout(); - } - }; - private final WeakEventHandler weakTriangleEventHandler = new WeakEventHandler(triangleEventHandler); - - private final ChangeListener<SpreadsheetCell> itemChangeListener = new ChangeListener<SpreadsheetCell>() { - @Override - public void changed(ObservableValue<? extends SpreadsheetCell> arg0, SpreadsheetCell oldCell, - SpreadsheetCell newCell) { - if (oldCell != null) { - oldCell.removeEventHandler(SpreadsheetCell.CORNER_EVENT_TYPE, weakTriangleEventHandler); - } - if (newCell != null) { - newCell.addEventHandler(SpreadsheetCell.CORNER_EVENT_TYPE, weakTriangleEventHandler); - } - if (getSkinnable().getItem() != null) { - layoutTriangle(); - } - } - }; - private final WeakChangeListener<SpreadsheetCell> weakItemChangeListener = new WeakChangeListener<>(itemChangeListener); -} diff --git a/src/impl/org/controlsfx/spreadsheet/FocusModelListener.java b/src/impl/org/controlsfx/spreadsheet/FocusModelListener.java deleted file mode 100644 index a359fb2..0000000 --- a/src/impl/org/controlsfx/spreadsheet/FocusModelListener.java +++ /dev/null @@ -1,142 +0,0 @@ -/** - * Copyright (c) 2013, 2014 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.spreadsheet; - -import javafx.application.Platform; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.collections.ObservableList; -import javafx.scene.control.TableColumn; -import javafx.scene.control.TablePosition; -import javafx.scene.control.TableView; -import org.controlsfx.control.spreadsheet.SpreadsheetCell; -import org.controlsfx.control.spreadsheet.SpreadsheetView; - -/** - * - * The FocusModel Listener adapted to the SpreadsheetView regarding Span. - */ -public class FocusModelListener implements ChangeListener<TablePosition<ObservableList<SpreadsheetCell>, ?>> { - - private final TableView.TableViewFocusModel<ObservableList<SpreadsheetCell>> tfm; - private final SpreadsheetGridView cellsView; - private final SpreadsheetView spreadsheetView; - - /** - * Constructor. - * - * @param spreadsheetView - * @param cellsView - */ - public FocusModelListener(SpreadsheetView spreadsheetView, SpreadsheetGridView cellsView) { - tfm = cellsView.getFocusModel(); - this.spreadsheetView = spreadsheetView; - this.cellsView = cellsView; - } - - @Override - public void changed(ObservableValue<? extends TablePosition<ObservableList<SpreadsheetCell>, ?>> ov, - final TablePosition<ObservableList<SpreadsheetCell>, ?> oldPosition, - final TablePosition<ObservableList<SpreadsheetCell>, ?> newPosition) { - final SpreadsheetView.SpanType spanType = spreadsheetView.getSpanType(newPosition.getRow(), newPosition.getColumn()); - switch (spanType) { - case ROW_SPAN_INVISIBLE: - // If we notice that the new focused cell is the previous one, - // then it means that we were - // already on the cell and we wanted to go below. - if (!spreadsheetView.isPressed() && oldPosition.getColumn() == newPosition.getColumn() && oldPosition.getRow() == newPosition.getRow() - 1) { - Platform.runLater(() -> { - tfm.focus(getNextRowNumber(oldPosition, cellsView), oldPosition.getTableColumn()); - }); - - } else { - // If the current focused cell if hidden by row span, we go - // above - Platform.runLater(() -> { - tfm.focus(newPosition.getRow() - 1, newPosition.getTableColumn()); - }); - } - - break; - case BOTH_INVISIBLE: - // If the current focused cell if hidden by a both (row and - // column) span, we go left-above - Platform.runLater(() -> { - tfm.focus(newPosition.getRow() - 1, cellsView.getColumns().get(newPosition.getColumn() - 1)); - }); - break; - case COLUMN_SPAN_INVISIBLE: - // If we notice that the new focused cell is the previous one, - // then it means that we were - // already on the cell and we wanted to go right. - if (!spreadsheetView.isPressed() && oldPosition.getColumn() == newPosition.getColumn() - 1 && oldPosition.getRow() == newPosition.getRow()) { - - Platform.runLater(() -> { - tfm.focus(oldPosition.getRow(), getTableColumnSpan(oldPosition, cellsView)); - }); - } else { - // If the current focused cell if hidden by column span, we - // go left - - Platform.runLater(() -> { - tfm.focus(newPosition.getRow(), cellsView.getColumns().get(newPosition.getColumn() - 1)); - }); - } - default: - break; - } - } - - /** - * Return the TableColumn right after the current TablePosition (including - * the ColumSpan to be on a visible Cell) - * - * @param t the current TablePosition - * @return - */ - static TableColumn<ObservableList<SpreadsheetCell>, ?> getTableColumnSpan(final TablePosition<?, ?> t, SpreadsheetGridView cellsView) { - return cellsView.getVisibleLeafColumn(t.getColumn() - + cellsView.getItems().get(t.getRow()).get(t.getColumn()).getColumnSpan()); - } - - /** - * Return the Row number right after the current TablePosition (including - * the RowSpan to be on a visible Cell) - * - * @param pos - * @param cellsView - * @return - */ - public static int getNextRowNumber(final TablePosition<?, ?> pos, TableView<ObservableList<SpreadsheetCell>> cellsView) { - return cellsView.getItems().get(pos.getRow()).get(pos.getColumn()).getRowSpan() - + cellsView.getItems().get(pos.getRow()).get(pos.getColumn()).getRow(); - } - - public static int getPreviousRowNumber(final TablePosition<?, ?> pos, TableView<ObservableList<SpreadsheetCell>> cellsView) { - return cellsView.getItems().get(pos.getRow()).get(pos.getColumn()).getRow() -1; - } -} diff --git a/src/impl/org/controlsfx/spreadsheet/GridCellEditor.java b/src/impl/org/controlsfx/spreadsheet/GridCellEditor.java deleted file mode 100644 index bf5c01a..0000000 --- a/src/impl/org/controlsfx/spreadsheet/GridCellEditor.java +++ /dev/null @@ -1,271 +0,0 @@ -/** - * Copyright (c) 2013, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.spreadsheet; - -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; -import javafx.beans.binding.Bindings; -import javafx.beans.binding.BooleanExpression; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.event.EventHandler; -import javafx.scene.Node; -import javafx.scene.control.Control; -import javafx.scene.control.TextArea; -import javafx.scene.input.KeyCode; -import javafx.scene.input.KeyEvent; - -import org.controlsfx.control.spreadsheet.SpreadsheetCell; -import org.controlsfx.control.spreadsheet.SpreadsheetCellEditor; -import org.controlsfx.control.spreadsheet.SpreadsheetCellType; -import org.controlsfx.control.spreadsheet.SpreadsheetView; - -public class GridCellEditor { - - /*************************************************************************** - * * Protected/Private Fields * * - **************************************************************************/ - - private final SpreadsheetHandle handle; - // transient properties - these fields will change based on the current - // cell being edited. - private SpreadsheetCell modelCell; - private CellView viewCell; - private BooleanExpression focusProperty; - - private boolean editing = false; - - //The cell's editor - private SpreadsheetCellEditor spreadsheetCellEditor; - - //The last key pressed in order to select cell below if it was "enter" - private KeyCode lastKeyPressed; - - /*************************************************************************** - * * Constructor * * - **************************************************************************/ - - /** - * Construct the GridCellEditor. - */ - public GridCellEditor(SpreadsheetHandle handle) { - this.handle = handle; - } - - /*************************************************************************** - * * Public Methods * * - **************************************************************************/ - /** - * Update the internal {@link SpreadsheetCell}. - * - * @param cell - */ - public void updateDataCell(SpreadsheetCell cell) { - this.modelCell = cell; - } - - /** - * Update the internal {@link CellView} - * - * @param cell - */ - public void updateSpreadsheetCell(CellView cell) { - this.viewCell = cell; - } - - /** - * Update the SpreadsheetCellEditor - * - * @param spreadsheetCellEditor - */ - public void updateSpreadsheetCellEditor(final SpreadsheetCellEditor spreadsheetCellEditor) { - this.spreadsheetCellEditor = spreadsheetCellEditor; - } - - /** - * Whenever you want to stop the edition, you call that method.<br/> - * True means you're trying to commit the value, then - * {@link SpreadsheetCellType#match(java.lang.Object) } will be called - * in order to verify that the value is correct.<br/> - * - * False means you're trying to cancel the value and it will be follow by - * {@link #end()}.<br/> - * See SpreadsheetCellEditor description - * - * @param commitValue true means commit, false means cancel - */ - public void endEdit(boolean commitValue) { - if (commitValue && editing) { - final SpreadsheetView view = handle.getView(); - boolean match = modelCell.getCellType().match(spreadsheetCellEditor.getControlValue()); - - if (match && viewCell != null) { - Object value = modelCell.getCellType().convertValue(spreadsheetCellEditor.getControlValue()); - - // We update the value - view.getGrid().setCellValue(modelCell.getRow(), modelCell.getColumn(), value); - editing = false; - viewCell.commitEdit(modelCell); - end(); - spreadsheetCellEditor.end(); - - //We select the cell below if "enter" was typed. - if (KeyCode.ENTER.equals(lastKeyPressed)) { - handle.getView().getSelectionModel().clearAndSelectNextCell(); - } else if (KeyCode.TAB.equals(lastKeyPressed)) { - handle.getView().getSelectionModel().clearAndSelectRightCell(); - handle.getCellsViewSkin().scrollHorizontally(); - } - } - } - - if (editing) { - editing = false; - if(viewCell != null){ - viewCell.cancelEdit(); - } - end(); - if(spreadsheetCellEditor != null){ - spreadsheetCellEditor.end(); - } - } - } - - /** - * Return if this editor is currently being used. - * - * @return if this editor is being used. - */ - public boolean isEditing() { - return editing; - } - - public SpreadsheetCell getModelCell() { - return modelCell; - } - - /*************************************************************************** - * * Protected/Private Methods * * - **************************************************************************/ - void startEdit() { - //If we do not reset this, it could false the endEdit behavior in case no key was pressed. - lastKeyPressed = null; - editing = true; - - handle.getGridView().addEventFilter(KeyEvent.KEY_PRESSED, enterKeyPressed); - - handle.getCellsViewSkin().getVBar().valueProperty().addListener(endEditionListener); - handle.getCellsViewSkin().getHBar().valueProperty().addListener(endEditionListener); - - Control editor = spreadsheetCellEditor.getEditor(); - - // Then we call the user editor in order for it to be ready - Object value = modelCell.getItem(); - //We don't want the editor to go beyond the cell boundaries - Double maxHeight = Math.min(viewCell.getHeight(), spreadsheetCellEditor.getMaxHeight()); - - if (editor != null) { - viewCell.setGraphic(editor); - editor.setMaxHeight(maxHeight); - editor.setPrefWidth(viewCell.getWidth()); - } - - spreadsheetCellEditor.startEdit(value); - - if (editor != null) { - focusProperty = getFocusProperty(editor); - focusProperty.addListener(focusListener); - } - - } - - private void end() { - if(focusProperty != null){ - focusProperty.removeListener(focusListener); - focusProperty = null; - } - handle.getCellsViewSkin().getVBar().valueProperty().removeListener(endEditionListener); - handle.getCellsViewSkin().getHBar().valueProperty().removeListener(endEditionListener); - - handle.getGridView().removeEventFilter(KeyEvent.KEY_PRESSED, enterKeyPressed); - - this.modelCell = null; - this.viewCell = null; - } - - /** - * If we have a TextArea, we need to return a custom BooleanExpression - * because we want to let the editor in place even if the user is touching - * the scrollBars inside the textArea. - * - * @param control - * @return - */ - private BooleanExpression getFocusProperty(Control control) { - if (control instanceof TextArea) { - return Bindings.createBooleanBinding(() -> { - if(handle.getView().getScene() == null){ - return false; - } - for (Node n = handle.getView().getScene().getFocusOwner(); n != null; n = n.getParent()) { - if (n == control) { - return true; - } - } - return false; - }, handle.getView().getScene().focusOwnerProperty()); - } else { - return control.focusedProperty(); - } - } - - /** - * When we stop editing a cell, if enter was pressed, we want to go to the next line. - */ - private final EventHandler<KeyEvent> enterKeyPressed = new EventHandler<KeyEvent>() { - @Override - public void handle(KeyEvent t) { - lastKeyPressed = t.getCode(); - } - }; - - private final ChangeListener<Boolean> focusListener = new ChangeListener<Boolean>() { - @Override - public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean isFocus) { - if (!isFocus) { - endEdit(true); - } - } - }; - - private final InvalidationListener endEditionListener = new InvalidationListener() { - @Override - public void invalidated(Observable observable) { - endEdit(true); - } - }; -} diff --git a/src/impl/org/controlsfx/spreadsheet/GridRow.java b/src/impl/org/controlsfx/spreadsheet/GridRow.java deleted file mode 100644 index bbffc04..0000000 --- a/src/impl/org/controlsfx/spreadsheet/GridRow.java +++ /dev/null @@ -1,161 +0,0 @@ -/** - * Copyright (c) 2013, 2014 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.spreadsheet; - -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; -import javafx.beans.WeakInvalidationListener; -import javafx.beans.property.DoubleProperty; -import javafx.beans.property.SimpleDoubleProperty; -import javafx.collections.MapChangeListener; -import javafx.collections.ObservableList; -import javafx.event.Event; -import javafx.event.EventHandler; -import javafx.event.WeakEventHandler; -import javafx.scene.control.Skin; -import javafx.scene.control.TableRow; -import javafx.scene.input.MouseEvent; -import org.controlsfx.control.spreadsheet.SpreadsheetCell; -import org.controlsfx.control.spreadsheet.SpreadsheetView; - - -/** - * - * The tableRow which will holds the SpreadsheetCell. - */ -public class GridRow extends TableRow<ObservableList<SpreadsheetCell>> { - - /*************************************************************************** - * * Private Fields * * - **************************************************************************/ - private final SpreadsheetHandle handle; - /** - * When the row is fixed, it may have a shift from its original position - * which we need in order to layout the cells properly and also for the - * rectangle selection. - */ - DoubleProperty verticalShift = new SimpleDoubleProperty(); - - /*************************************************************************** - * * Constructor * * - **************************************************************************/ - public GridRow(SpreadsheetHandle handle) { - super(); - this.handle = handle; - - /** - * FIXME Bug? When re-using the row, it should re-compute the prefHeight and not - * keep the old value. - */ - this.indexProperty().addListener(weakPrefHeightListener); - this.visibleProperty().addListener(weakPrefHeightListener); - - handle.getView().gridProperty().addListener(weakPrefHeightListener); - - /** - * When the height is changing elsewhere, we need to update ourself if necessary. - */ - handle.getCellsViewSkin().rowHeightMap.addListener(new MapChangeListener<Integer, Double>() { - - @Override - public void onChanged(MapChangeListener.Change<? extends Integer, ? extends Double> change) { - if (change.wasAdded() && change.getKey() == getIndex()) { - setRowHeight(change.getValueAdded()); - } else if (change.wasRemoved() && change.getKey() == getIndex()) { - setRowHeight(computePrefHeight(-1)); - } - } - }); - /** - * When we are adding deported cells (fixed in columns) into a row via - * addCell. The cell is not receiving the DRAG_DETECTED eventHandler - * because it's the row that receives it first. If it's the case, we - * must give the event to the cell underneath. - */ - this.addEventHandler(MouseEvent.DRAG_DETECTED, weakDragHandler); - } - /*************************************************************************** - * * Protected Methods * * - **************************************************************************/ - - void addCell(CellView cell) { - getChildren().add(cell); - } - - void removeCell(CellView gc) { - getChildren().remove(gc); - } - - SpreadsheetView getSpreadsheetView() { - return handle.getView(); - } - - @Override - protected double computePrefHeight(double width) { - return handle.getCellsViewSkin().getRowHeight(getIndex()); - } - - @Override - protected double computeMinHeight(double width) { - return handle.getCellsViewSkin().getRowHeight(getIndex()); - } - - @Override - protected Skin<?> createDefaultSkin() { - return new GridRowSkin(handle, this); - } - - private final InvalidationListener setPrefHeightListener = new InvalidationListener() { - - @Override - public void invalidated(Observable o) { - setRowHeight(computePrefHeight(-1)); - } - }; - - private final WeakInvalidationListener weakPrefHeightListener = new WeakInvalidationListener(setPrefHeightListener); - - public void setRowHeight(double height) { - CellView.getValue(() -> { - setHeight(height); - }); - - setPrefHeight(height); - handle.getCellsViewSkin().rectangleSelection.updateRectangle(); - } - - private final EventHandler<MouseEvent> dragDetectedEventHandler = new EventHandler<MouseEvent>() { - @Override - public void handle(MouseEvent event) { - if (event.getTarget().getClass().equals(GridRow.class) && event.getPickResult().getIntersectedNode() != null) { - Event.fireEvent(event.getPickResult().getIntersectedNode(), event); - } - } - }; - - private final WeakEventHandler<MouseEvent> weakDragHandler = new WeakEventHandler(dragDetectedEventHandler); -} diff --git a/src/impl/org/controlsfx/spreadsheet/GridRowSkin.java b/src/impl/org/controlsfx/spreadsheet/GridRowSkin.java deleted file mode 100644 index a0bd3d1..0000000 --- a/src/impl/org/controlsfx/spreadsheet/GridRowSkin.java +++ /dev/null @@ -1,615 +0,0 @@ -/** - * Copyright (c) 2013, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.spreadsheet; - -import com.sun.javafx.scene.control.behavior.CellBehaviorBase; -import com.sun.javafx.scene.control.behavior.TableRowBehavior; -import com.sun.javafx.scene.control.skin.CellSkinBase; -import java.lang.ref.Reference; -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import javafx.collections.ObservableList; -import javafx.scene.Node; -import javafx.scene.control.TableColumn; -import javafx.scene.control.TableColumnBase; -import javafx.scene.control.TableRow; -import org.controlsfx.control.spreadsheet.Grid; -import org.controlsfx.control.spreadsheet.SpreadsheetCell; -import org.controlsfx.control.spreadsheet.SpreadsheetColumn; -import org.controlsfx.control.spreadsheet.SpreadsheetView; - -public class GridRowSkin extends CellSkinBase<TableRow<ObservableList<SpreadsheetCell>>, CellBehaviorBase<TableRow<ObservableList<SpreadsheetCell>>>> { - - private final SpreadsheetHandle handle; - private final SpreadsheetView spreadsheetView; - - private Reference<HashMap<TableColumnBase, CellView>> cellsMap; - - private final List<CellView> cells = new ArrayList<>(); - - public GridRowSkin(SpreadsheetHandle handle, TableRow<ObservableList<SpreadsheetCell>> gridRow) { - super(gridRow, new TableRowBehavior<>(gridRow)); - this.handle = handle; - spreadsheetView = handle.getView(); - - getSkinnable().setPickOnBounds(false); - - registerChangeListener(gridRow.itemProperty(), "ITEM"); - registerChangeListener(gridRow.indexProperty(), "INDEX"); - } - - @Override - protected void handleControlPropertyChanged(String p) { - super.handleControlPropertyChanged(p); - - if ("INDEX".equals(p)) { - // Fix for RT-36661, where empty table cells were showing content, as they - // had incorrect table cell indices (but the table row index was correct). - // Note that we only do the update on empty cells to avoid the issue - // noted below in requestCellUpdate(). - if (getSkinnable().isEmpty()) { - requestCellUpdate(); - } - } else if ("ITEM".equals(p)) { - requestCellUpdate(); - } else if ("FIXED_CELL_SIZE".equals(p)) { -// fixedCellSize = fixedCellSizeProperty().get(); -// fixedCellSizeEnabled = fixedCellSize > 0; - } - } - - private void requestCellUpdate() { - getSkinnable().requestLayout(); - - // update the index of all children cells (RT-29849). - // Note that we do this after the TableRow item has been updated, - // rather than when the TableRow index has changed (as this will be - // before the row has updated its item). This will result in the - // issue highlighted in RT-33602, where the table cell had the correct - // item whilst the row had the old item. - final int newIndex = getSkinnable().getIndex(); - /** - * When the index is changing, we need to clear out all the children - * because we may end up with useless cell in the row. - */ - getChildren().clear(); - for (int i = 0, max = cells.size(); i < max; i++) { - cells.get(i).updateIndex(newIndex); - } - } - - @Override - protected void layoutChildren(double x, final double y, final double w, final double h) { - - final ObservableList<? extends TableColumnBase<?, ?>> visibleLeafColumns = handle.getGridView().getVisibleLeafColumns(); - if (visibleLeafColumns.isEmpty()) { - super.layoutChildren(x, y, w, h); - return; - } - - final GridRow control = (GridRow) getSkinnable(); - final SpreadsheetGridView gridView = (SpreadsheetGridView) handle.getGridView(); - final Grid grid = spreadsheetView.getGrid(); - final int index = control.getIndex(); - - /** - * If this row is out of bounds, this means that the row is displayed - * either at the top or at the bottom. In any case, this row is not - * meant to be seen so we clear its children list in order not to show - * previous TableCell that could be there. - */ - if (index < 0 || index >= gridView.getItems().size()) { - getChildren().clear(); - putCellsInCache(); - return; - } - - final List<SpreadsheetCell> row = grid.getRows().get(index); - final List<SpreadsheetColumn> columns = spreadsheetView.getColumns(); - final ObservableList<TableColumn<ObservableList<SpreadsheetCell>, ?>> tableViewColumns = gridView.getColumns(); - /** - * If we use "setGrid" on SpreadsheetView, we must be careful because we - * set our columns after (due to threading safety). So if, by mistake, - * we are in layout and the columns are set in SpreadsheetView, but not - * in TableView (yet). Then just return and wait for next calling. - */ - if (columns.size() != tableViewColumns.size()) { - return; - } - - getSkinnable().setVisible(true); - // layout the individual column cells - double width; - double height; - - final double verticalPadding = snappedTopInset() + snappedBottomInset(); - final double horizontalPadding = snappedLeftInset() - + snappedRightInset(); - /** - * Here we make the distinction between the official controlHeight and - * the customHeight that we may apply. - */ - double controlHeight = getTableRowHeight(index); - double customHeight = controlHeight == Grid.AUTOFIT ? GridViewSkin.DEFAULT_CELL_HEIGHT : controlHeight; - - final GridViewSkin skin = handle.getCellsViewSkin(); - skin.hBarValue.set(index, true); - - // determine the width of the visible portion of the table - double headerWidth = gridView.getWidth(); - final double hbarValue = skin.getHBar().getValue(); - - /** - * FOR FIXED ROWS - */ - ((GridRow) getSkinnable()).verticalShift.setValue(getFixedRowShift(index)); - - double fixedColumnWidth = 0; - List<CellView> fixedCells = new ArrayList(); - - //We compute the cells here - putCellsInCache(); - - boolean firstVisibleCell = false; - CellView lastCell = null; - boolean needToBeShifted; - boolean rowHeightChange = false; - for (int indexColumn = 0; indexColumn < columns.size(); indexColumn++) { - - width = snapSize(columns.get(indexColumn).getWidth()) - snapSize(horizontalPadding); - - final SpreadsheetCell spreadsheetCell = row.get(indexColumn); - boolean isVisible = !isInvisible(x, width, hbarValue, headerWidth, spreadsheetCell.getColumnSpan()); - - if (columns.get(indexColumn).isFixed()) { - isVisible = true; - } - - if (!isVisible) { - if (firstVisibleCell) { - break; - } - x += width; - continue; - } - final CellView tableCell = getCell(gridView.getColumns().get(indexColumn)); - - cells.add(0, tableCell); - - // In case the node was treated previously - tableCell.setManaged(true); - - /** - * FOR FIXED COLUMNS - */ - double tableCellX = 0; - - /** - * We need to update the fixedColumnWidth only on visible cell and - * we need to add the full width including the span. - * - * If we fail to do so, we may be in the situation where x will grow - * with the correct width and not fixedColumnWidth. Thus some cell - * that should be shifted will not because the computation based on - * fixedColumnWidth will be wrong. - */ - boolean increaseFixedWidth = false; - //Virtualization of column - // We translate that column by the Hbar Value if it's fixed - if (columns.get(indexColumn).isFixed()) { - if (hbarValue + fixedColumnWidth > x && spreadsheetCell.getColumn() == indexColumn) { - increaseFixedWidth = true; - tableCellX = Math.abs(hbarValue - x + fixedColumnWidth); -// tableCell.toFront(); - fixedColumnWidth += width; -// isVisible = true; // If in fixedColumn, it's obviously visible - fixedCells.add(tableCell); - } - } - - if (isVisible) { - final SpreadsheetView.SpanType spanType = grid.getSpanType(spreadsheetView, index, indexColumn); - - switch (spanType) { - case ROW_SPAN_INVISIBLE: - case BOTH_INVISIBLE: - fixedCells.remove(tableCell); - getChildren().remove(tableCell); -// cells.remove(tableCell); - x += width; - continue; // we don't want to fall through - case COLUMN_SPAN_INVISIBLE: - fixedCells.remove(tableCell); - getChildren().remove(tableCell); -// cells.remove(tableCell); - continue; // we don't want to fall through - case ROW_VISIBLE: -// final TableViewSpanSelectionModel sm = (TableViewSpanSelectionModel) handle.getGridView().getSelectionModel(); -// final TableColumn<ObservableList<SpreadsheetCell>, ?> col = tableViewColumns.get(indexColumn); - - /** - * In case this cell was selected before but we scroll - * up/down and it's invisible now. It has to pass his - * "selected property" to the new Cell in charge of - * spanning - */ -// final TablePosition<ObservableList<SpreadsheetCell>, ?> selectedPosition = sm.isSelectedRange(index, col, indexColumn); - // If the selected cell is in the same row, no need to re-select it -// if (selectedPosition != null -// //When shift selecting, all cells become ROW_VISIBLE so -// //We avoid loop selecting here -// && skin.containsRow(index) -// && selectedPosition.getRow() != index) { -// sm.clearSelection(selectedPosition.getRow(), -// selectedPosition.getTableColumn()); -// sm.select(index, col); -// } - case NORMAL_CELL: // fall through and carry on - if (tableCell.getIndex() != index) { - tableCell.updateIndex(index); - } else { - tableCell.updateItem(spreadsheetCell, false); - } - /** - * Here we need to add the cells on the first position - * because this row may contain some deported cells from - * other rows in order to be on top in term of z-order. - * So the cell we're currently adding must not recover - * them. - */ - if (tableCell.getParent() == null) { - getChildren().add(0, tableCell); - } - } - - if (spreadsheetCell.getColumnSpan() > 1) { - /** - * we need to span multiple columns, so we sum up the width - * of the additional columns, adding it to the width - * variable - */ - for (int i = 1, colSpan = spreadsheetCell.getColumnSpan(), max1 = columns - .size() - indexColumn; i < colSpan && i < max1; i++) { - double tempWidth = snapSize(columns.get(indexColumn + i).getWidth()); - width += tempWidth; - if (increaseFixedWidth) { - fixedColumnWidth += tempWidth; - } - } - } - - /** - * If we are in autofit and the prefHeight of this cell is - * superior to the default cell height. Then we will use this - * new height for row's height. - * - * We then need to apply the value to previous cell, and also - * layout the children because since we are layouting upward, - * next rows needs to know that this row is bigger than usual. - */ - if (controlHeight == Grid.AUTOFIT && !tableCell.isEditing()) { - double tempHeight = tableCell.prefHeight(width); - if (tempHeight > customHeight) { - rowHeightChange = true; - skin.rowHeightMap.put(index, tempHeight); - for (CellView cell : cells) { - /** - * We need to add the difference between the - * previous height and the new height. If we were - * just setting the new height, the row spanning - * cell would be shorter. That's why we need to use - * the cell height. - */ - cell.resize(cell.getWidth(), cell.getHeight() + (tempHeight - customHeight)); - } - customHeight = tempHeight; - skin.getFlow().layoutChildren(); - } - } - - height = customHeight; - height = snapSize(height) - snapSize(verticalPadding); - /** - * We need to span multiple rows, so we sum up the height of all - * the rows. The height of the current row is ignored and the - * whole value is computed. - */ - if (spreadsheetCell.getRowSpan() > 1) { - height = 0; - final int maxRow = spreadsheetCell.getRow() + spreadsheetCell.getRowSpan(); - for (int i = spreadsheetCell.getRow(); i < maxRow; ++i) { - height += snapSize(skin.getRowHeight(i)); - } - } - - //Fix for JDK-8146406 - needToBeShifted = false; - /** - * If the current cell has no left border, and the previous cell - * had no right border, and we're fixed. We may have the problem - * where there is a tiny gap between the cells when scrolling - * horizontally. Thus we must enlarge this cell a bit, and shift - * it a bit in order to mask that gap. If the cell has a border - * defined, the problem seems not to happen. - */ - if (spreadsheetView.getFixedRows().contains(index) - && lastCell != null - && !hasRightBorder(lastCell) - && !hasLeftBorder(tableCell)) { - tableCell.resize(width +1, height); - needToBeShifted = true; - } else { - tableCell.resize(width, height); - } - lastCell = tableCell; - // We want to place the layout always at the starting cell. - double spaceBetweenTopAndMe = 0; - for (int p = spreadsheetCell.getRow(); p < index; ++p) { - spaceBetweenTopAndMe += skin.getRowHeight(p); - } - - tableCell.relocate(x + tableCellX + (needToBeShifted? -1 : 0), snappedTopInset() - - spaceBetweenTopAndMe + ((GridRow) getSkinnable()).verticalShift.get()); - - // Request layout is here as (partial) fix for RT-28684 -// tableCell.requestLayout(); - } else { - getChildren().remove(tableCell); - } - x += width; - } - skin.fixedColumnWidth = fixedColumnWidth; - handleFixedCell(fixedCells, index); - removeUselessCell(index); - if (handle.getCellsViewSkin().lastRowLayout.get() == true) { - handle.getCellsViewSkin().lastRowLayout.setValue(false); - } - /** - * If we modified an height here, ROW_HEIGHT_CHANGE will not be - * triggered, because it's not the user who has modified that. So the - * rectangle will not update, we need to force it here. - */ - if (rowHeightChange && spreadsheetView.getFixedRows().contains(index)) { - skin.computeFixedRowHeight(); - } - } - - private boolean hasRightBorder(CellView tableCell) { - return tableCell.getBorder() != null - && !tableCell.getBorder().isEmpty() - && tableCell.getBorder().getStrokes().get(0).getWidths().getRight() > 0; - } - - private boolean hasLeftBorder(CellView tableCell) { - return tableCell.getBorder() != null - && !tableCell.getBorder().isEmpty() - && tableCell.getBorder().getStrokes().get(0).getWidths().getLeft()> 0; - } - - /** - * Here we want to remove of the sceneGraph cells that are not used. - * - * Before we were removing the cells that we were getting from the cache. - * But that is not enough because some cells can be added somehow, and stay - * within the row. Since we do not often clear the children because of some - * deportedCell present inside, we must use that Predicate to clear all - * CellView not contained in cells and with the same index. Thus we preserve - * the deported cell. - */ - private void removeUselessCell(int index) { - getChildren().removeIf((Node t) -> { - if (t instanceof CellView) { - return !cells.contains(t) && ((CellView) t).getIndex() == index; - } - return false; - }); - } - - /** - * This handles the fixed cells in column. - * - * @param fixedCells - * @param index - */ - private void handleFixedCell(List<CellView> fixedCells, int index) { - if (fixedCells.isEmpty()) { - return; - } - - /** - * If we have a fixedCell (in column) and that cell may be recovered by - * a rowSpan, we want to put that tableCell ahead in term of z-order. So - * we need to put it in another row. - */ - if (handle.getCellsViewSkin().rowToLayout.get(index)) { - GridRow gridRow = handle.getCellsViewSkin().getFlow().getTopRow(); - if (gridRow != null) { - for (CellView cell : fixedCells) { - final double originalLayoutY = getSkinnable().getLayoutY() + cell.getLayoutY(); - gridRow.removeCell(cell); - gridRow.addCell(cell); - if (handle.getCellsViewSkin().deportedCells.containsKey(gridRow)) { - handle.getCellsViewSkin().deportedCells.get(gridRow).add(cell); - } else { - Set<CellView> temp = new HashSet<>(); - temp.add(cell); - handle.getCellsViewSkin().deportedCells.put(gridRow, temp); - } - /** - * I need to have the layoutY of the original row, but also - * to remove the layoutY of the row I'm adding in. Because - * if the first row is fixed and is undergoing a bit of - * translate in order to be visible, we need to remove that - * "bit of translate". - */ - cell.relocate(cell.getLayoutX(), originalLayoutY - gridRow.getLayoutY()); - } - } - } else { - for (CellView cell : fixedCells) { - cell.toFront(); - } - } - } - - /** - * Return the Cache. Here we use a WeakReference because the WeakHashMap is - * not working. TableCell added to it are not removed if the GC wants them. - * So we put the whole cache in WeakReference. In normal condition, the - * cache is not trashed that much and is efficient. In the case where the - * user scroll horizontally a lot, that cache can then be trashed in order - * to avoid OutOfMemoryError. - * - * @return - */ - private HashMap<TableColumnBase, CellView> getCellsMap() { - if (cellsMap == null || cellsMap.get() == null) { - HashMap<TableColumnBase, CellView> map = new HashMap<>(); - cellsMap = new WeakReference<>(map); - return map; - } - return cellsMap.get(); - } - - /** - * This will put all current displayed cell into the cache. - */ - private void putCellsInCache() { - for (CellView cell : cells) { - getCellsMap().put(cell.getTableColumn(), cell); - } - cells.clear(); - } - - /** - * This will retrieve a cell for the specified column. If the cell exists in - * the cache, it's extracted from it. Otherwise, a cell is created. - * - * @param tcb - * @return - */ - private CellView getCell(TableColumnBase tcb) { - TableColumn tableColumn = (TableColumn<CellView, ?>) tcb; - CellView cell; - if (getCellsMap().containsKey(tableColumn)) { - return getCellsMap().remove(tableColumn); - } else { - cell = (CellView) tableColumn.getCellFactory().call(tableColumn); - cell.updateTableColumn(tableColumn); - cell.updateTableView(tableColumn.getTableView()); - cell.updateTableRow(getSkinnable()); - } - return cell; - } - - /** - * Return the space we need to shift that row if it's fixed. Also update the {@link GridViewSkin#getCurrentlyFixedRow() - * } . - * - * @param index - * @return - */ - private double getFixedRowShift(int index) { - double tableCellY = 0; - int positionY = spreadsheetView.getFixedRows().indexOf(index); - - //FIXME Integrate if fixedCellSize is enabled - //Computing how much space we need to translate - //because each row has different space. - double space = 0; - for (int o = 0; o < positionY; ++o) { - space += handle.getCellsViewSkin().getRowHeight(spreadsheetView.getFixedRows().get(o)); - } - - //If true, this row is fixed - if (positionY != -1 && getSkinnable().getLocalToParentTransform().getTy() <= space) { - //This row is a bit hidden on top so we translate then for it to be fully visible - tableCellY = space - getSkinnable().getLocalToParentTransform().getTy(); - handle.getCellsViewSkin().getCurrentlyFixedRow().add(index); - } else { - handle.getCellsViewSkin().getCurrentlyFixedRow().remove(index); - } - return tableCellY; - } - - /** - * Return the height of a row. - * - * @param row - * @return - */ - private double getTableRowHeight(int row) { - Double rowHeightCache = handle.getCellsViewSkin().rowHeightMap.get(row); - return rowHeightCache == null ? handle.getView().getGrid().getRowHeight(row) : rowHeightCache; - } - - /** - * Return true if the current cell is part of the sceneGraph. - * - * @param x beginning of the cell - * @param width total width of the cell - * @param hbarValue - * @param headerWidth width of the visible portion of the tableView - * @param columnSpan - * @return - */ - private boolean isInvisible(double x, double width, double hbarValue, - double headerWidth, int columnSpan) { - return (x + width < hbarValue && columnSpan == 1) || (x > hbarValue + headerWidth); - } - - @Override - protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) { - double prefWidth = 0.0; - - final List<? extends TableColumnBase/*<T,?>*/> visibleLeafColumns = handle.getGridView().getVisibleLeafColumns(); - for (int i = 0, max = visibleLeafColumns.size(); i < max; i++) { - prefWidth += visibleLeafColumns.get(i).getWidth(); - } - - return prefWidth; - } - - @Override - protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { - return getSkinnable().getPrefHeight(); - } - - @Override - protected double computeMinHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { - return getSkinnable().getPrefHeight(); - } - - @Override - protected double computeMaxHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { - return super.computeMaxHeight(width, topInset, rightInset, bottomInset, leftInset); - } -} diff --git a/src/impl/org/controlsfx/spreadsheet/GridViewBehavior.java b/src/impl/org/controlsfx/spreadsheet/GridViewBehavior.java deleted file mode 100644 index 9ef5a83..0000000 --- a/src/impl/org/controlsfx/spreadsheet/GridViewBehavior.java +++ /dev/null @@ -1,509 +0,0 @@ -/** - * Copyright (c) 2015 ControlsFX All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. * Redistributions in binary - * form must reproduce the above copyright notice, this list of conditions and - * the following disclaimer in the documentation and/or other materials provided - * with the distribution. * Neither the name of ControlsFX, any associated - * website, nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.spreadsheet; - -import com.sun.javafx.scene.control.behavior.TableViewBehavior; -import javafx.collections.ObservableList; -import javafx.scene.control.SelectionMode; -import javafx.scene.control.TableColumnBase; -import javafx.scene.control.TableFocusModel; -import javafx.scene.control.TablePositionBase; -import javafx.scene.control.TableSelectionModel; -import javafx.scene.control.TableView; -import javafx.util.Pair; -import org.controlsfx.control.spreadsheet.SpreadsheetCell; - -/** - * - * This overrides {@link TableViewBehavior} in order to modify the selection - * behavior. The selection will basically work like Excel: - * - * Selection will always be rectangles. So selection by SHIFT will produce a - * rectangle extending your selection. - * - * Pressing SHORTCUT with an arrow will on a cell will do: - * - * - If the cell is empty, we go to the next (in the direction) non empty cell. - * - * - If the cell is not empty, then we either go to the last non empty cell if - * the next is not empty, or the first non empty cell if the next is empty. - * - * This is meant to increase navigation on non empty cell in a Spreadsheet more - * easily. - * - * Pressing SHORTCUT and SHIFT together will behave as the ShortCut previously - * explained but the selection will be extended instead of just selecting the - * new cell. - * - */ -public class GridViewBehavior extends TableViewBehavior<ObservableList<SpreadsheetCell>> { - - private GridViewSkin skin; - - public GridViewBehavior(TableView<ObservableList<SpreadsheetCell>> control) { - super(control); - } - - void setGridViewSkin(GridViewSkin skin) { - this.skin = skin; - } - - @Override - protected void updateCellVerticalSelection(int delta, Runnable defaultAction) { - TableViewSpanSelectionModel sm = (TableViewSpanSelectionModel) getSelectionModel(); - if (sm == null || sm.getSelectionMode() == SelectionMode.SINGLE) { - return; - } - - TableFocusModel fm = getFocusModel(); - if (fm == null) { - return; - } - - final TablePositionBase focusedCell = getFocusedCell(); - - if (isShiftDown && getAnchor() != null) { - - final SpreadsheetCell cell = getControl().getItems().get(fm.getFocusedIndex()).get(focusedCell.getColumn()); - sm.direction = new Pair<>(delta, 0); - /** - * If the delta is >0, it means we want to go down, so we need to - * target the cell that is after our cell. So we need to take the - * last row of our cell if spanning. If the delta is < 0, it means - * we want to go up, so we just take the row. - */ - int newRow; - if (delta < 0) { - newRow = cell.getRow() + delta; - } else { - newRow = cell.getRow() + cell.getRowSpan() - 1 + delta; - } - - // we don't let the newRow go outside the bounds of the data - newRow = Math.max(Math.min(getItemCount() - 1, newRow), 0); - - final TablePositionBase<?> anchor = getAnchor(); - int minRow = Math.min(anchor.getRow(), newRow); - int maxRow = Math.max(anchor.getRow(), newRow); - int minColumn = Math.min(anchor.getColumn(), focusedCell.getColumn()); - int maxColumn = Math.max(anchor.getColumn(), focusedCell.getColumn()); - - sm.clearSelection(); - if (minColumn != -1 && maxColumn != -1) { - sm.selectRange(minRow, getControl().getColumns().get(minColumn), maxRow, - getControl().getColumns().get(maxColumn)); - } - fm.focus(newRow, focusedCell.getTableColumn()); - } else { - final int focusIndex = fm.getFocusedIndex(); - if (!sm.isSelected(focusIndex, focusedCell.getTableColumn())) { - sm.select(focusIndex, focusedCell.getTableColumn()); - } - defaultAction.run(); - } - } - - @Override - protected void updateCellHorizontalSelection(int delta, Runnable defaultAction) { - TableViewSpanSelectionModel sm = (TableViewSpanSelectionModel) getSelectionModel(); - if (sm == null || sm.getSelectionMode() == SelectionMode.SINGLE) { - return; - } - - TableFocusModel fm = getFocusModel(); - if (fm == null) { - return; - } - - final TablePositionBase focusedCell = getFocusedCell(); - if (focusedCell == null || focusedCell.getTableColumn() == null) { - return; - } - - TableColumnBase adjacentColumn = getColumn(focusedCell.getTableColumn(), delta); - if (adjacentColumn == null) { - return; - } - - final int focusedCellRow = focusedCell.getRow(); - - if (isShiftDown && getAnchor() != null) { - final int columnPos = getVisibleLeafIndex(focusedCell.getTableColumn()); - - final SpreadsheetCell cell = getControl().getItems().get(focusedCellRow).get(columnPos); - - sm.direction = new Pair<>(0, delta); - final int newColumn;// = columnCell + delta; - if (delta < 0) { - newColumn = cell.getColumn() + delta; - } else { - newColumn = cell.getColumn() + cell.getColumnSpan() - 1 + delta; - } - final TablePositionBase<?> anchor = getAnchor(); - int minRow = Math.min(anchor.getRow(), focusedCellRow); - int maxRow = Math.max(anchor.getRow(), focusedCellRow); - int minColumn = Math.min(anchor.getColumn(), newColumn); - int maxColumn = Math.max(anchor.getColumn(), newColumn); - - sm.clearSelection(); - if (minColumn != -1 && maxColumn != -1) { - sm.selectRange(minRow, getControl().getColumns().get(minColumn), maxRow, - getControl().getColumns().get(maxColumn)); - } - fm.focus(focusedCell.getRow(), getColumn(newColumn)); - } else { - defaultAction.run(); - } - - } - - @Override - protected void focusPreviousRow() { - focusVertical(true); - } - - @Override - protected void focusNextRow() { - focusVertical(false); - } - - @Override - protected void focusLeftCell() { - focusHorizontal(true); - } - - @Override - protected void focusRightCell() { - focusHorizontal(false); - } - - @Override - protected void discontinuousSelectPreviousRow() { - discontinuousSelectVertical(true); - } - - @Override - protected void discontinuousSelectNextRow() { - discontinuousSelectVertical(false); - } - - @Override - protected void discontinuousSelectPreviousColumn() { - discontinuousSelectHorizontal(true); - } - - @Override - protected void discontinuousSelectNextColumn() { - discontinuousSelectHorizontal(false); - } - - private void focusVertical(boolean previous) { - TableSelectionModel sm = getSelectionModel(); - if (sm == null || sm.getSelectionMode() == SelectionMode.SINGLE) { - return; - } - - TableFocusModel fm = getFocusModel(); - if (fm == null) { - return; - } - - final TablePositionBase focusedCell = getFocusedCell(); - if (focusedCell == null || focusedCell.getTableColumn() == null) { - return; - } - - final SpreadsheetCell cell = getControl().getItems().get(focusedCell.getRow()).get(focusedCell.getColumn()); - sm.clearAndSelect(previous ? findPreviousRow(focusedCell, cell) : findNextRow(focusedCell, cell), focusedCell.getTableColumn()); - skin.focusScroll(); - } - - private void focusHorizontal(boolean previous) { - TableSelectionModel sm = getSelectionModel(); - if (sm == null) { - return; - } - - TableFocusModel fm = getFocusModel(); - if (fm == null) { - return; - } - final TablePositionBase focusedCell = getFocusedCell(); - if (focusedCell == null || focusedCell.getTableColumn() == null) { - return; - } - - final SpreadsheetCell cell = getControl().getItems().get(focusedCell.getRow()).get(focusedCell.getColumn()); - - sm.clearAndSelect(focusedCell.getRow(), getControl().getColumns().get(previous ? findPreviousColumn(focusedCell, cell) : findNextColumn(focusedCell, cell))); - skin.focusScroll(); - } - - private int findPreviousRow(TablePositionBase focusedCell, SpreadsheetCell cell) { - final ObservableList<ObservableList<SpreadsheetCell>> items = getControl().getItems(); - SpreadsheetCell temp; - //If my cell is empty, I seek the next non-empty - if (isEmpty(cell)) { - for (int row = focusedCell.getRow() - 1; row >= 0; --row) { - temp = items.get(row).get(focusedCell.getColumn()); - if (!isEmpty(temp)) { - return row; - } - } - } else if (focusedCell.getRow() - 1 >= 0 && !isEmpty(items.get(focusedCell.getRow() - 1).get(focusedCell.getColumn()))) { - for (int row = focusedCell.getRow() - 2; row >= 0; --row) { - temp = items.get(row).get(focusedCell.getColumn()); - if (isEmpty(temp)) { - return row + 1; - } - } - } else { - //If I'm not empty and the next is empty, I seek the first non empty - for (int row = focusedCell.getRow() - 2; row >= 0; --row) { - temp = items.get(row).get(focusedCell.getColumn()); - if (!isEmpty(temp)) { - return row; - } - } - } - - //If we're here, we then select the last on - return 0; - } - - - @Override - protected void selectCell(int rowDiff, int columnDiff) { - TableViewSpanSelectionModel sm = (TableViewSpanSelectionModel) getSelectionModel(); - if (sm == null) { - return; - } - sm.direction = new Pair<>(rowDiff, columnDiff); - - TableFocusModel fm = getFocusModel(); - if (fm == null) { - return; - } - - TablePositionBase focusedCell = getFocusedCell(); - int currentRow = focusedCell.getRow(); - int currentColumn = getVisibleLeafIndex(focusedCell.getTableColumn()); - - if (rowDiff < 0 && currentRow <= 0) return; - else if (rowDiff > 0 && currentRow >= getItemCount() - 1) return; - else if (columnDiff < 0 && currentColumn <= 0) return; - else if (columnDiff > 0 && currentColumn >= getVisibleLeafColumns().size() - 1) return; - else if (columnDiff > 0 && currentColumn == -1) return; - - TableColumnBase tc = focusedCell.getTableColumn(); - tc = getColumn(tc, columnDiff); - - int row = focusedCell.getRow() + rowDiff; - - sm.clearAndSelect(row, tc); - setAnchor(row, tc); - } - - private int findNextRow(TablePositionBase focusedCell, SpreadsheetCell cell) { - final ObservableList<ObservableList<SpreadsheetCell>> items = getControl().getItems(); - final int itemCount = getItemCount(); - SpreadsheetCell temp; - //If my cell is empty, I seek the next non-empty - if (isEmpty(cell)) { - for (int row = focusedCell.getRow() + 1; row < itemCount; ++row) { - temp = items.get(row).get(focusedCell.getColumn()); - if (!isEmpty(temp)) { - return row; - } - } - } else if (focusedCell.getRow() + 1 < itemCount && !isEmpty(items.get(focusedCell.getRow() + 1).get(focusedCell.getColumn()))) { - for (int row = focusedCell.getRow() + 2; row < getItemCount(); ++row) { - temp = items.get(row).get(focusedCell.getColumn()); - if (isEmpty(temp)) { - return row - 1; - } - } - } else { - for (int row = focusedCell.getRow() + 2; row < itemCount; ++row) { - temp = items.get(row).get(focusedCell.getColumn()); - if (!isEmpty(temp)) { - return row; - } - } - } - return itemCount - 1; - } - - private void discontinuousSelectVertical(boolean previous) { - TableSelectionModel sm = getSelectionModel(); - if (sm == null) { - return; - } - - TableFocusModel fm = getFocusModel(); - if (fm == null) { - return; - } - final TablePositionBase focusedCell = getFocusedCell(); - if (focusedCell == null || focusedCell.getTableColumn() == null) { - return; - } - - final SpreadsheetCell cell = getControl().getItems().get(fm.getFocusedIndex()).get(focusedCell.getColumn()); - - /** - * If the delta is >0, it means we want to go down, so we need to target - * the cell that is after our cell. So we need to take the last row of - * our cell if spanning. If the delta is < 0, it means we want to go up, - * so we just take the row. - */ - int newRow = previous ? findPreviousRow(focusedCell, cell) : findNextRow(focusedCell, cell);; - - // we don't let the newRow go outside the bounds of the data - newRow = Math.max(Math.min(getItemCount() - 1, newRow), 0); - - final TablePositionBase<?> anchor = getAnchor(); - int minRow = Math.min(anchor.getRow(), newRow); - int maxRow = Math.max(anchor.getRow(), newRow); - int minColumn = Math.min(anchor.getColumn(), focusedCell.getColumn()); - int maxColumn = Math.max(anchor.getColumn(), focusedCell.getColumn()); - - sm.clearSelection(); - if (minColumn != -1 && maxColumn != -1) { - sm.selectRange(minRow, getControl().getColumns().get(minColumn), maxRow, - getControl().getColumns().get(maxColumn)); - } - fm.focus(newRow, focusedCell.getTableColumn()); - skin.focusScroll(); - } - - private void discontinuousSelectHorizontal(boolean previous) { - TableSelectionModel sm = getSelectionModel(); - if (sm == null) { - return; - } - - TableFocusModel fm = getFocusModel(); - if (fm == null) { - return; - } - final TablePositionBase focusedCell = getFocusedCell(); - if (focusedCell == null || focusedCell.getTableColumn() == null) { - return; - } - - final int columnPos = getVisibleLeafIndex(focusedCell.getTableColumn()); - int focusedCellRow = focusedCell.getRow(); - final SpreadsheetCell cell = getControl().getItems().get(focusedCellRow).get(columnPos); - - final int newColumn = previous ? findPreviousColumn(focusedCell, cell) : findNextColumn(focusedCell, cell); - - final TablePositionBase<?> anchor = getAnchor(); - int minRow = Math.min(anchor.getRow(), focusedCellRow); - int maxRow = Math.max(anchor.getRow(), focusedCellRow); - int minColumn = Math.min(anchor.getColumn(), newColumn); - int maxColumn = Math.max(anchor.getColumn(), newColumn); - - sm.clearSelection(); - if (minColumn != -1 && maxColumn != -1) { - sm.selectRange(minRow, getControl().getColumns().get(minColumn), maxRow, - getControl().getColumns().get(maxColumn)); - } - fm.focus(focusedCell.getRow(), getColumn(newColumn)); - skin.focusScroll(); - } - - private int findNextColumn(TablePositionBase focusedCell, SpreadsheetCell cell) { - final ObservableList<ObservableList<SpreadsheetCell>> items = getControl().getItems(); - final int itemCount = getControl().getColumns().size(); - SpreadsheetCell temp; - //If my cell is empty, I seek the next non-empty - if (isEmpty(cell)) { - for (int column = focusedCell.getColumn() + 1; column < itemCount; ++column) { - temp = items.get(focusedCell.getRow()).get(column); - if (!isEmpty(temp)) { - return column; - } - } - } else if (focusedCell.getColumn() + 1 < itemCount && !isEmpty(items.get(focusedCell.getRow()).get(focusedCell.getColumn() + 1))) { - for (int column = focusedCell.getColumn() + 2; column < itemCount; ++column) { - temp = items.get(focusedCell.getRow()).get(column); - if (isEmpty(temp)) { - return column - 1; - } - } - } else { - for (int column = focusedCell.getColumn() + 2; column < itemCount; ++column) { - temp = items.get(focusedCell.getRow()).get(column); - if (!isEmpty(temp)) { - return column; - } - } - } - return itemCount - 1; - } - - private int findPreviousColumn(TablePositionBase focusedCell, SpreadsheetCell cell) { - final ObservableList<ObservableList<SpreadsheetCell>> items = getControl().getItems(); - SpreadsheetCell temp; - //If my cell is empty, I seek the next non-empty - if (isEmpty(cell)) { - for (int column = focusedCell.getColumn() - 1; column >= 0; --column) { - temp = items.get(focusedCell.getRow()).get(column); - if (!isEmpty(temp)) { - return column; - } - } - } else if (focusedCell.getColumn() - 1 >= 0 && !isEmpty(items.get(focusedCell.getRow()).get(focusedCell.getColumn() - 1))) { - for (int column = focusedCell.getColumn() - 2; column >= 0; --column) { - temp = items.get(focusedCell.getRow()).get(column); - if (isEmpty(temp)) { - return column + 1; - } - } - } else { - for (int column = focusedCell.getColumn() - 2; column >= 0; --column) { - temp = items.get(focusedCell.getRow()).get(column); - if (!isEmpty(temp)) { - return column; - } - } - } - return 0; - } - - /** - * Cell is empty if there's nothing in it or if we have a NaN instead of a - * proper Double. - * - * @param cell - * @return - */ - private boolean isEmpty(SpreadsheetCell cell) { - return cell.getGraphic() == null && (cell.getItem() == null - || (cell.getItem() instanceof Double && ((Double) cell.getItem()).isNaN())); - } -} diff --git a/src/impl/org/controlsfx/spreadsheet/GridViewSkin.java b/src/impl/org/controlsfx/spreadsheet/GridViewSkin.java deleted file mode 100644 index afb42b3..0000000 --- a/src/impl/org/controlsfx/spreadsheet/GridViewSkin.java +++ /dev/null @@ -1,1138 +0,0 @@ -/** - * Copyright (c) 2013, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.spreadsheet; - -import java.lang.reflect.Field; -import java.time.LocalDate; -import java.util.BitSet; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.collections.FXCollections; -import javafx.collections.ListChangeListener; -import javafx.collections.ObservableList; -import javafx.collections.ObservableMap; -import javafx.collections.ObservableSet; -import javafx.collections.SetChangeListener; -import javafx.event.EventHandler; -import javafx.geometry.HPos; -import javafx.geometry.VPos; -import javafx.scene.Node; -import javafx.scene.control.IndexedCell; -import javafx.scene.control.ResizeFeaturesBase; -import javafx.scene.control.TableCell; -import javafx.scene.control.TableColumn; -import javafx.scene.control.TableColumnBase; -import javafx.scene.control.TableFocusModel; -import javafx.scene.control.TablePositionBase; -import javafx.scene.control.TableRow; -import javafx.scene.control.TableSelectionModel; -import javafx.scene.control.TableView; -import javafx.scene.input.MouseEvent; -import javafx.scene.layout.Region; -import javafx.stage.Screen; -import javafx.util.Callback; - -import org.controlsfx.control.spreadsheet.Grid; -import org.controlsfx.control.spreadsheet.SpreadsheetCell; -import org.controlsfx.control.spreadsheet.SpreadsheetColumn; -import org.controlsfx.control.spreadsheet.SpreadsheetView; - -import com.sun.javafx.scene.control.behavior.TableViewBehavior; -import com.sun.javafx.scene.control.skin.TableHeaderRow; -import com.sun.javafx.scene.control.skin.TableViewSkinBase; -import com.sun.javafx.scene.control.skin.VirtualFlow; -import javafx.application.Platform; -import javafx.event.Event; -import javafx.scene.control.ScrollBar; - -/** - * This skin is actually the skin of the SpreadsheetGridView (tableView) - * contained within the SpreadsheetView. The skin for the SpreadsheetView itself - * currently resides inside the SpreadsheetView constructor! - * - * We need to extends directly from TableViewSkinBase in order to work-around - * https://javafx-jira.kenai.com/browse/RT-34753 if we want to set a custom - * TableViewBehavior. - * - */ -public class GridViewSkin extends TableViewSkinBase<ObservableList<SpreadsheetCell>,ObservableList<SpreadsheetCell>,TableView<ObservableList<SpreadsheetCell>>,TableViewBehavior<ObservableList<SpreadsheetCell>>,TableRow<ObservableList<SpreadsheetCell>>,TableColumn<ObservableList<SpreadsheetCell>,?>> { - - /*************************************************************************** - * * STATIC FIELDS * * - **************************************************************************/ - - /** Default height of a row. */ - public static final double DEFAULT_CELL_HEIGHT; - - // FIXME This should seriously be investigated .. - private static final double DATE_CELL_MIN_WIDTH = 200 - Screen.getPrimary().getDpi(); - - static { - double cell_size = 24.0; - try { - Class<?> clazz = com.sun.javafx.scene.control.skin.CellSkinBase.class; - Field f = clazz.getDeclaredField("DEFAULT_CELL_SIZE"); //$NON-NLS-1$ - f.setAccessible(true); - cell_size = f.getDouble(null); - } catch (NoSuchFieldException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (SecurityException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - DEFAULT_CELL_HEIGHT = cell_size; - } - - /** - * When we add some tableCell to some topRow in order for them to be on top - * in term of z-order. We may end up with the situation where the row that - * put the cell is not in the ViewPort anymore. For example when a fixedRow - * has taken over the real row when scrolling down. Then, the tableCell - * added is still hanging out in the topRow. That tableCell has no clue that - * its "creator" has been destroyed or re-used since that tableCell was not - * technically belonging to its "creator". Therefore, we need to track those - * cells in order to remove them each time. - */ - final Map<GridRow,Set<CellView>> deportedCells = new HashMap<>(); - /*************************************************************************** - * * PRIVATE FIELDS * * - **************************************************************************/ - /** - * When resizing, we save the height here in order to override default row - * height. package protected. - */ - ObservableMap<Integer, Double> rowHeightMap = FXCollections.observableHashMap(); - - /** The editor. */ - private GridCellEditor gridCellEditor; - - protected final SpreadsheetHandle handle; - protected SpreadsheetView spreadsheetView; - protected VerticalHeader verticalHeader; - protected HorizontalPicker horizontalPickers; - - /** - * The currently fixedRow. This handles an Integer's set of rows being - * fixed. NOT Fixable but truly fixed. - */ - private ObservableSet<Integer> currentlyFixedRow = FXCollections.observableSet(new HashSet<Integer>()); - - /** - * A list of Integer with the current selected Rows. This is useful for - * HorizontalHeader and VerticalHeader because they need to highlight when a - * selection is made. - */ - private final ObservableList<Integer> selectedRows = FXCollections.observableArrayList(); - - /** - * A list of Integer with the current selected Columns. This is useful for - * HorizontalHeader and VerticalHeader because they need to highlight when a - * selection is made. - */ - private final ObservableList<Integer> selectedColumns = FXCollections.observableArrayList(); - - /** - * The total height of the currently fixedRows. - */ - private double fixedRowHeight = 0; - - /** - * These variable try to optimize the layout of the rows in order not to layout - * every time every row. - * - * So rowToLayout contains the rows that really needs layout(contain span or fixed). - * - * And hBarValue is an indicator for the VirtualFlow. When the Hbar is touched, this BitSet - * is set to false. And when a row is drawing, it flips its value in this BitSet. - * So that we know when scrolling up or down whether a row has taken into account - * that the HBar was moved (otherwise, blank area may appear). - */ - BitSet hBarValue; - BitSet rowToLayout; - - /** - * This rectangle will be used for drawing a border around the selection. - */ - RectangleSelection rectangleSelection; - - /** - * This is the current width used by the currently fixed column on the left. - */ - double fixedColumnWidth; - - /** - * When we try to select cells after a setGrid, we end up with the cell - * selected but no visual confirmation. In order to prevent that, we need to - * warn the selectionModel when the layout is starting and then the - * selectionModel will do the appropriate actions in order to force the - * visual to come. - */ - BooleanProperty lastRowLayout = new SimpleBooleanProperty(true); - - /*************************************************************************** - * * CONSTRUCTOR * * - **************************************************************************/ - public GridViewSkin(final SpreadsheetHandle handle) { - super(handle.getGridView(), new GridViewBehavior(handle.getGridView())); - super.init(handle.getGridView()); - - this.handle = handle; - this.spreadsheetView = handle.getView(); - gridCellEditor = new GridCellEditor(handle); - TableView<ObservableList<SpreadsheetCell>> tableView = handle.getGridView(); - - //Set a new row factory, useful when handling row height. - tableView.setRowFactory(new Callback<TableView<ObservableList<SpreadsheetCell>>, TableRow<ObservableList<SpreadsheetCell>>>() { - @Override - public TableRow<ObservableList<SpreadsheetCell>> call(TableView<ObservableList<SpreadsheetCell>> p) { - return new GridRow(handle); - } - }); - - tableView.getStyleClass().add("cell-spreadsheet"); //$NON-NLS-1$ - - getCurrentlyFixedRow().addListener(currentlyFixedRowListener); - spreadsheetView.getFixedRows().addListener(fixedRowsListener); - spreadsheetView.getFixedColumns().addListener(fixedColumnsListener); - - init(); - /** - * When we are changing the grid we re-instantiate the rowToLayout because - * spans and fixedRow may have changed. - */ - handle.getView().gridProperty().addListener(new ChangeListener<Grid>() { - - @Override - public void changed(ObservableValue<? extends Grid> ov, Grid t, Grid t1) { - rowToLayout = initRowToLayoutBitSet(); - } - }); - hBarValue = new BitSet(handle.getView().getGrid().getRowCount()); - rowToLayout = initRowToLayoutBitSet(); - // Because fixedRow Listener is not reacting first time. - computeFixedRowHeight(); - - - EventHandler<MouseEvent> ml = (MouseEvent event) -> { - // RT-15127: cancel editing on scroll. This is a bit extreme - // (we are cancelling editing on touching the scrollbars). - // This can be improved at a later date. - if (tableView.getEditingCell() != null) { - tableView.edit(-1, null); - } - - // This ensures that the table maintains the focus, even when the vbar - // and hbar controls inside the flow are clicked. Without this, the - // focus border will not be shown when the user interacts with the - // scrollbars, and more importantly, keyboard navigation won't be - // available to the user. - tableView.requestFocus(); - }; - - getFlow().getVerticalBar().addEventFilter(MouseEvent.MOUSE_PRESSED, ml); - getFlow().getHorizontalBar().addEventFilter(MouseEvent.MOUSE_PRESSED, ml); - - // init the behavior 'closures' - TableViewBehavior<ObservableList<SpreadsheetCell>> behavior = getBehavior(); - behavior.setOnFocusPreviousRow(new Runnable() { - @Override public void run() { onFocusPreviousCell(); } - }); - behavior.setOnFocusNextRow(new Runnable() { - @Override public void run() { onFocusNextCell(); } - }); - behavior.setOnMoveToFirstCell(new Runnable() { - @Override public void run() { onMoveToFirstCell(); } - }); - behavior.setOnMoveToLastCell(new Runnable() { - @Override public void run() { onMoveToLastCell(); } - }); - behavior.setOnScrollPageDown(new Callback<Boolean, Integer>() { - @Override public Integer call(Boolean isFocusDriven) { return onScrollPageDown(isFocusDriven); } - }); - behavior.setOnScrollPageUp(new Callback<Boolean, Integer>() { - @Override public Integer call(Boolean isFocusDriven) { return onScrollPageUp(isFocusDriven); } - }); - behavior.setOnSelectPreviousRow(new Runnable() { - @Override public void run() { onSelectPreviousCell(); } - }); - behavior.setOnSelectNextRow(new Runnable() { - @Override public void run() { onSelectNextCell(); } - }); - behavior.setOnSelectLeftCell(new Runnable() { - @Override public void run() { onSelectLeftCell(); } - }); - behavior.setOnSelectRightCell(new Runnable() { - @Override public void run() { onSelectRightCell(); } - }); - - registerChangeListener(tableView.fixedCellSizeProperty(), "FIXED_CELL_SIZE"); - - } - - /** - * Compute the height of a particular row. If the row is in - * {@link Grid#AUTOFIT}, {@link #DEFAULT_CELL_HEIGHT} is returned. - * - * @param row - * @return - */ - public double getRowHeight(int row) { - Double rowHeightCache = rowHeightMap.get(row); - if (rowHeightCache == null) { - double rowHeight = handle.getView().getGrid().getRowHeight(row); - return rowHeight == Grid.AUTOFIT ? DEFAULT_CELL_HEIGHT : rowHeight; - } else { - return rowHeightCache; - } - } - - public double getFixedRowHeight() { - return fixedRowHeight; - } - - public ObservableList<Integer> getSelectedRows() { - return selectedRows; - } - - public ObservableList<Integer> getSelectedColumns() { - return selectedColumns; - } - - public GridCellEditor getSpreadsheetCellEditorImpl() { - return gridCellEditor; - } - - /** - * This return the GridRow which has the specified index if found. Otherwise - * null is returned. - * - * @param index - * @return - */ - public GridRow getRowIndexed(int index) { - List<? extends IndexedCell> cells = getFlow().getCells(); - if (!cells.isEmpty()) { - IndexedCell cell = cells.get(0); - if (index >= cell.getIndex() && index - cell.getIndex() < cells.size()) { - return (GridRow) cells.get(index - cell.getIndex()); - } - } - for (IndexedCell cell : getFlow().getFixedCells()) { - if (cell.getIndex() == index) { - return (GridRow) cell; - } - } - return null; - } - - /** - * This return the row at the specified index in the list. The index - * specified HAS NOTHING to do with the index of the row. - * @see #getRowIndexed(int) for a getting a row with its real index. - * @param index - * @return - */ - public GridRow getRow(int index) { - return (GridRow) getFlow().getCells().get(index); - } - - /** - * Indicate whether or not the row at the specified index is currently being - * displayed. - * - * @param index - * @return - */ - public final boolean containsRow(int index) { - for (Object obj : getFlow().getCells()) { - if (((GridRow) obj).getIndex() == index) - return true; - } - return false; - } - - public int getCellsSize() { - return getFlow().getCells().size(); - } - - public ScrollBar getHBar() { - if (getFlow() != null) { - return getFlow().getHorizontalBar(); - } - return null; - } - - public ScrollBar getVBar() { - return getFlow().getVerticalBar(); - } - - /** - * Will compute for every row the necessary height and fit the line. - * This can degrade performance a lot so need to use it wisely. - * But I don't see other solutions right now. - */ - public void resizeRowsToFitContent() { - Grid grid = spreadsheetView.getGrid(); - int maxRows = handle.getView().getGrid().getRowCount(); - for (int row = 0; row < maxRows; row++) { - if (grid.isRowResizable(row)) { - resizeRowToFitContent(row); - } - } - } - - /** - * Will compute for the row the necessary height and fit the line. - * This can degrade performance a lot so need to use it wisely. - * But I don't see other solutions right now. - * @param row - */ - public void resizeRowToFitContent(int row) { - if(getSkinnable().getColumns().isEmpty()){ - return; - } - final TableColumn<ObservableList<SpreadsheetCell>, ?> col = getSkinnable().getColumns().get(0); - List<?> items = itemsProperty().get(); - if (items == null || items.isEmpty()) { - return; - } - - if (!spreadsheetView.getGrid().isRowResizable(row)) { - return; - } - Callback/* <TableColumn<T, ?>, TableCell<T,?>> */ cellFactory = col.getCellFactory(); - if (cellFactory == null) { - return; - } - - CellView cell = (CellView) cellFactory.call(col); - if (cell == null) { - return; - } - - // set this property to tell the TableCell we want to know its actual - // preferred width, not the width of the associated TableColumnBase - cell.getProperties().put("deferToParentPrefWidth", Boolean.TRUE); //$NON-NLS-1$ - - // determine cell padding - double padding = 5; - - Node n = cell.getSkin() == null ? null : cell.getSkin().getNode(); - if (n instanceof Region) { - Region r = (Region) n; - padding = r.snappedTopInset() + r.snappedBottomInset(); - } - - double maxHeight; - maxHeight = 0; - getChildren().add(cell); - - for (TableColumn column : getSkinnable().getColumns()) { - cell.updateTableColumn(column); - cell.updateTableView(handle.getGridView()); - cell.updateIndex(row); - - if ((cell.getText() != null && !cell.getText().isEmpty()) || cell.getGraphic() != null) { - cell.setWrapText(true); - - cell.impl_processCSS(false); - maxHeight = Math.max(maxHeight, cell.prefHeight(column.getWidth())); - } - } - getChildren().remove(cell); - rowHeightMap.put(row, maxHeight + padding); - Event.fireEvent(spreadsheetView, new SpreadsheetView.RowHeightEvent(row, maxHeight + padding)); - - rectangleSelection.updateRectangle(); - } - - public void resizeRowsToMaximum() { - //First we resize to fit. - resizeRowsToFitContent(); - - Grid grid = spreadsheetView.getGrid(); - - //Then we take the maximum and apply it everywhere. - double maxHeight = 0; - for(int key:rowHeightMap.keySet()){ - maxHeight = Math.max(maxHeight, rowHeightMap.get(key)); - } - - rowHeightMap.clear(); - int maxRows = handle.getView().getGrid().getRowCount(); - for (int row = 0; row < maxRows; row++) { - if (grid.isRowResizable(row)) { - Event.fireEvent(spreadsheetView, new SpreadsheetView.RowHeightEvent(row, maxHeight)); - rowHeightMap.put(row, maxHeight); - } - } - rectangleSelection.updateRectangle(); - } - - public void resizeRowsToDefault() { - rowHeightMap.clear(); - Grid grid = spreadsheetView.getGrid(); - /** - * When resizing to default, we need to go through the visible rows in - * order to update them directly. Because if the rowHeightMap is empty, - * the rows will not detect that maybe the height has changed. - */ - for (GridRow row : (List<GridRow>) getFlow().getCells()) { - if (grid.isRowResizable(row.getIndex())) { - double newHeight = row.computePrefHeight(-1); - if (row.getPrefHeight() != newHeight) { - row.setRowHeight(newHeight); - row.requestLayout(); - } - } - } - - //Fixing https://bitbucket.org/controlsfx/controlsfx/issue/358/ - getFlow().layoutChildren(); - - for (GridRow row : (List<GridRow>) getFlow().getCells()) { - double height = getRowHeight(row.getIndex()); - if (row.getHeight() != height) { - if (grid.isRowResizable(row.getIndex())) { - row.setRowHeight(height); - } - } - } - rectangleSelection.updateRectangle(); - } - /** - * We want to have extra space when displaying LocalDate because they will - * use an editor that display a little icon on the right. Thus, that icon is - * reducing the visibility of the date string. - */ - @Override - public void resizeColumnToFitContent(TableColumn<ObservableList<SpreadsheetCell>, ?> tc, int maxRows) { - - final TableColumn<ObservableList<SpreadsheetCell>, ?> col = tc; - List<?> items = itemsProperty().get(); - if (items == null || items.isEmpty()) { - return; - } - - Callback/* <TableColumn<T, ?>, TableCell<T,?>> */ cellFactory = col.getCellFactory(); - if (cellFactory == null) { - return; - } - - TableCell<ObservableList<SpreadsheetCell>, ?> cell = (TableCell<ObservableList<SpreadsheetCell>, ?>) cellFactory - .call(col); - if (cell == null) { - return; - } - - //The current index of that column - int indexColumn = handle.getGridView().getColumns().indexOf(tc); - - /** - * This is to prevent resize of columns that have the same default width - * at initialisation. If the "system" is calling this method, the - * maxRows will be set at 30. When we set a prefWidth and it's equal to - * the "default width", the system wants to resize the column. We must - * prevent that, thus we check if the two conditions are met. - */ - if(maxRows == 30 && handle.isColumnWidthSet(indexColumn)){ - return; - } - - // set this property to tell the TableCell we want to know its actual - // preferred width, not the width of the associated TableColumnBase - cell.getProperties().put("deferToParentPrefWidth", Boolean.TRUE); //$NON-NLS-1$ - - // determine cell padding - double padding = 10; - Node n = cell.getSkin() == null ? null : cell.getSkin().getNode(); - if (n instanceof Region) { - Region r = (Region) n; - padding = r.snappedLeftInset() + r.snappedRightInset(); - } - - ObservableList<ObservableList<SpreadsheetCell>> gridRows = spreadsheetView.getGrid().getRows();//.get(row) - - /** - * If maxRows is -1, we take all rows. If it's 30, it means it's coming - * from TableColumnHeader during initialization, so we push it to 100. - */ - int rows = maxRows == -1 ? items.size() : Math.min(items.size(), maxRows == 30 ? 100 : maxRows); - double maxWidth = 0; - boolean datePresent = false; - cell.updateTableColumn(col); - cell.updateTableView(handle.getGridView()); - /** - * Sometime the skin is not set, and the width computed is zero which - * destroy the grid... So in that case, we manually set the skin... - */ - if (cell.getSkin() == null) { - cell.setSkin(new CellViewSkin((TableCell<ObservableList<SpreadsheetCell>, SpreadsheetCell>) cell)); - } - for (int row = 0; row < rows; row++) { - cell.updateIndex(row); - - if ((cell.getText() != null && !cell.getText().isEmpty()) || cell.getGraphic() != null) { - getChildren().add(cell); - - if (((SpreadsheetCell) cell.getItem()).getItem() instanceof LocalDate) { - datePresent = true; - } - cell.impl_processCSS(false); - double width = cell.prefWidth(-1); - /** - * If the cell is spanning in column, we need to take the other - * columns into account in the calculation of the width. So we - * compute the width needed by the cell and we substract the - * other columns width. - * - * Also if the cell considered is not in the column, we still - * have to compute because a previous column may have based its - * calculation on the current width which will be modified. - */ - SpreadsheetCell spc = gridRows.get(row).get(indexColumn); - if (spc.getColumnSpan() > 1) { - for (int i = spc.getColumn(); i < spc.getColumn() + spc.getColumnSpan(); ++i) { - if(i != indexColumn){ - width -= spreadsheetView.getColumns().get(i).getWidth(); - } - } - } - maxWidth = Math.max(maxWidth, width); - getChildren().remove(cell); - } - } - - // dispose of the cell to prevent it retaining listeners (see RT-31015) - cell.updateIndex(-1); - - // RT-23486 - double widthMax = maxWidth + padding; - if (handle.getGridView().getColumnResizePolicy() == TableView.CONSTRAINED_RESIZE_POLICY) { - widthMax = Math.max(widthMax, col.getWidth()); - } - - if (datePresent && widthMax < DATE_CELL_MIN_WIDTH) { - widthMax = DATE_CELL_MIN_WIDTH; - } - /** - * This method is called by the system at initialisation and later by - * some methods that check wether the specified column is resizable. So - * we do not check if the column is resizable because it will be checked - * before. If we end up here, it either means the column is resizable, - * OR this is the initialisation and we haven't set a specific width so - * we just compute one time the correct width for that column, and once - * set, it will not be called again. - * - * Also, if the prefWidth has already been set but the user resized the - * column with his mouse, we must force the column to resize because - * setting the prefWidth again will not trigger the listeners. - */ - widthMax = snapSize(widthMax); - if (col.getPrefWidth() == widthMax && col.getWidth() != widthMax) { - col.impl_setWidth(widthMax); - } else { - col.setPrefWidth(widthMax); - } - - rectangleSelection.updateRectangle(); - } - - /*************************************************************************** - * * PRIVATE/PROTECTED METHOD * * - **************************************************************************/ - protected final void init() { - rectangleSelection = new RectangleSelection(this, (TableViewSpanSelectionModel) handle.getGridView().getSelectionModel()); - getFlow().getVerticalBar().valueProperty().addListener(vbarValueListener); - verticalHeader = new VerticalHeader(handle); - getChildren().add(verticalHeader); - - ((HorizontalHeader) getTableHeaderRow()).init(); - verticalHeader.init(this, (HorizontalHeader) getTableHeaderRow()); - - horizontalPickers = new HorizontalPicker((HorizontalHeader) getTableHeaderRow(), spreadsheetView); - getChildren().add(horizontalPickers); - getFlow().init(spreadsheetView); - ((GridViewBehavior)getBehavior()).setGridViewSkin(this); - } - - protected final ObservableSet<Integer> getCurrentlyFixedRow() { - return currentlyFixedRow; - } - - /** - * Used in the HorizontalColumnHeader when we need to resize in double - * click. - * - * @param tc - * @param maxRows - */ - public void resize(TableColumnBase<?, ?> tc, int maxRows) { - if(tc.isResizable()){ - int columnIndex = getColumns().indexOf(tc); - TableColumn tableColumn = getColumns().get(columnIndex); - resizeColumnToFitContent(tableColumn, maxRows); - Event.fireEvent(spreadsheetView, new SpreadsheetView.ColumnWidthEvent(columnIndex, tableColumn.getWidth())); - } - } - - @Override - protected void layoutChildren(double x, double y, double w, final double h) { - if (spreadsheetView == null) { - return; - } - double verticalHeaderWidth = verticalHeader.computeHeaderWidth(); - double horizontalPickerHeight = spreadsheetView.getColumnPickers().isEmpty() ? 0: VerticalHeader.PICKER_SIZE; - - if (spreadsheetView.isShowRowHeader() || !spreadsheetView.getRowPickers().isEmpty()) { - x += verticalHeaderWidth; - w -= verticalHeaderWidth; - } else { - x = 0.0; - } - - - y += horizontalPickerHeight; - super.layoutChildren(x, y, w, h-horizontalPickerHeight); - - final double baselineOffset = getSkinnable().getLayoutBounds().getHeight() / 2; - double tableHeaderRowHeight = 0; - - if(!spreadsheetView.getColumnPickers().isEmpty()){ - layoutInArea(horizontalPickers, x, y - VerticalHeader.PICKER_SIZE, w, tableHeaderRowHeight, baselineOffset, HPos.CENTER, VPos.CENTER); - } - - if (spreadsheetView.showColumnHeaderProperty().get()) { - // position the table header - tableHeaderRowHeight = getTableHeaderRow().prefHeight(-1); - layoutInArea(getTableHeaderRow(), x, y, w, tableHeaderRowHeight, baselineOffset, HPos.CENTER, VPos.CENTER); - - y += tableHeaderRowHeight; - } else { - // This is temporary handled in the HorizontalHeader with Css - // FIXME tweak open in https://javafx-jira.kenai.com/browse/RT-32673 - } - - if (spreadsheetView.isShowRowHeader() || !spreadsheetView.getRowPickers().isEmpty()) { - layoutInArea(verticalHeader, x - verticalHeaderWidth, y - tableHeaderRowHeight, w, h, baselineOffset, - HPos.CENTER, VPos.CENTER); - } - } - - @Override - protected void onFocusPreviousCell() { - focusScroll(); - } - - @Override - protected void onFocusNextCell() { - focusScroll(); - } - - void focusScroll() { - final TableFocusModel<?, ?> fm = getFocusModel(); - if (fm == null) { - return; - } - /** - * *************************************************************** - * MODIFIED - **************************************************************** - */ - final int row = fm.getFocusedIndex(); - // We try to make visible the rows that may be hidden by Fixed rows - if (!getFlow().getCells().isEmpty() - && getFlow().getCells().get(spreadsheetView.getFixedRows().size()).getIndex() > row - && !spreadsheetView.getFixedRows().contains(row)) { - flow.scrollTo(row); - } else { - flow.show(row); - } - scrollHorizontally(); - /** - * *************************************************************** - * END OF MODIFIED - **************************************************************** - */ - } - - @Override - protected void onSelectPreviousCell() { - super.onSelectPreviousCell(); - scrollHorizontally(); - } - - @Override - protected void onSelectNextCell() { - super.onSelectNextCell(); - scrollHorizontally(); - } - - @Override - protected VirtualFlow<TableRow<ObservableList<SpreadsheetCell>>> createVirtualFlow() { - return new GridVirtualFlow<>(this); - } - - @Override - protected TableHeaderRow createTableHeaderRow() { - return new HorizontalHeader(this); - } - - protected HorizontalHeader getHorizontalHeader(){ - return (HorizontalHeader) getTableHeaderRow(); - } - - BooleanProperty getTableMenuButtonVisibleProperty() { - return tableMenuButtonVisibleProperty(); - } - - @Override - public void scrollHorizontally(){ - super.scrollHorizontally(); - } - - @Override - protected void scrollHorizontally(TableColumn<ObservableList<SpreadsheetCell>, ?> col) { - if (col == null || !col.isVisible()) { - return; - } - /** - * We modified this function so that we ensure that any selected cells - * will not be below a fixed column. Because when there's some fixed - * columns, the "left border" is not the table anymore, but the right - * side of the last fixed columns. - * - * Moreover, we need to re-compute the fixedColumnWidth because the - * layout of the rows hasn't been done yet and the value is not right. - * So we might end up below a fixedColumns. - */ - - fixedColumnWidth = 0; - final double pos = getFlow().getHorizontalBar().getValue(); - int index = getColumns().indexOf(col); - double start = 0;// scrollX; - - for (int i = 0; i < index; ++i) { - SpreadsheetColumn column = spreadsheetView.getColumns().get(i); - if (column.isFixed()) { - fixedColumnWidth += column.getWidth(); - } - start += column.getWidth(); - } - - final double end = start + col.getWidth(); - - // determine the visible width of the table - final double headerWidth = handle.getView().getWidth() - snappedLeftInset() - snappedRightInset() - verticalHeader.getVerticalHeaderWidth(); - - // determine by how much we need to translate the table to ensure that - // the start position of this column lines up with the left edge of the - // tableview, and also that the columns don't become detached from the - // right edge of the table - final double max = getFlow().getHorizontalBar().getMax(); - double newPos; - - /** - * If the starting position of our column if inferior to the left egde - * (of tableView or fixed columns), then we need to scroll. - */ - if (start < pos + fixedColumnWidth && start >= 0 && start >= fixedColumnWidth) { - newPos = start - fixedColumnWidth < 0 ? start : start - fixedColumnWidth; - getFlow().getHorizontalBar().setValue(newPos); - //If the starting point is not visible on the right. - } else if(start > pos + headerWidth){ - final double delta = start < 0 || end > headerWidth ? start - pos - fixedColumnWidth : 0; - newPos = pos + delta > max ? max : pos + delta; - getFlow().getHorizontalBar().setValue(newPos); - } - /** - * In all other cases, it means the cell is visible so no scroll needed, - * because otherwise we may end up with a continous scroll that always - * place the selected cell in the center of the screen. - */ - } - - private void verticalScroll() { - verticalHeader.requestLayout(); - } - - GridVirtualFlow<?> getFlow() { - return (GridVirtualFlow<?>) flow; - } - - /** - * Return a BitSet of the rows that needs layout all the time. This - * includes any row containing a span, or a fixed row. - * @return - */ - private BitSet initRowToLayoutBitSet(){ - Grid grid = handle.getView().getGrid(); - BitSet bitSet = new BitSet(grid.getRowCount()); - for(int row = 0;row<grid.getRowCount();++row){ - if(spreadsheetView.getFixedRows().contains(row)){ - bitSet.set(row); - continue; - } - List<SpreadsheetCell> myRow = grid.getRows().get(row); - for(SpreadsheetCell cell:myRow){ - - if(cell.getRowSpan()>1 /*|| cell.getColumnSpan() >1*/){ - bitSet.set(row); - break; - } - } - } - return bitSet; - } - - /** - * When the vertical moves, we update the verticalHeader - */ - private final InvalidationListener vbarValueListener = new InvalidationListener() { - @Override - public void invalidated(Observable valueModel) { - verticalScroll(); - } - }; - - /** - * We listen on the FixedRows in order to do the modification in the - * VirtualFlow - */ - private final ListChangeListener<Integer> fixedRowsListener = new ListChangeListener<Integer>() { - @Override - public void onChanged(Change<? extends Integer> c) { - hBarValue.clear(); - while (c.next()) { - if (c.wasPermutated()) { - for (Integer fixedRow : c.getList()) { - rowToLayout.set(fixedRow, true); - } - } else { - for (Integer unfixedRow : c.getRemoved()) { - rowToLayout.set(unfixedRow, false); - //If the grid permits it, we check the spanning in order not - //to remove a row that might need layout. - if (spreadsheetView.getGrid().getRows().size() > unfixedRow) { - List<SpreadsheetCell> myRow = spreadsheetView.getGrid().getRows().get(unfixedRow); - for (SpreadsheetCell cell : myRow) { - if (cell.getRowSpan() > 1 || cell.getColumnSpan() > 1) { - rowToLayout.set(unfixedRow, true); - break; - } - } - } - } - - //We check for the newly fixedRow - for (Integer fixedRow : c.getAddedSubList()) { - rowToLayout.set(fixedRow, true); - } - } - } - // requestLayout() not responding immediately.. - getFlow().requestLayout(); - } - }; - - /** - * We listen on the currentlyFixedRow in order to do the modification in the - * FixedRowHeight. - */ - private final SetChangeListener<? super Integer> currentlyFixedRowListener = new SetChangeListener<Integer>() { - @Override - public void onChanged(javafx.collections.SetChangeListener.Change<? extends Integer> arg0) { - computeFixedRowHeight(); - } - }; - - /** - * We compute the total height of the fixedRows so that the selection can - * use it without performance regression. - */ - public void computeFixedRowHeight() { - fixedRowHeight = 0; - for (int i : getCurrentlyFixedRow()) { - fixedRowHeight += getRowHeight(i); - } - } - - /** - * We listen on the FixedColumns in order to do the modification in the - * VirtualFlow. - */ - private final ListChangeListener<SpreadsheetColumn> fixedColumnsListener = new ListChangeListener<SpreadsheetColumn>() { - @Override - public void onChanged(Change<? extends SpreadsheetColumn> c) { - hBarValue.clear(); - getFlow().requestLayout(); - // requestLayout() not responding immediately.. -// getFlow().layoutTotal(); - } - }; - - @Override - protected TableSelectionModel<ObservableList<SpreadsheetCell>> getSelectionModel() { - return getSkinnable().getSelectionModel(); - } - - @Override - protected TableFocusModel<ObservableList<SpreadsheetCell>, TableColumn<ObservableList<SpreadsheetCell>, ?>> getFocusModel() { - return getSkinnable().getFocusModel(); - } - - @Override - protected TablePositionBase<? extends TableColumn<ObservableList<SpreadsheetCell>, ?>> getFocusedCell() { - return getSkinnable().getFocusModel().getFocusedCell(); - } - - @Override - protected ObservableList<? extends TableColumn<ObservableList<SpreadsheetCell>, ?>> getVisibleLeafColumns() { - return getSkinnable().getVisibleLeafColumns(); - } - - @Override - protected int getVisibleLeafIndex(TableColumn<ObservableList<SpreadsheetCell>, ?> tc) { - return getSkinnable().getVisibleLeafIndex(tc); - } - - @Override - protected TableColumn<ObservableList<SpreadsheetCell>, ?> getVisibleLeafColumn(int col) { - return getSkinnable().getVisibleLeafColumn(col); - } - - @Override - protected ObservableList<TableColumn<ObservableList<SpreadsheetCell>, ?>> getColumns() { - return getSkinnable().getColumns(); - } - - @Override - protected ObservableList<TableColumn<ObservableList<SpreadsheetCell>, ?>> getSortOrder() { - return getSkinnable().getSortOrder(); - } - - @Override - protected ObjectProperty<ObservableList<ObservableList<SpreadsheetCell>>> itemsProperty() { - return getSkinnable().itemsProperty(); - } - - @Override - protected ObjectProperty<Callback<TableView<ObservableList<SpreadsheetCell>>, TableRow<ObservableList<SpreadsheetCell>>>> rowFactoryProperty() { - return getSkinnable().rowFactoryProperty(); - } - - @Override - protected ObjectProperty<Node> placeholderProperty() { - return getSkinnable().placeholderProperty(); - } - - @Override - protected BooleanProperty tableMenuButtonVisibleProperty() { - return getSkinnable().tableMenuButtonVisibleProperty(); - } - - @Override - protected ObjectProperty<Callback<ResizeFeaturesBase, Boolean>> columnResizePolicyProperty() { - return (ObjectProperty<Callback<ResizeFeaturesBase, Boolean>>) (Object)getSkinnable().columnResizePolicyProperty(); - } - - @Override - protected boolean resizeColumn(TableColumn<ObservableList<SpreadsheetCell>, ?> tc, double delta) { - getHorizontalHeader().getRootHeader().lastColumnResized = getColumns().indexOf(tc); - boolean returnedValue = getSkinnable().resizeColumn(tc, delta); - if(returnedValue){ - Event.fireEvent(spreadsheetView, new SpreadsheetView.ColumnWidthEvent(getColumns().indexOf(tc), tc.getWidth())); - } - return returnedValue; - } - - @Override - protected void edit(int index, TableColumn<ObservableList<SpreadsheetCell>, ?> column) { - getSkinnable().edit(index, column); - } - - @Override - public TableRow<ObservableList<SpreadsheetCell>> createCell() { - TableRow<ObservableList<SpreadsheetCell>> cell; - - if (getSkinnable().getRowFactory() != null) { - cell = getSkinnable().getRowFactory().call(getSkinnable()); - } else { - cell = new TableRow<>(); - } - - cell.updateTableView(getSkinnable()); - return cell; - } - - @Override - public int getItemCount() { - return getSkinnable().getItems() == null ? 0 : getSkinnable().getItems().size(); - } - - /** - * If the scene is not yet instantiated, we need to wait otherwise the - * VirtualFlow will not shift the cells properly. - * - * @param value - */ - public void setHbarValue(double value) { - setHbarValue(value, 0); - } - - public void setHbarValue(double value, int count) { - if (count > 5) { - return; - } - final int newCount = count + 1; - if (flow.getScene() == null) { - Platform.runLater(() -> { - setHbarValue(value, newCount); - }); - return; - } - getHBar().setValue(value); - } -} diff --git a/src/impl/org/controlsfx/spreadsheet/GridVirtualFlow.java b/src/impl/org/controlsfx/spreadsheet/GridVirtualFlow.java deleted file mode 100644 index ea54945..0000000 --- a/src/impl/org/controlsfx/spreadsheet/GridVirtualFlow.java +++ /dev/null @@ -1,426 +0,0 @@ -/** - * Copyright (c) 2013, 2016 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.spreadsheet; - -import com.sun.javafx.scene.control.skin.VirtualFlow; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import javafx.beans.Observable; -import javafx.beans.binding.When; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.collections.ObservableList; -import javafx.scene.Group; -import javafx.scene.Node; -import javafx.scene.control.IndexedCell; -import javafx.scene.control.ScrollBar; -import javafx.scene.control.TableRow; -import javafx.scene.input.MouseEvent; -import javafx.scene.layout.Region; -import javafx.scene.shape.Rectangle; -import org.controlsfx.control.spreadsheet.SpreadsheetCell; -import org.controlsfx.control.spreadsheet.SpreadsheetView; - -public final class GridVirtualFlow<T extends IndexedCell<?>> extends VirtualFlow<T> { - - /** - * With that comparator we can lay out our rows in the reverse order. That - * is to say from the bottom to the very top. In that manner we are sure - * that our spanning cells will COVER the cell below so we don't have any - * problems with missing hovering, the editor jammed etc. - * <br/> - * - * The only problem is for the fixed column but the {@link #getTopRow(int) } - * now returns the very first row and allow us to put some privileged - * TableCell in it if they feel the need to be on top in term of z-order. - * - * FIXME The best would be to put a TreeList of something like that in order - * not to sort the rows everytime, need investigation.. - */ - private static final Comparator<GridRow> ROWCMP = new Comparator<GridRow>() { - @Override - public int compare(GridRow firstRow, GridRow secondRow) { - //o1.getIndex() < o2.getIndex() ? -1 : +1; - return secondRow.getIndex() - firstRow.getIndex(); - } - }; - - /*************************************************************************** - * * Private Fields * * - **************************************************************************/ - private SpreadsheetView spreadSheetView; - private final GridViewSkin gridViewSkin; - /** - * Store the fixedRow in order to place them at the top when necessary. - * That is to say, when the VirtualFlow has not already placed one. - */ - private final ArrayList<T> myFixedCells = new ArrayList<>(); - public final List<Node> sheetChildren; - - /*************************************************************************** - * * Constructor * * - **************************************************************************/ - public GridVirtualFlow(GridViewSkin gridViewSkin) { - super(); - this.gridViewSkin = gridViewSkin; - final ChangeListener<Number> listenerY = new ChangeListener<Number>() { - @Override - public void changed(ObservableValue<? extends Number> ov, Number t, Number t1) { - layoutTotal(); - } - }; - getVbar().valueProperty().addListener(listenerY); - getHbar().valueProperty().addListener(hBarValueChangeListener); - widthProperty().addListener(hBarValueChangeListener); - - sheetChildren = findSheetChildren(); - - //When we click outside of the grid, we want to deselect all cells. - addEventHandler(MouseEvent.MOUSE_PRESSED, (MouseEvent event) -> { - if (event.getTarget().getClass() == GridRow.class) { - spreadSheetView.getSelectionModel().clearSelection(); - } - }); - } - - /*************************************************************************** - * * Public Methods * * - **************************************************************************/ - public void init(SpreadsheetView spv) { - /** - * The idea is to work-around - * https://javafx-jira.kenai.com/browse/RT-36396 in order to have the - * same behavior between the vertical scrollBar and the horizontal - * scrollBar. - */ - getHbar().maxProperty().addListener(new ChangeListener<Number>() { - - @Override - public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) { - //We want to go page by page. - getHbar().setBlockIncrement(getWidth()); - getHbar().setUnitIncrement(newValue.doubleValue()/20); - } - }); - - this.spreadSheetView = spv; - - //We clip the rectangle selection with a rectangle, inception style. - Rectangle rec = new Rectangle(); - rec.widthProperty().bind(widthProperty().subtract(new When(getVbar().visibleProperty()).then(getVbar().widthProperty()).otherwise(0))); - rec.heightProperty().bind(heightProperty().subtract(new When(getHbar().visibleProperty()).then(getHbar().heightProperty()).otherwise(0))); - gridViewSkin.rectangleSelection.setClip(rec); - - getChildren().add(gridViewSkin.rectangleSelection); - - spv.getFixedRows().addListener((Observable observable) -> { - List<T> toRemove = new ArrayList<>(); - for (T cell : myFixedCells) { - if (!spv.getFixedRows().contains(cell.getIndex())) { - cell.setManaged(false); - cell.setVisible(false); - toRemove.add(cell); - } - } - myFixedCells.removeAll(toRemove); - }); - } - - @Override - public void show(int index) { - super.show(index); - layoutTotal(); - layoutFixedRows(); - } - - @Override - public void scrollTo(int index) { - //If we have some fixedRows, we check if the selected row is not below them - if (!getCells().isEmpty() && spreadSheetView.getFixedRows().size() > 0) { - double offset = gridViewSkin.getFixedRowHeight(); - - while (offset >= 0 && index > 0) { - index--; - offset -= gridViewSkin.getRowHeight(index); - } - } - super.scrollTo(index); - - layoutTotal(); - layoutFixedRows(); - } - - @Override - public double adjustPixels(final double delta) { - final double returnValue = super.adjustPixels(delta); - - layoutTotal(); - layoutFixedRows(); - - return returnValue; - } - - List<T> getFixedCells(){ - return myFixedCells; - } - /*************************************************************************** - * * Protected Methods * * - **************************************************************************/ - - /** - * We need to return here the very top row in term of "z-order". Because we - * will add in this row the TableCell that are in fixedColumn and which - * needs to be drawn on top of all others. - * - * @return - */ - GridRow getTopRow() { - if (!sheetChildren.isEmpty()) { - return (GridRow) sheetChildren.get(sheetChildren.size() - 1); - } - return null; - } - - @Override - protected void layoutChildren() { - /** - * In fact, we must do a layout even when editing, because if the user - * resize the window during edition, if we block layout, the view will - * be in a wrong state. - */ - if (spreadSheetView != null - /*&& (spreadSheetView.getEditingCell() == null || spreadSheetView - .getEditingCell().getRow() == -1)*/) { - sortRows(); - super.layoutChildren(); - layoutTotal(); - layoutFixedRows(); - - /** - * Sometimes, the visible amount is not computed when we have few - * big rows. If we detect that case, we must compute it manually - * otherwise the Vbar is wrongly set. - */ - if (getVbar().getVisibleAmount() == 0.0 - && getVbar().isVisible() - && getCells().size() != getCellCount()) { - getVbar().setMax(1); - getVbar().setVisibleAmount(getCells().size() / (float) getCellCount()); - } - } - } - - /** - * Layout all the visible rows - */ - protected void layoutTotal() { - sortRows(); - - /** - * When we layout, we also remove the cell that have been deported into - * other rows in order not to have some TableCell hanging out. - */ - for(GridRow row : gridViewSkin.deportedCells.keySet()){ - for(CellView cell: gridViewSkin.deportedCells.get(row)){ - row.removeCell(cell); - } - } - gridViewSkin.deportedCells.clear(); - // When scrolling fast with fixed Rows, cells is empty and not recreated.. - if (getCells().isEmpty()) { - reconfigureCells(); - } - - for (GridRow cell : (List<GridRow>)getCells()) { - if (cell != null && cell.getIndex() >= 0 && (!gridViewSkin.hBarValue.get(cell.getIndex()) || gridViewSkin.rowToLayout.get(cell.getIndex()))) { - cell.requestLayout(); - } - } - } - - protected ScrollBar getVerticalBar() { - return getVbar(); - } - protected ScrollBar getHorizontalBar() { - return getHbar(); - } - - @Override - protected List<T> getCells() { - return super.getCells(); - } - - /*************************************************************************** - * * Private Methods * * - **************************************************************************/ - - /** - * WARNING : This is bad but no other options right now. This will find the - * sheetChildren of the VirtualFlow, aka where the cells are kept and - * clipped. See layoutFixedRows() or getTopRow() for use. - * - * @return - */ - private List<Node> findSheetChildren(){ - if(!getChildren().isEmpty()){ - if(getChildren().get(0) instanceof Region){ - Region region = (Region) getChildren().get(0); - if(!region.getChildrenUnmodifiable().isEmpty()){ - if(region.getChildrenUnmodifiable().get(0) instanceof Group){ - return ((Group)region.getChildrenUnmodifiable().get(0)).getChildren(); - } - } - } - } - return new ArrayList<>(); - } - - /** - * Layout the fixed rows to position them correctly - */ - private void layoutFixedRows() { - - //We must have a cell in ViewPort because otherwise - //we short-circuit the VirtualFlow. - if (spreadSheetView.getFixedRows().size() > 0 && getFirstVisibleCellWithinViewPort() != null) { - sortRows(); - /** - * What I do is just going after the VirtualFlow in order to ADD - * (not replace like before) new rows at the top. - * - * If the VirtualFlow has the row, then I will hide mine and let him - * handle. But if the row is missing, then I must show mine in order - * to have the fixed row. - */ - T row = null; - Integer fixedRowIndex; - - rows: - for (int i = spreadSheetView.getFixedRows().size() - 1; i >= 0; i--) { - fixedRowIndex = spreadSheetView.getFixedRows().get(i); - T lastCell = getLastVisibleCellWithinViewPort(); - //If the fixed row is out of bounds - if (lastCell != null && fixedRowIndex > lastCell.getIndex()) { - if (row != null) { - row.setVisible(false); - row.setManaged(false); - sheetChildren.remove(row); - } - continue; - } - - //We see if the row is laid out by the VirtualFlow - for (T virtualFlowCells : getCells()) { - if (virtualFlowCells.getIndex() > fixedRowIndex) { - break; - } else if (virtualFlowCells.getIndex() == fixedRowIndex) { - row = containsRows(fixedRowIndex); - if (row != null) { - row.setVisible(false); - row.setManaged(false); - sheetChildren.remove(row); - } - /** - * OLD COMMENT : We must push to Front only if the row - * is at the very top and has a risk to be recovered. - * This is happening only if this row is translated. - * - * NEW COMMENT: I'm not sure about this.. Since the - * fixedColumn are not in the special top row, we don't - * care if the row is pushed to front.. need - * investigation - */ - virtualFlowCells.toFront(); - continue rows; - } - } - - row = containsRows(fixedRowIndex); - if (row == null) { - /** - * getAvailableCell is not added our cell to the ViewPort in some cases. - * So we need to instantiate it ourselves. - */ - row = getCreateCell().call(this); - row.getProperties().put("newcell", null); //$NON-NLS-1$ - - setCellIndex(row, fixedRowIndex); - resizeCellSize(row); - myFixedCells.add(row); - } - - /** - * Sometime, when we set a new Grid on a SpreadsheetView without recreating it, - * we can end up with some rows not being added to the ViewPort. - * So we must be sure it's in and add it ourself otherwise. - */ - if(!sheetChildren.contains(row)){ - sheetChildren.add(row); - } - - row.setManaged(true); - row.setVisible(true); - row.toFront(); - row.requestLayout(); - } - } - } - - /** - * Verify if the row has been added to myFixedCell - * @param i - * @return - */ - private T containsRows(int i){ - for(T cell:myFixedCells){ - if(cell.getIndex() == i) - return cell; - } - return null; - } - /** - * Sort the rows so that they stay in order for layout - */ - private void sortRows() { - final List<GridRow> temp = (List<GridRow>) getCells(); - final List<GridRow> tset = new ArrayList<>(temp); - Collections.sort(tset, ROWCMP); - for (final TableRow<ObservableList<SpreadsheetCell>> r : tset) { - r.toFront(); - } - } - - private final ChangeListener<Number> hBarValueChangeListener = new ChangeListener<Number>() { - @Override - public void changed(ObservableValue<? extends Number> ov, Number t, Number t1) { - gridViewSkin.hBarValue.clear(); - } - }; -} - diff --git a/src/impl/org/controlsfx/spreadsheet/HorizontalHeader.java b/src/impl/org/controlsfx/spreadsheet/HorizontalHeader.java deleted file mode 100644 index 6540da8..0000000 --- a/src/impl/org/controlsfx/spreadsheet/HorizontalHeader.java +++ /dev/null @@ -1,349 +0,0 @@ -/** - * Copyright (c) 2013, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.spreadsheet; - -import com.sun.javafx.scene.control.skin.NestedTableColumnHeader; -import com.sun.javafx.scene.control.skin.TableColumnHeader; -import com.sun.javafx.scene.control.skin.TableHeaderRow; -import java.util.BitSet; -import java.util.List; -import javafx.application.Platform; -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.collections.ListChangeListener; -import javafx.collections.ObservableList; -import javafx.event.EventHandler; -import javafx.scene.control.TableColumn; -import javafx.scene.control.TablePosition; -import javafx.scene.control.TableView.TableViewSelectionModel; -import javafx.scene.input.MouseEvent; -import javafx.scene.shape.Rectangle; -import org.controlsfx.control.spreadsheet.SpreadsheetCell; -import org.controlsfx.control.spreadsheet.SpreadsheetColumn; -import org.controlsfx.control.spreadsheet.SpreadsheetView; - -/** - * The set of horizontal (column) headers. - */ -public class HorizontalHeader extends TableHeaderRow { - - final GridViewSkin gridViewSkin; - - // Indicate whether the this HorizontalHeader is activated or not - private boolean working = true; - /** - * When the columns header are clicked, we consider the column as selected. - * This BitSet is reset when a modification on cells is done. - */ - protected BitSet selectedColumns = new BitSet(); - - /*************************************************************************** - * - * Constructor - * - **************************************************************************/ - public HorizontalHeader(final GridViewSkin skin) { - super(skin); - gridViewSkin = skin; - } - - /************************************************************************** - * - * Public API - * - **************************************************************************/ - public void init() { - SpreadsheetView spv = gridViewSkin.handle.getView(); - updateHorizontalHeaderVisibility(spv.isShowColumnHeader()); - - //Visibility of vertical Header listener - spv.showRowHeaderProperty().addListener(verticalHeaderListener); - gridViewSkin.verticalHeader.verticalHeaderWidthProperty().addListener(verticalHeaderListener); - - //Visibility of horizontal Header listener - spv.showColumnHeaderProperty().addListener(horizontalHeaderVisibilityListener); - - //Selection listener to highlight header - gridViewSkin.getSelectedColumns().addListener(selectionListener); - - //Fixed Column listener to change style of header - spv.getFixedColumns().addListener(fixedColumnsListener); - - Platform.runLater(() -> { - //We are doing that because some columns may be already fixed. - for (SpreadsheetColumn column : spv.getFixedColumns()) { - fixColumn(column); - } - requestLayout(); - /** - * Clicking on header select the whole column. - */ - installHeaderMouseEvent(); - }); - - /** - * When we are setting a new Grid (model) on the SpreadsheetView, it - * appears that the headers are re-created. So we need to listen to - * those changes in order to re-apply our css style class. Otherwise - * we'll end up with fixedColumns but no graphic confirmation. - */ - getRootHeader().getColumnHeaders().addListener((Observable o) -> { - for (SpreadsheetColumn fixItem : spv.getFixedColumns()) { - fixColumn(fixItem); - } - updateHighlightSelection(); - installHeaderMouseEvent(); - }); - } - - @Override - public HorizontalHeaderColumn getRootHeader() { - return (HorizontalHeaderColumn) super.getRootHeader(); - } - - void clearSelectedColumns(){ - selectedColumns.clear(); - } - /************************************************************************** - * - * Protected methods - * - **************************************************************************/ - @Override - protected void updateTableWidth() { - super.updateTableWidth(); - // snapping added for RT-19428 - double padding = 0; - - if (working && gridViewSkin != null - && gridViewSkin.spreadsheetView != null - && gridViewSkin.spreadsheetView.showRowHeaderProperty().get() - && gridViewSkin.verticalHeader != null) { - padding += gridViewSkin.verticalHeader.getVerticalHeaderWidth(); - } - - Rectangle clip = ((Rectangle) getClip()); - - clip.setWidth(clip.getWidth() == 0 ? 0 : clip.getWidth() - padding); - } - - @Override - protected void updateScrollX() { - super.updateScrollX(); - gridViewSkin.horizontalPickers.updateScrollX(); - - if (working) { - requestLayout(); - getRootHeader().layoutFixedColumns(); - } - } - - @Override - protected NestedTableColumnHeader createRootHeader() { - return new HorizontalHeaderColumn(getTableSkin(), null); - } - - /************************************************************************** - * - * Private methods. - * - **************************************************************************/ - - /** - * When we click on header, we want to select the whole column. - */ - private void installHeaderMouseEvent() { - for (final TableColumnHeader columnHeader : getRootHeader().getColumnHeaders()) { - EventHandler<MouseEvent> mouseEventHandler = (MouseEvent mouseEvent) -> { - if (mouseEvent.isPrimaryButtonDown()) { - headerClicked((TableColumn) columnHeader.getTableColumn(), mouseEvent); - } - }; - columnHeader.getChildrenUnmodifiable().get(0).setOnMousePressed(mouseEventHandler); - } - } - /** - * If a header is clicked, we must select the whole column. If Control key of - * Shift key is pressed, we must not deselect the previous selection but - * just act like the {@link GridViewBehavior} would. - * - * @param column - * @param event - */ - private void headerClicked(TableColumn column, MouseEvent event) { - TableViewSelectionModel<ObservableList<SpreadsheetCell>> sm = gridViewSkin.handle.getGridView().getSelectionModel(); - int lastRow = gridViewSkin.spreadsheetView.getGrid().getRowCount() - 1; - int indexColumn = column.getTableView().getColumns().indexOf(column); - TablePosition focusedPosition = sm.getTableView().getFocusModel().getFocusedCell(); - if (event.isShortcutDown()) { - BitSet tempSet = (BitSet) selectedColumns.clone(); - sm.selectRange(0, column, lastRow, column); - selectedColumns.or(tempSet); - selectedColumns.set(indexColumn); - } else if (event.isShiftDown() && focusedPosition != null && focusedPosition.getTableColumn() != null) { - sm.clearSelection(); - sm.selectRange(0, column, lastRow, focusedPosition.getTableColumn()); - sm.getTableView().getFocusModel().focus(0, focusedPosition.getTableColumn()); - int min = Math.min(indexColumn, focusedPosition.getColumn()); - int max = Math.max(indexColumn, focusedPosition.getColumn()); - selectedColumns.set(min, max + 1); - } else { - sm.clearSelection(); - sm.selectRange(0, column, lastRow, column); - //And we want to have the focus on the first cell in order to be able to copy/paste between columns. - sm.getTableView().getFocusModel().focus(0, column); - selectedColumns.set(indexColumn); - } - } - /** - * Whether the Vertical Header is showing, we need to update the width - * because some space on the left will be available/used. - */ - private final InvalidationListener verticalHeaderListener = new InvalidationListener() { - - @Override - public void invalidated(Observable observable) { - updateTableWidth(); - } - }; - - /** - * Whether the Horizontal Header is showing, we need to toggle its - * visibility. - */ - private final ChangeListener<Boolean> horizontalHeaderVisibilityListener = new ChangeListener<Boolean>() { - @Override - public void changed(ObservableValue<? extends Boolean> arg0, Boolean arg1, Boolean arg2) { - updateHorizontalHeaderVisibility(arg2); - } - }; - - /** - * When we fix/unfix some columns, we change the style of the Label header - * text - */ - private final ListChangeListener<SpreadsheetColumn> fixedColumnsListener = new ListChangeListener<SpreadsheetColumn>() { - - @Override - public void onChanged(javafx.collections.ListChangeListener.Change<? extends SpreadsheetColumn> change) { - while (change.next()) { - //If we unfix a column - for (SpreadsheetColumn remitem : change.getRemoved()) { - unfixColumn(remitem); - } - //If we fix one - for (SpreadsheetColumn additem : change.getAddedSubList()) { - fixColumn(additem); - } - } - updateHighlightSelection(); - } - }; - - /** - * Fix this column regarding the style - * - * @param column - */ - private void fixColumn(SpreadsheetColumn column) { - addStyleHeader(gridViewSkin.spreadsheetView.getColumns().indexOf(column)); - } - - /** - * Unfix this column regarding the style - * - * @param column - */ - private void unfixColumn(SpreadsheetColumn column) { - removeStyleHeader(gridViewSkin.spreadsheetView.getColumns().indexOf(column)); - } - - /** - * Add the fix style of the header Label of the specified column - * - * @param i - */ - private void removeStyleHeader(Integer i) { - if (getRootHeader().getColumnHeaders().size() > i) { - getRootHeader().getColumnHeaders().get(i).getStyleClass().removeAll("fixed"); //$NON-NLS-1$ - } - } - - /** - * Remove the fix style of the header Label of the specified column - * - * @param i - */ - private void addStyleHeader(Integer i) { - if (getRootHeader().getColumnHeaders().size() > i) { - getRootHeader().getColumnHeaders().get(i).getStyleClass().addAll("fixed"); //$NON-NLS-1$ - } - } - - /** - * When we select some cells, we want the header to be highlighted - */ - private final InvalidationListener selectionListener = new InvalidationListener() { - @Override - public void invalidated(Observable valueModel) { - updateHighlightSelection(); - } - }; - - /** - * Highlight the header Label when selection change. - */ - private void updateHighlightSelection() { - for (final TableColumnHeader i : getRootHeader().getColumnHeaders()) { - i.getStyleClass().removeAll("selected"); //$NON-NLS-1$ - - } - final List<Integer> selectedColumns = gridViewSkin.getSelectedColumns(); - for (final Integer i : selectedColumns) { - if (getRootHeader().getColumnHeaders().size() > i) { - getRootHeader().getColumnHeaders().get(i).getStyleClass() - .addAll("selected"); //$NON-NLS-1$ - } - } - - } - - private void updateHorizontalHeaderVisibility(boolean visible) { - working = visible; - setManaged(working); - if (!visible) { - getStyleClass().add("invisible"); //$NON-NLS-1$ - } else { - getStyleClass().remove("invisible"); //$NON-NLS-1$ - requestLayout(); - getRootHeader().layoutFixedColumns(); - updateHighlightSelection(); - } - } -} diff --git a/src/impl/org/controlsfx/spreadsheet/HorizontalHeaderColumn.java b/src/impl/org/controlsfx/spreadsheet/HorizontalHeaderColumn.java deleted file mode 100644 index a8d7726..0000000 --- a/src/impl/org/controlsfx/spreadsheet/HorizontalHeaderColumn.java +++ /dev/null @@ -1,149 +0,0 @@ -/** - * Copyright (c) 2013, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.spreadsheet; - -import org.controlsfx.control.spreadsheet.SpreadsheetView; - -import javafx.event.EventHandler; -import javafx.scene.control.TableColumnBase; -import javafx.scene.input.MouseEvent; - -import com.sun.javafx.scene.control.skin.NestedTableColumnHeader; -import com.sun.javafx.scene.control.skin.TableColumnHeader; -import com.sun.javafx.scene.control.skin.TableViewSkinBase; -import javafx.beans.Observable; -import javafx.beans.value.ObservableValue; - -/** - * A cell column header. - */ -public class HorizontalHeaderColumn extends NestedTableColumnHeader { - - int lastColumnResized = -1; - - public HorizontalHeaderColumn( - TableViewSkinBase<?, ?, ?, ?, ?, ?> skin, TableColumnBase<?, ?> tc) { - super(skin, tc); - /** - * Resolve https://bitbucket.org/controlsfx/controlsfx/issue/395 - * and https://bitbucket.org/controlsfx/controlsfx/issue/434 - */ - widthProperty().addListener((Observable observable) -> { - ((GridViewSkin)skin).hBarValue.clear(); - ((GridViewSkin)skin).rectangleSelection.updateRectangle(); - }); - - /** - * We want to resize all other selected columns when we resize one. - * - * I cannot really determine when a resize is finished. Apparently, when - * this variable Layout is set to 0, it means the drag is done, so until - * a beter solution is shown, it will do the trick. - */ - columnReorderLine.layoutXProperty().addListener((ObservableValue<? extends Number> observable, Number oldValue, Number newValue) -> { - HorizontalHeader headerRow = (HorizontalHeader) ((GridViewSkin) skin).getTableHeaderRow(); - GridViewSkin mySkin = ((GridViewSkin) skin); - if (newValue.intValue() == 0 && lastColumnResized >= 0) { - if (headerRow.selectedColumns.get(lastColumnResized)) { - double width1 = mySkin.getColumns().get(lastColumnResized).getWidth(); - for (int i = headerRow.selectedColumns.nextSetBit(0); i >= 0; i = headerRow.selectedColumns.nextSetBit(i + 1)) { - mySkin.getColumns().get(i).setPrefWidth(width1); - } - } - } - }); - } - - @Override - protected TableColumnHeader createTableColumnHeader(final TableColumnBase col) { - TableViewSkinBase<?,?,?,?,?,TableColumnBase<?,?>> tableViewSkin = getTableViewSkin(); - if (col.getColumns().isEmpty()) { - final TableColumnHeader columnHeader = new TableColumnHeader(tableViewSkin, col); - /** - * When the user double click on a header, we want to resize the - * column to fit the content. - */ - columnHeader.setOnMousePressed(new EventHandler<MouseEvent>() { - @Override - public void handle(MouseEvent mouseEvent) { - if (mouseEvent.getClickCount() == 2 && mouseEvent.isPrimaryButtonDown()) { - ((GridViewSkin) (Object) tableViewSkin).resize(col, -1); - } - } - }); - return columnHeader; - } else { - return new HorizontalHeaderColumn(getTableViewSkin(), col); - } - } - - @Override - protected void layoutChildren() { - super.layoutChildren(); - layoutFixedColumns(); - } - - /** - * We want ColumnHeader to be fixed when we freeze some columns - * - */ - public void layoutFixedColumns() { - SpreadsheetHandle handle = ((GridViewSkin) (Object) getTableViewSkin()).handle; - final SpreadsheetView spreadsheetView = handle.getView(); - if (handle.getCellsViewSkin() == null || getChildren().isEmpty()) { - return; - } - double hbarValue = handle.getCellsViewSkin().getHBar().getValue(); - - final int labelHeight = (int) getChildren().get(0).prefHeight(-1); - double fixedColumnWidth = 0; - double x = snappedLeftInset(); - int max = getColumnHeaders().size(); - max = max > spreadsheetView.getColumns().size() ? spreadsheetView.getColumns().size() : max; - for (int j = 0 ; j < max; j++) { - final TableColumnHeader n = getColumnHeaders().get(j); - final double prefWidth = snapSize(n.prefWidth(-1)); - n.setPrefHeight(24.0); - //If the column is fixed - if (spreadsheetView.getFixedColumns().indexOf(spreadsheetView.getColumns().get(j)) != -1) { - double tableCellX = 0; - //If the column is hidden we have to translate it - if (hbarValue + fixedColumnWidth > x) { - - tableCellX = Math.abs(hbarValue - x + fixedColumnWidth); - - n.toFront(); - fixedColumnWidth += prefWidth; - } - n.relocate(x + tableCellX, labelHeight + snappedTopInset()); - } - - x += prefWidth; - } - - } -} diff --git a/src/impl/org/controlsfx/spreadsheet/HorizontalPicker.java b/src/impl/org/controlsfx/spreadsheet/HorizontalPicker.java deleted file mode 100644 index 9ef50ab..0000000 --- a/src/impl/org/controlsfx/spreadsheet/HorizontalPicker.java +++ /dev/null @@ -1,152 +0,0 @@ -/** - * Copyright (c) 2014 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.spreadsheet; - -import com.sun.javafx.scene.control.skin.TableColumnHeader; -import java.util.Stack; -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; -import javafx.event.EventHandler; -import javafx.scene.control.Label; -import javafx.scene.input.MouseEvent; -import javafx.scene.layout.Region; -import javafx.scene.layout.StackPane; -import javafx.scene.shape.Rectangle; -import org.controlsfx.control.spreadsheet.Picker; -import org.controlsfx.control.spreadsheet.SpreadsheetView; - -/** - * - * This class will display all the available pickers. It is a StackPane clipped - * which contain a inner Region that display the picker. In that way, we don't - * need to re-layout every time but just "slide" the inner Region inside this - * class so that the pickers are sliding along with the TableColumnHeaders. - */ -public class HorizontalPicker extends StackPane { - - private static final String PICKER_INDEX = "PickerIndex"; //$NON-NLS-1$ - - private final HorizontalHeader horizontalHeader; - - private final SpreadsheetView spv; - private final Stack<Label> pickerPile; - private final Stack<Label> pickerUsed; - - private final InnerHorizontalPicker innerPicker = new InnerHorizontalPicker(); - - public HorizontalPicker(HorizontalHeader horizontalHeader, SpreadsheetView spv) { - this.horizontalHeader = horizontalHeader; - this.spv = spv; - - pickerPile = new Stack<>(); - pickerUsed = new Stack<>(); - - //Clip this StackPane just like the TableHeaderRow. - Rectangle clip = new Rectangle(); - clip.setSmooth(true); - clip.setHeight(VerticalHeader.PICKER_SIZE); - clip.widthProperty().bind(horizontalHeader.widthProperty()); - setClip(clip); - - getChildren().add(innerPicker); - - horizontalHeader.getRootHeader().getColumnHeaders().addListener(layoutListener); - spv.getColumnPickers().addListener(layoutListener); - } - - @Override - protected void layoutChildren() { - //Just relocate the inner for sliding. - innerPicker.relocate(horizontalHeader.getRootHeader().getLayoutX(), snappedTopInset()); - //We must turn off pickers that are behind fixed columns - for (Label label : pickerUsed) { - label.setVisible(label.getLayoutX() + innerPicker.getLayoutX() + label.getWidth() > horizontalHeader.gridViewSkin.fixedColumnWidth); - } - } - - /** - * Method called by the HorizontalHeader in order to slide the pickers. - */ - public void updateScrollX() { - requestLayout(); - } - - private Label getPicker(Picker picker) { - Label pickerLabel; - if (pickerPile.isEmpty()) { - pickerLabel = new Label(); - pickerLabel.getStyleClass().addListener(layoutListener); - pickerLabel.setOnMouseClicked(pickerMouseEvent); - } else { - pickerLabel = pickerPile.pop(); - } - pickerUsed.push(pickerLabel); - pickerLabel.getStyleClass().setAll(picker.getStyleClass()); - pickerLabel.getProperties().put(PICKER_INDEX, picker); - return pickerLabel; - } - - private final EventHandler<MouseEvent> pickerMouseEvent = (MouseEvent mouseEvent) -> { - Label picker = (Label) mouseEvent.getSource(); - - ((Picker) picker.getProperties().get(PICKER_INDEX)).onClick(); - }; - - /** - * Inner class that will lay out all the pickers. - */ - private class InnerHorizontalPicker extends Region { - - @Override - protected void layoutChildren() { - pickerPile.addAll(pickerUsed.subList(0, pickerUsed.size())); - //Unbind every picker used before setting new ones. - for (Label label : pickerUsed) { - label.layoutXProperty().unbind(); - label.setVisible(true); - } - pickerUsed.clear(); - - getChildren().clear(); - int index = 0; - for (TableColumnHeader column : horizontalHeader.getRootHeader().getColumnHeaders()) { - if (spv.getColumnPickers().containsKey(index)) { - Label label = getPicker(spv.getColumnPickers().get(index)); - label.resize(column.getWidth(), VerticalHeader.PICKER_SIZE); - label.layoutXProperty().bind(column.layoutXProperty()); - - getChildren().add(0, label); - } - index++; - } - } - } - - private final InvalidationListener layoutListener = (Observable arg0) -> { - innerPicker.requestLayout(); - }; -} diff --git a/src/impl/org/controlsfx/spreadsheet/RectangleSelection.java b/src/impl/org/controlsfx/spreadsheet/RectangleSelection.java deleted file mode 100644 index 7496914..0000000 --- a/src/impl/org/controlsfx/spreadsheet/RectangleSelection.java +++ /dev/null @@ -1,436 +0,0 @@ -/** - * Copyright (c) 2014, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.spreadsheet; - -import java.util.List; -import java.util.TreeSet; -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; -import javafx.event.EventHandler; -import javafx.scene.control.IndexedCell; -import javafx.scene.control.TablePosition; -import javafx.scene.input.MouseEvent; -import javafx.scene.shape.Rectangle; -import org.controlsfx.control.spreadsheet.Grid; -import org.controlsfx.control.spreadsheet.GridChange; -import org.controlsfx.control.spreadsheet.SpreadsheetCell; -import org.controlsfx.control.spreadsheet.SpreadsheetColumn; - -/** - * - * This class extends Rectangle and will draw a rectangle with a border to the - * selection. - */ -public class RectangleSelection extends Rectangle { - - private final GridViewSkin skin; - private final TableViewSpanSelectionModel sm; - private final SelectionRange selectionRange; - - public RectangleSelection(GridViewSkin skin, TableViewSpanSelectionModel sm) { - this.skin = skin; - this.sm = sm; - getStyleClass().add("selection-rectangle"); //$NON-NLS-1$ - setMouseTransparent(true); - - selectionRange = new SelectionRange(); - skin.getVBar().valueProperty().addListener(layoutListener); - - //When draging, it's not working properly so we remove the rectangle. - skin.getVBar().addEventFilter(MouseEvent.MOUSE_DRAGGED, new EventHandler<MouseEvent>() { - - @Override - public void handle(MouseEvent event) { - skin.getVBar().valueProperty().removeListener(layoutListener); - setVisible(false); - skin.getVBar().addEventFilter(MouseEvent.MOUSE_RELEASED, new EventHandler<MouseEvent>() { - - @Override - public void handle(MouseEvent event) { - skin.getVBar().removeEventFilter(MouseEvent.MOUSE_RELEASED, this); - skin.getVBar().valueProperty().addListener(layoutListener); - updateRectangle(); - } - }); - } - }); - - skin.getHBar().valueProperty().addListener(layoutListener); - sm.getSelectedCells().addListener((Observable observable) -> { - skin.getHorizontalHeader().clearSelectedColumns(); - skin.verticalHeader.clearSelectedRows(); - selectionRange.fill(sm.getSelectedCells()); - updateRectangle(); - }); - } - - private final InvalidationListener layoutListener = (Observable observable) -> { - updateRectangle(); - }; - - public final void updateRectangle() { - if (sm.getSelectedCells().isEmpty() - || skin.getSelectedRows().isEmpty() - || skin.getSelectedColumns().isEmpty() - || selectionRange.range == null) { - setVisible(false); - return; - } - - IndexedCell topRowCell = skin.getFlow().getTopRow(); - if(topRowCell == null){ - return; - } - //We fetch the first and last row currently displayed - int topRow = topRowCell.getIndex(); - IndexedCell bottomRowCell = skin.getFlow().getCells().get(skin.getFlow().getCells().size() - 1); - if(bottomRowCell == null){ - return; - } - int bottomRow = bottomRowCell.getIndex(); - - int minRow = selectionRange.range.getTop(); - if (minRow > bottomRow) { - setVisible(false); - return; - } - minRow = Math.max(minRow, topRow); - - int maxRow = selectionRange.range.getBottom(); - if (maxRow < topRow) { - setVisible(false); - return; - } - - maxRow = Math.min(maxRow, bottomRow); - int minColumn = selectionRange.range.getLeft(); - int maxColumn = selectionRange.range.getRight(); - - GridRow gridMinRow = skin.getRowIndexed(minRow); - if (gridMinRow == null) { - setVisible(false); - return; - } - - Grid grid = skin.spreadsheetView.getGrid(); - if (maxRow >= grid.getRowCount() || maxColumn >= grid.getColumnCount()) { - setVisible(false); - return; - } - SpreadsheetCell cell = grid.getRows().get(maxRow).get(maxColumn); - handleHorizontalPositioning(minColumn, maxColumn, cell.getColumnSpan()); - - //If we are out of sight - if (getX() + getWidth() < 0) { - setVisible(false); - return; - } - - GridRow gridMaxRow = skin.getRowIndexed(maxRow); - if (gridMaxRow == null) { - setVisible(false); - return; - } - setVisible(true); - - handleVerticalPositioning(minRow, maxRow, gridMinRow, gridMaxRow, cell.getRowSpan()); - } - - /** - * This will compute and assign the y and height properties of the - * rectangle. - * - * @param minRow - * @param maxRow - * @param gridMinRow - */ - private void handleVerticalPositioning(int minRow, int maxRow, GridRow gridMinRow, GridRow gridMaxRow, int rowSpan) { - double height = 0; - for (int i = maxRow; i <= maxRow /*+ (rowSpan - 1)*/; ++i) { - height += skin.getRowHeight(i); - } - - /** - * If we are not in fixed row, we will just take the layout Y, and if - * it's below some of our fixed rows, we will take the fixedRowheight as - * value. - */ - if (!skin.getCurrentlyFixedRow().contains(minRow)) { - yProperty().unbind(); - //If we have fixedRows, we do not want to overlap them with the rectangle. - if (gridMinRow.getLayoutY() < skin.getFixedRowHeight()) { - setY(skin.getFixedRowHeight()); - } else { - yProperty().bind(gridMinRow.layoutYProperty()); - } - /** - * If we are in fixedRow, we cannot trust the layoutY alone. We also - * need to rely on the verticalShift for shifting the rectangle to - * the right starting position.\n - * - */ - } else { - yProperty().bind(gridMinRow.layoutYProperty().add(gridMinRow.verticalShift)); - } - - /** - * Finally we compute the height by subtracting our starting point to - * the ending point. - */ - heightProperty().bind(gridMaxRow.layoutYProperty().add(gridMaxRow.verticalShift).subtract(yProperty()).add(height)); - } - - /** - * This will compute and assign the x and width propertis of the Rectangle. - * - * @param minColumn - * @param maxColumn - */ - private void handleHorizontalPositioning(int minColumn, int maxColumn, int columnSpan) { - double x = 0; - - final List<SpreadsheetColumn> columns = skin.spreadsheetView.getColumns(); - if(columns.size() <= minColumn || columns.size() <= maxColumn){ - return; - } - //We first compute the total space between the left edge and our first column - for (int i = 0; i < minColumn; ++i) { - //Here we use Ceil because we want to "snapSize" otherwise we may end up with a weird shift. - x += snapSize(columns.get(i).getWidth()); - } - - - /** - * We then substract the value of the Hbar in order to place it properly - * because 0 means the left edge or the SpreadsheetView and we want to - * consider the left edge of the viewport of the virtualFlow. - */ - x -= skin.getHBar().getValue(); - - //Then we compute the width by adding the space between the min and max column - double width = 0; - for (int i = minColumn; i <= maxColumn /*+ (columnSpan - 1)*/; ++i) { - width += snapSize(columns.get(i).getWidth()); - } - - //FIXED COLUMNS - /** - * If the selection is not on a fixed column, we may have the case where - * the first selected cell will be hid by a fixed column. If so, we must - * translate the starting point in because the rectangle must also be - * hidden by the fixed column. - */ - if (!skin.spreadsheetView.getFixedColumns().contains(columns.get(minColumn))) { - if (x < skin.fixedColumnWidth) { - //Since I translate the starting point, I must reduce the width by the value I'm translating. - width -= skin.fixedColumnWidth - x; - x = skin.fixedColumnWidth; - } - /** - * If the maxColumn is contained within the fixed column, we may - * look at the starting point and the ending point. Because prior - * computation are wrong since our columns are fixed on the left. So - * there initial position are worthless and we must consider their - * current position compared to each other. - * - */ - } else { - /** - * If x + width is inferior, we can re-compute the width by checking - * our fixed columns interval - */ - if (x + width < skin.fixedColumnWidth) { - x = 0; - width = 0; - for (SpreadsheetColumn column : skin.spreadsheetView.getFixedColumns()) { - int indexColumn = columns.indexOf(column); - if (indexColumn < minColumn && indexColumn != minColumn) { - x += snapSize(column.getWidth()); - } - if (indexColumn >= minColumn && indexColumn <= maxColumn) { - width += snapSize(column.getWidth()); - } - } - /** - * If just x is inferior to fixedColumnWidth, we just adjust the - * width by substracting the gap between the original x and the - * new x. - */ - } else if (x < skin.fixedColumnWidth) { - double tempX = 0; - for (SpreadsheetColumn column : skin.spreadsheetView.getFixedColumns()) { - int indexColumn = columns.indexOf(column); - if (indexColumn < minColumn && indexColumn != minColumn) { - tempX += snapSize(column.getWidth()); - } - } - width -= tempX - x; - x = tempX; - } - } - setX(x); - setWidth(width); - } - - /** - * Returns a value ceiled to the nearest pixel. - * - * @param value the size value to be snapped - * @return value ceiled to nearest pixel - */ - private double snapSize(double value) { - return Math.ceil(value); - } - - /** - * Utility class to transform a list of selected cells into a union of - * ranges. - */ - public static class SelectionRange { - - private final TreeSet<Long> set = new TreeSet<>(); - private GridRange range; - - public SelectionRange() { - } - - /** - * Construct a SelectionRange with a List of Pair where the value is the - * row (of the WsGrid) and the value is column(of the WsGrid). - * - * @param list - */ - public void fill(List<TablePosition> list) { - set.clear(); - for (TablePosition pos : list) { - set.add(key(pos.getRow(), pos.getColumn())); - } - computeRange(); - } - - public void fillGridRange(List<GridChange> list) { - set.clear(); - for (GridChange pos : list) { - set.add(key(pos.getRow(), pos.getColumn())); - } - computeRange(); - } - - public GridRange getRange(){ - return range; - } - private Long key(int row, int column) { - return (((long) row) << 32) | column; - } - - private int getRow(Long l) { - return (int) (l >> 32); - } - - private int getColumn(Long l) { - return (int) (l & 0xffFFffFF); - } - - /** - * return a list of WsGridRange - * - * @return - */ - private void computeRange() { - range = null; - while (!set.isEmpty()) { - if (range != null) { - range = null; - return; - } - - long first = set.first(); - set.remove(first); - - int row = getRow(first); - int column = getColumn(first); - - //Go in row - while (set.contains(key(row, column + 1))) { - ++column; - set.remove(key(row, column)); - } - - //Go in column - boolean flag = true; - while (flag) { - ++row; - for (int col = getColumn(first); col <= column; ++col) { - if (!set.contains(key(row, col))) { - flag = false; - break; - } - } - if (flag) { - for (int col = getColumn(first); col <= column; ++col) { - set.remove(key(row, col)); - } - } else { - --row; - } - } - range = new GridRange(getRow(first), row, getColumn(first), column); - } - } - } - - public static class GridRange { - - private final int top; - private final int bottom; - private final int left; - private final int right; - - public GridRange(int top, int bottom, int left, int right) { - this.top = top; - this.bottom = bottom; - this.left = left; - this.right = right; - } - - public int getTop() { - return top; - } - - public int getBottom() { - return bottom; - } - - public int getLeft() { - return left; - } - - public int getRight() { - return right; - } - } -} diff --git a/src/impl/org/controlsfx/spreadsheet/SelectedCellsMapTemp.java b/src/impl/org/controlsfx/spreadsheet/SelectedCellsMapTemp.java deleted file mode 100644 index 9d37392..0000000 --- a/src/impl/org/controlsfx/spreadsheet/SelectedCellsMapTemp.java +++ /dev/null @@ -1,205 +0,0 @@ -/** - * Copyright (c) 2014 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.spreadsheet; - -import java.util.BitSet; -import java.util.Collection; -import java.util.Map; -import java.util.TreeMap; -import javafx.collections.FXCollections; -import javafx.collections.ListChangeListener; -import javafx.collections.ObservableList; -import javafx.collections.transformation.SortedList; -import javafx.scene.control.TablePositionBase; - -/** - * This class is copied from com.sun.javafx.scene.control.SelectedCellsMap - * temporary in 8u20 to resolve https://javafx-jira.kenai.com/browse/RT-38306 - * - * Will be removed in 8u40 - * - * @param <T> - */ -public class SelectedCellsMapTemp<T extends TablePositionBase> { - private final ObservableList<T> selectedCells; - private final ObservableList<T> sortedSelectedCells; - - private final Map<Integer, BitSet> selectedCellBitSetMap; - - public SelectedCellsMapTemp(final ListChangeListener<T> listener) { - selectedCells = FXCollections.<T>observableArrayList(); - sortedSelectedCells = new SortedList<>(selectedCells, (T o1, T o2) -> { - int result = o1.getRow() - o2.getRow(); - return result == 0 ? (o1.getColumn() - o2.getColumn()) : result; - }); - sortedSelectedCells.addListener(listener); - - selectedCellBitSetMap = new TreeMap<>((o1, o2) -> o1.compareTo(o2)); - } - - public int size() { - return selectedCells.size(); - } - - public T get(int i) { - if (i < 0) { - return null; - } - return sortedSelectedCells.get(i); - } - - public void add(T tp) { - final int row = tp.getRow(); - final int columnIndex = tp.getColumn(); - - // update the bitset map - BitSet bitset; - if (! selectedCellBitSetMap.containsKey(row)) { - bitset = new BitSet(); - selectedCellBitSetMap.put(row, bitset); - } else { - bitset = selectedCellBitSetMap.get(row); - } - - if (columnIndex >= 0) { - boolean isAlreadySet = bitset.get(columnIndex); - bitset.set(columnIndex); - - if (! isAlreadySet) { - // add into the list - selectedCells.add(tp); - } - } else { - // FIXME slow path (for now) - if (! selectedCells.contains(tp)) { - selectedCells.add(tp); - } - } - } - - public void addAll(Collection<T> cells) { - // update bitset - for (T tp : cells) { - final int row = tp.getRow(); - final int columnIndex = tp.getColumn(); - - // update the bitset map - BitSet bitset; - if (! selectedCellBitSetMap.containsKey(row)) { - bitset = new BitSet(); - selectedCellBitSetMap.put(row, bitset); - } else { - bitset = selectedCellBitSetMap.get(row); - } - - if (columnIndex < 0) { - continue; - } - - bitset.set(columnIndex); - } - - // add into the list - selectedCells.addAll(cells); - } - - public void setAll(Collection<T> cells) { - // update bitset - selectedCellBitSetMap.clear(); - for (T tp : cells) { - final int row = tp.getRow(); - final int columnIndex = tp.getColumn(); - - // update the bitset map - BitSet bitset; - if (! selectedCellBitSetMap.containsKey(row)) { - bitset = new BitSet(); - selectedCellBitSetMap.put(row, bitset); - } else { - bitset = selectedCellBitSetMap.get(row); - } - - if (columnIndex < 0) { - continue; - } - - bitset.set(columnIndex); - } - - // add into the list - selectedCells.setAll(cells); - } - - public void remove(T tp) { - final int row = tp.getRow(); - final int columnIndex = tp.getColumn(); - - // update the bitset map - if (selectedCellBitSetMap.containsKey(row)) { - BitSet bitset = selectedCellBitSetMap.get(row); - - if (columnIndex >= 0) { - bitset.clear(columnIndex); - } - - if (bitset.isEmpty()) { - selectedCellBitSetMap.remove(row); - } - } - - // update list - selectedCells.remove(tp); - } - - public void clear() { - // update bitset - selectedCellBitSetMap.clear(); - - // update list - selectedCells.clear(); - } - - public boolean isSelected(int row, int columnIndex) { - if (columnIndex < 0) { - return selectedCellBitSetMap.containsKey(row); - } else { - return selectedCellBitSetMap.containsKey(row) ? selectedCellBitSetMap.get(row).get(columnIndex) : false; - } - } - - public int indexOf(T tp) { - return sortedSelectedCells.indexOf(tp); - } - - public boolean isEmpty() { - return selectedCells.isEmpty(); - } - - public ObservableList<T> getSelectedCells() { - return selectedCells; - } -} diff --git a/src/impl/org/controlsfx/spreadsheet/SpreadsheetGridView.java b/src/impl/org/controlsfx/spreadsheet/SpreadsheetGridView.java deleted file mode 100644 index 53f9fe9..0000000 --- a/src/impl/org/controlsfx/spreadsheet/SpreadsheetGridView.java +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Copyright (c) 2013, 2014, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.spreadsheet; - -import javafx.collections.ObservableList; -import javafx.event.EventHandler; -import javafx.scene.control.TableView; -import javafx.scene.input.MouseEvent; - -import org.controlsfx.control.spreadsheet.SpreadsheetCell; -import org.controlsfx.control.spreadsheet.SpreadsheetView; - -public class SpreadsheetGridView extends TableView<ObservableList<SpreadsheetCell>> { - private final SpreadsheetHandle handle; - - /* - * cache the stylesheet as lookup takes time and the getUserAgentStylesheet is called repeatedly - */ - private String stylesheet; - - /** - * We don't want to show the current value in the TextField when we are - * editing by typing a key. We want directly to take those typed letters - * and put them into the textfield. - */ - public SpreadsheetGridView(SpreadsheetHandle handle) { - this.handle = handle; - - - } - - @Override - public String getUserAgentStylesheet() { - /* - * For more information please see RT-40658 - */ - if (stylesheet == null) { - stylesheet = SpreadsheetView.class.getResource("spreadsheet.css") //$NON-NLS-1$ - .toExternalForm(); - } - - return stylesheet; - } - - @Override - protected javafx.scene.control.Skin<?> createDefaultSkin() { - return new GridViewSkin(handle); - } - - public GridViewSkin getGridViewSkin() { - return handle.getCellsViewSkin(); - } -}; diff --git a/src/impl/org/controlsfx/spreadsheet/SpreadsheetHandle.java b/src/impl/org/controlsfx/spreadsheet/SpreadsheetHandle.java deleted file mode 100644 index 474f009..0000000 --- a/src/impl/org/controlsfx/spreadsheet/SpreadsheetHandle.java +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright (c) 2013, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package impl.org.controlsfx.spreadsheet; - -import org.controlsfx.control.spreadsheet.SpreadsheetView; - -/** - * Implementation vs public bridge. - */ -public abstract class SpreadsheetHandle { - /** Access the main control. */ - protected abstract SpreadsheetView getView(); - /** Accesses the grid (ie cell table) in the spreadsheet. */ - protected abstract SpreadsheetGridView getGridView(); - /** Accesses the grid view (ie cell table view). */ - protected abstract GridViewSkin getCellsViewSkin(); - /** Whether that column width has been set by the user. */ - protected abstract boolean isColumnWidthSet(int indexColumn); -} diff --git a/src/impl/org/controlsfx/spreadsheet/TableViewSpanSelectionModel.java b/src/impl/org/controlsfx/spreadsheet/TableViewSpanSelectionModel.java deleted file mode 100644 index c2b585b..0000000 --- a/src/impl/org/controlsfx/spreadsheet/TableViewSpanSelectionModel.java +++ /dev/null @@ -1,912 +0,0 @@ -/** - * Copyright (c) 2013, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.spreadsheet; - -import com.sun.javafx.collections.MappingChange; -import com.sun.javafx.collections.NonIterableChange; -import com.sun.javafx.scene.control.ReadOnlyUnbackedObservableList; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import javafx.animation.KeyFrame; -import javafx.animation.Timeline; -import javafx.beans.InvalidationListener; -import javafx.beans.NamedArg; -import javafx.beans.Observable; -import javafx.collections.ListChangeListener; -import javafx.collections.ObservableList; -import javafx.collections.WeakListChangeListener; -import javafx.event.ActionEvent; -import javafx.event.EventHandler; -import javafx.event.WeakEventHandler; -import javafx.scene.control.SelectionMode; -import javafx.scene.control.TableColumn; -import javafx.scene.control.TableColumnBase; -import javafx.scene.control.TablePosition; -import javafx.scene.control.TableView; -import javafx.scene.input.KeyEvent; -import javafx.scene.input.MouseEvent; -import javafx.util.Duration; -import javafx.util.Pair; -import org.controlsfx.control.spreadsheet.SpreadsheetCell; -import org.controlsfx.control.spreadsheet.SpreadsheetView; - -/** - * - * The Selection Model adapted for the SpreadsheetView regarding span. - */ -public class TableViewSpanSelectionModel extends - TableView.TableViewSelectionModel<ObservableList<SpreadsheetCell>>{ - - private boolean shift = false; // Register state of 'shift' key - private boolean key = false; // Register if we last touch the keyboard - // or the mouse - private boolean drag = false; // register if we are dragging (no - // edition) - private MouseEvent mouseEvent; - private boolean makeAtomic; - private SpreadsheetGridView cellsView; - - private SpreadsheetView spreadsheetView; - // the only 'proper' internal data structure, selectedItems and - // selectedIndices - // are both 'read-only and unbacked'. - private final SelectedCellsMapTemp<TablePosition<ObservableList<SpreadsheetCell>, ?>> selectedCellsMap; - - // we create a ReadOnlyUnbackedObservableList of selectedCells here so - // that we can fire custom list change events. - private final ReadOnlyUnbackedObservableList<TablePosition<ObservableList<SpreadsheetCell>, ?>> selectedCellsSeq; - - /** - * We use these variable in order to stay on the same row/column when - * navigating with arrows. If we are going down, and we are arriving on a - * column-spanning cell, when going down again, we don't want to go on the - * starting column of the spanning cell but on the same column we arrived - * previously. - */ - private int oldCol = -1; - private TableColumn oldTableColumn = null; - private int oldRow = -1; - Pair<Integer, Integer> direction; - private int oldColSpan = -1; - private int oldRowSpan = -1; - /** - * Make the tableView move when selection operating outside bounds - */ - private final Timeline timer; - - private final EventHandler<ActionEvent> timerEventHandler = (ActionEvent event) -> { - GridViewSkin skin = (GridViewSkin) getCellsViewSkin(); - if (mouseEvent != null && !cellsView.contains(mouseEvent.getX(), mouseEvent.getY())) { - double sceneX = mouseEvent.getSceneX(); - double sceneY = mouseEvent.getSceneY(); - double layoutX = cellsView.getLayoutX(); - double layoutY = cellsView.getLayoutY(); - double layoutXMax = layoutX + cellsView.getWidth(); - double layoutYMax = layoutY + cellsView.getHeight(); - - if (sceneX > layoutXMax) { - skin.getHBar().increment(); - } else if (sceneX < layoutX) { - skin.getHBar().decrement(); - } - if (sceneY > layoutYMax) { - skin.getVBar().increment(); - } else if (sceneY < layoutY) { - skin.getVBar().decrement(); - } - } - }; - /** - * When the drag is over, we remove the listener and stop the timer - */ - private final EventHandler<MouseEvent> dragDoneHandler = new EventHandler<MouseEvent>() { - @Override - public void handle(MouseEvent mouseEvent) { - drag = false; - timer.stop(); - spreadsheetView.removeEventHandler(MouseEvent.MOUSE_RELEASED, this); - } - }; - - private final EventHandler<KeyEvent> keyPressedEventHandler = (KeyEvent keyEvent) -> { - key = true; - shift = keyEvent.isShiftDown(); - }; - - private final EventHandler<MouseEvent> mousePressedEventHandler = (MouseEvent mouseEvent1) -> { - key = false; - shift = mouseEvent1.isShiftDown(); - }; - - private final EventHandler<MouseEvent> onDragDetectedEventHandler = new EventHandler<MouseEvent>() { - @Override - public void handle(MouseEvent mouseEvent) { - cellsView.addEventHandler(MouseEvent.MOUSE_RELEASED, dragDoneHandler); - drag = true; - timer.setCycleCount(Timeline.INDEFINITE); - timer.play(); - } - }; - - private final EventHandler<MouseEvent> onMouseDragEventHandler = (MouseEvent e) -> { - mouseEvent = e; - }; - - private final ListChangeListener<TablePosition<ObservableList<SpreadsheetCell>, ?>> listChangeListener = this::handleSelectedCellsListChangeEvent; - - /** - * ********************************************************************* - * - * Constructors - * - ********************************************************************* - */ - /** - * Constructor - * @param spreadsheetView - * @param cellsView - */ - public TableViewSpanSelectionModel(@NamedArg("spreadsheetView") SpreadsheetView spreadsheetView, @NamedArg("cellsView") SpreadsheetGridView cellsView) { - super(cellsView); - this.cellsView = cellsView; - this.spreadsheetView = spreadsheetView; - - timer = new Timeline(new KeyFrame(Duration.millis(100), new WeakEventHandler<>((timerEventHandler)))); - cellsView.addEventHandler(KeyEvent.KEY_PRESSED, new WeakEventHandler<>(keyPressedEventHandler)); - - cellsView.addEventFilter(MouseEvent.MOUSE_PRESSED, new WeakEventHandler<>(mousePressedEventHandler)); - cellsView.setOnDragDetected(new WeakEventHandler<>(onDragDetectedEventHandler)); - - cellsView.setOnMouseDragged(new WeakEventHandler<>(onMouseDragEventHandler)); - - selectedCellsMap = new SelectedCellsMapTemp<>(new WeakListChangeListener<>(listChangeListener)); - - selectedCellsSeq = new ReadOnlyUnbackedObservableList<TablePosition<ObservableList<SpreadsheetCell>, ?>>() { - @Override - public TablePosition<ObservableList<SpreadsheetCell>, ?> get(int i) { - return selectedCellsMap.get(i); - } - - @Override - public int size() { - return selectedCellsMap.size(); - } - }; - } - - private void handleSelectedCellsListChangeEvent( - ListChangeListener.Change<? extends TablePosition<ObservableList<SpreadsheetCell>, ?>> c) { - if (makeAtomic) { - return; - } - - selectedCellsSeq.callObservers(new MappingChange<>(c, MappingChange.NOOP_MAP, selectedCellsSeq)); - c.reset(); - } - - /** - * ********************************************************************* - * * Public selection API * * - * ******************************************************************** - */ - private TablePosition<ObservableList<SpreadsheetCell>, ?> old = null; - - @Override - public void select(int row, TableColumn<ObservableList<SpreadsheetCell>, ?> column) { - if (row < 0 || row >= getItemCount()) { - return; - } - - // if I'm in cell selection mode but the column is null, I don't - // want - // to select the whole row instead... - if (isCellSelectionEnabled() && column == null) { - return; - } - // Variable we need for algorithm - TablePosition<ObservableList<SpreadsheetCell>, ?> posFinal = new TablePosition<>(getTableView(), row, - column); - - final SpreadsheetView.SpanType spanType = spreadsheetView.getSpanType(row, posFinal.getColumn()); - - /** - * We check if we are on covered cell. If so we have the algorithm of - * the focus model to give the selection to the right cell. - * - */ - switch (spanType) { - case ROW_SPAN_INVISIBLE: - /** - * If we notice that the new selected cell is the previous one, - * then it means that we were already on the cell and we wanted - * to go below. We make sure that old is not null, and that the - * move is initiated by keyboard. Because if it's a click, then - * we just want to go on the clicked cell (not below) - */ - if (old != null && !shift && old.getColumn() == posFinal.getColumn() - && old.getRow() == posFinal.getRow() - 1) { - int visibleRow = FocusModelListener.getNextRowNumber(old, cellsView); - /** - * If the visibleRow we're targeting is out of bounds, we do - * not want to get a visibleCell, so we step out. But we - * need to set edition to false because we will be going - * back to the old cell and we could go to edition. - */ - if (visibleRow < getItemCount()) { - posFinal = getVisibleCell(visibleRow, old.getTableColumn(), old.getColumn()); - break; - } - } - // If the current selected cell if hidden by row span, we go - // above - posFinal = getVisibleCell(row, column, posFinal.getColumn()); - break; - case BOTH_INVISIBLE: - // If the current selected cell if hidden by a both (row and - // column) span, we go left-above - posFinal = getVisibleCell(row, column, posFinal.getColumn()); - break; - case COLUMN_SPAN_INVISIBLE: - // If we notice that the new selected cell is the previous one, - // then it means that we were - // already on the cell and we wanted to go right. - if (old != null && !shift && old.getColumn() == posFinal.getColumn() - 1 - && old.getRow() == posFinal.getRow()) { - posFinal = getVisibleCell(old.getRow(), FocusModelListener.getTableColumnSpan(old, cellsView), getTableColumnSpanInt(old)); - } else { - // If the current selected cell if hidden by column span, we - // go left - posFinal = getVisibleCell(row, column, posFinal.getColumn()); - } - default: - break; - } - - if (direction != null && key) { - /** - * If I'm going up or down, and the previous cell had a column span, - * then we take the column used before instead of the current - * column. - */ - if (direction.getKey() != 0 && oldColSpan > 1) { - posFinal = getVisibleCell(posFinal.getRow(), oldTableColumn, oldCol); - } else if (direction.getValue() != 0 && oldRowSpan > 1) { - posFinal = getVisibleCell(oldRow, posFinal.getTableColumn(), posFinal.getColumn()); - } - } - old = posFinal; - - //If it's a click, we register everything. - if (!key) { - oldRow = old.getRow(); - oldCol = old.getColumn(); - oldTableColumn = old.getTableColumn(); - } else { - //If we're going up or down, we register the row changing, not the column. - if (direction != null && direction.getKey() != 0) { - oldRow = old.getRow(); - } else if (direction != null && direction.getValue() != 0) { - oldCol = old.getColumn(); - oldTableColumn = old.getTableColumn(); - } - } - if (getSelectionMode() == SelectionMode.SINGLE) { - quietClearSelection(); - } - SpreadsheetCell cell = cellsView.getItems().get(old.getRow()).get(old.getColumn()); - oldRowSpan = cell.getRowSpan(); - oldColSpan = cell.getColumnSpan(); - for (int i = cell.getRow(); i < cell.getRowSpan() + cell.getRow(); ++i) { - for (int j = cell.getColumn(); j < cell.getColumnSpan() + cell.getColumn(); ++j) { - posFinal = new TablePosition<>(getTableView(), i, getTableView().getVisibleLeafColumn(j)); - selectedCellsMap.add(posFinal); - } - } - - updateScroll(old); - addSelectedRowsAndColumns(old); - - setSelectedIndex(old.getRow()); - setSelectedItem(getModelItem(old.getRow())); - if (getTableView().getFocusModel() == null) { - return; - } - - getTableView().getFocusModel().focus(old.getRow(), old.getTableColumn()); - } - - /** - * We try to make visible the rows that may be hidden by Fixed rows. - * - * @param posFinal - */ - private void updateScroll(TablePosition<ObservableList<SpreadsheetCell>, ?> posFinal) { - - /** - * We don't want to do any scroll when dragging or selecting with click. - * Only keyboard action arrow action. - */ - if (!drag && key && getCellsViewSkin().getCellsSize() != 0 && spreadsheetView.getFixedRows().size() != 0) { - - int start = getCellsViewSkin().getRow(0).getIndex(); - double posFinalOffset = 0; - for (int j = start; j < posFinal.getRow(); ++j) { - posFinalOffset += getSpreadsheetViewSkin().getRowHeight(j); - } - - if (getCellsViewSkin().getFixedRowHeight() > posFinalOffset) { - cellsView.scrollTo(posFinal.getRow()); - } - } - } - - @SuppressWarnings("unchecked") - @Override - public void clearSelection(int row, TableColumn<ObservableList<SpreadsheetCell>, ?> column) { - - final TablePosition<ObservableList<SpreadsheetCell>, ?> tp = new TablePosition<>(getTableView(), row, - column); - if (tp.getRow() < 0 || tp.getColumn() < 0) { - return; - } - List<TablePosition<ObservableList<SpreadsheetCell>, ?>> selectedCells; - if ((selectedCells = isSelectedRange(row, column, tp.getColumn())) != null) { - for (TablePosition<ObservableList<SpreadsheetCell>, ?> cell : selectedCells) { - selectedCellsMap.remove(cell); - removeSelectedRowsAndColumns(cell); - focus(cell.getRow()); - } - } else { - for (TablePosition<ObservableList<SpreadsheetCell>, ?> pos : getSelectedCells()) { - if (pos.equals(tp)) { - selectedCellsMap.remove(pos); - removeSelectedRowsAndColumns(pos); - // give focus to this cell index - focus(row); - return; - } - } - } - } - - /** - * When we set a new grid, we need to update the selected Cells because - * otherwise we will end up with TablePosition which have "-1" as their - * column number. So we need to verify that the old selected cells are still - * selectable and select them. - * - * @param selectedCells - */ - public void verifySelectedCells(List<Pair<Integer, Integer>> selectedCells) { - List<TablePosition<ObservableList<SpreadsheetCell>, ?>> newList = new ArrayList<>(); - clearSelection(); - - final int itemCount = getItemCount(); - final int columnSize = getTableView().getColumns().size(); - final HashSet<Integer> selectedRows = new HashSet<>(); - final HashSet<Integer> selectedColumns = new HashSet<>(); - TablePosition<ObservableList<SpreadsheetCell>, ?> pos = null; - for (Pair<Integer, Integer> position : selectedCells) { - if (position.getKey() < 0 - || position.getKey() >= itemCount - || position.getValue() < 0 - || position.getValue() >= columnSize) { - continue; - } - - final TableColumn<ObservableList<SpreadsheetCell>, ?> column = getTableView().getVisibleLeafColumn(position.getValue()); - - pos = getVisibleCell(position.getKey(), column, position.getValue()); - // We store all the selectedColumn and Rows, we will update - // just once at the end - final SpreadsheetCell cell = cellsView.getItems().get(pos.getRow()).get(pos.getColumn()); - for (int i = cell.getRow(); i < cell.getRowSpan() + cell.getRow(); ++i) { - selectedColumns.add(i); - for (int j = cell.getColumn(); j < cell.getColumnSpan() + cell.getColumn(); ++j) { - selectedRows.add(j); - pos = new TablePosition<>(getTableView(), i, getTableView().getVisibleLeafColumn(j)); - newList.add(pos); - } - } - } - selectedCellsMap.setAll(newList); - - final TablePosition finalPos = pos; - // Then we update visuals just once - GridViewSkin skin = getSpreadsheetViewSkin(); - //If the skin is null, we just wait till everything is ready.. - if (skin == null) { - cellsView.skinProperty().addListener(new InvalidationListener() { - - @Override - public void invalidated(Observable observable) { - cellsView.skinProperty().removeListener(this); - GridViewSkin skin = getSpreadsheetViewSkin(); - if (skin != null) { - updateSelectedVisuals(skin, finalPos, selectedRows, selectedColumns); - } - } - }); - } else { - updateSelectedVisuals(skin, pos, selectedRows, selectedColumns); - } - } - - /** - * When all the selection has been made, we just need to light up the - * indicators that are showing which indexes are selected. - * - * @param skin - * @param pos - * @param selectedRows - * @param selectedColumns - */ - private void updateSelectedVisuals(GridViewSkin skin, TablePosition pos, HashSet<Integer> selectedRows, HashSet<Integer> selectedColumns) { - if (skin != null) { - skin.getSelectedRows().addAll(selectedColumns); - skin.getSelectedColumns().addAll(selectedRows); - } - - /** - * If we made some selection, we need to force the visual selected - * confirmation to come when the layout is starting. Doing it before - * will result in a selected cell with no css applied to it. - */ - if (pos != null) { - getCellsViewSkin().lastRowLayout.set(true); - getCellsViewSkin().lastRowLayout.addListener(new InvalidationListener() { - - @Override - public void invalidated(Observable observable) { - handleSelectedCellsListChangeEvent(new NonIterableChange.SimpleAddChange<>(0, - selectedCellsMap.size(), selectedCellsSeq)); - getCellsViewSkin().lastRowLayout.removeListener(this); - } - }); - } - } - - @Override - public void selectRange(int minRow, TableColumnBase<ObservableList<SpreadsheetCell>, ?> minColumn, int maxRow, - TableColumnBase<ObservableList<SpreadsheetCell>, ?> maxColumn) { - - if (getSelectionMode() == SelectionMode.SINGLE) { - quietClearSelection(); - select(maxRow, maxColumn); - return; - } - SpreadsheetCell cell; - - makeAtomic = true; - - final int itemCount = getItemCount(); - - final int minColumnIndex = getTableView().getVisibleLeafIndex( - (TableColumn<ObservableList<SpreadsheetCell>, ?>) minColumn); - final int maxColumnIndex = getTableView().getVisibleLeafIndex( - (TableColumn<ObservableList<SpreadsheetCell>, ?>) maxColumn); - final int _minColumnIndex = Math.min(minColumnIndex, maxColumnIndex); - final int _maxColumnIndex = Math.max(minColumnIndex, maxColumnIndex); - - final int _minRow = Math.min(minRow, maxRow); - final int _maxRow = Math.max(minRow, maxRow); - - HashSet<Integer> selectedRows = new HashSet<>(); - HashSet<Integer> selectedColumns = new HashSet<>(); - - for (int _row = _minRow; _row <= _maxRow; _row++) { - for (int _col = _minColumnIndex; _col <= _maxColumnIndex; _col++) { - // begin copy/paste of select(int, column) method (with some - // slight modifications) - if (_row < 0 || _row >= itemCount) { - continue; - } - - final TableColumn<ObservableList<SpreadsheetCell>, ?> column = getTableView().getVisibleLeafColumn( - _col); - - // if I'm in cell selection mode but the column is null, I - // don't want - // to select the whole row instead... - if (column == null) { - continue; - } - - TablePosition<ObservableList<SpreadsheetCell>, ?> pos = getVisibleCell(_row, column, _col); - - // We store all the selectedColumn and Rows, we will update - // just once at the end - cell = cellsView.getItems().get(pos.getRow()).get(pos.getColumn()); - for (int i = cell.getRow(); i < cell.getRowSpan() + cell.getRow(); ++i) { - selectedColumns.add(i); - for (int j = cell.getColumn(); j < cell.getColumnSpan() + cell.getColumn(); ++j) { - selectedRows.add(j); - pos = new TablePosition<>(getTableView(), i, getTableView().getVisibleLeafColumn(j)); - selectedCellsMap.add(pos); - } - } - -// makeAtomic = true; - // end copy/paste - } - } - makeAtomic = false; - - // Then we update visuals just once - getSpreadsheetViewSkin().getSelectedRows().addAll(selectedColumns); - getSpreadsheetViewSkin().getSelectedColumns().addAll(selectedRows); - - // fire off events - setSelectedIndex(maxRow); - setSelectedItem(getModelItem(maxRow)); - if (getTableView().getFocusModel() == null) { - return; - } - - //FIXME Focus is wrong, and endIndex also.. - getTableView().getFocusModel().focus(maxRow, (TableColumn<ObservableList<SpreadsheetCell>, ?>) maxColumn); - - /** - * If we end up on a spanned cell, there is not reliable way to - * determine which is the last index, certainly not the maxRow and - * maxColumn. So right now we need to take this extreme measure in order - * to be sure that the cells will be highlighted correctly. - */ - final int startChangeIndex = selectedCellsMap.indexOf(new TablePosition<>(getTableView(), minRow, - (TableColumn<ObservableList<SpreadsheetCell>, ?>) minColumn)); - final int endChangeIndex = selectedCellsMap.getSelectedCells().size() - 1;//indexOf(new TablePosition<>(getTableView(), maxRow, -// (TableColumn<ObservableList<SpreadsheetCell>, ?>) maxColumn)); - - if (startChangeIndex > -1 && endChangeIndex > -1) { - final int startIndex = Math.min(startChangeIndex, endChangeIndex); - final int endIndex = Math.max(startChangeIndex, endChangeIndex); - handleSelectedCellsListChangeEvent(new NonIterableChange.SimpleAddChange<>(startIndex, - endIndex + 1, selectedCellsSeq)); - } - } - - @Override - public void selectAll() { - if (getSelectionMode() == SelectionMode.SINGLE) { - return; - } - - quietClearSelection(); - - List<TablePosition<ObservableList<SpreadsheetCell>, ?>> indices = new ArrayList<>(); - TableColumn<ObservableList<SpreadsheetCell>, ?> column; - TablePosition<ObservableList<SpreadsheetCell>, ?> tp = null; - - for (int col = 0; col < getTableView().getVisibleLeafColumns().size(); col++) { - column = getTableView().getVisibleLeafColumns().get(col); - for (int row = 0; row < getItemCount(); row++) { - tp = new TablePosition<>(getTableView(), row, column); - indices.add(tp); - } - } - selectedCellsMap.setAll(indices); - - // Then we update visuals just once - ArrayList<Integer> selectedColumns = new ArrayList<>(); - for (int col = 0; col < spreadsheetView.getGrid().getColumnCount(); col++) { - selectedColumns.add(col); - } - - ArrayList<Integer> selectedRows = new ArrayList<>(); - for (int row = 0; row < spreadsheetView.getGrid().getRowCount(); row++) { - selectedRows.add(row); - } - getSpreadsheetViewSkin().getSelectedRows().addAll(selectedRows); - getSpreadsheetViewSkin().getSelectedColumns().addAll(selectedColumns); - - if (tp != null) { - select(tp.getRow(), tp.getTableColumn()); - //Just like verticalHeader, the focus should be put on the - //first cell to ease copy/paste operation. - getTableView().getFocusModel().focus(0, getTableView().getColumns().get(0)); - } - } - - @Override - public boolean isSelected(int row, TableColumn<ObservableList<SpreadsheetCell>, ?> column) { - // When in cell selection mode, we currently do NOT support - // selecting - // entire rows, so a isSelected(row, null) - // should always return false. - if (column == null || row < 0) { - return false; - } - - int columnIndex = getTableView().getVisibleLeafIndex(column); - - if (getCellsViewSkin().getCellsSize() != 0) { - TablePosition<ObservableList<SpreadsheetCell>, ?> posFinal = getVisibleCell(row, column, columnIndex); - return selectedCellsMap.isSelected(posFinal.getRow(), posFinal.getColumn()); - } else { - return selectedCellsMap.isSelected(row, columnIndex); - } - } - - /** - * Return the tablePosition of a selected cell inside a spanned cell if any. - * - * @param row - * @param column - * @param col - * @return - */ - public List<TablePosition<ObservableList<SpreadsheetCell>, ?>> isSelectedRange(int row, - TableColumn<ObservableList<SpreadsheetCell>, ?> column, int col) { - - if (col < 0 || row < 0) { - return null; - } - - final SpreadsheetCell cellSpan = cellsView.getItems().get(row).get(col); - final int infRow = cellSpan.getRow(); - final int supRow = infRow + cellSpan.getRowSpan(); - - final int infCol = cellSpan.getColumn(); - final int supCol = infCol + cellSpan.getColumnSpan(); - List<TablePosition<ObservableList<SpreadsheetCell>, ?>> selectedCells = new ArrayList<>(); - for (final TablePosition<ObservableList<SpreadsheetCell>, ?> tp : getSelectedCells()) { - if (tp.getRow() >= infRow && tp.getRow() < supRow && tp.getColumn() >= infCol - && tp.getColumn() < supCol) { - selectedCells.add(tp); - } - } - return selectedCells.isEmpty()? null : selectedCells; - } - - /** - * ********************************************************************* - * * Support code * * - * ******************************************************************** - */ - private void addSelectedRowsAndColumns(TablePosition<?, ?> position) { - GridViewSkin skin = getSpreadsheetViewSkin(); - if (skin == null) { - return; - } - final SpreadsheetCell cell = cellsView.getItems().get(position.getRow()).get(position.getColumn()); - for (int i = cell.getRow(); i < cell.getRowSpan() + cell.getRow(); ++i) { - skin.getSelectedRows().add(i); - for (int j = cell.getColumn(); j < cell.getColumnSpan() + cell.getColumn(); ++j) { - skin.getSelectedColumns().add(j); - } - } - } - - private void removeSelectedRowsAndColumns(TablePosition<?, ?> position) { - final SpreadsheetCell cell = cellsView.getItems().get(position.getRow()).get(position.getColumn()); - for (int i = cell.getRow(); i < cell.getRowSpan() + cell.getRow(); ++i) { - getSpreadsheetViewSkin().getSelectedRows().remove(Integer.valueOf(i)); - for (int j = cell.getColumn(); j < cell.getColumnSpan() + cell.getColumn(); ++j) { - getSpreadsheetViewSkin().getSelectedColumns().remove(Integer.valueOf(j)); - } - } - } - - @Override - public void clearAndSelect(int row, TableColumn<ObservableList<SpreadsheetCell>, ?> column) { - // RT-33558 if this method has been called with a given row/column - // intersection, and that row/column intersection is the only - // selection currently, then this method becomes a no-op. - - // This is understandable but not compatible with spanning - // selection. - /* - * if (getSelectedCells().size() == 1 && isSelected(row, column)) { - * return; } - */ - makeAtomic = true; - // firstly we make a copy of the selection, so that we can send out - // the correct details in the selection change event - List<TablePosition<ObservableList<SpreadsheetCell>, ?>> previousSelection = new ArrayList<>( - selectedCellsMap.getSelectedCells()); - - // then clear the current selection - clearSelection(); - - // and select the new row - select(row, column); - - makeAtomic = false; - - // fire off a single add/remove/replace notification (rather than - // individual remove and add notifications) - see RT-33324 - if (old != null && old.getColumn() >= 0) { - TableColumn<ObservableList<SpreadsheetCell>, ?> columnFinal = getTableView().getColumns().get( - old.getColumn()); - int changeIndex = selectedCellsSeq.indexOf(new TablePosition<>(getTableView(), old.getRow(), - columnFinal)); - NonIterableChange.GenericAddRemoveChange<TablePosition<ObservableList<SpreadsheetCell>, ?>> change = new NonIterableChange.GenericAddRemoveChange<>( - changeIndex, changeIndex + 1, previousSelection, selectedCellsSeq); - handleSelectedCellsListChangeEvent(change); - } - } - - /** - * FIXME I don't understand why TablePosition is not parameterized in the - * API.. - * - * @return - */ - @Override - public ObservableList<TablePosition> getSelectedCells() { - return (ObservableList<TablePosition>) (Object) selectedCellsSeq; - } - - @Override - public void selectAboveCell() { - final TablePosition<ObservableList<SpreadsheetCell>, ?> pos = getFocusedCell(); - if (pos.getRow() == -1) { - select(getItemCount() - 1); - } else if (pos.getRow() > 0) { - select(pos.getRow() - 1, pos.getTableColumn()); - } - - } - - @Override - public void selectBelowCell() { - final TablePosition<ObservableList<SpreadsheetCell>, ?> pos = getFocusedCell(); - - if (pos.getRow() == -1) { - select(0); - } else if (pos.getRow() < getItemCount() - 1) { - select(pos.getRow() + 1, pos.getTableColumn()); - } - - } - - @Override - public void selectLeftCell() { - if (!isCellSelectionEnabled()) { - return; - } - - final TablePosition<ObservableList<SpreadsheetCell>, ?> pos = getFocusedCell(); - if (pos.getColumn() - 1 >= 0) { - select(pos.getRow(), getTableColumn(pos.getTableColumn(), -1)); - } - - } - - @Override - public void selectRightCell() { - if (!isCellSelectionEnabled()) { - return; - } - - final TablePosition<ObservableList<SpreadsheetCell>, ?> pos = getFocusedCell(); - if (pos.getColumn() + 1 < getTableView().getVisibleLeafColumns().size()) { - select(pos.getRow(), getTableColumn(pos.getTableColumn(), 1)); - } - - } - - @Override - public void clearSelection() { - if (!makeAtomic) { - setSelectedIndex(-1); - setSelectedItem(getModelItem(-1)); - focus(-1); - } - quietClearSelection(); - } - - private void quietClearSelection() { - selectedCellsMap.clear(); - GridViewSkin skin = getSpreadsheetViewSkin(); - if (skin != null) { - skin.getSelectedRows().clear(); - skin.getSelectedColumns().clear(); - } - } - - @SuppressWarnings("unchecked") - private TablePosition<ObservableList<SpreadsheetCell>, ?> getFocusedCell() { - if (getTableView().getFocusModel() == null) { - return new TablePosition<>(getTableView(), -1, null); - } - return (TablePosition<ObservableList<SpreadsheetCell>, ?>) cellsView.getFocusModel().getFocusedCell(); - } - - private TableColumn<ObservableList<SpreadsheetCell>, ?> getTableColumn( - TableColumn<ObservableList<SpreadsheetCell>, ?> column, int offset) { - final int columnIndex = getTableView().getVisibleLeafIndex(column); - final int newColumnIndex = columnIndex + offset; - return getTableView().getVisibleLeafColumn(newColumnIndex); - } - - private GridViewSkin getSpreadsheetViewSkin() { - return (GridViewSkin) getCellsViewSkin(); - } - - /** - * For a position, return the Visible Cell associated with It can be the top - * of the span cell if it's visible, or it can be the first row visible if - * we have scrolled - * - * @param row - * @param column - * @param col - * @return - */ - private TablePosition<ObservableList<SpreadsheetCell>, ?> getVisibleCell(int row, - TableColumn<ObservableList<SpreadsheetCell>, ?> column, int col) { - final SpreadsheetView.SpanType spanType = spreadsheetView.getSpanType(row, col); - switch (spanType) { - case NORMAL_CELL: - case ROW_VISIBLE: - return new TablePosition<>(cellsView, row, column); - case BOTH_INVISIBLE: - case COLUMN_SPAN_INVISIBLE: - case ROW_SPAN_INVISIBLE: - default: - final SpreadsheetCell cellSpan = cellsView.getItems().get(row).get(col); - if (getCellsViewSkin() == null || (getCellsViewSkin().getCellsSize() != 0 && getNonFixedRow(0).getIndex() <= cellSpan.getRow())) { - return new TablePosition<>(cellsView, cellSpan.getRow(), cellsView.getColumns().get( - cellSpan.getColumn())); - } else { // If it's not, then it's the firstkey - return new TablePosition<>(cellsView, getNonFixedRow(0).getIndex(), cellsView.getColumns().get( - cellSpan.getColumn())); - } - } - } - - /** - * @return the inner table view skin - */ - final GridViewSkin getCellsViewSkin() { - return (GridViewSkin) (cellsView.getSkin()); - } - - /** - * Return the {@link GridRow} at the specified index - * - * @param index - * @return - */ - private GridRow getNonFixedRow(int index) { - return getCellsViewSkin().getRow(index); - } - - /** - * Return the TableColumn right after the current TablePosition (including - * the ColumSpan to be on a visible Cell) - * - * @param t the current TablePosition - * @return - */ - private int getTableColumnSpanInt(final TablePosition<?, ?> t) { - return t.getColumn() + cellsView.getItems().get(t.getRow()).get(t.getColumn()).getColumnSpan(); - } - -} diff --git a/src/impl/org/controlsfx/spreadsheet/VerticalHeader.java b/src/impl/org/controlsfx/spreadsheet/VerticalHeader.java deleted file mode 100644 index 0cefc9e..0000000 --- a/src/impl/org/controlsfx/spreadsheet/VerticalHeader.java +++ /dev/null @@ -1,675 +0,0 @@ -/** - * Copyright (c) 2013, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.spreadsheet; - -import static impl.org.controlsfx.i18n.Localization.asKey; -import static impl.org.controlsfx.i18n.Localization.localize; - -import java.util.ArrayList; -import java.util.BitSet; -import java.util.List; -import java.util.Set; -import java.util.Stack; -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; -import javafx.beans.property.DoubleProperty; -import javafx.beans.property.ReadOnlyDoubleProperty; -import javafx.beans.property.SimpleDoubleProperty; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.collections.ObservableList; -import javafx.event.ActionEvent; -import javafx.event.Event; -import javafx.event.EventHandler; -import javafx.geometry.NodeOrientation; -import javafx.scene.Cursor; -import javafx.scene.control.ContextMenu; -import javafx.scene.control.Label; -import javafx.scene.control.MenuItem; -import javafx.scene.control.ScrollBar; -import javafx.scene.control.TableColumn; -import javafx.scene.control.TableView.TableViewSelectionModel; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import javafx.scene.input.MouseEvent; -import javafx.scene.layout.StackPane; -import javafx.scene.paint.Color; -import javafx.scene.shape.Rectangle; -import javafx.stage.WindowEvent; -import org.controlsfx.control.spreadsheet.Picker; -import org.controlsfx.control.spreadsheet.SpreadsheetCell; -import org.controlsfx.control.spreadsheet.SpreadsheetView; - -/** - * Display the vertical header on the left of the cells (view), the index of the - * lines displayed on screen. - */ -public class VerticalHeader extends StackPane { - - public static final int PICKER_SIZE = 16; - private static final int DRAG_RECT_HEIGHT = 5; - private static final String TABLE_ROW_KEY = "TableRow"; //$NON-NLS-1$ - private static final String PICKER_INDEX = "PickerIndex"; //$NON-NLS-1$ - private static final String TABLE_LABEL_KEY = "Label"; //$NON-NLS-1$ - private static final Image pinImage = new Image(SpreadsheetView.class.getResource("pinSpreadsheetView.png").toExternalForm()); //$NON-NLS-1$ - - /** - * ************************************************************************* - * * Private Fields * * - * ************************************************************************ - */ - private final SpreadsheetHandle handle; - private final SpreadsheetView spreadsheetView; - private double horizontalHeaderHeight; - /** - * This represents the VerticalHeader width. It's the total amount of space - * used by the VerticalHeader. It's composed of the sum of the - * SpreadsheetView {@link SpreadsheetView#getRowHeaderWidth() } and the size - * of the pickers (which is fixed right now). - * - */ - private final DoubleProperty innerVerticalHeaderWidth = new SimpleDoubleProperty(); - private Rectangle clip; // Ensure that children do not go out of bounds - private ContextMenu blankContextMenu; - - // used for column resizing - private double lastY = 0.0F; - private static double dragAnchorY = 0.0; - - // drag rectangle overlays - private final List<Rectangle> dragRects = new ArrayList<>(); - - private final List<Label> labelList = new ArrayList<>(); - private GridViewSkin skin; - private boolean resizing = false; - - private final Stack<Label> pickerPile; - private final Stack<Label> pickerUsed; - - /** - * This BitSet keeps track of the selected rows (when clicked on their - * header) in order to allow multi-resize. - */ - private final BitSet selectedRows = new BitSet(); - - /** - * **************************************************************** - * CONSTRUCTOR - * - * @param handle - * *************************************************************** - */ - public VerticalHeader(final SpreadsheetHandle handle) { - this.handle = handle; - this.spreadsheetView = handle.getView(); - pickerPile = new Stack<>(); - pickerUsed = new Stack<>(); - } - - /** - * ************************************************************************* - * * Private/Protected Methods * - * *********************************************************************** - */ - /** - * Init - * - * @param skin - * @param horizontalHeader - */ - void init(final GridViewSkin skin, HorizontalHeader horizontalHeader) { - this.skin = skin; - // Adjust position upon HorizontalHeader height - horizontalHeader.heightProperty().addListener(new ChangeListener<Number>() { - @Override - public void changed(ObservableValue<? extends Number> arg0, Number oldHeight, Number newHeight) { - horizontalHeaderHeight = newHeight.doubleValue(); - requestLayout(); - } - }); - - // When the Grid is changing, we need to update our information. - handle.getView().gridProperty().addListener(layout); - - // Clip property to stay within bounds - clip = new Rectangle(getVerticalHeaderWidth(), snapSize(skin.getSkinnable().getHeight())); - clip.relocate(snappedTopInset(), snappedLeftInset()); - clip.setSmooth(false); - clip.heightProperty().bind(skin.getSkinnable().heightProperty()); - clip.widthProperty().bind(innerVerticalHeaderWidth); - VerticalHeader.this.setClip(clip); - - // We desactivate and activate the verticalHeader upon request - spreadsheetView.showRowHeaderProperty().addListener(layout); - - // When the Column header is showing or not, we need to update the - // position of the verticalHeader - spreadsheetView.showColumnHeaderProperty().addListener(layout); - spreadsheetView.getFixedRows().addListener(layout); - spreadsheetView.fixingRowsAllowedProperty().addListener(layout); - spreadsheetView.rowHeaderWidthProperty().addListener(layout); - - // In case we resize the view in any manners - spreadsheetView.heightProperty().addListener(layout); - - //When rowPickers is changing - spreadsheetView.getRowPickers().addListener(layout); - - // For layout properly the verticalHeader when there are some selected - // items - skin.getSelectedRows().addListener(layout); - - blankContextMenu = new ContextMenu(); - } - - public double getVerticalHeaderWidth() { - return innerVerticalHeaderWidth.get(); - } - - public ReadOnlyDoubleProperty verticalHeaderWidthProperty(){ - return innerVerticalHeaderWidth; - } - - public double computeHeaderWidth() { - double width = 0; - if (!spreadsheetView.getRowPickers().isEmpty()) { - width += PICKER_SIZE; - } - if (spreadsheetView.isShowRowHeader()) { - width += spreadsheetView.getRowHeaderWidth(); - } - return width; - } - - void clearSelectedRows(){ - selectedRows.clear(); - } - - @Override - protected void layoutChildren() { - if (resizing) { - return; - } - if ((spreadsheetView.isShowRowHeader() || !spreadsheetView.getRowPickers().isEmpty()) && skin.getCellsSize() > 0) { - - double x = snappedLeftInset(); - /** - * Pickers - */ - pickerPile.addAll(pickerUsed.subList(0, pickerUsed.size())); - pickerUsed.clear(); - if (!spreadsheetView.getRowPickers().isEmpty()) { - innerVerticalHeaderWidth.setValue(PICKER_SIZE); - x += PICKER_SIZE; - } else { - innerVerticalHeaderWidth.setValue(0); - } - if (spreadsheetView.isShowRowHeader()) { - innerVerticalHeaderWidth.setValue(getVerticalHeaderWidth() + spreadsheetView.getRowHeaderWidth()); - } - - getChildren().clear(); - - final int cellSize = skin.getCellsSize(); - - int rowCount = 0; - Label label; - - rowCount = addVisibleRows(rowCount, x, cellSize); - -// if (spreadsheetView.isShowRowHeader()) { - rowCount = addFixedRows(rowCount, x, cellSize); -// } - // First one blank and on top (z-order) of the others - if (spreadsheetView.showColumnHeaderProperty().get()) { - label = getLabel(rowCount++, null); - label.setOnMousePressed((MouseEvent event) -> { - spreadsheetView.getSelectionModel().selectAll(); - }); - label.setText(""); //$NON-NLS-1$ - label.resize(spreadsheetView.getRowHeaderWidth(), horizontalHeaderHeight); - label.layoutYProperty().unbind(); - label.setLayoutY(0); - label.setLayoutX(x); - label.getStyleClass().clear(); - label.setContextMenu(blankContextMenu); - getChildren().add(label); - } - - ScrollBar hbar = handle.getCellsViewSkin().getHBar(); - //FIXME handle height. - if (hbar.isVisible()) { - // Last one blank and on top (z-order) of the others - label = getLabel(rowCount++, null); - label.getProperties().put(TABLE_ROW_KEY, null); - label.setText(""); //$NON-NLS-1$ - label.resize(getVerticalHeaderWidth(), hbar.getHeight()); - label.layoutYProperty().unbind(); - label.relocate(snappedLeftInset(), getHeight() - hbar.getHeight()); - label.getStyleClass().clear(); - label.setContextMenu(blankContextMenu); - getChildren().add(label); - } - } else { - getChildren().clear(); - } - } - - private int addFixedRows(int rowCount, double x, int cellSize) { - double spaceUsedByFixedRows = 0; - int rowIndex; - Label label; - final Set<Integer> currentlyFixedRow = handle.getCellsViewSkin().getCurrentlyFixedRow(); - // Then we iterate over the FixedRows if any - if (!spreadsheetView.getFixedRows().isEmpty() && cellSize != 0) { - for (int j = 0; j < spreadsheetView.getFixedRows().size(); ++j) { - - rowIndex = spreadsheetView.getFixedRows().get(j); - if (!currentlyFixedRow.contains(rowIndex)) { - break; - } - double rowHeight = skin.getRowHeight(rowIndex); - double y = spreadsheetView.showColumnHeaderProperty().get() ? snappedTopInset() + horizontalHeaderHeight + spaceUsedByFixedRows - : snappedTopInset() + spaceUsedByFixedRows; - - if (spreadsheetView.getRowPickers().containsKey(rowIndex)) { - Label picker = getPicker(spreadsheetView.getRowPickers().get(rowIndex)); - picker.resize(PICKER_SIZE, rowHeight); - picker.layoutYProperty().unbind(); - picker.setLayoutY(y); - getChildren().add(picker); - } - if (spreadsheetView.isShowRowHeader()) { - label = getLabel(rowCount++, rowIndex); - GridRow row = skin.getRowIndexed(rowIndex); - label.getProperties().put(TABLE_ROW_KEY, row); - label.setText(getRowHeader(rowIndex)); - label.resize(spreadsheetView.getRowHeaderWidth(), rowHeight); - label.setContextMenu(getRowContextMenu(rowIndex)); - if(row != null){ - label.layoutYProperty().bind(row.layoutYProperty().add(horizontalHeaderHeight).add(row.verticalShift)); - } - label.setLayoutX(x); - final ObservableList<String> css = label.getStyleClass(); - if (skin.getSelectedRows().contains(rowIndex)) { - css.addAll("selected"); //$NON-NLS-1$ - } else { - css.removeAll("selected"); //$NON-NLS-1$ - } - css.addAll("fixed"); //$NON-NLS-1$ - getChildren().add(label); - // position drag overlay to intercept row resize requests if authorized by the grid. - if (spreadsheetView.getGrid().isRowResizable(rowIndex)) { - Rectangle dragRect = getDragRect(rowCount++); - dragRect.getProperties().put(TABLE_ROW_KEY, row); - dragRect.getProperties().put(TABLE_LABEL_KEY, label); - dragRect.setWidth(label.getWidth()); - dragRect.relocate(snappedLeftInset() + x, y + rowHeight - DRAG_RECT_HEIGHT); - getChildren().add(dragRect); - } - } - spaceUsedByFixedRows += skin.getRowHeight(rowIndex); - - - } - } - return rowCount; - } - - private int addVisibleRows(int rowCount, double x, int cellSize) { - int rowIndex; - // We add horizontalHeaderHeight because we need to - // take the other header into account. - double y = snappedTopInset(); - - if (spreadsheetView.showColumnHeaderProperty().get()) { - y += horizontalHeaderHeight; - } - - // The Labels must be aligned with the rows - if (cellSize != 0) { - y += skin.getRow(0).getLocalToParentTransform().getTy(); - } - - Label label; - // We don't want to add Label if there are no rows associated with. - final int modelRowCount = spreadsheetView.getGrid().getRowCount(); - - int i = 0; - - GridRow row = skin.getRow(i); - - double fixedRowHeight = skin.getFixedRowHeight(); - double rowHeaderWidth = spreadsheetView.getRowHeaderWidth(); - double height; - - // We iterate over the visibleRows - while (cellSize != 0 && row != null && row.getIndex() < modelRowCount) { - rowIndex = row.getIndex(); - height = row.getHeight(); - /** - * Picker - */ - if (row.getLayoutY() >= fixedRowHeight && spreadsheetView.getRowPickers().containsKey(rowIndex)) { - Label picker = getPicker(spreadsheetView.getRowPickers().get(rowIndex)); - picker.resize(PICKER_SIZE, height); - picker.layoutYProperty().bind(row.layoutYProperty().add(horizontalHeaderHeight)); - getChildren().add(picker); - } - - if (spreadsheetView.isShowRowHeader()) { - label = getLabel(rowCount++, rowIndex); - label.getProperties().put(TABLE_ROW_KEY, row); - label.setText(getRowHeader(rowIndex)); - label.resize(rowHeaderWidth, height); - label.setLayoutX(x); - label.layoutYProperty().bind(row.layoutYProperty().add(horizontalHeaderHeight)); - label.setContextMenu(getRowContextMenu(rowIndex)); - - getChildren().add(label); - // We want to highlight selected rows - final ObservableList<String> css = label.getStyleClass(); - if (skin.getSelectedRows().contains(rowIndex)) { - css.addAll("selected"); //$NON-NLS-1$ - } else { - css.removeAll("selected"); //$NON-NLS-1$ - } - if (spreadsheetView.getFixedRows().contains(rowIndex)) { - css.addAll("fixed"); //$NON-NLS-1$ - } else { - css.removeAll("fixed"); //$NON-NLS-1$ - } - - y += height; - - // position drag overlay to intercept row resize requests if authorized by the grid. - if (spreadsheetView.getGrid().isRowResizable(rowIndex)) { - Rectangle dragRect = getDragRect(rowCount++); - dragRect.getProperties().put(TABLE_ROW_KEY, row); - dragRect.getProperties().put(TABLE_LABEL_KEY, label); - dragRect.setWidth(label.getWidth()); - dragRect.relocate(snappedLeftInset() + x, y - DRAG_RECT_HEIGHT); - getChildren().add(dragRect); - } - } - row = skin.getRow(++i); - } - return rowCount; - } - - private final EventHandler<MouseEvent> rectMousePressed = new EventHandler<MouseEvent>() { - @Override - public void handle(MouseEvent me) { - - if (me.getClickCount() == 2 && me.isPrimaryButtonDown()) { - Rectangle rect = (Rectangle) me.getSource(); - GridRow row = (GridRow) rect.getProperties().get(TABLE_ROW_KEY); - skin.resizeRowToFitContent(row.getIndex()); - requestLayout(); - } else { - // rather than refer to the rect variable, we just grab - // it from the source to prevent a small memory leak. - dragAnchorY = me.getSceneY(); - resizing = true; - } - me.consume(); - } - }; - - private final EventHandler<MouseEvent> rectMouseDragged = new EventHandler<MouseEvent>() { - @Override - public void handle(MouseEvent me) { - Rectangle rect = (Rectangle) me.getSource(); - GridRow row = (GridRow) rect.getProperties().get(TABLE_ROW_KEY); - Label label = (Label) rect.getProperties().get(TABLE_LABEL_KEY); - if (row != null) { - rowResizing(row, label, me); - } - me.consume(); - } - }; - - private void rowResizing(GridRow gridRow, Label label, MouseEvent me) { - double draggedY = me.getSceneY() - dragAnchorY; - if (gridRow.getEffectiveNodeOrientation() == NodeOrientation.RIGHT_TO_LEFT) { - draggedY = -draggedY; - } - - double delta = draggedY - lastY; - - Double newHeight = gridRow.getHeight() + delta; - if (newHeight < 0) { - return; - } - handle.getCellsViewSkin().rowHeightMap.put(gridRow.getIndex(), newHeight); - Event.fireEvent(spreadsheetView, new SpreadsheetView.RowHeightEvent(gridRow.getIndex(), newHeight)); - label.resize(spreadsheetView.getRowHeaderWidth(), newHeight); - gridRow.setPrefHeight(newHeight); - gridRow.requestLayout(); - - lastY = draggedY; - } - - private final EventHandler<MouseEvent> rectMouseReleased = new EventHandler<MouseEvent>() { - @Override - public void handle(MouseEvent me) { - lastY = 0.0F; - resizing = false; - requestLayout(); - me.consume(); - //We resize the other selected rows if the resized one is selected. - Rectangle rect = (Rectangle) me.getSource(); - GridRow row = (GridRow) rect.getProperties().get(TABLE_ROW_KEY); - if (selectedRows.get(row.getIndex())) { - double height = row.getHeight(); - for (int i = selectedRows.nextSetBit(0); i >= 0; i = selectedRows.nextSetBit(i + 1)) { - skin.rowHeightMap.put(i, height); - Event.fireEvent(spreadsheetView, new SpreadsheetView.RowHeightEvent(i, height)); - } - } - } - }; - - /** - * Create a new label and put it in the pile or just grab one from the pile. - * - * @param rowNumber - * @return - */ - private Label getLabel(int rowNumber, Integer row) { - Label label; - if (labelList.isEmpty() || labelList.size() <= rowNumber) { - label = new Label(); - labelList.add(label); - } else { - label = labelList.get(rowNumber); - } - // We want to select the whole row when clicking on a header. - label.setOnMousePressed(row == null ? null : (MouseEvent event) -> { - if (event.isPrimaryButtonDown()) { - if (event.getClickCount() == 2) { - skin.resizeRowToFitContent(row); - requestLayout(); - } else { - headerClicked(row, event); - } - } - }); - return label; - } - - /** - * If a header is clicked, we must select the whole row. If Control key of - * Shift key is pressed, we must not deselect the previous selection but - * just act like the {@link GridViewBehavior} would. - * - * @param row - * @param event - */ - private void headerClicked(int row, MouseEvent event) { - TableViewSelectionModel<ObservableList<SpreadsheetCell>> sm = handle.getGridView().getSelectionModel(); - int focusedRow = sm.getFocusedIndex(); - int rowCount = handle.getView().getGrid().getRowCount(); - ObservableList<TableColumn<ObservableList<SpreadsheetCell>, ?>> columns = sm.getTableView().getColumns(); - TableColumn<ObservableList<SpreadsheetCell>, ?> firstColumn = columns.get(0); - TableColumn<ObservableList<SpreadsheetCell>, ?> lastColumn = columns.get(columns.size() - 1); - - if (event.isShortcutDown()) { - BitSet tempSet = (BitSet) selectedRows.clone(); - sm.selectRange(row, firstColumn, row, lastColumn); - selectedRows.or(tempSet); - selectedRows.set(row); - } else if (event.isShiftDown() && focusedRow >= 0 && focusedRow < rowCount) { - sm.clearSelection(); - sm.selectRange(focusedRow, firstColumn, row, lastColumn); - //We want to let the focus on the focused row. - sm.getTableView().getFocusModel().focus(focusedRow, firstColumn); - int min = Math.min(row, focusedRow); - int max = Math.max(row, focusedRow); - selectedRows.set(min, max + 1); - } else { - sm.clearSelection(); - sm.selectRange(row, firstColumn, row, lastColumn); - //And we want to have the focus on the first cell in order to be able to copy/paste between rows. - sm.getTableView().getFocusModel().focus(row, firstColumn); - selectedRows.set(row); - } - } - - private Label getPicker(Picker picker) { - Label pickerLabel; - if (pickerPile.isEmpty()) { - pickerLabel = new Label(); - picker.getStyleClass().addListener(layout); - pickerLabel.setOnMouseClicked(pickerMouseEvent); - } else { - pickerLabel = pickerPile.pop(); - } - pickerUsed.push(pickerLabel); - - pickerLabel.getStyleClass().setAll(picker.getStyleClass()); - pickerLabel.getProperties().put(PICKER_INDEX, picker); - return pickerLabel; - } - - private final EventHandler<MouseEvent> pickerMouseEvent = new EventHandler<MouseEvent>() { - - @Override - public void handle(MouseEvent mouseEvent) { - Label picker = (Label) mouseEvent.getSource(); - - ((Picker) picker.getProperties().get(PICKER_INDEX)).onClick(); - } - }; - - /** - * Create a new Rectangle and put it in the pile or just grab one from the - * pile. - * - * @param rowNumber - * @return - */ - private Rectangle getDragRect(int rowNumber) { - if (dragRects.isEmpty() || dragRects.size() <= rowNumber) { - final Rectangle rect = new Rectangle(); - rect.setWidth(getVerticalHeaderWidth()); - rect.setHeight(DRAG_RECT_HEIGHT); - rect.setFill(Color.TRANSPARENT); - rect.setSmooth(false); - rect.setOnMousePressed(rectMousePressed); - rect.setOnMouseDragged(rectMouseDragged); - rect.setOnMouseReleased(rectMouseReleased); - rect.setCursor(Cursor.V_RESIZE); - dragRects.add(rect); - return rect; - } else { - return dragRects.get(rowNumber); - } - } - - /** - * Return a contextMenu for fixing a row if possible. - * - * @param row - * @return - */ - private ContextMenu getRowContextMenu(final Integer row) { - if (spreadsheetView.isRowFixable(row)) { - final ContextMenu contextMenu = new ContextMenu(); - - MenuItem fixItem = new MenuItem(localize(asKey("spreadsheet.verticalheader.menu.fix"))); //$NON-NLS-1$ - contextMenu.setOnShowing(new EventHandler<WindowEvent>() { - - @Override - public void handle(WindowEvent event) { - if (spreadsheetView.getFixedRows().contains(row)) { - fixItem.setText(localize(asKey("spreadsheet.verticalheader.menu.unfix"))); //$NON-NLS-1$ - } else { - fixItem.setText(localize(asKey("spreadsheet.verticalheader.menu.fix"))); //$NON-NLS-1$ - } - } - }); - fixItem.setGraphic(new ImageView(pinImage)); - - fixItem.setOnAction(new EventHandler<ActionEvent>() { - @Override - public void handle(ActionEvent arg0) { - if (spreadsheetView.getFixedRows().contains(row)) { - spreadsheetView.getFixedRows().remove(row); - } else { - spreadsheetView.getFixedRows().add(row); - } - } - }); - contextMenu.getItems().add(fixItem); - - return contextMenu; - } else { - return blankContextMenu; - } - } - - /** - * Return the String header associated with this row index. - * - * @param index - * @return - */ - private String getRowHeader(int index) { - return spreadsheetView.getGrid().getRowHeaders().size() > index ? spreadsheetView - .getGrid().getRowHeaders().get(index) : String.valueOf(index + 1); - } - - /** - * ************************************************************************* - * * Listeners * * - * ************************************************************************ - */ - private final InvalidationListener layout = (Observable arg0) -> { - requestLayout(); - }; -} diff --git a/src/impl/org/controlsfx/table/ColumnFilter.java b/src/impl/org/controlsfx/table/ColumnFilter.java deleted file mode 100644 index 50d79c6..0000000 --- a/src/impl/org/controlsfx/table/ColumnFilter.java +++ /dev/null @@ -1,308 +0,0 @@ -/** - * Copyright (c) 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.table; - -import javafx.beans.Observable; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.beans.value.WeakChangeListener; -import javafx.collections.FXCollections; -import javafx.collections.ListChangeListener; -import javafx.collections.ObservableList; -import javafx.collections.WeakListChangeListener; -import javafx.scene.control.ContextMenu; -import javafx.scene.control.CustomMenuItem; -import javafx.scene.control.TableColumn; -import org.controlsfx.control.table.TableFilter; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Objects; -import java.util.Optional; -import java.util.function.BiPredicate; - -public final class ColumnFilter<T,R> { - private final TableFilter<T> tableFilter; - private final TableColumn<T,R> tableColumn; - - private final ObservableList<FilterValue<T,R>> filterValues; - - private final DupeCounter<R> filterValuesDupeCounter = new DupeCounter<>(false); - private final DupeCounter<R> visibleValuesDupeCounter = new DupeCounter<>(false); - private final HashSet<R> unselectedValues = new HashSet<>(); - private final HashMap<CellIdentity<T>,ChangeListener<R>> trackedCells = new HashMap<>(); - - private boolean lastFilter = false; - private boolean isDirty = false; - private BiPredicate<String,String> searchStrategy = (inputString, subjectString) -> subjectString.contains(inputString); - private volatile FilterPanel filterPanel; - - private boolean initialized = false; - - private final ListChangeListener<T> backingListListener = lc -> { - while (lc.next()) { - if (lc.wasAdded()) { - lc.getAddedSubList().stream() - .forEach(t -> addBackingItem(t, getTableColumn().getCellObservableValue(t))); - } - if (lc.wasRemoved()) { - lc.getRemoved().stream() - .forEach(t -> removeBackingItem(t, getTableColumn().getCellObservableValue(t))); - } - } - }; - - private final ListChangeListener<T> itemsListener = lc -> { - while (lc.next()) { - if (lc.wasAdded()) { - lc.getAddedSubList().stream() - .map(getTableColumn()::getCellObservableValue) - .forEach(this::addVisibleItem); - } - if (lc.wasRemoved()) { - lc.getRemoved().stream() - .map(getTableColumn()::getCellObservableValue) - .forEach(this::removeVisibleItem); - } - } - }; - - private final ChangeListener<R> changeListener = (observable, oldValue, newValue) -> { - if (filterValuesDupeCounter.add(newValue) == 1) { - getFilterValues().add(new FilterValue<>(newValue,this)); - } - removeValue(oldValue); - }; - - private final ListChangeListener<FilterValue<T, R>> filterValueListChangeListener = lc -> { - while (lc.next()) { - if (lc.wasRemoved()) { - lc.getRemoved().stream() - .filter(v -> !v.selectedProperty().get()) - .forEach(unselectedValues::remove); - } - if (lc.wasUpdated()) { - int from = lc.getFrom(); - int to = lc.getTo(); - lc.getList().subList(from, to).forEach(v -> { - isDirty = true; - - boolean value = v.selectedProperty().getValue(); - if (!value) { - unselectedValues.add(v.getValue()); - } else { - unselectedValues.remove(v.getValue()); - } - }); - } - } - }; - - public ColumnFilter(TableFilter<T> tableFilter, TableColumn<T,R> tableColumn) { - this.tableFilter = tableFilter; - this.tableColumn = tableColumn; - - this.filterValues = FXCollections.observableArrayList(cb -> new Observable[] { cb.selectedProperty()}); - this.attachContextMenu(); - } - void setFilterPanel(FilterPanel filterPanel) { - this.filterPanel = filterPanel; - } - FilterPanel getFilterPanel() { - return filterPanel; - } - public void initialize() { - if (!initialized) { - initializeListeners(); - initializeValues(); - initialized = true; - } - } - public boolean isInitialized() { - return initialized; - } - - public void selectValue(Object value) { - filterPanel.selectValue(value); - } - public void unselectValue(Object value) { - filterPanel.unSelectValue(value); - } - public void selectAllValues() { - filterPanel.selectAllValues(); - } - public void unSelectAllValues() { - filterPanel.unSelectAllValues(); - } - public boolean wasLastFiltered() { - return lastFilter; - } - public boolean hasUnselections() { - return unselectedValues.size() != 0; - } - public void setSearchStrategy(BiPredicate<String,String> searchStrategy) { - this.searchStrategy = searchStrategy; - } - public BiPredicate<String,String> getSearchStrategy() { - return searchStrategy; - } - public boolean isFiltered() { - return isDirty || unselectedValues.size() > 0; - } - public boolean valueIsVisible(R value) { - return visibleValuesDupeCounter.get(value) > 0; - } - public void applyFilter() { - tableFilter.executeFilter(); - lastFilter = true; - tableFilter.getColumnFilters().stream().filter(c -> !c.equals(this)).forEach(c -> c.lastFilter = false); - tableFilter.getColumnFilters().stream().flatMap(c -> c.filterValues.stream()).forEach(FilterValue::refreshScope); - isDirty = false; - } - - public void resetAllFilters() { - tableFilter.getColumnFilters().stream().flatMap(c -> c.filterValues.stream()).forEach(fv -> fv.selectedProperty().set(true)); - tableFilter.resetFilter(); - tableFilter.getColumnFilters().stream().forEach(c -> c.lastFilter = false); - tableFilter.getColumnFilters().stream().flatMap(c -> c.filterValues.stream()).forEach(FilterValue::refreshScope); - isDirty = false; - } - - public ObservableList<FilterValue<T,R>> getFilterValues() { - return filterValues; - } - - public TableColumn<T,R> getTableColumn() { - return tableColumn; - } - public TableFilter<T> getTableFilter() { - return tableFilter; - } - public boolean evaluate(T item) { - ObservableValue<R> value = tableColumn.getCellObservableValue(item); - - return unselectedValues.size() == 0 - || !unselectedValues.contains(value.getValue()); - } - - private void initializeValues() { - tableFilter.getBackingList().stream() - .forEach(t -> addBackingItem(t, tableColumn.getCellObservableValue(t))); - tableFilter.getTableView().getItems().stream() - .map(tableColumn::getCellObservableValue).forEach(this::addVisibleItem); - - } - - private void addBackingItem(T item, ObservableValue<R> cellValue) { - if (cellValue == null) { - return; - } - if (filterValuesDupeCounter.add(cellValue.getValue()) == 1) { - filterValues.add(new FilterValue<>(cellValue.getValue(),this)); - } - - //listen to cell value and track it - CellIdentity<T> trackedCellValue = new CellIdentity<>(item); - - ChangeListener<R> cellListener = new WeakChangeListener(changeListener); - cellValue.addListener(cellListener); - trackedCells.put(trackedCellValue,cellListener); - } - private void removeBackingItem(T item, ObservableValue<R> cellValue) { - if (cellValue == null) { - return; - } - removeValue(cellValue.getValue()); - - //remove listener from cell - ChangeListener<R> listener = trackedCells.get(new CellIdentity<>(item)); - cellValue.removeListener(listener); - trackedCells.remove(new CellIdentity<>(item)); - } - private void removeValue(R value) { - boolean removedLastDuplicate = filterValuesDupeCounter.remove(value) == 0; - if (removedLastDuplicate) { - // Remove the FilterValue associated with the value - FilterValue<T,R> existingFilterValue = getFilterValues().stream() - .filter(fv -> Objects.equals(fv.getValue(), value)).findAny().get(); - getFilterValues().remove(existingFilterValue); - } - } - private void addVisibleItem(ObservableValue<R> cellValue) { - if (cellValue != null) { - visibleValuesDupeCounter.add(cellValue.getValue()); - } - } - private void removeVisibleItem(ObservableValue<R> cellValue) { - if (cellValue != null) { - visibleValuesDupeCounter.remove(cellValue.getValue()); - } - } - private void initializeListeners() { - //listen to backing list and update distinct values accordingly - tableFilter.getBackingList().addListener(new WeakListChangeListener<T>(backingListListener)); - - //listen to visible items and update visible values accordingly - tableFilter.getTableView().getItems().addListener(new WeakListChangeListener<T>(itemsListener)); - - //listen to selections on filterValues - filterValues.addListener(new WeakListChangeListener<>(filterValueListChangeListener)); - } - - /**Leverages tableColumn's context menu to attach filter panel */ - private void attachContextMenu() { - - ContextMenu contextMenu = new ContextMenu(); - - CustomMenuItem item = FilterPanel.getInMenuItem(this, contextMenu); - - contextMenu.getStyleClass().add("column-filter"); - contextMenu.getItems().add(item); - - tableColumn.setContextMenu(contextMenu); - - contextMenu.setOnShowing(ae -> initialize()); - } - - private static final class CellIdentity<T> { - private final T item; - - CellIdentity(T item) { - this.item = item; - } - - @Override - public boolean equals(Object other) { - return this.item == ((CellIdentity<?>)other).item; - } - - @Override - public int hashCode() { - return System.identityHashCode(item); - } - } -} diff --git a/src/impl/org/controlsfx/table/DupeCounter.java b/src/impl/org/controlsfx/table/DupeCounter.java deleted file mode 100644 index 851a6ce..0000000 --- a/src/impl/org/controlsfx/table/DupeCounter.java +++ /dev/null @@ -1,52 +0,0 @@ -package impl.org.controlsfx.table; - -import java.util.HashMap; -import java.util.Optional; - -final class DupeCounter<T> { - - private final HashMap<T,Integer> counts = new HashMap<>(); - private final boolean enforceFloor; - - public DupeCounter(boolean enforceFloor) { - this.enforceFloor = enforceFloor; - } - public int add(T value) { - Integer prev = counts.get(value); - int newVal; - if (prev == null) { - newVal = 1; - counts.put(value, newVal); - } else { - newVal = prev + 1; - counts.put(value, newVal); - } - return newVal; - } - public int get(T value) { - return Optional.ofNullable(counts.get(value)).orElse(0); - } - public int remove(T value) { - Integer prev = counts.get(value); - if (prev != null && prev > 0) { - int newVal = prev - 1; - if (newVal == 0) { - counts.remove(value); - } else { - counts.put(value, newVal); - } - return newVal; - } - else if (enforceFloor) { - throw new IllegalStateException(); - } - else { - return 0; - } - } - - @Override - public String toString() { - return counts.toString(); - } -} diff --git a/src/impl/org/controlsfx/table/FilterPanel.java b/src/impl/org/controlsfx/table/FilterPanel.java deleted file mode 100644 index 3f417ba..0000000 --- a/src/impl/org/controlsfx/table/FilterPanel.java +++ /dev/null @@ -1,275 +0,0 @@ -/** - * Copyright (c) 2015, 2016, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.table; - -import com.sun.javafx.scene.control.skin.NestedTableColumnHeader; -import com.sun.javafx.scene.control.skin.TableColumnHeader; -import com.sun.javafx.scene.control.skin.TableViewSkin; -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; -import javafx.beans.WeakInvalidationListener; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.WeakChangeListener; -import javafx.collections.transformation.FilteredList; -import javafx.collections.transformation.SortedList; -import javafx.geometry.Insets; -import javafx.geometry.Pos; -import javafx.geometry.Side; -import javafx.scene.control.*; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Priority; -import javafx.scene.layout.VBox; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Optional; -import java.util.function.Supplier; - - -public final class FilterPanel<T,R> extends VBox { - - private final ColumnFilter<T,R> columnFilter; - - private final FilteredList<FilterValue> filterList; - private static final String promptText = "Search..."; - private final TextField searchBox = new TextField(); - private boolean searchMode = false; - private boolean bumpedWidth = false; - - private final ListView<FilterValue> checkListView; - - // This collection will reference column header listeners. References must be kept locally because weak listeners are registered - private final Collection<InvalidationListener> columnHeadersChangeListeners = new ArrayList(); - - private static final Image filterIcon = new Image("/impl/org/controlsfx/table/filter.png"); - - private static final Supplier<ImageView> filterImageView = () -> { - ImageView imageView = new ImageView(filterIcon); - imageView.setFitHeight(15); - imageView.setPreserveRatio(true); - return imageView; - }; - - private final ChangeListener<Skin<?>> skinListener = (w, o, n) -> { - // Clear references to listeners, this will (eventually) cause the WeakListeners to expire - columnHeadersChangeListeners.clear(); - - if (n instanceof TableViewSkin) { - TableViewSkin<?> skin = (TableViewSkin<?>) n; - checkChangeContextMenu(skin, getColumnFilter().getTableColumn(), this); - } - }; - - void selectAllValues() { - checkListView.getItems().stream() - .forEach(item -> item.selectedProperty().set(true)); - } - void unSelectAllValues() { - checkListView.getItems().stream() - .forEach(item -> item.selectedProperty().set(false)); - } - void selectValue(Object value) { - checkListView.getItems().stream().filter(item -> item.getValue().equals(value)) - .forEach(item -> item.selectedProperty().set(true)); - } - void unSelectValue(Object value) { - checkListView.getItems().stream().filter(item -> item.getValue() == value) - .forEach(item -> item.selectedProperty().set(false)); - } - - FilterPanel(ColumnFilter<T,R> columnFilter, ContextMenu contextMenu) { - columnFilter.setFilterPanel(this); - this.columnFilter = columnFilter; - getStyleClass().add("filter-panel"); - - //initialize search box - setPadding(new Insets(3)); - - searchBox.setPromptText(promptText); - getChildren().add(searchBox); - - //initialize checklist view - - filterList = new FilteredList<>(new SortedList<>(columnFilter.getFilterValues()), t -> true); - checkListView = new ListView<>(); - checkListView.setItems(new SortedList<>(filterList, FilterValue::compareTo)); - - getChildren().add(checkListView); - - //initialize apply button - HBox buttonBox = new HBox(); - - Button applyBttn = new Button("APPLY"); - HBox.setHgrow(applyBttn, Priority.ALWAYS); - - applyBttn.setOnAction(e -> { - if (searchMode) { - filterList.forEach(v -> v.selectedProperty().setValue(true)); - - columnFilter.getFilterValues().stream() - .filter(v -> !filterList.stream().filter(fl -> fl.equals(v)).findAny().isPresent()) - .forEach(v -> v.selectedProperty().setValue(false)); - - resetSearchFilter(); - } - if (columnFilter.getTableFilter().isDirty()) { - columnFilter.applyFilter(); - columnFilter.getTableFilter().getColumnFilters().stream().map(ColumnFilter::getFilterPanel) - .forEach(fp -> { - if (!fp.columnFilter.hasUnselections()) { - fp.columnFilter.getTableColumn().setGraphic(null); - } else { - fp.columnFilter.getTableColumn().setGraphic(filterImageView.get()); - if (!bumpedWidth) { - fp.columnFilter.getTableColumn().setPrefWidth(columnFilter.getTableColumn().getWidth() + 20); - bumpedWidth = true; - } - } - }); - } - contextMenu.hide(); - }); - - buttonBox.getChildren().add(applyBttn); - - //initialize unselect all button - Button unselectAllButton = new Button("NONE"); - HBox.setHgrow(unselectAllButton, Priority.ALWAYS); - - unselectAllButton.setOnAction(e -> columnFilter.getFilterValues().forEach(v -> v.selectedProperty().set(false))); - buttonBox.getChildren().add(unselectAllButton); - - //initialize reset buttons - Button selectAllButton = new Button("ALL"); - HBox.setHgrow(selectAllButton, Priority.ALWAYS); - - selectAllButton.setOnAction(e -> { - columnFilter.getFilterValues().forEach(v -> v.selectedProperty().set(true)); - }); - - buttonBox.getChildren().add(selectAllButton); - - Button clearAllButton = new Button("RESET ALL"); - HBox.setHgrow(clearAllButton, Priority.ALWAYS); - - clearAllButton.setOnAction(e -> { - columnFilter.resetAllFilters(); - columnFilter.getTableFilter().getColumnFilters().stream().forEach(cf -> cf.getTableColumn().setGraphic(null)); - contextMenu.hide(); - }); - buttonBox.getChildren().add(clearAllButton); - - buttonBox.setAlignment(Pos.BASELINE_CENTER); - - - getChildren().add(buttonBox); - } - - public void resetSearchFilter() { - this.filterList.setPredicate(t -> true); - searchBox.clear(); - } - public static <T,R> CustomMenuItem getInMenuItem(ColumnFilter<T,R> columnFilter, ContextMenu contextMenu) { - - FilterPanel<T,R> filterPanel = new FilterPanel<>(columnFilter, contextMenu); - - CustomMenuItem menuItem = new CustomMenuItem(); - - filterPanel.initializeListeners(); - - menuItem.contentProperty().set(filterPanel); - - columnFilter.getTableFilter().getTableView().skinProperty().addListener(new WeakChangeListener<>(filterPanel.skinListener)); - - menuItem.setHideOnClick(false); - return menuItem; - } - private void initializeListeners() { - searchBox.textProperty().addListener(l -> { - searchMode = !searchBox.getText().isEmpty(); - filterList.setPredicate(val -> searchBox.getText().isEmpty() || - columnFilter.getSearchStrategy().test(searchBox.getText(), Optional.ofNullable(val.getValue()).map(Object::toString).orElse(""))); - }); - } - - /* Methods below helps will anchor the context menu under the column */ - private static void checkChangeContextMenu(TableViewSkin<?> skin, TableColumn<?, ?> column, FilterPanel filterPanel) { - NestedTableColumnHeader header = skin.getTableHeaderRow().getRootHeader(); - InvalidationListener listener = filterPanel.getOrCreateChangeListener(header, column); - header.getColumnHeaders().addListener(new WeakInvalidationListener(listener)); - changeContextMenu(header, column); - } - - private InvalidationListener getOrCreateChangeListener(NestedTableColumnHeader header, TableColumn<?, ?> column) { - InvalidationListener listener = (Observable obs) -> changeContextMenu(header, column); - - // Keep a reference locally because this listener will be used with a WeakInvalidationListener - columnHeadersChangeListeners.add(listener); - - return listener; - } - - private static void changeContextMenu(NestedTableColumnHeader header, TableColumn<?, ?> column) { - TableColumnHeader headerSkin = scan(column, header); - if (headerSkin != null) { - headerSkin.setOnContextMenuRequested(ev -> { - ContextMenu cMenu = column.getContextMenu(); - if (cMenu != null) { - cMenu.show(headerSkin, Side.BOTTOM, 5, 5); - } - ev.consume(); - }); - } - } - - private static TableColumnHeader scan(TableColumn<?, ?> search, - TableColumnHeader header) { - // firstly test that the parent isn't what we are looking for - if (search.equals(header.getTableColumn())) { - return header; - } - - if (header instanceof NestedTableColumnHeader) { - NestedTableColumnHeader parent = (NestedTableColumnHeader) header; - for (int i = 0; i < parent.getColumnHeaders().size(); i++) { - TableColumnHeader result = scan(search, parent - .getColumnHeaders().get(i)); - if (result != null) { - return result; - } - } - } - - return null; - } - - public ColumnFilter<T,R> getColumnFilter() { - return columnFilter; - } -} diff --git a/src/impl/org/controlsfx/table/FilterValue.java b/src/impl/org/controlsfx/table/FilterValue.java deleted file mode 100644 index fc00c05..0000000 --- a/src/impl/org/controlsfx/table/FilterValue.java +++ /dev/null @@ -1,68 +0,0 @@ -package impl.org.controlsfx.table; - -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; -import javafx.beans.WeakInvalidationListener; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.scene.control.CheckBox; -import javafx.scene.control.Label; -import javafx.scene.layout.HBox; -import javafx.scene.paint.Color; - -import java.util.Optional; - -final class FilterValue<T,R> extends HBox implements Comparable<FilterValue<T,R>> { - - private final R value; - private final BooleanProperty isSelected = new SimpleBooleanProperty(true); - private final BooleanProperty inScope = new SimpleBooleanProperty(true); - private final ColumnFilter<T,R> columnFilter; - private final InvalidationListener scopeListener; - - - FilterValue(R value, ColumnFilter<T,R> columnFilter) { - this.value = value; - this.columnFilter = columnFilter; - - final CheckBox checkBox = new CheckBox(); - final Label label = new Label(); - label.setText(Optional.ofNullable(value).map(Object::toString).orElse(null)); - scopeListener = (Observable v) -> label.textFillProperty().set(getInScopeProperty().get() ? Color.BLACK : Color.LIGHTGRAY); - inScope.addListener(new WeakInvalidationListener(scopeListener)); - checkBox.selectedProperty().bindBidirectional(selectedProperty()); - getChildren().addAll(checkBox,label); - } - - public R getValue() { - return value; - } - - public BooleanProperty selectedProperty() { - return isSelected; - } - public BooleanProperty getInScopeProperty() { - return inScope; - } - - public void refreshScope() { - inScope.setValue(columnFilter.wasLastFiltered() || columnFilter.valueIsVisible(value)); - } - - @Override - public String toString() { - return Optional.ofNullable(value).map(Object::toString).orElse(""); - } - - - @Override - public int compareTo(FilterValue<T,R> other) { - if (value != null && other.value != null) { - if (value instanceof Comparable<?> && other.value instanceof Comparable<?>) { - return ((Comparable<Object>) value).compareTo(((Comparable<Object>) other.value)); - } - } - return Optional.ofNullable(value).map(Object::toString).orElse("") - .compareTo(Optional.ofNullable(other).map(Object::toString).orElse("")); - } -} diff --git a/src/impl/org/controlsfx/table/filter.png b/src/impl/org/controlsfx/table/filter.png deleted file mode 100644 index 1098d3ac27a2c86136b60e2fb5e1b5e49bac6dfe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4700 zcmeAS@N?(olHy`uVBq!ia0y~yU}ykg4mJh`hQoG=rx_R+BuiW)N`mv#O3D+9QW+dm z@{>{(JaZG%Q-e|yQz{EjrrIzt2>$bQaSW-r^+wh^NBVf_H}|0VZb6fFIZPI@WV7Y` zu+seL6$w}2t=pG4D%{qr(r7y2*>&WT|0dbvKev`Ou(3)lC_B&UrE2@-g3={b%cTpd zvYFM3vakE;1ctbL+<eFX{_OMbCM;UPZ@)X{EHm5Zn@`^rJo|h9%$jGv?E(u59D_L) z2srdMIWe$uF^Xug1S}A6XvE}1{f)TX^y$Or{ncEX3eOrGb)EP6Ybon)W<!0)cOTCj z)d~OeSO3}J=)V~P4>q5-Qx@L;w}hoD^6UmR9%uEo%%CF|7OZhz_u6Xp>xgs@;U@tX zn#|TdlzQTlT{OSOe&zqUasPYLzCX4-lHUC6^PR&+^4Zt=a?hSheD^W?q46x6%}4)k z>HT2!=Z5mb-!DwhKfZ1gSN_uUdZ~hAbF%&ce>L&CpUqznxAVWR<~v(9;mg8yIkh7j zHW?fcez`C)>A-_oFL}=PhICzJRLr<*(!n`7OM-2+@}`7CMrXF2yj`%#x5_tp|8+^B zjaGM#7YC+m{^|9b-@KoD{#xljR`u-XwsAARuCkN$>7Q=9ru*B1zV9u$dI5``dwt(^ z<Jh}{X6Mt-mn?by@b9`E_wzsb{ru^;-=>aNO=iR4wO1o{$1dC%duvXEduk$|T)z(s zkNx*|!BJHf*@w>Tt9WAY^W6)9fPDv7_+DQcvnb0qe?irz)?bIKU*CRGz5TbWm(1J~ zKd)7%W__<%I<ZT$)MyjWsfyQOr`9jenqMq@>s{;Dv^z%@+pnlk`}_Gr-M2>#$_!3- z^roDsuK&wk$T0EGr(Y=_`}NPeA7Y$w#++lW?%gGy;x6-Qz27)@V~ldj-h)p}6Q5RX zF8evlrqkD@X`gM<g?FCs#fpU4qo=F6OjdK6tk&d_syk!Fv8umE0u2}c7Mf(3a;f&% zyXH;D@2Rdkof`FBpi$wvjh2?iRVlHHYk2<XKhbM`d_hE#iRHt;NBdu>M9g$N))bt1 zY?iLK5Mz`A(-}9xgbYVp5ypiX8EQ-#v-3aA{xB;fUy<pKo8W`I)Z<3o>ylqi;+PP* z>+-A0I1Q#3TX#L*UHbQvOx*gLCgnRg5@uZZw`XfVgH-S*23^VBtbPu~M}lU3w$f^j zF4}u^>)mJ7|9O=f+>ZAL#ssMCdE=d0<=_2!PS)#pAIq!eowt;DQZ@N^bKS!qnP2SA zX=yB9di~-prgaWI-<Ac0f4g>&EtuEw{*D}{axeB+tuAH_z6<M)bDb5QvRY5X(W;W~ zBcpHacDA<@9;=>lbYBqEH!E?`-1uzu?;by5YV>caT|e}@qhP~=Hs8yBsq=z)?@yL7 z`>owB%YVD|TK{{cgVwgMelEUcKcjxj-PF?g*KDt?vpC>bD(-%sv8ZF>in+i1czbgn zU0>BOSE_X0f@^OX-51>2o-N>?u9viCcORpaj_IwH@{YzP@BABN-hJeKBDCh6^WElM z?4|PaJ3FtpO1|(+ldt+0WBWx-YR@|J8I5sszxQ65nfo>FVAW?`6Xw=(fm_it8t;ke z$G=GZk}^3!tD5gIgWU3p^<l|V^1~&suL#Ysuh~7NyN6k4pG6~I2kWcZVHbiQ>}zO^ zes60pFUc+;A>p9@b&2bo)~t*2?yrhgg}!QY<yTOCm)qpH>)NHY(iQ(z%Gd2!XZ~3u zk5gx2?%vK8k9oUyIrw~j;JbKw{%YwRt_2;tCpN!!d7-<O+0D_CgU#^oK~}$Rmgz;O zEoaY|{I>1$ZKsBb69YeO`FURZLg&Z-70M|~r?Gv@E+}qo`yAot6mMI~&R&{!FXPs? zPTx6tial~$UhZ<xnX5GG+|50GC&Zsv@vC*-c@SvY?{*_XZ<6-Zy$!bA2h%OH#p`|r zSmw-a`F&G8@l9iAq5XvCb{}6qsajxg$%vbMu}8&)6_eh-eErzKE}Y}%&5I|R9FO<O zR$nwZt9|sW(MFx_#3@G$PC4)^EVWUd;UOj?R9dMN8Pe~&LeOW5V$rOUu9zP&!go(i z2>x!gZKm2rpYE;Bl6TLGZHp9Jo17P^>7nMiG^j)=+jRB~)AlPl(x*&=iZ}FF21rbM zIP39-7D3D7g`Le4EoU(=x}Y)F{k7iotLq#TT(lZBm}WAud}3Bnn$s<CNx*$Vv%B2v zitDA3?+n)7Z>;0v=S}+kg<Za;z*I}MKtz*ccg>R%!YMg9J${QGFf^$eYo&jzRoeKp z>ec%FavSnv)4tCU4%n!)sCP}Q`IlX<*`6~+1w4~!(r%pc>u5^g(bG>w&Z}LVz9K$g z*YU_r;v3T9lWy~h=-=2c6Y!|i@S#fqi{H<EOK!ElcC47I%(O2*H@COu$3^!k)emJ{ zGFelCHM6(%6wN;yd*BoA-kBUXx>&xJR&LtrP|oqHR55L>oa8H)1J^v={Zc$Q9#nm> zUXn6bvGG}^4C9uDu9v%Q`_<&%C113zu)EhT*7<&8#$CTR@m!pz*X(`TV!o+v-TLf? z1x*zb7Kg6Bnv<fmARt2B*jU|OFI-Fb(1HyOM=#0T$lJ@o5zg_DHRW}*3&Z>s%ajg? zEOO{zXzpS;^@&+9AxJRAQ%S)`GvR-j0#lB(t3z)W!|cs<icB&&(_I`C*e0AU7CaF4 zY=^IF!<z6dLX3*1r%!SBd--Tq!e74hzZ&Z}_$7E#E^#04m#^P5SJW}rx@p1T&6;}u zYn@(AF}I!YHSv<my3Aa)+S8kN&oo&pTzk(l_kZ0wm(MSfxddd7+kJ{S@bq-Pp40J7 z&CQajbG~yFtSLMbU-7Wj^-0yl-A#>i{TR3EKVH;*A?H=c@*u{CN=@CuF?H-RiIT_v zTv+IwQc_}K#Uh|R_uk*H`PUR@v&;-J*eUPeD6Uk#;5Sc-5v$DW?f2@^WqqHOs0k~w zb0|gIS=RqMB&4BrdFB?@(CL~UFOGlP>o7TV!}Nt;ncJrZXkC6OqSbu)dD`=7PD?gC z66W1g^0N2!i@8!#5(-(;9?uz$7iDBHOns#-t{1aMPgpMVvgn<U1s`S_r~5NZ(_3KI zpvL`mfn}HQn}e$sdCr(`(PlACujl2NGb@GX*2QnX#_ZE{cCXGEXV%~CCSPMCLf(}> z{wW*CBz?KHd;R+9r=NN{m0z^D@?NfpY5oe{m1|S%F3+9t>Eg~7zWH8DjSQ{J>uPs@ z>}wUeF~cEj;UXhbiwTME;#jNO5-0q&XfycfeYeUze0s~mLqTi9)<4`;CRKR&Z?4Q? z(H#GuA@2^Kd2r+GxpT4kt{EGHnWP!d9A4bE?)e3qkPX%nXO<Ygn`m90_bp@l{i~B* z7cLFTWO@?Wc=W1kfoow?T9kcs>RZu*Gk?UY!gNX+?v{OcTYk^g{~=4(mR(jFNzn&h zJZA{7&-yd{eogjX@%L|L3Eh}+Zl3LSmQA@*Um4wBFg1K^V&dDgH~)6YW9`0+D=(*u zRbTC&_l}!k=?ATXhHOpmw;tIojg2O3l>skz?-D<x6sX5_m%qW+n)jx~ik8QwJ-MHk zMklcf>T!5lJzeZBa{bH0I}Z<ui1Z%dEuOHf`tJOBFBpnuS=TqZ@%cLIYt%LfoHi*a zWdHhQuC4j*ee(_9N((A5On9JH#q~C;b?v#W*+E|nX3lf^xWDDh_SI%rTMORH7r4&( zGdu9h>U6J!<XN+=`?Wil^)jDgEvO7vn|r86Os(E<Rh`Q&OOXi=vX%y&3)5EJ<{>=k zw0O*<mV%}Wm!Ds${59cI?(SKvuQS%kI(6+;FAz6iwNY?CanO*}ciTl)^HM+8yVK`s zH}<}~^X5*~%8*&B!n9hwb{^6^@^E+7Z+T6p>iem30qsHdRlk<`&9~fruhZ~NIiJJ5 zn%B8fmP^{bRVprWMA`1x!TkUAQgc21ql^3lH5+?hetBv9+2QZzsYb7uL$lPAUxoW8 z8vD!7o67L?=4AEsXV#WwwdWaCmI{b2T64O5zX~VMw!pMTt=hs%?zgToTJa_bFHV|b z?ECs+h?Vd5CPmeU*9>~|G+)b~5|6%MaELu7S8}dx;pXh5ayJ33R*QhGQB&Lcg%y97 z_E!B0c&W_ASk@LEZ@n`_Z~F4<pH?r4(VU#MRp`W}9j{oDlvlh+-x{@aWss)eAAN(L z-Wy%c?a*lKeR*SJ^7V(j;iqQLu6-?VsV3%%=emZb>b<j*r&{nSFtEKl@+_?|v9wfm z!HOM6d7hZo?#PX)Fgd+c>6J0}5BVhBd5g+ewie}l_@pu;;B<!EH|`7Pcm1ey)Tq7d z*ZGuz!+5#h;^hTK`*(SDNlWt@GMkG{(f|EJ`>By*%2CtW8{cneulVZ_C?3Dx#kRF| zYfV9zpN^)y{nOyhE0_0wpQ$3vxNF&!AJOyvzgoRMmi^TJvghY=lbZDuG|qK*2y<k& zysK|%`E~NyG4qK1ZMAP#T`CWla=<OJ{MDD4iw$n<w3*Rf$b5TUf{b!|?VHv+@2Bty zSo=TlJAbscXu>ph_I5XSH}{(d0~|UvwXX{QZ}9nfqH;!QkmAy_z9GNVex38YnlJmT z>*|qLr);&j7O{1)Of}jX_RI0*Yhm{beI5?Bt?_k*%x~Tb6}1*D^_~8Q`O%vCn8O|K zS01wdxcBEDuGp76wNWay93P)C=uSvUdv+!Cc;ULg@4u}*u`8TqDgT;D**B)o)2c1J zDSjc>{*K>ycfAd}c3Hjq`R_+^f9?EN%$nOSOe*<Rz*QJlu=P}pfVM)@foJCv<$qN^ zP13PEkjMVzPiwbH(T-{7#jjnfN|&5+T6Ip%tCx>!12_ak_mmYqQ>)_IzoW33!8~CX zLu~EknJW?>pPH9c*t~$L>-~}P@4tT>y)C$<+HV8LWRtyrp7uVl_?kDfL1GbGYJu2& zPa%enPZ<8)6MQo@ysosgxY+pj&*%TuuJRq@O4%*1DR1&mXHT|X&{BQ9c?a^Uw}1OM z`{mT??<+d5WjcJ@|M9H(7umhvzR14Fco6rM@ypTsF>!n;WxMMb4|-1cb@7c)(;a^u zrh*-pdLtZHZt<KycgsPq79owp-unADu}J;;RJHKJH7Tc`vu#s%g&&Nw`*`WJx2JPM zg;kT3-TY1bCvru)`}_KOOP5%OiWQ$wExcW&WG~A-Wxlppx2)xKf&Fg|+h3mK{U~B( zKD&H@hYHh%7YlqNxBpOhQdi2LWcPmBh0ndWtyR2af32Bv;N6Rcy4_w6ruiQzOPbpd z#3ZW0cftDw%Tcr69h)C9)HX2`TKiaawnrZi=6up$dTZnTrTa>|iey_E_69Lo9<}^v zC9jb8*K-fYfzpaq_UuvY1tIk!>>bx81;{9HZSJtY-YI$1vWxl4iGTf~M}Hc=KJR#m zaf)ccfzk$v8+Z5VcdHy_tXjijwaT77kn>8Z*y2OUR}1yyOs41`71$y6;8*~=$MWEl zj~Uo}_M}F#?6=+%*>(P9Lg5ysV{Grd7f5m#n3(une{|R0%quMH`nUa?roYjbija3z z`BQEG@gc(rRr#6(ohZHwS6|FnHu2%Zd_mrS8bwV-;$^?zi0&(X(Rf4QfP<RwUcL*Z zYbDg`IVLdpKlEC9srvdo=H-XpX~wTn5?bBqdT86k-)`T&nt%AsewX3=^+m1?aW{{C znNeX}RhoLg_5nx2^+(HHwjF0odLucx{M&<B2j-S><o-OwKJWkW;_3Bo_uTz2eVkP_ z_Z7p*&E2yd3paN}uDkpH^^Pv)FH@K~BKxF_>*_i72X_8uouJ$ieDuc6!*8zW|A~^E z_qBUUe>L}oH-{&m>Xw#1eZ22~P2K+g;nzKK{&M7MHJ*IN(7_XbcW?92mu3I5PnjfH z$8|ns*dgsP=S`zR8RtT$PIkY?no1RGc_#NviPxIGVryfcx(&ypcXO?${A!f;vHgAL zN{#jZPz8riB@HY;k9|y;SRG&Q8x|J!f_+}XBk={5-(IHA+k5lhf1jh%5+1!}&tRVL z=;-$93DOy}{B%w)F_QnvyyV^P^8HHN^Y1Ese^=XkrE_=v<_fk8#^>#}U+Mk-Ld~DE zN0<G?x~HEv_x{xu;ZnH#ep2-If8L*d+U(^&;w1K|Rb9QlYV+;?+I?Y@ul3pg&#(V) zu_@zjpTvjf_J0-U`uW@bIiY-{%}(qZ_lhgJhg+1h&;R>za{ig`i{xLdmY3eUe)W5c znjZxw93M`q&!1Gi`sa<V#{D%jYEPM*E&Szfs{8w}vi+-{g8KLC9@KTQ_}A>%Hu>Q$ z->LaiME!K83(m>ke4``&p2E-X{qD^ST)*T+m^4@dKw~RdMpK~UERK&J{%7K0&@_%$ VS<r47!@$76;OXk;vd$@?2>|nT?{xqG diff --git a/src/impl/org/controlsfx/table/no_filter.png b/src/impl/org/controlsfx/table/no_filter.png deleted file mode 100644 index 8861914d3125d46120d870d15c94385224f37fae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7021 zcmeAS@N?(olHy`uVBq!ia0y~yU}ykg4mJh`hQoG=rx_R+*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>l<H3=9nHC7!;n><^gv7=)BARQG;kV37Ld>EaktaqDeu^#qxt zGoR}luU<9Z`10b3Zig9|6pIf;a(LRb^va5De9a)ax#xPEa7F&%#TGwvt_f)0zqRjk zw!g&s_#18>v*b7*PZl|LZ^QL_vTHxeZA+DC40q$X!^^g11Cx%T!zG)lUC%GZhW^}T zziQX6>MNI(7glD5?C<DVv&KEGv_8J>{`C9PXR@|%2r9XB2q-#XFrFEo2nn5XXTx7J z25nB`KePU>;#{lKZef~Xs~29U#<-yT%kTMjjMXI+cGhJxH|QNYv$ZGC;4p(COG{vY zlY{2hQ&XCR8U%t)X)<!2n^<_Afhp+ezE8gcf6A;~v-sBE79j`bsO${;@F?fs|F@RM zIfvTnJw3HQY}I0~xu)-~O9gy5?d81i%Dih0L8taF`?IO#np6;%$4bVBWy~4UcPq=^ z`MgM<W5{i|xm#e9*(8sqKqh4&*2OGmHtpGzSdrR%Z~;T|8ExZNs$K^)S|83|Jmo-w zNRQzA%2$RH!<QNS*%R?C=%u6=r-ZUW#>%`?e_q!~UuX#73d;0Yx$sZ&(vp`o0oNvM zD)Gx=RXzP~s#H+*ca5ilabCQEVe=>b+wAr8dtdhEJ^vo;ol@`Xpyg2XZf<$5$I^$- zj$g~_)nhO}H;cvN&(-og<%ucN69fL7-L?ASEUyNGXJ5^{PJh}I=lfzuT>s>%`j_`k z6+iv%_eEwQgKK5or@c@2#{O*mxHrPFIw<`0gNVgZ=hwfvdTY9x*YEQzmzH`-M=?KM z;+$G5bt>Ot0!Pq;vpI6na)0*=1UZWr<tE$zc{A_kBnEBHWQL^-rVLJw8q6GwiD$%j zu2HFCeiSPBbjz)upR%92tXU-V;z*BUrsZRS_^nk(7N@c(rnV@gwm950<m52j7vpJ> z;Sd~qEJe;Z@NMVs2N9LIqU)#2J7)_lUAWM(qbY2jt-}n?Bsa&EO_M%OW%zbx9@mG7 z_r4oxs2VIT^k<0{^f#HEHj_)Ck;~xNY6iEaB2U&SA<m|v2?0@GXI|R6sfbrp;rMEX z%1st};ul4g_WH0+=`IOeZ5JBE7}U2uK5Wl)p}Lv7CwMvk&`Mb4^TRlu;gMve!WrT1 zS3VS_{n{D7Y>Ss)c8vAaKVRlIe*0(5wEj5j@elo_Hw{fX))n4;zg6`6i<7S|?_;^F zu;tX>gVllpZVnx7`dSQG71w7n3b1Z4R#xOa9{t>`=Yzh*?ijNcpQYc`rZ6mIu_*4J z+H_6if>4xThUx;&#%VH9!Wmrp>Srz&vBddxx9M4Kj#(I@uQ-n}R#$!L?|_mG8gG}M z?E4#&ow4?mj9LEs9bX<T{p`9rUYnIAS1Uu+_H{hh`#oPyMRA?io1ip>;rY7V72i}H z)=v{skcuj35XyMx;LXI!>%=)lXx>*{Ns+HHM_PnD4l=kgcrkc6N__mw$&w&4OE6>q z8p+lqmad=-uLT;Mr;a8r(31WZ=%$c)a`uToMzZESA)@!pLwIg$?QNQRc>5)T4KHM` z1emrpzEaVTKY4n^srHuC<6ad)4nJ+<3g3OLx&Cnp+xCS^+R8rf-K@q~!ymGJiq)H5 zW1jos7i!hw4y@eBsFH82xNC0U-bsdB4=og~d}gScTiui(plW(|SL65fXXZxl@mpOf z;?Jd%=#;M%@NDO5jw2!b_j<m6n)`-rouJI8yC)8oioBh6i*fM-3l6r*Z_OeyL0J)- zF1$XJF}qax1K(r**;}t^$A|MuJP-^x_U9oNYsdV>Pgb)l&f9!goyXx+&0lr({(>z% zi5Ufbmz0tN1EPFbrfk|Y=hwj{N$38onAH??>3p~6G}+Y-Hsb$l^uM1I|NBMt@rE+3 zUGq)7HnRKozIK?O{eo++oJ3DUx&~7~P?BQthL&exLQZD&@)7pg2N!&Oef@uLqQq?X z<6H*5mmh0feyn+nXaDn!4HM!DRz&EjFA=}`nd20b)5fH8Gu$1H9hkv*IKg1X!=2M5 znT>g7w7r~b&Lgpm^Rhw0EHxf`b6@UdnFluMXe>RjlY2UM!FAT>GBF$l)0?^ZG+8Xf z1rB)!ad9XrE@==Ea`Mv9w3(~7<h|Uq39f9DxK^Fea82Wq@L>00iSJ@~{D|Y}L1j=G z^YZDT&A(b7c&I&^5R~`lAb;J5138`zQ>Ji99oSWBzIfwC!6}m*m_%GRT|d3|hux_o zMXB%C?~&`skJ5Wr>*=uaxW&IxFAa^wqSt5Yvw9S~@#eVC5wgm|;;D4prS~7@1WO~| z>whbG+MOcWkru1A?fBOpi+<?yYy5nwbTDuVN8S1Bsmp3J?K<MWNjhfsE?lVi=d^wu zqoydslC)sflE`U0S3a<?+vu${|6-QbgA}zDI@5(`vutw?SjS;F*(+^D0HeC_+@NRu z0$qz4xRg{yzRqaScx24LS!K9T#6?qJ>4KG?7MHVxWahgpnkv3_w$GpGtu3crt9_gL z#sBWx>o<kRsy|bzKxTRNwGak|JC)Dp_KW9K=N397MopVO`<aDkz$`_UN3N{?L5y|_ zSFK`Lyn?GstD(^-{t3I*fri9iO7;SO(-tu4oaPB>c)hE@lD#~3$G#W(s~8SewsLV? zX_(T;^&#!qiB(z)?yOs}l*vnJ|Cx#})m0y(0>5y_e<?m!dnohBqKWU$ojYedOQ7gj zpTg2BYNxONms(+PFJr-L?@p0or*j4uC%>9^&gDeNp3hG*AAPG;zSVCRwTyA;m1U9r ztZ!~?OqN$%qAl0o*8Ex0$wrP<aY^>^KH1;TTntW>-YxSwk=T53Q{v?*6<W>*!UgwP z8S-#>y-d7bdi%MLNx}1Tb1fNiH)g10|EOyaxGb>KSR(0ShM2?b|MSoDvN1H|-ri=b z-f}~tcgBUNDz-^e>R5bQuUOx$lb2{zU2G(@QK99=j@;YZo-bQ9SF@Kb@BY48bH$Wm zB{An6JSndn7*vD|1DwqA@9(Sq9&*k0>B9%V-|zo#?9`Fh99VG9mVXw9>cPyORSTwY zwauSXEYah{b+PvU-|zKlt8UL;_md%aTB@8LAHVaSS{EJRX{l+9TYTOBUOvR|vcxJ} zL*&*1(J3Mi?&wZtQLQiU$g;Y>d9KCtfS@La!`t3&eOY2ve$AlaJj;2;jQ-<`=Iu5= zlBqnigVAC4|M*91k{IT5mRa|0?iP6KddGs_!sf^k+xf+O%}jld-*_#*ynFfPznSxe zZ(O{%abDmp>E4!a2UaS{^)?t@yM6KE#=2d%XHE26__L;N?IfeuN3V7toEjh$viaBE z$ZJ}&&p*F@&gHl9A%=a|vvQ9ZHETvH`mrq**_gpH!^!{toCF4j8=F#37ti_J+mg|- zNLRt-0`s|_ANRdJl)y6Qb8qyvoSWvs?+q8fX0o!jmS52FX49Dh*IN}wk^}?1%1g`2 z><lKqJ!hesbNe1g!cxvPPojPoGk6*_cLbTeuikf!%c&rPcgMQ!j#MYEi`uO>EH1w{ zeyrVG)9yC=V20Tic81Fd8+??x7v%1mV_V$CSfgeUq#<%E=J>a?=ezdkR9V>DwjRA7 zdgbT3$4&)&YgKY?=Xo!`?4I^`Z(43{g4Nu6?i@EyoD0-+;BYiaY82R{IoI#~?6u!# zTs^w*Wyvqb+j=FIW%p(;dAVz!ihyXh`ZMSA`hH5fRll}ODu`XKJ=gEP@$C2J;$iID zg%^lhl(#jtZNIQo+~If5{?luW9o*gB_2!@7ZoO^pR_<;0om=*=`t~Nh>rzF0m0ZBV zg;UQw`~34;UtixH%kvBj8;YNwd(N;WTlLx3C4ydi?w(@U@_WCeBJ&SW*vg&zskVDU z`)ezKCTEViYgJsUD}PN95^&17wJG)VJj=sVieLJ_e)DDzdsMk+{nyhqOrOP0m6Vs2 z-7}tkFZ<ljl-%2S>=&{no*fNSVLHa6vGf2>e&@}Y`K599K6iUxSRfj6-LfZh)-}_7 zl?Hp0GmIIJ@0>hke1{?P+@F(E&dgf=eoZpNe9n2=B3#n#M$H;GSS|WwUtHRmB`hM| zBzFIDp^QZz^X+qs12l5xoXd>;+{aj>c7r#eI5FqVno<ryUB`yAmu=T(#~C%8XPGZ4 zE&WzbMuwy6O36{4DM1tbZ5rG3YXw`y<87WkKlS_zrzUfMnxZ||?QOd+zbrYs^Ur;j zbv7I}o8*7|u~H~JC*2r&;aKeU>v~W0{Zw8rTR%1a57YZU@5(Pc*|p=z%H<pW7td$E zS9|#ODlcu$4BMA6|Joa+^O*i^oVfAxjw#z~_#+NB?*7JfQ&M{FnbKF^zkIPcJzf8O zSWsP;A=~LLhiu-%1`JFRZGk(LIaY7mACStG_VAaqb;sK1!pdFDrJXEaLc<TrNH~1H z%wC`~wP{C1=GC=HUC}2w?q|QW;%gB((cgQpG^eMxH}?O7W_~}3hqwJseBI9QKOkR1 z{K2hk$7I7R=|<Z3+)so?H_T_AA;|q>%?-^hFEr2ar8ey?TE^tWv7-9@QPJIHN<zI( z@zuIt7P%g%zTe$)En;)B^@jTYnJbtb3dCm|x%@r8@&6yiwe^wt65<nIuW!%GYTEZD z=tAo0f_>Ls$0?@hGZ;@{NVO<<aG-c~`1*Y}p1wO3p~H6AV8OyfDK-ZW1x~+ErYFCD zEAIPds`LB!{3cVAhPwsK3A5xxC7CmGTfbh5&Zte2kBhA0Eb;bkWzp#K=qmGE7~qhY zBhvTy&8rtLW?Z=Wxx8h~ulX%+{3FAdBe!y;9Avtmq@r;4Y(Oj1tD>E%^`0lX>Q$di zk37IDdEmJ5d7I7YXJ?t_I(1EJYZK8}y1_?y%B9Om4NeOgzOM9tI4S-=*OslKUtX== zE4!}ilB?zclZCTqC8QcfT>5KqFC(j|`l2f%vj}hCLDntTB&4MqgEp1FzP9$YTGfB~ zz+e0Nv;LmvUAB`UJdSfy#m4K?t~vUhv*y25IN?m1e!P2TH}{*r^$hmQLl0Q^KfHD3 zK|)!=0{LyZhd-`;cljg#lX*2v;&1<(zql5b@Uv*eBKGt5mw0BreS2}XkJI|7)(EA> z@9*xl?%G@3T-H@sd%V!V%BtzljfiW7bG8ciWoXoXk6J3{C*{T+w!STHkHo4o>jk%* zwJf-qn&3VCQPR?D_nB&*%-PPks)Fk}AK#b5rE|82vhOe8RAI0+VzTgCDc<KF#I#Xj zLmKa+w#M%^f1D%suiwJCWJ<vsrmV_ecAPOk(+~V#Y2L$q!t^==FK^u4tGB*PmXd4Z zeo*?LU<H$(oaCH{ty!UE7Sng{+_+IN>UF~Mpv&Q$!kzWUBwo#$^`S_ok9Ge~(-R*I zHY7A|5B}-GqR6sqDeJKV40`V>rP#$y64w~APA~rQeSX7(nq;fF|2(&r|E+dfw|n-+ z`%8J0JGIxd_%6*7k_&R$_kqc!et%Wt#%j61R}bxd9+!Eizm<72Z{9rS@c7!VM}xYi zt~}=Eq8u3Dl^B)g`$)X^z>h9bi&<-&AALOT(B9S%!ewxF)80Q?!ihW)8yMWoy1lFC z9h3fO(Pw_;@W!{XFH3%LhaUgg_EEi_?a!Kf22zDbMHRZmDp#d8?QIc#K7pOz>D$+b zsfT~ut6s9_IsauF8JpGW5B1~s?TO|n+?;z`cV&q3lpq6L;TC}z%Pd#QH|+g9w_@== zM&Ii1PU%Jpyu1q2OgDOM&{?pOvm}E<T-K&zyUg>oi+g*wfBW`r-jeQZM&IUrXSQFL z{KjTi601jYa_&ZbmM7l&j_F1g4llRoP5I<K!|ic?oPk4r{`%s(rPpn<#JS#{Oi`NU zp(6M(?AkmbW{tIpv4yPv_U@E?Zu@P<ahBd*hUBZAOQw7;?0%Le!OXnl&DZO%&pe-B z|2N&sHuzuMe73N)<~_$>b3{6<-y@_lbIy#Fe^lbDII{`_?oO%8T|Ongl5@tyshiXP z8qJwEZ{D3xPfyR+65)EgF+%2KiqHkAX{oG-51+JYyjUL7<$U&RMpcr$huY(n%>VbT zdNfNQ;i1!n7(Q{1!qcWx=Ka_ibe`$JcFo%FY?o^m^-Yl2`Nn9%uV1&SIlVdmeL5}h z_wO&(%YW|a&Z+;oRC11@wf?oluiw7OMQ%>>ElWxH@$B>Y{S0l13PK-M4z4t4n8J0< zdfLOY%hay?|MxxN?_Y(|(s?K5uXt|6W@6I7!~fXnoc)iw(?aG!vwkrs+OJ}kI<a(m zlbM;{9~%Z;mLm(DCp0%#9Nn~SP3c|zb1gUKm-9TR=Hg!yv$JSv$fr*s$;wI-Pqb`v zFl7tyYK+^&<1Vi6c6qXY0}mflCrd)4us74;4@-`o;F$I4=XX8DC(MOj;+IbAf3Nz- z!nX99)G76Sa*_ubkL@d*{JM^_!T9q3+k2uqE8lLtZl`K-|Hhp?5+_rNoT3wy*aCtY z<4OeoJzk`mQTfTUpYzo#wJ>(CO1(SF)C6v)u`M<H)mPqdB+0aM{noaMr=lw!CfazO zu$6!KM|+0iT>JHs3zjceFTY!QJyvIF%*{)en4CNkxDC?g2r+9cP1riGKYY55WAgdS z2ETsUlqN_BOBXVD1Pi}d<a)1QW822%OIs?whJJ|g`@1{!Zu#uj|Mbs1+IH&m$K8#y zjb|P-UZ=A0S=F9`>vvDMEiT}fZIY1F+u5^PRZ%N;_v6XeCamNB_iA;4yIX;V)ZcTy z+ibIK>*Kr_7%E<^T<*6fZtt$Yd!~I33R7wFP<hnPb|!cl!##I-l?%7J!o~I7K5ssM zNJ6Hi&n4>?i>dH)fp&i9U3z>5-=5yi`MugW_rqLmAqIvjcQ^OtOO%R_hW?n&JO4mO zYG&aRjwdHNzW=;-*~5!thkIXxHD4Wj&A;8-{+6D((9&N#iLpgs@8ZRagE#3fY-`(? z!dbTeb?okT-o^KAi<TtiFZP^#t)O47HCp3?xbExK^-nGCzn$qkKZs+$Y)#h*z1UyZ z7?RJk?TR}U?Cs@f$tQDJrZV*Pa>L`(9M5~RZOF}kE_l4KiQj2n*?InbKc3dEem~7! z{%?2K?R}j~f*K7Yrs!>*B*e62r=-|(?mU&0=i$1q{hiq?PS42vdG3Gj>3-SWQ;s}l z>Fs6w=<mwvp}Ejkc*#=Mi%yAw(I&rU>l<v-OKHeF_QU_czPY6=t^4eB?*3w!CTGPW z+S_Di%KGp3W#1zvdlfFd(0JEz{C{b+&A-BgZ{-*HR1dI7*j9<?zRZpI^Qim6NtKM` z#r7#v{-r<gH}>R=5IeERb-}h?)2R195}gkpo4~kCP}q0R44&rtKgxQ4-qmJQ{j0pN z%SvG)M~B74jp94%YVSL3RcUQ7;+e2a%|KK6wCwYJ?XO<H=afv~Q!M_VFzxPU&Xd>U zKF1umxWfI8(nNKSniQ72dV80J0iW%3RZSRXc{O^RyvFgdod4?ed|t@}sjB*|kE2f5 ze&&hV|FLw&@xI0@R~uaxFITx$smDI?{A;FU%Xz0AdwPA>X)#P_V=FjU$ostf@0NuR zf19fdot(g!#>w1o-*=_<zSEZ<h3lWYD@~66<<!8>>nPlG_~aA*|GH9pZ6|wt(YW0v zA;}qX*yVgS!;*b+PMSKpB4&3|XIVdTFiL5VJT}|@zoc00@92(s7K}$82edtW`8tYE zPVvCzNCh!x{^a`=4WIq%%qIW5>c8aAgM}4;481shd?@hUz0g9p_sC<0r5SS4zi*tM zJxh*JfKxJ|?ZdHtIk(f>);g#$A4v*mnPO8Rtg31I=-A^Iicjimic+3*`}g$TWcYC5 zM#TNMJMZ}FyDhd?>#3ZSFlpD6AO{sDUyfNtJHOlBy7R|`d6pB~jHKuVGV5MHy0LEV ziu>Dmvr0rfR2FE?y|P}vwLwC%QM$W#uSoab@7C?@`(u|@eT;8wyS9ItPoC&9&7UVc zF5FfRVUJ?IsG*|hk!qw}x3l2k;`-Shf0j>RT*j%sEw}aK0p<nUcx8K?goC1=XY;<a zxUj9)skZiCg3`zP*S>$hAHSIM`?to%{k9_g^%JjOb$t4H!a8e3;S)xl3YxC5X4PkZ zFTOax?$D-b?K}oYE1nk5XRUsr*#D#L;n|C`dw#6r)@5mX{kr`dQ~jrv`}WDtcM9H9 zTkv6@`qW<&=6Y$q-8Es(^)U9Js^AM8j!79WR#{6)f3KTz>8c{Lk6_&W&FsgN`yH(L zwxm|dr_WC@YJVgX#nEG8^5^4rue(3K#=Kj3`Jz+2oaD=2Yp1-|H!<PS`rkZZ@>b4c z3nZHhA02tLKW@*D>ob<UO+IJIw!v7^<9MUel4k<C0%zB4x7q*x&*%QXTt6;sFW$L* z>+S3JpBMGZ8uaw{EDie4xc}bCTWotenWMb2n0OVLeHf$i_lkb=HE(oP5?B{~JM!@^ zg^L<-kz1wu?-m^Pe|J9RT*m6{`d`17zh}0qS+nn7xrxw6yLq9jYtJbLY06Cb#4S^y zozkG`Q1sAAXZL&S6Kj4m^tdp2b*#F)cj^=eo4)J!wu`Cf{Z)u4{yZh;&X==3&szTm z)&1C7@n?R9NtC3!#P&Rgr9m%P&1$L&J{-KjHp9tfvS&=y`@JXbR%v^fR9)&ySSk{t z)Am??2kW2n_B>L(ewn{#7w_Ds+uST~zb)aQea7jatGBLywD^}18UOY~T6wb6@(E}E zXDF<4XI9=Q5oQ0q(qj94KH2WdU-#5o)~rANAihTAnXG(s;;esD{;gbkaPxr|vibXd ze%$x$*;}KTAzrU9nF}Qu@|c*^)H}!DH;<qF?BwF-ThtBa`7C<5Zui5SA1oEg%1U3q z7KrJ&yjySI`(l25g<4!={hJpT{r883Zx37&wBgk&1u5ymCF|bZ+ubjFn`42&UHybJ z_wU8qIQVi(^}20*kzC(-X7{?|6YXvKk8Dcy*s|@=wz;Qv)?VIW|8ef|zNPywUHGuZ z^~7%X#{2)C9qD}jJ3Zr8#Scz@hBGD;ccn-QiR&~zwh}P@zn7^pUvInofqygeD&)Ky zjGFykdX@`XzvPym!@l#&{xUmx!M0|9#>L5t87^4M*WcbVjp3*Q_fiq30s*FicTSqJ zZ$3YN`|j++8)g>b8@O3H6ccWnwTMW_$Q*ca;>5$Zx3|CNR6StHwmaZJ=i}oH36E?3 z_I?gy5-I=uY@cIzjH=5YiH66!9?V%BpwUp=Sfj{)(DK-)${rs6$3HeEOUTGH2rT-0 zkX`<cu+agV;|}%qzkdHRFfd@aUdqR<xQj7o)z+ugCm4z)`W~~~e;4T0B*1mq<iRez zE!RK}`1n};!!zmp1^f5&2c3#zh~1W3es*fVRU6NTZx>CcoXingbZPpevuTBoeiZKc zcq}l*NRr`2kXI?=i+69{*fbRjeExR(t+ZLr4arWITlzabIPK``&e7xE9bmC$$}6@D zTa%CX*>V`xOCCsXy3KPqf|H?T!n$+k&OLXU)Q)pP>744H`i&>bo?Q3dUd6z`z~JfX K=d#Wzp$Py}@+!ap diff --git a/src/impl/org/controlsfx/table/tablefilter.css b/src/impl/org/controlsfx/table/tablefilter.css deleted file mode 100644 index 96e4c32..0000000 --- a/src/impl/org/controlsfx/table/tablefilter.css +++ /dev/null @@ -1,7 +0,0 @@ -.column-filter .custom-menu-item:focused { - -fx-background-color: transparent; -} - -.filter-panel { - -fx-spacing: 10px -} \ No newline at end of file diff --git a/src/impl/org/controlsfx/tools/MathTools.java b/src/impl/org/controlsfx/tools/MathTools.java deleted file mode 100644 index 6284bf6..0000000 --- a/src/impl/org/controlsfx/tools/MathTools.java +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.tools; - -import java.util.Objects; - -/** - * Contains methods {@link Math} might also contain but doesn't. - */ -public class MathTools { - - /** - * Checks whether the specified value lies in the closed interval defined by the specified bounds. - * - * @param lowerBound - * the interval's lower bound; included in the interval - * @param value - * the value which will be checked - * @param upperBound - * the interval's upper bound; included in the interval - * @return {@code true} if {@code lowerBound} <= {@code value} <= {@code upperBound} <br> - * {@code false} otherwise - */ - public static boolean isInInterval(double lowerBound, double value, double upperBound) { - return lowerBound <= value && value <= upperBound; - } - - /** - * Checks whether the specified value lies in the closed interval defined by the specified bounds. If it does, it is - * returned; otherwise the bound closer to the value will be returned. - * - * @param lowerBound - * the interval's lower bound; included in the interval - * @param value - * the value which will be checked - * @param upperBound - * the interval's upper bound; included in the interval - * @return {@code value} if {@code lowerBound} <= {@code value} <= {@code upperBound} <br> - * {@code lowerBound} if {@code value} < {@code lowerBound} <br> - * {@code upperBound} if {@code upperBound} < {@code value} - */ - public static double inInterval(double lowerBound, double value, double upperBound) { - if (value < lowerBound) - return lowerBound; - if (upperBound < value) - return upperBound; - return value; - } - - /** - * Returns the smallest value in the specified array according to {@link Math#min(double, double)}. - * - * @param values - * a non-null, non-empty array of double values - * @return a value from the array which is smaller then or equal to any other value from the array - * @throws NullPointerException - * if the values array is {@code null} - * @throws IllegalArgumentException - * if the values array is empty (i.e. has {@code length} 0) - */ - public static double min(double... values) { - Objects.requireNonNull(values, "The specified value array must not be null."); //$NON-NLS-1$ - if (values.length == 0) - throw new IllegalArgumentException("The specified value array must contain at least one element."); //$NON-NLS-1$ - - double min = Double.MAX_VALUE; - for (double value : values) - min = Math.min(value, min); - return min; - } - -} diff --git a/src/impl/org/controlsfx/tools/PrefixSelectionCustomizer.java b/src/impl/org/controlsfx/tools/PrefixSelectionCustomizer.java deleted file mode 100644 index c03367c..0000000 --- a/src/impl/org/controlsfx/tools/PrefixSelectionCustomizer.java +++ /dev/null @@ -1,221 +0,0 @@ -/** - * Copyright (c) 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.tools; - -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; - -import org.controlsfx.control.PrefixSelectionChoiceBox; -import org.controlsfx.control.PrefixSelectionComboBox; - -import javafx.collections.ObservableList; -import javafx.event.EventHandler; -import javafx.scene.control.ChoiceBox; -import javafx.scene.control.ComboBox; -import javafx.scene.control.Control; -import javafx.scene.input.KeyCode; -import javafx.scene.input.KeyEvent; -import javafx.util.StringConverter; - -/** - * <p>This utility class can be used to customize a {@link ChoiceBox} or - * {@link ComboBox} and enable the "prefix selection" feature. This will enable - * the user to type letters or digits on the keyboard while the {@link ChoiceBox} - * or {@link ComboBox} has the focus. The {@link ChoiceBox} or {@link ComboBox} - * will attempt to select the first item it can find with a matching prefix ignoring - * case. - * - * <p>This feature is available natively on the Windows combo box control, so many - * users have asked for it. There is a feature request to include this feature - * into JavaFX (<a href="https://javafx-jira.kenai.com/browse/RT-18064">Issue RT-18064</a>). - * The class is published as part of ContorlsFX to allow testing and feedback. - * - * <h3>Example</h3> - * - * <p>Let's look at an example to clarify this. The combo box offers the items - * ["Aaaaa", "Abbbb", "Abccc", "Abcdd", "Abcde"]. The user now types "abc" in - * quick succession (and then stops typing). The combo box will select a new entry - * on every key pressed. The first entry it will select is "Aaaaa" since it is the - * first entry that starts with an "a" (case ignored). It will then select "Abbbb", - * since this is the first entry that started with "ab" and will finally settle for - * "Abccc". - * - * <ul><table> - * <tr><th>Keys typed</th><th>Element selected</th></tr> - * <tr><td>a</td><td>Aaaaa<td></tr> - * <tr><td>aaa</td><td>Aaaaa<td></tr> - * <tr><td>ab</td><td>Abbbb<td></tr> - * <tr><td>abc</td><td>Abccc<td></tr> - * <tr><td>xyz</td><td>-<td></tr> - * </table></ul> - * - * <h3>Usage</h3> - * - * <p>A common use case is to customize a {@link ChoiceBox} or {@link ComboBox} - * that has been loaded as part of an FXML. In this case you can use the utility - * methods {@link #customize(ChoiceBox)} or {@link #customize(ComboBox)}. This - * will install a {@link EventHandler} that monitors the {@link KeyEvent} - * events. - * - * <p>If you are coding, you can also use the preconfigured classes - * {@link PrefixSelectionChoiceBox} and {@link PrefixSelectionComboBox} as a - * substitute for {@link ChoiceBox} and {@link ComboBox}. - * - * @see PrefixSelectionChoiceBox - * @see PrefixSelectionComboBox - */ -public class PrefixSelectionCustomizer { - private static final String SELECTION_PREFIX_STRING = "selectionPrefixString"; - private static final Object SELECTION_PREFIX_TASK = "selectionPrefixTask"; - - private static EventHandler<KeyEvent> handler = new EventHandler<KeyEvent>() { - private ScheduledExecutorService executorService = null; - - @Override - public void handle(KeyEvent event) { - keyPressed(event); - } - - private <T> void keyPressed(KeyEvent event) { - KeyCode code = event.getCode(); - if (code.isLetterKey() || code.isDigitKey() || code == KeyCode.SPACE) { - String letter = code.impl_getChar(); - if (event.getSource() instanceof ComboBox) { - ComboBox<T> comboBox = (ComboBox<T>) event.getSource(); - T item = getEntryWithKey(letter, comboBox.getConverter(), comboBox.getItems(), comboBox); - if (item != null) { - comboBox.setValue(item); - } - } else if (event.getSource() instanceof ChoiceBox) { - ChoiceBox<T> choiceBox = (ChoiceBox<T>) event.getSource(); - T item = getEntryWithKey(letter, choiceBox.getConverter(), choiceBox.getItems(), choiceBox); - if (item != null) { - choiceBox.setValue(item); - } - } - } - } - - private <T> T getEntryWithKey(String letter, StringConverter<T> converter, ObservableList<T> items, Control control) { - T result = null; - - // The converter is null by default for the ChoiceBox. The ComboBox has a default converter - if (converter == null) { - converter = new StringConverter<T>() { - @Override - public String toString(T t) { - return t == null ? null : t.toString(); - } - - @Override - public T fromString(String string) { - return null; - } - }; - } - - String selectionPrefixString = (String) control.getProperties().get(SELECTION_PREFIX_STRING); - if (selectionPrefixString == null) { - selectionPrefixString = letter.toUpperCase(); - } else { - selectionPrefixString += letter.toUpperCase(); - } - control.getProperties().put(SELECTION_PREFIX_STRING, selectionPrefixString); - - for (T item : items) { - String string = converter.toString(item); - if (string != null && string.toUpperCase().startsWith(selectionPrefixString)) { - result = item; - break; - } - } - - ScheduledFuture<?> task = (ScheduledFuture<?>) control.getProperties().get(SELECTION_PREFIX_TASK); - if (task != null) { - task.cancel(false); - } - task = getExecutorService().schedule( - () -> control.getProperties().put(SELECTION_PREFIX_STRING, ""), 500, TimeUnit.MILLISECONDS); - control.getProperties().put(SELECTION_PREFIX_TASK, task); - - return result; - } - - private ScheduledExecutorService getExecutorService() { - if (executorService == null) { - executorService = Executors.newScheduledThreadPool(1, - runnabble -> { - Thread result = new Thread(runnabble); - result.setDaemon(true); - return result; - }); - } - return executorService; - } - - }; - - /** - * This will install an {@link EventHandler} that monitors the - * {@link KeyEvent} events to enable the "prefix selection" feature. - * The {@link EventHandler} will only be installed if the {@link ComboBox} - * is <b>not</b> editable. - * - * @param comboBox - * The {@link ComboBox} that should be customized - * - * @see PrefixSelectionCustomizer - */ - public static void customize(ComboBox<?> comboBox) { - if (!comboBox.isEditable()) { - comboBox.addEventHandler(KeyEvent.KEY_PRESSED, handler); - } - comboBox.editableProperty().addListener((o, oV, nV) -> { - if (!nV) { - comboBox.addEventHandler(KeyEvent.KEY_PRESSED, handler); - } else { - comboBox.removeEventHandler(KeyEvent.KEY_PRESSED, handler); - } - }); - } - - /** - * This will install an {@link EventHandler} that monitors the - * {@link KeyEvent} events to enable the "prefix selection" feature. - * - * @param choiceBox - * The {@link ChoiceBox} that should be customized - * - * @see PrefixSelectionCustomizer - */ - public static void customize(ChoiceBox<?> choiceBox) { - choiceBox.addEventHandler(KeyEvent.KEY_PRESSED, handler); - } - -} diff --git a/src/impl/org/controlsfx/tools/rectangle/CoordinatePosition.java b/src/impl/org/controlsfx/tools/rectangle/CoordinatePosition.java deleted file mode 100644 index e015701..0000000 --- a/src/impl/org/controlsfx/tools/rectangle/CoordinatePosition.java +++ /dev/null @@ -1,84 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.tools.rectangle; - -/** - * Enumerates all possible positions coordinates can have relative to a rectangle. - */ -public enum CoordinatePosition { - - /** - * The coordinates are inside the rectangle. - */ - IN_RECTANGLE, - - /** - * The coordinates are outside of the rectangle. - */ - OUT_OF_RECTANGLE, - - /** - * The coordinates are close to the northern edge of the rectangle. - */ - NORTH_EDGE, - - /** - * The coordinates are close to the northern and the eastern edge of the rectangle. - */ - NORTHEAST_EDGE, - - /** - * The coordinates are close to the eastern edge of the rectangle. - */ - EAST_EDGE, - - /** - * The coordinates are close to the southern and eastern edge of the rectangle. - */ - SOUTHEAST_EDGE, - - /** - * The coordinates are close to the southern edge of the rectangle. - */ - SOUTH_EDGE, - - /** - * The coordinates are close to the southern and western edge of the rectangle. - */ - SOUTHWEST_EDGE, - - /** - * The coordinates are close to the western edge of the rectangle. - */ - WEST_EDGE, - - /** - * The coordinates are close to the northern and the western edge of the rectangle. - */ - NORTHWEST_EDGE, - -} diff --git a/src/impl/org/controlsfx/tools/rectangle/CoordinatePositions.java b/src/impl/org/controlsfx/tools/rectangle/CoordinatePositions.java deleted file mode 100644 index 13ec009..0000000 --- a/src/impl/org/controlsfx/tools/rectangle/CoordinatePositions.java +++ /dev/null @@ -1,222 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.tools.rectangle; - -import java.util.EnumSet; - -import javafx.geometry.Point2D; -import javafx.geometry.Rectangle2D; - -/** - * Computes coordinate positions relative to a rectangle. - */ -public class CoordinatePositions { - - /** - * Returns all positions the specified point has regarding the specified rectangle and its edges (using the - * specified tolerance). - * - * @param rectangle - * the rectangle relative to which the point will be checked - * @param point - * the checked point - * @param edgeTolerance - * the tolerance in pixels used to determine whether the coordinates are on some edge - * @return a set of those positions the coordinates have regarding the specified rectangle - */ - public static EnumSet<CoordinatePosition> onRectangleAndEdges( - Rectangle2D rectangle, Point2D point, double edgeTolerance) { - - EnumSet<CoordinatePosition> positions = EnumSet.noneOf(CoordinatePosition.class); - positions.add(inRectangle(rectangle, point)); - positions.add(onEdges(rectangle, point, edgeTolerance)); - return positions; - } - - /* - * RECTANGLE - */ - - /** - * Returns the position the specified coordinates have regarding the specified rectangle. Edges are not checked. - * - * @param rectangle - * the rectangle relative to which the point will be checked - * @param point - * the checked point - * @return depending on the point either {@link CoordinatePosition#IN_RECTANGLE IN_RECTANGLE} or - * {@link CoordinatePosition#OUT_OF_RECTANGLE OUT_OF_RECTANGLE} - */ - public static CoordinatePosition inRectangle(Rectangle2D rectangle, Point2D point) { - if (rectangle.contains(point)) { - return CoordinatePosition.IN_RECTANGLE; - } else { - return CoordinatePosition.OUT_OF_RECTANGLE; - } - } - - /* - * EDGES - */ - - /** - * Returns the position the specified coordinates have regarding the specified rectangle's edges using the specified - * tolerance. - * - * @param rectangle - * the rectangle relative to which the point will be checked - * @param point - * the checked point - * @param edgeTolerance - * the tolerance in pixels used to determine whether the coordinates are on some edge - * @return the edge position the coordinates have regarding the specified rectangle; the value will be null if the - * point is not near any edge - */ - public static CoordinatePosition onEdges(Rectangle2D rectangle, Point2D point, - double edgeTolerance) { - - CoordinatePosition vertical = closeToVertical(rectangle, point, edgeTolerance); - CoordinatePosition horizontal = closeToHorizontal(rectangle, point, edgeTolerance); - - return extractSingleCardinalDirection(vertical, horizontal); - } - - /** - * Returns the vertical bound the specified coordinates are closest to, if the distance is smaller than the edge - * tolerance. Otherwise, null is returned. - * - * @param rectangle - * the rectangle relative to which the point will be checked - * @param point - * the checked point - * @param edgeTolerance - * the tolerance in pixels used to determine whether the coordinates are on some edge - * @return EAST_EDGE, WEST_EDGE or null - */ - private static CoordinatePosition closeToVertical(Rectangle2D rectangle, Point2D point, double edgeTolerance) { - - double xDistanceToLeft = Math.abs(point.getX() - rectangle.getMinX()); - double xDistanceToRight = Math.abs(point.getX() - rectangle.getMaxX()); - boolean xCloseToLeft = xDistanceToLeft < edgeTolerance && xDistanceToLeft < xDistanceToRight; - boolean xCloseToRight = xDistanceToRight < edgeTolerance && xDistanceToRight < xDistanceToLeft; - - if (!xCloseToLeft && !xCloseToRight) { - return null; - } - - boolean yCloseToVertical = rectangle.getMinY() - edgeTolerance < point.getY() - && point.getY() < rectangle.getMaxY() + edgeTolerance; - if (yCloseToVertical) { - if (xCloseToLeft) { - return CoordinatePosition.WEST_EDGE; - } - if (xCloseToRight) { - return CoordinatePosition.EAST_EDGE; - } - } - - return null; - } - - /** - * Returns the horizontal bound the specified coordinates are closest to, if the distance is smaller than the edge - * tolerance. Otherwise, null is returned. - * - * @param rectangle - * the rectangle relative to which the point will be checked - * @param point - * the checked point - * @param edgeTolerance - * the tolerance in pixels used to determine whether the coordinates are on some edge - * @return NORTH_EDGE, SOUTH_EDGE or null - */ - private static CoordinatePosition closeToHorizontal(Rectangle2D rectangle, Point2D point, double edgeTolerance) { - - double yDistanceToUpper = Math.abs(point.getY() - rectangle.getMinY()); - double yDistanceToLower = Math.abs(point.getY() - rectangle.getMaxY()); - boolean yCloseToUpper = yDistanceToUpper < edgeTolerance && yDistanceToUpper < yDistanceToLower; - boolean yCloseToLower = yDistanceToLower < edgeTolerance && yDistanceToLower < yDistanceToUpper; - - if (!yCloseToUpper && !yCloseToLower) { - return null; - } - - boolean xCloseToHorizontal = rectangle.getMinX() - edgeTolerance < point.getX() - && point.getX() < rectangle.getMaxX() + edgeTolerance; - if (xCloseToHorizontal) { - if (yCloseToUpper) { - return CoordinatePosition.NORTH_EDGE; - } - if (yCloseToLower) { - return CoordinatePosition.SOUTH_EDGE; - } - } - - return null; - } - - /** - * Extracts a single cardinal direction from the two specified positions. The conditions stated below are not - * checked! - * - * @param vertical - * a vertical edge (EAST or WEST) or null - * @param horizontal - * a horizontal edge (NORTH OR SOUTH) or null - * @return the single coordinate position which matches the specified positions <br> - * (e.g. NORTH for (null, NORTH) and SOUTHWEST for (WEST, SOUTH)) - */ - private static CoordinatePosition extractSingleCardinalDirection(CoordinatePosition vertical, - CoordinatePosition horizontal) { - if (vertical == null) { - return horizontal; - } - - if (horizontal == null) { - return vertical; - } - - // north - if (horizontal == CoordinatePosition.NORTH_EDGE && vertical == CoordinatePosition.EAST_EDGE) { - return CoordinatePosition.NORTHEAST_EDGE; - } - if (horizontal == CoordinatePosition.NORTH_EDGE && vertical == CoordinatePosition.WEST_EDGE) { - return CoordinatePosition.NORTHWEST_EDGE; - } - - // south - if (horizontal == CoordinatePosition.SOUTH_EDGE && vertical == CoordinatePosition.EAST_EDGE) { - return CoordinatePosition.SOUTHEAST_EDGE; - } - if (horizontal == CoordinatePosition.SOUTH_EDGE && vertical == CoordinatePosition.WEST_EDGE) { - return CoordinatePosition.SOUTHWEST_EDGE; - } - - throw new IllegalArgumentException(); - } - -} diff --git a/src/impl/org/controlsfx/tools/rectangle/Edge2D.java b/src/impl/org/controlsfx/tools/rectangle/Edge2D.java deleted file mode 100644 index e9f17e6..0000000 --- a/src/impl/org/controlsfx/tools/rectangle/Edge2D.java +++ /dev/null @@ -1,249 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.tools.rectangle; - -import java.util.Objects; - -import javafx.geometry.Orientation; -import javafx.geometry.Point2D; - -/** - * The edge of a rectangle, i.e. a vertical or horizontal line segment. - */ -public class Edge2D { - - /* - * ATTRIBUTES - */ - - /** - * The edge's center point. - */ - private final Point2D centerPoint; - - /** - * The edge's orientation. - */ - private final Orientation orientation; - - /** - * The edge's length. - */ - private final double length; - - /* - * ATTRIBUTES - */ - - /** - * Creates a new edge which is specified by its center point, orientation and length. - * - * @param centerPoint - * the edge's center point - * @param orientation - * the edge's orientation - * @param length - * the edge's length; must be non-negative. - */ - public Edge2D(Point2D centerPoint, Orientation orientation, double length) { - Objects.requireNonNull(centerPoint, "The specified center point must not be null."); //$NON-NLS-1$ - Objects.requireNonNull(orientation, "The specified orientation must not be null."); //$NON-NLS-1$ - if (length < 0) - throw new IllegalArgumentException( - "The length must not be negative, i.e. zero or a positive value is alowed."); //$NON-NLS-1$ - - this.centerPoint = centerPoint; - this.orientation = orientation; - this.length = length; - } - - /* - * CORNERS AND DISTANCES - */ - - /** - * Returns the edge's upper left end point. It has ({@link #getLength() length} / 2) distance from the center point - * and depending on the edge's orientation either the same X (for {@link Orientation#HORIZONTAL}) or Y (for - * {@link Orientation#VERTICAL}) coordinate. - * - * @return the edge's upper left point - */ - public Point2D getUpperLeft() { - if (isHorizontal()) { - // horizontal - double cornersX = centerPoint.getX() - (length / 2); - double edgesY = centerPoint.getY(); - return new Point2D(cornersX, edgesY); - } else { - // vertical - double edgesX = centerPoint.getX(); - double cornersY = centerPoint.getY() - (length / 2); - return new Point2D(edgesX, cornersY); - } - } - - /** - * Returns the edge's lower right end point. It has ({@link #getLength() length} / 2) distance from the center point - * and depending on the edge's orientation either the same X (for {@link Orientation#HORIZONTAL}) or Y (for - * {@link Orientation#VERTICAL}) coordinate. - * - * @return the edge's lower right point - */ - public Point2D getLowerRight() { - if (isHorizontal()) { - // horizontal - double cornersX = centerPoint.getX() + (length / 2); - double edgesY = centerPoint.getY(); - return new Point2D(cornersX, edgesY); - } else { - // vertical - double edgesX = centerPoint.getX(); - double cornersY = centerPoint.getY() + (length / 2); - return new Point2D(edgesX, cornersY); - } - } - - /** - * Returns the distance of the specified point to the edge in terms of the dimension orthogonal to the edge's - * orientation. The sign denotes whether on which side of the edge, the point lies.<br> - * So e.g. if the edge is horizontal, only the Y coordinate's difference between the specified point and the edge is - * considered. If the point lies to the right of the edge, the returned value is positive. - * - * @param otherPoint - * the point to where the distance is computed - * @return the distance - */ - public double getOrthogonalDifference(Point2D otherPoint) { - Objects.requireNonNull(otherPoint, "The other point must nt be null."); //$NON-NLS-1$ - - if (isHorizontal()) - // horizontal -> subtract y coordinates - return otherPoint.getY() - centerPoint.getY(); - else - // vertical-> subtract x coordinates - return otherPoint.getX() - centerPoint.getX(); - } - - /* - * ATTRIBUTE ACCESS - */ - - /** - * @return the edge's center point - */ - public Point2D getCenterPoint() { - return centerPoint; - } - - /** - * Returns this edge's orientation. Note that the orientation can also be checked with {@link #isHorizontal()} and - * {@link #isVertical()}. - * - * @return the edge's orientation - */ - public Orientation getOrientation() { - return orientation; - } - - /** - * Indicates whether this is a {@link Orientation#HORIZONTAL horizontal} edge. - * - * @return true if {@link #getOrientation()} returns {@link Orientation#HORIZONTAL} - */ - public boolean isHorizontal() { - return orientation == Orientation.HORIZONTAL; - } - - /** - * Indicates whether this is a {@link Orientation#VERTICAL horizontal} edge. - * - * @return true if {@link #getOrientation()} returns {@link Orientation#VERTICAL} - */ - public boolean isVertical() { - return orientation == Orientation.VERTICAL; - } - - /** - * @return the edge's length - */ - public double getLength() { - return length; - } - - /* - * EQUALS, HASHCODE & TOSTRING - */ - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((centerPoint == null) ? 0 : centerPoint.hashCode()); - long temp; - temp = Double.doubleToLongBits(length); - result = prime * result + (int) (temp ^ (temp >>> 32)); - result = prime * result + ((orientation == null) ? 0 : orientation.hashCode()); - return result; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - Edge2D other = (Edge2D) obj; - if (centerPoint == null) { - if (other.centerPoint != null) - return false; - } else if (!centerPoint.equals(other.centerPoint)) - return false; - if (Double.doubleToLongBits(length) != Double.doubleToLongBits(other.length)) - return false; - if (orientation != other.orientation) - return false; - return true; - } - - /** - * {@inheritDoc} - */ - @Override - public String toString() { - return "Edge2D [centerX = " + centerPoint.getX() + ", centerY = " + centerPoint.getY() //$NON-NLS-1$ //$NON-NLS-2$ - + ", orientation = " + orientation + ", length = " + length + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - } - -} diff --git a/src/impl/org/controlsfx/tools/rectangle/Rectangles2D.java b/src/impl/org/controlsfx/tools/rectangle/Rectangles2D.java deleted file mode 100644 index 80f5d90..0000000 --- a/src/impl/org/controlsfx/tools/rectangle/Rectangles2D.java +++ /dev/null @@ -1,796 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.tools.rectangle; - -import impl.org.controlsfx.tools.MathTools; - -import java.util.Objects; - -import javafx.geometry.Bounds; -import javafx.geometry.Orientation; -import javafx.geometry.Point2D; -import javafx.geometry.Rectangle2D; - -/** - * Usability methods for rectangles. - */ -public class Rectangles2D { - - /* - * CHECKS - */ - - /** - * Indicates whether the specified rectangle contains the specified edge. - * - * @param rectangle - * the rectangle to check - * @param edge - * the edge to check - * @return {@code true} if both end points of the edge are {@link Rectangle2D#contains(Point2D) contained} in the - * rectangle - */ - public static boolean contains(Rectangle2D rectangle, Edge2D edge) { - Objects.requireNonNull(rectangle, "The argument 'rectangle' must not be null."); //$NON-NLS-1$ - Objects.requireNonNull(edge, "The argument 'edge' must not be null."); //$NON-NLS-1$ - - boolean edgeInBounds = rectangle.contains(edge.getUpperLeft()) && rectangle.contains(edge.getLowerRight()); - return edgeInBounds; - } - - /* - * POINT - */ - - /** - * Moves the specified point into the specified rectangle. If the point is already with the rectangle, it is - * returned. Otherwise the point in the rectangle which is closest to the specified one is returned. - * - * @param rectangle - * the {@link Rectangle2D} into which the point should be moved - * @param point - * the {@link Point2D} which is checked - * @return either the specified {@code point} or the {@link Point2D} which is closest to it while still being - * contained on the {@code rectangle} - */ - public static Point2D inRectangle(Rectangle2D rectangle, Point2D point) { - Objects.requireNonNull(rectangle, "The argument 'rectangle' must not be null."); //$NON-NLS-1$ - Objects.requireNonNull(point, "The argument 'point' must not be null."); //$NON-NLS-1$ - - if (rectangle.contains(point)) { - return point; - } - - // force the x and y coordinate into the rectangle - double newX = MathTools.inInterval(rectangle.getMinX(), point.getX(), rectangle.getMaxX()); - double newY = MathTools.inInterval(rectangle.getMinY(), point.getY(), rectangle.getMaxY()); - return new Point2D(newX, newY); - } - - /** - * Returns the center of the specified rectangle as a point. - * - * @param rectangle - * the {@link Rectangle2D} whose center point will be returned - * @return the {@link Point2D} whose x/y coordinates lie at {@code (min + max) / 2}. - */ - public static Point2D getCenterPoint(Rectangle2D rectangle) { - Objects.requireNonNull(rectangle, "The argument 'rectangle' must not be null."); //$NON-NLS-1$ - - double centerX = (rectangle.getMinX() + rectangle.getMaxX()) / 2; - double centerY = (rectangle.getMinY() + rectangle.getMaxY()) / 2; - return new Point2D(centerX, centerY); - } - - /* - * OTHER RECTANGLE - */ - - /** - * Returns the rectangle which represents the intersection of the two specified rectangles. - * - * @param a - * a {@link Rectangle2D} - * @param b - * another {@link Rectangle2D} - * @return a {@link Rectangle2D} which is the intersection of {@code a} and {@code b}; possible - * {@link Rectangle2D#EMPTY}. - */ - public static Rectangle2D intersection(Rectangle2D a, Rectangle2D b) { - Objects.requireNonNull(a, "The argument 'a' must not be null."); //$NON-NLS-1$ - Objects.requireNonNull(b, "The argument 'b' must not be null."); //$NON-NLS-1$ - - if (a.intersects(b)) { - double intersectionMinX = Math.max(a.getMinX(), b.getMinX()); - double intersectionMaxX = Math.min(a.getMaxX(), b.getMaxX()); - double intersectionWidth = intersectionMaxX - intersectionMinX; - double intersectionMinY = Math.max(a.getMinY(), b.getMinY()); - double intersectionMaxY = Math.min(a.getMaxY(), b.getMaxY()); - double intersectionHeight = intersectionMaxY - intersectionMinY; - return new Rectangle2D(intersectionMinX, intersectionMinY, intersectionWidth, intersectionHeight); - } else { - return Rectangle2D.EMPTY; - } - } - - /* - * TWO CORNERS - */ - - /** - * Creates a new rectangle with the two specified corners. The two corners will be interpreted as being diagonal of - * each other. - * - * @param oneCorner - * one corner - * @param diagonalCorner - * another corner, diagonal from the first - * @return the {@link Rectangle2D} which is defined by the two corners - */ - public static Rectangle2D forDiagonalCorners(Point2D oneCorner, Point2D diagonalCorner) { - Objects.requireNonNull(oneCorner, "The specified corner must not be null."); //$NON-NLS-1$ - Objects.requireNonNull(diagonalCorner, "The specified diagonal corner must not be null."); //$NON-NLS-1$ - - double minX = Math.min(oneCorner.getX(), diagonalCorner.getX()); - double minY = Math.min(oneCorner.getY(), diagonalCorner.getY()); - double width = Math.abs(oneCorner.getX() - diagonalCorner.getX()); - double height = Math.abs(oneCorner.getY() - diagonalCorner.getY()); - - return new Rectangle2D(minX, minY, width, height); - } - - /* - * CORNER AND SIZE - */ - - /** - * Creates a new rectangle with the specified {@code upperLeft} corner and the specified {@code width} and - * {@code height}. - * - * @param upperLeft - * one corner - * @param width - * the new rectangle's width - * @param height - * the new rectangle's height - * @return the {@link Rectangle2D} which is defined by the specified upper left corner and width and height - */ - public static Rectangle2D forUpperLeftCornerAndSize(Point2D upperLeft, double width, double height) { - return new Rectangle2D(upperLeft.getX(), upperLeft.getY(), width, height); - } - - /* - * CORNER AND RATIO - */ - - /** - * Creates a new rectangle with the two specified corners. The two corners will be interpreted as being diagonal of - * each other. The returned rectangle will have the specified {@code fixedCorner} as its corner. The other one will - * either be on the same x- or y-parallel as the {@code diagonalCorner} but will be such that the rectangle has the - * specified {@code ratio}. - * - * @param fixedCorner - * one corner - * @param diagonalCorner - * another corner, diagonal from the first - * @param ratio - * the ratio the returned rectangle must have; must be non-negative - * @return the {@link Rectangle2D} which is defined by the {@code fixedCorner}, the x- or y-parallel of the - * {@code diagonalCorner} and the {@code ratio} - */ - public static Rectangle2D forDiagonalCornersAndRatio(Point2D fixedCorner, Point2D diagonalCorner, double ratio) { - Objects.requireNonNull(fixedCorner, "The specified fixed corner must not be null."); //$NON-NLS-1$ - Objects.requireNonNull(diagonalCorner, "The specified diagonal corner must not be null."); //$NON-NLS-1$ - if (ratio < 0) { - throw new IllegalArgumentException("The specified ratio " + ratio + " must be larger than zero."); //$NON-NLS-1$ //$NON-NLS-2$ - } - - // the coordinate differences - note that they can be negative - double xDifference = diagonalCorner.getX() - fixedCorner.getX(); - double yDifference = diagonalCorner.getY() - fixedCorner.getY(); - - // the following calls will only change one of the two differences: - // the one whose value is too large compared to what it should be based on the other difference and the ratio; - // its value will instead be the other difference time or divided by the ratio - double xDifferenceByRatio = correctCoordinateDifferenceByRatio(xDifference, yDifference, ratio); - double yDifferenceByRatio = correctCoordinateDifferenceByRatio(yDifference, xDifference, 1 / ratio); - - // these are the coordinates of the upper left corner of the future rectangle - double minX = getMinCoordinate(fixedCorner.getX(), xDifferenceByRatio); - double minY = getMinCoordinate(fixedCorner.getY(), yDifferenceByRatio); - - double width = Math.abs(xDifferenceByRatio); - double height = Math.abs(yDifferenceByRatio); - - return new Rectangle2D(minX, minY, width, height); - } - - /** - * Returns the difference with the following properties:<br> - * - it has the same sign as the specified difference <br> - * - its absolute value is the minimum of the absolute values of ...<br> - * ... the specified difference and <br> - * ... the product of the specified ratio and the other specified difference <br> - * - * @param difference - * the difference to check - * @param otherDifference - * the other difference - * @param ratioAsMultiplier - * the ratio as a multiplier for the other difference - * @return the corrected difference - */ - private static double correctCoordinateDifferenceByRatio(double difference, double otherDifference, - double ratioAsMultiplier) { - double differenceByRatio = otherDifference * ratioAsMultiplier; - double correctedDistance = Math.min(Math.abs(difference), Math.abs(differenceByRatio)); - - return correctedDistance * Math.signum(difference); - } - - /** - * Returns the minimum coordinate such that a rectangle starting from that coordinate will contain the fixed - * coordinate as a corner. - * - * @param fixedCoordinate - * the coordinate which must be a corner - * @param difference - * the difference in the computed coordinate - * @return fixedCoordinate + difference; if difference < 0 <br> - * fixedCoordinate; else - */ - private static double getMinCoordinate(double fixedCoordinate, double difference) { - if (difference < 0) { - return fixedCoordinate + difference; - } - - return fixedCoordinate; - } - - /* - * CENTER AND SIZE - */ - - /** - * Creates a new rectangle with the specified center and the specified width and height. - * - * @param centerPoint - * the center point o the new rectangle - * @param width - * the width of the new rectangle - * @param height - * the height of the new rectangle - * @return a rectangle with the specified center and size - */ - public static Rectangle2D forCenterAndSize(Point2D centerPoint, double width, double height) { - Objects.requireNonNull(centerPoint, "The specified center point must not be null."); //$NON-NLS-1$ - - double absoluteWidth = Math.abs(width); - double absoluteHeight = Math.abs(height); - double minX = centerPoint.getX() - absoluteWidth / 2; - double minY = centerPoint.getY() - absoluteHeight / 2; - - return new Rectangle2D(minX, minY, width, height); - } - - /* - * ORIGINAL, AREA AND RATIO - */ - - /** - * Creates a new rectangle with the same center point and area as the specified {@code original} rectangle with the - * specified {@code ratio}. - * - * @param original - * the original rectangle - * @param ratio - * the new ratio - * @return a new {@link Rectangle2D} with the same center point as the {@code original} and the specified - * {@code ratio}; it has the same area as the {@code original} - * @throws NullPointerException - * if the {@code original} rectangle is null - */ - public static Rectangle2D fixRatio(Rectangle2D original, double ratio) { - Objects.requireNonNull(original, "The specified original rectangle must not be null."); //$NON-NLS-1$ - if (ratio < 0) { - throw new IllegalArgumentException("The specified ratio " + ratio + " must be larger than zero."); //$NON-NLS-1$ //$NON-NLS-2$ - } - - return createWithFixedRatioWithinBounds(original, ratio, null); - } - - /** - * Creates a new rectangle with the same center point and area (if possible) as the specified {@code original} - * rectangle with the specified {@code ratio} and respecting the specified {@code bounds}. - * - * @param original - * the original rectangle - * @param ratio - * the new ratio - * @param bounds - * the bounds within which the new rectangle will be located - * @return a new {@link Rectangle2D} with the same center point as the {@code original} and the specified - * {@code ratio}; it has the same area as the {@code original} unless this would violate the bounds; in this - * case it is as large as possible while still staying within the bounds - * @throws NullPointerException - * if the {@code original} or {@code bounds} rectangle is null - * @throws IllegalArgumentException - * if the {@code original} rectangle's center point is out of the bounds - */ - public static Rectangle2D fixRatioWithinBounds(Rectangle2D original, double ratio, Rectangle2D bounds) { - Objects.requireNonNull(original, "The specified original rectangle must not be null."); //$NON-NLS-1$ - Objects.requireNonNull(bounds, "The specified bounds for the new rectangle must not be null."); //$NON-NLS-1$ - if (ratio < 0) { - throw new IllegalArgumentException("The specified ratio " + ratio + " must be larger than zero."); //$NON-NLS-1$ //$NON-NLS-2$ - } - - return createWithFixedRatioWithinBounds(original, ratio, bounds); - } - - /** - * Creates a new rectangle with the same center point and area as the specified {@code original} rectangle with the - * specified {@code ratio} and respecting the specified {@code bounds} (if not-{@code null}). - * - * @param original - * the original rectangle - * @param ratio - * the new ratio - * @param bounds - * the bounds within which the new rectangle will be located; might be {@code null} - * @return a new {@link Rectangle2D} with the same center point as the {@code original} and the specified - * {@code ratio}; it has the same area as the {@code original} unless this would violate the bounds; in this - * case it is as large as possible while still staying within the bounds - * @throws IllegalArgumentException - * if the {@code original} rectangle's center point is out of the {@code bounds} - */ - private static Rectangle2D createWithFixedRatioWithinBounds(Rectangle2D original, double ratio, Rectangle2D bounds) { - Point2D centerPoint = getCenterPoint(original); - - boolean centerPointInBounds = bounds == null || bounds.contains(centerPoint); - if (!centerPointInBounds) { - throw new IllegalArgumentException("The center point " + centerPoint //$NON-NLS-1$ - + " of the original rectangle is out of the specified bounds."); //$NON-NLS-1$ - } - - double area = original.getWidth() * original.getHeight(); - - return createForCenterAreaAndRatioWithinBounds(centerPoint, area, ratio, bounds); - } - - /* - * CENTER, AREA AND RATIO - */ - - /** - * Creates a new rectangle with the specified {@code centerPoint}, {@code area} and {@code ratio}. - * - * @param centerPoint - * the new rectangle's center point - * @param area - * the new rectangle's area - * @param ratio - * the new ratio - * @return a new {@link Rectangle2D} with the specified {@code centerPoint}, {@code area} and {@code ratio} - * @throws IllegalArgumentException - * if the {@code centerPoint} is out of the {@code bounds} - */ - public static Rectangle2D forCenterAndAreaAndRatio(Point2D centerPoint, double area, double ratio) { - Objects.requireNonNull(centerPoint, "The specified center point of the new rectangle must not be null."); //$NON-NLS-1$ - if (area < 0) { - throw new IllegalArgumentException("The specified area " + area + " must be larger than zero."); //$NON-NLS-1$ //$NON-NLS-2$ - } - if (ratio < 0) { - throw new IllegalArgumentException("The specified ratio " + ratio + " must be larger than zero."); //$NON-NLS-1$ //$NON-NLS-2$ - } - - return createForCenterAreaAndRatioWithinBounds(centerPoint, area, ratio, null); - } - - /** - * Creates a new rectangle with the specified {@code centerPoint}, {@code area} (if possible) and {@code ratio}, - * respecting the specified {@code bounds}. - * - * @param centerPoint - * the new rectangle's center point - * @param area - * the new rectangle's area (if possible without violating the bounds) - * @param ratio - * the new ratio - * @param bounds - * the bounds within which the new rectangle will be located - * @return a new {@link Rectangle2D} with the specified {@code centerPoint} and {@code ratio}; it has the specified - * {@code area} unless this would violate the {@code bounds}; in this case it is as large as possible while - * still staying within the bounds - * @throws IllegalArgumentException - * if the {@code centerPoint} is out of the {@code bounds} - */ - public static Rectangle2D forCenterAndAreaAndRatioWithinBounds( - Point2D centerPoint, double area, double ratio, Rectangle2D bounds) { - - Objects.requireNonNull(centerPoint, "The specified center point of the new rectangle must not be null."); //$NON-NLS-1$ - Objects.requireNonNull(bounds, "The specified bounds for the new rectangle must not be null."); //$NON-NLS-1$ - boolean centerPointInBounds = bounds.contains(centerPoint); - if (!centerPointInBounds) { - throw new IllegalArgumentException("The center point " + centerPoint //$NON-NLS-1$ - + " of the original rectangle is out of the specified bounds."); //$NON-NLS-1$ - } - if (area < 0) { - throw new IllegalArgumentException("The specified area " + area + " must be larger than zero."); //$NON-NLS-1$ //$NON-NLS-2$ - } - if (ratio < 0) { - throw new IllegalArgumentException("The specified ratio " + ratio + " must be larger than zero."); //$NON-NLS-1$ //$NON-NLS-2$ - } - - return createForCenterAreaAndRatioWithinBounds(centerPoint, area, ratio, bounds); - } - - /** - * Creates a new rectangle with the specified {@code centerPoint}, {@code area} (if possible) and {@code ratio}, - * respecting the specified {@code bounds} (if not-null). - * - * @param centerPoint - * the new rectangle's center point - * @param area - * the new rectangle's area (if possible without violating the bounds) - * @param ratio - * the new ratio - * @param bounds - * the bounds within which the new rectangle will be located - * @return a new {@link Rectangle2D} with the specified {@code centerPoint} and {@code ratio}; it has the specified - * {@code area} unless this would violate the {@code bounds}; in this case it is as large as possible while - * still staying within the bounds - * @throws IllegalArgumentException - * if the {@code centerPoint} is out of the {@code bounds} - */ - private static Rectangle2D createForCenterAreaAndRatioWithinBounds( - Point2D centerPoint, double area, double ratio, Rectangle2D bounds) { - - double newWidth = Math.sqrt(area * ratio); - double newHeight = area / newWidth; - - boolean boundsSpecified = bounds != null; - if (boundsSpecified) { - double reductionFactor = lengthReductionToStayWithinBounds(centerPoint, newWidth, newHeight, bounds); - newWidth *= reductionFactor; - newHeight *= reductionFactor; - } - - return Rectangles2D.forCenterAndSize(centerPoint, newWidth, newHeight); - } - - /** - * Computes the factor by which the specified width and height must be multiplied to keep a rectangle with their - * ratio and the specified center point within the specified bounds. - * - * @param centerPoint - * the center point of the new rectangle - * @param width - * the original width which might be too large - * @param height - * the original height which might be too large - * @param bounds - * the bounds within which the new rectangle will be located - * @return the factor with which the width and height must be multiplied to stay within the bounds; always in the - * closed interval [0; 1] - * @throws IllegalArgumentException - * if the {@code centerPoint} is out of the {@code bounds}; if {@code width} or {@code height} are not - * larger than zero - */ - private static double lengthReductionToStayWithinBounds( - Point2D centerPoint, double width, double height, Rectangle2D bounds) { - - Objects.requireNonNull(centerPoint, "The specified center point of the new rectangle must not be null."); //$NON-NLS-1$ - Objects.requireNonNull(bounds, "The specified bounds for the new rectangle must not be null."); //$NON-NLS-1$ - boolean centerPointInBounds = bounds.contains(centerPoint); - if (!centerPointInBounds) { - throw new IllegalArgumentException("The center point " + centerPoint //$NON-NLS-1$ - + " of the original rectangle is out of the specified bounds."); //$NON-NLS-1$ - } - if (width < 0) { - throw new IllegalArgumentException("The specified width " + width + " must be larger than zero."); //$NON-NLS-1$ //$NON-NLS-2$ - } - if (height < 0) { - throw new IllegalArgumentException("The specified height " + height + " must be larger than zero."); //$NON-NLS-1$ //$NON-NLS-2$ - } - - /* - * Compute the center point's distance to all edges. The width and height must be reduced (by the returned - * factor) such that their halves (!) are not greater than those distances. This can be done by finding the - * minimum ratio between the distance and the halved width/height. - */ - - double distanceToEast = Math.abs(centerPoint.getX() - bounds.getMinX()); - double distanceToWest = Math.abs(centerPoint.getX() - bounds.getMaxX()); - double distanceToNorth = Math.abs(centerPoint.getY() - bounds.getMinY()); - double distanceToSouth = Math.abs(centerPoint.getY() - bounds.getMaxY()); - - // the returned factor must not be greater than one; otherwise the size would increase - return MathTools.min(1, - distanceToEast / width * 2, distanceToWest / width * 2, - distanceToNorth / height * 2, distanceToSouth / height * 2); - } - - /* - * EDGES - */ - - /** - * Returns a rectangle that has the specified edge and has its opposing edge on the parallel axis defined by the - * specified point's X or Y coordinate (depending on the edge's orientation). - * - * @param edge - * the edge which will be contained in the returned rectangle - * @param point - * the point whose X or Y coordinate defines the other edge - * @return a rectangle - */ - public static Rectangle2D forEdgeAndOpposingPoint(Edge2D edge, Point2D point) { - double otherDimension = edge.getOrthogonalDifference(point); - return createForEdgeAndOtherDimension(edge, otherDimension); - } - - /** - * Returns a rectangle that is principally defined by the specified edge and point. It should have the specified - * edge as one of its own and its parallel edge should contain the point. While this would already well-define the - * rectangle (compare {@link #forEdgeAndOpposingPoint(Edge2D, Point2D) forEdgeAndOpposingPoint}) the additionally - * specified ratio and bounds have precedence over these arguments:<br> - * The returned rectangle will have the ratio and will be within the bounds. If the bounds make it possible, the - * specified point will lie on the edge parallel to the specified one. In order to maintain the ratio, this will - * make it necessary to not use the specified edge but instead one with a different length. The new edge will have - * the same center point as the specified one.<br> - * This results on the following behavior: As the point is moved closer to or further away from the edge, the - * resulting rectangle shrinks and grows while being anchored to the specified edge's center point and keeping the - * ratio. This is limited by the bounds. - * - * @param edge - * the edge which defines the center point and orientation of one of the rectangle's edges; must be - * within the specified {@code bounds} - * @param point - * the point to which the rectangle spans if ratio and bounds allow it - * @param ratio - * the ratio the new rectangle must have - * @param bounds - * the bounds within which the new rectangle must lie - * @return a rectangle - */ - public static Rectangle2D forEdgeAndOpposingPointAndRatioWithinBounds( - Edge2D edge, Point2D point, double ratio, Rectangle2D bounds) { - - Objects.requireNonNull(edge, "The specified edge must not be null."); //$NON-NLS-1$ - Objects.requireNonNull(point, "The specified point must not be null."); //$NON-NLS-1$ - Objects.requireNonNull(bounds, "The specified bounds must not be null."); //$NON-NLS-1$ - - boolean edgeInBounds = contains(bounds, edge); - if (!edgeInBounds) { - throw new IllegalArgumentException( - "The specified edge " + edge + " is not entirely contained on the specified bounds."); //$NON-NLS-1$ //$NON-NLS-2$ - } - if (ratio < 0) { - throw new IllegalArgumentException("The specified ratio " + ratio + " must be larger than zero."); //$NON-NLS-1$ //$NON-NLS-2$ - } - - /* - * 1. move the point into the bounds - * 2. create an edge whose length matches the distance to the point and the ratio - * 3. correct that edge so that it lies within the bounds - * 4. create a new rectangle from that edge and the ratio - */ - - Point2D boundedPoint = movePointIntoBounds(point, bounds); - Edge2D unboundedEdge = resizeEdgeForDistanceAndRatio(edge, boundedPoint, ratio); - Edge2D boundedEdge = resizeEdgeForBounds(unboundedEdge, bounds); - - // when computing the other dimension, note that the sign of the original difference between edge and point is - // important; otherwise the "direction" of the resize is wrong - double otherDimension = Math.signum(boundedEdge.getOrthogonalDifference(boundedPoint)); - if (boundedEdge.isHorizontal()) { - // edge horizontal -> width fixed -> use length to compute height - otherDimension *= boundedEdge.getLength() / ratio; - } else { - // edge vertical -> height fixed -> use length to compute width - otherDimension *= boundedEdge.getLength() * ratio; - } - - return createForEdgeAndOtherDimension(boundedEdge, otherDimension); - } - - /** - * Returns either the specified point if if the specified bounds {@link Rectangle2D#contains(Point2D) contain} it or - * a point whose X and/or Y coordinates are moved into the bounds. - * - * @param point - * the point to move into the {@code bounds} - * @param bounds - * the bounds into which the {@code point} will be moved - * @return either {@code point} or a new {@link Point2D} whose coordinates were changed so that it lies within the - * {@code bounds} - */ - private static Point2D movePointIntoBounds(Point2D point, Rectangle2D bounds) { - if (bounds.contains(point)) { - return point; - } else { - double boundedPointX = MathTools.inInterval(bounds.getMinX(), point.getX(), bounds.getMaxX()); - double boundedPointY = MathTools.inInterval(bounds.getMinY(), point.getY(), bounds.getMaxY()); - return new Point2D(boundedPointX, boundedPointY); - } - } - - /** - * Returns an edge with the same center point and orientation as the specified edge. Its length has the specified - * ratio to the distance of the edge and the specified point. - * - * @param edge - * the edge whose center point and orientation defines the returned edge's center point and orientation - * @param point - * the point to which the distance is measured - * @param ratio - * the ratio between the distance to the {@code point} and the returned edge's length - * @return an {@link Edge2D} - */ - private static Edge2D resizeEdgeForDistanceAndRatio(Edge2D edge, Point2D point, double ratio) { - double distance = Math.abs(edge.getOrthogonalDifference(point)); - if (edge.isHorizontal()) { - // a horizontal edge's length lies in the X axis; the distance lies in the Y axis: x = y * ratio - double xLength = distance * ratio; - return new Edge2D(edge.getCenterPoint(), edge.getOrientation(), xLength); - } else { - // a vertical edge's length lies in the Y axis; the distance lies in the X axis: y = x / ratio - double yLength = distance / ratio; - return new Edge2D(edge.getCenterPoint(), edge.getOrientation(), yLength); - } - } - - /** - * Returns an edge with the same center point and orientation as the specified edge. If necessary, its length is - * reduced to fit within the bounds. - * - * @param edge - * the edge whose center point and orientation defines the returned edge's center point and orientation; - * the center point must be within the bounds or an {@link IllegalArgumentException} will be thrown - * @param bounds - * the bounds within which the returned edge must be contained - * @return either the specified {@code edge} if it is with in the {@code bounds} or one with a corrected length - * @throws IllegalArgumentException - * if the {@code edge}'s center point is out of {@code bounds} - */ - private static Edge2D resizeEdgeForBounds(Edge2D edge, Rectangle2D bounds) { - // return the same edge if it is in the bounds - boolean edgeInBounds = contains(bounds, edge); - if (edgeInBounds) { - return edge; - } - - // make sure the bounds contain the edge's center point - boolean centerPointInBounds = bounds.contains(edge.getCenterPoint()); - if (!centerPointInBounds) { - throw new IllegalArgumentException( - "The specified edge's center point (" + edge + ") is out of the specified bounds (" + bounds + ")."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - } - - if (edge.isHorizontal()) { - // compute the length bounds for the left and right part of the edge - double leftPartLengthBound = Math.abs(bounds.getMinX() - edge.getCenterPoint().getX()); - double rightPartLengthBound = Math.abs(bounds.getMaxX() - edge.getCenterPoint().getX()); - // compute the length of the left and right parts of the edge - double leftPartLength = MathTools.inInterval(0, edge.getLength() / 2, leftPartLengthBound); - double rightPartLength = MathTools.inInterval(0, edge.getLength() / 2, rightPartLengthBound); - // compute the total length as double of the smaller length - double horizontalLength = Math.min(leftPartLength, rightPartLength) * 2; - return new Edge2D(edge.getCenterPoint(), edge.getOrientation(), horizontalLength); - } else { - // compute the length bounds for the lower and upper part of the edge - double lowerPartLengthBound = Math.abs(bounds.getMinY() - edge.getCenterPoint().getY()); - double upperPartLengthBound = Math.abs(bounds.getMaxY() - edge.getCenterPoint().getY()); - // compute the length of the lower and upper part of the edge - double lowerPartLength = MathTools.inInterval(0, edge.getLength() / 2, lowerPartLengthBound); - double upperPartLength = MathTools.inInterval(0, edge.getLength() / 2, upperPartLengthBound); - // compute the total length as double of the smaller length - double verticalLength = Math.min(lowerPartLength, upperPartLength) * 2; - return new Edge2D(edge.getCenterPoint(), edge.getOrientation(), verticalLength); - } - } - - /** - * Returns a rectangle that has the specified edge and a height or width (depending on the edge's orientation) as - * specified by {@code otherDimension}. - * - * @param edge - * the edge which will be contained in the returned rectangle - * @param otherDimension - * if the edge's orientation is {@link Orientation#HORIZONTAL horizontal}, this is interpreted as the - * height; if the edge's orientation is {@link Orientation#VERTICAL vertical}, this is interpreted as the - * width - * @return a rectangle - */ - private static Rectangle2D createForEdgeAndOtherDimension(Edge2D edge, double otherDimension) { - if (edge.isHorizontal()) { - return createForHorizontalEdgeAndHeight(edge, otherDimension); - } else { - return createForVerticalEdgeAndWidth(edge, otherDimension); - } - } - - /** - * Returns a rectangle that has the specified horizontal edge and height. Depending on whether the width is positive - * or negative, the specified edge will be the upper or lower edge of the returned rectangle. - * - * @param horizontalEdge - * the horizontal edge which will be contained in the returned rectangle - * @param height - * the returned rectangle's height - * @return a rectangle - */ - private static Rectangle2D createForHorizontalEdgeAndHeight(Edge2D horizontalEdge, double height) { - Point2D leftEdgeEndPoint = horizontalEdge.getUpperLeft(); - double upperLeftX = leftEdgeEndPoint.getX(); - // if the height is negative, reduce the Y coordinate by that amount - double upperLeftY = leftEdgeEndPoint.getY() + Math.min(0, height); - - double absoluteWidth = Math.abs(horizontalEdge.getLength()); - double absoluteHeight = Math.abs(height); - - return new Rectangle2D(upperLeftX, upperLeftY, absoluteWidth, absoluteHeight); - } - - /** - * Returns a rectangle that has the specified horizontal edge and width. Depending on whether the width is positive - * or negative, the specified edge will be the left or right edge of the returned rectangle. - * - * @param verticalEdge - * the vertical edge which will be contained in the returned rectangle - * @param width - * the returned rectangle's height - * @return a rectangle - */ - private static Rectangle2D createForVerticalEdgeAndWidth(Edge2D verticalEdge, double width) { - Point2D upperEdgeEndPoint = verticalEdge.getUpperLeft(); - // if the width is negative, reduce the X coordinate by that amount - double upperLeftX = upperEdgeEndPoint.getX() + Math.min(0, width); - double upperLeftY = upperEdgeEndPoint.getY(); - - double absoluteWidth = Math.abs(width); - double absoluteHeight = Math.abs(verticalEdge.getLength()); - - return new Rectangle2D(upperLeftX, upperLeftY, absoluteWidth, absoluteHeight); - } - - /* - * MISC - */ - - /** - * Returns a rectangle with the same coordinates as the specified bounds. - * - * @param bounds - * the {@link Bounds} for which the rectangle will be created - * @return a {@link Rectangle2D} with the same minX-, minY-, maxX- and maxY-coordiantes as the specified bounds - */ - public static Rectangle2D fromBounds(Bounds bounds) { - return new Rectangle2D(bounds.getMinX(), bounds.getMinY(), bounds.getWidth(), bounds.getHeight()); - } - -} diff --git a/src/impl/org/controlsfx/tools/rectangle/change/AbstractBeginEndCheckingChangeStrategy.java b/src/impl/org/controlsfx/tools/rectangle/change/AbstractBeginEndCheckingChangeStrategy.java deleted file mode 100644 index 61e0e82..0000000 --- a/src/impl/org/controlsfx/tools/rectangle/change/AbstractBeginEndCheckingChangeStrategy.java +++ /dev/null @@ -1,149 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.tools.rectangle.change; - -import java.util.Objects; - -import javafx.geometry.Point2D; -import javafx.geometry.Rectangle2D; - -/** - * Abstract superclass to implementations of {@link Rectangle2DChangeStrategy}. Checks whether the specified points are not-null - * and the "begin-continue-end"-contract. - */ -abstract class AbstractBeginEndCheckingChangeStrategy implements Rectangle2DChangeStrategy { - - // ATTRIBUTES - - /** - * Indicates whether {@link #beginChange(Point2D) beginChange} was called. - */ - private boolean beforeBegin; - - // CONSTRUCTOR - - /** - * Creates a change strategy which checks whether begin and end are correctly called. - */ - protected AbstractBeginEndCheckingChangeStrategy() { - beforeBegin = true; - } - - // IMPLEMENTATION OF 'ChangeStrategy' - - /** - * {@inheritDoc} - */ - @Override - public final Rectangle2D beginChange(Point2D point) { - Objects.requireNonNull(point, "The specified point must not be null."); //$NON-NLS-1$ - if (!beforeBegin) - throw new IllegalStateException( - "The change already began, so 'beginChange' must not be called again before 'endChange' was called."); //$NON-NLS-1$ - beforeBegin = false; - - beforeBeginHook(point); - return doBegin(point); - } - - /** - * {@inheritDoc} - */ - @Override - public final Rectangle2D continueChange(Point2D point) { - Objects.requireNonNull(point, "The specified point must not be null."); //$NON-NLS-1$ - if (beforeBegin) - throw new IllegalStateException("The change did not begin. Call 'beginChange' before 'continueChange'."); //$NON-NLS-1$ - - return doContinue(point); - } - - /** - * {@inheritDoc} - */ - @Override - public final Rectangle2D endChange(Point2D point) { - Objects.requireNonNull(point, "The specified point must not be null."); //$NON-NLS-1$ - if (beforeBegin) - throw new IllegalStateException("The change did not begin. Call 'beginChange' before 'endChange'."); //$NON-NLS-1$ - - Rectangle2D finalRectangle = doEnd(point); - afterEndHook(point); - beforeBegin = true; - return finalRectangle; - } - - //ABSTRACT METHODS - - /** - * Called before the change begins at the specified point. - * - * @param point - * a point - */ - protected void beforeBeginHook(Point2D point) { - // can be overridden by subclasses - } - - /** - * Begins the change at the specified point. - * - * @param point - * a point - * @return the new rectangle - */ - protected abstract Rectangle2D doBegin(Point2D point); - - /** - * Continues the change to the specified point. Must not be called before a call to {@link #beginChange}. - * - * @param point - * a point - * @return the new rectangle - */ - protected abstract Rectangle2D doContinue(Point2D point); - - /** - * Ends the change at the specified point. Must not be called before a call to {@link #beginChange}. - * - * @param point - * a point - * @return the new rectangle - */ - protected abstract Rectangle2D doEnd(Point2D point); - - /** - * Called after the change ends at the specified point. - * - * @param point - * a point - */ - protected void afterEndHook(Point2D point) { - // can be overridden by subclasses - } - -} diff --git a/src/impl/org/controlsfx/tools/rectangle/change/AbstractFixedEdgeChangeStrategy.java b/src/impl/org/controlsfx/tools/rectangle/change/AbstractFixedEdgeChangeStrategy.java deleted file mode 100644 index ccc5019..0000000 --- a/src/impl/org/controlsfx/tools/rectangle/change/AbstractFixedEdgeChangeStrategy.java +++ /dev/null @@ -1,137 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.tools.rectangle.change; - -import impl.org.controlsfx.tools.rectangle.Edge2D; -import impl.org.controlsfx.tools.rectangle.Rectangles2D; -import javafx.geometry.Point2D; -import javafx.geometry.Rectangle2D; - -/** - * Abstract superclass to those implementations of {@link Rectangle2DChangeStrategy} which compute their rectangle by - * spanning it from a fixed edge to the parallel edge defined by the point given to - * {@link Rectangle2DChangeStrategy#continueChange(Point2D) continueChange}. <br> - * The edge is fixed during the change but can be changed in between changes. Implemented such that a ratio is respected - * if specified. - */ -abstract class AbstractFixedEdgeChangeStrategy extends AbstractRatioRespectingChangeStrategy { - - // ATTRIBUTES - - /** - * A rectangle which defines the bounds within which the new rectangle must be contained. - */ - private final Rectangle2D bounds; - - /** - * The edge which is fixed during the change. In {@link #doBegin(Point2D)} it is set to {@link #getFixedEdge()}; in - * {@link #doEnd(Point2D)} it is set to {@code null}. - */ - private Edge2D fixedEdge; - - // CONSTRUCTOR - - /** - * Creates a fixed edge change strategy. It respects the specified {@code ratio} if {@code ratioFixed} is - * {@code true}. - * - * @param ratioFixed - * indicates whether the ratio will be fixed - * @param ratio - * defines the fixed ratio - * @param bounds - * the bounds within which the new rectangle must be contained - */ - protected AbstractFixedEdgeChangeStrategy(boolean ratioFixed, double ratio, Rectangle2D bounds) { - super(ratioFixed, ratio); - this.bounds = bounds; - } - - // ABSTRACT METHODS - - /** - * Returns the edge which is fixed during the change. Called once when the change begins. - * - * @return the edge which is fixed during the change - */ - protected abstract Edge2D getFixedEdge(); - - // IMPLEMENTATION OF 'do...' - - /** - * Creates a new rectangle from the two edges defined by {@link #fixedEdge} and its parallel through the specified - * point. - * - * @param point - * the point defining the parallel edge - * @return the rectangle defined the two edges - */ - private final Rectangle2D createFromEdges(Point2D point) { - Point2D pointInBounds = Rectangles2D.inRectangle(bounds, point); - - if (isRatioFixed()) { - return Rectangles2D.forEdgeAndOpposingPointAndRatioWithinBounds( - fixedEdge, pointInBounds, getRatio(), bounds); - } else { - return Rectangles2D.forEdgeAndOpposingPoint(fixedEdge, pointInBounds); - } - } - - /** - * {@inheritDoc} - */ - @Override - protected final Rectangle2D doBegin(Point2D point) { - boolean startPointNotInBounds = !bounds.contains(point); - if (startPointNotInBounds) { - throw new IllegalArgumentException( - "The change's start point (" + point + ") must lie within the bounds (" + bounds + ")."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - } - - fixedEdge = getFixedEdge(); - return createFromEdges(point); - } - - /** - * {@inheritDoc} - */ - @Override - protected Rectangle2D doContinue(Point2D point) { - return createFromEdges(point); - } - - /** - * {@inheritDoc} - */ - @Override - protected final Rectangle2D doEnd(Point2D point) { - Rectangle2D newRectangle = createFromEdges(point); - fixedEdge = null; - return newRectangle; - } - -} diff --git a/src/impl/org/controlsfx/tools/rectangle/change/AbstractFixedPointChangeStrategy.java b/src/impl/org/controlsfx/tools/rectangle/change/AbstractFixedPointChangeStrategy.java deleted file mode 100644 index 27353e8..0000000 --- a/src/impl/org/controlsfx/tools/rectangle/change/AbstractFixedPointChangeStrategy.java +++ /dev/null @@ -1,139 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.tools.rectangle.change; - -import impl.org.controlsfx.tools.rectangle.Rectangles2D; - -import java.util.Objects; - -import javafx.geometry.Point2D; -import javafx.geometry.Rectangle2D; - -/** - * Abstract superclass to those implementations of {@link Rectangle2DChangeStrategy} which compute their rectangle by - * spanning it from a fixed point to the point given to {@link Rectangle2DChangeStrategy#continueChange(Point2D) - * continueChange}. <br> - * The point is fixed during the change but can be changed in between changes. Implemented such that a ratio is - * respected if specified. - */ -abstract class AbstractFixedPointChangeStrategy extends AbstractRatioRespectingChangeStrategy { - - // ATTRIBUTES - - /** - * A rectangle which defines the bounds within which the new rectangle must be contained. - */ - private final Rectangle2D bounds; - - /** - * The point which is fixed during the change. In {@link #doBegin(Point2D)} it is set to {@link #getFixedCorner()}; - * in {@link #doEnd(Point2D)} it is set to {@code null}. - */ - private Point2D fixedCorner; - - // CONSTRUCTOR - - /** - * Creates a fixed corner change strategy. It respects the specified {@code ratio} if {@code ratioFixed} is - * {@code true}. - * - * @param ratioFixed - * indicates whether the ratio will be fixed - * @param ratio - * defines the fixed ratio - * @param bounds - * the bounds within which the new rectangle must be contained - */ - protected AbstractFixedPointChangeStrategy(boolean ratioFixed, double ratio, Rectangle2D bounds) { - super(ratioFixed, ratio); - Objects.requireNonNull(bounds, "The argument 'bounds' must not be null."); //$NON-NLS-1$ - - this.bounds = bounds; - } - - // ABSTRACT METHODS - - /** - * Returns the corner which is fixed during the change. Called once when the change begins. - * - * @return the corner which is fixed during the change - */ - protected abstract Point2D getFixedCorner(); - - // IMPLEMENTATION OF 'do...' - - /** - * Creates a new rectangle from the two corners defined by {@link #getFixedCorner()} and the specified point. - * - * @param point - * the second corner - * @return the rectangle defined the two corners - */ - private final Rectangle2D createFromCorners(Point2D point) { - Point2D pointInBounds = Rectangles2D.inRectangle(bounds, point); - - if (isRatioFixed()) { - return Rectangles2D.forDiagonalCornersAndRatio(fixedCorner, pointInBounds, getRatio()); - } else { - return Rectangles2D.forDiagonalCorners(fixedCorner, pointInBounds); - } - } - - /** - * {@inheritDoc} - */ - @Override - protected final Rectangle2D doBegin(Point2D point) { - boolean startPointNotInBounds = !bounds.contains(point); - if (startPointNotInBounds) { - throw new IllegalArgumentException( - "The change's start point (" + point + ") must lie within the bounds (" + bounds + ")."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - } - - fixedCorner = getFixedCorner(); - return createFromCorners(point); - } - - /** - * {@inheritDoc} - */ - @Override - protected Rectangle2D doContinue(Point2D point) { - return createFromCorners(point); - } - - /** - * {@inheritDoc} - */ - @Override - protected final Rectangle2D doEnd(Point2D point) { - Rectangle2D newRectangle = createFromCorners(point); - fixedCorner = null; - return newRectangle; - } - -} diff --git a/src/impl/org/controlsfx/tools/rectangle/change/AbstractPreviousRectangleChangeStrategy.java b/src/impl/org/controlsfx/tools/rectangle/change/AbstractPreviousRectangleChangeStrategy.java deleted file mode 100644 index bf169d3..0000000 --- a/src/impl/org/controlsfx/tools/rectangle/change/AbstractPreviousRectangleChangeStrategy.java +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.tools.rectangle.change; - -import java.util.Objects; - -import javafx.geometry.Rectangle2D; - -/** - * Abstract superclass to those implementations of {@link Rectangle2DChangeStrategy}, which are based on a previous - * rectangle. Respects a ratio if one is set. - */ -abstract class AbstractPreviousRectangleChangeStrategy extends AbstractRatioRespectingChangeStrategy { - - // ATTRIBUTES - - /** - * The rectangle these changes are based on. - */ - private final Rectangle2D previous; - - // CONSTRUCTOR - - /** - * Creates a change strategy which is based on the specified {@code previous} rectangle and respects the specified - * {@code ratio} if {@code ratioFixed} is {@code true}. - * - * @param previous - * the previous rectangle this change is based on - * @param ratioFixed - * indicates whether the ratio will be fixed - * @param ratio - * defines the fixed ratio - */ - protected AbstractPreviousRectangleChangeStrategy(Rectangle2D previous, boolean ratioFixed, double ratio) { - super(ratioFixed, ratio); - - Objects.requireNonNull(previous, "The previous rectangle must not be null."); //$NON-NLS-1$ - this.previous = previous; - } - - // ATTRIBUTE ACCESS - - /** - * The previous rectangle this change is based on. - * - * @return the previous rectangle - */ - protected final Rectangle2D getPrevious() { - return previous; - } - -} diff --git a/src/impl/org/controlsfx/tools/rectangle/change/AbstractRatioRespectingChangeStrategy.java b/src/impl/org/controlsfx/tools/rectangle/change/AbstractRatioRespectingChangeStrategy.java deleted file mode 100644 index 1d89c73..0000000 --- a/src/impl/org/controlsfx/tools/rectangle/change/AbstractRatioRespectingChangeStrategy.java +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.tools.rectangle.change; - -/** - * Abstract superclass to implementations of {@link Rectangle2DChangeStrategy}, which might be parameterized such that only - * rectangles of a defined ratio are created. This parameterization happens during construction. Subclasses must - * implement the ratio handling themselves! This class only holds the parameters. - */ -abstract class AbstractRatioRespectingChangeStrategy extends AbstractBeginEndCheckingChangeStrategy { - - // ATTRIBUTES - - /** - * Indicates whether the current selection must have a fixed ratio. If so, 'ratio' can be used. - */ - private final boolean ratioFixed; - - /** - * The currently used ratio. Should only be used if 'ratioFixed' is true. - */ - private final double ratio; - - // CONSTRUCTOR - - /** - * Creates a change strategy which respects the specified {@code ratio} if {@code ratioFixed} is {@code true}. - * - * @param ratioFixed - * indicates whether the ratio will be fixed - * @param ratio - * defines the fixed ratio - */ - protected AbstractRatioRespectingChangeStrategy(boolean ratioFixed, double ratio) { - super(); - this.ratioFixed = ratioFixed; - this.ratio = ratio; - } - - // Attribute Access - - /** - * Indicates whether the ratio is fixed. If so, the ratio can be accessed with {@link #getRatio()}. - * - * @return true if the ratio is fixed; false otherwise - */ - protected final boolean isRatioFixed() { - return ratioFixed; - } - - /** - * The current ratio. Can only be called without exception when {@link #isRatioFixed()} returns true. - * - * @return the current ratio - */ - protected final double getRatio() { - if (!ratioFixed) - throw new IllegalStateException("The ratio is not fixed."); //$NON-NLS-1$ - return ratio; - } - -} diff --git a/src/impl/org/controlsfx/tools/rectangle/change/MoveChangeStrategy.java b/src/impl/org/controlsfx/tools/rectangle/change/MoveChangeStrategy.java deleted file mode 100644 index 26f8c9d..0000000 --- a/src/impl/org/controlsfx/tools/rectangle/change/MoveChangeStrategy.java +++ /dev/null @@ -1,166 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.tools.rectangle.change; - -import impl.org.controlsfx.tools.MathTools; - -import java.util.Objects; - -import javafx.geometry.Point2D; -import javafx.geometry.Rectangle2D; - -/** - * Moves the rectangle around. - */ -public class MoveChangeStrategy extends AbstractPreviousRectangleChangeStrategy { - - /* - * The previous rectangle will be moved around using a vector computed from the start to the current point. - * The moved rectangle will be forced within defined bounds. - */ - - // ATTRIBUTES - - /** - * A rectangle which defines the bounds within which the previous rectangle can be moved. - */ - private final Rectangle2D bounds; - - /** - * The starting point of the selection change. The move will be computed relative to this point. - */ - private Point2D startingPoint; - - // CONSTRUCTORS - - /** - * Creates a new change strategy which moves the specified rectangle within the specified bounds. - * - * @param previous - * the previous rectangle this move is based on - * @param bounds - * the bounds within which the rectangle can be moved - */ - public MoveChangeStrategy(Rectangle2D previous, Rectangle2D bounds) { - super(previous, false, 0); - Objects.requireNonNull(bounds, "The specified bounds must not be null."); //$NON-NLS-1$ - this.bounds = bounds; - } - - /** - * Creates a new change strategy which moves the specified rectangle within the specified bounds defined by the - * rectangle from {@code (0, 0)} to {@code (maxX, maxY)}. - * - * @param previous - * the previous rectangle this move is based on - * @param maxX - * the maximal x-coordinate of the right edge of the created rectangles; must be greater than or equal to - * the previous rectangle's width - * @param maxY - * the maximal y-coordinate of the lower edge of the created rectangles; must be greater than or equal to - * the previous rectangle's height - */ - public MoveChangeStrategy(Rectangle2D previous, double maxX, double maxY) { - super(previous, false, 0); - if (maxX < previous.getWidth()) { - throw new IllegalArgumentException( - "The specified maximal x-coordinate must be greater than or equal to the previous rectangle's width."); //$NON-NLS-1$ - } - if (maxY < previous.getHeight()) { - throw new IllegalArgumentException( - "The specified maximal y-coordinate must be greater than or equal to the previous rectangle's height."); //$NON-NLS-1$ - } - - bounds = new Rectangle2D(0, 0, maxX, maxY); - } - - // IMPLEMENTATION OF 'do...' - - /** - * Moves the previous rectangle to the specified point relative to the {@link #startingPoint}. - * - * @param point - * the vector from the {@link #startingPoint} to this point defines the movement - * @return the moved rectangle - */ - private final Rectangle2D moveRectangleToPoint(Point2D point) { - - /* - * The computation makes sure that no part of the rectangle can be moved out the bounds. - * To achieve this, the coordinates of the future rectangle's upper left corner are forced into the intervals - * - [boundsMinX, boundsMaxX - previousRectangleWidth], - * - [boundsMinY, boundsMaxY - previousRectangleHeight] respectively. - */ - - // vector from starting to specified point - double xMove = point.getX() - startingPoint.getX(); - double yMove = point.getY() - startingPoint.getY(); - - // upper left corner - double upperLeftX = getPrevious().getMinX() + xMove; - double upperLeftY = getPrevious().getMinY() + yMove; - - // upper bounds for upper left corner - double maxX = bounds.getMaxX() - getPrevious().getWidth(); - double maxY = bounds.getMaxY() - getPrevious().getHeight(); - - // corrected upper left corner - double correctedUpperLeftX = MathTools.inInterval(bounds.getMinX(), upperLeftX, maxX); - double correctedUpperLeftY = MathTools.inInterval(bounds.getMinY(), upperLeftY, maxY); - - // rectangle from corrected upper left corner with the previous rectangle's width and height - return new Rectangle2D( - correctedUpperLeftX, correctedUpperLeftY, - getPrevious().getWidth(), getPrevious().getHeight()); - } - - /** - * {@inheritDoc} - */ - @Override - protected Rectangle2D doBegin(Point2D point) { - this.startingPoint = point; - return getPrevious(); - } - - /** - * {@inheritDoc} - */ - @Override - protected Rectangle2D doContinue(Point2D point) { - return moveRectangleToPoint(point); - } - - /** - * {@inheritDoc} - */ - @Override - protected Rectangle2D doEnd(Point2D point) { - return moveRectangleToPoint(point); - } - -} diff --git a/src/impl/org/controlsfx/tools/rectangle/change/NewChangeStrategy.java b/src/impl/org/controlsfx/tools/rectangle/change/NewChangeStrategy.java deleted file mode 100644 index e62f4b4..0000000 --- a/src/impl/org/controlsfx/tools/rectangle/change/NewChangeStrategy.java +++ /dev/null @@ -1,82 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.tools.rectangle.change; - -import javafx.geometry.Point2D; -import javafx.geometry.Rectangle2D; - -/** - * A strategy which creates a new rectangle. - */ -public class NewChangeStrategy extends AbstractFixedPointChangeStrategy { - - /* - * The new selection will have the starting point as a fixed corner. The other corner will always be the current - * point modulo the ratio which will be respected if enforced. Both is handled by the superclass. - */ - - // ATTRIBUTES - - /** - * The starting point of this change. - */ - private Point2D startingPoint; - - // CONSTRUCTOR - - /** - * Creates a change strategy which creates a new rectangle. It respects the specified {@code ratio} if - * {@code ratioFixed} is {@code true}. - * - * @param ratioFixed - * indicates whether the ratio will be fixed - * @param ratio - * defines the fixed ratio - * @param bounds - * the bounds within which the new rectangle must be contained - */ - public NewChangeStrategy(boolean ratioFixed, double ratio, Rectangle2D bounds) { - super(ratioFixed, ratio, bounds); - } - - /** - * {@inheritDoc} - */ - @Override - protected void beforeBeginHook(Point2D point) { - startingPoint = point; - } - - /** - * {@inheritDoc} - */ - @Override - protected Point2D getFixedCorner() { - return startingPoint; - } - -} diff --git a/src/impl/org/controlsfx/tools/rectangle/change/Rectangle2DChangeStrategy.java b/src/impl/org/controlsfx/tools/rectangle/change/Rectangle2DChangeStrategy.java deleted file mode 100644 index 3784106..0000000 --- a/src/impl/org/controlsfx/tools/rectangle/change/Rectangle2DChangeStrategy.java +++ /dev/null @@ -1,73 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.tools.rectangle.change; - -import javafx.geometry.Point2D; -import javafx.geometry.Rectangle2D; - -/** - * A {@code Rectangle2DChangeStrategy} creates instances of {@link Rectangle2D} based on the coordinates of the begin, - * continuation and end of an action. The behavior is undefined if these three methods are not called on the following - * order:<br> - * ({@link #beginChange(Point2D) begin} -> {@link #continueChange(Point2D) continue}* -> {@link #endChange(Point2D) end} - * )* <br> - * <br> - * Most implementations will be creating new rectangles based on an existing one. If the created ones constantly replace - * the original, this effectively "changes" the rectangle's appearance (note that {@link Rectangle2D} instances - * themselves are immutable !). This interface and its implementations were created to easily allow a GUI user to change - * an existing rectangle by typical resize and move operations. - */ -public interface Rectangle2DChangeStrategy { - - /** - * Begins the change at the specified point. - * - * @param point - * a point - * @return the new rectangle - */ - Rectangle2D beginChange(Point2D point); - - /** - * Continues the change to the specified point. Must not be called before a call to {@link #beginChange}. - * - * @param point - * a point - * @return the new rectangle - */ - Rectangle2D continueChange(Point2D point); - - /** - * Ends the change at the specified point. Must not be called before a call to {@link #beginChange}. - * - * @param point - * a point - * @return the new rectangle - */ - Rectangle2D endChange(Point2D point); - -} diff --git a/src/impl/org/controlsfx/tools/rectangle/change/ToEastChangeStrategy.java b/src/impl/org/controlsfx/tools/rectangle/change/ToEastChangeStrategy.java deleted file mode 100644 index ccbe662..0000000 --- a/src/impl/org/controlsfx/tools/rectangle/change/ToEastChangeStrategy.java +++ /dev/null @@ -1,104 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.tools.rectangle.change; - -import impl.org.controlsfx.tools.rectangle.Edge2D; -import javafx.geometry.Orientation; -import javafx.geometry.Point2D; -import javafx.geometry.Rectangle2D; - -/** - * A strategy which enlarges an existing rectangle to the east. - */ -public class ToEastChangeStrategy extends AbstractFixedEdgeChangeStrategy { - - /* - * The new rectangle will have the existing rectangle's western edge as a fixed edge. The parallel edge will - * be defined by the current point (modulo the ratio which will be respected if enforced), which is handled by the - * superclass. - */ - - // ATTRIBUTES - - /** - * The new rectangle's western edge. - */ - private final Edge2D westernEdge; - - // CONSTRUCTOR - - /** - * Creates a new change strategy which enlarges the specified {@code original} rectangle to the east. The given - * {@code ratio} is enforced when indicated by {@code ratioFixed}. - * - * @param original - * the original rectangle - * @param ratioFixed - * indicates whether the rectangle's ratio will be fixed to the {@code ratio} - * @param ratio - * the possibly fixed ratio of the rectangle created by this strategy - * @param bounds - * the bounds within which the rectangle can be resized - */ - public ToEastChangeStrategy(Rectangle2D original, boolean ratioFixed, double ratio, Rectangle2D bounds) { - super(ratioFixed, ratio, bounds); - Point2D edgeCenterPoint = new Point2D(original.getMinX(), (original.getMinY() + original.getMaxY()) / 2); - westernEdge = new Edge2D(edgeCenterPoint, Orientation.VERTICAL, original.getMaxY() - original.getMinY()); - } - - /** - * Creates a new change strategy which enlarges the specified {@code original} rectangle to the northeast. The given - * {@code ratio} is enforced when indicated by {@code ratioFixed}. - * - * @param original - * the original rectangle - * @param ratioFixed - * indicates whether the rectangle's ratio will be fixed to the {@code ratio} - * @param ratio - * the possibly fixed ratio of the rectangle created by this strategy - * @param maxX - * the maximal x-coordinate of the right edge of the created rectangles; must be greater than or equal to - * the previous rectangle's width - * @param maxY - * the maximal y-coordinate of the lower edge of the created rectangles; must be greater than or equal to - * the previous rectangle's height - */ - public ToEastChangeStrategy(Rectangle2D original, boolean ratioFixed, double ratio, double maxX, double maxY) { - this(original, ratioFixed, ratio, new Rectangle2D(0, 0, maxX, maxY)); - } - - // IMPLEMENTATION OF 'AbstractFixedEdgeChangeStrategy' - - /** - * {@inheritDoc} - */ - @Override - protected Edge2D getFixedEdge() { - return westernEdge; - } - -} diff --git a/src/impl/org/controlsfx/tools/rectangle/change/ToNorthChangeStrategy.java b/src/impl/org/controlsfx/tools/rectangle/change/ToNorthChangeStrategy.java deleted file mode 100644 index 29674d0..0000000 --- a/src/impl/org/controlsfx/tools/rectangle/change/ToNorthChangeStrategy.java +++ /dev/null @@ -1,104 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.tools.rectangle.change; - -import impl.org.controlsfx.tools.rectangle.Edge2D; -import javafx.geometry.Orientation; -import javafx.geometry.Point2D; -import javafx.geometry.Rectangle2D; - -/** - * A strategy which enlarges an existing rectangle to the north. - */ -public class ToNorthChangeStrategy extends AbstractFixedEdgeChangeStrategy { - - /* - * The new rectangle will have the existing rectangle's southern edge as a fixed edge. The parallel edge will - * be defined by the current point (modulo the ratio which will be respected if enforced), which is handled by the - * superclass. - */ - - // ATTRIBUTES - - /** - * The new rectangle's southern edge. - */ - private final Edge2D southernEdge; - - // CONSTRUCTOR - - /** - * Creates a new change strategy which enlarges the specified {@code original} rectangle to the north. The given - * {@code ratio} is enforced when indicated by {@code ratioFixed}. - * - * @param original - * the original rectangle - * @param ratioFixed - * indicates whether the rectangle's ratio will be fixed to the {@code ratio} - * @param ratio - * the possibly fixed ratio of the rectangle created by this strategy - * @param bounds - * the bounds within which the rectangle can be resized - */ - public ToNorthChangeStrategy(Rectangle2D original, boolean ratioFixed, double ratio, Rectangle2D bounds) { - super(ratioFixed, ratio, bounds); - Point2D edgeCenterPoint = new Point2D((original.getMinX() + original.getMaxX()) / 2, original.getMaxY()); - southernEdge = new Edge2D(edgeCenterPoint, Orientation.HORIZONTAL, original.getMaxX() - original.getMinX()); - } - - /** - * Creates a new change strategy which enlarges the specified {@code original} rectangle to the northeast. The given - * {@code ratio} is enforced when indicated by {@code ratioFixed}. - * - * @param original - * the original rectangle - * @param ratioFixed - * indicates whether the rectangle's ratio will be fixed to the {@code ratio} - * @param ratio - * the possibly fixed ratio of the rectangle created by this strategy - * @param maxX - * the maximal x-coordinate of the right edge of the created rectangles; must be greater than or equal to - * the previous rectangle's width - * @param maxY - * the maximal y-coordinate of the lower edge of the created rectangles; must be greater than or equal to - * the previous rectangle's height - */ - public ToNorthChangeStrategy(Rectangle2D original, boolean ratioFixed, double ratio, double maxX, double maxY) { - this(original, ratioFixed, ratio, new Rectangle2D(0, 0, maxX, maxY)); - } - - // IMPLEMENTATION OF 'AbstractFixedEdgeChangeStrategy' - - /** - * {@inheritDoc} - */ - @Override - protected Edge2D getFixedEdge() { - return southernEdge; - } - -} diff --git a/src/impl/org/controlsfx/tools/rectangle/change/ToNortheastChangeStrategy.java b/src/impl/org/controlsfx/tools/rectangle/change/ToNortheastChangeStrategy.java deleted file mode 100644 index 5edb288..0000000 --- a/src/impl/org/controlsfx/tools/rectangle/change/ToNortheastChangeStrategy.java +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.tools.rectangle.change; - -import javafx.geometry.Point2D; -import javafx.geometry.Rectangle2D; - -/** - * A strategy which enlarges an existing rectangle to the northeast. - */ -public class ToNortheastChangeStrategy extends AbstractFixedPointChangeStrategy { - - /* - * The new rectangle will have the existing rectangle's southwestern corner as a fixed corner. The other corner will - * always be the current point (modulo the ratio which will be respected if enforced), which is handled by the - * superclass. - */ - - // ATTRIBUTES - - /** - * The new rectangle's southwestern corner. - */ - private final Point2D southwesternCorner; - - // CONSTRUCTOR - - /** - * Creates a new change strategy which enlarges the specified {@code original} rectangle to the northeast. The given - * {@code ratio} is enforced when indicated by {@code ratioFixed}. - * - * @param original - * the original rectangle - * @param ratioFixed - * indicates whether the rectangle's ratio will be fixed to the {@code ratio} - * @param ratio - * the possibly fixed ratio of the rectangle created by this strategy - * @param bounds - * the bounds within which the new rectangle must be contained - */ - public ToNortheastChangeStrategy(Rectangle2D original, boolean ratioFixed, double ratio, Rectangle2D bounds) { - super(ratioFixed, ratio, bounds); - southwesternCorner = new Point2D(original.getMinX(), original.getMaxY()); - } - - // IMPLEMENTATION OF 'AbstractFixedPointChangeStrategy' - - /** - * {@inheritDoc} - */ - @Override - protected Point2D getFixedCorner() { - return southwesternCorner; - } - -} diff --git a/src/impl/org/controlsfx/tools/rectangle/change/ToNorthwestChangeStrategy.java b/src/impl/org/controlsfx/tools/rectangle/change/ToNorthwestChangeStrategy.java deleted file mode 100644 index 1831333..0000000 --- a/src/impl/org/controlsfx/tools/rectangle/change/ToNorthwestChangeStrategy.java +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.tools.rectangle.change; - -import javafx.geometry.Point2D; -import javafx.geometry.Rectangle2D; - -/** - * A strategy which enlarges an existing rectangle to the northwest. - */ -public class ToNorthwestChangeStrategy extends AbstractFixedPointChangeStrategy { - - /* - * The new rectangle will have the existing rectangle's southeastern corner as a fixed corner. The other corner will - * always be the current point (modulo the ratio which will be respected if enforced), which is handled by the - * superclass. - */ - - // ATTRIBUTES - - /** - * The new rectangle's southeastern corner. - */ - private final Point2D southeasternCorner; - - // CONSTRUCTOR - - /** - * Creates a new change strategy which enlarges the specified {@code original} rectangle to the northwest. The given - * {@code ratio} is enforced when indicated by {@code ratioFixed}. - * - * @param original - * the original rectangle - * @param ratioFixed - * indicates whether the rectangle's ratio will be fixed to the {@code ratio} - * @param ratio - * the possibly fixed ratio of the rectangle created by this strategy - * @param bounds - * the bounds within which the new rectangle must be contained - */ - public ToNorthwestChangeStrategy(Rectangle2D original, boolean ratioFixed, double ratio, Rectangle2D bounds) { - super(ratioFixed, ratio, bounds); - southeasternCorner = new Point2D(original.getMaxX(), original.getMaxY()); - } - - // IMPLEMENTATION OF 'AbstractFixedPointChangeStrategy' - - /** - * {@inheritDoc} - */ - @Override - protected Point2D getFixedCorner() { - return southeasternCorner; - } - -} diff --git a/src/impl/org/controlsfx/tools/rectangle/change/ToSouthChangeStrategy.java b/src/impl/org/controlsfx/tools/rectangle/change/ToSouthChangeStrategy.java deleted file mode 100644 index 3ea9f78..0000000 --- a/src/impl/org/controlsfx/tools/rectangle/change/ToSouthChangeStrategy.java +++ /dev/null @@ -1,104 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.tools.rectangle.change; - -import impl.org.controlsfx.tools.rectangle.Edge2D; -import javafx.geometry.Orientation; -import javafx.geometry.Point2D; -import javafx.geometry.Rectangle2D; - -/** - * A strategy which enlarges an existing rectangle to the south. - */ -public class ToSouthChangeStrategy extends AbstractFixedEdgeChangeStrategy { - - /* - * The new rectangle will have the existing rectangle's northern edge as a fixed edge. The parallel edge will - * be defined by the current point (modulo the ratio which will be respected if enforced), which is handled by the - * superclass. - */ - - // ATTRIBUTES - - /** - * The new rectangle's northern edge. - */ - private final Edge2D northernEdge; - - // CONSTRUCTOR - - /** - * Creates a new change strategy which enlarges the specified {@code original} rectangle to the south. The given - * {@code ratio} is enforced when indicated by {@code ratioFixed}. - * - * @param original - * the original rectangle - * @param ratioFixed - * indicates whether the rectangle's ratio will be fixed to the {@code ratio} - * @param ratio - * the possibly fixed ratio of the rectangle created by this strategy - * @param bounds - * the bounds within which the rectangle can be resized - */ - public ToSouthChangeStrategy(Rectangle2D original, boolean ratioFixed, double ratio, Rectangle2D bounds) { - super(ratioFixed, ratio, bounds); - Point2D edgeCenterPoint = new Point2D((original.getMinX() + original.getMaxX()) / 2, original.getMinY()); - northernEdge = new Edge2D(edgeCenterPoint, Orientation.HORIZONTAL, original.getMaxX() - original.getMinX()); - } - - /** - * Creates a new change strategy which enlarges the specified {@code original} rectangle to the northeast. The given - * {@code ratio} is enforced when indicated by {@code ratioFixed}. - * - * @param original - * the original rectangle - * @param ratioFixed - * indicates whether the rectangle's ratio will be fixed to the {@code ratio} - * @param ratio - * the possibly fixed ratio of the rectangle created by this strategy - * @param maxX - * the maximal x-coordinate of the right edge of the created rectangles; must be greater than or equal to - * the previous rectangle's width - * @param maxY - * the maximal y-coordinate of the lower edge of the created rectangles; must be greater than or equal to - * the previous rectangle's height - */ - public ToSouthChangeStrategy(Rectangle2D original, boolean ratioFixed, double ratio, double maxX, double maxY) { - this(original, ratioFixed, ratio, new Rectangle2D(0, 0, maxX, maxY)); - } - - // IMPLEMENTATION OF 'AbstractFixedEdgeChangeStrategy' - - /** - * {@inheritDoc} - */ - @Override - protected Edge2D getFixedEdge() { - return northernEdge; - } - -} diff --git a/src/impl/org/controlsfx/tools/rectangle/change/ToSoutheastChangeStrategy.java b/src/impl/org/controlsfx/tools/rectangle/change/ToSoutheastChangeStrategy.java deleted file mode 100644 index 430c3f5..0000000 --- a/src/impl/org/controlsfx/tools/rectangle/change/ToSoutheastChangeStrategy.java +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.tools.rectangle.change; - -import javafx.geometry.Point2D; -import javafx.geometry.Rectangle2D; - -/** - * A strategy which enlarges an existing rectangle to the southeast. - */ -public class ToSoutheastChangeStrategy extends AbstractFixedPointChangeStrategy { - - /* - * The new rectangle will have the existing rectangle's northwestern corner as a fixed corner. The other corner will - * always be the current point (modulo the ratio which will be respected if enforced), which is handled by the - * superclass. - */ - - // ATTRIBUTES - - /** - * The new rectangle's northwestern corner. - */ - private final Point2D northwesternCorner; - - // CONSTRUCTOR - - /** - * Creates a new change strategy which enlarges the specified {@code original} rectangle to the southeast. The given - * {@code ratio} is enforced when indicated by {@code ratioFixed}. - * - * @param original - * the original rectangle - * @param ratioFixed - * indicates whether the rectangle's ratio will be fixed to the {@code ratio} - * @param ratio - * the possibly fixed ratio of the rectangle created by this strategy - * @param bounds - * the bounds within which the new rectangle must be contained - */ - public ToSoutheastChangeStrategy(Rectangle2D original, boolean ratioFixed, double ratio, Rectangle2D bounds) { - super(ratioFixed, ratio, bounds); - northwesternCorner = new Point2D(original.getMinX(), original.getMinY()); - } - - // IMPLEMENTATION OF 'AbstractFixedPointChangeStrategy' - - /** - * {@inheritDoc} - */ - @Override - protected Point2D getFixedCorner() { - return northwesternCorner; - } - -} diff --git a/src/impl/org/controlsfx/tools/rectangle/change/ToSouthwestChangeStrategy.java b/src/impl/org/controlsfx/tools/rectangle/change/ToSouthwestChangeStrategy.java deleted file mode 100644 index cad2aee..0000000 --- a/src/impl/org/controlsfx/tools/rectangle/change/ToSouthwestChangeStrategy.java +++ /dev/null @@ -1,82 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.tools.rectangle.change; - -import javafx.geometry.Point2D; -import javafx.geometry.Rectangle2D; - -/** - * A strategy which enlarges an existing rectangle to the southwest. - * - * @author pan - */ -public class ToSouthwestChangeStrategy extends AbstractFixedPointChangeStrategy { - - /* - * The new rectangle will have the existing rectangle's northeastern corner as a fixed corner. The other corner will - * always be the current point (modulo the ratio which will be respected if enforced), which is handled by the - * superclass. - */ - - // ATTRIBUTES - - /** - * The new rectangle's northeastern corner. - */ - private final Point2D northeasternCorner; - - // CONSTRUCTOR - - /** - * Creates a new change strategy which enlarges the specified {@code original} rectangle to the southwest. The given - * {@code ratio} is enforced when indicated by {@code ratioFixed}. - * - * @param original - * the original rectangle - * @param ratioFixed - * indicates whether the rectangle's ratio will be fixed to the {@code ratio} - * @param ratio - * the possibly fixed ratio of the rectangle created by this strategy - * @param bounds - * the bounds within which the new rectangle must be contained - */ - public ToSouthwestChangeStrategy(Rectangle2D original, boolean ratioFixed, double ratio, Rectangle2D bounds) { - super(ratioFixed, ratio, bounds); - northeasternCorner = new Point2D(original.getMaxX(), original.getMinY()); - } - - // IMPLEMENTATION OF 'AbstractFixedPointChangeStrategy' - - /** - * {@inheritDoc} - */ - @Override - protected Point2D getFixedCorner() { - return northeasternCorner; - } - -} diff --git a/src/impl/org/controlsfx/tools/rectangle/change/ToWestChangeStrategy.java b/src/impl/org/controlsfx/tools/rectangle/change/ToWestChangeStrategy.java deleted file mode 100644 index 4500992..0000000 --- a/src/impl/org/controlsfx/tools/rectangle/change/ToWestChangeStrategy.java +++ /dev/null @@ -1,104 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.tools.rectangle.change; - -import impl.org.controlsfx.tools.rectangle.Edge2D; -import javafx.geometry.Orientation; -import javafx.geometry.Point2D; -import javafx.geometry.Rectangle2D; - -/** - * A strategy which enlarges an existing rectangle to the west. - */ -public class ToWestChangeStrategy extends AbstractFixedEdgeChangeStrategy { - - /* - * The new rectangle will have the existing rectangle's eastern edge as a fixed edge. The parallel edge will - * be defined by the current point (modulo the ratio which will be respected if enforced), which is handled by the - * superclass. - */ - - // ATTRIBUTES - - /** - * The new rectangle's eastern edge. - */ - private final Edge2D easternEdge; - - // CONSTRUCTOR - - /** - * Creates a new change strategy which enlarges the specified {@code original} rectangle to the west. The given - * {@code ratio} is enforced when indicated by {@code ratioFixed}. - * - * @param original - * the original rectangle - * @param ratioFixed - * indicates whether the rectangle's ratio will be fixed to the {@code ratio} - * @param ratio - * the possibly fixed ratio of the rectangle created by this strategy - * @param bounds - * the bounds within which the rectangle can be resized - */ - public ToWestChangeStrategy(Rectangle2D original, boolean ratioFixed, double ratio, Rectangle2D bounds) { - super(ratioFixed, ratio, bounds); - Point2D edgeCenterPoint = new Point2D(original.getMaxX(), (original.getMinY() + original.getMaxY()) / 2); - easternEdge = new Edge2D(edgeCenterPoint, Orientation.VERTICAL, original.getMaxY() - original.getMinY()); - } - - /** - * Creates a new change strategy which enlarges the specified {@code original} rectangle to the northeast. The given - * {@code ratio} is enforced when indicated by {@code ratioFixed}. - * - * @param original - * the original rectangle - * @param ratioFixed - * indicates whether the rectangle's ratio will be fixed to the {@code ratio} - * @param ratio - * the possibly fixed ratio of the rectangle created by this strategy - * @param maxX - * the maximal x-coordinate of the right edge of the created rectangles; must be greater than or equal to - * the previous rectangle's width - * @param maxY - * the maximal y-coordinate of the lower edge of the created rectangles; must be greater than or equal to - * the previous rectangle's height - */ - public ToWestChangeStrategy(Rectangle2D original, boolean ratioFixed, double ratio, double maxX, double maxY) { - this(original, ratioFixed, ratio, new Rectangle2D(0, 0, maxX, maxY)); - } - - // IMPLEMENTATION OF 'AbstractFixedEdgeChangeStrategy' - - /** - * {@inheritDoc} - */ - @Override - protected Edge2D getFixedEdge() { - return easternEdge; - } - -} diff --git a/src/impl/org/controlsfx/version/VersionChecker.java b/src/impl/org/controlsfx/version/VersionChecker.java deleted file mode 100644 index 4e91d0f..0000000 --- a/src/impl/org/controlsfx/version/VersionChecker.java +++ /dev/null @@ -1,222 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package impl.org.controlsfx.version; - -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.util.Properties; - -import com.sun.javafx.runtime.VersionInfo; - -public class VersionChecker { - - private static final String javaFXVersion; - private static final String controlsFXSpecTitle; - private static final String controlsFXSpecVersion; - private static final String controlsFXImpVersion; - - private static final Package controlsFX; - - private static Properties props; - - static { - controlsFX = VersionChecker.class.getPackage(); - - javaFXVersion = VersionInfo.getVersion(); - controlsFXSpecTitle = getControlsFXSpecificationTitle(); - controlsFXSpecVersion = getControlsFXSpecificationVersion(); - controlsFXImpVersion = getControlsFXImplementationVersion(); - } - - private VersionChecker() { - // no-op - } - - public static void doVersionCheck() { - // We keep ControlsFX bleeding edge, and we try to let our version numbers - // do the talking. However, we can't always ensure people do the right - // thing, so here we will check the ControlsFX and JavaFX version numbers, - // to ensure they match. - // Fortunately, our system is simple at present: we use the - // 'controlsFXSpec' value to represent what we require. In other - // words, ControlsFX 8.0.0 has controlsFXSpecVersion of 8.0.0, so it will work on - // JavaFX 8.0.0 and later versions. Conversely, ControlsFX 8.0.6_20 has a controlsFXSpecVersion of - // 8.0.20 (controlsFXSpecTitle of Java 8u20), which means that ControlsFX will only work on JavaFX 8u20 - // and later versions. - - if (controlsFXSpecVersion == null) { - // FIXME temporary fix to allow ControlsFX to work when run inside - // an IDE (i.e. for developers of ControlsFX). - return; - } - - Comparable[] splitSpecVersion = toComparable(controlsFXSpecVersion.split("\\.")); //$NON-NLS-1$ - - // javaFXVersion may contain '-' like 8.0.20-ea so replace them with '.' before splitting. - Comparable[] splitJavaVersion = toComparable(javaFXVersion.replace('-', '.').split("\\.")); //$NON-NLS-1$ - - boolean notSupportedVersion = false; - - // Check Major Version - if (splitSpecVersion[0].compareTo(splitJavaVersion[0]) > 0) { - notSupportedVersion = true; - } else if (splitSpecVersion[0].compareTo(splitJavaVersion[0]) == 0) { - // Check Minor Version - if (splitSpecVersion[1].compareTo(splitJavaVersion[2])>0) { - notSupportedVersion = true; - } - } - - if (notSupportedVersion) { - throw new RuntimeException("ControlsFX Error: ControlsFX " + //$NON-NLS-1$ - controlsFXImpVersion + " requires at least " + controlsFXSpecTitle); //$NON-NLS-1$ - } - } - - private static Comparable<Comparable>[] toComparable(String[] tokens) { - Comparable[] ret= new Comparable[tokens.length]; - for (int i = 0; i<tokens.length; i++) { - String token = tokens[i]; - try { - ret[i] = new Integer(token); - } - catch (NumberFormatException e) { - ret[i] = token; - } - } - return ret; - } - - private static String getControlsFXSpecificationTitle() { - // firstly try to read from manifest - try { - return controlsFX.getSpecificationTitle(); - } catch (NullPointerException e) { - // no-op - } - - // try to read it from the controlsfx-build.properties if running - // from within an IDE - return getPropertyValue("controlsfx_specification_title"); //$NON-NLS-1$ - - -// try { -// Properties prop = new Properties(); -// File file = new File("../controlsfx-build.properties"); -// if (file.exists()) { -// prop.load(new FileReader(file)); -// String version = prop.getProperty("controlsfx_specification_title"); -// if (version != null && !version.isEmpty()) { -// return version; -// } -// } -// } catch (IOException e) { -// // no-op -// } -// -// return null; - } - - private static String getControlsFXSpecificationVersion() { - - // firstly try to read from manifest - try { - return controlsFX.getSpecificationVersion(); - } catch (NullPointerException e) { - // no-op - } - - // try to read it from the controlsfx-build.properties if running - // from within an IDE - return getPropertyValue("controlsfx_specification_title"); //$NON-NLS-1$ - -// try { -// Properties prop = new Properties(); -// File file = new File("../controlsfx-build.properties"); -// if (file.exists()) { -// prop.load(new FileReader(file)); -// String version = prop.getProperty("controlsfx_specification_version"); -// if (version != null && !version.isEmpty()) { -// return version; -// } -// } -// } catch (IOException e) { -// // no-op -// } -// -// return null; - } - - private static String getControlsFXImplementationVersion() { - - // firstly try to read from manifest - try { - return controlsFX.getImplementationVersion(); - } catch (NullPointerException e) { - // no-op - } - - // try to read it from the controlsfx-build.properties if running - // from within an IDE - - return getPropertyValue("controlsfx_specification_title") + //$NON-NLS-1$ - getPropertyValue("artifact_suffix"); //$NON-NLS-1$ - - -// try { -// Properties prop = new Properties(); -// File file = new File("../controlsfx-build.properties"); -// if (file.exists()) { -// prop.load(new FileReader(file)); -// String version = prop.getProperty("controlsfx_version"); -// if (version != null && !version.isEmpty()) { -// return version; -// } -// } -// } catch (IOException e) { -// // no-op -// } -// -// return null; - } - - private static synchronized String getPropertyValue(String key) { - - if ( props == null ) { - try { - File file = new File("../controlsfx-build.properties"); //$NON-NLS-1$ - if (file.exists()) { - props.load(new FileReader(file)); - } - } catch (IOException e) { - // no-op - } - } - return props.getProperty(key); - } -} diff --git a/src/org/controlsfx/control/BreadCrumbBar.java b/src/org/controlsfx/control/BreadCrumbBar.java deleted file mode 100644 index 38bfe10..0000000 --- a/src/org/controlsfx/control/BreadCrumbBar.java +++ /dev/null @@ -1,343 +0,0 @@ -/** - * Copyright (c) 2014, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control; - -import impl.org.controlsfx.skin.BreadCrumbBarSkin; -import impl.org.controlsfx.skin.BreadCrumbBarSkin.BreadCrumbButton; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.ObjectPropertyBase; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.event.Event; -import javafx.event.EventDispatchChain; -import javafx.event.EventHandler; -import javafx.event.EventType; -import javafx.scene.control.Button; -import javafx.scene.control.Skin; -import javafx.scene.control.TreeItem; -import javafx.util.Callback; - -import com.sun.javafx.event.EventHandlerManager; - -/** - * Represents a bread crumb bar. This control is useful to visualize and navigate - * a hierarchical path structure, such as file systems. - * - * <p>Shown below is a screenshot of the BreadCrumbBar control: - * - * <br> - * <center> - * <img src="breadCrumbBar.png" alt="Screenshot of BreadCrumbBar"> - * </center> - */ -public class BreadCrumbBar<T> extends ControlsFXControl { - - private final EventHandlerManager eventHandlerManager = new EventHandlerManager(this); - - - /** - * Represents an Event which is fired when a bread crumb was activated. - */ - @SuppressWarnings("serial") - public static class BreadCrumbActionEvent<TE> extends Event { - - /** - * The event type that should be listened to by people interested in - * knowing when the {@link BreadCrumbBar#selectedCrumbProperty() selected crumb} - * has changed. - */ - @SuppressWarnings("rawtypes") - public static final EventType<BreadCrumbActionEvent> CRUMB_ACTION = new EventType<>("CRUMB_ACTION"); //$NON-NLS-1$ - - private final TreeItem<TE> selectedCrumb; - - /** - * Creates a new event that can subsequently be fired. - */ - public BreadCrumbActionEvent(TreeItem<TE> selectedCrumb) { - super(CRUMB_ACTION); - this.selectedCrumb = selectedCrumb; - } - - /** - * Returns the crumb which was the action target. - */ - public TreeItem<TE> getSelectedCrumb() { - return selectedCrumb; - } - } - - - - /** - * Construct a tree model from the flat list which then can be set - * as selectedCrumb node to be shown - * @param crumbs - */ - public static <T> TreeItem<T> buildTreeModel(@SuppressWarnings("unchecked") T... crumbs){ - TreeItem<T> subRoot = null; - for (T crumb : crumbs) { - TreeItem<T> currentNode = new TreeItem<>(crumb); - if(subRoot == null){ - subRoot = currentNode; - }else{ - subRoot.getChildren().add(currentNode); - subRoot = currentNode; - } - } - return subRoot; - } - - - - - - - /*************************************************************************** - * - * Private fields - * - **************************************************************************/ - - - /** - * Default crumb node factory. This factory is used when no custom factory is specified by the user. - */ - private final Callback<TreeItem<T>, Button> defaultCrumbNodeFactory = new Callback<TreeItem<T>, Button>(){ - @Override - public Button call(TreeItem<T> crumb) { - return new BreadCrumbBarSkin.BreadCrumbButton(crumb.getValue() != null ? crumb.getValue().toString() : ""); //$NON-NLS-1$ - } - }; - - - - - /*************************************************************************** - * * - * Constructors * - * * - **************************************************************************/ - - /** - * Creates an empty bread crumb bar - */ - public BreadCrumbBar(){ - this(null); - } - - /** - * Creates a bread crumb bar with the given TreeItem as the currently - * selected crumb. - */ - public BreadCrumbBar(TreeItem<T> selectedCrumb) { - getStyleClass().add(DEFAULT_STYLE_CLASS); - setSelectedCrumb(selectedCrumb); - setCrumbFactory(defaultCrumbNodeFactory); - } - - - - /*************************************************************************** - * * - * Public API * - * * - **************************************************************************/ - - /** {@inheritDoc} */ - @Override public EventDispatchChain buildEventDispatchChain(EventDispatchChain tail) { - return tail.prepend(eventHandlerManager); - } - - - - /*************************************************************************** - * * - * Properties * - * * - **************************************************************************/ - - // --- selectedCrumb - /** - * Represents the bottom-most path node (the node on the most-right side in - * terms of the bread crumb bar). The full path is then being constructed - * using getParent() of the tree-items. - * - * <p> - * Consider the following hierarchy: - * [Root] > [Folder] > [SubFolder] > [myfile.txt] - * - * To show the above bread crumb bar, you have to set the [myfile.txt] tree-node as selected crumb. - */ - public final ObjectProperty<TreeItem<T>> selectedCrumbProperty() { - return selectedCrumb; - } - private final ObjectProperty<TreeItem<T>> selectedCrumb = - new SimpleObjectProperty<>(this, "selectedCrumb"); //$NON-NLS-1$ - - /** - * Get the current target path - */ - public final TreeItem<T> getSelectedCrumb() { - return selectedCrumb.get(); - } - - /** - * Select one node in the BreadCrumbBar for being the bottom-most path node. - * @param selectedCrumb - */ - public final void setSelectedCrumb(TreeItem<T> selectedCrumb){ - this.selectedCrumb.set(selectedCrumb); - } - - - // --- autoNavigation - /** - * Enable or disable auto navigation (default is enabled). - * If auto navigation is enabled, it will automatically navigate to the crumb which was clicked by the user. - * @return a {@link BooleanProperty} - */ - public final BooleanProperty autoNavigationEnabledProperty() { - return autoNavigation; - } - - private final BooleanProperty autoNavigation = - new SimpleBooleanProperty(this, "autoNavigationEnabled", true); //$NON-NLS-1$ - - /** - * Return whether auto-navigation is enabled. - * @return whether auto-navigation is enabled. - */ - public final boolean isAutoNavigationEnabled() { - return autoNavigation.get(); - } - - /** - * Enable or disable auto navigation (default is enabled). - * If auto navigation is enabled, it will automatically navigate to the crumb which was clicked by the user. - * @param enabled - */ - public final void setAutoNavigationEnabled(boolean enabled) { - autoNavigation.set(enabled); - } - - - - // --- crumbFactory - /** - * Return an ObjectProperty of the CrumbFactory. - * @return an ObjectProperty of the CrumbFactory. - */ - public final ObjectProperty<Callback<TreeItem<T>, Button>> crumbFactoryProperty() { - return crumbFactory; - } - - private final ObjectProperty<Callback<TreeItem<T>, Button>> crumbFactory = - new SimpleObjectProperty<>(this, "crumbFactory"); //$NON-NLS-1$ - - /** - * Sets the crumb factory to create (custom) {@link BreadCrumbButton} instances. - * <code>null</code> is not allowed and will result in a fall back to the default factory. - * @param value - */ - public final void setCrumbFactory(Callback<TreeItem<T>, Button> value) { - if(value == null){ - value = defaultCrumbNodeFactory; - } - crumbFactoryProperty().set(value); - } - - /** - * Returns the cell factory that will be used to create {@link BreadCrumbButton} - * instances - */ - public final Callback<TreeItem<T>, Button> getCrumbFactory() { - return crumbFactory.get(); - } - - - // --- onCrumbAction - /** - * @return an ObjectProperty representing the crumbAction EventHandler being used. - */ - public final ObjectProperty<EventHandler<BreadCrumbActionEvent<T>>> onCrumbActionProperty() { - return onCrumbAction; - } - - /** - * Set a new EventHandler for when a user selects a crumb. - * @param value - */ - public final void setOnCrumbAction(EventHandler<BreadCrumbActionEvent<T>> value) { - onCrumbActionProperty().set(value); - } - - /** - * Return the EventHandler currently used when a user selects a crumb. - * @return the EventHandler currently used when a user selects a crumb. - */ - public final EventHandler<BreadCrumbActionEvent<T>> getOnCrumbAction() { - return onCrumbActionProperty().get(); - } - - private ObjectProperty<EventHandler<BreadCrumbActionEvent<T>>> onCrumbAction = new ObjectPropertyBase<EventHandler<BreadCrumbBar.BreadCrumbActionEvent<T>>>() { - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Override protected void invalidated() { - eventHandlerManager.setEventHandler(BreadCrumbActionEvent.CRUMB_ACTION, (EventHandler<BreadCrumbActionEvent>)(Object)get()); - } - - @Override - public Object getBean() { - return BreadCrumbBar.this; - } - - @Override - public String getName() { - return "onCrumbAction"; //$NON-NLS-1$ - } - }; - - - /*************************************************************************** - * * - * Stylesheet Handling * - * * - **************************************************************************/ - - private static final String DEFAULT_STYLE_CLASS = "bread-crumb-bar"; //$NON-NLS-1$ - - /** {@inheritDoc} */ - @Override protected Skin<?> createDefaultSkin() { - return new BreadCrumbBarSkin<>(this); - } - - /** {@inheritDoc} */ - @Override public String getUserAgentStylesheet() { - return getUserAgentStylesheet(BreadCrumbBar.class, "breadcrumbbar.css"); - } -} diff --git a/src/org/controlsfx/control/CheckBitSetModelBase.java b/src/org/controlsfx/control/CheckBitSetModelBase.java deleted file mode 100644 index 0ba976f..0000000 --- a/src/org/controlsfx/control/CheckBitSetModelBase.java +++ /dev/null @@ -1,315 +0,0 @@ -/** - * Copyright (c) 2013, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control; - -import java.util.BitSet; -import java.util.Map; - -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.collections.ListChangeListener; -import javafx.collections.ObservableList; - -import com.sun.javafx.collections.MappingChange; -import com.sun.javafx.collections.NonIterableChange; -import com.sun.javafx.scene.control.ReadOnlyUnbackedObservableList; - -// not public API -abstract class CheckBitSetModelBase<T> implements IndexedCheckModel<T> { - - /*********************************************************************** - * * - * Internal properties * - * * - **********************************************************************/ - - private final Map<T, BooleanProperty> itemBooleanMap; - - private final BitSet checkedIndices; - private final ReadOnlyUnbackedObservableList<Integer> checkedIndicesList; - private final ReadOnlyUnbackedObservableList<T> checkedItemsList; - - - - /*********************************************************************** - * * - * Constructors * - * * - **********************************************************************/ - - CheckBitSetModelBase(final Map<T, BooleanProperty> itemBooleanMap) { - this.itemBooleanMap = itemBooleanMap; - - this.checkedIndices = new BitSet(); - - this.checkedIndicesList = new ReadOnlyUnbackedObservableList<Integer>() { - @Override public Integer get(int index) { - if (index < 0 || index >= getItemCount()) return -1; - - for (int pos = 0, val = checkedIndices.nextSetBit(0); - val >= 0 || pos == index; - pos++, val = checkedIndices.nextSetBit(val+1)) { - if (pos == index) return val; - } - - return -1; - } - - @Override public int size() { - return checkedIndices.cardinality(); - } - - @Override public boolean contains(Object o) { - if (o instanceof Number) { - Number n = (Number) o; - int index = n.intValue(); - - return index >= 0 && index < checkedIndices.length() && - checkedIndices.get(index); - } - - return false; - } - }; - - this.checkedItemsList = new ReadOnlyUnbackedObservableList<T>() { - @Override public T get(int i) { - int pos = checkedIndicesList.get(i); - if (pos < 0 || pos >= getItemCount()) return null; - return getItem(pos); - } - - @Override public int size() { - return checkedIndices.cardinality(); - } - }; - - final MappingChange.Map<Integer,T> map = f -> getItem(f); - - checkedIndicesList.addListener(new ListChangeListener<Integer>() { - @Override public void onChanged(final Change<? extends Integer> c) { - // when the selectedIndices ObservableList changes, we manually call - // the observers of the selectedItems ObservableList. - boolean hasRealChangeOccurred = false; - while (c.next() && ! hasRealChangeOccurred) { - hasRealChangeOccurred = c.wasAdded() || c.wasRemoved(); - } - - if (hasRealChangeOccurred) { - c.reset(); - checkedItemsList.callObservers(new MappingChange<>(c, map, checkedItemsList)); - } - c.reset(); - } - }); - - // this code is to handle the situation where a developer is manually - // toggling the check model, and expecting the UI to update (without - // this it won't happen!). - getCheckedItems().addListener(new ListChangeListener<T>() { - @Override public void onChanged(ListChangeListener.Change<? extends T> c) { - while (c.next()) { - if (c.wasAdded()) { - for (T item : c.getAddedSubList()) { - BooleanProperty p = getItemBooleanProperty(item); - if (p != null) { - p.set(true); - } - } - } - - if (c.wasRemoved()) { - for (T item : c.getRemoved()) { - BooleanProperty p = getItemBooleanProperty(item); - if (p != null) { - p.set(false); - } - } - } - } - } - }); - } - - - - /*********************************************************************** - * * - * Abstract API * - * * - **********************************************************************/ - - @Override - public abstract T getItem(int index); - - @Override - public abstract int getItemCount(); - - @Override - public abstract int getItemIndex(T item); - - BooleanProperty getItemBooleanProperty(T item) { - return itemBooleanMap.get(item); - } - - - /*********************************************************************** - * * - * Public selection API * - * * - **********************************************************************/ - - /** - * Returns a read-only list of the currently checked indices in the CheckBox. - */ - @Override - public ObservableList<Integer> getCheckedIndices() { - return checkedIndicesList; - } - - /** - * Returns a read-only list of the currently checked items in the CheckBox. - */ - @Override - public ObservableList<T> getCheckedItems() { - return checkedItemsList; - } - - /** {@inheritDoc} */ - @Override - public void checkAll() { - for (int i = 0; i < getItemCount(); i++) { - check(i); - } - } - - /** {@inheritDoc} */ - @Override - public void checkIndices(int... indices) { - for (int i = 0; i < indices.length; i++) { - check(indices[i]); - } - } - - /** {@inheritDoc} */ - @Override public void clearCheck(T item) { - int index = getItemIndex(item); - clearCheck(index); - } - - /** {@inheritDoc} */ - @Override - public void clearChecks() { - for( int index = 0; index < checkedIndices.length(); index++) { - clearCheck(index); - } - } - - /** {@inheritDoc} */ - @Override - public void clearCheck(int index) { - if (index < 0 || index >= getItemCount()) return; - checkedIndices.clear(index); - - final int changeIndex = checkedIndicesList.indexOf(index); - checkedIndicesList.callObservers(new NonIterableChange.SimpleRemovedChange<>(changeIndex, changeIndex, index, checkedIndicesList)); - } - - /** {@inheritDoc} */ - @Override - public boolean isEmpty() { - return checkedIndices.isEmpty(); - } - - /** {@inheritDoc} */ - @Override public boolean isChecked(T item) { - int index = getItemIndex(item); - return isChecked(index); - } - - /** {@inheritDoc} */ - @Override - public boolean isChecked(int index) { - return checkedIndices.get(index); - } - - /** {@inheritDoc} */ - @Override - public void check(int index) { - if (index < 0 || index >= getItemCount()) return; - checkedIndices.set(index); - final int changeIndex = checkedIndicesList.indexOf(index); - checkedIndicesList.callObservers(new NonIterableChange.SimpleAddChange<>(changeIndex, changeIndex+1, checkedIndicesList)); - } - - /** {@inheritDoc} */ - @Override - public void check(T item) { - int index = getItemIndex(item); - check(index); - } - - - - - /*********************************************************************** - * * - * Private implementation * - * * - **********************************************************************/ - - protected void updateMap() { - // reset the map - itemBooleanMap.clear(); - for (int i = 0; i < getItemCount(); i++) { - final int index = i; - final T item = getItem(index); - - final BooleanProperty booleanProperty = new SimpleBooleanProperty(item, "selected", false); //$NON-NLS-1$ - itemBooleanMap.put(item, booleanProperty); - - // this is where we listen to changes to the boolean properties, - // updating the selected indices list (and therefore indirectly - // the selected items list) when the checkbox is toggled - booleanProperty.addListener(new InvalidationListener() { - @Override public void invalidated(Observable o) { - if (booleanProperty.get()) { - checkedIndices.set(index); - final int changeIndex = checkedIndicesList.indexOf(index); - checkedIndicesList.callObservers(new NonIterableChange.SimpleAddChange<>(changeIndex, changeIndex+1, checkedIndicesList)); - } else { - final int changeIndex = checkedIndicesList.indexOf(index); - checkedIndices.clear(index); - checkedIndicesList.callObservers(new NonIterableChange.SimpleRemovedChange<>(changeIndex, changeIndex, index, checkedIndicesList)); - } - } - }); - } - } -} \ No newline at end of file diff --git a/src/org/controlsfx/control/CheckComboBox.java b/src/org/controlsfx/control/CheckComboBox.java deleted file mode 100644 index 86f175e..0000000 --- a/src/org/controlsfx/control/CheckComboBox.java +++ /dev/null @@ -1,297 +0,0 @@ -/** - * Copyright (c) 2013, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control; - -import impl.org.controlsfx.skin.CheckComboBoxSkin; - -import java.util.HashMap; -import java.util.Map; - -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.collections.FXCollections; -import javafx.collections.ListChangeListener; -import javafx.collections.ObservableList; -import javafx.scene.control.CheckBox; -import javafx.scene.control.Skin; -import javafx.util.StringConverter; - -/** - * A simple UI control that makes it possible to select zero or more items within - * a ComboBox-like control. Each row item shows a {@link CheckBox}, and the state - * of each row can be queried via the {@link #checkModelProperty() check model}. - * - * <h3>Screenshot</h3> - * <p>The following screenshot shows the CheckComboBox with some sample data: - * - * <br> - * <img src="checkComboBox.png" alt="Screenshot of CheckComboBox"> - * - * <h3>Code Example:</h3> - * <p>To create the CheckComboBox shown in the screenshot, simply do the - * following: - * - * <pre> - * {@code - * // create the data to show in the CheckComboBox - * final ObservableList<String> strings = FXCollections.observableArrayList(); - * for (int i = 0; i <= 100; i++) { - * strings.add("Item " + i); - * } - * - * // Create the CheckComboBox with the data - * final CheckComboBox<String> checkComboBox = new CheckComboBox<String>(strings); - * - * // and listen to the relevant events (e.g. when the selected indices or - * // selected items change). - * checkComboBox.getCheckModel().getSelectedItems().addListener(new ListChangeListener<String>() { - * public void onChanged(ListChangeListener.Change<? extends String> c) { - * System.out.println(checkComboBox.getCheckModel().getSelectedItems()); - * } - * });} - * }</pre> - * - * @param <T> The type of the data in the ComboBox. - */ -public class CheckComboBox<T> extends ControlsFXControl { - - /************************************************************************** - * - * Private fields - * - **************************************************************************/ - - private final ObservableList<T> items; - private final Map<T, BooleanProperty> itemBooleanMap; - - - - /************************************************************************** - * - * Constructors - * - **************************************************************************/ - - /** - * Creates a new CheckComboBox instance with an empty list of choices. - */ - public CheckComboBox() { - this(null); - } - - /** - * Creates a new CheckComboBox instance with the given items available as - * choices. - * - * @param items The items to display within the CheckComboBox. - */ - public CheckComboBox(final ObservableList<T> items) { - final int initialSize = items == null ? 32 : items.size(); - - this.itemBooleanMap = new HashMap<>(initialSize); - this.items = items == null ? FXCollections.<T>observableArrayList() : items; - setCheckModel(new CheckComboBoxBitSetCheckModel<>(this.items, itemBooleanMap)); - } - - - - /************************************************************************** - * - * Public API - * - **************************************************************************/ - - /** {@inheritDoc} */ - @Override protected Skin<?> createDefaultSkin() { - return new CheckComboBoxSkin<>(this); - } - - /** - * Represents the list of choices available to the user, from which they can - * select zero or more items. - */ - public ObservableList<T> getItems() { - return items; - } - - /** - * Returns the {@link BooleanProperty} for a given item index in the - * CheckComboBox. This is useful if you want to bind to the property. - */ - public BooleanProperty getItemBooleanProperty(int index) { - if (index < 0 || index >= items.size()) return null; - return getItemBooleanProperty(getItems().get(index)); - } - - /** - * Returns the {@link BooleanProperty} for a given item in the - * CheckComboBox. This is useful if you want to bind to the property. - */ - public BooleanProperty getItemBooleanProperty(T item) { - return itemBooleanMap.get(item); - } - - - - /************************************************************************** - * - * Properties - * - **************************************************************************/ - - // --- Check Model - private ObjectProperty<IndexedCheckModel<T>> checkModel = - new SimpleObjectProperty<>(this, "checkModel"); //$NON-NLS-1$ - - /** - * Sets the 'check model' to be used in the CheckComboBox - this is the - * code that is responsible for representing the selected state of each - * {@link CheckBox} - that is, whether each {@link CheckBox} is checked or - * not (and not to be confused with the - * selection model concept, which is used in the ComboBox control to - * represent the selection state of each row).. - */ - public final void setCheckModel(IndexedCheckModel<T> value) { - checkModelProperty().set(value); - } - - /** - * Returns the currently installed check model. - */ - public final IndexedCheckModel<T> getCheckModel() { - return checkModel == null ? null : checkModel.get(); - } - - /** - * The check model provides the API through which it is possible - * to check single or multiple items within a CheckComboBox, as well as inspect - * which items have been checked by the user. Note that it has a generic - * type that must match the type of the CheckComboBox itself. - */ - public final ObjectProperty<IndexedCheckModel<T>> checkModelProperty() { - return checkModel; - } - - // --- converter - private ObjectProperty<StringConverter<T>> converter = - new SimpleObjectProperty<StringConverter<T>>(this, "converter"); - - /** - * A {@link StringConverter} that, given an object of type T, will - * return a String that can be used to represent the object visually. - */ - public final ObjectProperty<StringConverter<T>> converterProperty() { - return converter; - } - - /** - * Sets the {@link StringConverter} to be used in the control. - * @param value A {@link StringConverter} that, given an object of type T, will - * return a String that can be used to represent the object visually. - */ - public final void setConverter(StringConverter<T> value) { - converterProperty().set(value); - } - - /** - * A {@link StringConverter} that, given an object of type T, will - * return a String that can be used to represent the object visually. - */ - public final StringConverter<T> getConverter() { - return converterProperty().get(); - } - - - - /************************************************************************** - * - * Implementation - * - **************************************************************************/ - - - - - /************************************************************************** - * - * Support classes - * - **************************************************************************/ - - private static class CheckComboBoxBitSetCheckModel<T> extends CheckBitSetModelBase<T> { - - /*********************************************************************** - * * - * Internal properties * - * * - **********************************************************************/ - - private final ObservableList<T> items; - - - - /*********************************************************************** - * * - * Constructors * - * * - **********************************************************************/ - - CheckComboBoxBitSetCheckModel(final ObservableList<T> items, final Map<T, BooleanProperty> itemBooleanMap) { - super(itemBooleanMap); - - this.items = items; - this.items.addListener(new ListChangeListener<T>() { - @Override public void onChanged(Change<? extends T> c) { - updateMap(); - } - }); - - updateMap(); - } - - - - /*********************************************************************** - * * - * Implementing abstract API * - * * - **********************************************************************/ - - @Override public T getItem(int index) { - return items.get(index); - } - - @Override public int getItemCount() { - return items.size(); - } - - @Override public int getItemIndex(T item) { - return items.indexOf(item); - } - } -} diff --git a/src/org/controlsfx/control/CheckListView.java b/src/org/controlsfx/control/CheckListView.java deleted file mode 100644 index 1ec23b0..0000000 --- a/src/org/controlsfx/control/CheckListView.java +++ /dev/null @@ -1,264 +0,0 @@ -/** - * Copyright (c) 2013, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control; - -import java.util.HashMap; -import java.util.Map; - -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.value.ObservableValue; -import javafx.collections.FXCollections; -import javafx.collections.ListChangeListener; -import javafx.collections.ObservableList; -import javafx.scene.control.CheckBox; -import javafx.scene.control.ListView; -import javafx.scene.control.cell.CheckBoxListCell; -import javafx.util.Callback; - -/** - * A simple UI control that makes it possible to select zero or more items within - * a ListView without the need to set a custom cell factory or manually create - * boolean properties for each row - simply use the - * {@link #checkModelProperty() check model} to request the current selection - * state. - * - * <h3>Screenshot</h3> - * <p>The following screenshot shows the CheckListView with some sample data: - * - * <br> - * <img src="checkListView.png" alt="Screenshot of CheckListView"> - * - * <h3>Code Example:</h3> - * <p>To create the CheckListView shown in the screenshot, simply do the - * following: - * - * <pre> - * {@code - * // create the data to show in the CheckListView - * final ObservableList<String> strings = FXCollections.observableArrayList(); - * for (int i = 0; i <= 100; i++) { - * strings.add("Item " + i); - * } - * - * // Create the CheckListView with the data - * final CheckListView<String> checkListView = new CheckListView<>(strings); - * - * // and listen to the relevant events (e.g. when the selected indices or - * // selected items change). - * checkListView.getCheckModel().getCheckedItems().addListener(new ListChangeListener<String>() { - * public void onChanged(ListChangeListener.Change<? extends String> c) { - * System.out.println(checkListView.getCheckModel().getCheckedItems()); - * } - * }); - * }</pre> - * - * @param <T> The type of the data in the CheckListView. - */ -public class CheckListView<T> extends ListView<T> { - - /************************************************************************** - * - * Private fields - * - **************************************************************************/ - - private final Map<T, BooleanProperty> itemBooleanMap; - - - - /************************************************************************** - * - * Constructors - * - **************************************************************************/ - - /** - * Creates a new CheckListView instance with an empty list of choices. - */ - public CheckListView() { - this(FXCollections.<T> observableArrayList()); - } - - /** - * Creates a new CheckListView instance with the given items available as - * choices. - * - * @param items The items to display within the CheckListView. - */ - public CheckListView(ObservableList<T> items) { - super(items); - this.itemBooleanMap = new HashMap<>(); - - setCheckModel(new CheckListViewBitSetCheckModel<>(getItems(), itemBooleanMap)); - itemsProperty().addListener(ov -> { - setCheckModel(new CheckListViewBitSetCheckModel<>(getItems(), itemBooleanMap)); - }); - - setCellFactory(listView -> new CheckBoxListCell<>(new Callback<T, ObservableValue<Boolean>>() { - @Override public ObservableValue<Boolean> call(T item) { - return getItemBooleanProperty(item); - } - })); - } - - - - /************************************************************************** - * - * Public API - * - **************************************************************************/ - - /** - * Returns the {@link BooleanProperty} for a given item index in the - * CheckListView. This is useful if you want to bind to the property. - */ - public BooleanProperty getItemBooleanProperty(int index) { - if (index < 0 || index >= getItems().size()) return null; - return getItemBooleanProperty(getItems().get(index)); - } - - /** - * Returns the {@link BooleanProperty} for a given item in the - * CheckListView. This is useful if you want to bind to the property. - */ - public BooleanProperty getItemBooleanProperty(T item) { - return itemBooleanMap.get(item); - } - - - - /************************************************************************** - * - * Properties - * - **************************************************************************/ - - // --- Check Model - private ObjectProperty<IndexedCheckModel<T>> checkModel = - new SimpleObjectProperty<>(this, "checkModel"); //$NON-NLS-1$ - - /** - * Sets the 'check model' to be used in the CheckListView - this is the - * code that is responsible for representing the selected state of each - * {@link CheckBox} - that is, whether each {@link CheckBox} is checked or - * not (and not to be confused with the - * selection model concept, which is used in the ListView control to - * represent the selection state of each row).. - */ - public final void setCheckModel(IndexedCheckModel<T> value) { - checkModelProperty().set(value); - } - - /** - * Returns the currently installed check model. - */ - public final IndexedCheckModel<T> getCheckModel() { - return checkModel == null ? null : checkModel.get(); - } - - /** - * The check model provides the API through which it is possible - * to check single or multiple items within a CheckListView, as well as inspect - * which items have been checked by the user. Note that it has a generic - * type that must match the type of the CheckListView itself. - */ - public final ObjectProperty<IndexedCheckModel<T>> checkModelProperty() { - return checkModel; - } - - - - /************************************************************************** - * - * Implementation - * - **************************************************************************/ - - - - - /************************************************************************** - * - * Support classes - * - **************************************************************************/ - - private static class CheckListViewBitSetCheckModel<T> extends CheckBitSetModelBase<T> { - - /*********************************************************************** - * * - * Internal properties * - * * - **********************************************************************/ - - private final ObservableList<T> items; - - - - /*********************************************************************** - * * - * Constructors * - * * - **********************************************************************/ - - CheckListViewBitSetCheckModel(final ObservableList<T> items, final Map<T, BooleanProperty> itemBooleanMap) { - super(itemBooleanMap); - - this.items = items; - this.items.addListener(new ListChangeListener<T>() { - @Override public void onChanged(Change<? extends T> c) { - updateMap(); - } - }); - - updateMap(); - } - - - - /*********************************************************************** - * * - * Implementing abstract API * - * * - **********************************************************************/ - - @Override public T getItem(int index) { - return items.get(index); - } - - @Override public int getItemCount() { - return items.size(); - } - - @Override public int getItemIndex(T item) { - return items.indexOf(item); - } - } -} diff --git a/src/org/controlsfx/control/CheckModel.java b/src/org/controlsfx/control/CheckModel.java deleted file mode 100644 index c305ae2..0000000 --- a/src/org/controlsfx/control/CheckModel.java +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Copyright (c) 2014, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control; - -import javafx.collections.ObservableList; - -public interface CheckModel<T> { - - /** - * Returns the count of items in the control. - */ - public int getItemCount(); - - /** - * Returns a read-only list of the currently checked items in the control. - */ - public ObservableList<T> getCheckedItems(); - - /** - * Checks all items in the control - */ - public void checkAll(); - - public void clearCheck(T item); - - /** - * Unchecks all items in the control - */ - public void clearChecks(); - - /** - * Returns true if there are no checked items in the control. - */ - public boolean isEmpty(); - - public boolean isChecked(T item); - - /** - * Checks the given item in the control. - */ - public void check(T item); -} diff --git a/src/org/controlsfx/control/CheckTreeView.java b/src/org/controlsfx/control/CheckTreeView.java deleted file mode 100644 index d8b8689..0000000 --- a/src/org/controlsfx/control/CheckTreeView.java +++ /dev/null @@ -1,327 +0,0 @@ -/** - * Copyright (c) 2013, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.Consumer; - -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.scene.control.CheckBox; -import javafx.scene.control.CheckBoxTreeItem; -import javafx.scene.control.TreeItem; -import javafx.scene.control.TreeView; -import javafx.scene.control.cell.CheckBoxTreeCell; - -/** - * A simple UI control that makes it possible to select zero or more items within - * a TreeView without the need to set a custom cell factory or manually create - * boolean properties for each row - simply use the - * {@link #checkModelProperty() check model} to request the current selection - * state. - * - * <h3>Screenshot</h3> - * <p>The following screenshot shows the CheckTreeView with some sample data: - * - * <br> - * <img src="checkTreeView.png" alt="Screenshot of CheckTreeView"> - * - * <h3>Code Example:</h3> - * <p>To create the CheckTreeView shown in the screenshot, simply do the - * following: - * - * <pre> - * {@code - * // create the data to show in the CheckTreeView - * CheckBoxTreeItem<String> root = new CheckBoxTreeItem<String>("Root"); - * root.setExpanded(true); - * root.getChildren().addAll( - * new CheckBoxTreeItem<String>("Jonathan"), - * new CheckBoxTreeItem<String>("Eugene"), - * new CheckBoxTreeItem<String>("Henri"), - * new CheckBoxTreeItem<String>("Samir")); - * - * // Create the CheckTreeView with the data - * final CheckTreeView<String> checkTreeView = new CheckTreeView<>(root); - * - * // and listen to the relevant events (e.g. when the checked items change). - * checkTreeView.getCheckModel().getCheckedItems().addListener(new ListChangeListener<TreeItem<String>>() { - * public void onChanged(ListChangeListener.Change<? extends TreeItem<String>> c) { - * System.out.println(checkTreeView.getCheckModel().getCheckedItems()); - * } - * }); - * }</pre> - * - * @param <T> The type of the data in the TreeView. - */ -public class CheckTreeView<T> extends TreeView<T> { - - /************************************************************************** - * - * Private fields - * - **************************************************************************/ - - - - - /************************************************************************** - * - * Constructors - * - **************************************************************************/ - - /** - * Creates a new CheckTreeView instance with an empty tree of choices. - */ - public CheckTreeView() { - this(null); - } - - /** - * Creates a new CheckTreeView instance with the given CheckBoxTreeItem set - * as the tree root. - * - * @param root The root tree item to display in the CheckTreeView. - */ - public CheckTreeView(final CheckBoxTreeItem<T> root) { - super(root); - rootProperty().addListener(o -> updateCheckModel()); - - updateCheckModel(); - - setCellFactory(CheckBoxTreeCell.<T> forTreeView()); - } - - protected void updateCheckModel() { - if (getRoot() != null) { - setCheckModel(new CheckTreeViewCheckModel<>(this)); - } - } - - - /************************************************************************** - * - * Public API - * - **************************************************************************/ - - /** - * Returns the {@link BooleanProperty} for a given item index in the - * CheckTreeView. This is useful if you want to bind to the property. - */ - public BooleanProperty getItemBooleanProperty(int index) { - CheckBoxTreeItem<T> treeItem = (CheckBoxTreeItem<T>) getTreeItem(index); - return treeItem.selectedProperty(); - } - - - - /************************************************************************** - * - * Properties - * - **************************************************************************/ - - // --- Check Model - private ObjectProperty<CheckModel<TreeItem<T>>> checkModel = - new SimpleObjectProperty<>(this, "checkModel"); //$NON-NLS-1$ - - /** - * Sets the 'check model' to be used in the CheckTreeView - this is the - * code that is responsible for representing the selected state of each - * {@link CheckBox} - that is, whether each {@link CheckBox} is checked or - * not (and not to be confused with the - * selection model concept, which is used in the TreeView control to - * represent the selection state of each row).. - */ - public final void setCheckModel(CheckModel<TreeItem<T>> value) { - checkModelProperty().set(value); - } - - /** - * Returns the currently installed check model. - */ - public final CheckModel<TreeItem<T>> getCheckModel() { - return checkModel == null ? null : checkModel.get(); - } - - /** - * The check model provides the API through which it is possible - * to check single or multiple items within a CheckTreeView, as well as inspect - * which items have been checked by the user. Note that it has a generic - * type that must match the type of the CheckTreeView itself. - */ - public final ObjectProperty<CheckModel<TreeItem<T>>> checkModelProperty() { - return checkModel; - } - - - - /************************************************************************** - * - * Implementation - * - **************************************************************************/ - - - - - /************************************************************************** - * - * Support classes - * - **************************************************************************/ - - private static class CheckTreeViewCheckModel<T> implements CheckModel<TreeItem<T>> {// extends CheckBitSetModelBase<TreeItem<T>> { - - /*********************************************************************** - * * - * Internal properties * - * * - **********************************************************************/ - - private final CheckTreeView<T> treeView; - private final TreeItem<T> root; - - private ObservableList<TreeItem<T>> checkedItems = FXCollections.observableArrayList(); - - - - /*********************************************************************** - * * - * Constructors * - * * - **********************************************************************/ - - CheckTreeViewCheckModel(final CheckTreeView<T> treeView) { - this.treeView = treeView; - this.root = treeView.getRoot(); - this.root.addEventHandler(CheckBoxTreeItem.<T>checkBoxSelectionChangedEvent(), e -> { - CheckBoxTreeItem<T> treeItem = e.getTreeItem(); - - if (treeItem.isSelected()) { // && ! treeItem.isIndeterminate()) { - check(treeItem); - } else { - clearCheck(treeItem); - } - }); - - // we should reset the check model and then update the checked items - // based on the currently checked items in the tree view - clearChecks(); - for (int i = 0; i < treeView.getExpandedItemCount(); i++) { - CheckBoxTreeItem<T> treeItem = (CheckBoxTreeItem<T>) treeView.getTreeItem(i); - if (treeItem.isSelected() && ! treeItem.isIndeterminate()) { - check(treeItem); - } - } - } - - - - /*********************************************************************** - * * - * Implementing abstract API * - * * - **********************************************************************/ - - @Override public int getItemCount() { - return treeView.getExpandedItemCount(); - } - - - // TODO make read-only - @Override public ObservableList<TreeItem<T>> getCheckedItems() { - return checkedItems; - } - - @Override public void checkAll() { - iterateOverTree(this::check); - } - - @Override public void clearCheck(TreeItem<T> item) { - if (item instanceof CheckBoxTreeItem) { - ((CheckBoxTreeItem<T>)item).setSelected(false); - } - checkedItems.remove(item); - } - - @Override public void clearChecks() { - List<TreeItem<T>> items = new ArrayList<>(checkedItems); - for(TreeItem<T> item : items){ - clearCheck(item); - } - } - - @Override public boolean isEmpty() { - return checkedItems.isEmpty(); - } - - @Override public boolean isChecked(TreeItem<T> item) { - return checkedItems.contains(item); - } - - @Override public void check(TreeItem<T> item) { - if (item instanceof CheckBoxTreeItem) { - ((CheckBoxTreeItem<T>)item).setSelected(true); - } - if (!checkedItems.contains(item)) { - checkedItems.add(item); - } - } - - - - /*********************************************************************** - * * - * Private Implementation * - * * - **********************************************************************/ - - private void iterateOverTree(Consumer<TreeItem<T>> consumer) { - processNode(consumer, root); - } - - private void processNode(Consumer<TreeItem<T>> consumer, TreeItem<T> node) { - if (node == null) return; - consumer.accept(node); - processChildren(consumer, node.getChildren()); - } - - private void processChildren(Consumer<TreeItem<T>> consumer, List<TreeItem<T>> children) { - if (children == null) return; - for (TreeItem<T> child : children) { - processNode(consumer, child); - } - } - } -} diff --git a/src/org/controlsfx/control/ControlsFXControl.java b/src/org/controlsfx/control/ControlsFXControl.java deleted file mode 100644 index 15b3057..0000000 --- a/src/org/controlsfx/control/ControlsFXControl.java +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control; - -import impl.org.controlsfx.version.VersionChecker; -import javafx.scene.control.Control; - -abstract class ControlsFXControl extends Control { - - public ControlsFXControl() { - VersionChecker.doVersionCheck(); - } - - private String stylesheet; - - /** - * A helper method that ensures that the resource based lookup of the user - * agent stylesheet only happens once. Caches the external form of the - * resource. - * - * @param clazz - * the class used for the resource lookup - * @param fileName - * the name of the user agent stylesheet - * @return the external form of the user agent stylesheet (the path) - */ - protected final String getUserAgentStylesheet(Class<?> clazz, - String fileName) { - - /* - * For more information please see RT-40658 - */ - if (stylesheet == null) { - stylesheet = clazz.getResource(fileName).toExternalForm(); - } - - return stylesheet; - } -} diff --git a/src/org/controlsfx/control/GridCell.java b/src/org/controlsfx/control/GridCell.java deleted file mode 100644 index 158ec89..0000000 --- a/src/org/controlsfx/control/GridCell.java +++ /dev/null @@ -1,125 +0,0 @@ -/** - * Copyright (c) 2013, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control; - -import impl.org.controlsfx.skin.GridCellSkin; -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; -import javafx.beans.property.SimpleObjectProperty; -import javafx.scene.control.IndexedCell; -import javafx.scene.control.ListView; -import javafx.scene.control.Skin; -import javafx.scene.control.TableView; - -/** - * A GridCell is created to represent items in the {@link GridView} - * {@link GridView#getItems() items list}. As with other JavaFX UI controls - * (like {@link ListView}, {@link TableView}, etc), the {@link GridView} control - * is virtualised, meaning it is exceedingly memory and CPU efficient. Refer to - * the {@link GridView} class documentation for more details. - * - * @see GridView - */ -public class GridCell<T> extends IndexedCell<T> { - - /************************************************************************** - * - * Constructors - * - **************************************************************************/ - - /** - * Creates a default GridCell instance. - */ - public GridCell() { - getStyleClass().add("grid-cell"); //$NON-NLS-1$ - -// itemProperty().addListener(new ChangeListener<T>() { -// @Override public void changed(ObservableValue<? extends T> arg0, T oldItem, T newItem) { -// updateItem(newItem, newItem == null); -// } -// }); - - // TODO listen for index change and update index and item, rather than - // listen to just item update as above. This requires the GridCell to - // know about its containing GridRow (and the GridRow to know its - // containing GridView) - indexProperty().addListener(new InvalidationListener() { - @Override public void invalidated(Observable observable) { - final GridView<T> gridView = getGridView(); - if (gridView == null) return; - - if(getIndex() < 0) { - updateItem(null, true); - return; - } - T item = gridView.getItems().get(getIndex()); - -// updateIndex(getIndex()); - updateItem(item, item == null); - } - }); - } - - /** - * {@inheritDoc} - */ - @Override protected Skin<?> createDefaultSkin() { - return new GridCellSkin<>(this); - } - - - - /************************************************************************** - * - * Properties - * - **************************************************************************/ - - /** - * The {@link GridView} that this GridCell exists within. - */ - public SimpleObjectProperty<GridView<T>> gridViewProperty() { - return gridView; - } - private final SimpleObjectProperty<GridView<T>> gridView = - new SimpleObjectProperty<>(this, "gridView"); //$NON-NLS-1$ - - /** - * Sets the {@link GridView} that this GridCell exists within. - */ - public final void updateGridView(GridView<T> gridView) { - this.gridView.set(gridView); - } - - /** - * Returns the {@link GridView} that this GridCell exists within. - */ - public GridView<T> getGridView() { - return gridView.get(); - } -} \ No newline at end of file diff --git a/src/org/controlsfx/control/GridView.java b/src/org/controlsfx/control/GridView.java deleted file mode 100644 index c575fe3..0000000 --- a/src/org/controlsfx/control/GridView.java +++ /dev/null @@ -1,560 +0,0 @@ -/** - * Copyright (c) 2013, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control; - -import impl.org.controlsfx.skin.GridViewSkin; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import javafx.beans.property.DoubleProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.css.CssMetaData; -import javafx.css.StyleConverter; -import javafx.css.Styleable; -import javafx.css.StyleableDoubleProperty; -import javafx.css.StyleableProperty; -import javafx.scene.Node; -import javafx.scene.control.Cell; -import javafx.scene.control.Control; -import javafx.scene.control.ListCell; -import javafx.scene.control.Skin; -import javafx.scene.paint.Color; -import javafx.util.Callback; - -import org.controlsfx.control.cell.ColorGridCell; - -/** - * A GridView is a virtualised control for displaying {@link #getItems()} in a - * visual, scrollable, grid-like fashion. In other words, whereas a ListView - * shows one {@link ListCell} per row, in a GridView there will be zero or more - * {@link GridCell} instances on a single row. - * - * <p> This approach means that the number of GridCell instances - * instantiated will be a significantly smaller number than the number of - * items in the GridView items list, as only enough GridCells are created for - * the visible area of the GridView. This helps to improve performance and - * reduce memory consumption. - * - * <p>Because each {@link GridCell} extends from {@link Cell}, the same approach - * of cell factories that is taken in other UI controls is also taken in GridView. - * This has two main benefits: - * - * <ol> - * <li>GridCells are created on demand and without user involvement, - * <li>GridCells can be arbitrarily complex. A simple GridCell may just have - * its {@link GridCell#textProperty() text property} set, whereas a more complex - * GridCell can have an arbitrarily complex scenegraph set inside its - * {@link GridCell#graphicProperty() graphic property} (as it accepts any Node). - * </ol> - * - * <h3>Examples</h3> - * <p>The following screenshot shows the GridView with the {@link ColorGridCell} - * being used: - * - * <br> - * <img src="gridView.png" alt="Screenshot of GridView"> - * - * <p>To create this GridView was simple. Note that the majority of the code below - * is related to randomly creating the colours to be represented: - * - * <pre> - * {@code - * GridView<Color> myGrid = new GridView<>(list); - * myGrid.setCellFactory(new Callback<GridView<Color>, GridCell<Color>>() { - * public GridCell<Color> call(GridView<Color> gridView) { - * return new ColorGridCell(); - * } - * }); - * Random r = new Random(System.currentTimeMillis()); - * for(int i = 0; i < 500; i++) { - * list.add(new Color(r.nextDouble(), r.nextDouble(), r.nextDouble(), 1.0)); - * } - * }</pre> - * - * @see GridCell - */ -public class GridView<T> extends ControlsFXControl { - - /************************************************************************** - * - * Constructors - * - **************************************************************************/ - - /** - * Creates a default, empty GridView control. - */ - public GridView() { - this(FXCollections.<T> observableArrayList()); - } - - /** - * Creates a default GridView control with the provided items prepopulated. - * - * @param items The items to display inside the GridView. - */ - public GridView(ObservableList<T> items) { - getStyleClass().add(DEFAULT_STYLE_CLASS); - setItems(items); - } - - - - /************************************************************************** - * - * Public API - * - **************************************************************************/ - - /** - * {@inheritDoc} - */ - @Override protected Skin<?> createDefaultSkin() { - return new GridViewSkin<>(this); - } - - /** {@inheritDoc} */ - @Override public String getUserAgentStylesheet() { - return getUserAgentStylesheet(GridView.class, "gridview.css"); - } - - /************************************************************************** - * - * Properties - * - **************************************************************************/ - - // --- horizontal cell spacing - /** - * Property for specifying how much spacing there is between each cell - * in a row (i.e. how much horizontal spacing there is). - */ - public final DoubleProperty horizontalCellSpacingProperty() { - if (horizontalCellSpacing == null) { - horizontalCellSpacing = new StyleableDoubleProperty(12) { - @Override public CssMetaData<GridView<?>, Number> getCssMetaData() { - return GridView.StyleableProperties.HORIZONTAL_CELL_SPACING; - } - - @Override public Object getBean() { - return GridView.this; - } - - @Override public String getName() { - return "horizontalCellSpacing"; //$NON-NLS-1$ - } - }; - } - return horizontalCellSpacing; - } - private DoubleProperty horizontalCellSpacing; - - /** - * Sets the amount of horizontal spacing there should be between cells in - * the same row. - * @param value The amount of spacing to use. - */ - public final void setHorizontalCellSpacing(double value) { - horizontalCellSpacingProperty().set(value); - } - - /** - * Returns the amount of horizontal spacing there is between cells in - * the same row. - */ - public final double getHorizontalCellSpacing() { - return horizontalCellSpacing == null ? 12.0 : horizontalCellSpacing.get(); - } - - - - // --- vertical cell spacing - /** - * Property for specifying how much spacing there is between each cell - * in a column (i.e. how much vertical spacing there is). - */ - private DoubleProperty verticalCellSpacing; - public final DoubleProperty verticalCellSpacingProperty() { - if (verticalCellSpacing == null) { - verticalCellSpacing = new StyleableDoubleProperty(12) { - @Override public CssMetaData<GridView<?>, Number> getCssMetaData() { - return GridView.StyleableProperties.VERTICAL_CELL_SPACING; - } - - @Override public Object getBean() { - return GridView.this; - } - - @Override public String getName() { - return "verticalCellSpacing"; //$NON-NLS-1$ - } - }; - } - return verticalCellSpacing; - } - - /** - * Sets the amount of vertical spacing there should be between cells in - * the same column. - * @param value The amount of spacing to use. - */ - public final void setVerticalCellSpacing(double value) { - verticalCellSpacingProperty().set(value); - } - - /** - * Returns the amount of vertical spacing there is between cells in - * the same column. - */ - public final double getVerticalCellSpacing() { - return verticalCellSpacing == null ? 12.0 : verticalCellSpacing.get(); - } - - - - // --- cell width - /** - * Property representing the width that all cells should be. - */ - public final DoubleProperty cellWidthProperty() { - if (cellWidth == null) { - cellWidth = new StyleableDoubleProperty(64) { - @Override public CssMetaData<GridView<?>, Number> getCssMetaData() { - return GridView.StyleableProperties.CELL_WIDTH; - } - - @Override public Object getBean() { - return GridView.this; - } - - @Override public String getName() { - return "cellWidth"; //$NON-NLS-1$ - } - }; - } - return cellWidth; - } - private DoubleProperty cellWidth; - - /** - * Sets the width that all cells should be. - */ - public final void setCellWidth(double value) { - cellWidthProperty().set(value); - } - - /** - * Returns the width that all cells should be. - */ - public final double getCellWidth() { - return cellWidth == null ? 64.0 : cellWidth.get(); - } - - - // --- cell height - /** - * Property representing the height that all cells should be. - */ - public final DoubleProperty cellHeightProperty() { - if (cellHeight == null) { - cellHeight = new StyleableDoubleProperty(64) { - @Override public CssMetaData<GridView<?>, Number> getCssMetaData() { - return GridView.StyleableProperties.CELL_HEIGHT; - } - - @Override public Object getBean() { - return GridView.this; - } - - @Override public String getName() { - return "cellHeight"; //$NON-NLS-1$ - } - }; - } - return cellHeight; - } - private DoubleProperty cellHeight; - - /** - * Sets the height that all cells should be. - */ - public final void setCellHeight(double value) { - cellHeightProperty().set(value); - } - - /** - * Returns the height that all cells should be. - */ - public final double getCellHeight() { - return cellHeight == null ? 64.0 : cellHeight.get(); - } - - - // I've removed this functionality until there is a clear need for it. - // To re-enable it, there is code in GridRowSkin that has been commented - // out that must be re-enabled. - // Don't forget also to enable the styleable property further down in this - // class. -// // --- horizontal alignment -// private ObjectProperty<HPos> horizontalAlignment; -// public final ObjectProperty<HPos> horizontalAlignmentProperty() { -// if (horizontalAlignment == null) { -// horizontalAlignment = new StyleableObjectProperty<HPos>(HPos.CENTER) { -// @Override public CssMetaData<GridView<?>,HPos> getCssMetaData() { -// return GridView.StyleableProperties.HORIZONTAL_ALIGNMENT; -// } -// -// @Override public Object getBean() { -// return GridView.this; -// } -// -// @Override public String getName() { -// return "horizontalAlignment"; -// } -// }; -// } -// return horizontalAlignment; -// } -// -// public final void setHorizontalAlignment(HPos value) { -// horizontalAlignmentProperty().set(value); -// } -// -// public final HPos getHorizontalAlignment() { -// return horizontalAlignment == null ? HPos.CENTER : horizontalAlignment.get(); -// } - - - // --- cell factory - /** - * Property representing the cell factory that is currently set in this - * GridView, or null if no cell factory has been set (in which case the - * default cell factory provided by the GridView skin will be used). The cell - * factory is used for instantiating enough GridCell instances for the - * visible area of the GridView. Refer to the GridView class documentation - * for more information and examples. - */ - public final ObjectProperty<Callback<GridView<T>, GridCell<T>>> cellFactoryProperty() { - if (cellFactory == null) { - cellFactory = new SimpleObjectProperty<>(this, "cellFactory"); //$NON-NLS-1$ - } - return cellFactory; - } - private ObjectProperty<Callback<GridView<T>, GridCell<T>>> cellFactory; - - /** - * Sets the cell factory to use to create {@link GridCell} instances to - * show in the GridView. - */ - public final void setCellFactory(Callback<GridView<T>, GridCell<T>> value) { - cellFactoryProperty().set(value); - } - - /** - * Returns the cell factory that will be used to create {@link GridCell} - * instances to show in the GridView. - */ - public final Callback<GridView<T>, GridCell<T>> getCellFactory() { - return cellFactory == null ? null : cellFactory.get(); - } - - - // --- items - /** - * The items to be displayed in the GridView (as rendered via {@link GridCell} - * instances). For example, if the {@link ColorGridCell} were being used - * (as in the case at the top of this class documentation), this items list - * would be populated with {@link Color} values. It is important to - * appreciate that the items list is used for the data, not the rendering. - * What is meant by this is that the items list should contain Color values, - * not the {@link Node nodes} that represent the Color. The actual rendering - * should be left up to the {@link #cellFactoryProperty() cell factory}, - * where it will take the Color value and create / update the display as - * necessary. - */ - public final ObjectProperty<ObservableList<T>> itemsProperty() { - if (items == null) { - items = new SimpleObjectProperty<>(this, "items"); //$NON-NLS-1$ - } - return items; - } - private ObjectProperty<ObservableList<T>> items; - - /** - * Sets a new {@link ObservableList} as the items list underlying GridView. - * The old items list will be discarded. - */ - public final void setItems(ObservableList<T> value) { - itemsProperty().set(value); - } - - /** - * Returns the currently-in-use items list that is being used by the - * GridView. - */ - public final ObservableList<T> getItems() { - return items == null ? null : items.get(); - } - - - - - - /*************************************************************************** - * * - * Stylesheet Handling * - * * - **************************************************************************/ - - private static final String DEFAULT_STYLE_CLASS = "grid-view"; //$NON-NLS-1$ - - /** @treatAsPrivate */ - private static class StyleableProperties { - private static final CssMetaData<GridView<?>,Number> HORIZONTAL_CELL_SPACING = - new CssMetaData<GridView<?>,Number>("-fx-horizontal-cell-spacing", StyleConverter.getSizeConverter(), 12d) { //$NON-NLS-1$ - - @Override public Double getInitialValue(GridView<?> node) { - return node.getHorizontalCellSpacing(); - } - - @Override public boolean isSettable(GridView<?> n) { - return n.horizontalCellSpacing == null || !n.horizontalCellSpacing.isBound(); - } - - @Override - @SuppressWarnings("unchecked") - public StyleableProperty<Number> getStyleableProperty(GridView<?> n) { - return (StyleableProperty<Number>)n.horizontalCellSpacingProperty(); - } - }; - - private static final CssMetaData<GridView<?>,Number> VERTICAL_CELL_SPACING = - new CssMetaData<GridView<?>,Number>("-fx-vertical-cell-spacing", StyleConverter.getSizeConverter(), 12d) { //$NON-NLS-1$ - - @Override public Double getInitialValue(GridView<?> node) { - return node.getVerticalCellSpacing(); - } - - @Override public boolean isSettable(GridView<?> n) { - return n.verticalCellSpacing == null || !n.verticalCellSpacing.isBound(); - } - - @Override - @SuppressWarnings("unchecked") - public StyleableProperty<Number> getStyleableProperty(GridView<?> n) { - return (StyleableProperty<Number>)n.verticalCellSpacingProperty(); - } - }; - - private static final CssMetaData<GridView<?>,Number> CELL_WIDTH = - new CssMetaData<GridView<?>,Number>("-fx-cell-width", StyleConverter.getSizeConverter(), 64d) { //$NON-NLS-1$ - - @Override public Double getInitialValue(GridView<?> node) { - return node.getCellWidth(); - } - - @Override public boolean isSettable(GridView<?> n) { - return n.cellWidth == null || !n.cellWidth.isBound(); - } - - @Override - @SuppressWarnings("unchecked") - public StyleableProperty<Number> getStyleableProperty(GridView<?> n) { - return (StyleableProperty<Number>)n.cellWidthProperty(); - } - }; - - private static final CssMetaData<GridView<?>,Number> CELL_HEIGHT = - new CssMetaData<GridView<?>,Number>("-fx-cell-height", StyleConverter.getSizeConverter(), 64d) { //$NON-NLS-1$ - - @Override public Double getInitialValue(GridView<?> node) { - return node.getCellHeight(); - } - - @Override public boolean isSettable(GridView<?> n) { - return n.cellHeight == null || !n.cellHeight.isBound(); - } - - @Override - @SuppressWarnings("unchecked") - public StyleableProperty<Number> getStyleableProperty(GridView<?> n) { - return (StyleableProperty<Number>)n.cellHeightProperty(); - } - }; - -// private static final CssMetaData<GridView<?>,HPos> HORIZONTAL_ALIGNMENT = -// new CssMetaData<GridView<?>,HPos>("-fx-horizontal_alignment", -// new EnumConverter<HPos>(HPos.class), -// HPos.CENTER) { -// -// @Override public HPos getInitialValue(GridView node) { -// return node.getHorizontalAlignment(); -// } -// -// @Override public boolean isSettable(GridView n) { -// return n.horizontalAlignment == null || !n.horizontalAlignment.isBound(); -// } -// -// @Override public StyleableProperty<HPos> getStyleableProperty(GridView n) { -// return (StyleableProperty<HPos>)n.horizontalAlignmentProperty(); -// } -// }; - - private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES; - static { - final List<CssMetaData<? extends Styleable, ?>> styleables = - new ArrayList<>(Control.getClassCssMetaData()); - styleables.add(HORIZONTAL_CELL_SPACING); - styleables.add(VERTICAL_CELL_SPACING); - styleables.add(CELL_WIDTH); - styleables.add(CELL_HEIGHT); -// styleables.add(HORIZONTAL_ALIGNMENT); - STYLEABLES = Collections.unmodifiableList(styleables); - } - } - - /** - * @return The CssMetaData associated with this class, which may include the - * CssMetaData of its super classes. - */ - public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() { - return StyleableProperties.STYLEABLES; - } - - /** - * {@inheritDoc} - */ - @Override - public List<CssMetaData<? extends Styleable, ?>> getControlCssMetaData() { - return getClassCssMetaData(); - } -} diff --git a/src/org/controlsfx/control/HiddenSidesPane.java b/src/org/controlsfx/control/HiddenSidesPane.java deleted file mode 100644 index 9aa37cb..0000000 --- a/src/org/controlsfx/control/HiddenSidesPane.java +++ /dev/null @@ -1,426 +0,0 @@ -/** - * Copyright (c) 2014, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control; - -import impl.org.controlsfx.skin.HiddenSidesPaneSkin; -import javafx.beans.property.DoubleProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleDoubleProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.geometry.Side; -import javafx.scene.Node; -import javafx.scene.control.Skin; -import javafx.util.Duration; - -/** - * A pane used to display a full-size content node and four initially hidden - * nodes on the four sides. The hidden nodes can be made visible by moving the - * mouse cursor to the edges (see {@link #setTriggerDistance(double)}) of the - * pane. The hidden node will appear (at its preferred width or height) with a - * short slide-in animation. The node will disappear again as soon as the mouse - * cursor exits it. A hidden node / side can also be pinned by calling - * {@link #setPinnedSide(Side)}. It will remain visible as long as it stays - * pinned. - * - * <h3>Screenshot</h3> The following screenshots shows the right side node - * hovering over a table after it was made visible: - * - * <center><img src="hiddenSidesPane.png" alt="Screenshot of HiddenSidesPane"> - * - * </center> <h3>Code Sample</h3> - * - * <pre> - * HiddenSidesPane pane = new HiddenSidesPane(); - * pane.setContent(new TableView()); - * pane.setRight(new ListView()); - * </pre> - */ -public class HiddenSidesPane extends ControlsFXControl { - - /** - * Constructs a new pane with the given content node and the four side - * nodes. Each one of the side nodes may be null. - * - * @param content - * the primary node that will fill the entire width and height of - * the pane - * @param top - * the hidden node on the top side - * @param right - * the hidden node on the right side - * @param bottom - * the hidden node on the bottom side - * @param left - * the hidden node on the left side - */ - public HiddenSidesPane(Node content, Node top, Node right, Node bottom, - Node left) { - setContent(content); - setTop(top); - setRight(right); - setBottom(bottom); - setLeft(left); - } - - /** - * Constructs a new pane with no content and no side nodes. - */ - public HiddenSidesPane() { - this(null, null, null, null, null); - } - - @Override - protected Skin<?> createDefaultSkin() { - return new HiddenSidesPaneSkin(this); - } - - private DoubleProperty triggerDistance = new SimpleDoubleProperty(this, - "triggerDistance", 16); //$NON-NLS-1$ - - /** - * The property that stores the distance to the pane's edges that will - * trigger the appearance of the hidden side nodes.<br> - * Setting the property to zero or a negative value will disable this - * functionality, so a hidden side can only be made visible with - * {@link #setPinnedSide(Side)}. - * - * @return the trigger distance property - */ - public final DoubleProperty triggerDistanceProperty() { - return triggerDistance; - } - - /** - * Returns the value of the trigger distance property. - * - * @return the trigger distance property value - */ - public final double getTriggerDistance() { - return triggerDistance.get(); - } - - /** - * Set the value of the trigger distance property. <br> - * Setting the property to zero or a negative value will disable this - * functionality, so a hidden side can only be made visible with - * {@link #setPinnedSide(Side)}. - * - * @param distance - * the new value for the trigger distance property - */ - public final void setTriggerDistance(double distance) { - triggerDistance.set(distance); - } - - // Content node support. - - private ObjectProperty<Node> content = new SimpleObjectProperty<>(this, - "content"); //$NON-NLS-1$ - - /** - * The property that is used to store a reference to the content node. The - * content node will fill the entire width and height of the pane. - * - * @return the content node property - */ - public final ObjectProperty<Node> contentProperty() { - return content; - } - - /** - * Returns the value of the content node property. - * - * @return the content node property value - */ - public final Node getContent() { - return contentProperty().get(); - } - - /** - * Sets the value of the content node property. - * - * @param content - * the new content node - */ - public final void setContent(Node content) { - contentProperty().set(content); - } - - // Top node support. - - private ObjectProperty<Node> top = new SimpleObjectProperty<>(this, - "top"); //$NON-NLS-1$ - - /** - * The property used to store a reference to the node shown at the top side - * of the pane. - * - * @return the hidden node at the top side of the pane - */ - public final ObjectProperty<Node> topProperty() { - return top; - } - - /** - * Returns the value of the top node property. - * - * @return the top node property value - */ - public final Node getTop() { - return topProperty().get(); - } - - /** - * Sets the value of the top node property. - * - * @param top - * the top node value - */ - public final void setTop(Node top) { - topProperty().set(top); - } - - // Right node support. - - /** - * The property used to store a reference to the node shown at the right - * side of the pane. - * - * @return the hidden node at the right side of the pane - */ - private ObjectProperty<Node> right = new SimpleObjectProperty<>(this, - "right"); //$NON-NLS-1$ - - /** - * Returns the value of the right node property. - * - * @return the right node property value - */ - public final ObjectProperty<Node> rightProperty() { - return right; - } - - /** - * Returns the value of the right node property. - * - * @return the right node property value - */ - public final Node getRight() { - return rightProperty().get(); - } - - /** - * Sets the value of the right node property. - * - * @param right - * the right node value - */ - public final void setRight(Node right) { - rightProperty().set(right); - } - - // Bottom node support. - - /** - * The property used to store a reference to the node shown at the bottom - * side of the pane. - * - * @return the hidden node at the bottom side of the pane - */ - private ObjectProperty<Node> bottom = new SimpleObjectProperty<>(this, - "bottom"); //$NON-NLS-1$ - - /** - * Returns the value of the bottom node property. - * - * @return the bottom node property value - */ - public final ObjectProperty<Node> bottomProperty() { - return bottom; - } - - /** - * Returns the value of the bottom node property. - * - * @return the bottom node property value - */ - public final Node getBottom() { - return bottomProperty().get(); - } - - /** - * Sets the value of the bottom node property. - * - * @param bottom - * the bottom node value - */ - public final void setBottom(Node bottom) { - bottomProperty().set(bottom); - } - - // Left node support. - - /** - * The property used to store a reference to the node shown at the left side - * of the pane. - * - * @return the hidden node at the left side of the pane - */ - private ObjectProperty<Node> left = new SimpleObjectProperty<>(this, - "left"); //$NON-NLS-1$ - - /** - * Returns the value of the left node property. - * - * @return the left node property value - */ - public final ObjectProperty<Node> leftProperty() { - return left; - } - - /** - * Returns the value of the left node property. - * - * @return the left node property value - */ - public final Node getLeft() { - return leftProperty().get(); - } - - /** - * Sets the value of the left node property. - * - * @param left - * the left node value - */ - public final void setLeft(Node left) { - leftProperty().set(left); - } - - // Pinned side support. - - private ObjectProperty<Side> pinnedSide = new SimpleObjectProperty<>( - this, "pinnedSide"); //$NON-NLS-1$ - - /** - * Returns the pinned side property. The value of this property determines - * if one of the four hidden sides stays visible all the time. - * - * @return the pinned side property - */ - public final ObjectProperty<Side> pinnedSideProperty() { - return pinnedSide; - } - - /** - * Returns the value of the pinned side property. - * - * @return the pinned side property value - */ - public final Side getPinnedSide() { - return pinnedSideProperty().get(); - } - - /** - * Sets the value of the pinned side property. - * - * @param side - * the new pinned side value - */ - public final void setPinnedSide(Side side) { - pinnedSideProperty().set(side); - } - - // slide in animation delay - - private final ObjectProperty<Duration> animationDelay = new SimpleObjectProperty<>( - this, "animationDelay", Duration.millis(300)); //$NON-NLS-1$ - - /** - * Returns the animation delay property. The value of this property - * determines the delay before the hidden side slide in / slide out - * animation starts to play. - * - * @return animation delay property - */ - public final ObjectProperty<Duration> animationDelayProperty() { - return animationDelay; - } - - /** - * Returns the animation delay - * - * @return animation delay - */ - public final Duration getAnimationDelay() { - return animationDelay.get(); - } - - /** - * Set the animation delay - * - * @param duration - * slide in animation delay - */ - public final void setAnimationDelay(Duration duration) { - animationDelay.set(duration); - } - - // slide in / slide out duration - - private final ObjectProperty<Duration> animationDuration = new SimpleObjectProperty<>( - this, "animationDuration", Duration.millis(200)); //$NON-NLS-1$ - - /** - * Returns the animation duration property. The value of this property - * determines the fade in time for a hidden side to become visible. - * - * @return animation delay property - */ - public final ObjectProperty<Duration> animationDurationProperty() { - return animationDuration; - } - - /** - * Returns the animation delay - * - * @return animation delay - */ - public final Duration getAnimationDuration() { - return animationDuration.get(); - } - - /** - * Set the animation delay - * - * @param duration - * animation duration - */ - public final void setAnimationDuration(Duration duration) { - animationDuration.set(duration); - } -} diff --git a/src/org/controlsfx/control/HyperlinkLabel.java b/src/org/controlsfx/control/HyperlinkLabel.java deleted file mode 100644 index abf3b90..0000000 --- a/src/org/controlsfx/control/HyperlinkLabel.java +++ /dev/null @@ -1,211 +0,0 @@ -/** - * Copyright (c) 2013, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control; - -import impl.org.controlsfx.skin.HyperlinkLabelSkin; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.property.StringProperty; -import javafx.event.ActionEvent; -import javafx.event.EventHandler; -import javafx.event.EventTarget; -import javafx.scene.control.Hyperlink; -import javafx.scene.control.Skin; - -import com.sun.javafx.event.EventHandlerManager; - -/** - * A UI control that will convert the given text into a series of text labels - * and {@link Hyperlink hyperlinks}, based on the use of delimiter characters - * to specify where hyperlinks should appear. The delimiter characters are - * square braces (that is, [ and ]). To create a hyperlink in a string you would - * therefore do something like - * <code>hyperlinkLabel.setText("Click [here] for more information!");</code>, - * with the word 'here' appearing as a hyperlink that a use may click. This - * approach therefore allows for hyperlinks to be easily embedded within a - * label. - * - * <p>Once hyperlinks have been declared in a text string, it is necessary to - * respond to the user interacting with the hyperlink (most commonly via mouse - * clicks). To do so, you register a single event handler for action events on - * the HyperlinkLabel instance, and then determine what to do within that - * callback. For example: - * - * <pre> - * {@code - * hyperlinkLabel.setOnAction(new EventHandler<ActionEvent>() { - * public void handle(ActionEvent event) { - * Hyperlink link = (Hyperlink)event.getSource(); - * final String str = link == null ? "" : link.getText(); - * switch(str) { - * case "here": // do 'here' action - * break; - * case "exit": // do exit action - * break; - * } - * } - * });}</pre> - * - * <p>This simple single-handler approach was chosen over any more complex - * per-hyperlink solution because it is anticipated that most use cases will - * normally consist of one, or very few hyperlinks, and it was therefore unlikely - * that the increased API complexity would be warranted. - * - * <h3>Screenshot</h3> - * <p>To demonstrate what a HyperlinkLabel looks like, refer to the screenshot - * below, when the text - * <code>"Hello [world]! I [wonder] what hyperlink [you] [will] [click]"</code> - * was passed in to the HyperlinkLabel instance: - * - * <br><br> - * <center><img src="hyperlinkLabel.PNG" alt="Screenshot of HyperlinkLabel"></center> - * - * @see Hyperlink - * @see ActionEvent - */ -public class HyperlinkLabel extends ControlsFXControl implements EventTarget { - - /*************************************************************************** - * - * Private fields - * - **************************************************************************/ - - private final EventHandlerManager eventHandlerManager = - new EventHandlerManager(this); - - - - /*************************************************************************** - * - * Constructors - * - **************************************************************************/ - - /** - * Creates an empty HyperlinkLabel instance with no {@link #textProperty() text} - * specified. - */ - public HyperlinkLabel() { - this(null); - } - - /** - * Creates a HyperlinkLabel instance with the given text value used as the - * initial text. - * - * @param text The text to display to the user. - */ - public HyperlinkLabel(String text) { - setText(text); - } - - - - /************************************************************************** - * - * Public API - * - **************************************************************************/ - - /** - * {@inheritDoc} - */ - @Override protected Skin<?> createDefaultSkin() { - return new HyperlinkLabelSkin(this); - } - - - // --- text - private final StringProperty text = new SimpleStringProperty(this, "text"); //$NON-NLS-1$ - - /** - * Return a {@link StringProperty} representing the text being displayed. - * @return a {@link StringProperty}. - */ - public final StringProperty textProperty() { - return text; - } - - /** - * Return the text currently displayed. - * @return the text currently displayed. - */ - public final String getText() { - return text.get(); - } - - /** - * Set a new text to display to the user, using the delimiter characters [ and ] - * to indicate where hyperlinks should be displayed. - * @param value - */ - public final void setText(String value) { - text.set(value); - } - - - // --- onAction - private ObjectProperty<EventHandler<ActionEvent>> onAction; - - /** - * The action, which is invoked whenever a hyperlink is fired. This - * may be due to the user clicking on the hyperlink with the mouse, or by - * a touch event, or by a key press. - * @return an {@link ObjectProperty} representing the action. - */ - public final ObjectProperty<EventHandler<ActionEvent>> onActionProperty() { - if (onAction == null) { - onAction = new SimpleObjectProperty<EventHandler<ActionEvent>>(this, "onAction") { //$NON-NLS-1$ - @Override protected void invalidated() { - eventHandlerManager.setEventHandler(ActionEvent.ACTION, get()); - } - }; - } - return onAction; - } - - /** - * Sets a new EventHandler which will be invoked whenever a hyperlink is - * fired. - * @param value - */ - public final void setOnAction(EventHandler<ActionEvent> value) { - onActionProperty().set( value); - } - - /** - * - * @return the action, which is invoked whenever a hyperlink is fired. - */ - public final EventHandler<ActionEvent> getOnAction() { - return onAction == null ? null : onAction.get(); - } - - -} diff --git a/src/org/controlsfx/control/IndexedCheckModel.java b/src/org/controlsfx/control/IndexedCheckModel.java deleted file mode 100644 index acb77cd..0000000 --- a/src/org/controlsfx/control/IndexedCheckModel.java +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Copyright (c) 2014, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control; - -import javafx.collections.ObservableList; - -public interface IndexedCheckModel<T> extends CheckModel<T> { - - /** - * Returns the item in the given index in the control. - */ - public T getItem(int index); - - /** - * Returns the index of the given item. - */ - public int getItemIndex(T item); - - /** - * Returns a read-only list of the currently checked indices in the control. - */ - public ObservableList<Integer> getCheckedIndices(); - - /** - * Checks the given indices in the control - */ - public void checkIndices(int... indices); - - /** - * Unchecks the given index in the control - */ - public void clearCheck(int index); - - /** - * Returns true if the given index represents an item that is checked in the control. - */ - public boolean isChecked(int index); - - /** - * Checks the item in the given index in the control. - */ - public void check(int index); - -} \ No newline at end of file diff --git a/src/org/controlsfx/control/InfoOverlay.java b/src/org/controlsfx/control/InfoOverlay.java deleted file mode 100644 index 3d9cf5d..0000000 --- a/src/org/controlsfx/control/InfoOverlay.java +++ /dev/null @@ -1,220 +0,0 @@ -/** - * Copyright (c) 2014, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.controlsfx.control; - -import impl.org.controlsfx.skin.InfoOverlaySkin; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.property.StringProperty; -import javafx.scene.Node; -import javafx.scene.control.Skin; -import javafx.scene.image.ImageView; - -/** - * A simple UI control that allows for an information popup to be displayed over - * a node to describe it in further detail. In some ways, it can be thought of - * as a always visible tooltip (although by default it is collapsed so only the - * first line is shown - clicking on it will expand it to show all text). - * - * <p>Shown below is a screenshot of the InfoOverlay control in both its - * collapsed and expanded states: - * - * <br> - * <center> - * <img src="infoOverlay.png" alt="Screenshot of InfoOverlay"> - * </center> - */ -public class InfoOverlay extends ControlsFXControl { - - /*************************************************************************** - * * - * Constructors * - * * - **************************************************************************/ - - /** - * Constructs a default InfoOverlay control with no node or text. - */ - public InfoOverlay() { - this((Node)null, null); - } - - /** - * Attempts to construct an InfoOverlay instance using the given string - * to load an image, and to place the given text string over top of it. - * - * @param imageUrl The image file to attempt to load. - * @param text The text to display over top of the image. - */ - public InfoOverlay(String imageUrl, String text) { - this(new ImageView(imageUrl), text); - } - - /** - * Constructs an InfoOverlay instance using the given Node (which can be - * an arbitrarily complex node / scenegraph, or a simple ImageView, for example), - * and places the given text string over top of it. - * - * @param content The arbitrarily complex scenegraph over which the text will be displayed. - * @param text The text to display over top of the node. - */ - public InfoOverlay(Node content, String text) { - getStyleClass().setAll(DEFAULT_STYLE_CLASS); - - setContent(content); - setText(text); - } - - - - /*************************************************************************** - * * - * Public API * - * * - **************************************************************************/ - - /** {@inheritDoc} */ - @Override protected Skin<?> createDefaultSkin() { - return new InfoOverlaySkin(this); - } - - - - /*************************************************************************** - * * - * Properties * - * * - **************************************************************************/ - - // --- content - private ObjectProperty<Node> content = new SimpleObjectProperty<>(this, "content"); //$NON-NLS-1$ - - /** - * - * @return an {@link ObjectProperty} containing the arbitrarily complex - * scenegraph over which the text will be displayed. - */ - public final ObjectProperty<Node> contentProperty() { - return content; - } - - /** - * Sets a new value for the {@link #contentProperty() }. - * @param content - */ - public final void setContent(Node content) { - contentProperty().set(content); - } - - /** - * - * @return the arbitrarily complex scenegraph over which the text will be - * displayed. - */ - public final Node getContent() { - return contentProperty().get(); - } - - - // --- text - - private StringProperty text = new SimpleStringProperty(this, "text"); //$NON-NLS-1$ - - /** - * @return A {@link StringProperty} representing the text displayed over top - * of the {@link #contentProperty() content}. - */ - public final StringProperty textProperty() { - return text; - } - - /** - * - * @return The text displayed over top of the {@link #contentProperty() content}. - */ - public final String getText() { - return textProperty().get(); - } - - /** - * Specifies the text to display over top of the {@link #contentProperty() content}. - * @param text - */ - public final void setText(String text) { - textProperty().set(text); - } - - - // --- showOnHover - private BooleanProperty showOnHover = new SimpleBooleanProperty(this, "showOnHover", true); //$NON-NLS-1$ - - /** - * - * @return A {@link BooleanProperty} representing whether the overlay on - * hover of the content node is showing. - */ - public final BooleanProperty showOnHoverProperty() { - return showOnHover; - } - - /** - * - * @return whether the overlay on hover of the content node is showing. - */ - public final boolean isShowOnHover() { - return showOnHoverProperty().get(); - } - - /** - * Specifies whether to show the overlay on hover of the content node (and - * to hide it again when the content is no longer being hovered). By default - * this is true. - * @param value - */ - public final void setShowOnHover(boolean value) { - showOnHoverProperty().set(value); - } - - - - /*************************************************************************** - * * - * Stylesheet Handling * - * * - **************************************************************************/ - - private static final String DEFAULT_STYLE_CLASS = "info-overlay"; //$NON-NLS-1$ - - /** {@inheritDoc} */ - @Override public String getUserAgentStylesheet() { - return getUserAgentStylesheet(InfoOverlay.class, "info-overlay.css"); - } -} diff --git a/src/org/controlsfx/control/ListSelectionView.java b/src/org/controlsfx/control/ListSelectionView.java deleted file mode 100644 index 6c6d669..0000000 --- a/src/org/controlsfx/control/ListSelectionView.java +++ /dev/null @@ -1,370 +0,0 @@ -/** - * Copyright (c) 2014, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control; - -import static impl.org.controlsfx.i18n.Localization.asKey; -import static impl.org.controlsfx.i18n.Localization.localize; - -import impl.org.controlsfx.skin.ListSelectionViewSkin; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.geometry.Orientation; -import javafx.scene.Node; -import javafx.scene.control.Cell; -import javafx.scene.control.Label; -import javafx.scene.control.ListCell; -import javafx.scene.control.ListView; -import javafx.scene.control.Skin; -import javafx.util.Callback; - -/** - * A control used to perform a multi-selection via the help of two list views. - * Items can be moved from one list (source) to the other (target). This can be - * done by either double clicking on the list items or by using one of the - * "move" buttons between the two lists. Each list can be decorated with a - * header and a footer node. The default header nodes are simply two labels - * ("Available", "Selected"). - * - * <h3>Screenshot</h3> - * - * <center><img src="list-selection-view.png" alt="Screenshot of ListSelectionView"></center> - * - * <h3>Code Example</h3> - * - * <pre> - * ListSelectionView<String> view = new ListSelectionView<>(); - * view.getSourceItems().add("One", "Two", "Three"); - * view.getTargetItems().add("Four", "Five"); - * </pre> - * - * @param <T> - * the type of the list items - */ -public class ListSelectionView<T> extends ControlsFXControl { - - private static final String DEFAULT_STYLECLASS = "list-selection-view"; - - /** - * Constructs a new dual list view. - */ - public ListSelectionView() { - getStyleClass().add(DEFAULT_STYLECLASS); - - Label sourceHeader = new Label( - localize(asKey("listSelectionView.header.source"))); - sourceHeader.getStyleClass().add("list-header-label"); - sourceHeader.setId("source-header-label"); - setSourceHeader(sourceHeader); - - Label targetHeader = new Label( - localize(asKey("listSelectionView.header.target"))); - targetHeader.getStyleClass().add("list-header-label"); - targetHeader.setId("target-header-label"); - setTargetHeader(targetHeader); - } - - @Override - protected Skin<ListSelectionView<T>> createDefaultSkin() { - return new ListSelectionViewSkin<>(this); - } - - /** {@inheritDoc} */ - @Override public String getUserAgentStylesheet() { - return getUserAgentStylesheet(ListSelectionView.class, "listselectionview.css"); - } - - private final ObjectProperty<Node> sourceHeader = new SimpleObjectProperty<>( - this, "sourceHeader"); - - /** - * A property used to store a reference to a node that will be displayed - * above the source list view. The default node is a {@link Label} - * displaying the text "Available". - * - * @return the property used to store the source header node - */ - public final ObjectProperty<Node> sourceHeaderProperty() { - return sourceHeader; - } - - /** - * Returns the value of {@link #sourceHeaderProperty()}. - * - * @return the source header node - */ - public final Node getSourceHeader() { - return sourceHeader.get(); - } - - /** - * Sets the value of {@link #sourceHeaderProperty()}. - * - * @param node - * the new header node to use for the source list - */ - public final void setSourceHeader(Node node) { - sourceHeader.set(node); - } - - private final ObjectProperty<Node> sourceFooter = new SimpleObjectProperty<>( - this, "sourceFooter"); - - /** - * A property used to store a reference to a node that will be displayed - * below the source list view. The default node is a node with two buttons - * for easily selecting / deselecting all elements in the list view. - * - * @return the property used to store the source footer node - */ - public final ObjectProperty<Node> sourceFooterProperty() { - return sourceFooter; - } - - /** - * Returns the value of {@link #sourceFooterProperty()}. - * - * @return the source footer node - */ - public final Node getSourceFooter() { - return sourceFooter.get(); - } - - /** - * Sets the value of {@link #sourceFooterProperty()}. - * - * @param node - * the new node shown below the source list - */ - public final void setSourceFooter(Node node) { - sourceFooter.set(node); - } - - private final ObjectProperty<Node> targetHeader = new SimpleObjectProperty<>( - this, "targetHeader"); - - /** - * A property used to store a reference to a node that will be displayed - * above the target list view. The default node is a {@link Label} - * displaying the text "Selected". - * - * @return the property used to store the target header node - */ - public final ObjectProperty<Node> targetHeaderProperty() { - return targetHeader; - } - - /** - * Returns the value of {@link #targetHeaderProperty()}. - * - * @return the source header node - */ - public final Node getTargetHeader() { - return targetHeader.get(); - } - - /** - * Sets the value of {@link #targetHeaderProperty()}. - * - * @param node - * the new node shown above the target list - */ - public final void setTargetHeader(Node node) { - targetHeader.set(node); - } - - private final ObjectProperty<Node> targetFooter = new SimpleObjectProperty<>( - this, "targetFooter"); - - /** - * A property used to store a reference to a node that will be displayed - * below the target list view. The default node is a node with two buttons - * for easily selecting / deselecting all elements in the list view. - * - * @return the property used to store the source footer node - */ - public final ObjectProperty<Node> targetFooterProperty() { - return targetFooter; - } - - /** - * Returns the value of {@link #targetFooterProperty()}. - * - * @return the source header node - */ - public final Node getTargetFooter() { - return targetFooter.get(); - } - - /** - * Sets the value of {@link #targetFooterProperty()}. - * - * @param node - * the new node shown below the target list - */ - public final void setTargetFooter(Node node) { - targetFooter.set(node); - } - - private ObjectProperty<ObservableList<T>> sourceItems; - - /** - * Sets the underlying data model for the ListView. Note that it has a - * generic type that must match the type of the ListView itself. - */ - public final void setSourceItems(ObservableList<T> value) { - sourceItemsProperty().set(value); - } - - /** - * Returns an {@link ObservableList} that contains the items currently being - * shown to the user in the source list. This may be null if - * {@link #setSourceItems(javafx.collections.ObservableList)} has previously - * been called, however, by default it is an empty ObservableList. - * - * @return An ObservableList containing the items to be shown to the user in - * the source list, or null if the items have previously been set to - * null. - */ - public final ObservableList<T> getSourceItems() { - return sourceItemsProperty().get(); - } - - /** - * The underlying data model for the source list view. Note that it has a - * generic type that must match the type of the source list view itself. - */ - public final ObjectProperty<ObservableList<T>> sourceItemsProperty() { - if (sourceItems == null) { - sourceItems = new SimpleObjectProperty<>(this, "sourceItems", - FXCollections.observableArrayList()); - } - return sourceItems; - } - - private ObjectProperty<ObservableList<T>> targetItems; - - /** - * Sets the underlying data model for the ListView. Note that it has a - * generic type that must match the type of the ListView itself. - */ - public final void setTargetItems(ObservableList<T> value) { - targetItemsProperty().set(value); - } - - /** - * Returns an {@link ObservableList} that contains the items currently being - * shown to the user in the target list. This may be null if - * {@link #setTargetItems(javafx.collections.ObservableList)} has previously - * been called, however, by default it is an empty ObservableList. - * - * @return An ObservableList containing the items to be shown to the user in - * the target list, or null if the items have previously been set to - * null. - */ - public final ObservableList<T> getTargetItems() { - return targetItemsProperty().get(); - } - - /** - * The underlying data model for the target list view. Note that it has a - * generic type that must match the type of the source list view itself. - */ - public final ObjectProperty<ObservableList<T>> targetItemsProperty() { - if (targetItems == null) { - targetItems = new SimpleObjectProperty<>(this, "targetItems", - FXCollections.observableArrayList()); - } - return targetItems; - } - - // --- Orientation - private final ObjectProperty<Orientation> orientation = new SimpleObjectProperty<>( - this, "orientation", Orientation.HORIZONTAL); //$NON-NLS-1$; - - /** - * The {@link Orientation} of the {@code ListSelectionView} - this can - * either be horizontal or vertical. - */ - public final ObjectProperty<Orientation> orientationProperty() { - return orientation; - } - - /** - * Sets the {@link Orientation} of the {@code ListSelectionView} - this can - * either be horizontal or vertical. - */ - public final void setOrientation(Orientation value) { - orientationProperty().set(value); - }; - - /** - * Returns the {@link Orientation} of the {@code ListSelectionView} - this - * can either be horizontal or vertical. - */ - public final Orientation getOrientation() { - return orientation.get(); - } - - // --- Cell Factory - private ObjectProperty<Callback<ListView<T>, ListCell<T>>> cellFactory; - - /** - * Sets a new cell factory to use by both list views. This forces all old - * {@link ListCell}'s to be thrown away, and new ListCell's created with the - * new cell factory. - */ - public final void setCellFactory(Callback<ListView<T>, ListCell<T>> value) { - cellFactoryProperty().set(value); - } - - /** - * Returns the current cell factory. - */ - public final Callback<ListView<T>, ListCell<T>> getCellFactory() { - return cellFactory == null ? null : cellFactory.get(); - } - - /** - * <p> - * Setting a custom cell factory has the effect of deferring all cell - * creation, allowing for total customization of the cell. Internally, the - * ListView is responsible for reusing ListCells - all that is necessary is - * for the custom cell factory to return from this function a ListCell which - * might be usable for representing any item in the ListView. - * - * <p> - * Refer to the {@link Cell} class documentation for more detail. - */ - public final ObjectProperty<Callback<ListView<T>, ListCell<T>>> cellFactoryProperty() { - if (cellFactory == null) { - cellFactory = new SimpleObjectProperty<>(this, "cellFactory"); - } - return cellFactory; - } -} diff --git a/src/org/controlsfx/control/MaskerPane.java b/src/org/controlsfx/control/MaskerPane.java deleted file mode 100644 index 0003d46..0000000 --- a/src/org/controlsfx/control/MaskerPane.java +++ /dev/null @@ -1,117 +0,0 @@ -/** - * Copyright (c) 2014, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control; - -import impl.org.controlsfx.skin.MaskerPaneSkin; -import javafx.beans.property.*; -import javafx.scene.Node; -import javafx.scene.control.ProgressIndicator; -import javafx.scene.control.Skin; -import javafx.scene.layout.StackPane; - - -/** - * <p>MaskerPane is designed to be placed alongside other controls in a {@link StackPane}, - * in order to visually mask these controls, preventing them from being accessed - * for a short period of time. This comes in handy whenever waiting on asynchronous - * code to finish, and you do not want the user to be able to modify the state - * of the UI while waiting.</p> - * - * <p>To use this control, it is necessary to place it as the last child in a {@link StackPane}, - * with the other children being masked by this MaskerPane when visible. Simply use - * {@link #setVisible(boolean)} to toggle between visible states.</p> - */ -public class MaskerPane extends ControlsFXControl { - - /************************************************************************** - * - * Constructors - * - **************************************************************************/ - - /** - * Construct a new {@link MaskerPane} - */ - public MaskerPane() { getStyleClass().add("masker-pane"); } //$NON-NLS-1$ - - - - /************************************************************************** - * - * Properties - * - **************************************************************************/ - - // -- Background Color - - // -- Progress - private final DoubleProperty progress = new SimpleDoubleProperty(this, "progress", -1.0); //$NON-NLS-1$ - public final DoubleProperty progressProperty() { return progress; } - public final double getProgress() { return progress.get(); } - public final void setProgress(double progress) { this.progress.set(progress); } - - // -- Progress Node - private final ObjectProperty<Node> progressNode = new SimpleObjectProperty<Node>() { - { - ProgressIndicator node = new ProgressIndicator(); - node.progressProperty().bind(progress); - setValue(node); - } - - @Override public String getName() { return "progressNode"; } //$NON-NLS-1$ - @Override public Object getBean() { return MaskerPane.this; } - }; - public final ObjectProperty<Node> progressNodeProperty() { return progressNode; } - public final Node getProgressNode() { return progressNode.get();} - public final void setProgressNode(Node progressNode) { this.progressNode.set(progressNode); } - - // -- Progress Visibility - private final BooleanProperty progressVisible = new SimpleBooleanProperty(this, "progressVisible", true); //$NON-NLS-1$ - public final BooleanProperty progressVisibleProperty() { return progressVisible; } - public final boolean getProgressVisible() { return progressVisible.get(); } - public final void setProgressVisible(boolean progressVisible) { this.progressVisible.set(progressVisible); } - - // -- Text - private final StringProperty text = new SimpleStringProperty(this, "text", "Please Wait..."); //$NON-NLS-1$ - public final StringProperty textProperty() { return text; } - public final String getText() { return text.get(); } - public final void setText(String text) { this.text.set(text); } - - - - /************************************************************************** - * - * Interface implementation - * - **************************************************************************/ - - /** {@inheritDoc} */ - @Override protected Skin<?> createDefaultSkin() { return new MaskerPaneSkin(this); } - - /** {@inheritDoc} */ - @Override public String getUserAgentStylesheet() { return getUserAgentStylesheet(MaskerPane.class, "maskerpane.css"); } //$NON-NLS-1$ -} \ No newline at end of file diff --git a/src/org/controlsfx/control/MasterDetailPane.java b/src/org/controlsfx/control/MasterDetailPane.java deleted file mode 100644 index 18f1061..0000000 --- a/src/org/controlsfx/control/MasterDetailPane.java +++ /dev/null @@ -1,386 +0,0 @@ -/** - * Copyright (c) 2014, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control; - -import impl.org.controlsfx.skin.MasterDetailPaneSkin; - -import java.util.Objects; - -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.DoubleProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.SimpleDoubleProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.geometry.Pos; -import javafx.geometry.Side; -import javafx.scene.Node; -import javafx.scene.control.Label; -import javafx.scene.control.Skin; - -/** - * A master / detail pane is used to display two nodes with a strong - * relationship to each other. Most of the time the user works with the - * information displayed in the master node but every once in a while additional - * information is required and can be made visible via the detail node. By - * default the detail appears with a short slide-in animation and disappears - * with a slide-out. This control allows the detail node to be positioned in - * four different locations (top, bottom, left, or right). - * <h3>Screenshot</h3> - * To better describe what a master / detail pane is, please refer to the picture - * below: - * <center><img src="masterDetailPane.png" alt="Screenshot of MasterDetailPane"></center> - * <h3>Code Sample</h3> - * <pre> - * {@code - * MasterDetailPane pane = new MasterDetailPane(); - * pane.setMasterNode(new TableView()); - * pane.setDetailNode(new PropertySheet()); - * pane.setDetailSide(Side.RIGHT); - * pane.setShowDetailNode(true); - * }</pre> - */ -public class MasterDetailPane extends ControlsFXControl { - - /** - * Constructs a new pane. - * - * @param side - * the position where the detail will be shown (top, bottom, - * left, right) - * @param masterNode - * the master node (always visible) - * @param detailNode - * the detail node (slides in and out) - * @param showDetail - * the initial state of the detail node (shown or hidden) - */ - public MasterDetailPane(Side side, Node masterNode, Node detailNode, - boolean showDetail) { - - super(); - - Objects.requireNonNull(side); - Objects.requireNonNull(masterNode); - Objects.requireNonNull(detailNode); - - getStyleClass().add("master-detail-pane"); //$NON-NLS-1$ - - setDetailSide(side); - setMasterNode(masterNode); - setDetailNode(detailNode); - setShowDetailNode(showDetail); - - switch (side) { - case BOTTOM: - case RIGHT: - setDividerPosition(.8); - break; - case TOP: - case LEFT: - setDividerPosition(.2); - break; - default: - break; - - } - } - - /** - * Constructs a new pane with two placeholder nodes. - * - * @param pos - * the position where the details will be shown (top, bottom, - * left, right) - * @param showDetail - * the initial state of the detail node (shown or hidden) - */ - public MasterDetailPane(Side pos, boolean showDetail) { - this(pos, new Placeholder(true), new Placeholder(false), showDetail); - } - - /** - * Constructs a new pane with two placeholder nodes. The detail node will be - * shown. - * - * @param pos - * the position where the details will be shown (top, bottom, - * left, right) - */ - public MasterDetailPane(Side pos) { - this(pos, new Placeholder(true), new Placeholder(false), true); - } - - /** - * Constructs a new pane with two placeholder nodes. The detail node will be - * shown and to the right of the master node. - */ - public MasterDetailPane() { - this(Side.RIGHT, new Placeholder(true), new Placeholder(false), true); - } - - /** {@inheritDoc} */ - @Override protected Skin<?> createDefaultSkin() { - return new MasterDetailPaneSkin(this); - } - - /** {@inheritDoc} */ - @Override public String getUserAgentStylesheet() { - return getUserAgentStylesheet(MasterDetailPane.class, "masterdetailpane.css"); - } - - // Detail postion support - - private final ObjectProperty<Side> detailSide = new SimpleObjectProperty<>( - this, "detailSide", Side.RIGHT); //$NON-NLS-1$ - - /** - * The property used to store the side where the detail node will be shown. - * - * @return the details side property - */ - public final ObjectProperty<Side> detailSideProperty() { - return detailSide; - } - - /** - * Returns the value of the detail side property. - * - * @return the side where the detail node will be shown (left, right, top, - * bottom) - */ - public final Side getDetailSide() { - return detailSideProperty().get(); - } - - /** - * Sets the value of the detail side property. - * - * @param side - * the side where the detail node will be shown (left, right, - * top, bottom) - */ - public final void setDetailSide(Side side) { - Objects.requireNonNull(side); - detailSideProperty().set(side); - } - - // Show / hide detail node support. - - private final BooleanProperty showDetailNode = new SimpleBooleanProperty( - this, "showDetailNode", true); //$NON-NLS-1$ - - /** - * The property used to store the visibility of the detail node. - * - * @return true if the pane is currently expanded (shows the detail node) - */ - public final BooleanProperty showDetailNodeProperty() { - return showDetailNode; - } - - /** - * Returns the value of the "show detail node" property. - * - * @return true if the pane is currently expanded (shows the detail node) - */ - public final boolean isShowDetailNode() { - return showDetailNodeProperty().get(); - } - - /** - * Sets the value of the "show detail node" property. - * - * @param show - * if true the pane will show the detail node - */ - public final void setShowDetailNode(boolean show) { - showDetailNodeProperty().set(show); - } - - // Master node support. - - private final ObjectProperty<Node> masterNode = new SimpleObjectProperty<>( - this, "masterNode"); //$NON-NLS-1$ - - /** - * The property used to store the master node. - * - * @return the master node property - */ - public final ObjectProperty<Node> masterNodeProperty() { - return masterNode; - } - - /** - * Returns the value of the master node property. - * - * @return the master node - */ - public final Node getMasterNode() { - return masterNodeProperty().get(); - } - - /** - * Sets the value of the master node property. - * - * @param node - * the new master node - */ - public final void setMasterNode(Node node) { - Objects.requireNonNull(node); - masterNodeProperty().set(node); - } - - // Detail node support. - - private final ObjectProperty<Node> detailNode = new SimpleObjectProperty<>( - this, "detailNode"); //$NON-NLS-1$ - - /** - * The property used to store the detail node. - * - * @return the detail node property - */ - public final ObjectProperty<Node> detailNodeProperty() { - return detailNode; - } - - /** - * Returns the value of the detail node property. - * - * @return the detail node - */ - public final Node getDetailNode() { - return detailNodeProperty().get(); - } - - /** - * Sets the value of the detail node property. - * - * @param node - * the new master node - */ - public final void setDetailNode(Node node) { - Objects.requireNonNull(node); - detailNodeProperty().set(node); - } - - // Animation support. - - private final BooleanProperty animated = new SimpleBooleanProperty(this, - "animated", true); //$NON-NLS-1$ - - /** - * The property used to store the "animated" flag. If true then the detail - * node will be shown / hidden with a short slide in / out animation. - * - * @return the "animated" property - */ - public final BooleanProperty animatedProperty() { - return animated; - } - - /** - * Returns the value of the "animated" property. - * - * @return true if the detail node will be shown with a short animation - * (slide in) - */ - public final boolean isAnimated() { - return animatedProperty().get(); - } - - /** - * Sets the value of the "animated" property. - * - * @param animated - * if true the detail node will be shown with a short animation - * (slide in) - */ - public final void setAnimated(boolean animated) { - animatedProperty().set(animated); - } - - private DoubleProperty dividerPosition = new SimpleDoubleProperty(this, - "dividerPosition", .33); //$NON-NLS-1$ - - /** - * Stores the location of the divider. - * - * @return the divider location - */ - public final DoubleProperty dividerPositionProperty() { - return dividerPosition; - } - - /** - * Returns the value of the divider position property. - * - * @return the position of the divider - */ - public final double getDividerPosition() { - return dividerPosition.get(); - } - - /** - * Sets the value of the divider position property. - * - * @param position - * the new divider position. - */ - public final void setDividerPosition(double position) { - /** - * See https://bitbucket.org/controlsfx/controlsfx/issue/145/divider-position-in-masterdetailpane-is - * - * Thie work-around is not the best ever found but at least it works. - */ - if(getDividerPosition() == position){ - dividerPosition.set(-1); - } - dividerPosition.set(position); - } - - /* - * A placeholder for the constructors that do not accept a master or a - * detail node. - */ - private static final class Placeholder extends Label { - - public Placeholder(boolean master) { - super(master ? "Master" : "Detail"); //$NON-NLS-1$ //$NON-NLS-2$ - - setAlignment(Pos.CENTER); - - if (master) { - setStyle("-fx-background-color: -fx-background;"); //$NON-NLS-1$ - } else { - setStyle("-fx-background-color: derive(-fx-background, -10%);"); //$NON-NLS-1$ - } - } - } -} diff --git a/src/org/controlsfx/control/NotificationPane.java b/src/org/controlsfx/control/NotificationPane.java deleted file mode 100644 index 4bb82b9..0000000 --- a/src/org/controlsfx/control/NotificationPane.java +++ /dev/null @@ -1,630 +0,0 @@ -/** - * Copyright (c) 2013, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control; - -import impl.org.controlsfx.skin.NotificationPaneSkin; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.ReadOnlyBooleanProperty; -import javafx.beans.property.ReadOnlyBooleanWrapper; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.property.StringProperty; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.event.Event; -import javafx.event.EventHandler; -import javafx.event.EventType; -import javafx.scene.Node; -import javafx.scene.control.Skin; -import javafx.scene.web.WebView; - -import org.controlsfx.control.action.Action; - -/** - * The NotificationPane control is a container control that, when prompted by - * the {@link #show()} method, will show a non-modal message to the user. The - * notification appears as a bar that will slide in to their application window, - * either from the top or the bottom of the NotificationPane (based on - * {@link #showFromTopProperty()}) wherever that may be in the scenegraph. - * - * <h3>Alternative Styling</h3> - * <p>As is visible in the screenshots further down this documentation, - * there are two different styles supported by the NotificationPane control. - * Firstly, there is the default style based on the JavaFX Modena look. The - * alternative style is what is currently referred to as the 'dark' look. To - * enable this functionality, simply do the following: - * - * <pre> - * {@code - * NotificationPane notificationPane = new NotificationPane(); - * notificationPane.getStyleClass().add(NotificationPane.STYLE_CLASS_DARK); - * }</pre> - * - * <h3>Screenshots</h3> - * <p>To better explain NotificationPane, here is a table showing both the - * default and dark look for the NotificationPane on a Windows machine (although - * that shouldn't impact the visuals a great deal). Also, to show the difference - * between top and bottom placement, these two modes are also captured in the - * screenshots below: - * - * <br> - * <center> - * <table style="border: 1px solid gray; max-width:750px" summary="NotificationPane Screenshots"> - * <tr> - * <th width="200"><center><h3>Setting</h3></center></th> - * <th width="520"><center><h3>Screenshot</h3></center></th> - * </tr> - * <tr> - * <td valign="top" style="text-align:center;"><strong>Light theme from top:</strong></td> - * <td><center><img src="notication-pane-light-top.png" alt="Screenshot of NotificationPane - Light theme from top"></center></td> - * </tr> - * <tr> - * <td valign="top" style="text-align:center;"><strong>Light theme from bottom:</strong></td> - * <td><center><img src="notication-pane-light-bottom.png" alt="Screenshot of NotificationPane - Light theme from bottom"></center></td> - * </tr> - * <tr> - * <td valign="top" style="text-align:center;"><strong>Dark theme from top:</strong></td> - * <td><center><img src="notication-pane-dark-top.png" alt="Screenshot of NotificationPane - Dark theme from top"></center></td> - * </tr> - * <tr> - * <td valign="top" style="text-align:center;"><strong>Dark theme from bottom:</strong></td> - * <td><center><img src="notication-pane-dark-bottom.png" alt="Screenshot of NotificationPane - Dark theme from bottom"></center></td> - * </tr> - * </table> - * </center> - * - * <h3>Code Examples</h3> - * - * <p>NotificationPane is a conceptually very simple control - you simply create - * your user interface as you normally would, and then wrap it inside the - * NotificationPane. You can then show a notification bar on top of your content - * simply by calling {@link #show()} on the notification bar. Here is an example: - * - * <pre> - * {@code - * // Create a WebView - * WebView webView = new WebView(); - * - * // Wrap it inside a NotificationPane - * NotificationPane notificationPane = new NotificationPane(webView); - * - * // and put the NotificationPane inside a Tab - * Tab tab1 = new Tab("Tab 1"); - * tab1.setContent(notificationPane); - * - * // and the Tab inside a TabPane. We just have one tab here, but of course - * // you can have more! - * TabPane tabPane = new TabPane(); - * tabPane.getTabs().addAll(tab1); - * }</pre> - * - * <p>Now that the notification pane is installed inside the tab, at some point - * later in you application lifecycle, you can do something like the following - * to have the notification bar slide into view: - * - * <pre> - * {@code - * notificationPane.setText("Do you want to save your password?"); - * notificationPane.getActions().add(new AbstractAction("Save Password") { - * public void execute(ActionEvent ae) { - * // do save... - * - * // then hide... - * notificationPane.hide(); - * } - * }}</pre> - * - * @see Action - */ -public class NotificationPane extends ControlsFXControl { - - /*************************************************************************** - * - * Static fields - * - **************************************************************************/ - - public static final String STYLE_CLASS_DARK = "dark"; //$NON-NLS-1$ - - /** - * Called when the NotificationPane <b>will</b> be shown. - */ - public static final EventType<Event> ON_SHOWING = - new EventType<>(Event.ANY, "NOTIFICATION_PANE_ON_SHOWING"); //$NON-NLS-1$ - - /** - * Called when the NotificationPane shows. - */ - public static final EventType<Event> ON_SHOWN = - new EventType<>(Event.ANY, "NOTIFICATION_PANE_ON_SHOWN"); //$NON-NLS-1$ - - /** - * Called when the NotificationPane <b>will</b> be hidden. - */ - public static final EventType<Event> ON_HIDING = - new EventType<>(Event.ANY, "NOTIFICATION_PANE_ON_HIDING"); //$NON-NLS-1$ - - /** - * Called when the NotificationPane is hidden. - */ - public static final EventType<Event> ON_HIDDEN = - new EventType<>(Event.ANY, "NOTIFICATION_PANE_ON_HIDDEN"); //$NON-NLS-1$ - - - - /*************************************************************************** - * - * Constructors - * - **************************************************************************/ - - /** - * Creates an instance of NotificationPane with no - * {@link #contentProperty() content}, {@link #textProperty() text}, - * {@link #graphicProperty() graphic} properties set, and no - * {@link #getActions() actions} specified. - */ - public NotificationPane() { - this(null); - } - - /** - * Creates an instance of NotificationPane with the - * {@link #contentProperty() content} property set, but no - * {@link #textProperty() text} or - * {@link #graphicProperty() graphic} property set, and no - * {@link #getActions() actions} specified. - * - * @param content The content to show in the NotificationPane behind where - * the notification bar will appear, that is, the content - * <strong>will not</strong>appear in the notification bar. - */ - public NotificationPane(Node content) { - getStyleClass().add(DEFAULT_STYLE_CLASS); - setContent(content); - - updateStyleClasses(); - } - - - - /*************************************************************************** - * - * Overriding public API - * - **************************************************************************/ - - /** {@inheritDoc} */ - @Override protected Skin<?> createDefaultSkin() { - return new NotificationPaneSkin(this); - } - - /** {@inheritDoc} */ - @Override public String getUserAgentStylesheet() { - return getUserAgentStylesheet(NotificationPane.class, "notificationpane.css"); - } - - /*************************************************************************** - * - * Properties - * - **************************************************************************/ - - // --- content - private ObjectProperty<Node> content = new SimpleObjectProperty<>(this, "content"); //$NON-NLS-1$ - - /** - * The content property represents what is shown in the scene - * <strong>that is not within</strong> the notification bar. In other words, - * it is what the notification bar should appear on top of. For example, in - * the scenario where you are using a {@link WebView} to show to the user - * websites, and you want to popup up a notification bar to save a password, - * the content would be the {@link WebView}. Refer to the - * {@link NotificationPane} class documentation for more details. - * - * @return A property representing the content of this NotificationPane. - */ - public final ObjectProperty<Node> contentProperty() { - return content; - } - - /** - * Set the content to be shown in the scene, - * <strong>that is not within</strong> the notification bar. - * @param value - */ - public final void setContent(Node value) { - this.content.set(value); - } - - /** - * - * @return The content shown in the scene. - */ - public final Node getContent() { - return content.get(); - } - - - // --- text - private StringProperty text = new SimpleStringProperty(this, "text"); //$NON-NLS-1$ - - /** - * The text property represents the text to show within the popup - * notification bar that appears on top of the - * {@link #contentProperty() content} that is within the NotificationPane. - * - * @return A property representing the text shown in the notification bar. - */ - public final StringProperty textProperty() { - return text; - } - - /** - * Sets the text to show within the popup - * notification bar that appears on top of the - * {@link #contentProperty() content}. - * @param value - */ - public final void setText(String value) { - this.text.set(value); - } - - /** - * - * @return the text showing within the popup - * notification bar that appears on top of the - * {@link #contentProperty() content}. - */ - public final String getText() { - return text.get(); - } - - - // --- graphic - private ObjectProperty<Node> graphic = new SimpleObjectProperty<>(this, "graphic"); //$NON-NLS-1$ - - /** - * The graphic property represents the {@link Node} to show within the popup - * notification bar that appears on top of the - * {@link #contentProperty() content} that is within the NotificationPane. - * Despite the term 'graphic', this can be an arbitrarily complex scenegraph - * in its own right. - * - * @return A property representing the graphic shown in the notification bar. - */ - public final ObjectProperty<Node> graphicProperty() { - return graphic; - } - - /** - * Sets the {@link Node} to show within the popup - * notification bar. - * @param value - */ - public final void setGraphic(Node value) { - this.graphic.set(value); - } - - /** - * - * @return the {@link Node} to show within the popup - * notification bar. - */ - public final Node getGraphic() { - return graphic.get(); - } - - - // --- showing - private ReadOnlyBooleanWrapper showing = new ReadOnlyBooleanWrapper(this, "showing"); //$NON-NLS-1$ - - /** - * A read-only property that represents whether the notification bar popup - * should be showing to the user or not. To toggle visibility, use the - * {@link #show()} and {@link #hide()} methods. - * - * @return A property representing whether the notification bar is currently showing. - */ - public final ReadOnlyBooleanProperty showingProperty() { - return showing.getReadOnlyProperty(); - } - private final void setShowing(boolean value) { - this.showing.set(value); - } - /** - * - * @return whether the notification bar is currently showing. - */ - public final boolean isShowing() { - return showing.get(); - } - - - // --- show from top - private BooleanProperty showFromTop = new SimpleBooleanProperty(this, "showFromTop", true) { //$NON-NLS-1$ - @Override protected void invalidated() { - updateStyleClasses(); - } - }; - - /** - * A property representing whether the notification bar should appear from the - * top or the bottom of the NotificationPane area. By default it will appear - * from the top, but this can be changed by setting this property to false. - * - * @return A property representing where the notification bar should appear from. - */ - public final BooleanProperty showFromTopProperty() { - return showFromTop; - } - - /** - * Sets whether the notification bar should appear from the - * top or the bottom of the NotificationPane area. - * @param value - */ - public final void setShowFromTop(boolean value) { - this.showFromTop.set(value); - } - - /** - * @return whether the notification bar is appearing from the - * top or the bottom of the NotificationPane area. - */ - public final boolean isShowFromTop() { - return showFromTop.get(); - } - - - // --- On Showing - public final ObjectProperty<EventHandler<Event>> onShowingProperty() { return onShowing; } - /** - * Called just prior to the {@code NotificationPane} being shown. - */ - public final void setOnShowing(EventHandler<Event> value) { onShowingProperty().set(value); } - public final EventHandler<Event> getOnShowing() { return onShowingProperty().get(); } - private ObjectProperty<EventHandler<Event>> onShowing = new SimpleObjectProperty<EventHandler<Event>>(this, "onShowing") { //$NON-NLS-1$ - @Override protected void invalidated() { - setEventHandler(ON_SHOWING, get()); - } - }; - - - // -- On Shown - public final ObjectProperty<EventHandler<Event>> onShownProperty() { return onShown; } - /** - * Called just after the {@link NotificationPane} is shown. - */ - public final void setOnShown(EventHandler<Event> value) { onShownProperty().set(value); } - public final EventHandler<Event> getOnShown() { return onShownProperty().get(); } - private ObjectProperty<EventHandler<Event>> onShown = new SimpleObjectProperty<EventHandler<Event>>(this, "onShown") { //$NON-NLS-1$ - @Override protected void invalidated() { - setEventHandler(ON_SHOWN, get()); - } - }; - - - // --- On Hiding - public final ObjectProperty<EventHandler<Event>> onHidingProperty() { return onHiding; } - /** - * Called just prior to the {@link NotificationPane} being hidden. - */ - public final void setOnHiding(EventHandler<Event> value) { onHidingProperty().set(value); } - public final EventHandler<Event> getOnHiding() { return onHidingProperty().get(); } - private ObjectProperty<EventHandler<Event>> onHiding = new SimpleObjectProperty<EventHandler<Event>>(this, "onHiding") { //$NON-NLS-1$ - @Override protected void invalidated() { - setEventHandler(ON_HIDING, get()); - } - }; - - - // --- On Hidden - public final ObjectProperty<EventHandler<Event>> onHiddenProperty() { return onHidden; } - /** - * Called just after the {@link NotificationPane} has been hidden. - */ - public final void setOnHidden(EventHandler<Event> value) { onHiddenProperty().set(value); } - public final EventHandler<Event> getOnHidden() { return onHiddenProperty().get(); } - private ObjectProperty<EventHandler<Event>> onHidden = new SimpleObjectProperty<EventHandler<Event>>(this, "onHidden") { //$NON-NLS-1$ - @Override protected void invalidated() { - setEventHandler(ON_HIDDEN, get()); - } - }; - - // --- close button visibility - private BooleanProperty closeButtonVisible = new SimpleBooleanProperty(this, "closeButtonVisible", true); //$NON-NLS-1$ - - /** - * A property representing whether the close button in the {@code NotificationPane} should be visible or not. - * By default it will appear but this can be changed by setting this property to false. - * - * @return A property representing whether the close button in the {@code NotificationPane} should be visible. - */ - public final BooleanProperty closeButtonVisibleProperty() { - return closeButtonVisible; - } - - /** - * Sets whether the close button in {@code NotificationPane} should be visible. - * - * @param value - */ - public final void setCloseButtonVisible(boolean value) { - this.closeButtonVisible.set(value); - } - - /** - * @return whether the close button in {@code NotificationPane} is visible. - */ - public final boolean isCloseButtonVisible() { - return closeButtonVisible.get(); - } - - /*************************************************************************** - * - * Public API - * - **************************************************************************/ - - // --- actions - private final ObservableList<Action> actions = FXCollections.<Action> observableArrayList(); - - /** - * Observable list of actions used for the actions area of the notification - * bar. Modifying the contents of this list will change the actions available to - * the user. - * @return The {@link ObservableList} of actions available to the user. - */ - public final ObservableList<Action> getActions() { - return actions; - } - - /** - * Call this to make the notification bar appear on top of the - * {@link #contentProperty() content} of this {@link NotificationPane}. - * If the notification bar is already showing this will be a no-op. - */ - public void show() { - setShowing(true); - } - - /** - * Shows the NotificationPane with the - * {@link #contentProperty() content} and {@link #textProperty() text} - * property set, but no {@link #graphicProperty() graphic} property set, and - * no {@link #getActions() actions} specified. - * - * @param text The text to show in the notification pane. - */ - public void show(final String text) { - hideAndThen(new Runnable() { - @Override public void run() { - setText(text); - setShowing(true); - } - }); - } - - /** - * Shows the NotificationPane with the - * {@link #contentProperty() content}, {@link #textProperty() text} and - * {@link #graphicProperty() graphic} properties set, but no - * {@link #getActions() actions} specified. - * - * @param text The text to show in the notification pane. - * @param graphic The node to show in the notification pane. - */ - public void show(final String text, final Node graphic) { - hideAndThen(new Runnable() { - @Override public void run() { - setText(text); - setGraphic(graphic); - setShowing(true); - } - }); - } - - /** - * Shows the NotificationPane with the - * {@link #contentProperty() content}, {@link #textProperty() text} and - * {@link #graphicProperty() graphic} property set, and the provided actions - * copied into the {@link #getActions() actions} list. - * - * @param text The text to show in the notification pane. - * @param graphic The node to show in the notification pane. - * @param actions The actions to show in the notification pane. - */ - public void show(final String text, final Node graphic, final Action... actions) { - hideAndThen(new Runnable() { - @Override public void run() { - setText(text); - setGraphic(graphic); - - if (actions == null) { - getActions().clear(); - } else { - for (Action action : actions) { - if (action == null) continue; - getActions().add(action); - } - } - - setShowing(true); - } - }); - } - - /** - * Call this to make the notification bar disappear from the - * {@link #contentProperty() content} of this {@link NotificationPane}. - * If the notification bar is already hidden this will be a no-op. - */ - public void hide() { - setShowing(false); - } - - - - /************************************************************************** - * * - * Private Implementation * - * * - **************************************************************************/ - - private void updateStyleClasses() { - getStyleClass().removeAll("top", "bottom"); //$NON-NLS-1$ //$NON-NLS-2$ - getStyleClass().add(isShowFromTop() ? "top" : "bottom"); //$NON-NLS-1$ //$NON-NLS-2$ - } - - private void hideAndThen(final Runnable r) { - if (isShowing()) { - final EventHandler<Event> eventHandler = new EventHandler<Event>() { - @Override public void handle(Event e) { - r.run(); - removeEventHandler(NotificationPane.ON_HIDDEN, this); - } - }; - addEventHandler(NotificationPane.ON_HIDDEN, eventHandler); - hide(); - } else { - r.run(); - } - } - - - - /************************************************************************** - * * - * Stylesheet Handling * - * * - **************************************************************************/ - - private static final String DEFAULT_STYLE_CLASS = "notification-pane"; //$NON-NLS-1$ -} diff --git a/src/org/controlsfx/control/Notifications.java b/src/org/controlsfx/control/Notifications.java deleted file mode 100644 index f223db1..0000000 --- a/src/org/controlsfx/control/Notifications.java +++ /dev/null @@ -1,645 +0,0 @@ -/** - * Copyright (c) 2014, 2016, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control; - -import impl.org.controlsfx.skin.NotificationBar; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import javafx.animation.KeyFrame; -import javafx.animation.KeyValue; -import javafx.animation.ParallelTransition; -import javafx.animation.Timeline; -import javafx.animation.Transition; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.event.ActionEvent; -import javafx.event.EventHandler; -import javafx.geometry.Pos; -import javafx.geometry.Rectangle2D; -import javafx.scene.Node; -import javafx.scene.Scene; -import javafx.scene.image.ImageView; -import javafx.stage.Popup; -import javafx.stage.PopupWindow; -import javafx.stage.Screen; -import javafx.stage.Window; -import javafx.util.Duration; - -import org.controlsfx.control.action.Action; -import org.controlsfx.tools.Utils; - -/** - * An API to show popup notification messages to the user in the corner of their - * screen, unlike the {@link NotificationPane} which shows notification messages - * within your application itself. - * - * <h3>Screenshot</h3> - * <p> - * The following screenshot shows a sample notification rising from the - * bottom-right corner of my screen: - * - * <br> - * <br> - * <img src="notifications.png" alt="Screenshot of Notifications"> - * - * <h3>Code Example:</h3> - * <p> - * To create the notification shown in the screenshot, simply do the following: - * - * <pre> - * {@code - * Notifications.create() - * .title("Title Text") - * .text("Hello World 0!") - * .showWarning(); - * } - * </pre> - */ -public class Notifications { - - /*************************************************************************** - * * Static fields * * - **************************************************************************/ - - private static final String STYLE_CLASS_DARK = "dark"; //$NON-NLS-1$ - - /*************************************************************************** - * * Private fields * * - **************************************************************************/ - - private String title; - private String text; - private Node graphic; - private ObservableList<Action> actions = FXCollections.observableArrayList(); - private Pos position = Pos.BOTTOM_RIGHT; - private Duration hideAfterDuration = Duration.seconds(5); - private boolean hideCloseButton; - private EventHandler<ActionEvent> onAction; - private Window owner; - private Screen screen = Screen.getPrimary(); - - private List<String> styleClass = new ArrayList<>(); - - /*************************************************************************** - * * Constructors * * - **************************************************************************/ - - // we do not allow instantiation of the Notifications class directly - users - // must go via the builder API (that is, calling create()) - private Notifications() { - // no-op - } - - /*************************************************************************** - * * Public API * * - **************************************************************************/ - - /** - * Call this to begin the process of building a notification to show. - */ - public static Notifications create() { - return new Notifications(); - } - - /** - * Specify the text to show in the notification. - */ - public Notifications text(String text) { - this.text = text; - return this; - } - - /** - * Specify the title to show in the notification. - */ - public Notifications title(String title) { - this.title = title; - return this; - } - - /** - * Specify the graphic to show in the notification. - */ - public Notifications graphic(Node graphic) { - this.graphic = graphic; - return this; - } - - /** - * Specify the position of the notification on screen, by default it is - * {@link Pos#BOTTOM_RIGHT bottom-right}. - */ - public Notifications position(Pos position) { - this.position = position; - return this; - } - - /** - * The dialog window owner - which can be {@link Screen}, {@link Window} - * or {@link Node}. If specified, the notifications will be inside - * the owner, otherwise the notifications will be shown within the whole - * primary (default) screen. - */ - public Notifications owner(Object owner) { - if (owner instanceof Screen) { - this.screen = (Screen) owner; - } else { - this.owner = Utils.getWindow(owner); - } - return this; - } - - /** - * Specify the duration that the notification should show, after which it - * will be hidden. - */ - public Notifications hideAfter(Duration duration) { - this.hideAfterDuration = duration; - return this; - } - - /** - * Specify what to do when the user clicks on the notification (in addition - * to the notification hiding, which happens whenever the notification is - * clicked on). - */ - public Notifications onAction(EventHandler<ActionEvent> onAction) { - this.onAction = onAction; - return this; - } - - /** - * Specify that the notification should use the built-in dark styling, - * rather than the default 'modena' notification style (which is a - * light-gray). - */ - public Notifications darkStyle() { - styleClass.add(STYLE_CLASS_DARK); - return this; - } - - /** - * Specify that the close button in the top-right corner of the notification - * should not be shown. - */ - public Notifications hideCloseButton() { - this.hideCloseButton = true; - return this; - } - - /** - * Specify the actions that should be shown in the notification as buttons. - */ - public Notifications action(Action... actions) { - this.actions = actions == null ? FXCollections.<Action> observableArrayList() : FXCollections - .observableArrayList(actions); - return this; - } - - /** - * Instructs the notification to be shown, and that it should use the - * built-in 'warning' graphic. - */ - public void showWarning() { - graphic(new ImageView(Notifications.class.getResource("/org/controlsfx/dialog/dialog-warning.png").toExternalForm())); //$NON-NLS-1$ - show(); - } - - /** - * Instructs the notification to be shown, and that it should use the - * built-in 'information' graphic. - */ - public void showInformation() { - graphic(new ImageView(Notifications.class.getResource("/org/controlsfx/dialog/dialog-information.png").toExternalForm())); //$NON-NLS-1$ - show(); - } - - /** - * Instructs the notification to be shown, and that it should use the - * built-in 'error' graphic. - */ - public void showError() { - graphic(new ImageView(Notifications.class.getResource("/org/controlsfx/dialog/dialog-error.png").toExternalForm())); //$NON-NLS-1$ - show(); - } - - /** - * Instructs the notification to be shown, and that it should use the - * built-in 'confirm' graphic. - */ - public void showConfirm() { - graphic(new ImageView(Notifications.class.getResource("/org/controlsfx/dialog/dialog-confirm.png").toExternalForm())); //$NON-NLS-1$ - show(); - } - - /** - * Instructs the notification to be shown. - */ - public void show() { - NotificationPopupHandler.getInstance().show(this); - } - - /*************************************************************************** - * * Private support classes * * - **************************************************************************/ - - // not public so no need for JavaDoc - private static final class NotificationPopupHandler { - - private static final NotificationPopupHandler INSTANCE = new NotificationPopupHandler(); - - private double startX; - private double startY; - private double screenWidth; - private double screenHeight; - - static final NotificationPopupHandler getInstance() { - return INSTANCE; - } - - private final Map<Pos, List<Popup>> popupsMap = new HashMap<>(); - private final double padding = 15; - - // for animating in the notifications - private ParallelTransition parallelTransition = new ParallelTransition(); - - private boolean isShowing = false; - - public void show(Notifications notification) { - Window window; - if (notification.owner == null) { - /* - * If the owner is not set, we work with the whole screen. - */ - Rectangle2D screenBounds = notification.screen.getVisualBounds(); - startX = screenBounds.getMinX(); - startY = screenBounds.getMinY(); - screenWidth = screenBounds.getWidth(); - screenHeight = screenBounds.getHeight(); - - window = Utils.getWindow(null); - } else { - /* - * If the owner is set, we will make the notifications popup - * inside its window. - */ - startX = notification.owner.getX(); - startY = notification.owner.getY(); - screenWidth = notification.owner.getWidth(); - screenHeight = notification.owner.getHeight(); - window = notification.owner; - } - show(window, notification); - } - - private void show(Window owner, final Notifications notification) { - // Stylesheets which are added to the scene of a popup aren't - // considered for styling. For this reason, we need to find the next - // window in the hierarchy which isn't a popup. - Window ownerWindow = owner; - while (ownerWindow instanceof PopupWindow) { - ownerWindow = ((PopupWindow) ownerWindow).getOwnerWindow(); - } - // need to install our CSS - Scene ownerScene = ownerWindow.getScene(); - if (ownerScene != null) { - String stylesheetUrl = Notifications.class.getResource("notificationpopup.css").toExternalForm(); //$NON-NLS-1$ - if (!ownerScene.getStylesheets().contains(stylesheetUrl)) { - // The stylesheet needs to be added at the beginning so that - // the styling can be adjusted with custom stylesheets. - ownerScene.getStylesheets().add(0, stylesheetUrl); - } - } - - final Popup popup = new Popup(); - popup.setAutoFix(false); - - final Pos p = notification.position; - - final NotificationBar notificationBar = new NotificationBar() { - @Override public String getTitle() { - return notification.title; - } - - @Override public String getText() { - return notification.text; - } - - @Override public Node getGraphic() { - return notification.graphic; - } - - @Override public ObservableList<Action> getActions() { - return notification.actions; - } - - @Override public boolean isShowing() { - return isShowing; - } - - @Override protected double computeMinWidth(double height) { - String text = getText(); - Node graphic = getGraphic(); - if ((text == null || text.isEmpty()) && (graphic != null)) { - return graphic.minWidth(height); - } - return 400; - } - - @Override protected double computeMinHeight(double width) { - String text = getText(); - Node graphic = getGraphic(); - if ((text == null || text.isEmpty()) && (graphic != null)) { - return graphic.minHeight(width); - } - return 100; - } - - @Override public boolean isShowFromTop() { - return NotificationPopupHandler.this.isShowFromTop(notification.position); - } - - @Override public void hide() { - isShowing = false; - - // this would slide the notification bar out of view, - // but I prefer the fade out below - // doHide(); - - // animate out the popup by fading it - createHideTimeline(popup, this, p, Duration.ZERO).play(); - } - - @Override public boolean isCloseButtonVisible() { - return !notification.hideCloseButton; - } - - @Override public double getContainerHeight() { - return startY + screenHeight; - } - - @Override public void relocateInParent(double x, double y) { - // this allows for us to slide the notification upwards - switch (p) { - case BOTTOM_LEFT: - case BOTTOM_CENTER: - case BOTTOM_RIGHT: - popup.setAnchorY(y - padding); - break; - default: - // no-op - break; - } - } - }; - - notificationBar.getStyleClass().addAll(notification.styleClass); - - notificationBar.setOnMouseClicked(e -> { - if (notification.onAction != null) { - ActionEvent actionEvent = new ActionEvent(notificationBar, notificationBar); - notification.onAction.handle(actionEvent); - - // animate out the popup - createHideTimeline(popup, notificationBar, p, Duration.ZERO).play(); - } - }); - - popup.getContent().add(notificationBar); - popup.show(owner, 0, 0); - - // determine location for the popup - double anchorX = 0, anchorY = 0; - final double barWidth = notificationBar.getWidth(); - final double barHeight = notificationBar.getHeight(); - - // get anchorX - switch (p) { - case TOP_LEFT: - case CENTER_LEFT: - case BOTTOM_LEFT: - anchorX = padding + startX; - break; - - case TOP_CENTER: - case CENTER: - case BOTTOM_CENTER: - anchorX = startX + (screenWidth / 2.0) - barWidth / 2.0 - padding / 2.0; - break; - - default: - case TOP_RIGHT: - case CENTER_RIGHT: - case BOTTOM_RIGHT: - anchorX = startX + screenWidth - barWidth - padding; - break; - } - - // get anchorY - switch (p) { - case TOP_LEFT: - case TOP_CENTER: - case TOP_RIGHT: - anchorY = padding + startY; - break; - - case CENTER_LEFT: - case CENTER: - case CENTER_RIGHT: - anchorY = startY + (screenHeight / 2.0) - barHeight / 2.0 - padding / 2.0; - break; - - default: - case BOTTOM_LEFT: - case BOTTOM_CENTER: - case BOTTOM_RIGHT: - anchorY = startY + screenHeight - barHeight - padding; - break; - } - - popup.setAnchorX(anchorX); - popup.setAnchorY(anchorY); - - isShowing = true; - notificationBar.doShow(); - - addPopupToMap(p, popup); - - // begin a timeline to get rid of the popup - Timeline timeline = createHideTimeline(popup, notificationBar, p, notification.hideAfterDuration); - timeline.play(); - } - - private void hide(Popup popup, Pos p) { - popup.hide(); - removePopupFromMap(p, popup); - } - - private Timeline createHideTimeline(final Popup popup, NotificationBar bar, final Pos p, Duration startDelay) { - KeyValue fadeOutBegin = new KeyValue(bar.opacityProperty(), 1.0); - KeyValue fadeOutEnd = new KeyValue(bar.opacityProperty(), 0.0); - - KeyFrame kfBegin = new KeyFrame(Duration.ZERO, fadeOutBegin); - KeyFrame kfEnd = new KeyFrame(Duration.millis(500), fadeOutEnd); - - Timeline timeline = new Timeline(kfBegin, kfEnd); - timeline.setDelay(startDelay); - timeline.setOnFinished(new EventHandler<ActionEvent>() { - @Override - public void handle(ActionEvent e) { - hide(popup, p); - } - }); - - return timeline; - } - - private void addPopupToMap(Pos p, Popup popup) { - List<Popup> popups; - if (!popupsMap.containsKey(p)) { - popups = new LinkedList<>(); - popupsMap.put(p, popups); - } else { - popups = popupsMap.get(p); - } - - doAnimation(p, popup); - - // add the popup to the list so it is kept in memory and can be - // accessed later on - popups.add(popup); - } - - private void removePopupFromMap(Pos p, Popup popup) { - if (popupsMap.containsKey(p)) { - List<Popup> popups = popupsMap.get(p); - popups.remove(popup); - } - } - - private void doAnimation(Pos p, Popup changedPopup) { - List<Popup> popups = popupsMap.get(p); - if (popups == null) { - return; - } - - final double newPopupHeight = changedPopup.getContent().get(0).getBoundsInParent().getHeight(); - - parallelTransition.stop(); - parallelTransition.getChildren().clear(); - - final boolean isShowFromTop = isShowFromTop(p); - - // animate all other popups in the list upwards so that the new one - // is in the 'new' area. - // firstly, we need to determine the target positions for all popups - double sum = 0; - double targetAnchors[] = new double[popups.size()]; - for (int i = popups.size() - 1; i >= 0; i--) { - Popup _popup = popups.get(i); - - final double popupHeight = _popup.getContent().get(0).getBoundsInParent().getHeight(); - - if (isShowFromTop) { - if (i == popups.size() - 1) { - sum = startY + newPopupHeight + padding; - } else { - sum += popupHeight; - } - targetAnchors[i] = sum; - } else { - if (i == popups.size() - 1) { - sum = changedPopup.getAnchorY() - popupHeight; - } else { - sum -= popupHeight; - } - - targetAnchors[i] = sum; - } - } - - // then we set up animations for each popup to animate towards the - // target - for (int i = popups.size() - 1; i >= 0; i--) { - final Popup _popup = popups.get(i); - final double anchorYTarget = targetAnchors[i]; - if(anchorYTarget < 0){ - _popup.hide(); - } - final double oldAnchorY = _popup.getAnchorY(); - final double distance = anchorYTarget - oldAnchorY; - - Transition t = new CustomTransition(_popup, oldAnchorY, distance); - t.setCycleCount(1); - parallelTransition.getChildren().add(t); - } - parallelTransition.play(); - } - - private boolean isShowFromTop(Pos p) { - switch (p) { - case TOP_LEFT: - case TOP_CENTER: - case TOP_RIGHT: - return true; - default: - return false; - } - } - - class CustomTransition extends Transition { - - private WeakReference<Popup> popupWeakReference; - private double oldAnchorY; - private double distance; - - CustomTransition(Popup popup, double oldAnchorY, double distance) { - popupWeakReference = new WeakReference<>(popup); - this.oldAnchorY = oldAnchorY; - this.distance = distance; - setCycleDuration(Duration.millis(350.0)); - } - - @Override - protected void interpolate(double frac) { - Popup popup = popupWeakReference.get(); - if (popup != null) { - double newAnchorY = oldAnchorY + distance * frac; - popup.setAnchorY(newAnchorY); - } - } - - } - } -} - diff --git a/src/org/controlsfx/control/PlusMinusSlider.java b/src/org/controlsfx/control/PlusMinusSlider.java deleted file mode 100644 index 8749ffd..0000000 --- a/src/org/controlsfx/control/PlusMinusSlider.java +++ /dev/null @@ -1,345 +0,0 @@ -/** - * Copyright (c) 2014, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control; - -import impl.org.controlsfx.skin.PlusMinusSliderSkin; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.ObjectPropertyBase; -import javafx.beans.property.ReadOnlyDoubleProperty; -import javafx.beans.property.ReadOnlyDoubleWrapper; -import javafx.collections.MapChangeListener; -import javafx.css.CssMetaData; -import javafx.css.PseudoClass; -import javafx.css.Styleable; -import javafx.css.StyleableObjectProperty; -import javafx.css.StyleableProperty; -import javafx.event.EventHandler; -import javafx.event.EventTarget; -import javafx.event.EventType; -import javafx.geometry.Orientation; -import javafx.scene.control.Control; -import javafx.scene.control.Skin; -import javafx.scene.input.InputEvent; - -import com.sun.javafx.css.converters.EnumConverter; - -/** - * A plus minus slider allows the user to continously fire an event carrying a - * value between -1 and +1 by moving a thumb from its center position to the - * left or right (or top and bottom) edge of the control. The thumb will - * automatically center itself again on the zero position when the user lets go - * of the mouse button. Scrolling through a large list of items at different - * speeds is one possible use case for a control like this. - * - * <center> <img src="plus-minus-slider.png" alt="Screenshot of PlusMinusSlider"> </center> - */ -public class PlusMinusSlider extends ControlsFXControl { - - private static final String DEFAULT_STYLE_CLASS = "plus-minus-slider"; //$NON-NLS-1$ - - private static final PseudoClass VERTICAL_PSEUDOCLASS_STATE = PseudoClass - .getPseudoClass("vertical"); //$NON-NLS-1$ - - private static final PseudoClass HORIZONTAL_PSEUDOCLASS_STATE = PseudoClass - .getPseudoClass("horizontal"); //$NON-NLS-1$ - - /** - * Constructs a new adjuster control with a default horizontal orientation. - */ - public PlusMinusSlider() { - getStyleClass().add(DEFAULT_STYLE_CLASS); - - setOrientation(Orientation.HORIZONTAL); - - /* - * We are "abusing" the properties map to pass the new value of the - * slider from the skin to the control. It has to be done this way - * because the value property of this control is "read-only". - */ - getProperties().addListener(new MapChangeListener<Object, Object>() { - @Override - public void onChanged(MapChangeListener.Change<? extends Object, ? extends Object> change) { - if (change.getKey().equals("plusminusslidervalue")) { //$NON-NLS-1$ - if (change.getValueAdded() != null) { - Double valueAdded = (Double) change.getValueAdded(); - value.set(valueAdded); - change.getMap().remove("plusminusslidervalue"); //$NON-NLS-1$ - } - } - }; - }); - } - - /** {@inheritDoc} */ - @Override public String getUserAgentStylesheet() { - return getUserAgentStylesheet(PlusMinusSlider.class, "plusminusslider.css"); - } - - @Override - protected Skin<?> createDefaultSkin() { - return new PlusMinusSliderSkin(this); - } - - private ReadOnlyDoubleWrapper value = new ReadOnlyDoubleWrapper(this, - "value", 0); //$NON-NLS-1$ - - /** - * Returns the value property of the adjuster. The value is always between - * -1 and +1. - * - * @return the value of the adjuster - */ - public final ReadOnlyDoubleProperty valueProperty() { - return value.getReadOnlyProperty(); - } - - /** - * Returns the value of the value property. - * - * @return the value of the adjuster [-1, +1] - * - * @see #valueProperty() - */ - public final double getValue() { - return valueProperty().get(); - } - - // orientation - - private ObjectProperty<Orientation> orientation; - - /** - * Sets the value of the orientation property. - * - * @param value - * the new orientation (horizontal, vertical). - * @see #orientationProperty() - */ - public final void setOrientation(Orientation value) { - orientationProperty().set(value); - } - - /** - * Returns the value of the orientation property. - * - * @return the current orientation of the control - * @see #orientationProperty() - */ - public final Orientation getOrientation() { - return orientation == null ? Orientation.HORIZONTAL : orientation.get(); - } - - /** - * Returns the stylable object property used for storing the orientation of - * the adjuster control. The CSS property "-fx-orientation" can be used to - * initialize this value. - * - * @return the orientation property - */ - public final ObjectProperty<Orientation> orientationProperty() { - if (orientation == null) { - orientation = new StyleableObjectProperty<Orientation>(null) { - @Override - protected void invalidated() { - final boolean vertical = (get() == Orientation.VERTICAL); - pseudoClassStateChanged(VERTICAL_PSEUDOCLASS_STATE, - vertical); - pseudoClassStateChanged(HORIZONTAL_PSEUDOCLASS_STATE, - !vertical); - } - - @Override - public CssMetaData<PlusMinusSlider, Orientation> getCssMetaData() { - return StyleableProperties.ORIENTATION; - } - - @Override - public Object getBean() { - return PlusMinusSlider.this; - } - - @Override - public String getName() { - return "orientation"; //$NON-NLS-1$ - } - }; - } - return orientation; - } - - // event support - - /** - * Stores the event handler that will be informed when the adjuster's value - * changes. - * - * @return the value change event handler property - */ - public final ObjectProperty<EventHandler<PlusMinusEvent>> onValueChangedProperty() { - return onValueChanged; - } - - /** - * Sets an event handler that will receive plus minus events when the user - * moves the adjuster's thumb. - * - * @param value - * the event handler - * - * @see #onValueChangedProperty() - */ - public final void setOnValueChanged(EventHandler<PlusMinusEvent> value) { - onValueChangedProperty().set(value); - } - - /** - * Returns the event handler that will be notified when the adjuster's value - * changes. - * - * @return An EventHandler. - */ - public final EventHandler<PlusMinusEvent> getOnValueChanged() { - return onValueChangedProperty().get(); - } - - private ObjectProperty<EventHandler<PlusMinusEvent>> onValueChanged = new ObjectPropertyBase<EventHandler<PlusMinusEvent>>() { - - @Override - protected void invalidated() { - setEventHandler(PlusMinusEvent.VALUE_CHANGED, get()); - } - - @Override - public Object getBean() { - return PlusMinusSlider.this; - } - - @Override - public String getName() { - return "onValueChanged"; //$NON-NLS-1$ - } - }; - - private static class StyleableProperties { - - private static final CssMetaData<PlusMinusSlider, Orientation> ORIENTATION = new CssMetaData<PlusMinusSlider, Orientation>( - "-fx-orientation", new EnumConverter<>( //$NON-NLS-1$ - Orientation.class), Orientation.VERTICAL) { - - @Override - public Orientation getInitialValue(PlusMinusSlider node) { - // A vertical Slider should remain vertical - return node.getOrientation(); - } - - @Override - public boolean isSettable(PlusMinusSlider n) { - return n.orientation == null || !n.orientation.isBound(); - } - - @SuppressWarnings("unchecked") - @Override - public StyleableProperty<Orientation> getStyleableProperty( - PlusMinusSlider n) { - return (StyleableProperty<Orientation>) n.orientationProperty(); - } - }; - - private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES; - static { - final List<CssMetaData<? extends Styleable, ?>> styleables = new ArrayList<>(Control.getClassCssMetaData()); - styleables.add(ORIENTATION); - - STYLEABLES = Collections.unmodifiableList(styleables); - } - } - - /** - * @return The CssMetaData associated with this class, which may include the - * CssMetaData of its super classes. - * @since JavaFX 8.0 - */ - public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() { - return StyleableProperties.STYLEABLES; - } - - /** - * An event class used by the {@link PlusMinusSlider} to inform event - * handlers about changes. - */ - public static class PlusMinusEvent extends InputEvent { - - private static final long serialVersionUID = 2881004583512990781L; - - public static final EventType<PlusMinusEvent> ANY = new EventType<>( - InputEvent.ANY, "ANY"); //$NON-NLS-1$ - - /** - * An event type used when the value property ( - * {@link PlusMinusSlider#valueProperty()}) changes. - */ - public static final EventType<PlusMinusEvent> VALUE_CHANGED = new EventType<>( - PlusMinusEvent.ANY, "VALUE_CHANGED"); //$NON-NLS-1$ - - private double value; - - /** - * Constructs a new event object. - * - * @param source - * the source of the event (always the - * {@link PlusMinusSlider}) - * @param target - * the target of the event (always the - * {@link PlusMinusSlider}) - * @param eventType - * the type of the event (e.g. {@link #VALUE_CHANGED}) - * @param value - * the actual current value of the adjuster - */ - public PlusMinusEvent(Object source, EventTarget target, - EventType<? extends InputEvent> eventType, double value) { - super(source, target, eventType); - - this.value = value; - } - - /** - * The value of the {@link PlusMinusSlider}. - * - * @return the value - */ - public double getValue() { - return value; - } - } -} diff --git a/src/org/controlsfx/control/PopOver.java b/src/org/controlsfx/control/PopOver.java deleted file mode 100644 index b98b4e5..0000000 --- a/src/org/controlsfx/control/PopOver.java +++ /dev/null @@ -1,1011 +0,0 @@ -/** - * Copyright (c) 2013, 2016 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control; - -import impl.org.controlsfx.skin.PopOverSkin; -import javafx.animation.FadeTransition; -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; -import javafx.beans.WeakInvalidationListener; -import javafx.beans.property.*; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.beans.value.WeakChangeListener; -import javafx.event.EventHandler; -import javafx.event.WeakEventHandler; -import javafx.geometry.Bounds; -import javafx.geometry.Insets; -import javafx.scene.Node; -import javafx.scene.control.Label; -import javafx.scene.control.PopupControl; -import javafx.scene.control.Skin; -import javafx.scene.layout.StackPane; -import javafx.stage.Window; -import javafx.stage.WindowEvent; -import javafx.util.Duration; - -import static impl.org.controlsfx.i18n.Localization.asKey; -import static impl.org.controlsfx.i18n.Localization.localize; -import static java.util.Objects.requireNonNull; -import static javafx.scene.input.MouseEvent.MOUSE_CLICKED; - -/** - * The PopOver control provides detailed information about an owning node in a - * popup window. The popup window has a very lightweight appearance (no default - * window decorations) and an arrow pointing at the owner. Due to the nature of - * popup windows the PopOver will move around with the parent window when the - * user drags it. <br> - * <center> <img src="popover.png" alt="Screenshot of PopOver"> </center> <br> - * The PopOver can be detached from the owning node by dragging it away from the - * owner. It stops displaying an arrow and starts displaying a title and a close - * icon. <br> - * <br> - * <center> <img src="popover-detached.png" - * alt="Screenshot of a detached PopOver"> </center> <br> - * The following image shows a popover with an accordion content node. PopOver - * controls are automatically resizing themselves when the content node changes - * its size.<br> - * <br> - * <center> <img src="popover-accordion.png" - * alt="Screenshot of PopOver containing an Accordion"> </center> <br> - * For styling apply stylesheets to the root pane of the PopOver. - * - * <h3>Example:</h3> - * - * <pre> - * PopOver popOver = new PopOver(); - * popOver.getRoot().getStylesheets().add(...); - * </pre> - * - */ -public class PopOver extends PopupControl { - - private static final String DEFAULT_STYLE_CLASS = "popover"; //$NON-NLS-1$ - - private static final Duration DEFAULT_FADE_DURATION = Duration.seconds(.2); - - private double targetX; - - private double targetY; - - private final SimpleBooleanProperty animated = new SimpleBooleanProperty(true); - private final ObjectProperty<Duration> fadeInDuration = new SimpleObjectProperty<>(DEFAULT_FADE_DURATION); - private final ObjectProperty<Duration> fadeOutDuration = new SimpleObjectProperty<>(DEFAULT_FADE_DURATION); - - /** - * Creates a pop over with a label as the content node. - */ - public PopOver() { - super(); - - getStyleClass().add(DEFAULT_STYLE_CLASS); - - getRoot().getStylesheets().add( - PopOver.class.getResource("popover.css").toExternalForm()); //$NON-NLS-1$ - - setAnchorLocation(AnchorLocation.WINDOW_TOP_LEFT); - setOnHiding(new EventHandler<WindowEvent>() { - @Override - public void handle(WindowEvent evt) { - setDetached(false); - } - }); - - /* - * Create some initial content. - */ - Label label = new Label(localize(asKey("popOver.default.content"))); //$NON-NLS-1$ - label.setPrefSize(200, 200); - label.setPadding(new Insets(4)); - setContentNode(label); - - InvalidationListener repositionListener = observable -> { - if (isShowing() && !isDetached()) { - show(getOwnerNode(), targetX, targetY); - adjustWindowLocation(); - } - }; - - arrowSize.addListener(repositionListener); - cornerRadius.addListener(repositionListener); - arrowLocation.addListener(repositionListener); - arrowIndent.addListener(repositionListener); - headerAlwaysVisible.addListener(repositionListener); - - /* - * A detached popover should of course not automatically hide itself. - */ - detached.addListener(it -> { - if (isDetached()) { - setAutoHide(false); - } else { - setAutoHide(true); - } - }); - - setAutoHide(true); - } - - /** - * Creates a pop over with the given node as the content node. - * - * @param content - * The content shown by the pop over - */ - public PopOver(Node content) { - this(); - - setContentNode(content); - } - - @Override - protected Skin<?> createDefaultSkin() { - return new PopOverSkin(this); - } - - private final StackPane root = new StackPane(); - - /** - * The root pane stores the content node of the popover. It is accessible - * via this method in order to support proper styling. - * - * <h3>Example:</h3> - * - * <pre> - * PopOver popOver = new PopOver(); - * popOver.getRoot().getStylesheets().add(...); - * </pre> - * - * @return the root pane - */ - public final StackPane getRoot() { - return root; - } - - // Content support. - - private final ObjectProperty<Node> contentNode = new SimpleObjectProperty<Node>( - this, "contentNode") { //$NON-NLS-1$ - @Override - public void setValue(Node node) { - if (node == null) { - throw new IllegalArgumentException( - "content node can not be null"); //$NON-NLS-1$ - } - }; - }; - - /** - * Returns the content shown by the pop over. - * - * @return the content node property - */ - public final ObjectProperty<Node> contentNodeProperty() { - return contentNode; - } - - /** - * Returns the value of the content property - * - * @return the content node - * - * @see #contentNodeProperty() - */ - public final Node getContentNode() { - return contentNodeProperty().get(); - } - - /** - * Sets the value of the content property. - * - * @param content - * the new content node value - * - * @see #contentNodeProperty() - */ - public final void setContentNode(Node content) { - contentNodeProperty().set(content); - } - - private InvalidationListener hideListener = new InvalidationListener() { - @Override - public void invalidated(Observable observable) { - if (!isDetached()) { - hide(Duration.ZERO); - } - } - }; - - private WeakInvalidationListener weakHideListener = new WeakInvalidationListener( - hideListener); - - private ChangeListener<Number> xListener = new ChangeListener<Number>() { - @Override - public void changed(ObservableValue<? extends Number> value, - Number oldX, Number newX) { - if (!isDetached()) { - setAnchorX(getAnchorX() + (newX.doubleValue() - oldX.doubleValue())); - } - } - }; - - private WeakChangeListener<Number> weakXListener = new WeakChangeListener<>( - xListener); - - private ChangeListener<Number> yListener = new ChangeListener<Number>() { - @Override - public void changed(ObservableValue<? extends Number> value, - Number oldY, Number newY) { - if (!isDetached()) { - setAnchorY(getAnchorY() + (newY.doubleValue() - oldY.doubleValue())); - } - } - }; - - private WeakChangeListener<Number> weakYListener = new WeakChangeListener<>( - yListener); - - private Window ownerWindow; - private final EventHandler<WindowEvent> closePopOverOnOwnerWindowCloseLambda = event -> ownerWindowClosing(); - private final WeakEventHandler<WindowEvent> closePopOverOnOwnerWindowClose = new WeakEventHandler<>(closePopOverOnOwnerWindowCloseLambda); - - /** - * Shows the pop over in a position relative to the edges of the given owner - * node. The position is dependent on the arrow location. If the arrow is - * pointing to the right then the pop over will be placed to the left of the - * given owner. If the arrow points up then the pop over will be placed - * below the given owner node. The arrow will slightly overlap with the - * owner node. - * - * @param owner - * the owner of the pop over - */ - public final void show(Node owner) { - show(owner, 4); - } - - /** - * Shows the pop over in a position relative to the edges of the given owner - * node. The position is dependent on the arrow location. If the arrow is - * pointing to the right then the pop over will be placed to the left of the - * given owner. If the arrow points up then the pop over will be placed - * below the given owner node. - * - * @param owner - * the owner of the pop over - * @param offset - * if negative specifies the distance to the owner node or when - * positive specifies the number of pixels that the arrow will - * overlap with the owner node (positive values are recommended) - */ - public final void show(Node owner, double offset) { - requireNonNull(owner); - - Bounds bounds = owner.localToScreen(owner.getBoundsInLocal()); - - switch (getArrowLocation()) { - case BOTTOM_CENTER: - case BOTTOM_LEFT: - case BOTTOM_RIGHT: - show(owner, bounds.getMinX() + bounds.getWidth() / 2, - bounds.getMinY() + offset); - break; - case LEFT_BOTTOM: - case LEFT_CENTER: - case LEFT_TOP: - show(owner, bounds.getMaxX() - offset, - bounds.getMinY() + bounds.getHeight() / 2); - break; - case RIGHT_BOTTOM: - case RIGHT_CENTER: - case RIGHT_TOP: - show(owner, bounds.getMinX() + offset, - bounds.getMinY() + bounds.getHeight() / 2); - break; - case TOP_CENTER: - case TOP_LEFT: - case TOP_RIGHT: - show(owner, bounds.getMinX() + bounds.getWidth() / 2, - bounds.getMinY() + bounds.getHeight() - offset); - break; - default: - break; - } - } - - /** {@inheritDoc} */ - @Override - public final void show(Window owner) { - super.show(owner); - ownerWindow = owner; - - if (isAnimated()) { - showFadeInAnimation(getFadeInDuration()); - } - - ownerWindow.addEventFilter(WindowEvent.WINDOW_CLOSE_REQUEST, - closePopOverOnOwnerWindowClose); - ownerWindow.addEventFilter(WindowEvent.WINDOW_HIDING, - closePopOverOnOwnerWindowClose); - } - - /** {@inheritDoc} */ - @Override - public final void show(Window ownerWindow, double anchorX, double anchorY) { - super.show(ownerWindow, anchorX, anchorY); - this.ownerWindow = ownerWindow; - - if (isAnimated()) { - showFadeInAnimation(getFadeInDuration()); - } - - ownerWindow.addEventFilter(WindowEvent.WINDOW_CLOSE_REQUEST, - closePopOverOnOwnerWindowClose); - ownerWindow.addEventFilter(WindowEvent.WINDOW_HIDING, - closePopOverOnOwnerWindowClose); - } - - /** - * Makes the pop over visible at the give location and associates it with - * the given owner node. The x and y coordinate will be the target location - * of the arrow of the pop over and not the location of the window. - * - * @param owner - * the owning node - * @param x - * the x coordinate for the pop over arrow tip - * @param y - * the y coordinate for the pop over arrow tip - */ - @Override - public final void show(Node owner, double x, double y) { - show(owner, x, y, getFadeInDuration()); - } - - /** - * Makes the pop over visible at the give location and associates it with - * the given owner node. The x and y coordinate will be the target location - * of the arrow of the pop over and not the location of the window. - * - * @param owner - * the owning node - * @param x - * the x coordinate for the pop over arrow tip - * @param y - * the y coordinate for the pop over arrow tip - * @param fadeInDuration - * the time it takes for the pop over to be fully visible. This duration takes precedence over the fade-in property without setting. - */ - public final void show(Node owner, double x, double y, - Duration fadeInDuration) { - - /* - * Calling show() a second time without first closing the pop over - * causes it to be placed at the wrong location. - */ - if (ownerWindow != null && isShowing()) { - super.hide(); - } - - targetX = x; - targetY = y; - - if (owner == null) { - throw new IllegalArgumentException("owner can not be null"); //$NON-NLS-1$ - } - - if (fadeInDuration == null) { - fadeInDuration = DEFAULT_FADE_DURATION; - } - - /* - * This is all needed because children windows do not get their x and y - * coordinate updated when the owning window gets moved by the user. - */ - if (ownerWindow != null) { - ownerWindow.xProperty().removeListener(weakXListener); - ownerWindow.yProperty().removeListener(weakYListener); - ownerWindow.widthProperty().removeListener(weakHideListener); - ownerWindow.heightProperty().removeListener(weakHideListener); - } - - ownerWindow = owner.getScene().getWindow(); - ownerWindow.xProperty().addListener(weakXListener); - ownerWindow.yProperty().addListener(weakYListener); - ownerWindow.widthProperty().addListener(weakHideListener); - ownerWindow.heightProperty().addListener(weakHideListener); - - setOnShown(evt -> { - - /* - * The user clicked somewhere into the transparent background. If - * this is the case then hide the window (when attached). - */ - getScene().addEventHandler(MOUSE_CLICKED, mouseEvent -> { - if (mouseEvent.getTarget().equals(getScene().getRoot())) { - if (!isDetached()) { - hide(); - } - } - }); - - /* - * Move the window so that the arrow will end up pointing at the - * target coordinates. - */ - adjustWindowLocation(); - }); - - super.show(owner, x, y); - - if (isAnimated()) { - showFadeInAnimation(fadeInDuration); - } - - // Bug fix - close popup when owner window is closing - ownerWindow.addEventFilter(WindowEvent.WINDOW_CLOSE_REQUEST, - closePopOverOnOwnerWindowClose); - ownerWindow.addEventFilter(WindowEvent.WINDOW_HIDING, - closePopOverOnOwnerWindowClose); - } - - private void showFadeInAnimation(Duration fadeInDuration) { - // Fade In - Node skinNode = getSkin().getNode(); - skinNode.setOpacity(0); - - FadeTransition fadeIn = new FadeTransition(fadeInDuration, skinNode); - fadeIn.setFromValue(0); - fadeIn.setToValue(1); - fadeIn.play(); - } - - private void ownerWindowClosing() { - hide(Duration.ZERO); - } - - /** - * Hides the pop over by quickly changing its opacity to 0. - * - * @see #hide(Duration) - */ - @Override - public final void hide() { - hide(getFadeOutDuration()); - } - - /** - * Hides the pop over by quickly changing its opacity to 0. - * - * @param fadeOutDuration - * the duration of the fade transition that is being used to - * change the opacity of the pop over - * @since 1.0 - */ - public final void hide(Duration fadeOutDuration) { - //We must remove EventFilter in order to prevent memory leak. - if (ownerWindow != null){ - ownerWindow.removeEventFilter(WindowEvent.WINDOW_CLOSE_REQUEST, - closePopOverOnOwnerWindowClose); - ownerWindow.removeEventFilter(WindowEvent.WINDOW_HIDING, - closePopOverOnOwnerWindowClose); - } - if (fadeOutDuration == null) { - fadeOutDuration = DEFAULT_FADE_DURATION; - } - - if (isShowing()) { - if (isAnimated()) { - // Fade Out - Node skinNode = getSkin().getNode(); - - FadeTransition fadeOut = new FadeTransition(fadeOutDuration, - skinNode); - fadeOut.setFromValue(skinNode.getOpacity()); - fadeOut.setToValue(0); - fadeOut.setOnFinished(evt -> super.hide()); - fadeOut.play(); - } else { - super.hide(); - } - } - } - - private void adjustWindowLocation() { - Bounds bounds = PopOver.this.getSkin().getNode().getBoundsInParent(); - - switch (getArrowLocation()) { - case TOP_CENTER: - case TOP_LEFT: - case TOP_RIGHT: - setAnchorX(getAnchorX() + bounds.getMinX() - computeXOffset()); - setAnchorY(getAnchorY() + bounds.getMinY() + getArrowSize()); - break; - case LEFT_TOP: - case LEFT_CENTER: - case LEFT_BOTTOM: - setAnchorX(getAnchorX() + bounds.getMinX() + getArrowSize()); - setAnchorY(getAnchorY() + bounds.getMinY() - computeYOffset()); - break; - case BOTTOM_CENTER: - case BOTTOM_LEFT: - case BOTTOM_RIGHT: - setAnchorX(getAnchorX() + bounds.getMinX() - computeXOffset()); - setAnchorY(getAnchorY() - bounds.getMinY() - bounds.getMaxY() - 1); - break; - case RIGHT_TOP: - case RIGHT_BOTTOM: - case RIGHT_CENTER: - setAnchorX(getAnchorX() - bounds.getMinX() - bounds.getMaxX() - 1); - setAnchorY(getAnchorY() + bounds.getMinY() - computeYOffset()); - break; - } - } - - private double computeXOffset() { - switch (getArrowLocation()) { - case TOP_LEFT: - case BOTTOM_LEFT: - return getCornerRadius() + getArrowIndent() + getArrowSize(); - case TOP_CENTER: - case BOTTOM_CENTER: - return getContentNode().prefWidth(-1) / 2; - case TOP_RIGHT: - case BOTTOM_RIGHT: - return getContentNode().prefWidth(-1) - getArrowIndent() - - getCornerRadius() - getArrowSize(); - default: - return 0; - } - } - - private double computeYOffset() { - double prefContentHeight = getContentNode().prefHeight(-1); - - switch (getArrowLocation()) { - case LEFT_TOP: - case RIGHT_TOP: - return getCornerRadius() + getArrowIndent() + getArrowSize(); - case LEFT_CENTER: - case RIGHT_CENTER: - return Math.max(prefContentHeight, 2 * (getCornerRadius() - + getArrowIndent() + getArrowSize())) / 2; - case LEFT_BOTTOM: - case RIGHT_BOTTOM: - return Math.max(prefContentHeight - getCornerRadius() - - getArrowIndent() - getArrowSize(), getCornerRadius() - + getArrowIndent() + getArrowSize()); - default: - return 0; - } - } - - /** - * Detaches the pop over from the owning node. The pop over will no longer - * display an arrow pointing at the owner node. - */ - public final void detach() { - if (isDetachable()) { - setDetached(true); - } - } - - // always show header - - private final BooleanProperty headerAlwaysVisible = new SimpleBooleanProperty(this, "headerAlwaysVisible"); //$NON-NLS-1$ - - /** - * Determines whether or not the {@link PopOver} header should remain visible, even while attached. - */ - public final BooleanProperty headerAlwaysVisibleProperty() { - return headerAlwaysVisible; - } - - /** - * Sets the value of the headerAlwaysVisible property. - * - * @param visible - * if true, then the header is visible even while attached - * - * @see #headerAlwaysVisibleProperty() - */ - public final void setHeaderAlwaysVisible(boolean visible) { - headerAlwaysVisible.setValue(visible); - } - - /** - * Returns the value of the detachable property. - * - * @return true if the header is visible even while attached - * - * @see #headerAlwaysVisibleProperty() - */ - public final boolean isHeaderAlwaysVisible() { - return headerAlwaysVisible.getValue(); - } - - - // detach support - - private final BooleanProperty detachable = new SimpleBooleanProperty(this, - "detachable", true); //$NON-NLS-1$ - - /** - * Determines if the pop over is detachable at all. - */ - public final BooleanProperty detachableProperty() { - return detachable; - } - - /** - * Sets the value of the detachable property. - * - * @param detachable - * if true then the user can detach / tear off the pop over - * - * @see #detachableProperty() - */ - public final void setDetachable(boolean detachable) { - detachableProperty().set(detachable); - } - - /** - * Returns the value of the detachable property. - * - * @return true if the user is allowed to detach / tear off the pop over - * - * @see #detachableProperty() - */ - public final boolean isDetachable() { - return detachableProperty().get(); - } - - private final BooleanProperty detached = new SimpleBooleanProperty(this, - "detached", false); //$NON-NLS-1$ - - /** - * Determines whether the pop over is detached from the owning node or not. - * A detached pop over no longer shows an arrow pointing at the owner and - * features its own title bar. - * - * @return the detached property - */ - public final BooleanProperty detachedProperty() { - return detached; - } - - /** - * Sets the value of the detached property. - * - * @param detached - * if true the pop over will change its apperance to "detached" - * mode - * - * @see #detachedProperty() - */ - public final void setDetached(boolean detached) { - detachedProperty().set(detached); - } - - /** - * Returns the value of the detached property. - * - * @return true if the pop over is currently detached. - * - * @see #detachedProperty() - */ - public final boolean isDetached() { - return detachedProperty().get(); - } - - // arrow size support - - // TODO: make styleable - - private final DoubleProperty arrowSize = new SimpleDoubleProperty(this, - "arrowSize", 12); //$NON-NLS-1$ - - /** - * Controls the size of the arrow. Default value is 12. - * - * @return the arrow size property - */ - public final DoubleProperty arrowSizeProperty() { - return arrowSize; - } - - /** - * Returns the value of the arrow size property. - * - * @return the arrow size property value - * - * @see #arrowSizeProperty() - */ - public final double getArrowSize() { - return arrowSizeProperty().get(); - } - - /** - * Sets the value of the arrow size property. - * - * @param size - * the new value of the arrow size property - * - * @see #arrowSizeProperty() - */ - public final void setArrowSize(double size) { - arrowSizeProperty().set(size); - } - - // arrow indent support - - // TODO: make styleable - - private final DoubleProperty arrowIndent = new SimpleDoubleProperty(this, - "arrowIndent", 12); //$NON-NLS-1$ - - /** - * Controls the distance between the arrow and the corners of the pop over. - * The default value is 12. - * - * @return the arrow indent property - */ - public final DoubleProperty arrowIndentProperty() { - return arrowIndent; - } - - /** - * Returns the value of the arrow indent property. - * - * @return the arrow indent value - * - * @see #arrowIndentProperty() - */ - public final double getArrowIndent() { - return arrowIndentProperty().get(); - } - - /** - * Sets the value of the arrow indent property. - * - * @param size - * the arrow indent value - * - * @see #arrowIndentProperty() - */ - public final void setArrowIndent(double size) { - arrowIndentProperty().set(size); - } - - // radius support - - // TODO: make styleable - - private final DoubleProperty cornerRadius = new SimpleDoubleProperty(this, - "cornerRadius", 6); //$NON-NLS-1$ - - /** - * Returns the corner radius property for the pop over. - * - * @return the corner radius property (default is 6) - */ - public final DoubleProperty cornerRadiusProperty() { - return cornerRadius; - } - - /** - * Returns the value of the corner radius property. - * - * @return the corner radius - * - * @see #cornerRadiusProperty() - */ - public final double getCornerRadius() { - return cornerRadiusProperty().get(); - } - - /** - * Sets the value of the corner radius property. - * - * @param radius - * the corner radius - * - * @see #cornerRadiusProperty() - */ - public final void setCornerRadius(double radius) { - cornerRadiusProperty().set(radius); - } - - // Detached stage title - - private final StringProperty title = new SimpleStringProperty(this, "title", localize(asKey("popOver.default.title"))); //$NON-NLS-1$ //$NON-NLS-2$ - - /** - * Stores the title to display in the PopOver's header. - * - * @return the title property - */ - public final StringProperty titleProperty() { - return title; - } - - /** - * Returns the value of the title property. - * - * @return the detached title - * @see #titleProperty() - */ - public final String getTitle() { - return titleProperty().get(); - } - - /** - * Sets the value of the title property. - * - * @param title the title to use when detached - * @see #titleProperty() - */ - public final void setTitle(String title) { - if (title == null) { - throw new IllegalArgumentException("title can not be null"); //$NON-NLS-1$ - } - - titleProperty().set(title); - } - - private final ObjectProperty<ArrowLocation> arrowLocation = new SimpleObjectProperty<>( - this, "arrowLocation", ArrowLocation.LEFT_TOP); //$NON-NLS-1$ - - /** - * Stores the preferred arrow location. This might not be the actual - * location of the arrow if auto fix is enabled. - * - * @see #setAutoFix(boolean) - * - * @return the arrow location property - */ - public final ObjectProperty<ArrowLocation> arrowLocationProperty() { - return arrowLocation; - } - - /** - * Sets the value of the arrow location property. - * - * @see #arrowLocationProperty() - * - * @param location - * the requested location - */ - public final void setArrowLocation(ArrowLocation location) { - arrowLocationProperty().set(location); - } - - /** - * Returns the value of the arrow location property. - * - * @see #arrowLocationProperty() - * - * @return the preferred arrow location - */ - public final ArrowLocation getArrowLocation() { - return arrowLocationProperty().get(); - } - - /** - * All possible arrow locations. - */ - public enum ArrowLocation { - LEFT_TOP, LEFT_CENTER, LEFT_BOTTOM, RIGHT_TOP, RIGHT_CENTER, RIGHT_BOTTOM, TOP_LEFT, TOP_CENTER, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_CENTER, BOTTOM_RIGHT; - } - - /** - * Stores the fade-in duration. This should be set before calling PopOver.show(..). - * - * @return the fade-in duration property - */ - public final ObjectProperty<Duration> fadeInDurationProperty() { - return fadeInDuration; - } - - /** - * Stores the fade-out duration. - * - * @return the fade-out duration property - */ - public final ObjectProperty<Duration> fadeOutDurationProperty() { - return fadeOutDuration; - } - - /** - * Returns the value of the fade-in duration property. - * - * @return the fade-in duration - * @see #fadeInDurationProperty() - */ - public final Duration getFadeInDuration() { - return fadeInDurationProperty().get(); - } - - /** - * Sets the value of the fade-in duration property. This should be set before calling PopOver.show(..). - * - * @param duration the requested fade-in duration - * @see #fadeInDurationProperty() - */ - public final void setFadeInDuration(Duration duration) { - fadeInDurationProperty().setValue(duration); - } - - /** - * Returns the value of the fade-out duration property. - * - * @return the fade-out duration - * @see #fadeOutDurationProperty() - */ - public final Duration getFadeOutDuration() { - return fadeOutDurationProperty().get(); - } - - /** - * Sets the value of the fade-out duration property. - * - * @param duration the requested fade-out duration - * @see #fadeOutDurationProperty() - */ - public final void setFadeOutDuration(Duration duration) { - fadeOutDurationProperty().setValue(duration); - } - - /** - * Stores the "animated" flag. If true then the PopOver will be shown / hidden with a short fade in / out animation. - * - * @return the "animated" property - */ - public final BooleanProperty animatedProperty() { - return animated; - } - - /** - * Returns the value of the "animated" property. - * - * @return true if the PopOver will be shown and hidden with a short fade animation - * @see #animatedProperty() - */ - public final boolean isAnimated() { - return animatedProperty().get(); - } - - /** - * Sets the value of the "animated" property. - * - * @param animated if true the PopOver will be shown and hidden with a short fade animation - * @see #animatedProperty() - */ - public final void setAnimated(boolean animated) { - animatedProperty().set(animated); - } -} diff --git a/src/org/controlsfx/control/PrefixSelectionChoiceBox.java b/src/org/controlsfx/control/PrefixSelectionChoiceBox.java deleted file mode 100644 index d5cf6ce..0000000 --- a/src/org/controlsfx/control/PrefixSelectionChoiceBox.java +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Copyright (c) 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control; - -import impl.org.controlsfx.tools.PrefixSelectionCustomizer; -import javafx.scene.control.ChoiceBox; - -/** - * <p>A simple extension of the {@link ChoiceBox} which selects an entry of - * its item list based on keyboard input. The user can type letters or - * digits on the keyboard and die {@link ChoiceBox} will attempt to - * select the first item it can find with a matching prefix. - * - * <p>This feature is available natively on the Windows combo box control, so many - * users have asked for it. There is a feature request to include this feature - * into JavaFX (<a href="https://javafx-jira.kenai.com/browse/RT-18064">Issue RT-18064</a>). - * The class is published as part of ContorlsFX to allow testing and feedback. - * - * <h3>Example</h3> - * - * <p>Let's look at an example to clarify this. The choice box offers the items - * ["Aaaaa", "Abbbb", "Abccc", "Abcdd", "Abcde"]. The user now types "abc" in - * quick succession (and then stops typing). The choice box will select a new entry - * on every key pressed. The first entry it will select is "Aaaaa" since it is the - * first entry that starts with an "a" (case ignored). It will then select "Abbbb", - * since this is the first entry that started with "ab" and will finally settle for - * "Abccc". - * - * <ul><table> - * <tr><th>Keys typed</th><th>Element selected</th></tr> - * <tr><td>a</td><td>Aaaaa<td></tr> - * <tr><td>aaa</td><td>Aaaaa<td></tr> - * <tr><td>ab</td><td>Abbbb<td></tr> - * <tr><td>abc</td><td>Abccc<td></tr> - * <tr><td>xyz</td><td>-<td></tr> - * </table></ul> - * - * <p>If you want to modify an existing {@link ChoiceBox} you can use the - * {@link PrefixSelectionCustomizer} directly to do this. - * - * @see PrefixSelectionCustomizer - */ -public class PrefixSelectionChoiceBox<T> extends ChoiceBox<T> { - - /** - * Create a non editable {@link ChoiceBox} with the "prefix selection" - * feature installed. - */ - public PrefixSelectionChoiceBox() { - PrefixSelectionCustomizer.customize(this); - } - -} diff --git a/src/org/controlsfx/control/PrefixSelectionComboBox.java b/src/org/controlsfx/control/PrefixSelectionComboBox.java deleted file mode 100644 index 98092f6..0000000 --- a/src/org/controlsfx/control/PrefixSelectionComboBox.java +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Copyright (c) 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control; - -import impl.org.controlsfx.tools.PrefixSelectionCustomizer; -import javafx.scene.control.ComboBox; - -/** - * A simple extension of the {@link ComboBox} which selects an entry of - * its item list based on keyboard input. The user can type letters or - * digits on the keyboard and die ChoiceBox will attempt to - * select the first item it can find with a matching prefix. - * - * This will only be enabled, when the {@link ComboBox} is not editable, so - * this class will be setup as non editable by default. - * - * <p>This feature is available natively on the Windows combo box control, so many - * users have asked for it. There is a feature request to include this feature - * into JavaFX (<a href="https://javafx-jira.kenai.com/browse/RT-18064">Issue RT-18064</a>). - * The class is published as part of ContorlsFX to allow testing and feedback. - * - * <h3>Example</h3> - * - * <p>Let's look at an example to clarify this. The combo box offers the items - * ["Aaaaa", "Abbbb", "Abccc", "Abcdd", "Abcde"]. The user now types "abc" in - * quick succession (and then stops typing). The combo box will select a new entry - * on every key pressed. The first entry it will select is "Aaaaa" since it is the - * first entry that starts with an "a" (case ignored). It will then select "Abbbb", - * since this is the first entry that started with "ab" and will finally settle for - * "Abccc". - * - * <ul><table> - * <tr><th>Keys typed</th><th>Element selected</th></tr> - * <tr><td>a</td><td>Aaaaa<td></tr> - * <tr><td>aaa</td><td>Aaaaa<td></tr> - * <tr><td>ab</td><td>Abbbb<td></tr> - * <tr><td>abc</td><td>Abccc<td></tr> - * <tr><td>xyz</td><td>-<td></tr> - * </table></ul> - * - * <p>If you want to modify an existing {@link ComboBox} you can use the - * {@link PrefixSelectionCustomizer} directly to do this. - * - * @see PrefixSelectionCustomizer - */ -public class PrefixSelectionComboBox<T> extends ComboBox<T> { - - /** - * Create a non editable {@link ComboBox} with the "prefix selection" - * feature installed. - */ - public PrefixSelectionComboBox() { - setEditable(false); - PrefixSelectionCustomizer.customize(this); - } - -} diff --git a/src/org/controlsfx/control/PropertySheet.java b/src/org/controlsfx/control/PropertySheet.java deleted file mode 100644 index 2675b7c..0000000 --- a/src/org/controlsfx/control/PropertySheet.java +++ /dev/null @@ -1,452 +0,0 @@ -/** - * Copyright (c) 2013, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control; - -import impl.org.controlsfx.skin.PropertySheetSkin; - -import java.util.Optional; - -import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.value.ObservableValue; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.scene.control.Skin; -import javafx.util.Callback; - -import org.controlsfx.property.BeanPropertyUtils; -import org.controlsfx.property.editor.DefaultPropertyEditorFactory; -import org.controlsfx.property.editor.Editors; -import org.controlsfx.property.editor.PropertyEditor; - -/** - * The PropertySheet control is a powerful control designed to make it really - * easy for developers to present to end users a list of properties that the - * end user is allowed to manipulate. Commonly a property sheet is used in - * visual editors and other tools where a lot of properties exist. - * - * <p>To better describe what a property sheet is, please refer to the picture - * below: - * - * <br> - * <center><img src="propertySheet.PNG" alt="Screenshot of PropertySheet"></center> - * - * <p>In this property sheet there exists two columns: the left column shows a - * label describing the property itself, whereas the right column provides a - * {@link PropertyEditor} that allows the end user the means to manipulate the - * property. In the screenshot you can see CheckEditor, - * ChoiceEditor, TextEditor and FontEditor, among the - * many editors that are available in the {@link Editors} - * package. - * - * <p>To create a PropertySheet is simple: you firstly instantiate an instance - * of PropertySheet, and then you pass in a list of {@link Item} instances, - * where each Item represents a single property that is to be editable by the - * end user. - * - * <h3>Working with JavaBeans</h3> - * Because a very common use case for a property sheet is editing properties on - * a JavaBean, there is convenience API for making this interaction easier. - * Refer to the {@link BeanPropertyUtils class}, in particular the - * {@link BeanPropertyUtils#getProperties(Object)} method that will return a - * list of Item instances, one Item instance per property on the given JavaBean. - * - * @see Item - * @see Mode - */ -public class PropertySheet extends ControlsFXControl { - - - /************************************************************************** - * - * Static fields - * - **************************************************************************/ - - - - /************************************************************************** - * - * Static enumerations / interfaces - * - **************************************************************************/ - - /** - * Specifies how the {@link PropertySheet} should be laid out. Refer to the - * enumeration values to learn what each one means. - */ - public static enum Mode { - /** - * Simply displays the properties in the - * {@link PropertySheet#getItems() items list} in the order they are - * in the list. - */ - NAME, - - /** - * Groups the properties in the - * {@link PropertySheet#getItems() items list} based on their - * {@link Item#getCategory() category}. - */ - CATEGORY - } - - - - /** - * A wrapper interface for a single property to be displayed in a - * {@link PropertySheet} control. - * - * @see PropertySheet - */ - public static interface Item { - - /** - * Returns the class type of the property. - */ - public Class<?> getType(); - - /** - * Returns a String representation of the category of the property. This - * is relevant when the {@link PropertySheet} - * {@link PropertySheet#modeProperty() mode property} is set to - * {@link Mode#CATEGORY} - as then all properties with the same category - * will be grouped together visually. - */ - public String getCategory(); - - /** - * Returns the display name of the property, which should be short (i.e. - * less than two words). This is used to explain to the end user what the - * property represents and is displayed beside the {@link PropertyEditor}. - * If you need to explain more detail to the user, consider placing it - * in the {@link #getDescription()}. - */ - public String getName(); - - /** - * A String that will be shown to the user as a tooltip. This allows for - * a longer form of detail than what is possible with the {@link #getName()} - * method. - */ - public String getDescription(); - - /** - * Returns the current value of the property. - */ - public Object getValue(); - - /** - * Sets the current value of the property. - */ - public void setValue(Object value); - - /** - * Returns the underlying ObservableValue, where one exists, that the editor - * can monitor for changes. - */ - public Optional<ObservableValue<? extends Object>> getObservableValue(); - - /** - * Returns an Optional wrapping the class of the PropertyEditor that - * should be used for editing this item. The default implementation - * returns Optional.empty() - * - * The class must have a constructor that can accept a single argument - * of type PropertySheet.Item - */ - default public Optional<Class<? extends PropertyEditor<?>>> getPropertyEditorClass() { - return Optional.empty(); - } - - /** - * Indicates whether the PropertySheet should allow editing of this - * property, or whether it is read-only. The default implementation - * returns true. - */ - default public boolean isEditable() { - return true; - } - } - - - /************************************************************************** - * - * Private fields - * - **************************************************************************/ - - private final ObservableList<Item> items; - - - - /************************************************************************** - * - * Constructors - * - **************************************************************************/ - - /** - * Creates a default PropertySheet instance with no properties to edit. - */ - public PropertySheet() { - this(null); - } - - /** - * Creates a PropertySheet instance prepopulated with the items provided - * in the items {@link ObservableList}. - * - * @param items The items that should appear within the PropertySheet. - */ - public PropertySheet(ObservableList<Item> items) { - getStyleClass().add(DEFAULT_STYLE_CLASS); - - this.items = items == null ? FXCollections.<Item>observableArrayList() : items; - } - - - - /************************************************************************** - * - * Public API - * - **************************************************************************/ - - /** - * - * @return An ObservableList of properties that will be displayed to the user to allow for them - * to be edited. - */ - public ObservableList<Item> getItems() { - return items; - } - - /** - * {@inheritDoc} - */ - @Override protected Skin<?> createDefaultSkin() { - return new PropertySheetSkin(this); - } - - /** {@inheritDoc} */ - @Override public String getUserAgentStylesheet() { - return getUserAgentStylesheet(PropertySheet.class, "propertysheet.css"); - } - - - /************************************************************************** - * - * Properties - * - **************************************************************************/ - - // --- modeProperty - private final SimpleObjectProperty<Mode> modeProperty = - new SimpleObjectProperty<>(this, "mode", Mode.NAME); //$NON-NLS-1$ - - /** - * Used to represent how the properties should be laid out in - * the PropertySheet. Refer to the {@link Mode} enumeration to better - * understand the available options. - * @return A SimpleObjectproperty. - */ - public final SimpleObjectProperty<Mode> modeProperty() { - return modeProperty; - } - - /** - * @see Mode - * @return how the properties should be laid out in - * the PropertySheet. - */ - public final Mode getMode() { - return modeProperty.get(); - } - - /** - * Set how the properties should be laid out in - * the PropertySheet. - * @param mode - */ - public final void setMode(Mode mode) { - modeProperty.set(mode); - } - - - // --- propertyEditorFactory - private final SimpleObjectProperty<Callback<Item, PropertyEditor<?>>> propertyEditorFactory = - new SimpleObjectProperty<>(this, "propertyEditor", new DefaultPropertyEditorFactory()); //$NON-NLS-1$ - - /** - * The property editor factory is used by the PropertySheet to determine which - * {@link PropertyEditor} to use for a given {@link Item}. By default the - * {@link DefaultPropertyEditorFactory} is used, but this may be replaced - * or extended by developers wishing to add in (or substitute) their own - * property editors. - * - * @return A SimpleObjectproperty. - */ - public final SimpleObjectProperty<Callback<Item, PropertyEditor<?>>> propertyEditorFactory() { - return propertyEditorFactory; - } - - /** - * - * @return The editor factory used by the PropertySheet to determine which - * {@link PropertyEditor} to use for a given {@link Item}. - */ - public final Callback<Item, PropertyEditor<?>> getPropertyEditorFactory() { - return propertyEditorFactory.get(); - } - - /** - * Sets a new editor factory used by the PropertySheet to determine which - * {@link PropertyEditor} to use for a given {@link Item}. - * @param factory - */ - public final void setPropertyEditorFactory( Callback<Item, PropertyEditor<?>> factory ) { - propertyEditorFactory.set( factory == null? new DefaultPropertyEditorFactory(): factory ); - } - - - // --- modeSwitcherVisible - private final SimpleBooleanProperty modeSwitcherVisible = - new SimpleBooleanProperty(this, "modeSwitcherVisible", true); //$NON-NLS-1$ - - /** - * This property represents whether a visual option should be presented to - * users to switch between the various {@link Mode modes} available. By - * default this is true, so setting it to false will hide these buttons. - * @return A SimpleBooleanproperty. - */ - public final SimpleBooleanProperty modeSwitcherVisibleProperty() { - return modeSwitcherVisible; - } - - /** - * - * @return whether a visual option is presented to - * users to switch between the various {@link Mode modes} available. - */ - public final boolean isModeSwitcherVisible() { - return modeSwitcherVisible.get(); - } - - /** - * Set whether a visual option should be presented to - * users to switch between the various {@link Mode modes} available. - * @param visible - */ - public final void setModeSwitcherVisible( boolean visible ) { - modeSwitcherVisible.set(visible); - } - - - // --- toolbarSearchVisibleProperty - private final SimpleBooleanProperty searchBoxVisible = - new SimpleBooleanProperty(this, "searchBoxVisible", true); //$NON-NLS-1$ - - /** - * - */ - /** - * This property represents whether a text field should be presented to - * users to allow for them to filter the properties in the property sheet to - * only show ones matching the typed input. By default this is true, so - * setting it to false will hide this search field. - * @return A SimpleBooleanProperty. - */ - public final SimpleBooleanProperty searchBoxVisibleProperty() { - return searchBoxVisible; - } - - /** - * - * @return whether a text field should be presented to - * users to allow for them to filter the properties in the property sheet to - * only show ones matching the typed input. - */ - public final boolean isSearchBoxVisible() { - return searchBoxVisible.get(); - } - - /** - * Sets whether a text field should be presented to - * users to allow for them to filter the properties in the property sheet to - * only show ones matching the typed input. - * @param visible - */ - public final void setSearchBoxVisible( boolean visible ) { - searchBoxVisible.set(visible); - } - - - // --- titleFilterProperty - private final SimpleStringProperty titleFilterProperty = - new SimpleStringProperty(this, "titleFilter", ""); //$NON-NLS-1$ //$NON-NLS-2$ - - /** - * Regardless of whether the {@link #searchBoxVisibleProperty() search box} - * is visible or not, it is possible to filter the options shown on screen - * using this title filter property. If the search box is visible, it will - * manipulate this property to contain whatever the user types. - * @return A SimpleStringProperty. - */ - public final SimpleStringProperty titleFilter() { - return titleFilterProperty; - } - - /** - * @see #titleFilter() - * @return the filter for filtering the options shown on screen - */ - public final String getTitleFilter() { - return titleFilterProperty.get(); - } - - /** - * Sets the filter for filtering the options shown on screen. - * @param filter - * @see #titleFilter() - */ - public final void setTitleFilter( String filter ) { - titleFilterProperty.set(filter); - } - - - - /*************************************************************************** - * * - * Stylesheet Handling * - * * - **************************************************************************/ - - private static final String DEFAULT_STYLE_CLASS = "property-sheet"; //$NON-NLS-1$ - -} diff --git a/src/org/controlsfx/control/RangeSlider.java b/src/org/controlsfx/control/RangeSlider.java deleted file mode 100644 index b60462a..0000000 --- a/src/org/controlsfx/control/RangeSlider.java +++ /dev/null @@ -1,1102 +0,0 @@ -/** - * Copyright (c) 2013, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control; - -import impl.org.controlsfx.skin.RangeSliderSkin; -import org.controlsfx.tools.Utils; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.DoubleProperty; -import javafx.beans.property.DoublePropertyBase; -import javafx.beans.property.IntegerProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.SimpleDoubleProperty; -import javafx.css.CssMetaData; -import javafx.css.PseudoClass; -import javafx.css.StyleOrigin; -import javafx.css.Styleable; -import javafx.css.StyleableBooleanProperty; -import javafx.css.StyleableDoubleProperty; -import javafx.css.StyleableIntegerProperty; -import javafx.css.StyleableObjectProperty; -import javafx.css.StyleableProperty; -import javafx.geometry.Orientation; -import javafx.scene.control.Control; -import javafx.scene.control.Skin; -import javafx.scene.control.Slider; - -import com.sun.javafx.css.converters.BooleanConverter; -import com.sun.javafx.css.converters.EnumConverter; -import com.sun.javafx.css.converters.SizeConverter; - -import javafx.beans.property.SimpleObjectProperty; -import javafx.util.StringConverter; - -/** - * The RangeSlider control is simply a JavaFX {@link Slider} control with support - * for two 'thumbs', rather than one. A thumb is the non-technical name for the - * draggable area inside the Slider / RangeSlider that allows for a value to be - * set. - * - * <p>Because the RangeSlider has two thumbs, it also has a few additional rules - * and user interactions: - * - * <ol> - * <li>The 'lower value' thumb can not move past the 'higher value' thumb. - * <li>Whereas the {@link Slider} control only has one - * {@link Slider#valueProperty() value} property, the RangeSlider has a - * {@link #lowValueProperty() low value} and a - * {@link #highValueProperty() high value} property, not surprisingly - * represented by the 'low value' and 'high value' thumbs. - * <li>The area between the low and high values represents the allowable range. - * For example, if the low value is 2 and the high value is 8, then the - * allowable range is between 2 and 8. - * <li>The allowable range area is rendered differently. This area is able to - * be dragged with mouse / touch input to allow for the entire range to - * be modified. For example, following on from the previous example of the - * allowable range being between 2 and 8, if the user drags the range bar - * to the right, the low value will adjust to 3, and the high value 9, and - * so on until the user stops adjusting. - * </ol> - * - * <h3>Screenshots</h3> - * Because the RangeSlider supports both horizontal and vertical - * {@link #orientationProperty() orientation}, there are two screenshots below: - * - * <table border="0" summary="Screenshot of RangeSlider orientation"> - * <tr> - * <td width="75" valign="center"><strong>Horizontal:</strong></td> - * <td><img src="rangeSlider-horizontal.png" alt="Screenshot of a horizontal RangeSlider"></td> - * </tr> - * <tr> - * <td width="75" valign="top"><strong>Vertical:</strong></td> - * <td><img src="rangeSlider-vertical.png" alt="Screenshot of a vertical RangeSlider"></td> - * </tr> - * </table> - * - * <h3>Code Samples</h3> - * Instantiating a RangeSlider is simple. The first decision is to decide whether - * a horizontal or a vertical track is more appropriate. By default RangeSlider - * instances are horizontal, but this can be changed by setting the - * {@link #orientationProperty() orientation} property. - * - * <p>Once the orientation is determined, the next most important decision is - * to determine what the {@link #minProperty() min} / {@link #maxProperty() max} - * and default {@link #lowValueProperty() low} / {@link #highValueProperty() high} - * values are. The min / max values represent the smallest and largest legal - * values for the thumbs to be set to, whereas the low / high values represent - * where the thumbs are currently, within the bounds of the min / max values. - * Because all four values are required in all circumstances, they are all - * required parameters to instantiate a RangeSlider: the constructor takes - * four doubles, representing min, max, lowValue and highValue (in that order). - * - * <p>For example, here is a simple horizontal RangeSlider that has a minimum - * value of 0, a maximum value of 100, a low value of 10 and a high value of 90: - * - * <pre>{@code final RangeSlider hSlider = new RangeSlider(0, 100, 10, 90);}</pre> - * - * <p>To configure the hSlider to look like the RangeSlider in the horizontal - * RangeSlider screenshot above only requires a few additional properties to be - * set: - * - * <pre> - * {@code - * final RangeSlider hSlider = new RangeSlider(0, 100, 10, 90); - * hSlider.setShowTickMarks(true); - * hSlider.setShowTickLabels(true); - * hSlider.setBlockIncrement(10);}</pre> - * - * <p>To create a vertical slider, simply do the following: - * - * <pre> - * {@code - * final RangeSlider vSlider = new RangeSlider(0, 200, 30, 150); - * vSlider.setOrientation(Orientation.VERTICAL);}</pre> - * - * <p>This code creates a RangeSlider with a min value of 0, a max value of 200, - * a low value of 30, and a high value of 150. - * - * @see Slider - */ -public class RangeSlider extends ControlsFXControl { - - /*************************************************************************** - * * - * Constructors * - * * - **************************************************************************/ - - /** - * Creates a new RangeSlider instance using default values of 0.0, 0.25, 0.75 - * and 1.0 for min/lowValue/highValue/max, respectively. - */ - public RangeSlider() { - this(0, 1.0, 0.25, 0.75); - } - - /** - * Instantiates a default, horizontal RangeSlider with the specified - * min/max/low/high values. - * - * @param min The minimum allowable value that the RangeSlider will allow. - * @param max The maximum allowable value that the RangeSlider will allow. - * @param lowValue The initial value for the low value in the RangeSlider. - * @param highValue The initial value for the high value in the RangeSlider. - */ - public RangeSlider(double min, double max, double lowValue, double highValue) { - getStyleClass().setAll(DEFAULT_STYLE_CLASS); - - setMax(max); - setMin(min); - adjustValues(); - setLowValue(lowValue); - setHighValue(highValue); - } - - /** {@inheritDoc} */ - @Override public String getUserAgentStylesheet() { - return getUserAgentStylesheet(RangeSlider.class, "rangeslider.css"); - } - - /** - * {@inheritDoc} - */ - @Override protected Skin<?> createDefaultSkin() { - return new RangeSliderSkin(this); - } - - - - /*************************************************************************** - * * - * New properties (over and above what is in Slider) * - * * - **************************************************************************/ - - // --- low value - /** - * The low value property represents the current position of the low value - * thumb, and is within the allowable range as specified by the - * {@link #minProperty() min} and {@link #maxProperty() max} properties. By - * default this value is 0. - */ - public final DoubleProperty lowValueProperty() { - return lowValue; - } - private DoubleProperty lowValue = new SimpleDoubleProperty(this, "lowValue", 0.0D) { //$NON-NLS-1$ - @Override protected void invalidated() { - adjustLowValues(); - } - }; - - /** - * Sets the low value for the range slider, which may or may not be clamped - * to be within the allowable range as specified by the - * {@link #minProperty() min} and {@link #maxProperty() max} properties. - */ - public final void setLowValue(double d) { - lowValueProperty().set(d); - } - - /** - * Returns the current low value for the range slider. - */ - public final double getLowValue() { - return lowValue != null ? lowValue.get() : 0.0D; - } - - - - // --- low value changing - /** - * When true, indicates the current low value of this RangeSlider is changing. - * It provides notification that the low value is changing. Once the low - * value is computed, it is set back to false. - */ - public final BooleanProperty lowValueChangingProperty() { - if (lowValueChanging == null) { - lowValueChanging = new SimpleBooleanProperty(this, "lowValueChanging", false); //$NON-NLS-1$ - } - return lowValueChanging; - } - - private BooleanProperty lowValueChanging; - - /** - * Call this when the low value is changing. - * @param value True if the low value is changing, false otherwise. - */ - public final void setLowValueChanging(boolean value) { - lowValueChangingProperty().set(value); - } - - /** - * Returns whether or not the low value of this RangeSlider is currently - * changing. - */ - public final boolean isLowValueChanging() { - return lowValueChanging == null ? false : lowValueChanging.get(); - } - - - // --- high value - /** - * The high value property represents the current position of the high value - * thumb, and is within the allowable range as specified by the - * {@link #minProperty() min} and {@link #maxProperty() max} properties. By - * default this value is 100. - */ - public final DoubleProperty highValueProperty() { - return highValue; - } - private DoubleProperty highValue = new SimpleDoubleProperty(this, "highValue", 100D) { //$NON-NLS-1$ - @Override protected void invalidated() { - adjustHighValues(); - } - - @Override public Object getBean() { - return RangeSlider.this; - } - - @Override public String getName() { - return "highValue"; //$NON-NLS-1$ - } - }; - - /** - * Sets the high value for the range slider, which may or may not be clamped - * to be within the allowable range as specified by the - * {@link #minProperty() min} and {@link #maxProperty() max} properties. - */ - public final void setHighValue(double d) { - if (!highValueProperty().isBound()) highValueProperty().set(d); - } - - /** - * Returns the current high value for the range slider. - */ - public final double getHighValue() { - return highValue != null ? highValue.get() : 100D; - } - - - - // --- high value changing - /** - * When true, indicates the current high value of this RangeSlider is changing. - * It provides notification that the high value is changing. Once the high - * value is computed, it is set back to false. - */ - public final BooleanProperty highValueChangingProperty() { - if (highValueChanging == null) { - highValueChanging = new SimpleBooleanProperty(this, "highValueChanging", false); //$NON-NLS-1$ - } - return highValueChanging; - } - private BooleanProperty highValueChanging; - - /** - * Call this when high low value is changing. - * @param value True if the high value is changing, false otherwise. - */ - public final void setHighValueChanging(boolean value) { - highValueChangingProperty().set(value); - } - - /** - * Returns whether or not the high value of this RangeSlider is currently - * changing. - */ - public final boolean isHighValueChanging() { - return highValueChanging == null ? false : highValueChanging.get(); - } - - private final ObjectProperty<StringConverter<Number>> tickLabelFormatter = new SimpleObjectProperty<>(); - - /** - * Gets the value of the property tickLabelFormatter. - * @return the value of the property tickLabelFormatter. - */ - public final StringConverter<Number> getLabelFormatter(){ - return tickLabelFormatter.get(); - } - - /** - * Sets the value of the property tickLabelFormatter. - * @param value - */ - public final void setLabelFormatter(StringConverter<Number> value){ - tickLabelFormatter.set(value); - } - /** - * StringConverter used to format tick mark labels. If null a default will be used. - * @return a Property containing the StringConverter. - */ - public final ObjectProperty<StringConverter<Number>> labelFormatterProperty(){ - return tickLabelFormatter; - } - - /*************************************************************************** - * * - * New public API * - * * - **************************************************************************/ - - /** - * Increments the {@link #lowValueProperty() low value} by the - * {@link #blockIncrementProperty() block increment} amount. - */ - public void incrementLowValue() { - adjustLowValue(getLowValue() + getBlockIncrement()); - } - - /** - * Decrements the {@link #lowValueProperty() low value} by the - * {@link #blockIncrementProperty() block increment} amount. - */ - public void decrementLowValue() { - adjustLowValue(getLowValue() - getBlockIncrement()); - } - - /** - * Increments the {@link #highValueProperty() high value} by the - * {@link #blockIncrementProperty() block increment} amount. - */ - public void incrementHighValue() { - adjustHighValue(getHighValue() + getBlockIncrement()); - } - - /** - * Decrements the {@link #highValueProperty() high value} by the - * {@link #blockIncrementProperty() block increment} amount. - */ - public void decrementHighValue() { - adjustHighValue(getHighValue() - getBlockIncrement()); - } - - /** - * Adjusts {@link #lowValueProperty() lowValue} to match <code>newValue</code>, - * or as closely as possible within the constraints imposed by the - * {@link #minProperty() min} and {@link #maxProperty() max} properties. - * This function also takes into account - * {@link #snapToTicksProperty() snapToTicks}, which is the main difference - * between <code>adjustLowValue</code> and - * {@link #setLowValue(double) setLowValue}. - */ - public void adjustLowValue(double newValue) { - double d1 = getMin(); - double d2 = getMax(); - if (d2 <= d1) { - // no-op - } else { - newValue = newValue >= d1 ? newValue : d1; - newValue = newValue <= d2 ? newValue : d2; - setLowValue(snapValueToTicks(newValue)); - } - } - - /** - * Adjusts {@link #highValueProperty() highValue} to match <code>newValue</code>, - * or as closely as possible within the constraints imposed by the - * {@link #minProperty() min} and {@link #maxProperty() max} properties. - * This function also takes into account - * {@link #snapToTicksProperty() snapToTicks}, which is the main difference - * between <code>adjustHighValue</code> and - * {@link #setHighValue(double) setHighValue}. - */ - public void adjustHighValue(double newValue) { - double d1 = getMin(); - double d2 = getMax(); - if (d2 <= d1) { - // no-op - } else { - newValue = newValue >= d1 ? newValue : d1; - newValue = newValue <= d2 ? newValue : d2; - setHighValue(snapValueToTicks(newValue)); - } - } - - - - /*************************************************************************** - * * - * Properties copied from Slider (and slightly edited) * - * * - **************************************************************************/ - - private DoubleProperty max; - - /** - * Sets the maximum value for this Slider. - * @param value - */ - public final void setMax(double value) { - maxProperty().set(value); - } - - /** - * @return The maximum value of this slider. 100 is returned if - * the maximum value has never been set. - */ - public final double getMax() { - return max == null ? 100 : max.get(); - } - - /** - * - * @return A DoubleProperty representing the maximum value of this Slider. - * This must be a value greater than {@link #minProperty() min}. - */ - public final DoubleProperty maxProperty() { - if (max == null) { - max = new DoublePropertyBase(100) { - @Override protected void invalidated() { - if (get() < getMin()) { - setMin(get()); - } - adjustValues(); - } - - @Override public Object getBean() { - return RangeSlider.this; - } - - @Override public String getName() { - return "max"; //$NON-NLS-1$ - } - }; - } - return max; - } - - private DoubleProperty min; - - /** - * Sets the minimum value for this Slider. - * @param value - */ - public final void setMin(double value) { - minProperty().set(value); - } - - /** - * - * @return the minimum value for this Slider. 0 is returned if the minimum - * has never been set. - */ - public final double getMin() { - return min == null ? 0 : min.get(); - } - - /** - * - * @return A DoubleProperty representing The minimum value of this Slider. - * This must be a value less than {@link #maxProperty() max}. - */ - public final DoubleProperty minProperty() { - if (min == null) { - min = new DoublePropertyBase(0) { - @Override protected void invalidated() { - if (get() > getMax()) { - setMax(get()); - } - adjustValues(); - } - - @Override public Object getBean() { - return RangeSlider.this; - } - - @Override public String getName() { - return "min"; //$NON-NLS-1$ - } - }; - } - return min; - } - - /** - * - */ - private BooleanProperty snapToTicks; - - /** - * Sets the value of SnapToTicks. - * @see #snapToTicksProperty() - * @param value - */ - public final void setSnapToTicks(boolean value) { - snapToTicksProperty().set(value); - } - - /** - * - * @return the value of SnapToTicks. - * @see #snapToTicksProperty() - */ - public final boolean isSnapToTicks() { - return snapToTicks == null ? false : snapToTicks.get(); - } - - /** - * Indicates whether the {@link #lowValueProperty()} value} / - * {@link #highValueProperty()} value} of the {@code Slider} should always - * be aligned with the tick marks. This is honored even if the tick marks - * are not shown. - * @return A BooleanProperty. - */ - public final BooleanProperty snapToTicksProperty() { - if (snapToTicks == null) { - snapToTicks = new StyleableBooleanProperty(false) { - @Override public CssMetaData<? extends Styleable, Boolean> getCssMetaData() { - return RangeSlider.StyleableProperties.SNAP_TO_TICKS; - } - - @Override public Object getBean() { - return RangeSlider.this; - } - - @Override public String getName() { - return "snapToTicks"; //$NON-NLS-1$ - } - }; - } - return snapToTicks; - } - /** - * - */ - private DoubleProperty majorTickUnit; - - /** - * Sets the unit distance between major tick marks. - * @param value - * @see #majorTickUnitProperty() - */ - public final void setMajorTickUnit(double value) { - if (value <= 0) { - throw new IllegalArgumentException("MajorTickUnit cannot be less than or equal to 0."); //$NON-NLS-1$ - } - majorTickUnitProperty().set(value); - } - - /** - * @see #majorTickUnitProperty() - * @return The unit distance between major tick marks. - */ - public final double getMajorTickUnit() { - return majorTickUnit == null ? 25 : majorTickUnit.get(); - } - - /** - * The unit distance between major tick marks. For example, if - * the {@link #minProperty() min} is 0 and the {@link #maxProperty() max} is 100 and the - * {@link #majorTickUnitProperty() majorTickUnit} is 25, then there would be 5 tick marks: one at - * position 0, one at position 25, one at position 50, one at position - * 75, and a final one at position 100. - * <p> - * This value should be positive and should be a value less than the - * span. Out of range values are essentially the same as disabling - * tick marks. - * - * @return A DoubleProperty - */ - public final DoubleProperty majorTickUnitProperty() { - if (majorTickUnit == null) { - majorTickUnit = new StyleableDoubleProperty(25) { - @Override public void invalidated() { - if (get() <= 0) { - throw new IllegalArgumentException("MajorTickUnit cannot be less than or equal to 0."); //$NON-NLS-1$ - } - } - - @Override public CssMetaData<? extends Styleable, Number> getCssMetaData() { - return StyleableProperties.MAJOR_TICK_UNIT; - } - - @Override public Object getBean() { - return RangeSlider.this; - } - - @Override public String getName() { - return "majorTickUnit"; //$NON-NLS-1$ - } - }; - } - return majorTickUnit; - } - /** - * - */ - private IntegerProperty minorTickCount; - - /** - * Sets the number of minor ticks to place between any two major ticks. - * @param value - * @see #minorTickCountProperty() - */ - public final void setMinorTickCount(int value) { - minorTickCountProperty().set(value); - } - - /** - * @see #minorTickCountProperty() - * @return The number of minor ticks to place between any two major ticks. - */ - public final int getMinorTickCount() { - return minorTickCount == null ? 3 : minorTickCount.get(); - } - - /** - * The number of minor ticks to place between any two major ticks. This - * number should be positive or zero. Out of range values will disable - * disable minor ticks, as will a value of zero. - * @return An InterProperty - */ - public final IntegerProperty minorTickCountProperty() { - if (minorTickCount == null) { - minorTickCount = new StyleableIntegerProperty(3) { - @Override public CssMetaData<? extends Styleable, Number> getCssMetaData() { - return RangeSlider.StyleableProperties.MINOR_TICK_COUNT; - } - - @Override public Object getBean() { - return RangeSlider.this; - } - - @Override public String getName() { - return "minorTickCount"; //$NON-NLS-1$ - } - }; - } - return minorTickCount; - } - /** - * - */ - private DoubleProperty blockIncrement; - - /** - * Sets the amount by which to adjust the slider if the track of the slider is - * clicked. - * @param value - * @see #blockIncrementProperty() - */ - public final void setBlockIncrement(double value) { - blockIncrementProperty().set(value); - } - - /** - * @see #blockIncrementProperty() - * @return The amount by which to adjust the slider if the track of the slider is - * clicked. - */ - public final double getBlockIncrement() { - return blockIncrement == null ? 10 : blockIncrement.get(); - } - - /** - * The amount by which to adjust the slider if the track of the slider is - * clicked. This is used when manipulating the slider position using keys. If - * {@link #snapToTicksProperty() snapToTicks} is true then the nearest tick mark to the adjusted - * value will be used. - * @return A DoubleProperty - */ - public final DoubleProperty blockIncrementProperty() { - if (blockIncrement == null) { - blockIncrement = new StyleableDoubleProperty(10) { - @Override public CssMetaData<? extends Styleable, Number> getCssMetaData() { - return RangeSlider.StyleableProperties.BLOCK_INCREMENT; - } - - @Override public Object getBean() { - return RangeSlider.this; - } - - @Override public String getName() { - return "blockIncrement"; //$NON-NLS-1$ - } - }; - } - return blockIncrement; - } - - /** - * - */ - private ObjectProperty<Orientation> orientation; - - /** - * Sets the orientation of the Slider. - * @param value - */ - public final void setOrientation(Orientation value) { - orientationProperty().set(value); - } - - /** - * - * @return The orientation of the Slider. {@link Orientation#HORIZONTAL} is - * returned by default. - */ - public final Orientation getOrientation() { - return orientation == null ? Orientation.HORIZONTAL : orientation.get(); - } - - /** - * The orientation of the {@code Slider} can either be horizontal - * or vertical. - * @return An Objectproperty representing the orientation of the Slider. - */ - public final ObjectProperty<Orientation> orientationProperty() { - if (orientation == null) { - orientation = new StyleableObjectProperty<Orientation>(Orientation.HORIZONTAL) { - @Override protected void invalidated() { - final boolean vertical = (get() == Orientation.VERTICAL); - pseudoClassStateChanged(VERTICAL_PSEUDOCLASS_STATE, vertical); - pseudoClassStateChanged(HORIZONTAL_PSEUDOCLASS_STATE, ! vertical); - } - - @Override public CssMetaData<? extends Styleable, Orientation> getCssMetaData() { - return RangeSlider.StyleableProperties.ORIENTATION; - } - - @Override public Object getBean() { - return RangeSlider.this; - } - - @Override public String getName() { - return "orientation"; //$NON-NLS-1$ - } - }; - } - return orientation; - } - - private BooleanProperty showTickLabels; - - /** - * Sets whether labels of tick marks should be shown or not. - * @param value - */ - public final void setShowTickLabels(boolean value) { - showTickLabelsProperty().set(value); - } - - /** - * @return whether labels of tick marks are being shown. - */ - public final boolean isShowTickLabels() { - return showTickLabels == null ? false : showTickLabels.get(); - } - - /** - * Indicates that the labels for tick marks should be shown. Typically a - * {@link Skin} implementation will only show labels if - * {@link #showTickMarksProperty() showTickMarks} is also true. - * @return A BooleanProperty - */ - public final BooleanProperty showTickLabelsProperty() { - if (showTickLabels == null) { - showTickLabels = new StyleableBooleanProperty(false) { - @Override public CssMetaData<? extends Styleable, Boolean> getCssMetaData() { - return RangeSlider.StyleableProperties.SHOW_TICK_LABELS; - } - - @Override public Object getBean() { - return RangeSlider.this; - } - - @Override public String getName() { - return "showTickLabels"; //$NON-NLS-1$ - } - }; - } - return showTickLabels; - } - /** - * - */ - private BooleanProperty showTickMarks; - - /** - * Specifies whether the {@link Skin} implementation should show tick marks. - * @param value - */ - public final void setShowTickMarks(boolean value) { - showTickMarksProperty().set(value); - } - - /** - * - * @return whether the {@link Skin} implementation should show tick marks. - */ - public final boolean isShowTickMarks() { - return showTickMarks == null ? false : showTickMarks.get(); - } - - /** - * @return A BooleanProperty that specifies whether the {@link Skin} - * implementation should show tick marks. - */ - public final BooleanProperty showTickMarksProperty() { - if (showTickMarks == null) { - showTickMarks = new StyleableBooleanProperty(false) { - @Override public CssMetaData<? extends Styleable, Boolean> getCssMetaData() { - return RangeSlider.StyleableProperties.SHOW_TICK_MARKS; - } - - @Override public Object getBean() { - return RangeSlider.this; - } - - @Override public String getName() { - return "showTickMarks"; //$NON-NLS-1$ - } - }; - } - return showTickMarks; - } - - - - /*************************************************************************** - * * - * Private methods * - * * - **************************************************************************/ - - /** - * Ensures that min is always < max, that value is always - * somewhere between the two, and that if snapToTicks is set then the - * value will always be set to align with a tick mark. - */ - private void adjustValues() { - adjustLowValues(); - adjustHighValues(); - } - - private void adjustLowValues() { - /** - * We first look if the LowValue is between the min and max. - */ - if (getLowValue() < getMin() || getLowValue() > getMax()) { - double value = Utils.clamp(getMin(), getLowValue(), getMax()); - setLowValue(value); - /** - * If the LowValue seems right, we check if it's not superior to - * HighValue ONLY if the highValue itself is right. Because it may - * happen that the highValue has not yet been computed and is - * wrong, and therefore force the lowValue to change in a wrong way - * which may end up in an infinite loop. - */ - } else if (getLowValue() >= getHighValue() && (getHighValue() >= getMin() && getHighValue() <= getMax())) { - double value = Utils.clamp(getMin(), getLowValue(), getHighValue()); - setLowValue(value); - } - } - - private double snapValueToTicks(double d) { - double d1 = d; - if (isSnapToTicks()) { - double d2 = 0.0D; - if (getMinorTickCount() != 0) { - d2 = getMajorTickUnit() / (double) (Math.max(getMinorTickCount(), 0) + 1); - } else { - d2 = getMajorTickUnit(); - } - int i = (int) ((d1 - getMin()) / d2); - double d3 = (double) i * d2 + getMin(); - double d4 = (double) (i + 1) * d2 + getMin(); - d1 = Utils.nearest(d3, d1, d4); - } - return Utils.clamp(getMin(), d1, getMax()); - } - - private void adjustHighValues() { - if (getHighValue() < getMin() || getHighValue() > getMax()) { - setHighValue(Utils.clamp(getMin(), getHighValue(), getMax())); - } else if (getHighValue() < getLowValue() && (getLowValue() >= getMin() && getLowValue() <= getMax())) { - setHighValue(Utils.clamp(getLowValue(), getHighValue(), getMax())); - } - } - - - - /************************************************************************** - * * - * Stylesheet Handling * - * * - **************************************************************************/ - - private static final String DEFAULT_STYLE_CLASS = "range-slider"; //$NON-NLS-1$ - - private static class StyleableProperties { - private static final CssMetaData<RangeSlider,Number> BLOCK_INCREMENT = - new CssMetaData<RangeSlider,Number>("-fx-block-increment", //$NON-NLS-1$ - SizeConverter.getInstance(), 10.0) { - - @Override public boolean isSettable(RangeSlider n) { - return n.blockIncrement == null || !n.blockIncrement.isBound(); - } - - @SuppressWarnings("unchecked") - @Override public StyleableProperty<Number> getStyleableProperty(RangeSlider n) { - return (StyleableProperty<Number>)n.blockIncrementProperty(); - } - }; - - private static final CssMetaData<RangeSlider,Boolean> SHOW_TICK_LABELS = - new CssMetaData<RangeSlider,Boolean>("-fx-show-tick-labels", //$NON-NLS-1$ - BooleanConverter.getInstance(), Boolean.FALSE) { - - @Override public boolean isSettable(RangeSlider n) { - return n.showTickLabels == null || !n.showTickLabels.isBound(); - } - - @SuppressWarnings("unchecked") - @Override public StyleableProperty<Boolean> getStyleableProperty(RangeSlider n) { - return (StyleableProperty<Boolean>)n.showTickLabelsProperty(); - } - }; - - private static final CssMetaData<RangeSlider,Boolean> SHOW_TICK_MARKS = - new CssMetaData<RangeSlider,Boolean>("-fx-show-tick-marks", //$NON-NLS-1$ - BooleanConverter.getInstance(), Boolean.FALSE) { - - @Override public boolean isSettable(RangeSlider n) { - return n.showTickMarks == null || !n.showTickMarks.isBound(); - } - - @SuppressWarnings("unchecked") - @Override public StyleableProperty<Boolean> getStyleableProperty(RangeSlider n) { - return (StyleableProperty<Boolean>)n.showTickMarksProperty(); - } - }; - - private static final CssMetaData<RangeSlider,Boolean> SNAP_TO_TICKS = - new CssMetaData<RangeSlider,Boolean>("-fx-snap-to-ticks", //$NON-NLS-1$ - BooleanConverter.getInstance(), Boolean.FALSE) { - - @Override public boolean isSettable(RangeSlider n) { - return n.snapToTicks == null || !n.snapToTicks.isBound(); - } - - @SuppressWarnings("unchecked") - @Override public StyleableProperty<Boolean> getStyleableProperty(RangeSlider n) { - return (StyleableProperty<Boolean>)n.snapToTicksProperty(); - } - }; - - private static final CssMetaData<RangeSlider,Number> MAJOR_TICK_UNIT = - new CssMetaData<RangeSlider,Number>("-fx-major-tick-unit", //$NON-NLS-1$ - SizeConverter.getInstance(), 25.0) { - - @Override public boolean isSettable(RangeSlider n) { - return n.majorTickUnit == null || !n.majorTickUnit.isBound(); - } - - @SuppressWarnings("unchecked") - @Override public StyleableProperty<Number> getStyleableProperty(RangeSlider n) { - return (StyleableProperty<Number>)n.majorTickUnitProperty(); - } - }; - - private static final CssMetaData<RangeSlider,Number> MINOR_TICK_COUNT = - new CssMetaData<RangeSlider,Number>("-fx-minor-tick-count", //$NON-NLS-1$ - SizeConverter.getInstance(), 3.0) { - - @SuppressWarnings("deprecation") - @Override public void set(RangeSlider node, Number value, StyleOrigin origin) { - super.set(node, value.intValue(), origin); - } - - @Override public boolean isSettable(RangeSlider n) { - return n.minorTickCount == null || !n.minorTickCount.isBound(); - } - - @SuppressWarnings("unchecked") - @Override public StyleableProperty<Number> getStyleableProperty(RangeSlider n) { - return (StyleableProperty<Number>)n.minorTickCountProperty(); - } - }; - - private static final CssMetaData<RangeSlider,Orientation> ORIENTATION = - new CssMetaData<RangeSlider,Orientation>("-fx-orientation", //$NON-NLS-1$ - new EnumConverter<>(Orientation.class), - Orientation.HORIZONTAL) { - - @Override public Orientation getInitialValue(RangeSlider node) { - // A vertical Slider should remain vertical - return node.getOrientation(); - } - - @Override public boolean isSettable(RangeSlider n) { - return n.orientation == null || !n.orientation.isBound(); - } - - @SuppressWarnings("unchecked") - @Override public StyleableProperty<Orientation> getStyleableProperty(RangeSlider n) { - return (StyleableProperty<Orientation>)n.orientationProperty(); - } - }; - - private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES; - static { - final List<CssMetaData<? extends Styleable, ?>> styleables = - new ArrayList<>(Control.getClassCssMetaData()); - styleables.add(BLOCK_INCREMENT); - styleables.add(SHOW_TICK_LABELS); - styleables.add(SHOW_TICK_MARKS); - styleables.add(SNAP_TO_TICKS); - styleables.add(MAJOR_TICK_UNIT); - styleables.add(MINOR_TICK_COUNT); - styleables.add(ORIENTATION); - - STYLEABLES = Collections.unmodifiableList(styleables); - } - } - - - /** - * @return The CssMetaData associated with this class, which may include the - * CssMetaData of its super classes. - */ - public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() { - return StyleableProperties.STYLEABLES; - } - - private static final PseudoClass VERTICAL_PSEUDOCLASS_STATE = - PseudoClass.getPseudoClass("vertical"); //$NON-NLS-1$ - private static final PseudoClass HORIZONTAL_PSEUDOCLASS_STATE = - PseudoClass.getPseudoClass("horizontal"); //$NON-NLS-1$ -} diff --git a/src/org/controlsfx/control/Rating.java b/src/org/controlsfx/control/Rating.java deleted file mode 100644 index a5f1f34..0000000 --- a/src/org/controlsfx/control/Rating.java +++ /dev/null @@ -1,317 +0,0 @@ -/** - * Copyright (c) 2013, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control; - -import impl.org.controlsfx.skin.RatingSkin; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.DoubleProperty; -import javafx.beans.property.IntegerProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.SimpleDoubleProperty; -import javafx.beans.property.SimpleIntegerProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.geometry.Orientation; -import javafx.scene.control.Skin; - -/** - * A control for allowing users to provide a rating. This control supports - * {@link #partialRatingProperty() partial ratings} (i.e. not whole numbers and - * dependent upon where the user clicks in the control) and - * {@link #updateOnHoverProperty() updating the rating on hover}. Read on for - * more examples! - * - * <h3>Examples</h3> - * It can be hard to appreciate some of the features of the Rating control, so - * hopefully the following screenshots will help. Firstly, here is what the - * standard (horizontal) Rating control looks like when it has five stars, and a - * rating of two: - * - * <br> - * <center> - * <img src="rating-horizontal.png" alt="Screenshot of horizontal Rating"> - * </center> - * - * <p>To create a Rating control that looks like this is simple: - * - * <pre> - * {@code - * final Rating rating = new Rating();}</pre> - * - * <p>This creates a default horizontal rating control. To create a vertical - * Rating control, simply change the orientation, as such: - * - * <pre> - * {@code - * final Rating rating = new Rating(); - * rating.setOrientation(Orientation.VERTICAL);}</pre> - * - * <p>The end result of making this one line change is shown in the screenshot - * below: - * - * <br> - * <center> - * <img src="rating-vertical.png" alt="Screenshot of vertical Rating"> - * </center> - * - * <p>One of the features of the Rating control is that it doesn't just allow - * for 'integer' ratings: it also allows for the user to click anywhere within - * the rating area to set a 'float' rating. This is hard to describe, but easy - * to show in a picture: - * - * <br> - * <center> - * <img src="rating-partial.png" alt="Screenshot of partial Rating"> - * </center> - * - * <p>In essence, in the screenshot above, the user clicked roughly in the - * middle of the third star. This results in a rating of approximately 2.44. - * To enable {@link #partialRatingProperty() partial ratings}, simply do the - * following when instantiating the Rating control: - * - * <pre> - * {@code - * final Rating rating = new Rating(); - * rating.setPartialRating(true);}</pre> - * - * <p>So far all of the Rating controls demonstrated above have - * required the user to click on the stars to register their rating. This may not - * be the preferred user interaction - often times the preferred approach is to - * simply allow for the rating to be registered by the user hovering their mouse - * over the rating stars. This mode is also supported by the Rating control, - * using the {@link #updateOnHoverProperty() update on hover} property, as such: - * - * <pre> - * {@code - * final Rating rating = new Rating(); - * rating.setUpdateOnHover(true);}</pre> - * - * <p>It is also allowable to have a Rating control that both updates on hover - * and allows for partial values: the 'golden fill' of the default graphics will - * automatically follow the users mouse as they move it along the Rating scale. - * To enable this, just set both properties to true. - */ -public class Rating extends ControlsFXControl { - - /*************************************************************************** - * - * Constructors - * - **************************************************************************/ - - /** - * Creates a default instance with a minimum rating of 0 and a maximum - * rating of 5. - */ - public Rating() { - this(5); - } - - /** - * Creates a default instance with a minimum rating of 0 and a maximum rating - * as provided by the argument. - * - * @param max The maximum allowed rating value. - */ - public Rating(int max) { - this(max, -1); - } - - /** - * Creates a Rating instance with a minimum rating of 0, a maximum rating - * as provided by the {@code max} argument, and a current rating as provided - * by the {@code rating} argument. - * - * @param max The maximum allowed rating value. - */ - public Rating(int max, int rating) { - getStyleClass().setAll("rating"); //$NON-NLS-1$ - - setMax(max); - setRating(rating == -1 ? (int) Math.floor(max / 2.0) : rating); - } - - - - /*************************************************************************** - * - * Overriding public API - * - **************************************************************************/ - - /** {@inheritDoc} */ - @Override protected Skin<?> createDefaultSkin() { - return new RatingSkin(this); - } - - /** {@inheritDoc} */ - @Override public String getUserAgentStylesheet() { - return getUserAgentStylesheet(Rating.class, "rating.css"); - } - - /*************************************************************************** - * - * Properties - * - **************************************************************************/ - - // --- Rating - /** - * The current rating value. - */ - public final DoubleProperty ratingProperty() { - return rating; - } - private DoubleProperty rating = new SimpleDoubleProperty(this, "rating", 3); //$NON-NLS-1$ - - /** - * Sets the current rating value. - */ - public final void setRating(double value) { - ratingProperty().set(value); - } - - /** - * Returns the current rating value. - */ - public final double getRating() { - return rating == null ? 3 : rating.get(); - } - - - // --- Max - /** - * The maximum-allowed rating value. - */ - public final IntegerProperty maxProperty() { - return max; - } - private IntegerProperty max = new SimpleIntegerProperty(this, "max", 5); //$NON-NLS-1$ - - /** - * Sets the maximum-allowed rating value. - */ - public final void setMax(int value) { - maxProperty().set(value); - } - - /** - * Returns the maximum-allowed rating value. - */ - public final int getMax() { - return max == null ? 5 : max.get(); - } - - - // --- Orientation - /** - * The {@link Orientation} of the {@code Rating} - this can either be - * horizontal or vertical. - */ - public final ObjectProperty<Orientation> orientationProperty() { - if (orientation == null) { - orientation = new SimpleObjectProperty<>(this, "orientation", Orientation.HORIZONTAL); //$NON-NLS-1$ - } - return orientation; - } - private ObjectProperty<Orientation> orientation; - - /** - * Sets the {@link Orientation} of the {@code Rating} - this can either be - * horizontal or vertical. - */ - public final void setOrientation(Orientation value) { - orientationProperty().set(value); - }; - - /** - * Returns the {@link Orientation} of the {@code Rating} - this can either - * be horizontal or vertical. - */ - public final Orientation getOrientation() { - return orientation == null ? Orientation.HORIZONTAL : orientation.get(); - } - - - // --- partial rating - /** - * If true this allows for users to set a rating as a floating point value. - * In other words, the range of the rating 'stars' can be thought of as a - * range between [0, max], and whereever the user clicks will be calculated - * as the new rating value. If this is false the more typical approach is used - * where the selected 'star' is used as the rating. - */ - public final BooleanProperty partialRatingProperty() { - return partialRating; - } - private BooleanProperty partialRating = new SimpleBooleanProperty(this, "partialRating", false); //$NON-NLS-1$ - - /** - * Sets whether {@link #partialRatingProperty() partial rating} support is - * enabled or not. - */ - public final void setPartialRating(boolean value) { - partialRatingProperty().set(value); - } - - /** - * Returns whether {@link #partialRatingProperty() partial rating} support is - * enabled or not. - */ - public final boolean isPartialRating() { - return partialRating == null ? false : partialRating.get(); - } - - - // --- update on hover - /** - * If true this allows for the {@link #ratingProperty() rating property} to - * be updated simply by the user hovering their mouse over the control. If - * false the user is required to click on their preferred rating to register - * the new rating with this control. - */ - public final BooleanProperty updateOnHoverProperty() { - return updateOnHover; - } - private BooleanProperty updateOnHover = new SimpleBooleanProperty(this, "updateOnHover", false); //$NON-NLS-1$ - - /** - * Sets whether {@link #updateOnHoverProperty() update on hover} support is - * enabled or not. - */ - public final void setUpdateOnHover(boolean value) { - updateOnHoverProperty().set(value); - } - - /** - * Returns whether {@link #updateOnHoverProperty() update on hover} support is - * enabled or not. - */ - public final boolean isUpdateOnHover() { - return updateOnHover == null ? false : updateOnHover.get(); - } -} diff --git a/src/org/controlsfx/control/SegmentedButton.java b/src/org/controlsfx/control/SegmentedButton.java deleted file mode 100644 index b27f81a..0000000 --- a/src/org/controlsfx/control/SegmentedButton.java +++ /dev/null @@ -1,241 +0,0 @@ -/** - * Copyright (c) 2013, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control; - -import impl.org.controlsfx.skin.SegmentedButtonSkin; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.scene.control.Skin; -import javafx.scene.control.ToggleButton; -import javafx.scene.control.ToggleGroup; - -/** - * The SegmentedButton is a simple control that forces together a group of - * {@link ToggleButton} instances such that they appear as one collective button - * (with sub-buttons), rather than as individual buttons. This is better - * clarified with a picture: - * - * <br> - * <center> - * <img src="segmentedButton.png" alt="Screenshot of SegmentedButton"> - * </center> - * - * <h3>Code Samples</h3> - * - * <p>There is very little API on this control, you essentially create - * {@link ToggleButton} instances as per usual (and don't bother putting them - * into a {@link ToggleGroup}, as this is done by the SegmentedButton itself), and then - * you place these buttons inside the {@link #getButtons() buttons list}. The - * long-hand way to code this is as follows: - * - * <pre> - * {@code - * ToggleButton b1 = new ToggleButton("day"); - * ToggleButton b2 = new ToggleButton("week"); - * ToggleButton b3 = new ToggleButton("month"); - * ToggleButton b4 = new ToggleButton("year"); - * - * SegmentedButton segmentedButton = new SegmentedButton(); - * segmentedButton.getButtons().addAll(b1, b2, b3, b4);}</pre> - * - * <p>A slightly shorter way of doing this is to pass the ToggleButton instances - * into the varargs constructor, as such: - * - * <pre>{@code SegmentedButton segmentedButton = new SegmentedButton(b1, b2, b3, b4);}</pre> - * - * <h3>Custom ToggleGroup</h3> - * <p>It is possible to configure the ToggleGroup, which is used internally. - * By setting the ToggleGroup to null, the control will allow multiple selections. - * - * <pre> - * {@code - * SegmentedButton segmentedButton = new SegmentedButton(); - * segmentedButton.setToggleGroup(null); - * }</pre> - * - * <h3>Alternative Styling</h3> - * <p>As is visible in the screenshot at the top of this class documentation, - * there are two different styles supported by the SegmentedButton control. - * Firstly, there is the default style based on the JavaFX Modena look. The - * alternative style is what is currently referred to as the 'dark' look. To - * enable this functionality, simply do the following: - * - * <pre> - * {@code - * SegmentedButton segmentedButton = new SegmentedButton(); - * segmentedButton.getStyleClass().add(SegmentedButton.STYLE_CLASS_DARK); - * }</pre> - * - * <h3>Resizable Range</h3> - * <p>By default, the maximum width and height of a SegmentedButton match its - * preferred width and height. Thus, the SegmentedButton only fills the area - * which is necessary to display the contained buttons. To change this behavior, - * the following code can be used: - * - * <pre> - * {@code - * SegmentedButton segmentedButton = new SegmentedButton(); - * segmentedButton.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); - * }</pre> - * - * @see ToggleButton - * @see ToggleGroup - */ -public class SegmentedButton extends ControlsFXControl { - - /************************************************************************** - * - * Static fields - * - *************************************************************************/ - - /** - * An alternative styling for the segmented button, with a darker pressed - * color which stands out more than the default modena styling. Refer to - * the class documentation for details on how to use (and screenshots), but - * in short, simply do the following to get the dark styling: - * - * <pre> - * {@code - * SegmentedButton segmentedButton = new SegmentedButton(); - * segmentedButton.getStyleClass().add(SegmentedButton.STYLE_CLASS_DARK); - * }</pre> - */ - public static final String STYLE_CLASS_DARK = "dark"; //$NON-NLS-1$ - - - - /************************************************************************** - * - * Private fields - * - *************************************************************************/ - - private final ObservableList<ToggleButton> buttons; - private final ObjectProperty<ToggleGroup> toggleGroup = new SimpleObjectProperty<>(new ToggleGroup()); - - /************************************************************************** - * - * Constructors - * - *************************************************************************/ - - /** - * Creates a default SegmentedButton instance with no buttons. - */ - public SegmentedButton() { - this((ObservableList<ToggleButton>)null); - } - - /** - * Creates a default SegmentedButton instance with the provided buttons - * inserted into it. - * - * @param buttons A varargs array of buttons to add into the SegmentedButton - * instance. - */ - public SegmentedButton(ToggleButton... buttons) { - this(buttons == null ? - FXCollections.<ToggleButton>observableArrayList() : - FXCollections.observableArrayList(buttons)); - } - - /** - * Creates a default SegmentedButton instance with the provided buttons - * inserted into it. - * - * @param buttons A list of buttons to add into the SegmentedButton instance. - */ - public SegmentedButton(ObservableList<ToggleButton> buttons) { - getStyleClass().add("segmented-button"); //$NON-NLS-1$ - this.buttons = buttons == null ? FXCollections.<ToggleButton>observableArrayList() : buttons; - - // Fix for Issue #87: - // https://bitbucket.org/controlsfx/controlsfx/issue/87/segmentedbutton-keyboard-focus-traversal - setFocusTraversable(false); - } - - - - - /************************************************************************** - * - * Public API - * - *************************************************************************/ - - /** {@inheritDoc} */ - @Override protected Skin<?> createDefaultSkin() { - return new SegmentedButtonSkin(this); - } - - /** - * Returns the list of buttons that this SegmentedButton will draw together - * into one 'grouped button'. It is possible to modify this list to add or - * remove {@link ToggleButton} instances, as shown in the javadoc - * documentation for this class. - */ - public final ObservableList<ToggleButton> getButtons() { - return buttons; - } - - /** - * @return Property of the ToggleGroup used internally - */ - public ObjectProperty<ToggleGroup> toggleGroupProperty() { - return this.toggleGroup; - } - - /** - * @return ToggleGroup used internally - */ - public ToggleGroup getToggleGroup() { - return this.toggleGroupProperty().getValue(); - } - - /** - * @param toggleGroup ToggleGroup to be used internally - */ - public void setToggleGroup(final ToggleGroup toggleGroup) { - this.toggleGroupProperty().setValue(toggleGroup); - } - - - /************************************************************************** - * - * CSS - * - *************************************************************************/ - - /** {@inheritDoc} */ - @Override public String getUserAgentStylesheet() { - return getUserAgentStylesheet(SegmentedButton.class, "segmentedbutton.css"); - } - -} \ No newline at end of file diff --git a/src/org/controlsfx/control/SnapshotView.java b/src/org/controlsfx/control/SnapshotView.java deleted file mode 100644 index 6a9f480..0000000 --- a/src/org/controlsfx/control/SnapshotView.java +++ /dev/null @@ -1,1733 +0,0 @@ -/** - * Copyright (c) 2014, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control; - -import static javafx.beans.binding.Bindings.and; -import static javafx.beans.binding.Bindings.isNotNull; -import static javafx.beans.binding.Bindings.notEqual; -import impl.org.controlsfx.skin.SnapshotViewSkin; -import impl.org.controlsfx.tools.rectangle.Rectangles2D; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.function.Consumer; -import java.util.function.Function; - -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.DoubleProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.Property; -import javafx.beans.property.ReadOnlyBooleanProperty; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.SimpleDoubleProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.collections.MapChangeListener; -import javafx.collections.ObservableMap; -import javafx.css.CssMetaData; -import javafx.css.StyleConverter; -import javafx.css.Styleable; -import javafx.css.StyleableDoubleProperty; -import javafx.css.StyleableObjectProperty; -import javafx.css.StyleableProperty; -import javafx.geometry.Bounds; -import javafx.geometry.Point2D; -import javafx.geometry.Rectangle2D; -import javafx.scene.Node; -import javafx.scene.SnapshotParameters; -import javafx.scene.control.Control; -import javafx.scene.control.Skin; -import javafx.scene.image.WritableImage; -import javafx.scene.layout.Pane; -import javafx.scene.paint.Color; -import javafx.scene.paint.Paint; - -/** - * A {@code SnapshotView} is a control which allows the user to select an area of a node in the typical manner used by - * picture editors and crate snapshots of the selection. - * <p> - * While holding the left mouse key down, a rectangular selection can be drawn. This selection can be moved, resized in - * eight cardinal directions and removed. Additionally, the selection's ratio can be fixed in which case the user's - * resizing will be limited such that the ratio is always upheld. - * <p> - * The area where the selection is possible is either this entire control or limited to the displayed node. - * - * <h3>Screenshots</h3> - * <center><img src="snapshotView.png" alt="Screenshot of SnapshotView"></center> - * - * <h3>Code Samples</h3> - * The following snippet creates a new instance with the ControlsFX logo loaded from the web, sets a selected area and - * fixes its ratio: - * - * <pre> - * ImageView controlsFxView = new ImageView( - * "http://cache.fxexperience.com/wp-content/uploads/2013/05/ControlsFX.png"); - * SnapshotView snapshotView = new SnapshotView(controlsFxView); - * snapshotView.setSelection(33, 50, 100, 100); - * snapshotView.setFixedSelectionRatio(1); // (this is actually the default value) - * snapshotView.setSelectionRatioFixed(true); - * </pre> - * - * <h3>Functionality Overview</h3> - * - * This is just a vague overview. The linked properties provide a more detailed explanation. - * - * <h4>Node</h4> - * - * The node which this control displays is held by the {@link #nodeProperty() node} property. - * - * <h4>Selection</h4> - * - * There are several properties which interact to manage and indicate the selection. - * - * <h5>State</h5> - * <ul> - * <li>the selection is held by the {@link #selectionProperty() selection} property - * <li>the {@link #hasSelectionProperty() hasSelection} property indicates whether a selection exists - * <li>the {@link #selectionActiveProperty() selectionActive} property indicates whether the current selection is active - * (it is only displayed if it is); by default this property is updated by this control which is determined by the - * {@link #selectionActivityManagedProperty() selectionActivityManaged} property - * </ul> - * - * <h5>Interaction</h5> - * <ul> - * <li>if the selection is changing due to the user interacting with the control, this is indicated by the - * {@link #selectionChangingProperty() selectionChanging} property - * <li>whether the user can select any area of the control or only one above the node is determined by the - * {@link #selectionAreaBoundaryProperty() selectionAreaBoundary} property - * <li>with the {@link #selectionMouseTransparentProperty() selectionMouseTransparent} property the control can be made - * mouse transparent so the user can interact with the displayed node - * <li>the selection's ratio of width to height can be fixed with the {@link #selectionRatioFixedProperty() - * selectionRatioFixed} and the {@link #fixedSelectionRatioProperty() fixedSelectionRatio} properties - * </ul> - * - * <h5>Visualization</h5> - * <ul> - * <li> {@link #selectionAreaFillProperty() selectionAreaFill} property for the selected area's paint - * <li> {@link #selectionBorderPaintProperty() selectionBorderPaint} property for the selection border's paint - * <li> {@link #selectionBorderWidthProperty() selectionBorderWidth} property for the selection border's width - * <li> {@link #unselectedAreaFillProperty() unselectedAreaFill} property for the area outside of the selection - * <li> {@link #unselectedAreaBoundaryProperty() unselectedAreaBoundary} property which defined what the unselected area - * covers - * </ul> - */ -public class SnapshotView extends ControlsFXControl { - - /** - * The maximal divergence between a selection's ratio and the {@link #fixedSelectionRatioProperty() - * fixedselectionRatio} for the selection to still have the correct ratio (see {@link #hasCorrectRatio(Rectangle2D) - * hasCorrectRatio}). - * <p> - * The divergence is expressed relative to the {@code fixedselectionRatio}. - */ - public static final double MAX_SELECTION_RATIO_DIVERGENCE = 1e-6; - - /** - * The key of the {@link #getProperties() property} which is used to update {@link #selectionChangingProperty() - * selectionChanging}. - */ - public static final String SELECTION_CHANGING_PROPERTY_KEY = - SnapshotView.class.getCanonicalName() + ".selection_changing"; //$NON-NLS-1$ - - /* ************************************************************************ - * * - * Attributes & Properties * - * * - **************************************************************************/ - - // NODE - - /** - * @see #nodeProperty() - */ - private final ObjectProperty<Node> node; - - // SELECTION - - /** - * @see #selectionProperty() - */ - private final ObjectProperty<Rectangle2D> selection; - - /** - * @see #hasSelectionProperty() - */ - private final BooleanProperty hasSelection; - - /** - * @see #selectionActiveProperty() - */ - private final BooleanProperty selectionActive; - - /** - * @see #selectionChangingProperty() - */ - private final BooleanProperty selectionChanging; - - /** - * @see #selectionRatioFixedProperty() - */ - private final BooleanProperty selectionRatioFixed; - - /** - * @see #fixedSelectionRatioProperty() - */ - private final DoubleProperty fixedSelectionRatio; - - // META - - /** - * @see #selectionAreaBoundaryProperty() - */ - private final ObjectProperty<Boundary> selectionAreaBoundary; - - /** - * @see #selectionActivityManagedProperty() - */ - private final BooleanProperty selectionActivityManaged; - - /** - * @see #selectionMouseTransparentProperty() - */ - private final BooleanProperty selectionMouseTransparent; - - // VISUALIZATION - - /** - * @see #unselectedAreaBoundaryProperty() - */ - private final ObjectProperty<Boundary> unselectedAreaBoundary; - - /** - * @see #selectionBorderPaintProperty() - */ - private final ObjectProperty<Paint> selectionBorderPaint; - - /** - * @see #selectionBorderWidthProperty() - */ - private final DoubleProperty selectionBorderWidth; - - /** - * @see #selectionAreaFillProperty() - */ - private final ObjectProperty<Paint> selectionAreaFill; - - /** - * @see #unselectedAreaFillProperty() - */ - private final ObjectProperty<Paint> unselectedAreaFill; - - /* ************************************************************************ - * * - * Construction * - * * - **************************************************************************/ - - /** - * Creates a new SnapshotView. - */ - public SnapshotView() { - getStyleClass().setAll(DEFAULT_STYLE_CLASS); - - // NODE - node = new SimpleObjectProperty<>(this, "node"); //$NON-NLS-1$ - - // SELECTION - selection = new SimpleObjectProperty<Rectangle2D>(this, "selection") { //$NON-NLS-1$ - @Override - public void set(Rectangle2D selection) { - if (!isSelectionValid(selection)) { - throw new IllegalArgumentException("The selection \"" + selection + "\" is invalid. " + //$NON-NLS-1$ //$NON-NLS-2$ - "Check the comment on 'SnapshotView.selectionProperty()' " + //$NON-NLS-1$ - "for all criteria a selection must fulfill."); //$NON-NLS-1$ - } - super.set(selection); - } - }; - hasSelection = new SimpleBooleanProperty(this, "hasSelection", false); //$NON-NLS-1$ - hasSelection.bind(and(isNotNull(selection), notEqual(Rectangle2D.EMPTY, selection))); - selectionActive = new SimpleBooleanProperty(this, "selectionActive", false); //$NON-NLS-1$ - selectionChanging = new SimpleBooleanProperty(this, "selectionChanging", false); //$NON-NLS-1$ - - selectionRatioFixed = new SimpleBooleanProperty(this, "selectionRatioFixed", false); //$NON-NLS-1$ - fixedSelectionRatio = new SimpleDoubleProperty(this, "fixedSelectionRatio", 1) { //$NON-NLS-1$ - @Override - public void set(double newValue) { - if (newValue <= 0) { - throw new IllegalArgumentException("The fixed selection ratio must be positive."); //$NON-NLS-1$ - } - super.set(newValue); - } - }; - - // META - selectionAreaBoundary = createStylableObjectProperty( - this, "selectionAreaBoundary", Boundary.CONTROL, Css.SELECTION_AREA_BOUNDARY); //$NON-NLS-1$ - selectionActivityManaged = new SimpleBooleanProperty(this, "selectionActivityManaged", true); //$NON-NLS-1$ - selectionMouseTransparent = new SimpleBooleanProperty(this, "selectionMouseTransparent", false); //$NON-NLS-1$ - - // VISUALIZATION - unselectedAreaBoundary = createStylableObjectProperty( - this, "unselectedAreaBoundary", Boundary.CONTROL, Css.UNSELECTED_AREA_BOUNDARY); //$NON-NLS-1$ - selectionBorderPaint = createStylableObjectProperty( - this, "selectionBorderPaint", Color.WHITESMOKE, Css.SELECTION_BORDER_PAINT); //$NON-NLS-1$ - selectionBorderWidth = createStylableDoubleProperty( - this, "selectionBorderWidth", 2.5, Css.SELECTION_BORDER_WIDTH); //$NON-NLS-1$ - selectionAreaFill = createStylableObjectProperty( - this, "selectionAreaFill", Color.TRANSPARENT, Css.SELECTION_AREA_FILL); //$NON-NLS-1$ - unselectedAreaFill = createStylableObjectProperty( - this, "unselectedAreaFill", new Color(0, 0, 0, 0.5), Css.UNSELECTED_AREA_FILL); //$NON-NLS-1$ - - addStateUpdatingListeners(); - // update selection when resizing - new SelectionSizeUpdater().enableResizing(); - } - - /** - * Adds listeners to the properties which update the control's state. - */ - private void addStateUpdatingListeners() { - // update the selection activity state when the selection is set - selection.addListener((o, oldValue, newValue) -> updateSelectionActivityState()); - - // ratio - selectionRatioFixed.addListener((o, oldValue, newValue) -> { - boolean valueChangedToTrue = !oldValue && newValue; - if (valueChangedToTrue) { - fixSelectionRatio(); - } - }); - fixedSelectionRatio.addListener((o, oldValue, newValue) -> { - if (isSelectionRatioFixed()) { - fixSelectionRatio(); - } - }); - - // set selection changing according to the values set in the property map - listenToProperty( - getProperties(), SELECTION_CHANGING_PROPERTY_KEY, (Boolean value) -> selectionChanging.set(value)); - } - - /** - * Listens to the specified properties. When a pair with the specified key is added, it is processed. If the value - * has the correct type, it is given to the specified consumer. Even if the type does not match, it is removed from - * the map. - * - * @param properties - * the {@link ObservableMap} which contains the properties; typically {@link Control#getProperties()} - * @param key - * the key for whose value is listened - * @param processValue - * the {@link Consumer} for the new value - */ - private static <T> void listenToProperty( - ObservableMap<Object, Object> properties, Object key, Consumer<T> processValue) { - - Objects.requireNonNull(properties, "The argument 'properties' must not be null."); //$NON-NLS-1$ - Objects.requireNonNull(key, "The argument 'key' must not be null."); //$NON-NLS-1$ - Objects.requireNonNull(processValue, "The argument 'processValue' must not be null."); //$NON-NLS-1$ - - @SuppressWarnings("unchecked") - MapChangeListener<Object, Object> listener = change -> { - boolean addedForKey = - change.wasAdded() && Objects.equals(key, change.getKey()); - if (addedForKey) { - // give the value to the consumer if it has the correct type - try { - // note that this cast does nothing except to calm the compiler - // (hence the warning which had to be suppressed) - T newValue = (T) change.getValueAdded(); - // this is where the actual exception is created - processValue.accept(newValue); - } catch (ClassCastException e) { - // the value was of the wrong type so it can't be processed by the consumer - // -> do nothing - } - // remove the value from the properties map - properties.remove(key); - } - }; - - properties.addListener(listener); - } - - /** - * Creates a new SnapshotView using the specified node. - * - * @param node - * the node to show after construction - */ - public SnapshotView(Node node) { - this(); - setNode(node); - } - - /* ************************************************************************ - * * - * Public Methods * - * * - **************************************************************************/ - - /** - * Transforms the {@link #selectionProperty() selection} to node coordinates by calling - * {@link #transformToNodeCoordinates(Rectangle2D) transformToNodeCoordinates}. - * - * @return a {@link Rectangle2D} which expresses the selection in the node's coordinates - * @throws IllegalStateException - * if {@link #nodeProperty() node} is {@code null} or {@link #hasSelection() hasSelection} is - * {@code false} - * @see #transformToNodeCoordinates(Rectangle2D) - */ - public Rectangle2D transformSelectionToNodeCoordinates() { - if (!hasSelection()) { - throw new IllegalStateException( - "The selection can not be transformed if it does not exist (check 'hasSelection()')."); //$NON-NLS-1$ - } - - return transformToNodeCoordinates(getSelection()); - } - - /** - * Transforms the specified area's coordinates to coordinates relative to the node. (The node's coordinate system - * has its origin in the upper left corner of the node.) - * - * @param area - * the {@link Rectangle2D} which will be transformed (must not be {@code null}); its coordinates will be - * interpreted relative to the control (like the {@link #selectionProperty() selection}) - * @return a {@link Rectangle2D} with the same width and height as the specified {@code area} but with coordinates - * which are relative to the current {@link #nodeProperty() node} - * @throws IllegalStateException - * if {@link #nodeProperty() node} is {@code null} - */ - public Rectangle2D transformToNodeCoordinates(Rectangle2D area) throws IllegalStateException { - Objects.requireNonNull(area, "The argument 'area' must not be null."); //$NON-NLS-1$ - if (getNode() == null) { - throw new IllegalStateException( - "The selection can not be transformed if the node is null (check 'getNode()')."); //$NON-NLS-1$ - } - - // get the offset from the node's bounds - Bounds nodeBounds = getNode().getBoundsInParent(); - double xOffset = nodeBounds.getMinX(); - double yOffset = nodeBounds.getMinY(); - - // the coordinates of the transformed selection - double minX = area.getMinX() - xOffset; - double minY = area.getMinY() - yOffset; - - return new Rectangle2D(minX, minY, area.getWidth(), area.getHeight()); - } - - /** - * Creates a snapshot of the selected area of the node. - * - * @return the {@link WritableImage} that holds the rendered selection - * @throws IllegalStateException - * if {@link #nodeProperty() node} is {@code null} or {@link #hasSelection() hasSelection} is - * {@code false} - * @see Node#snapshot - */ - public WritableImage createSnapshot() throws IllegalStateException { - // make sure the node and the selection exist - if (getNode() == null) { - throw new IllegalStateException("No snapshot can be created if the node is null (check 'getNode()')."); //$NON-NLS-1$ - } - if (!hasSelection()) { - throw new IllegalStateException( - "No snapshot can be created if there is no selection (check 'hasSelection()')."); //$NON-NLS-1$ - } - - SnapshotParameters parameters = new SnapshotParameters(); - parameters.setViewport(getSelection()); - return createSnapshot(parameters); - } - - /** - * Creates a snapshot of the node with the specified parameters. - * - * @param parameters - * the {@link SnapshotParameters} used for the snapshot (must not be {@code null}); the viewport will be - * interpreted relative to this control (like the {@link #selectionProperty() selection}) - * @return the {@link WritableImage} that holds the rendered viewport - * @throws IllegalStateException - * if {@link #nodeProperty() node} is {@code null} - * @see Node#snapshot - */ - public WritableImage createSnapshot(SnapshotParameters parameters) throws IllegalStateException { - // make sure the node and the snapshot parameters exist - Objects.requireNonNull(parameters, "The argument 'parameters' must not be null."); //$NON-NLS-1$ - if (getNode() == null) { - throw new IllegalStateException("No snapshot can be created if the node is null (check 'getNode()')."); //$NON-NLS-1$ - } - - // take the snapshot - return getNode().snapshot(parameters, null); - } - - /* ************************************************************************ - * * - * Model State * - * * - **************************************************************************/ - - /** - * Updates the {@link #selectionActiveProperty() selectionActive} property if the - * {@link #selectionActivityManagedProperty() selectionActivityManaged} property indicates that it is managed by - * this control. - */ - private void updateSelectionActivityState() { - boolean userManaged = !isSelectionActivityManaged(); - if (userManaged) { - return; - } - - boolean selectionActive = getSelection() != null && getSelection() != Rectangle2D.EMPTY; - setSelectionActive(selectionActive); - } - - /** - * Resizes the current selection (if it exists) to the {@link #fixedSelectionRatioProperty() fixedSelectionRatio}. - */ - private void fixSelectionRatio() { - boolean noSelectionToFix = getNode() == null || !hasSelection(); - if (noSelectionToFix) { - return; - } - - Rectangle2D selectionBounds = getSelectionBounds(); - Rectangle2D resizedSelection = Rectangles2D.fixRatioWithinBounds( - getSelection(), getFixedSelectionRatio(), selectionBounds); - - selection.set(resizedSelection); - } - - /** - * - * @return the bounds of the current selection according to the {@link #selectionAreaBoundaryProperty() - * selectionAreaBoundary}. - */ - private Rectangle2D getSelectionBounds() { - Boundary boundary = getSelectionAreaBoundary(); - switch (boundary) { - case CONTROL: - return new Rectangle2D(0, 0, getWidth(), getHeight()); - case NODE: - return Rectangles2D.fromBounds(getNode().getBoundsInParent()); - default: - throw new IllegalArgumentException("The boundary '" + boundary + "' is not fully implemented yet."); //$NON-NLS-1$ //$NON-NLS-2$ - } - } - - /** - * Checks whether the specified selection is valid. This includes checking whether the selection is in bounds and - * has the correct ratio (if the ratio is fixed). - * - * @param selection - * the selection to check as a {@link Rectangle2D} - * @return {@code true} if the selection is valid; {@code false} otherwise - */ - private boolean isSelectionValid(Rectangle2D selection) { - // empty selections are valid - boolean emptySelection = selection == null || selection == Rectangle2D.EMPTY; - if (emptySelection) { - return true; - } - - // check values - if (!valuesFinite(selection)) { - return false; - } - - // check bounds - if (!inBounds(selection)) { - return false; - } - - // check ratio - if (!hasCorrectRatio(selection)) { - return false; - } - - return true; - } - - /** - * Indicates whether the specified selection has only finite values (e.g. width and height). - * - * @param selection - * the selection as a {@link Rectangle2D} - * @return {@code true} if the selection has only finite values. - */ - private static boolean valuesFinite(Rectangle2D selection) { - return Double.isFinite(selection.getMinX()) && Double.isFinite(selection.getMinY()) && - Double.isFinite(selection.getWidth()) && Double.isFinite(selection.getHeight()); - } - - /** - * Indicates whether the specified selection is inside the bounds determined by the - * {@link #selectionAreaBoundaryProperty() selectionAreaBoundary} property. - * - * @param selection - * the non-null and non-empty selection as a {@link Rectangle2D} - * @return {@code true} if the selection is fully contained in the bounds; otherwise {@code false} - */ - private boolean inBounds(Rectangle2D selection) { - Boundary boundary = getSelectionAreaBoundary(); - switch (boundary) { - case CONTROL: - return inBounds(selection, getBoundsInLocal()); - case NODE: - if (getNode() == null) { - return false; - } else { - return inBounds(selection, getNode().getBoundsInParent()); - } - default: - throw new IllegalArgumentException("The boundary '" + boundary + "' is not fully implemented yet."); //$NON-NLS-1$ //$NON-NLS-2$ - } - } - - /** - * Indicates whether the specified selection is inside the specified bounds. - * - * @param selection - * the selection as a {@link Rectangle2D} - * @param bounds - * the {@link Bounds} to check the selection against - * @return {@code true} if the selection is fully contained in the bounds; otherwise {@code false} - */ - private static boolean inBounds(Rectangle2D selection, Bounds bounds) { - return bounds.getMinX() <= selection.getMinX() && bounds.getMinY() <= selection.getMinY() && - selection.getMaxX() <= bounds.getMaxX() && selection.getMaxY() <= bounds.getMaxY(); - } - - /** - * Indicates whether the specified selection has the correct ratio (which depends on whether the ratio is even - * {@link #selectionRatioFixedProperty() fixed}). - * - * @param selection - * the selection to check as a {@link Rectangle2D} - * @return {@code true} if the selection has the correct ratio. - */ - private boolean hasCorrectRatio(Rectangle2D selection) { - if (!isSelectionRatioFixed()) { - return true; - } - - double ratio = selection.getWidth() / selection.getHeight(); - // compute the divergence relative to the fixed selection ratio - double ratioDivergence = Math.abs(1 - ratio / getFixedSelectionRatio()); - return ratioDivergence <= MAX_SELECTION_RATIO_DIVERGENCE; - } - - /* ************************************************************************ - * * - * Style Sheet & Skin Handling * - * * - **************************************************************************/ - - /** - * The name of the style class used in CSS for instances of this class. - */ - private static final String DEFAULT_STYLE_CLASS = "snapshot-view"; //$NON-NLS-1$ - - /** {@inheritDoc} */ - @Override - public String getUserAgentStylesheet() { - return getUserAgentStylesheet(SnapshotView.class, "snapshot-view.css"); //$NON-NLS-1$ - } - - /** - * Creates a {@link StyleableDoubleProperty} with the specified arguments. - * - * @param bean - * the {@link Property#getBean() bean} the created property belongs to - * @param name - * the property's {@link Property#getName() name} - * @param initialValue - * the property's initial value - * @param cssMetaData - * the {@link CssMetaData} for the created property - * @return a {@link StyleableDoubleProperty} - */ - private static StyleableDoubleProperty createStylableDoubleProperty( - Object bean, String name, double initialValue, CssMetaData<? extends Styleable, Number> cssMetaData) { - - return new StyleableDoubleProperty(initialValue) { - - @Override - public Object getBean() { - return bean; - } - - @Override - public String getName() { - return name; - } - - @Override - public CssMetaData<? extends Styleable, Number> getCssMetaData() { - return cssMetaData; - } - - }; - } - - /** - * Creates a {@link StyleableObjectProperty} with the specified arguments. - * - * @param bean - * the {@link Property#getBean() bean} the created property belongs to - * @param name - * the property's {@link Property#getName() name} - * @param initialValue - * the property's initial value - * @param cssMetaData - * the {@link CssMetaData} for the created property - * @return a {@link StyleableObjectProperty} - */ - private static <T> StyleableObjectProperty<T> createStylableObjectProperty( - Object bean, String name, T initialValue, CssMetaData<? extends Styleable, T> cssMetaData) { - - return new StyleableObjectProperty<T>(initialValue) { - - @Override - public Object getBean() { - return bean; - } - - @Override - public String getName() { - return name; - } - - @Override - public CssMetaData<? extends Styleable, T> getCssMetaData() { - return cssMetaData; - } - - }; - } - - /** - * Creates an instance of {@link CssMetaData} with the specified arguments. - * - * @param getProperty - * a function from the {@link Styleable} which owns the styled property to the property styled by the - * returned {@code CssMetaData} - * @param cssPropertyName - * the name by which the styled property is referenced in CSS files - * @param styleConverter - * the {@link StyleConverter} used to convert the CSS parsed value to a Java object - * @return an instance of {@link CssMetaData} - */ - private static <S extends Styleable, T> CssMetaData<S, T> createCssMetaData( - Function<S, Property<T>> getProperty, String cssPropertyName, StyleConverter<?, T> styleConverter) { - - return new CssMetaData<S, T>(cssPropertyName, styleConverter) { - - @Override - public boolean isSettable(S styleable) { - final Property<T> property = getProperty.apply(styleable); - return property != null && !property.isBound(); - } - - @Override - @SuppressWarnings("unchecked") - public StyleableProperty<T> getStyleableProperty(S styleable) { - return (StyleableProperty<T>) getProperty.apply(styleable); - } - }; - } - - /** - * The class which holds this control's {@link CssMetaData} for the different {@link StyleableProperty - * StyleableProperties}. - */ - @SuppressWarnings({ "javadoc", "unchecked" }) - private static class Css { - - public static final CssMetaData<SnapshotView, Boundary> SELECTION_AREA_BOUNDARY = - createCssMetaData( - snapshotView -> snapshotView.selectionAreaBoundary, "-fx-selection-area-boundary", //$NON-NLS-1$ - (StyleConverter<?, Boundary>) StyleConverter.getEnumConverter(Boundary.class)); - - public static final CssMetaData<SnapshotView, Boundary> UNSELECTED_AREA_BOUNDARY = - createCssMetaData( - snapshotView -> snapshotView.unselectedAreaBoundary, "-fx-unselected-area-boundary", //$NON-NLS-1$ - (StyleConverter<?, Boundary>) StyleConverter.getEnumConverter(Boundary.class)); - - public static final CssMetaData<SnapshotView, Paint> SELECTION_BORDER_PAINT = - createCssMetaData( - snapshotView -> snapshotView.selectionBorderPaint, "-fx-selection-border-paint", //$NON-NLS-1$ - StyleConverter.getPaintConverter()); - - public static final CssMetaData<SnapshotView, Number> SELECTION_BORDER_WIDTH = - createCssMetaData( - snapshotView -> snapshotView.selectionBorderWidth, "-fx-selection-border-width", //$NON-NLS-1$ - StyleConverter.getSizeConverter()); - - public static final CssMetaData<SnapshotView, Paint> SELECTION_AREA_FILL = - createCssMetaData( - snapshotView -> snapshotView.selectionAreaFill, "-fx-selection-area-fill", //$NON-NLS-1$ - StyleConverter.getPaintConverter()); - - public static final CssMetaData<SnapshotView, Paint> UNSELECTED_AREA_FILL = - createCssMetaData( - snapshotView -> snapshotView.unselectedAreaFill, "-fx-unselected-area-fill", //$NON-NLS-1$ - StyleConverter.getPaintConverter()); - - /** - * The {@link CssMetaData} associated with this class, which includes the {@code CssMetaData} of its super - * classes. - */ - public static final List<CssMetaData<? extends Styleable, ?>> CSS_META_DATA; - - static { - final List<CssMetaData<? extends Styleable, ?>> styleables = new ArrayList<>(Control.getClassCssMetaData()); - styleables.add(SELECTION_AREA_BOUNDARY); - styleables.add(UNSELECTED_AREA_BOUNDARY); - styleables.add(SELECTION_BORDER_PAINT); - styleables.add(SELECTION_BORDER_WIDTH); - styleables.add(SELECTION_AREA_FILL); - styleables.add(UNSELECTED_AREA_FILL); - CSS_META_DATA = Collections.unmodifiableList(styleables); - } - } - - /** - * @return the {@link CssMetaData} associated with this class, which includes the {@code CssMetaData} of its super - * classes - */ - public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() { - return Css.CSS_META_DATA; - } - - @Override - public List<CssMetaData<? extends Styleable, ?>> getControlCssMetaData() { - return getClassCssMetaData(); - } - - @Override - protected Skin<?> createDefaultSkin() { - return new SnapshotViewSkin(this); - } - - /* ************************************************************************ - * * - * Property Access * - * * - **************************************************************************/ - - // NODE - - /** - * The {@link Node} which will be displayed in the center of this control. - * <p> - * The node's {@link Node#boundsInParentProperty() boundsInParent} show its relative position inside this control. - * Since the {@link #selectionProperty() selection} property also uses this control as its reference coordinate - * system, the bounds can be used to compute which area of the node is selected. - * <p> - * If this control or the node behaves strangely when resized, try embedding the original node in a {@link Pane} and - * setting the pane here. - * - * @return the property holding the displayed node - */ - public final ObjectProperty<Node> nodeProperty() { - return node; - } - - /** - * @return the displayed node - * @see #nodeProperty() - */ - public final Node getNode() { - return nodeProperty().get(); - } - - /** - * @param node - * the node to display - * @see #nodeProperty() - */ - public final void setNode(Node node) { - nodeProperty().set(node); - } - - // SELECTION - - /** - * The current selection as a {@link Rectangle2D}. As such an instance is immutable a new one must be set to chane - * the selection. - * <p> - * The rectangle's coordinates are interpreted relative to this control. The top left corner is the origin (0, 0) - * and the lower right corner is ({@link #widthProperty() width}, {@link #heightProperty() height}). It is - * guaranteed that the selection always lies within these bounds. If the control is resized, so is the selection. If - * a selection which violates these bounds is set, an {@link IllegalArgumentException} is thrown. - * <p> - * The same is true if the {@link #selectionAreaBoundaryProperty() selectionAreaBoundary} is set to {@code NODE} but - * with the stricter condition that the selection must lie within the {@link #nodeProperty() node}'s - * {@link Node#boundsInParentProperty() boundsInParent}. - * <p> - * If the selection ratio is {@link #selectionRatioFixedProperty() fixed}, any new selection must have the - * {@link #fixedSelectionRatioProperty() fixedSelectionRatio}. Otherwise, an {@code IllegalArgumentException} is - * thrown. - * <p> - * An {@code IllegalArgumentException} is also thrown if not all of the selection's values (e.g. width and height) - * are finite. - * <p> - * The selection might be {@code null} or {@link Rectangle2D#EMPTY} in which case no selection is displayed and - * {@link #hasSelectionProperty() hasSelection} is {@code false}. - * - * @return the property holding the current selection - * @see #hasSelectionProperty() - */ - public final ObjectProperty<Rectangle2D> selectionProperty() { - return selection; - } - - /** - * @return the current selection - * @see #selectionProperty() - */ - public final Rectangle2D getSelection() { - return selectionProperty().get(); - } - - /** - * @param selection - * the new selection - * @throws IllegalArgumentException - * if the selection is out of the bounds defined by the {@link #selectionAreaBoundaryProperty() - * selectionAreaBoundary} or the selection ratio is {@link #selectionRatioFixedProperty() fixed} and the - * new selection does not have the {@link #fixedSelectionRatioProperty() fixedSelectionRatio}. - * @see #selectionProperty() - */ - public final void setSelection(Rectangle2D selection) { - selectionProperty().set(selection); - } - - /** - * Creates a new {@link Rectangle2D} from the specified arguments and sets it as the new - * {@link #selectionProperty() selection}. It will have ({@code upperLeftX}, {@code upperLeftY}) as its upper left - * point and span {@code width} to the right and {@code height} down. - * - * @param upperLeftX - * the x coordinate of the selection's upper left point - * @param upperLeftY - * the y coordinate of the selection's upper left point - * @param width - * the selection's width - * @param height - * the selection's height - * @throws IllegalArgumentException - * if the selection is out of the bounds defined by the {@link #selectionAreaBoundaryProperty() - * selectionAreaBoundary} or the selection ratio is {@link #selectionRatioFixedProperty() fixed} and the - * new selection does not have the {@link #fixedSelectionRatioProperty() fixedSelectionRatio}. - * @see #selectionProperty() - * - */ - public final void setSelection(double upperLeftX, double upperLeftY, double width, double height) { - selectionProperty().set(new Rectangle2D(upperLeftX, upperLeftY, width, height)); - } - - /** - * Indicates whether there currently is a selection. This will be {@code false} if the {@link #selectionProperty() - * selection} property holds {@code null} or {@link Rectangle2D#EMPTY} . - * - * @return a property indicating whether there currently is a selection - */ - public final ReadOnlyBooleanProperty hasSelectionProperty() { - return hasSelection; - } - - /** - * @return whether there currently is a selection - * @see #hasSelectionProperty() - */ - public final boolean hasSelection() { - return hasSelectionProperty().get(); - } - - /** - * Indicates whether the selection is currently active. Only an active selection will be displayed by the control. - * <p> - * See {@link #selectionActivityManagedProperty() selectionActivityManaged} for documentation on how this property - * might be changed by this control. - * - * @return the property indicating whether the selection is active - */ - public final BooleanProperty selectionActiveProperty() { - return selectionActive; - } - - /** - * @return whether the selection is active - * @see #selectionActiveProperty() - */ - public final boolean isSelectionActive() { - return selectionActiveProperty().get(); - } - - /** - * @param selectionActive - * the new selection active status - * @see #selectionActiveProperty() - */ - public final void setSelectionActive(boolean selectionActive) { - selectionActiveProperty().set(selectionActive); - } - - /** - * Indicates whether the {@link #selectionProperty() selection} is currently changing due to user interaction with - * the control. It will be set to {@code true} when changing the selection begins and set to {@code false} when it - * ends. - * <p> - * If a selection is set by the code using this control (e.g. by calling {@link #setSelection(Rectangle2D) - * setSelection}) this property does not change its value. - * - * @return a property indicating whether the selection is changing by user interaction - */ - public final ReadOnlyBooleanProperty selectionChangingProperty() { - return selectionChanging; - } - - /** - * @return whether the selection is changing by user interaction - * @see #selectionChangingProperty() - */ - public final boolean isSelectionChanging() { - return selectionChangingProperty().get(); - } - - /** - * Indicates whether the ratio of the {@link #selectionProperty() selection} is fixed. - * <p> - * By default this property is {@code false} and the user interacting with this control can make arbitrary - * selections with any ratio of width to height. If it is {@code true}, the user is limited to making selections - * with the ratio defined by the {@link #fixedSelectionRatioProperty() fixedSelectionRatio} property. If the ratio - * is fixed and a selection with a different ratio is set, an {@link IllegalArgumentException} is thrown. - * <p> - * If a selection exists and this property is set to {@code true}, the selection is immediately resized to the - * currently set ratio. - * - * @defaultValue {@code false} - * @return the property indicating whether the selection ratio is fixed - */ - public final BooleanProperty selectionRatioFixedProperty() { - return selectionRatioFixed; - } - - /** - * @return whether the selection ratio is fixed - * @see #selectionRatioFixedProperty() - */ - public final boolean isSelectionRatioFixed() { - return selectionRatioFixedProperty().get(); - } - - /** - * @param selectionRatioFixed - * whether the selection ratio will be fixed - * @see #selectionRatioFixedProperty() - */ - public final void setSelectionRatioFixed(boolean selectionRatioFixed) { - selectionRatioFixedProperty().set(selectionRatioFixed); - } - - /** - * The value to which the selection ratio is fixed. The ratio is defined as {@code width / height} and its value - * must be strictly positive. - * <p> - * If {@link #selectionRatioFixedProperty() selectionRatioFixed} is {@code true}, this ratio will be upheld by all - * changes made by user interaction with this control. If the ratio is fixed and a selection is set by code (e.g. by - * calling {@link #setSelection(Rectangle2D) setSelection}), this ratio is checked and if violated an - * {@link IllegalArgumentException} is thrown. - * <p> - * If a selection exists and {@code selectionRatioFixed} is set to {@code true}, the selection is immediately - * resized to this ratio. Similarly, if a selection exists and its ratio is fixed, setting a new value resizes the - * selection to the new ratio. - * - * @defaultValue 1.0 - * @return a property containing the fixed selection ratio - */ - public final DoubleProperty fixedSelectionRatioProperty() { - return fixedSelectionRatio; - } - - /** - * @return the fixedSelectionRatio, which will always be a strictly positive value - * @see #fixedSelectionRatioProperty() - */ - public final double getFixedSelectionRatio() { - return fixedSelectionRatioProperty().get(); - } - - /** - * @param fixedSelectionRatio - * the fixed selection ratio to set - * @throws IllegalArgumentException - * if {@code fixedSelectionRatio} is not strictly positive - * @see #fixedSelectionRatioProperty() - */ - public final void setFixedSelectionRatio(double fixedSelectionRatio) { - fixedSelectionRatioProperty().set(fixedSelectionRatio); - } - - // META - - /** - * Indicates which {@link Boundary} is set for the area the user can select. - * <p> - * By default the user can select any area of the control. If this should be limited to the area over the displayed - * node instead, this property can be set to {@link Boundary#NODE NODE}. If the value is changed from - * {@code CONTROL} to {@code NODE} a possibly existing selection is resized accordingly. - * <p> - * If the boundary is set to {@code NODE}, this is also respected when a new {@link #selectionProperty() selection} - * is set. This means the condition for the new selection's coordinates is made stricter and setting a selection out - * of the node's bounds (instead of only out of the control's bounds) throws an {@link IllegalArgumentException}. - * <p> - * Note that this does <b>not</b> change the reference coordinate system! The selection's coordinates are still - * interpreted relative to the {@link #nodeProperty() node}'s {@link Node#boundsInParentProperty() boundsInParent}. - * - * @defaultValue {@link Boundary#CONTROL CONTROL} - * @return the property indicating the {@link Boundary} for the area the user can select - */ - public final ObjectProperty<Boundary> selectionAreaBoundaryProperty() { - return selectionAreaBoundary; - } - - /** - * @return the {@link Boundary} for the area the user can select - */ - public final Boundary getSelectionAreaBoundary() { - return selectionAreaBoundaryProperty().get(); - } - - /** - * @param selectionAreaBoundary - * the new {@link Boundary} for the area the user can select - */ - public final void setSelectionAreaBoundary(Boundary selectionAreaBoundary) { - selectionAreaBoundaryProperty().set(selectionAreaBoundary); - } - - /** - * Indicates whether the value of the {@link #selectionActiveProperty() selectionActive} property is managed by this - * control. - * <p> - * If this property is set to {@code true} (which is the default) this control will update the - * {@code selectionActive} property immediately after a new selection is set: if the new selection is {@code null} - * or {@link Rectangle2D#EMPTY}, it will be set to {@code false}; otherwise to {@code true}. - * <p> - * If this property is {@code false} this control will never change {@code selectionActive}'s value. In this case it - * must be managed by the using code but it is possible to unidirectionally bind it to another property without this - * control interfering. - * - * @defaultValue {@code true} - * @return the property indicating whether the value of the {@link #selectionActiveProperty() selectionActive} - * property is managed by this control - */ - public final BooleanProperty selectionActivityManagedProperty() { - return selectionActivityManaged; - } - - /** - * @return whether the selection activity is managed by this control - * @see #selectionActivityManagedProperty() - */ - public final boolean isSelectionActivityManaged() { - return selectionActivityManagedProperty().get(); - } - - /** - * @param selectionActivityManaged - * whether the selection activity will be managed by this control - * @see #selectionActivityManagedProperty() - */ - public final void setSelectionActivityManaged(boolean selectionActivityManaged) { - selectionActivityManagedProperty().set(selectionActivityManaged); - } - - /** - * Indicates whether the overlay which displays the selection is mouse transparent. - * <p> - * By default all mouse events are captured by this control and used to interact with the selection. If this - * property is set to {@code true}, this behavior changes and the user is able to interact with the displayed - * {@link #nodeProperty() node}. - * - * @defaultValue {@code false} - * @return the property indicating whether the selection is mouse transparent - */ - public final BooleanProperty selectionMouseTransparentProperty() { - return selectionMouseTransparent; - } - - /** - * @return whether the selection is mouse transparent - * @see #selectionMouseTransparentProperty() - */ - public final boolean isSelectionMouseTransparent() { - return selectionMouseTransparentProperty().get(); - } - - /** - * @param selectionMouseTransparent - * whether the selection will be mouse transparent - * @see #selectionMouseTransparentProperty() - */ - public final void setSelectionMouseTransparent(boolean selectionMouseTransparent) { - selectionMouseTransparentProperty().set(selectionMouseTransparent); - } - - // VISUALIZATION - - /** - * Indicates which {@link Boundary} is set for the visualization of the unselected area (i.e. the area outside of - * the selection rectangle). - * <p> - * If it is set to {@link Boundary#CONTROL CONTROL} (which is the default), the unselected area covers the whole - * control. - * <p> - * If it is set to {@link Boundary#NODE NODE}, the area only covers the displayed {@link #nodeProperty() node}. In - * most cases this only makes sense if the {@link #selectionAreaBoundaryProperty() selectionAreaBoundary} is also - * set to {@code NODE}. - * - * @defaultValue {@link Boundary#CONTROL} - * @return the property defining the {@link Boundary} of the unselected area - */ - public final ObjectProperty<Boundary> unselectedAreaBoundaryProperty() { - return unselectedAreaBoundary; - } - - /** - * @return the {@link Boundary} for the unselected area - * @see #unselectedAreaBoundaryProperty() - */ - public final Boundary getUnselectedAreaBoundary() { - return unselectedAreaBoundaryProperty().get(); - } - - /** - * @param unselectedAreaBoundary - * the new {@link Boundary} for the unselected area - * @see #unselectedAreaBoundaryProperty() - */ - public final void setUnselectedAreaBoundary(Boundary unselectedAreaBoundary) { - unselectedAreaBoundaryProperty().set(unselectedAreaBoundary); - } - - /** - * Determines the visualization of the selection's border. - * - * @defaultValue {@link Color#WHITESMOKE} - * @return the property holding the {@link Paint} of the selection border - * @see #selectionBorderWidthProperty() - */ - public final ObjectProperty<Paint> selectionBorderPaintProperty() { - return selectionBorderPaint; - } - - /** - * @return the {@link Paint} of the selection border - * @see #selectionBorderPaintProperty() - */ - public final Paint getSelectionBorderPaint() { - return selectionBorderPaintProperty().get(); - } - - /** - * @param selectionBorderPaint - * the new {@link Paint} of the selection border - * @see #selectionBorderPaintProperty() - */ - public final void setSelectionBorderPaint(Paint selectionBorderPaint) { - selectionBorderPaintProperty().set(selectionBorderPaint); - } - - /** - * Determines the width of the selection's border. The border is always painted to the outside of the selected area, - * i.e. the selected area is never covered by the border. - * - * @defaultValue 2.5 - * @return the property defining the selection border's width - * @see #selectionBorderPaintProperty() - * @see javafx.scene.shape.Shape#strokeWidthProperty() Shape.strokeWidthProperty() - */ - public final DoubleProperty selectionBorderWidthProperty() { - return selectionBorderWidth; - } - - /** - * @return the selection border width - * @see #selectionBorderWidthProperty() - */ - public final double getSelectionBorderWidth() { - return selectionBorderWidthProperty().get(); - } - - /** - * @param selectionBorderWidth - * the selection border width to set - * @see #selectionBorderWidthProperty() - */ - public final void setSelectionBorderWidth(double selectionBorderWidth) { - selectionBorderWidthProperty().set(selectionBorderWidth); - } - - /** - * Determines the visualization of the selected area. - * - * @defaultValue {@link Color#TRANSPARENT} - * @return the property holding the {@link Paint} of the selected area - */ - public final ObjectProperty<Paint> selectionAreaFillProperty() { - return selectionAreaFill; - } - - /** - * @return the {@link Paint} of the selected area - * @see #selectionAreaFillProperty() - */ - public final Paint getSelectionAreaFill() { - return selectionAreaFillProperty().get(); - } - - /** - * @param selectionAreaFill - * the new {@link Paint} of the selected area - * @see #selectionAreaFillProperty() - */ - public final void setSelectionAreaFill(Paint selectionAreaFill) { - selectionAreaFillProperty().set(selectionAreaFill); - } - - /** - * Determines the visualization of the area outside of the selection. - * - * @defaultValue {@link Color#BLACK black} with {@link Color#getOpacity() opacity} 0.5 - * @return the property holding the {@link Paint} of the area outside of the selection - */ - public final ObjectProperty<Paint> unselectedAreaFillProperty() { - return unselectedAreaFill; - } - - /** - * @return the {@link Paint} of the area outside of the selection - * @see #unselectedAreaFillProperty() - */ - public final Paint getUnselectedAreaFill() { - return unselectedAreaFillProperty().get(); - } - - /** - * @param unselectedAreaFill - * the new {@link Paint} of the area outside of the selection - * @see #unselectedAreaFillProperty() - */ - public final void setUnselectedAreaFill(Paint unselectedAreaFill) { - unselectedAreaFillProperty().set(unselectedAreaFill); - } - - /* ************************************************************************ - * * - * Inner Classes * - * * - **************************************************************************/ - - /** - * The {@link SnapshotView#selectionAreaBoundaryProperty() selectionArea}, in which the user can create a selection, - * and the {@link SnapshotView#unselectedAreaBoundaryProperty() unselectedArea}, in which the unselected area is - * visualized, are limited to a certain area of the control. This area's boundary is represented by this enum. - * - */ - public static enum Boundary { - - /** - * The boundary is this control's bound. - */ - CONTROL, - - /** - * The boundary is the displayed node's bound. - */ - NODE, - - } - - /** - * Updates the size of the {@link SnapshotView#selectionProperty() selection} whenever necessary. This is the case - * if the {@link SnapshotView#selectionAreaBoundaryProperty() selectionAreaBoundary} is set to - * {@link Boundary#CONTROL CONTROL} and the control is resized or when it is set to {@link Boundary#NODE NODE} and - * the node is changed or resized. - * - */ - private class SelectionSizeUpdater { - - /* - * If the 'selectionAreaBoundary' is set to 'CONTROL', the selection is only updated when the control changes - * its width or height. If it is set to 'NODE', the selection is resized whenever the node or its - * 'boundsInParent' change. - * For both cases methods exist which resize the selection. The listeners which call those methods are only - * added to the corresponding properties when the matching boundary is selected. - */ - - // CONTROL - - /** - * Calls {@link #resizeSelectionToNewControlWidth(ObservableValue, Number, Number) - * updateSelectionToNewControlWidth} whenever the control's width changes. - */ - private final ChangeListener<Number> resizeSelectionToNewControlWidthListener; - - /** - * Calls {@link #resizeSelectionToNewControlHeight(ObservableValue, Number, Number) - * updateSelectionToNewControlWidth} whenever the control's height changes. - */ - private final ChangeListener<Number> resizeSelectionToNewControlHeightListener; - - // NODE - - /** - * Calls {@link #updateSelectionToNewNode(ObservableValue, Node, Node) updateSelectionToNewNode} whenever a new - * {@link SnapshotView#nodeProperty() node} is set. - */ - private final ChangeListener<Node> updateSelectionToNodeListener; - - /** - * Calls {@link #resizeSelectionToNewNodeBounds(ObservableValue, Bounds, Bounds) updateSelectionToNewNodeBounds} - * whenever the node's {@link Node#boundsInParentProperty() boundsInParent} change. - */ - private final ChangeListener<Bounds> resizeSelectionToNewNodeBoundsListener; - - // CONSTRUCTION - - /** - * Creates a new selection size updater. - */ - public SelectionSizeUpdater() { - // create listeners which point to methods - resizeSelectionToNewControlWidthListener = this::resizeSelectionToNewControlWidth; - resizeSelectionToNewControlHeightListener = this::resizeSelectionToNewControlHeight; - updateSelectionToNodeListener = this::updateSelectionToNewNode; - resizeSelectionToNewNodeBoundsListener = this::resizeSelectionToNewNodeBounds; - } - - // ENABLE RESIZING - - /** - * Enables resizing of the control. - */ - public void enableResizing() { - // only resize if the selection is not null - enableResizingForBoundary(getSelectionAreaBoundary()); - selectionAreaBoundary.addListener((o, oldBoundary, newBoundary) -> enableResizingForBoundary(newBoundary)); - } - - /** - * Enables resizing for the specified boundary. - * - * @param boundary - * the {@link Boundary} for which the control will be resized. - */ - private void enableResizingForBoundary(Boundary boundary) { - switch (boundary) { - case CONTROL: - enableResizingForControl(); - break; - case NODE: - enableResizingForNode(); - break; - default: - throw new IllegalArgumentException("The boundary '" + boundary + "' is not fully implemented yet."); //$NON-NLS-1$ //$NON-NLS-2$ - } - } - - /** - * Enables resizing if the {@link SnapshotView#selectionAreaBoundary selectionAreaBoundary} is - * {@link Boundary#CONTROL CONTROL}. - */ - private void enableResizingForControl() { - // remove listeners for node and its bounds - node.removeListener(updateSelectionToNodeListener); - if (getNode() != null) { - getNode().boundsInParentProperty().removeListener(resizeSelectionToNewNodeBoundsListener); - } - - // add listener for the control's size - widthProperty().addListener(resizeSelectionToNewControlWidthListener); - heightProperty().addListener(resizeSelectionToNewControlHeightListener); - - resizeSelectionFromNodeToControl(); - } - - /** - * Enables resizing if the {@link SnapshotView#selectionAreaBoundary selectionAreaBoundary} is - * {@link Boundary#NODE NODE}. - */ - private void enableResizingForNode() { - // remove listeners for the control's size - widthProperty().removeListener(resizeSelectionToNewControlWidthListener); - heightProperty().removeListener(resizeSelectionToNewControlHeightListener); - - // add listener for the node's bounds and for new nodes - if (getNode() != null) { - getNode().boundsInParentProperty().addListener(resizeSelectionToNewNodeBoundsListener); - } - node.addListener(updateSelectionToNodeListener); - - resizeSelectionFromControlToNode(); - } - - // RESIZE TO CONTROL - - /** - * Resizes the current {@link SnapshotView#selectionProperty() selection} from the node's to the control's - * bounds. - */ - private void resizeSelectionFromNodeToControl() { - if (getNode() == null) { - setSelection(null); - } else { - // transform the selection from the control's to the node's bounds - Rectangle2D controlBounds = new Rectangle2D(0, 0, getWidth(), getHeight()); - Rectangle2D nodeBounds = Rectangles2D.fromBounds(getNode().getBoundsInParent()); - resizeSelectionToNewBounds(nodeBounds, controlBounds); - } - } - - /** - * Resizes the current {@link SnapshotView#selectionProperty() selection} from the control's specified old width - * to its specified new width. - * <p> - * Designed to be used as a lambda method reference. - * - * @param o - * the {@link ObservableValue} which changed its value - * @param oldWidth - * the control's old width - * @param newWidth - * the control's new width - */ - private void resizeSelectionToNewControlWidth( - @SuppressWarnings("unused") ObservableValue<? extends Number> o, Number oldWidth, Number newWidth) { - - Rectangle2D oldBounds = new Rectangle2D(0, 0, oldWidth.doubleValue(), getHeight()); - Rectangle2D newBounds = new Rectangle2D(0, 0, newWidth.doubleValue(), getHeight()); - resizeSelectionToNewBounds(oldBounds, newBounds); - } - - /** - * Resizes the current {@link SnapshotView#selectionProperty() selection} from the control's specified old - * height to its specified new height. - * <p> - * Designed to be used as a lambda method reference. - * - * @param o - * the {@link ObservableValue} which changed its value - * @param oldHeight - * the control's old height - * @param newHeight - * the control's new height - */ - private void resizeSelectionToNewControlHeight( - @SuppressWarnings("unused") ObservableValue<? extends Number> o, Number oldHeight, Number newHeight) { - - Rectangle2D oldBounds = new Rectangle2D(0, 0, getWidth(), oldHeight.doubleValue()); - Rectangle2D newBounds = new Rectangle2D(0, 0, getWidth(), newHeight.doubleValue()); - resizeSelectionToNewBounds(oldBounds, newBounds); - } - - // RESIZE TO NODE - - /** - * Resizes the current {@link SnapshotView#selectionProperty() selection} from the control's to the node's - * bounds - */ - private void resizeSelectionFromControlToNode() { - if (getNode() == null) { - setSelection(null); - } else { - // transform the selection from the control's to the node's bounds - Rectangle2D controlBounds = new Rectangle2D(0, 0, getWidth(), getHeight()); - Rectangle2D nodeBounds = Rectangles2D.fromBounds(getNode().getBoundsInParent()); - resizeSelectionToNewBounds(controlBounds, nodeBounds); - } - } - - /** - * Moves the {@link #resizeSelectionToNewNodeBoundsListener} from the specified old to the specified new node's - * {@link Node#boundsInParentProperty() boundsInParent} property and resizes the current - * {@link SnapshotView#selectionProperty() selection} from the old to the new node's bounds. - * <p> - * Designed to be used as a lambda method reference. - * - * @param o - * the {@link ObservableValue} which changed its value - * @param oldNode - * the old node - * @param newNode - * the new node - */ - private void updateSelectionToNewNode( - @SuppressWarnings("unused") ObservableValue<? extends Node> o, Node oldNode, Node newNode) { - - // move the bounds listener from the old to the new node - if (oldNode != null) { - oldNode.boundsInParentProperty().removeListener(resizeSelectionToNewNodeBoundsListener); - } - if (newNode != null) { - newNode.boundsInParentProperty().addListener(resizeSelectionToNewNodeBoundsListener); - } - - // update selection - if (oldNode == null || newNode == null) { - // if one of the nodes is null, set no selection - setSelection(null); - } else { - // transform the current selection - resizeSelectionToNewNodeBounds(null, oldNode.getBoundsInParent(), newNode.getBoundsInParent()); - } - } - - /** - * Resizes the current {@link SnapshotView#selectionProperty() selection} from the specified old to the - * specified new bounds of the {@link SnapshotView#nodeProperty() node}. - * - * @param o - * the {@link ObservableValue} which changed its value - * @param oldBounds - * the node's old bounds - * @param newBounds - * the node's new bounds - */ - private void resizeSelectionToNewNodeBounds( - @SuppressWarnings("unused") ObservableValue<? extends Bounds> o, Bounds oldBounds, Bounds newBounds) { - - resizeSelectionToNewBounds(Rectangles2D.fromBounds(oldBounds), Rectangles2D.fromBounds(newBounds)); - } - - // GENERAL RESIZING - - /** - * If this control {@link SnapshotView#hasSelection() has a selection} it is resized from the specified old to - * the specified new bounds. - * - * @param oldBounds - * the {@link SnapshotView#selectionProperty() selection}'s old bounds as a {@link Rectangle2D} - * @param newBounds - * the {@link SnapshotView#selectionProperty() selection}'s new bounds as a {@link Rectangle2D} - */ - private void resizeSelectionToNewBounds(Rectangle2D oldBounds, Rectangle2D newBounds) { - if (!hasSelection()) { - return; - } - - Rectangle2D newSelection = transformSelectionToNewBounds(getSelection(), oldBounds, newBounds); - if (isSelectionValid(newSelection)) { - setSelection(newSelection); - } else { - setSelection(null); - } - } - - /** - * Returns a new selection which is a transformation of the specified old selection. The transformation is such - * that the new selection's "relative position" in the specified new bounds is the same as the old selection's - * relative position in the specified old bounds. - * <p> - * Here, "relative position" is a representation of the selection where the coordinates of its upper left point - * and its width and height are expressed in a percentage of its bounds. Those percentages are the same for - * "old selection in old bounds" and "returned selection in new bounds" - * - * @param oldSelection - * the selection to be transformed as a {@link Rectangle2D} - * @param oldBounds - * the {@code oldSelection}'s old bounds as a {@link Rectangle2D} - * @param newBounds - * the {@code oldSelection}'s new bounds as a {@link Rectangle2D} - * @return s {@link Rectangle2D} which is the transformation of the old selection to the new bounds - */ - private Rectangle2D transformSelectionToNewBounds( - Rectangle2D oldSelection, Rectangle2D oldBounds, Rectangle2D newBounds) { - - Point2D newSelectionCenter = computeNewSelectionCenter(oldSelection, oldBounds, newBounds); - - double widthRatio = newBounds.getWidth() / oldBounds.getWidth(); - double heightRatio = newBounds.getHeight() / oldBounds.getHeight(); - - if (isSelectionRatioFixed()) { - double newArea = (oldSelection.getWidth() * widthRatio) * (oldSelection.getHeight() * heightRatio); - double ratio = getFixedSelectionRatio(); - return Rectangles2D.forCenterAndAreaAndRatioWithinBounds(newSelectionCenter, newArea, ratio, newBounds); - } else { - double newWidth = oldSelection.getWidth() * widthRatio; - double newHeight = oldSelection.getHeight() * heightRatio; - return Rectangles2D.forCenterAndSize(newSelectionCenter, newWidth, newHeight); - } - } - - /** - * Computes a point with the same relative position in the specified new bounds as the specified old selection's - * center point in the specified old bounds. (See - * {@link #transformSelectionToNewBounds(Rectangle2D, Rectangle2D, Rectangle2D) transformSelectionToNewBounds} - * for a definition of "relative position"). - * - * @param oldSelection - * the selection whose center point is the base for the returned center point as a - * {@link Rectangle2D} - * @param oldBounds - * the bounds of the old selection as a {@link Rectangle2D} - * @param newBounds - * the bounds for the new selection as a {@link Rectangle2D} - * @return a {@link Point2D} with the same relative position in the new bounds as the old selection's center - * point in the old bounds - */ - private Point2D computeNewSelectionCenter(Rectangle2D oldSelection, Rectangle2D oldBounds, Rectangle2D newBounds) { - - Point2D oldSelectionCenter = Rectangles2D.getCenterPoint(oldSelection); - Point2D oldBoundsCenter = Rectangles2D.getCenterPoint(oldBounds); - Point2D oldSelectionCenterOffset = oldSelectionCenter.subtract(oldBoundsCenter); - - double widthRatio = newBounds.getWidth() / oldBounds.getWidth(); - double heightRatio = newBounds.getHeight() / oldBounds.getHeight(); - - Point2D newSelectionCenterOffset = new Point2D( - oldSelectionCenterOffset.getX() * widthRatio, oldSelectionCenterOffset.getY() * heightRatio); - Point2D newBoundsCenter = Rectangles2D.getCenterPoint(newBounds); - Point2D newSelectionCenter = newBoundsCenter.add(newSelectionCenterOffset); - - return newSelectionCenter; - } - - } - -} diff --git a/src/org/controlsfx/control/StatusBar.java b/src/org/controlsfx/control/StatusBar.java deleted file mode 100644 index 40273de..0000000 --- a/src/org/controlsfx/control/StatusBar.java +++ /dev/null @@ -1,211 +0,0 @@ -/** - * Copyright (c) 2014, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control; - -import static impl.org.controlsfx.i18n.Localization.asKey; -import static impl.org.controlsfx.i18n.Localization.localize; - -import impl.org.controlsfx.skin.StatusBarSkin; -import javafx.beans.property.DoubleProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleDoubleProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.property.StringProperty; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.scene.Node; -import javafx.scene.control.ProgressBar; -import javafx.scene.control.Skin; - -/** - * The StatusBar control is normally placed at the bottom of a window. It is - * used to display various types of application status information. This can be - * a text message, the progress of a task, or any other kind of status (e.g. red - * / green / yellow lights). By default the status bar contains a label for - * displaying plain text and a progress bar (see {@link ProgressBar}) for long - * running tasks. Additional controls / nodes can be placed on the left and - * right sides (see {@link #getLeftItems()} and {@link #getRightItems()}). - * - * <h3>Screenshots</h3> - * The picture below shows the default appearance of the StatusBar control: - * <center><img src="statusbar.png" alt="Screenshot of StatusBar"></center> - * - * <br> - * The following picture shows the status bar reporting progress of a task: - * <center><img src="statusbar-progress.png" alt="Screenshot of StatusBar - * reporting progress of a task"></center> - * - * <br> - * The last picture shows the status bar reporting progress, along with a couple - * of extra items added to the left and right areas of the bar: - * <center><img src="statusbar-items.png" alt="Screenshot of StatusBar - * reporting progress, along with a couple of extra items"></center> - * - * <h3>Code Sample</h3> - * - * <pre> - * StatusBar statusBar = new StatusBar(); - * statusBar.getLeftItems().add(new Button("Info")); - * statusBar.setProgress(.5); - * </pre> - */ -public class StatusBar extends ControlsFXControl { - - /** - * Constructs a new status bar control. - */ - public StatusBar() { - getStyleClass().add("status-bar"); //$NON-NLS-1$ - } - - @Override - protected Skin<?> createDefaultSkin() { - return new StatusBarSkin(this); - } - - /** {@inheritDoc} */ - @Override public String getUserAgentStylesheet() { - return getUserAgentStylesheet(StatusBar.class, "statusbar.css"); - } - - private final StringProperty text = new SimpleStringProperty(this, "text", //$NON-NLS-1$ - localize(asKey("statusbar.ok"))); //$NON-NLS-1$ - - /** - * The property used for storing the text message shown by the status bar. - * - * @return the text message property - */ - public final StringProperty textProperty() { - return text; - } - - /** - * Sets the value of the {@link #textProperty()}. - * - * @param text the text shown by the label control inside the status bar - */ - public final void setText(String text) { - textProperty().set(text); - } - - /** - * Returns the value of the {@link #textProperty()}. - * - * @return the text currently shown by the status bar - */ - public final String getText() { - return textProperty().get(); - } - - private final ObjectProperty<Node> graphic = new SimpleObjectProperty<>( - this, "graphic"); //$NON-NLS-1$ - - /** - * The property used to store a graphic node that can be displayed by the - * status label inside the status bar control. - * - * @return the property used for storing a graphic node - */ - public final ObjectProperty<Node> graphicProperty() { - return graphic; - } - - /** - * Returns the value of the {@link #graphicProperty()}. - * - * @return the graphic node shown by the label inside the status bar - */ - public final Node getGraphic() { - return graphicProperty().get(); - } - - /** - * Sets the value of {@link #graphicProperty()}. - * - * @param node the graphic node shown by the label inside the status bar - */ - public final void setGraphic(Node node) { - graphicProperty().set(node); - } - - private final ObservableList<Node> leftItems = FXCollections - .observableArrayList(); - - /** - * Returns the list of items / nodes that will be shown to the left of the status label. - * - * @return the items on the left-hand side of the status bar - */ - public final ObservableList<Node> getLeftItems() { - return leftItems; - } - - private final ObservableList<Node> rightItems = FXCollections - .observableArrayList(); - - /** - * Returns the list of items / nodes that will be shown to the right of the status label. - * - * @return the items on the left-hand side of the status bar - */ - public final ObservableList<Node> getRightItems() { - return rightItems; - } - - private final DoubleProperty progress = new SimpleDoubleProperty(this, - "progress"); //$NON-NLS-1$ - - /** - * The property used to store the progress, a value between 0 and 1. A negative - * value causes the progress bar to show an indeterminate state. - * - * @return the property used to store the progress of a task - */ - public final DoubleProperty progressProperty() { - return progress; - } - - /** - * Sets the value of the {@link #progressProperty()}. - * - * @param progress the new progress value - */ - public final void setProgress(double progress) { - progressProperty().set(progress); - } - - /** - * Returns the value of {@link #progressProperty()}. - * - * @return the current progress value - */ - public final double getProgress() { - return progressProperty().get(); - } -} diff --git a/src/org/controlsfx/control/TaskProgressView.java b/src/org/controlsfx/control/TaskProgressView.java deleted file mode 100644 index 839d4ce..0000000 --- a/src/org/controlsfx/control/TaskProgressView.java +++ /dev/null @@ -1,158 +0,0 @@ -/** - * Copyright (c) 2014, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control; - -import impl.org.controlsfx.skin.TaskProgressViewSkin; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.collections.FXCollections; -import javafx.collections.ListChangeListener; -import javafx.collections.ObservableList; -import javafx.concurrent.Task; -import javafx.concurrent.WorkerStateEvent; -import javafx.event.EventHandler; -import javafx.scene.Node; -import javafx.scene.control.Skin; -import javafx.util.Callback; - -/** - * The task progress view is used to visualize the progress of long running - * tasks. These tasks are created via the {@link Task} class. This view - * manages a list of such tasks and displays each one of them with their - * name, progress, and update messages.<p> - * An optional graphic factory can be set to place a graphic in each row. - * This allows the user to more easily distinguish between different types - * of tasks. - * - * <h3>Screenshots</h3> - * The picture below shows the default appearance of the task progress view - * control: - * <center><img src="task-monitor.png" alt="Screenshot of TaskProgressView"></center> - * - * <h3>Code Sample</h3> - * <pre> - * TaskProgressView<MyTask> view = new TaskProgressView<>(); - * view.setGraphicFactory(task -> return new ImageView("db-access.png")); - * view.getTasks().add(new MyTask()); - * </pre> - */ -public class TaskProgressView<T extends Task<?>> extends ControlsFXControl { - - /** - * Constructs a new task progress view. - */ - public TaskProgressView() { - getStyleClass().add("task-progress-view"); - - EventHandler<WorkerStateEvent> taskHandler = evt -> { - if (evt.getEventType().equals( - WorkerStateEvent.WORKER_STATE_SUCCEEDED) - || evt.getEventType().equals( - WorkerStateEvent.WORKER_STATE_CANCELLED) - || evt.getEventType().equals( - WorkerStateEvent.WORKER_STATE_FAILED)) { - getTasks().remove(evt.getSource()); - } - }; - - getTasks().addListener(new ListChangeListener<Task<?>>() { - @Override - public void onChanged(Change<? extends Task<?>> c) { - while (c.next()) { - if (c.wasAdded()) { - for (Task<?> task : c.getAddedSubList()) { - task.addEventHandler(WorkerStateEvent.ANY, - taskHandler); - } - } else if (c.wasRemoved()) { - for (Task<?> task : c.getRemoved()) { - task.removeEventHandler(WorkerStateEvent.ANY, - taskHandler); - } - } - } - } - }); - } - - /** {@inheritDoc} */ - @Override public String getUserAgentStylesheet() { - return getUserAgentStylesheet(TaskProgressView.class, "taskprogressview.css"); - } - - @Override - protected Skin<?> createDefaultSkin() { - return new TaskProgressViewSkin<>(this); - } - - private final ObservableList<T> tasks = FXCollections - .observableArrayList(); - - /** - * Returns the list of tasks currently monitored by this view. - * - * @return the monitored tasks - */ - public final ObservableList<T> getTasks() { - return tasks; - } - - private ObjectProperty<Callback<T, Node>> graphicFactory; - - /** - * Returns the property used to store an optional callback for creating - * custom graphics for each task. - * - * @return the graphic factory property - */ - public final ObjectProperty<Callback<T, Node>> graphicFactoryProperty() { - if (graphicFactory == null) { - graphicFactory = new SimpleObjectProperty<Callback<T, Node>>( - this, "graphicFactory"); - } - - return graphicFactory; - } - - /** - * Returns the value of {@link #graphicFactoryProperty()}. - * - * @return the optional graphic factory - */ - public final Callback<T, Node> getGraphicFactory() { - return graphicFactory == null ? null : graphicFactory.get(); - } - - /** - * Sets the value of {@link #graphicFactoryProperty()}. - * - * @param factory an optional graphic factory - */ - public final void setGraphicFactory(Callback<T, Node> factory) { - graphicFactoryProperty().set(factory); - } -} diff --git a/src/org/controlsfx/control/ToggleSwitch.java b/src/org/controlsfx/control/ToggleSwitch.java deleted file mode 100644 index d380ead..0000000 --- a/src/org/controlsfx/control/ToggleSwitch.java +++ /dev/null @@ -1,171 +0,0 @@ -/** - * Copyright (c) 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.controlsfx.control; - -import impl.org.controlsfx.skin.ToggleSwitchSkin; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.BooleanPropertyBase; -import javafx.css.PseudoClass; -import javafx.event.ActionEvent; -import javafx.scene.control.Labeled; -import javafx.scene.control.Skin; - -/** - * Much like a Toggle Button this control allows the user to toggle between one of two states. It has been popularized - * in touch based devices where its usage is particularly useful because unlike a checkbox the finger touch of a user - * doesn't obscure the control. - * - * <p> Shown below is a screenshot of the ToggleSwitch control in its on and off state: - * <br> - * <center> - * <img src="ToggleSwitch.png" alt="Screenshot of ToggleSwitch"> - * </center> - */ -public class ToggleSwitch extends Labeled -{ - - /*************************************************************************** - * * - * Constructors * - * * - **************************************************************************/ - - /** - * Creates a toggle switch with empty string for its label. - */ - public ToggleSwitch() { - initialize(); - } - - /** - * Creates a toggle switch with the specified label. - * - * @param text The label string of the control. - */ - public ToggleSwitch(String text) { - super(text); - initialize(); - } - - private void initialize() { - getStyleClass().setAll(DEFAULT_STYLE_CLASS); - } - - /*************************************************************************** - * * - * Properties * - * * - **************************************************************************/ - - /** - * Indicates whether this ToggleSwitch is selected. - */ - private BooleanProperty selected; - - /** - * Sets the selected value of this Toggle Switch - */ - public final void setSelected(boolean value) { - selectedProperty().set(value); - } - - /** - * Returns whether this Toggle Switch is selected - */ - public final boolean isSelected() { - return selected == null ? false : selected.get(); - } - - /** - * Returns the selected property - */ - public final BooleanProperty selectedProperty() { - if (selected == null) { - selected = new BooleanPropertyBase() { - @Override protected void invalidated() { - final Boolean v = get(); - pseudoClassStateChanged(PSEUDO_CLASS_SELECTED, v); -// accSendNotification(Attribute.SELECTED); - } - - @Override - public Object getBean() { - return ToggleSwitch.this; - } - - @Override - public String getName() { - return "selected"; - } - }; - } - return selected; - } - - - /*************************************************************************** - * * - * Methods * - * * - **************************************************************************/ - - /** - * Toggles the state of the {@code ToggleSwitch}. The {@code ToggleSwitch} will cycle through - * the selected and unselected states. - */ - public void fire() { - if (!isDisabled()) { - setSelected(!isSelected()); - fireEvent(new ActionEvent()); - } - } - - /** {@inheritDoc} */ - @Override protected Skin<?> createDefaultSkin() { - return new ToggleSwitchSkin(this); - } - - - /*************************************************************************** - * * - * Stylesheet Handling * - * * - **************************************************************************/ - - private static final String DEFAULT_STYLE_CLASS = "toggle-switch"; - - private static final PseudoClass PSEUDO_CLASS_SELECTED = - PseudoClass.getPseudoClass("selected"); - - /** {@inheritDoc} */ - @Override - public String getUserAgentStylesheet() { - return ToggleSwitch.class.getResource("toggleswitch.css").toExternalForm(); - } - -} diff --git a/src/org/controlsfx/control/action/Action.java b/src/org/controlsfx/control/action/Action.java deleted file mode 100644 index 04d8439..0000000 --- a/src/org/controlsfx/control/action/Action.java +++ /dev/null @@ -1,430 +0,0 @@ -/** - * Copyright (c) 2013, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.action; - -import impl.org.controlsfx.i18n.Localization; -import impl.org.controlsfx.i18n.SimpleLocalizedStringProperty; - -import java.util.function.Consumer; - -import javafx.beans.NamedArg; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.property.StringProperty; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.collections.ObservableMap; -import javafx.event.ActionEvent; -import javafx.event.EventHandler; -import javafx.scene.Node; -import javafx.scene.control.Button; -import javafx.scene.control.Menu; -import javafx.scene.control.MenuItem; -import javafx.scene.input.KeyCombination; - -/** - * A base class for Action API. - * - * <h3>What is an Action?</h3> - * An action in JavaFX can be used to separate functionality and state from a - * control. For example, if you have two or more controls that perform the same - * function (e.g. one in a {@link Menu} and another on a toolbar), consider - * using an Action object to implement the function. An Action object provides - * centralized handling of the state of action-event-firing components such as - * buttons, menu items, etc. The state that an action can handle includes text, - * graphic, long text (i.e. tooltip text), and disabled. - */ -public class Action implements EventHandler<ActionEvent> { - - /************************************************************************** - * - * Private fields - * - **************************************************************************/ - - private boolean locked = false; - - private Consumer<ActionEvent> eventHandler; - - - /************************************************************************** - * - * Constructors - * - **************************************************************************/ - - public Action(@NamedArg("text") String text) { - this(text, null); - } - - public Action(Consumer<ActionEvent> eventHandler) { - this("", eventHandler); //$NON-NLS-1$ - } - - /** - * Creates a new AbstractAction instance with the given String set as the - * {@link #textProperty() text} value, as well as the {@code Consumer<ActionEvent>} - * set to be called when the action event is fired. - * - * @param text The string to display in the text property of controls such - * as {@link Button#textProperty() Button}. - * @param eventHandler This will be called when the ActionEvent is fired. - */ - public Action(@NamedArg("text") String text, Consumer<ActionEvent> eventHandler) { - setText(text); - setEventHandler(eventHandler); - getStyleClass().add( "action" ); // this class will be added to all bound controls - } - - protected void lock() { - locked = true; - } - - - /************************************************************************** - * - * Properties - * - **************************************************************************/ - - // --- style - /** - * A string representation of the CSS style associated with this - * Action instance and passed to related UI controls. - * This is analogous to the "style" attribute of an - * HTML element. Note that, like the HTML style attribute, this - * variable contains style properties and values and not the - * selector portion of a style rule. - * <p> - * Parsing this style might not be supported on some limited - * platforms. It is recommended to use a standalone CSS file instead. - */ - private StringProperty style; - public final void setStyle(String value) { styleProperty().set(value); } - public final String getStyle() { return style == null ? "" : style.get(); } //$NON-NLS-1$ - public final StringProperty styleProperty() { - if (style == null) { - style = new SimpleStringProperty(this, "style") { //$NON-NLS-1$ - @Override - public void set(String style) { - if (locked) throw new UnsupportedOperationException("The action is immutable, property change support is disabled."); //$NON-NLS-1$ - super.set(style); - } - }; - } - return style; - } - - - // --- Style class - private final ObservableList<String> styleClass = FXCollections.observableArrayList(); - /** - * A list of String identifiers which can be used to logically group - * Nodes, specifically for an external style engine. This variable is - * analogous to the "class" attribute on an HTML element and, as such, - * each element of the list is a style class to which this Node belongs. - * - * @see <a href="http://www.w3.org/TR/css3-selectors/#class-html">CSS3 class selectors</a> - */ - public ObservableList<String> getStyleClass() { - return styleClass; - } - - - // --- selected - private final BooleanProperty selectedProperty = new SimpleBooleanProperty(this, "selected") { //$NON-NLS-1$ - @Override public void set(boolean selected) { - if (locked) throw new UnsupportedOperationException("The action is immutable, property change support is disabled."); //$NON-NLS-1$ - super.set(selected); - } - }; - - /** - * Represents action's selected state. - * Usually bound to selected state of components such as Toggle Buttons, CheckBOxes etc - * - * @return An observable {@link BooleanProperty} that represents the current - * selected state, and which can be observed for changes. - */ - public final BooleanProperty selectedProperty() { - return selectedProperty; - } - - /** - * Selected state of the Action. - * @return The selected state of this action. - */ - public final boolean isSelected() { - return selectedProperty.get(); - } - - /** - * Sets selected state of the Action - * @param selected - */ - public final void setSelected( boolean selected ) { - selectedProperty.set(selected); - } - - - // --- text - private final StringProperty textProperty = new SimpleLocalizedStringProperty(this, "text"){ //$NON-NLS-1$ - @Override public void set(String value) { - if ( locked ) throw new RuntimeException("The action is immutable, property change support is disabled."); //$NON-NLS-1$ - super.set(value); - } - }; - - /** - * The text to show to the user. - * - * @return An observable {@link StringProperty} that represents the current - * text for this property, and which can be observed for changes. - */ - public final StringProperty textProperty() { - return textProperty; - } - - /** - * - * @return the text of the Action. - */ - public final String getText() { - return textProperty.get(); - } - - /** - * Sets the text of the Action. - * @param value - */ - public final void setText(String value) { - textProperty.set(value); - } - - - // --- disabled - private final BooleanProperty disabledProperty = new SimpleBooleanProperty(this, "disabled"){ //$NON-NLS-1$ - @Override public void set(boolean value) { - if ( locked ) throw new RuntimeException("The action is immutable, property change support is disabled."); //$NON-NLS-1$ - super.set(value); - } - }; - - /** - * This represents whether the action should be available to the end user, - * or whether it should appeared 'grayed out'. - * - * @return An observable {@link BooleanProperty} that represents the current - * disabled state for this property, and which can be observed for - * changes. - */ - public final BooleanProperty disabledProperty() { - return disabledProperty; - } - - /** - * - * @return whether the action is available to the end user, - * or whether it should appeared 'grayed out'. - */ - public final boolean isDisabled() { - return disabledProperty.get(); - } - - /** - * Sets whether the action should be available to the end user, - * or whether it should appeared 'grayed out'. - * @param value - */ - public final void setDisabled(boolean value) { - disabledProperty.set(value); - } - - - // --- longText - private final StringProperty longTextProperty = new SimpleLocalizedStringProperty(this, "longText"){ //$NON-NLS-1$ - @Override public void set(String value) { - if ( locked ) throw new RuntimeException("The action is immutable, property change support is disabled."); //$NON-NLS-1$ - super.set(value); - - } - }; - - /** - * The longer form of the text to show to the user (e.g. on a - * {@link Button}, it is usually a tooltip that should be shown to the user - * if their mouse hovers over this action). - * - * @return An observable {@link StringProperty} that represents the current - * long text for this property, and which can be observed for changes. - */ - public final StringProperty longTextProperty() { - return longTextProperty; - } - - /** - * @see #longTextProperty() - * @return The longer form of the text to show to the user - */ - public final String getLongText() { - return Localization.localize(longTextProperty.get()); - } - - /** - * Sets the longer form of the text to show to the user - * @param value - * @see #longTextProperty() - */ - public final void setLongText(String value) { - longTextProperty.set(value); - } - - - // --- graphic - private final ObjectProperty<Node> graphicProperty = new SimpleObjectProperty<Node>(this, "graphic"){ //$NON-NLS-1$ - @Override public void set(Node value) { - if ( locked ) throw new RuntimeException("The action is immutable, property change support is disabled."); //$NON-NLS-1$ - super.set(value); - - } - }; - - /** - * The graphic that should be shown to the user in relation to this action. - * - * @return An observable {@link ObjectProperty} that represents the current - * graphic for this property, and which can be observed for changes. - */ - public final ObjectProperty<Node> graphicProperty() { - return graphicProperty; - } - - /** - * - * @return The graphic that should be shown to the user in relation to this action. - */ - public final Node getGraphic() { - return graphicProperty.get(); - } - - /** - * Sets the graphic that should be shown to the user in relation to this action. - * @param value - */ - public final void setGraphic(Node value) { - graphicProperty.set(value); - } - - - // --- accelerator - private final ObjectProperty<KeyCombination> acceleratorProperty = new SimpleObjectProperty<KeyCombination>(this, "accelerator"){ //$NON-NLS-1$ - @Override public void set(KeyCombination value) { - if ( locked ) throw new RuntimeException("The action is immutable, property change support is disabled."); //$NON-NLS-1$ - super.set(value); - - } - }; - - /** - * The accelerator {@link KeyCombination} that should be used for this action, - * if it is used in an applicable UI control (most notably {@link MenuItem}). - * - * @return An observable {@link ObjectProperty} that represents the current - * accelerator for this property, and which can be observed for changes. - */ - public final ObjectProperty<KeyCombination> acceleratorProperty() { - return acceleratorProperty; - } - - /** - * - * @return The accelerator {@link KeyCombination} that should be used for this action, - * if it is used in an applicable UI control - */ - public final KeyCombination getAccelerator() { - return acceleratorProperty.get(); - } - - /** - * Sets the accelerator {@link KeyCombination} that should be used for this action, - * if it is used in an applicable UI control - * @param value - */ - public final void setAccelerator(KeyCombination value) { - acceleratorProperty.set(value); - } - - - // --- properties - private ObservableMap<Object, Object> props; - - /** - * Returns an observable map of properties on this Action for use primarily - * by application developers. - * - * @return An observable map of properties on this Action for use primarily - * by application developers - */ - public final synchronized ObservableMap<Object, Object> getProperties() { - if ( props == null ) props = FXCollections.observableHashMap(); - return props; - } - - protected Consumer<ActionEvent> getEventHandler() { - return eventHandler; - } - - protected void setEventHandler(Consumer<ActionEvent> eventHandler) { - this.eventHandler = eventHandler; - } - - /************************************************************************** - * - * Public API - * - **************************************************************************/ - - /** - * Defers to the {@code Consumer<ActionEvent>} passed in to the Action constructor. - */ - @Override public final void handle(ActionEvent event) { - if (eventHandler != null && !isDisabled()) { - eventHandler.accept(event); - } - } - -// public void bind(ButtonBase button) { -// ActionUtils.configureButton(this, button); -// } -// -// public void bind(MenuItem menuItem) { -// ActionUtils.configureMenuItem(this, menuItem); -// } -} \ No newline at end of file diff --git a/src/org/controlsfx/control/action/ActionCheck.java b/src/org/controlsfx/control/action/ActionCheck.java deleted file mode 100644 index b59ed06..0000000 --- a/src/org/controlsfx/control/action/ActionCheck.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.controlsfx.control.action; - -import javafx.scene.control.Button; -import javafx.scene.control.CheckMenuItem; -import javafx.scene.control.MenuItem; -import javafx.scene.control.ToggleButton; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Marks the {@link Action} or a method annotated with {@link ActionProxy} to let action engine know - * that {@link ToggleButton} or {@link CheckMenuItem} has to be bound to the action - * instead of standard {@link Button} and {@link MenuItem} - */ -@Target( { ElementType.TYPE, ElementType.METHOD } ) -@Retention(RetentionPolicy.RUNTIME) -public @interface ActionCheck { -} diff --git a/src/org/controlsfx/control/action/ActionGroup.java b/src/org/controlsfx/control/action/ActionGroup.java deleted file mode 100644 index 06ab1f0..0000000 --- a/src/org/controlsfx/control/action/ActionGroup.java +++ /dev/null @@ -1,167 +0,0 @@ -/** - * Copyright (c) 2013, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.action; - -import java.util.Arrays; -import java.util.Collection; - -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.scene.Node; -import javafx.scene.control.ContextMenu; -import javafx.scene.control.MenuBar; -import javafx.scene.control.ToolBar; - -/** - * An ActionGroup (unsurprisingly) groups together zero or more {@link Action} - * instances, allowing for more complex controls like {@link ToolBar}, - * {@link MenuBar} and {@link ContextMenu} to be automatically generated from - * the collection of actions inside the ActionGroup. For your convenience, - * there are a number of utility methods that do precisely this in the - * {@link ActionUtils} class. - * - * <h3>Code Examples</h3> - * <p>Consider the following code example (note that DummyAction is a fake class - * that extends from (and implements) {@link Action}): - * - * <pre> - * {@code - * // Firstly, create a list of Actions - * Collection<? extends Action> actions = Arrays.asList( - * new ActionGroup("Group 1", new DummyAction("Action 1.1"), - * new DummyAction("Action 2.1") ), - * new ActionGroup("Group 2", new DummyAction("Action 2.1"), - * new ActionGroup("Action 2.2", new DummyAction("Action 2.2.1"), - * new DummyAction("Action 2.2.2")), - * new DummyAction("Action 2.3") ), - * new ActionGroup("Group 3", new DummyAction("Action 3.1"), - * new DummyAction("Action 3.2") ) - * ); - * - * // Use the ActionUtils class to create UI controls from these actions, e.g: - * MenuBar menuBar = ActionUtils.createMenuBar(actions); - * - * ToolBar toolBar = ActionUtils.createToolBar(actions); - * - * Label context = new Label("Right-click to see the context menu"); - * context.setContextMenu(ActionUtils.createContextMenu(actions)); - * }</pre> - * - * <p>The end result of running the code above is shown in the screenshots below - * (hopefully it goes without saying that within the 'Group 1', 'Group 2' and - * 'Group 3' options are the 'Action 1.1', etc actions that have been specified - * in the code above): - * - * <table border="0" summary="ActionGroup Screenshots"> - * <tr> - * <td width="75" valign="center"><strong>MenuBar:</strong></td> - * <td><img src="actionGroup-menubar.png" alt="Screenshot of ActionGroup in a MenuBar"></td> - * </tr> - * <tr> - * <td width="75" valign="center"><strong>ToolBar:</strong></td> - * <td><img src="actionGroup-toolbar.png" alt="Screenshot of ActionGroup in a ToolBar"></td> - * </tr> - * <tr> - * <td width="75" valign="top"><strong>ContextMenu:</strong></td> - * <td><img src="actionGroup-contextmenu.png" alt="Screenshot of ActionGroup in a ContextMenu"></td> - * </tr> - * </table> - * - * @see Action - * @see ActionUtils - */ -public class ActionGroup extends Action { - - /** - * Creates an ActionGroup with the given text as the name of the {@link Action}, - * and zero or more Actions as members of this ActionGroup. Note that it is - * legitimate to pass in zero Actions to this constructor, and to later - * set the actions directly into the {@link #getActions() actions} list. - * - * @param text The {@link Action#textProperty() text} of this {@link Action}. - * @param actions Zero or more actions to insert into this ActionGroup. - */ - public ActionGroup(String text, Action... actions) { - this(text, Arrays.asList(actions)); - } - - /** - * Creates an ActionGroup with the given text as the name of the {@link Action}, - * and collection of Actions as members of this ActionGroup. - * - * @param text The {@link Action#textProperty() text} of this {@link Action}. - * @param actions Collection of actions to insert into this ActionGroup. - */ - public ActionGroup(String text, Collection<Action> actions) { - super(text); - getActions().addAll(actions); - } - - /** - * Creates an ActionGroup with the given text as the name of the {@link Action}, - * and zero or more Actions as members of this ActionGroup. Note that it is - * legitimate to pass in zero Actions to this constructor, and to later - * set the actions directly into the {@link #getActions() actions} list. - * - * @param text The {@link Action#textProperty() text} of this {@link Action}. - * @param icon The {@link Action#graphicProperty() image} of this {@link Action}. - * @param actions Zero or more actions to insert into this ActionGroup. - */ - public ActionGroup(String text, Node icon, Action... actions) { - this( text, icon, Arrays.asList(actions)); - } - - /** - * Creates an ActionGroup with the given text as the name of the {@link Action}, - * and collection of Actions as members of this ActionGroup. . - * - * @param text The {@link Action#textProperty() text} of this {@link Action}. - * @param icon The {@link Action#graphicProperty() image} of this {@link Action}. - * @param actions Collection of actions to insert into this ActionGroup. - */ - public ActionGroup(String text, Node icon, Collection<Action> actions) { - super(text); - setGraphic(icon); - getActions().addAll(actions); - } - - // --- actions - private final ObservableList<Action> actions = FXCollections.<Action> observableArrayList(); - - /** - * The list of {@link Action} instances that exist within this ActionGroup. - * This list may be modified, as shown in the class documentation. - */ - public final ObservableList<Action> getActions() { - return actions; - } - - @Override public String toString() { - return getText(); - } - -} diff --git a/src/org/controlsfx/control/action/ActionMap.java b/src/org/controlsfx/control/action/ActionMap.java deleted file mode 100644 index a8e8380..0000000 --- a/src/org/controlsfx/control/action/ActionMap.java +++ /dev/null @@ -1,224 +0,0 @@ -/** - * Copyright (c) 2013, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.action; - -import javafx.event.ActionEvent; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.util.*; - -/** - * Action Map provides an ability to create an action map of any object. - * Attempts to convert methods annotated with {@link ActionProxy} to {@link Action}. - * - * <h3>Code Example</h3> - * Here's a very simple example of how to use ActionMap to register a class (in - * this class it is the application class itself), and to then retrieve actions - * out of the ActionMap (via the static {@link ActionMap#action(String)} method: - * <br> - * - * <pre> - * public class ActionMapDemo extends Application { - * public ActionMapDemo() { - * ActionMap.register(this); - * Action action11 = ActionMap.action("action11"); - * Button actionButton = ActionUtils.createButton(action11); - * } - * - * @ActionProxy(text="Action 1.1", graphic="start.png", accelerator="ctrl+shift+T") - * private void action11() { - * System.out.println( "Action 1.1 is executed"); - * } - * } - * </pre> - * - * If you require more control over the creation of the Action objects, you can either set the - * global ActionFactory by calling ActionMap.setActionFactory() and/or you can use the factory - * property on individual @ActionProxy declarations to set the factory on a case-by-case basis. - * - * @see ActionProxy - * @see Action - */ -public class ActionMap { - - private static AnnotatedActionFactory actionFactory = new DefaultActionFactory(); - - private static final Map<String, AnnotatedAction> actions = new HashMap<>(); - - - private ActionMap() { - // no-op - } - - - /** - * Returns the action factory used by ActionMap to construct AnnotatedAction instances. By default, this - * is an instance of {@link DefaultActionFactory}. - */ - public static AnnotatedActionFactory getActionFactory() { - return actionFactory; - } - - /** - * Sets the action factory used by ActionMap to construct AnnotatedAction instances. This factory can be overridden on - * a case-by-case basis by specifying a factory class in {@link ActionProxy#factory()} - */ - public static void setActionFactory( AnnotatedActionFactory factory ) { - Objects.requireNonNull( factory ); - actionFactory = factory; - } - - - - - /** - * Attempts to convert target's methods annotated with {@link ActionProxy} to {@link Action}s. - * Three types of methods are currently converted: parameter-less methods, - * methods with one parameter of type {@link ActionEvent}, and methods with two parameters - * ({@link ActionEvent}, {@link Action}). - * - * Note that this method supports safe re-registration of a given instance or of another instance of the - * same class that has already been registered. If another instance of the same class is registered, then - * those actions will now be associated with the new instance. The first instance is implicitly unregistered. - * - * Actions are registered with their id or method name if id is not defined. - * - * @param target object to work on - * @throws IllegalStateException if a method with unsupported parameters is annotated with {@link ActionProxy}. - */ - public static void register(Object target) { - - for (Method method : target.getClass().getDeclaredMethods()) { - // Only process methods that have the ActionProxy annotation - Annotation[] annotations = method.getAnnotationsByType(ActionProxy.class); - if (annotations.length == 0) { - continue; - } - - // Only process methods that have - // a) no parameters OR - // b) one parameter of type ActionEvent OR - // c) two parameters (ActionEvent, Action) - int paramCount = method.getParameterCount(); - Class[] paramTypes = method.getParameterTypes(); - - if (paramCount > 2) { - throw new IllegalArgumentException( String.format( "Method %s has too many parameters", method.getName() ) ); - } - - if (paramCount == 1 && !ActionEvent.class.isAssignableFrom( paramTypes[0] )) { - throw new IllegalArgumentException( String.format( "Method %s -- single parameter must be of type ActionEvent", method.getName() ) ); - } - - if (paramCount == 2 && (!ActionEvent.class.isAssignableFrom( paramTypes[0] ) || - !Action.class.isAssignableFrom( paramTypes[1] ))) { - throw new IllegalArgumentException( String.format( "Method %s -- parameters must be of types (ActionEvent, Action)", method.getName() ) ); - } - - ActionProxy annotation = (ActionProxy) annotations[0]; - - AnnotatedActionFactory factory = determineActionFactory( annotation ); - AnnotatedAction action = factory.createAction( annotation, method, target ); - - String id = annotation.id().isEmpty() ? method.getName() : annotation.id(); - actions.put( id, action ); - } - } - - - - - private static AnnotatedActionFactory determineActionFactory( ActionProxy annotation ) { - // Default to using the global action factory - AnnotatedActionFactory factory = actionFactory; - - // If an action-factory has been specified on this specific ActionProxy, then - // instantiate it and use it instead. - String factoryClassName = annotation.factory(); - if (!factoryClassName.isEmpty()) { - try { - Class factoryClass = Class.forName( factoryClassName ); - factory = (AnnotatedActionFactory) factoryClass.newInstance(); - - } catch (ClassNotFoundException ex) { - throw new IllegalArgumentException( String.format( "Action proxy refers to non-existant factory class %s", factoryClassName ), ex ); - - } catch (InstantiationException | IllegalAccessException ex) { - throw new IllegalStateException( String.format( "Unable to instantiate action factory class %s", factoryClassName ), ex ); - } - } - - return factory; - } - - - /** - * Removes all the actions associated with target object from the action map. - * @param target object to work on - */ - public static void unregister(Object target) { - if ( target != null ) { - Iterator<Map.Entry<String, AnnotatedAction>> entryIter = actions.entrySet().iterator(); - while (entryIter.hasNext()) { - Map.Entry<String, AnnotatedAction> entry = entryIter.next(); - - Object actionTarget = entry.getValue().getTarget(); - - if (actionTarget == null || actionTarget == target) { - entryIter.remove(); - } - } - } - } - - /** - * Returns action by its id. - * @param id action id - * @return action or null if id was not found - */ - public static Action action(String id) { - return actions.get(id); - } - - /** - * Returns collection of actions by ids. Useful to create {@link ActionGroup}s. - * Ids starting with "---" are converted to {@link ActionUtils#ACTION_SEPARATOR}. - * Incorrect ids are ignored. - * @param ids action ids - * @return collection of actions - */ - public static Collection<Action> actions(String... ids) { - List<Action> result = new ArrayList<>(); - for( String id: ids ) { - if ( id.startsWith("---")) result.add(ActionUtils.ACTION_SEPARATOR); //$NON-NLS-1$ - Action action = action(id); - if ( action != null ) result.add(action); - } - return result; - } -} diff --git a/src/org/controlsfx/control/action/ActionProxy.java b/src/org/controlsfx/control/action/ActionProxy.java deleted file mode 100644 index 30f9064..0000000 --- a/src/org/controlsfx/control/action/ActionProxy.java +++ /dev/null @@ -1,138 +0,0 @@ -/** - * Copyright (c) 2013, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.action; - -import javafx.event.ActionEvent; -import org.controlsfx.glyphfont.Glyph; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * An annotation to allow conversion of class methods to {@link Action} instances. - * - * <p>The following steps are required to use {@link ActionProxy} annotations: - * - * <ol> - * <li>Annotate your methods with the {@link ActionProxy} annotation. For example: - * <pre>{@code @ActionProxy(text="Action 1.1", graphic=imagePath, accelerator="ctrl+shift+T") - * private void action11() { - * System.out.println("Action 1.1 is executed"); - * }}</pre> - * - * <p>The ActionProxy annotation is designed to work with three types of methods: - * <ol> - * <li>Methods with no parameters, - * <li>Methods with one parameter of type {@link ActionEvent}. - * <li>Methods that take both an {@link ActionEvent} and an {@link Action}. - * </ol> - * - * <p>The ActionProxy annotation {@link #graphic()} property supports different node types: - * <ol> - * <li>Images, - * <li>Glyph fonts. - * </ol> - * - * <p>The ability for ActionProxy to support glyph fonts is part of the ControlsFX - * {@link Glyph} API. For more information on how to specify - * images and glyph fonts, refer to the {@link ActionProxy#graphic()} method. - * <br><br></li> - * - * <li>Register your class in the global {@link ActionMap}, preferably in the - * class constructor: - * <pre>{@code ActionMap.register(this); }</pre> - * - * Immediately after that actions will be created according to the provided - * annotations and are accessible from {@link ActionMap}, which provides several - * convenience methods to access actions by id. Refer to the {@link ActionMap} - * class for more details on how to use it.</li> - * - * <p>{@link ActionCheck} annotation is supported on the same method where @ActionProxy is applied}</p> - * </ol> - * - * @see Action - * @see ActionMap - */ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface ActionProxy { - - /** - * By default the method name that this annotation is applied to, but if not - * null then this ID is what you use when requesting the {@link Action} out - * of the {@link ActionMap} when using the {@link ActionMap#action(String)} - * method. - */ - String id() default ""; - - /** - * The text that should be set in {@link Action#textProperty()}. - */ - String text(); - - /** - * The graphic that should be set in {@link Action#graphicProperty()}. - * - * <p>The graphic can be either image (local path or url) or font glyph. - * - * <p>Because a graphic can come from multiple sources, a simple protocol - * prefix is used to designate the type. Currently supported prefixes are - * '<code>image></code>' and '<code>font></code>'. Default protocol is - * '<code>image></code>'. - * - * <p>The following are the examples of different graphic nodes: - * <pre> - * @ActionProxy(text="Teacher", graphic="http://icons.iconarchive.com/icons/custom-icon-design/mini-3/16/teacher-male-icon.png") - * @ActionProxy(text="Security", graphic="/org/controlsfx/samples/security-low.png") - * @ActionProxy(text="Security", graphic="image>/org/controlsfx/samples/security-low.png") - * @ActionProxy(text="Star", graphic="font>FontAwesome|STAR") - * </pre> - * - */ - String graphic() default ""; - - /** - * The text that should be set in {@link Action#longTextProperty()}. - */ - String longText() default ""; - - /** - * Accepts string values such as "ctrl+shift+T" to represent the keyboard - * shortcut for this action. By default this is empty if there is no keyboard - * shortcut desired for this action. - */ - String accelerator() default ""; - - /** - * The full class-name of a class that implements {@link AnnotatedActionFactory}. {@link ActionMap} will - * use this class to instantiate the {@link AnnotatedAction} associated with this method, rather than - * using its own action factory. - */ - String factory() default ""; -} diff --git a/src/org/controlsfx/control/action/ActionUtils.java b/src/org/controlsfx/control/action/ActionUtils.java deleted file mode 100644 index d7169dc..0000000 --- a/src/org/controlsfx/control/action/ActionUtils.java +++ /dev/null @@ -1,890 +0,0 @@ -/** - * Copyright (c) 2013, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.action; - -import javafx.beans.InvalidationListener; -import javafx.beans.binding.ObjectBinding; -import javafx.beans.binding.StringBinding; -import javafx.beans.binding.When; -import javafx.collections.FXCollections; -import javafx.collections.ListChangeListener; -import javafx.collections.MapChangeListener; -import javafx.collections.ObservableList; -import javafx.css.Styleable; -import javafx.scene.Node; -import javafx.scene.control.*; -import javafx.scene.image.ImageView; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Pane; -import javafx.scene.layout.Priority; -import javafx.scene.layout.VBox; -import org.controlsfx.control.SegmentedButton; -import org.controlsfx.tools.Duplicatable; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; - -/** - * Convenience class for users of the {@link Action} API. Primarily this class - * is used to conveniently create UI controls from a given Action (this is - * necessary for now as there is no built-in support for Action in JavaFX - * UI controls at present). - * - * <p>Some of the methods in this class take a {@link Collection} of - * {@link Action actions}. In these cases, it is likely they are designed to - * work with {@link ActionGroup action groups}. For examples on how to work with - * these methods, refer to the {@link ActionGroup} class documentation. - * - * @see Action - * @see ActionGroup - */ -@SuppressWarnings("deprecation") -public class ActionUtils { - - /*************************************************************************** - * * - * Constructors * - * * - **************************************************************************/ - - private ActionUtils() { - // no-op - } - - /*************************************************************************** - * * - * Action API * - * * - **************************************************************************/ - - /** - * Action text behavior. - * Defines uniform action's text behavior for multi-action controls such as toolbars and menus - */ - public enum ActionTextBehavior { - /** - * Text is shown as usual on related control - */ - SHOW, - - /** - * Text is not shown on the related control - */ - HIDE, - } - - - /** - * Takes the provided {@link Action} and returns a {@link Button} instance - * with all relevant properties bound to the properties of the Action. - * - * @param action The {@link Action} that the {@link Button} should bind to. - * @param textBehavior Defines {@link ActionTextBehavior} - * @return A {@link Button} that is bound to the state of the provided - * {@link Action} - */ - public static Button createButton(final Action action, final ActionTextBehavior textBehavior) { - return configure(new Button(), action, textBehavior); - } - - /** - * Takes the provided {@link Action} and returns a {@link Button} instance - * with all relevant properties bound to the properties of the Action. - * - * @param action The {@link Action} that the {@link Button} should bind to. - * @return A {@link Button} that is bound to the state of the provided - * {@link Action} - */ - public static Button createButton(final Action action) { - return configure(new Button(), action, ActionTextBehavior.SHOW); - } - - /** - * Takes the provided {@link Action} and binds the relevant properties to - * the supplied {@link Button}. This allows for the use of Actions - * within custom Button subclasses. - * - * @param action The {@link Action} that the {@link Button} should bind to. - * @param button The {@link ButtonBase} that the {@link Action} should be bound to. - * @return The {@link ButtonBase} that was bound to the {@link Action}. - */ - public static ButtonBase configureButton(final Action action, ButtonBase button) { - return configure(button, action, ActionTextBehavior.SHOW); - } - - /** - * Removes all bindings and listeners which were added when the supplied - * {@link ButtonBase} was bound to an {@link Action} via one of the methods - * of this class. - * - * @param button a {@link ButtonBase} that was bound to an {@link Action} - */ - public static void unconfigureButton(ButtonBase button) { - unconfigure(button); - } - - /** - * Takes the provided {@link Action} and returns a {@link MenuButton} instance - * with all relevant properties bound to the properties of the Action. - * - * @param action The {@link Action} that the {@link MenuButton} should bind to. - * @param textBehavior Defines {@link ActionTextBehavior} - * @return A {@link MenuButton} that is bound to the state of the provided - * {@link Action} - */ - public static MenuButton createMenuButton(final Action action, final ActionTextBehavior textBehavior) { - return configure(new MenuButton(), action, textBehavior); - } - - /** - * Takes the provided {@link Action} and returns a {@link MenuButton} instance - * with all relevant properties bound to the properties of the Action. - * - * @param action The {@link Action} that the {@link MenuButton} should bind to. - * @return A {@link MenuButton} that is bound to the state of the provided - * {@link Action} - */ - public static MenuButton createMenuButton(final Action action) { - return configure(new MenuButton(), action, ActionTextBehavior.SHOW); - } - - /** - * Takes the provided {@link Action} and returns a {@link Hyperlink} instance - * with all relevant properties bound to the properties of the Action. - * - * @param action The {@link Action} that the {@link Hyperlink} should bind to. - * @return A {@link Hyperlink} that is bound to the state of the provided - * {@link Action} - */ - public static Hyperlink createHyperlink(final Action action) { - return configure(new Hyperlink(), action, ActionTextBehavior.SHOW); - } - - /** - * Takes the provided {@link Action} and returns a {@link ToggleButton} instance - * with all relevant properties bound to the properties of the Action. - * - * @param action The {@link Action} that the {@link ToggleButton} should bind to. - * @param textBehavior Defines {@link ActionTextBehavior} - * @return A {@link ToggleButton} that is bound to the state of the provided - * {@link Action} - */ - public static ToggleButton createToggleButton(final Action action, final ActionTextBehavior textBehavior ) { - return configure(new ToggleButton(), action, textBehavior); - } - - /** - * Takes the provided {@link Action} and returns a {@link ToggleButton} instance - * with all relevant properties bound to the properties of the Action. - * - * @param action The {@link Action} that the {@link ToggleButton} should bind to. - * @return A {@link ToggleButton} that is bound to the state of the provided - * {@link Action} - */ - public static ToggleButton createToggleButton( final Action action ) { - return createToggleButton( action, ActionTextBehavior.SHOW ); - } - - /** - * Takes the provided {@link Collection} of {@link Action} and returns a {@link SegmentedButton} instance - * with all relevant properties bound to the properties of the actions. - * - * @param actions The {@link Collection} of {@link Action} that the {@link SegmentedButton} should bind to. - * @param textBehavior Defines {@link ActionTextBehavior} - * @return A {@link SegmentedButton} that is bound to the state of the provided {@link Action}s - */ - public static SegmentedButton createSegmentedButton(final ActionTextBehavior textBehavior, Collection<? extends Action> actions) { - ObservableList<ToggleButton> buttons = FXCollections.observableArrayList(); - for( Action a: actions ) { - buttons.add( createToggleButton(a,textBehavior)); - } - return new SegmentedButton( buttons ); - } - - /** - * Takes the provided {@link Collection} of {@link Action} and returns a {@link SegmentedButton} instance - * with all relevant properties bound to the properties of the actions. - * - * @param actions The {@link Collection} of {@link Action} that the {@link SegmentedButton} should bind to. - * @return A {@link SegmentedButton} that is bound to the state of the provided {@link Action}s - */ - public static SegmentedButton createSegmentedButton(Collection<? extends Action> actions) { - return createSegmentedButton( ActionTextBehavior.SHOW, actions); - } - - /** - * Takes the provided varargs array of {@link Action} and returns a {@link SegmentedButton} instance - * with all relevant properties bound to the properties of the actions. - * - * @param actions A varargs array of {@link Action} that the {@link SegmentedButton} should bind to. - * @param textBehavior Defines {@link ActionTextBehavior} - * @return A {@link SegmentedButton} that is bound to the state of the provided {@link Action}s - */ - public static SegmentedButton createSegmentedButton(ActionTextBehavior textBehavior, Action... actions) { - return createSegmentedButton(textBehavior, Arrays.asList(actions)); - } - - /** - * Takes the provided varargs array of {@link Action} and returns a {@link SegmentedButton} instance - * with all relevant properties bound to the properties of the actions. - * - * @param actions A varargs array of {@link Action} that the {@link SegmentedButton} should bind to. - * @return A {@link SegmentedButton} that is bound to the state of the provided {@link Action}s - */ - public static SegmentedButton createSegmentedButton(Action... actions) { - return createSegmentedButton(ActionTextBehavior.SHOW, Arrays.asList(actions)); - } - - - - /** - * Takes the provided {@link Action} and returns a {@link CheckBox} instance - * with all relevant properties bound to the properties of the Action. - * - * @param action The {@link Action} that the {@link CheckBox} should bind to. - * @return A {@link CheckBox} that is bound to the state of the provided - * {@link Action} - */ - public static CheckBox createCheckBox(final Action action) { - return configure(new CheckBox(), action, ActionTextBehavior.SHOW); - } - - /** - * Takes the provided {@link Action} and returns a {@link RadioButton} instance - * with all relevant properties bound to the properties of the Action. - * - * @param action The {@link Action} that the {@link RadioButton} should bind to. - * @return A {@link RadioButton} that is bound to the state of the provided - * {@link Action} - */ - public static RadioButton createRadioButton(final Action action) { - return configure(new RadioButton(), action, ActionTextBehavior.SHOW); - } - - /** - * Takes the provided {@link Action} and returns a {@link MenuItem} instance - * with all relevant properties bound to the properties of the Action. - * - * @param action The {@link Action} that the {@link MenuItem} should bind to. - * @return A {@link MenuItem} that is bound to the state of the provided - * {@link Action} - */ - public static MenuItem createMenuItem(final Action action) { - - MenuItem menuItem = - action.getClass().isAnnotationPresent(ActionCheck.class)? new CheckMenuItem(): new MenuItem(); - - return configure( menuItem, action); - } - - public static MenuItem configureMenuItem(final Action action, MenuItem menuItem) { - return configure(menuItem, action); - } - - /** - * Removes all bindings and listeners which were added when the supplied - * {@link MenuItem} was bound to an {@link Action} via one of the methods - * of this class. - * - * @param menuItem a {@link MenuItem} that was bound to an {@link Action} - */ - public static void unconfigureMenuItem(final MenuItem menuItem) { - unconfigure(menuItem); - } - - /** - * Takes the provided {@link Action} and returns a {@link Menu} instance - * with all relevant properties bound to the properties of the Action. - * - * @param action The {@link Action} that the {@link Menu} should bind to. - * @return A {@link Menu} that is bound to the state of the provided - * {@link Action} - */ - public static Menu createMenu(final Action action) { - return configure(new Menu(), action); - } - - /** - * Takes the provided {@link Action} and returns a {@link CheckMenuItem} instance - * with all relevant properties bound to the properties of the Action. - * - * @param action The {@link Action} that the {@link CheckMenuItem} should bind to. - * @return A {@link CheckMenuItem} that is bound to the state of the provided - * {@link Action} - */ - public static CheckMenuItem createCheckMenuItem(final Action action) { - return configure(new CheckMenuItem(), action); - } - - /** - * Takes the provided {@link Action} and returns a {@link RadioMenuItem} instance - * with all relevant properties bound to the properties of the Action. - * - * @param action The {@link Action} that the {@link RadioMenuItem} should bind to. - * @return A {@link RadioMenuItem} that is bound to the state of the provided - * {@link Action} - */ - public static RadioMenuItem createRadioMenuItem(final Action action) { - return configure(new RadioMenuItem(action.textProperty().get()), action); - } - - - - /*************************************************************************** - * * - * ActionGroup API * - * * - **************************************************************************/ - - - /** - * Action representation of the generic separator. Adding this action anywhere in the - * action tree serves as indication that separator has be created in its place. - * See {@link ActionGroup} for example of action tree creation - */ - public static Action ACTION_SEPARATOR = new Action(null, null) { - @Override public String toString() { - return "Separator"; //$NON-NLS-1$ - } - }; - - public static Action ACTION_SPAN = new Action(null, null) { - @Override public String toString() { - return "Span"; //$NON-NLS-1$ - } - }; - - - - /** - * Takes the provided {@link Collection} of {@link Action} (or subclasses, - * such as {@link ActionGroup}) instances and returns a {@link ToolBar} - * populated with appropriate {@link Node nodes} bound to the provided - * {@link Action actions}. - * - * @param actions The {@link Action actions} to place on the {@link ToolBar}. - * @param textBehavior defines {@link ActionTextBehavior} - * @return A {@link ToolBar} that contains {@link Node nodes} which are bound - * to the state of the provided {@link Action} - */ - public static ToolBar createToolBar(Collection<? extends Action> actions, ActionTextBehavior textBehavior) { - return updateToolBar( new ToolBar(), actions, textBehavior ); - } - - /** - * Takes the provided {@link Collection} of {@link Action} (or subclasses, - * such as {@link ActionGroup}) instances and returns provided {@link ToolBar} - * populated with appropriate {@link Node nodes} bound to the provided - * {@link Action actions}. Previous toolbar content is removed - * - * @param toolbar The {@link ToolBar toolbar} to update - * @param actions The {@link Action actions} to place on the {@link ToolBar}. - * @param textBehavior defines {@link ActionTextBehavior} - * @return A {@link ToolBar} that contains {@link Node nodes} which are bound - * to the state of the provided {@link Action} - */ - public static ToolBar updateToolBar( ToolBar toolbar, Collection<? extends Action> actions, ActionTextBehavior textBehavior) { - toolbar.getItems().clear(); - for (Action action : actions) { - if ( action instanceof ActionGroup ) { - MenuButton menu = createMenuButton( action, textBehavior ); - menu.setFocusTraversable(false); - menu.getItems().addAll( toMenuItems( ((ActionGroup)action).getActions())); - toolbar.getItems().add(menu); - } else if ( action == ACTION_SEPARATOR ) { - toolbar.getItems().add( new Separator()); - } else if ( action == ACTION_SPAN ) { - Pane span = new Pane(); - HBox.setHgrow(span, Priority.ALWAYS); - VBox.setVgrow(span, Priority.ALWAYS); - toolbar.getItems().add(span); - } else if ( action == null ) { - //no-op - } else { - - ButtonBase button; - if ( action.getClass().getAnnotation(ActionCheck.class) != null ) { - button = createToggleButton(action, textBehavior); - } else { - button = createButton(action, textBehavior); - } - button.setFocusTraversable(false); - toolbar.getItems().add(button); - } - } - - return toolbar; - } - - /** - * Takes the provided {@link Collection} of {@link Action} (or subclasses, - * such as {@link ActionGroup}) instances and returns a {@link MenuBar} - * populated with appropriate {@link Node nodes} bound to the provided - * {@link Action actions}. - * - * @param actions The {@link Action actions} to place on the {@link MenuBar}. - * @return A {@link MenuBar} that contains {@link Node nodes} which are bound - * to the state of the provided {@link Action} - */ - public static MenuBar createMenuBar(Collection<? extends Action> actions) { - return updateMenuBar(new MenuBar(), actions); - } - - /** - * Takes the provided {@link Collection} of {@link Action} (or subclasses, - * such as {@link ActionGroup}) instances and updates a {@link MenuBar} - * populated with appropriate {@link Node nodes} bound to the provided - * {@link Action actions}. Previous MenuBar content is removed. - * - * @param menuBar The {@link MenuBar menuBar} to update - * @param actions The {@link Action actions} to place on the {@link MenuBar}. - * @return A {@link MenuBar} that contains {@link Node nodes} which are bound - * to the state of the provided {@link Action} - */ - public static MenuBar updateMenuBar( MenuBar menuBar, Collection<? extends Action> actions) { - menuBar.getMenus().clear(); - for (Action action : actions) { - - if ( action == ACTION_SEPARATOR || action == ACTION_SPAN ) continue; - - Menu menu = createMenu( action ); - - if ( action instanceof ActionGroup ) { - menu.getItems().addAll( toMenuItems( ((ActionGroup)action).getActions())); - } else if ( action == null ) { - //no-op - } - - menuBar.getMenus().add(menu); - } - - return menuBar; - } - - /** - * Takes the provided {@link Collection} of {@link Action} (or subclasses, - * such as {@link ActionGroup}) instances and returns a {@link ButtonBar} - * populated with appropriate {@link Node nodes} bound to the provided - * {@link Action actions}. - * - * @param actions The {@link Action actions} to place on the {@link ButtonBar}. - * @return A {@link ButtonBar} that contains {@link Node nodes} which are bound - * to the state of the provided {@link Action} - */ - public static ButtonBar createButtonBar(Collection<? extends Action> actions) { - return updateButtonBar( new ButtonBar(), actions); - } - - /** - * Takes the provided {@link Collection} of {@link Action} (or subclasses, - * such as {@link ActionGroup}) instances and updates a {@link ButtonBar} - * populated with appropriate {@link Node nodes} bound to the provided - * {@link Action actions}. Previous content of button bar is removed - * - * @param buttonBar The {@link ButtonBar buttonBar} to update - * @param actions The {@link Action actions} to place on the {@link ButtonBar}. - * @return A {@link ButtonBar} that contains {@link Node nodes} which are bound - * to the state of the provided {@link Action} - */ - public static ButtonBar updateButtonBar( ButtonBar buttonBar, Collection<? extends Action> actions) { - buttonBar.getButtons().clear(); - for (Action action : actions) { - if ( action instanceof ActionGroup ) { - // no-op - } else if ( action == ACTION_SPAN || action == ACTION_SEPARATOR || action == null ) { - // no-op - } else { - buttonBar.getButtons().add(createButton(action, ActionTextBehavior.SHOW)); - } - } - - return buttonBar; - } - - /** - * Takes the provided {@link Collection} of {@link Action} (or subclasses, - * such as {@link ActionGroup}) instances and returns a {@link ContextMenu} - * populated with appropriate {@link Node nodes} bound to the provided - * {@link Action actions}. - * - * @param actions The {@link Action actions} to place on the {@link ContextMenu}. - * @return A {@link ContextMenu} that contains {@link Node nodes} which are bound - * to the state of the provided {@link Action} - */ - public static ContextMenu createContextMenu(Collection<? extends Action> actions) { - return updateContextMenu(new ContextMenu(), actions); - } - - /** - * Takes the provided {@link Collection} of {@link Action} (or subclasses, - * such as {@link ActionGroup}) instances and updates a {@link ContextMenu} - * populated with appropriate {@link Node nodes} bound to the provided - * {@link Action actions}. Previous content of context menu is removed - * - * @param menu The {@link ContextMenu menu} to update - * @param actions The {@link Action actions} to place on the {@link ContextMenu}. - * @return A {@link ContextMenu} that contains {@link Node nodes} which are bound - * to the state of the provided {@link Action} - */ - public static ContextMenu updateContextMenu(ContextMenu menu, Collection<? extends Action> actions) { - menu.getItems().clear(); - menu.getItems().addAll(toMenuItems(actions)); - return menu; - } - - - /*************************************************************************** - * * - * Private implementation * - * * - **************************************************************************/ - - private static Collection<MenuItem> toMenuItems( Collection<? extends Action> actions ) { - - Collection<MenuItem> items = new ArrayList<>(); - - for (Action action : actions) { - - if ( action instanceof ActionGroup ) { - - Menu menu = createMenu( action ); - menu.getItems().addAll( toMenuItems( ((ActionGroup)action).getActions())); - items.add(menu); - - } else if ( action == ACTION_SEPARATOR ) { - - items.add( new SeparatorMenuItem()); - - } else if ( action == null || action == ACTION_SPAN) { - // no-op - } else { - - items.add( createMenuItem(action)); - - } - - } - - return items; - - } - - private static Node copyNode( Node node ) { - if ( node instanceof ImageView ) { - return new ImageView( ((ImageView)node).getImage()); - } else if ( node instanceof Duplicatable<?> ) { - return (Node) ((Duplicatable<?>)node).duplicate(); - } else { - return null; - } - } - - // Carry over action style classes changes to the styleable - // Binding as not a good solution since it wipes out existing styleable classes - private static void bindStyle(final Styleable styleable, final Action action ) { - styleable.getStyleClass().addAll( action.getStyleClass() ); - action.getStyleClass().addListener(new ListChangeListener<String>() { - @Override - public void onChanged(Change<? extends String> c) { - while(c.next()) { - if (c.wasRemoved()) { - styleable.getStyleClass().removeAll(c.getRemoved()); - } - if (c.wasAdded()) { - styleable.getStyleClass().addAll(c.getAddedSubList()); - } - } - } - }); - } - - private static <T extends ButtonBase> T configure(final T btn, final Action action, final ActionTextBehavior textBehavior) { - if (action == null) { - throw new NullPointerException("Action can not be null"); //$NON-NLS-1$ - } - - // button bind to action properties - - bindStyle(btn,action); - - //btn.textProperty().bind(action.textProperty()); - if ( textBehavior == ActionTextBehavior.SHOW ) { - btn.textProperty().bind(action.textProperty()); - } - btn.disableProperty().bind(action.disabledProperty()); - - - btn.graphicProperty().bind(new ObjectBinding<Node>() { - { bind(action.graphicProperty()); } - - @Override protected Node computeValue() { - return copyNode(action.graphicProperty().get()); - } - - @Override - public void removeListener(InvalidationListener listener) { - super.removeListener(listener); - unbind(action.graphicProperty()); - } - }); - - - // add all the properties of the action into the button, and set up - // a listener so they are always copied across - btn.getProperties().putAll(action.getProperties()); - action.getProperties().addListener(new ButtonPropertiesMapChangeListener<>(btn, action)); - - // tooltip requires some special handling (i.e. don't have one when - // the text property is null - btn.tooltipProperty().bind(new ObjectBinding<Tooltip>() { - private Tooltip tooltip = new Tooltip(); - private StringBinding textBinding = new When(action.longTextProperty().isEmpty()).then(action.textProperty()).otherwise(action.longTextProperty()); - - { - bind(textBinding); - tooltip.textProperty().bind(textBinding); - } - - @Override protected Tooltip computeValue() { - String longText = textBinding.get(); - return longText == null || textBinding.get().isEmpty() ? null : tooltip; - } - - @Override - public void removeListener(InvalidationListener listener) { - super.removeListener(listener); - unbind(action.longTextProperty()); - tooltip.textProperty().unbind(); - } - }); - - - - // Handle the selected state of the button if it is of the applicable type - - if ( btn instanceof ToggleButton ) { - ((ToggleButton)btn).selectedProperty().bindBidirectional(action.selectedProperty()); - } - - // Just call the execute method on the action itself when the action - // event occurs on the button - btn.setOnAction(action); - - return btn; - } - - private static void unconfigure(final ButtonBase btn) { - if (btn == null || !(btn.getOnAction() instanceof Action)) { - return; - } - - Action action = (Action) btn.getOnAction(); - - btn.styleProperty().unbind(); - btn.textProperty().unbind(); - btn.disableProperty().unbind(); - btn.graphicProperty().unbind(); - - action.getProperties().removeListener(new ButtonPropertiesMapChangeListener<>(btn, action)); - - btn.tooltipProperty().unbind(); - - if (btn instanceof ToggleButton) { - ((ToggleButton) btn).selectedProperty().unbindBidirectional(action.selectedProperty()); - } - - btn.setOnAction(null); - } - - private static <T extends MenuItem> T configure(final T menuItem, final Action action) { - if (action == null) { - throw new NullPointerException("Action can not be null"); //$NON-NLS-1$ - } - - // button bind to action properties - bindStyle(menuItem,action); - - menuItem.textProperty().bind(action.textProperty()); - menuItem.disableProperty().bind(action.disabledProperty()); - menuItem.acceleratorProperty().bind(action.acceleratorProperty()); - - menuItem.graphicProperty().bind(new ObjectBinding<Node>() { - { bind(action.graphicProperty()); } - - @Override protected Node computeValue() { - return copyNode( action.graphicProperty().get()); - } - - @Override - public void removeListener(InvalidationListener listener) { - super.removeListener(listener); - unbind(action.graphicProperty()); - } - }); - - - // add all the properties of the action into the button, and set up - // a listener so they are always copied across - menuItem.getProperties().putAll(action.getProperties()); - action.getProperties().addListener(new MenuItemPropertiesMapChangeListener<>(menuItem, action)); - - // Handle the selected state of the menu item if it is a - // CheckMenuItem or RadioMenuItem - - if ( menuItem instanceof RadioMenuItem ) { - ((RadioMenuItem)menuItem).selectedProperty().bindBidirectional(action.selectedProperty()); - } else if ( menuItem instanceof CheckMenuItem ) { - ((CheckMenuItem)menuItem).selectedProperty().bindBidirectional(action.selectedProperty()); - } - - // Just call the execute method on the action itself when the action - // event occurs on the button - menuItem.setOnAction(action); - - return menuItem; - } - - private static void unconfigure(final MenuItem menuItem) { - if (menuItem == null || !(menuItem.getOnAction() instanceof Action)) { - return; - } - - Action action = (Action) menuItem.getOnAction(); - - menuItem.styleProperty().unbind(); - menuItem.textProperty().unbind(); - menuItem.disableProperty().unbind(); - menuItem.acceleratorProperty().unbind(); - menuItem.graphicProperty().unbind(); - - action.getProperties().removeListener(new MenuItemPropertiesMapChangeListener<>(menuItem, action)); - - if (menuItem instanceof RadioMenuItem) { - ((RadioMenuItem) menuItem).selectedProperty().unbindBidirectional(action.selectedProperty()); - } else if (menuItem instanceof CheckMenuItem) { - ((CheckMenuItem) menuItem).selectedProperty().unbindBidirectional(action.selectedProperty()); - } - - menuItem.setOnAction(null); - } - - private static class ButtonPropertiesMapChangeListener<T extends ButtonBase> implements MapChangeListener<Object, Object> { - - private final WeakReference<T> btnWeakReference; - private final Action action; - - private ButtonPropertiesMapChangeListener(T btn, Action action) { - btnWeakReference = new WeakReference<>(btn); - this.action = action; - } - - @Override public void onChanged(MapChangeListener.Change<?, ?> change) { - T btn = btnWeakReference.get(); - if (btn == null) { - action.getProperties().removeListener(this); - } else { - btn.getProperties().clear(); - btn.getProperties().putAll(action.getProperties()); - } - } - - @Override - public boolean equals(Object otherObject) { - if (this == otherObject) { - return true; - } - if (otherObject == null || getClass() != otherObject.getClass()) { - return false; - } - - ButtonPropertiesMapChangeListener<?> otherListener = (ButtonPropertiesMapChangeListener<?>) otherObject; - - T btn = btnWeakReference.get(); - ButtonBase otherBtn = otherListener.btnWeakReference.get(); - if (btn != null ? !btn.equals(otherBtn) : otherBtn != null) { - return false; - } - return action.equals(otherListener.action); - } - - @Override - public int hashCode() { - T btn = btnWeakReference.get(); - int result = btn != null ? btn.hashCode() : 0; - result = 31 * result + action.hashCode(); - return result; - } - } - - private static class MenuItemPropertiesMapChangeListener<T extends MenuItem> implements MapChangeListener<Object, Object> { - - private final WeakReference<T> menuItemWeakReference; - private final Action action; - - private MenuItemPropertiesMapChangeListener(T menuItem, Action action) { - menuItemWeakReference = new WeakReference<>(menuItem); - this.action = action; - } - - @Override public void onChanged(MapChangeListener.Change<?, ?> change) { - T menuItem = menuItemWeakReference.get(); - if (menuItem == null) { - action.getProperties().removeListener(this); - } else { - menuItem.getProperties().clear(); - menuItem.getProperties().putAll(action.getProperties()); - } - } - - @Override - public boolean equals(Object otherObject) { - if (this == otherObject) { - return true; - } - if (otherObject == null || getClass() != otherObject.getClass()) { - return false; - } - - MenuItemPropertiesMapChangeListener<?> otherListener = (MenuItemPropertiesMapChangeListener<?>) otherObject; - - T menuItem = menuItemWeakReference.get(); - MenuItem otherMenuItem = otherListener.menuItemWeakReference.get(); - return menuItem != null ? menuItem.equals(otherMenuItem) : otherMenuItem == null && action.equals(otherListener.action); - - } - - @Override - public int hashCode() { - T menuItem = menuItemWeakReference.get(); - int result = menuItem != null ? menuItem.hashCode() : 0; - result = 31 * result + action.hashCode(); - return result; - } - } -} diff --git a/src/org/controlsfx/control/action/AnnotatedAction.java b/src/org/controlsfx/control/action/AnnotatedAction.java deleted file mode 100644 index b667cda..0000000 --- a/src/org/controlsfx/control/action/AnnotatedAction.java +++ /dev/null @@ -1,115 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.action; - -import java.lang.ref.WeakReference; -import java.lang.reflect.Method; -import java.util.Objects; -import javafx.event.ActionEvent; - - - -/** - * An action that invokes a method that has been annotated with {@link ActionProxy}. These actions are created via - * {@link ActionMap#register(java.lang.Object)}, which delegates the actual instantiation to an {@link AnnotatedActionFactory}. - * - * Note that this class maintains a WeakReference to the supplied target object, so the existence of an - * AnnotatedAction instance will not prevent the target from being garbage-collected. - */ -public class AnnotatedAction extends Action { - - private final Method method; - private final WeakReference<Object> target; - - /** - * Instantiates an action that will call the specified method on the specified target. - */ - public AnnotatedAction(String text, Method method, Object target) { - super(text); - Objects.requireNonNull( method ); - Objects.requireNonNull( target ); - - setEventHandler(this::handleAction); - - this.method = method; - this.method.setAccessible(true); - this.target = new WeakReference( target ); - } - - /** - * Returns the target object (the object on which the annotated method will be called). - * - * @return The target object, or null if the target object has been garbage-collected. - */ - public Object getTarget() { - return target.get(); - } - - /** - * Handle the action-event by invoking the annotated method on the target object. If an exception is - * thrown, then the default implementation of this method will call handleActionException(). - */ - protected void handleAction(ActionEvent ae) { - try { - Object actionTarget = getTarget(); - if (actionTarget == null) { - throw new IllegalStateException( "Action target object is no longer reachable" ); - } - - int paramCount = method.getParameterCount(); - if ( paramCount == 0 ) { - method.invoke(actionTarget); - - } else if ( paramCount == 1) { - method.invoke(actionTarget, ae); - - } else if ( paramCount == 2) { - method.invoke(actionTarget, ae, this); - } - } catch (Throwable e) { - handleActionException( ae, e ); - } - } - - - /** - * Called if the annotated method throws an exception when invoked. The default implementation of this method simply prints - * the stack trace of the specified exception. - */ - protected void handleActionException( ActionEvent ae, Throwable ex ) { - ex.printStackTrace(); - } - - - /** - * Overridden to return the text of this action. - */ - @Override - public String toString() { - return getText(); - } -} diff --git a/src/org/controlsfx/control/action/AnnotatedActionFactory.java b/src/org/controlsfx/control/action/AnnotatedActionFactory.java deleted file mode 100644 index 9c083de..0000000 --- a/src/org/controlsfx/control/action/AnnotatedActionFactory.java +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.action; - -import java.lang.reflect.Method; - - -/** - * Defines the interface used by {@link ActionMap} for creating instances of {@link AnnotatedAction}. - */ -public interface AnnotatedActionFactory { - - /** - * Create an {@link AnnotatedAction} instance. - * - * @param annotation The annotation specified on the method. - * @param method The method to be invoked when an action is fired. - * @param target The target object on which the method will be invoked. - * @return An {@link AnnotatedAction} instance. - */ - AnnotatedAction createAction( ActionProxy annotation, Method method, Object target ); -} diff --git a/src/org/controlsfx/control/action/AnnotatedCheckAction.java b/src/org/controlsfx/control/action/AnnotatedCheckAction.java deleted file mode 100644 index 5b5dfd3..0000000 --- a/src/org/controlsfx/control/action/AnnotatedCheckAction.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.controlsfx.control.action; - -import java.lang.reflect.Method; - -@ActionCheck -public class AnnotatedCheckAction extends AnnotatedAction { - - /** - * Instantiates an action that will call the specified method on the specified target. - * This action is marked with @ActionCheck - * - * @param text - * @param method - * @param target - */ - public AnnotatedCheckAction(String text, Method method, Object target) { - super(text, method, target); - } -} diff --git a/src/org/controlsfx/control/action/DefaultActionFactory.java b/src/org/controlsfx/control/action/DefaultActionFactory.java deleted file mode 100644 index 3dc3d31..0000000 --- a/src/org/controlsfx/control/action/DefaultActionFactory.java +++ /dev/null @@ -1,114 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.action; - -import javafx.scene.Node; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import javafx.scene.input.KeyCombination; -import org.controlsfx.glyphfont.Glyph; - -import java.lang.reflect.Method; - -/** - * The default {@link AnnotatedActionFactory} to be used when no alternative has been specified. This class creates - * instances of {@link AnnotatedAction}. - */ -public class DefaultActionFactory implements AnnotatedActionFactory { - - /** - * Create an {@link AnnotatedAction}. This method is called by {@link ActionMap#register(java.lang.Object)}. - * - * @param annotation The annotation specified on the method. - * @param method The method to be invoked when an action is fired. - * @param target The target object on which the method will be invoked. - * @return An {@link AnnotatedAction} instance. - */ - @Override - public AnnotatedAction createAction( ActionProxy annotation, Method method, Object target ) { - AnnotatedAction action; - if ( method.isAnnotationPresent(ActionCheck.class)) { - action = new AnnotatedCheckAction(annotation.text(), method, target); - } else { - action = new AnnotatedAction(annotation.text(), method, target); - } - - configureAction( annotation, action ); - - return action; - } - - - /** - * Configures the newly-created action before it is returned to {@link ActionMap}. Subclasses can override this method - * to change configuration behavior. - * - * @param annotation The annotation specified on the method. - * @param action The newly-created action. - */ - protected void configureAction( ActionProxy annotation, AnnotatedAction action ) { - Node graphic = resolveGraphic(annotation); - action.setGraphic(graphic); - - // set long text / tooltip - String longText = annotation.longText().trim(); - if ( graphic != null ) { - action.setLongText(longText); - } - - // set accelerator - String acceleratorText = annotation.accelerator().trim(); - if (!acceleratorText.isEmpty()) { - action.setAccelerator(KeyCombination.keyCombination(acceleratorText)); - } - - } - - - /** - * Resolve the graphical representation of this action. The default implementation of this method implements the protocol described - * in {@link ActionProxy#graphic()}, but subclasses can override this method to provide alternative behavior. - * - * @param annotation The annotation specified on the method. - * @return A JavaFX Node for the graphic associated with this action. - */ - protected Node resolveGraphic( ActionProxy annotation ) { - String graphicDef = annotation.graphic().trim(); - if ( !graphicDef.isEmpty()) { - - String[] def = graphicDef.split("\\>"); // cannot use ':' because it used in urls //$NON-NLS-1$ - if ( def.length == 1 ) return new ImageView(new Image(def[0])); - switch (def[0]) { - case "font" : return Glyph.create(def[1]); //$NON-NLS-1$ - case "image" : return new ImageView(new Image(def[1])); //$NON-NLS-1$ - default: throw new IllegalArgumentException( String.format("Unknown ActionProxy graphic protocol: %s", def[0])); //$NON-NLS-1$ - } - } - return null; - } - -} diff --git a/src/org/controlsfx/control/action/package-info.java b/src/org/controlsfx/control/action/package-info.java deleted file mode 100644 index bcb828d..0000000 --- a/src/org/controlsfx/control/action/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * A package containing the {@link org.controlsfx.control.action.Action} API, as well - * as the {@link org.controlsfx.control.action.Action} convenience subclass. - * Refer to these two classes for the necessary details on what actions are in - * the JavaFX context. - */ -package org.controlsfx.control.action; \ No newline at end of file diff --git a/src/org/controlsfx/control/breadcrumbbar.css b/src/org/controlsfx/control/breadcrumbbar.css deleted file mode 100644 index 18ba307..0000000 --- a/src/org/controlsfx/control/breadcrumbbar.css +++ /dev/null @@ -1,3 +0,0 @@ -.bread-crumb-bar { - -} diff --git a/src/org/controlsfx/control/cell/ColorGridCell.java b/src/org/controlsfx/control/cell/ColorGridCell.java deleted file mode 100644 index 7317ccf..0000000 --- a/src/org/controlsfx/control/cell/ColorGridCell.java +++ /dev/null @@ -1,82 +0,0 @@ -/** - * Copyright (c) 2013, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.cell; - -import javafx.scene.control.ContentDisplay; -import javafx.scene.paint.Color; -import javafx.scene.shape.Rectangle; - -import org.controlsfx.control.GridCell; -import org.controlsfx.control.GridView; - -/** - * A {@link GridCell} that can be used to show coloured rectangles inside the - * {@link GridView} control. - * - * @see GridView - */ -public class ColorGridCell extends GridCell<Color> { - - private Rectangle colorRect; - - private static final boolean debug = false; - - /** - * Creates a default ColorGridCell instance. - */ - public ColorGridCell() { - getStyleClass().add("color-grid-cell"); //$NON-NLS-1$ - - colorRect = new Rectangle(); - colorRect.setStroke(Color.BLACK); - colorRect.heightProperty().bind(heightProperty()); - colorRect.widthProperty().bind(widthProperty()); - setGraphic(colorRect); - - if (debug) { - setContentDisplay(ContentDisplay.TEXT_ONLY); - } - } - - /** - * {@inheritDoc} - */ - @Override protected void updateItem(Color item, boolean empty) { - super.updateItem(item, empty); - - if (empty) { - setGraphic(null); - } else { - colorRect.setFill(item); - setGraphic(colorRect); - } - - if (debug) { - setText(getIndex() + ""); //$NON-NLS-1$ - } - } -} diff --git a/src/org/controlsfx/control/cell/ImageGridCell.java b/src/org/controlsfx/control/cell/ImageGridCell.java deleted file mode 100644 index 7703f30..0000000 --- a/src/org/controlsfx/control/cell/ImageGridCell.java +++ /dev/null @@ -1,85 +0,0 @@ -/** - * Copyright (c) 2013, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.cell; - -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; - -import org.controlsfx.control.GridCell; -import org.controlsfx.control.GridView; - -/** - * A {@link GridCell} that can be used to show images inside the - * {@link GridView} control. - * - * @see GridView - */ -public class ImageGridCell extends GridCell<Image> { - - private final ImageView imageView; - - private final boolean preserveImageProperties; - - - /** - * Creates a default ImageGridCell instance, which will preserve image properties - */ - public ImageGridCell() { - this(true); - } - - /** - * Create ImageGridCell instance - * @param preserveImageProperties if set to true will preserve image aspect ratio and smoothness - */ - public ImageGridCell( boolean preserveImageProperties ) { - getStyleClass().add("image-grid-cell"); //$NON-NLS-1$ - - this.preserveImageProperties = preserveImageProperties; - imageView = new ImageView(); - imageView.fitHeightProperty().bind(heightProperty()); - imageView.fitWidthProperty().bind(widthProperty()); - } - - /** - * {@inheritDoc} - */ - @Override protected void updateItem(Image item, boolean empty) { - super.updateItem(item, empty); - - if (empty) { - setGraphic(null); - } else { - if (preserveImageProperties) { - imageView.setPreserveRatio(item.isPreserveRatio()); - imageView.setSmooth( item.isSmooth()); - } - imageView.setImage(item); - setGraphic(imageView); - } - } -} \ No newline at end of file diff --git a/src/org/controlsfx/control/cell/MediaImageCell.java b/src/org/controlsfx/control/cell/MediaImageCell.java deleted file mode 100644 index 4564872..0000000 --- a/src/org/controlsfx/control/cell/MediaImageCell.java +++ /dev/null @@ -1,106 +0,0 @@ -/** - * Copyright (c) 2013, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.cell; - -import javafx.scene.media.Media; -import javafx.scene.media.MediaPlayer; -import javafx.scene.media.MediaView; - -import org.controlsfx.control.GridCell; -import org.controlsfx.control.GridView; - -/** - * A {@link GridCell} that can be used to show media (i.e. movies) inside the - * {@link GridView} control. - * - * @see GridView - */ -public class MediaImageCell extends GridCell<Media> { - - private MediaPlayer mediaPlayer; - private final MediaView mediaView; - - /** - * Creates a default MediaGridCell instance. - */ - public MediaImageCell() { - getStyleClass().add("media-grid-cell"); //$NON-NLS-1$ - - mediaView = new MediaView(); - mediaView.setMediaPlayer(mediaPlayer); - mediaView.fitHeightProperty().bind(heightProperty()); - mediaView.fitWidthProperty().bind(widthProperty()); - mediaView.setMediaPlayer(mediaPlayer); - } - - /** - * Pauses the media player inside this cell. - */ - public void pause() { - if(mediaPlayer != null) { - mediaPlayer.pause(); - } - } - - /** - * Starts playing the media player inside this cell. - */ - public void play() { - if(mediaPlayer != null) { - mediaPlayer.play(); - } - } - - /** - * Stops playing the media player inside this cell. - */ - public void stop() { - if(mediaPlayer != null) { - mediaPlayer.stop(); - } - } - - /** - * {@inheritDoc} - */ - @Override protected void updateItem(Media item, boolean empty) { - super.updateItem(item, empty); - - getChildren().clear(); - if (mediaPlayer != null) { - mediaPlayer.stop(); - } - - if (empty) { - setGraphic(null); - } else { - mediaPlayer = new MediaPlayer(item); - mediaView.setMediaPlayer(mediaPlayer); - setGraphic(mediaView); - } - } -} \ No newline at end of file diff --git a/src/org/controlsfx/control/cell/package-info.java b/src/org/controlsfx/control/cell/package-info.java deleted file mode 100644 index 4305006..0000000 --- a/src/org/controlsfx/control/cell/package-info.java +++ /dev/null @@ -1,9 +0,0 @@ -/** - * A package containing a number of useful cell-related classes that do not - * exist in the base JavaFX distribution, many related to the new - * {@link org.controlsfx.control.GridView GridView} control offered in - * ControlsFX. - * - * @see org.controlsfx.control.GridView - */ -package org.controlsfx.control.cell; \ No newline at end of file diff --git a/src/org/controlsfx/control/collapse.png b/src/org/controlsfx/control/collapse.png deleted file mode 100644 index b8896c70d7c216137b48d95a346c37f59a7b9588..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 912 zcmeAS@N?(olHy`uVBq!ia0y~yU=Rgi4mJh`hLz$=r!g=vFct^7J29*~C-ahlfq^C6 z(btiIVPik{pF~y$1_p&>k04(LhAK4%hK3dfhF=T}3=J<B7)lKo7+xhXFj&oCU=S~u zvn$Ysfq_A?#5JNMI6tkVJh3R1As{g`uSCz!HAJDzSkF|?c)`oas|*ZGFFjoxLoEEK zPRaD1?I>`3_L8*;nH&EK?9=}_i}9=P2jPqWMMXDG7nk@IfsaMsv+y^i?|CHJ8@TMZ zw6TBqK__{Md2?;+tUu4c%X>9zYk<3Z`-lHeYQOyaSHJcC;hc{@e^zE>WqAp8wtV^a z%}Yn@vc28kyg#?wrT4Z!>hJIO_V@4a>Fqsv?i^p_iPNXM|9vdpIj7I~{MXu#4^Mqw zcs0w^#K=f#Wr$Z^UY^L69J8k%KL)<~y35AK#$)lt3D2LW@7%X<T8fe88GBn>-g*gB zVKsGi(QjYAEKzv#?_b=zckiy`<>!|=-%dzMaypoAWY&K0;lo7Ms1!El6oUqr%F@!M zMGWdm*Vq$G7HVW1Nm2Te$d<^%!S><Pr=WA^&Rr>gx%yZm%eu|EX=!dp)x8>Cv`v%P z=g9DIvtjX#4?liHY?hFf6}9LSUl{Q4-@m$>ckf>9^kER|b-Vh)`E++T_ut32C5&Wc zWiyXtXJ<39&kM7c>(740;L8-9k#MX=;qQyef`SEQ6%`r<P0ClVUR@fhCd#JkEAKPq z{ol!xg(KtRuWLkdt2b<7R$$Yb+V$rB`{HDiSoxIPU%U}IVyVf=&e!*Jis*VRoz!%3 zT6D19^isvl-w8El>W8LI6^)FExnjEI_pe|7+`O)Cy1B-Sp{BYzdfT>bDaFOcEA$dp z`6halS5`)fiHR)<(0DP?Yx(7{zt^*01@#u3yJN~Lwy~hJG?aI)rUL867tfwQPtD8o zYrb*&_T+c(@>G8RdG_wJMS*cgn?@%~bW~K3vTt`zSy|YppL_b0FFts%z*bLiFGJZ@ zi!FB&<J9=94+;0Wx`Z?=TfY421diN^YfHc1{v$1FbIwnim7kY4bCpb1m)nwtjwvOL z8($tc(6Be??f;tSO700vy*C;}F7gP3y0!VJEq=WAyUCl>-?zS5Ic+&xzNr3r>+>Cj z|0;g|e7rsG-+HtCU&9wT-j022UViN+fBM`PuYH#+dbYXan}7QLsO+W$o?q;Xg$^8T UJr<nBz`(%Z>FVdQ&MBb@0EM!jYybcN diff --git a/src/org/controlsfx/control/decoration/Decoration.java b/src/org/controlsfx/control/decoration/Decoration.java deleted file mode 100644 index d5ff986..0000000 --- a/src/org/controlsfx/control/decoration/Decoration.java +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.decoration; - -import java.util.HashMap; -import java.util.Map; - -import javafx.scene.Node; - -/** - * Decoration is an abstract class used by the ControlsFX {@link Decorator} class - * for adding and removing decorations on a node. ControlsFX - * ships with pre-built decorations, including {@link GraphicDecoration} and - * {@link StyleClassDecoration}. - * - * <p>To better understand how to use the ControlsFX decoration API in your - * application, refer to the code samples and explanations in {@link Decorator}. - * - * @see Decorator - * @see GraphicDecoration - * @see StyleClassDecoration - */ -public abstract class Decoration { - - private volatile Map<String,Object> properties; - - /** - * Instantiates a default Decoration instance (obviously only callable by - * subclasses). - */ - protected Decoration() { - // no-op - } - - /** - * This method decorates the given - * target node with the relevant decorations, returning any 'decoration node' - * that needs to be added to the scenegraph (although this can be null). When - * the returned Node is null, this indicates that the decoration will be - * handled internally by the decoration (which is preferred, as the default - * implementation is not ideal in most circumstances). - * - * <p>When the boolean parameter is false, this method removes the decoration - * from the given target node, always returning null. - * - * @param targetNode The node to decorate. - * @return The decoration, but null is a valid return value. - */ - public abstract Node applyDecoration(Node targetNode); - - /** - * This method removes the decoration from the given target node. - * - * @param targetNode The node to undecorate. - */ - public abstract void removeDecoration(Node targetNode); - - /** - * Custom decoration properties - * @return decoration properties - */ - public synchronized final Map<String,Object> getProperties() { - if (properties == null) { - properties = new HashMap<>(); - } - return properties; - } -} diff --git a/src/org/controlsfx/control/decoration/Decorator.java b/src/org/controlsfx/control/decoration/Decorator.java deleted file mode 100644 index 0743593..0000000 --- a/src/org/controlsfx/control/decoration/Decorator.java +++ /dev/null @@ -1,241 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.decoration; - -import impl.org.controlsfx.ImplUtils; -import impl.org.controlsfx.skin.DecorationPane; - -import java.util.*; -import java.util.function.Consumer; - -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.scene.Node; -import javafx.scene.Parent; -import javafx.scene.Scene; -import javafx.scene.control.TextField; - -/** - * The Decorator class is responsible for accessing decorations for a given node. - * Through this class you may therefore add and remove decorations as desired. - * - * <h3>Code Example</h3> - * <p>Say you have a {@link TextField} that you want to decorate. You would simply - * do the following: - * - * <pre> - * {@code - * TextField textfield = new TextField(); - * Node decoration = ... // could be an ImageView or any Node! - * Decorator.addDecoration(textfield, new GraphicDecoration(decoration, Pos.CENTER_RIGHT));} - * </pre> - * - * <p>Similarly, if we wanted to add a CSS style class (e.g. because we have some - * css that knows to make the 'warning' style class turn the TextField a lovely - * shade of bright red, we would simply do the following: - * - * <pre> - * {@code - * TextField textfield = new TextField(); - * Decorator.addDecoration(textfield, new StyleClassDecoration("warning");} - * </pre> - * - * @see Decoration - */ -public class Decorator { - - - /*************************************************************************** - * * - * Static fields * - * * - **************************************************************************/ - - private final static String DECORATIONS_PROPERTY_KEY = "$org.controlsfx.decorations$"; //$NON-NLS-1$ - - - - /*************************************************************************** - * * - * Constructors * - * * - **************************************************************************/ - - private Decorator() { - // no op - } - - - - /*************************************************************************** - * * - * Static API * - * * - **************************************************************************/ - - /** - * Adds the given decoration to the given node. - * @param target The node to add the decoration to. - * @param decoration The decoration to add to the node. - */ - public static final void addDecoration(Node target, Decoration decoration) { - getDecorations(target, true).add(decoration); - updateDecorationsOnNode(target, FXCollections.observableArrayList(decoration), null); - } - - /** - * Removes the given decoration from the given node. - * @param target The node to remove the decoration from. - * @param decoration The decoration to remove from the node. - */ - public static final void removeDecoration(Node target, Decoration decoration) { - getDecorations(target, true).remove(decoration); - updateDecorationsOnNode(target, null, FXCollections.observableArrayList(decoration)); - } - - /** - * Removes all the decorations that have previously been set on the given node. - * @param target The node from which all previously set decorations should be removed. - */ - public static final void removeAllDecorations(Node target) { - List<Decoration> decorations = getDecorations(target, true); - List<Decoration> removed = FXCollections.observableArrayList(decorations); - - target.getProperties().remove(DECORATIONS_PROPERTY_KEY); - - updateDecorationsOnNode(target, null, removed); - } - - /** - * Returns all the currently set decorations for the given node. - * @param target The node for which all currently set decorations are required. - * @return An ObservableList of the currently set decorations for the given node. - */ - public static final ObservableList<Decoration> getDecorations(Node target) { - return getDecorations(target, false); - } - - - - /*************************************************************************** - * * - * Implementation * - * * - **************************************************************************/ - - private static final ObservableList<Decoration> getDecorations(Node target, boolean createIfAbsent) { - @SuppressWarnings("unchecked") - ObservableList<Decoration> decorations = (ObservableList<Decoration>) target.getProperties().get(DECORATIONS_PROPERTY_KEY); - if (decorations == null && createIfAbsent) { - decorations = FXCollections.observableArrayList(); - target.getProperties().put(DECORATIONS_PROPERTY_KEY, decorations); - } - return decorations; - } - - private static void updateDecorationsOnNode(Node target, List<Decoration> added, List<Decoration> removed) { - // find a DecorationPane parent and notify it that a node has updated - // decorations - getDecorationPane(target, (pane) -> pane.updateDecorationsOnNode(target, added, removed)); - } - - private static List<Scene> currentlyInstallingScenes = new ArrayList<>(); - private static Map<Scene, List<Consumer<DecorationPane>>> pendingTasksByScene = new HashMap<>(); - - private static void getDecorationPane(Node target, Consumer<DecorationPane> task) { - // find a DecorationPane parent and notify it that a node has updated - // decorations. If a DecorationPane doesn't exist, we install it into - // the scene. If a Scene does not exist, we add a listener to try again - // when a scene is available. - - DecorationPane pane = getDecorationPaneInParentHierarchy(target); - - if (pane != null) { - task.accept(pane); - } else { - // install decoration pane - final Consumer<Scene> sceneConsumer = scene -> { - if (currentlyInstallingScenes.contains(scene)) { - List<Consumer<DecorationPane>> pendingTasks = pendingTasksByScene.get(scene); - if (pendingTasks == null) { - pendingTasks = new LinkedList<>(); - pendingTasksByScene.put(scene, pendingTasks); - } - pendingTasks.add(task); - return; - } - - DecorationPane _pane = getDecorationPaneInParentHierarchy(target); - if (_pane == null) { - currentlyInstallingScenes.add(scene); - _pane = new DecorationPane(); - Node oldRoot = scene.getRoot(); - ImplUtils.injectAsRootPane(scene, _pane, true); - _pane.setRoot(oldRoot); - currentlyInstallingScenes.remove(scene); - } - - task.accept(_pane); - final List<Consumer<DecorationPane>> pendingTasks = pendingTasksByScene.remove(scene); - if (pendingTasks != null) { - for (Consumer<DecorationPane> pendingTask : pendingTasks) { - pendingTask.accept(_pane); - } - } - }; - - Scene scene = target.getScene(); - if (scene != null) { - sceneConsumer.accept(scene); - } else { - // install listener to try again later - InvalidationListener sceneListener = new InvalidationListener() { - @Override public void invalidated(Observable o) { - if (target.getScene() != null) { - target.sceneProperty().removeListener(this); - sceneConsumer.accept(target.getScene()); - } - } - }; - target.sceneProperty().addListener(sceneListener); - } - } - } - - private static DecorationPane getDecorationPaneInParentHierarchy(Node target) { - Parent p = target.getParent(); - while (p != null) { - if (p instanceof DecorationPane) { - return (DecorationPane) p; - } - p = p.getParent(); - } - return null; - } -} diff --git a/src/org/controlsfx/control/decoration/GraphicDecoration.java b/src/org/controlsfx/control/decoration/GraphicDecoration.java deleted file mode 100644 index ca521ad..0000000 --- a/src/org/controlsfx/control/decoration/GraphicDecoration.java +++ /dev/null @@ -1,193 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.decoration; - -import impl.org.controlsfx.ImplUtils; - -import java.util.List; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; - -import javafx.geometry.Bounds; -import javafx.geometry.Pos; -import javafx.scene.Node; -import javafx.scene.Parent; -import javafx.scene.image.ImageView; - -/** - * GraphicDecoration is a {@link Decoration} designed to show a graphic (be it - * an image loaded via an {@link ImageView} or an arbitrarily complex - * scenegraph in its own right) on top of a given node. GraphicDecoration is - * applied as part of the ControlsFX {@link Decorator} API - refer to the - * {@link Decorator} javadoc for more details. - * - * @see Decoration - * @see Decorator - */ -public class GraphicDecoration extends Decoration { - - private final Node decorationNode; - private final Pos pos; - private final double xOffset; - private final double yOffset; - - /** - * Constructs a new GraphicDecoration with the given decoration node to be - * applied to any node that has this decoration applied to it. By default - * the decoration node will be applied in the top-left corner of the node. - * - * @param decorationNode The decoration node to apply to any node that has this - * decoration applied to it - */ - public GraphicDecoration(Node decorationNode) { - this(decorationNode, Pos.TOP_LEFT); - } - - /** - * Constructs a new GraphicDecoration with the given decoration node to be - * applied to any node that has this decoration applied to it, in the location - * provided by the {@link Pos position} argument. - * - * @param decorationNode The decoration node to apply to any node that has this - * decoration applied to it - * @param position The location to position the decoration node relative to the - * node that is being decorated. - */ - public GraphicDecoration(Node decorationNode, Pos position) { - this(decorationNode, position, 0, 0); - } - - /** - * Constructs a new GraphicDecoration with the given decoration node to be - * applied to any node that has this decoration applied to it, in the location - * provided by the {@link Pos position} argument, with the given xOffset and - * yOffset values used to adjust the position. - * - * @param decorationNode The decoration node to apply to any node that has this - * decoration applied to it - * @param position The location to position the decoration node relative to the - * node that is being decorated. - * @param xOffset The amount of movement to apply to the decoration node in the - * x direction (i.e. left and right). - * @param yOffset The amount of movement to apply to the decoration node in the - * y direction (i.e. up and down). - */ - public GraphicDecoration(Node decorationNode, Pos position, double xOffset, double yOffset) { - this.decorationNode = decorationNode; - this.decorationNode.setManaged(false); - this.pos = position; - this.xOffset = xOffset; - this.yOffset = yOffset; - } - - /** {@inheritDoc} */ - @Override public Node applyDecoration(Node targetNode) { - List<Node> targetNodeChildren = ImplUtils.getChildren((Parent)targetNode, true); - updateGraphicPosition(targetNode); - if (!targetNodeChildren.contains(decorationNode)) { - targetNodeChildren.add(decorationNode); - } - return null; - } - - /** {@inheritDoc} */ - @Override public void removeDecoration(Node targetNode) { - List<Node> targetNodeChildren = ImplUtils.getChildren((Parent)targetNode, true); - - if (targetNodeChildren.contains(decorationNode)) { - targetNodeChildren.remove(decorationNode); - } - } - - private void updateGraphicPosition(Node targetNode) { - final double decorationNodeWidth = decorationNode.prefWidth(-1); - final double decorationNodeHeight = decorationNode.prefHeight(-1); - - Bounds targetBounds = targetNode.getLayoutBounds(); - double x = targetBounds.getMinX(); - double y = targetBounds.getMinY(); - - double targetWidth = targetBounds.getWidth(); - if (targetWidth <= 0) { - targetWidth = targetNode.prefWidth(-1); - } - - double targetHeight = targetBounds.getHeight(); - if (targetHeight <= 0) { - targetHeight = targetNode.prefHeight(-1); - } - - /** - * If both targetWidth and targetHeight are equal to 0, this means the - * targetNode has not been laid out so we can put a listener in order to - * catch when the layout will be updated, and then we will place our - * decorationNode to the proper position. - */ - if (targetWidth <= 0 && targetHeight <= 0) { - targetNode.layoutBoundsProperty().addListener(new ChangeListener<Bounds>() { - - @Override - public void changed(ObservableValue<? extends Bounds> observable, Bounds oldValue, Bounds newValue) { - targetNode.layoutBoundsProperty().removeListener(this); - updateGraphicPosition(targetNode); - } - }); - } - - // x - switch (pos.getHpos()) { - case CENTER: - x += targetWidth/2 - decorationNodeWidth / 2.0; - break; - case LEFT: - x -= decorationNodeWidth / 2.0; - break; - case RIGHT: - x += targetWidth - decorationNodeWidth / 2.0; - break; - } - - // y - switch (pos.getVpos()) { - case CENTER: - y += targetHeight/2 - decorationNodeHeight / 2.0; - break; - case TOP: - y -= decorationNodeHeight / 2.0; - break; - case BOTTOM: - y += targetHeight - decorationNodeWidth / 2.0; - break; - case BASELINE: - y += targetNode.getBaselineOffset() - decorationNode.getBaselineOffset() - decorationNodeHeight / 2.0; - break; - } - - decorationNode.setLayoutX(x + xOffset); - decorationNode.setLayoutY(y + yOffset); - } -} diff --git a/src/org/controlsfx/control/decoration/StyleClassDecoration.java b/src/org/controlsfx/control/decoration/StyleClassDecoration.java deleted file mode 100644 index 5e86b8b..0000000 --- a/src/org/controlsfx/control/decoration/StyleClassDecoration.java +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.decoration; - -import java.util.List; - -import javafx.scene.Node; - -/** - * StyleClassDecoration is a {@link Decoration} designed to add a CSS style class - * to a node (for example, to show a warning style when the field is incorrectly - * set). StyleClassDecoration is applied as part of the ControlsFX {@link Decorator} - * API - refer to the {@link Decorator} javadoc for more details. - * - * @see Decoration - * @see Decorator - */ -public class StyleClassDecoration extends Decoration { - - private final String[] styleClasses; - - /** - * Constructs a new StyleClassDecoration with the given var-args array of - * style classes set to be applied to any node that has this decoration - * applied to it. - * - * @param styleClass A var-args array of style classes to apply to any node. - * @throws IllegalArgumentException if the styleClass varargs array is null or empty. - */ - public StyleClassDecoration(String... styleClass) { - if (styleClass == null || styleClass.length == 0) { - throw new IllegalArgumentException("var-arg style class array must not be null or empty"); //$NON-NLS-1$ - } - this.styleClasses = styleClass; - } - - /** {@inheritDoc} */ - @Override public Node applyDecoration(Node targetNode) { - final List<String> styleClassList = targetNode.getStyleClass(); - - for (String styleClass : styleClasses) { - if (styleClassList.contains(styleClass)) { - continue; - } - - styleClassList.add(styleClass); - } - - // no decoration node, so return null - return null; - } - - /** {@inheritDoc} */ - @Override public void removeDecoration(Node targetNode) { - targetNode.getStyleClass().removeAll(styleClasses); - } -} diff --git a/src/org/controlsfx/control/decoration/package-info.java b/src/org/controlsfx/control/decoration/package-info.java deleted file mode 100644 index da9c058..0000000 --- a/src/org/controlsfx/control/decoration/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -/** - * A package containing decoration-related API (that is, API to allow for users - * to 'decorate' nodes with additional nodes or css decorations. - */ -package org.controlsfx.control.decoration; \ No newline at end of file diff --git a/src/org/controlsfx/control/expand.png b/src/org/controlsfx/control/expand.png deleted file mode 100644 index c45d4ac09eaa74b5ab9894fa5eef2f28e9c46376..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 933 zcmeAS@N?(olHy`uVBq!ia0y~yU=Rgi4mJh`hLz$=r!g=vFct^7J29*~C-ahlfq^C6 z(btiIVPik{pF~y$1_p&>k04(LhAK4%hK3dfhF=T}3=J<B7)lKo7+xhXFj&oCU=S~u zvn$Ysfq_A?#5JNMI6tkVJh3R1As{g`uSCz!HAJDzSkF|?c)`oas|*ZG|2$nBLoEDj zr~3LwIf}G(>&-IBbh@OLyDR_FT<-F}tg&CrOD@-6%JaO^`%!#_qfn=Y>Oq0n1wR_) z6;`Ndm@Znu;_^}W#7mpyXP!2>O@4f5r}5`A)%SK5f7ny?@cpMxpEgU%8B8?!c)i8o z?(45zlAkYJdj6BMZTh<er=2n1jyx`$IcLt4jT;R={;aum>G@vC|Ebr$%&y3Pl>2*T zT{`pag}q0UjEszwK7al^>HPCR)wN;X(Z4QcgdCrle($f@$BnwLmS^r?k;QFeZ~y(w z*|VMo5>r;M)@C)8;@!D_|Mc6pqj&D!J-NM|J=1J<(CVuxRaH?l>dVTmU7x*@IqlG+ zM~e>0$;*qn+_`hdV{hE`9sBlO<9*A<&CShac7fl&Ce=WMOY?%(W&;N?Hi4;EvqIl8 z^d(&@|C#Ai-|p_?wop1PG?94~BjcJ7t)jxhg|(CSRh@Zgm8q|<zxwBjEe@+Y?4)`5 z_^hOvOc)H)6_zhwKFifYM$BT>w0dD-;i7_q1?>r!T^JqiF>Y~`&ku~$n)>9)6PNkr zWo0aV%(AkwSFbQe?VrcI>tG7ghaW#87DwoC$*^0Qm@KKA$kn`r{mNQ_(!I4)(u^cS zPexh9dNCRnl$3nY5%^zqaE0&Eph;)bmIi2)Xdms4(Ob^-@!DPq?|?1)_pjHjT`jTN z%*?Fh?6+^*diwjzrxayP^l;H-$P;IF`1|hNx>brF1Y2cPBG;~8|61MD*!Z$#ZM4mg za~>02D_oXb&Q$l9>>&8++O=ybrKO>+GIDaKK725ke{=piZim7LX$z9_^ZmDN+h$^B zZf?q;I@vRH+onxQoi0wtPiAFhof4aF&UZzO`JKVkPU+^4D>iloux4atdNTKKWV?N< zeE<2Kzr{{)Kkf}%>7cOSzMQ=2Qof}P0baWf+_>`o`)#eSkC!H$=Y4&c%O;6A=!mhy z93!(c=gz&V*gbER({_vH)4uUZT>icCLrvZt5iNV&zhzJB->zD?ZQj4_2Wq3f-Ha_b uYiuvbU^nwe)}!5>`L@No>K6ZF+<g7U#tGi9wHO!}7(8A5T-G@yGywq3?4VTu diff --git a/src/org/controlsfx/control/format-indent-more.png b/src/org/controlsfx/control/format-indent-more.png deleted file mode 100644 index d57376f6bbfd8bda976f998f1436a5bf2a801578..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 532 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s77>k44ofy`glX=O&z`&C3 z=<CS9u(6-}Pa-P=0|RG)M`SSr1K(i~W;~w1B87p0L8`<xq9iy!t)x7$D3u`~F*C13 z&(AePq0Cs%RL{`B;7id$1_s7vPZ!4!3;(&7yuFzMCD<N(?vCQ+j5XVKVnO!{m+vo) z!h(GSrwT4ib5UH|%(YY@OZaYB;FI$LF&y`1%*;8ay=X`EV;Ko?Q>ASc33m6Uf0pHQ zzGr{0W%uvfH5Nskelho3dXGPEFDxo7U8mjE<hJ;tplj%dPrpJ`8W-?CE&3Vnl)hZy zH+!{)ShvrMH%oLkd&|z3Y0P<_w=h7%;A_=h-Ob*te6<Rno>}o6PFQ0Wl=e@0uWjVS zX$xOl1+TuUGxKM@_3qmW+})o~JT2<E|Gs_Is<S)0U*~l`lb&sK;>#Hk6W`>j>S_f~ zA)!u|*{iQ+d7DhX7UuY)(EPR+uNB+O2Z0mLhRr^!w^c>2si&`3VfI<0FB?2m&iE}a zUK;fC@SC9GLpmMFCmMa!4!bO#|Kr!CS(~r&`k2h0F^6Fz|BZ=WOC^4J&%Xb%L~3c! zO4V7r@90g~_s>pc^2vHhIZ3vSH*=zN#FF*zcUIW&Ex-KJ*P?GTcT>U#8~*;|%<He; k7JJ*dXvXx^n}3-l0~Lx_1kGN<z`(%Z>FVdQ&MBb@04VI?T>t<8 diff --git a/src/org/controlsfx/control/format-line-spacing-triple.png b/src/org/controlsfx/control/format-line-spacing-triple.png deleted file mode 100644 index 8e80972978fabf98774a16acc6856b65137114c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 499 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s77>k44ofy`glX=O&z`&C3 z=<CS9u(6-}Pa-P=0|RG)M`SSr1K(i~W;~w1B87p0L8`<xq9iy!t)x7$D3u`~F*C13 z&(AePq0Cs%RL{`B;7id$1_s6?PZ!4!3;((2y}g+NCD<N(?vC=z%So1I*1agW+wW#X zq>qrApkkPd;M!)c#SUv+OQK!>@*iw{&?~u7GGC)(xA{Ki$4+dL(KctQf86_N(O&z% zrgP@<65G;x?$t);Gi_{^eYyU9I>YXryRV73I_|$O-@Qod$B&xqO;0?T-j>aty}_4n zlj!tt@q~7F_6)Pxf6@<sxXDv`?wtR@q>r{HQoMa^ZtuQUDF>=o&S99m*!n{0+{LVJ z+nVyun<-0QFzE$xlI-P}qq)~E3R}&4&#moz+KSE6QxA$w7YkS$W+^4H^YY6Dx8KfM zBw4C-J37JX0DowxWmH0n_O+z~H{Q%)pX${LHp4ZBt@!MY0KMt#`O1gWjjwQ?V?Q|O zvY$w|YaiPe-Kky~TceZ%&p-d(Xt_*ALxk)9qi;J7zA39Voqbkm{`r2@>8B6A{`${o v_St75u7Tn#j1LQL7<o>5wMpmqe+HW`JnpJ7i}@KC7#KWV{an^LB{Ts5DVxWY diff --git a/src/org/controlsfx/control/gridview.css b/src/org/controlsfx/control/gridview.css deleted file mode 100644 index ea2c3ca..0000000 --- a/src/org/controlsfx/control/gridview.css +++ /dev/null @@ -1,7 +0,0 @@ -.grid-view { - -fx-vertical-cell-spacing: 12; - -fx-horizontal-cell-spacing: 12; - -fx-cell-height: 64; - -fx-cell-width: 64; - -fx-horizontal-alignment: CENTER; -} diff --git a/src/org/controlsfx/control/info-overlay.css b/src/org/controlsfx/control/info-overlay.css deleted file mode 100644 index a18ded7..0000000 --- a/src/org/controlsfx/control/info-overlay.css +++ /dev/null @@ -1,15 +0,0 @@ -.info-overlay > .info-panel { - -fx-background-color: lightgray; - -fx-opacity: .75; - -fx-padding: 5 5 5 5; -} - -.info-panel > .info-panel > .expand-button { - -fx-padding: 0 0 0 0 ; - /*-fx-graphic: url("/helloworld/david/collapse.png");*/ -} - -.info-panel > .info-panel > .collapse-button { - -fx-padding: 0 0 0 0 ; - /*-fx-graphic: url("expand.png");*/ -} diff --git a/src/org/controlsfx/control/listselectionview.css b/src/org/controlsfx/control/listselectionview.css deleted file mode 100644 index c13cd77..0000000 --- a/src/org/controlsfx/control/listselectionview.css +++ /dev/null @@ -1,13 +0,0 @@ -.list-selection-view { - -fx-padding: 10px; -} - -.list-selection-view > .grid-pane { - -fx-vgap: 10px; - -fx-hgap: 10px; -} - -.list-selection-view > .grid-pane > .list-header-label { - -fx-font-size: 1.0em; - -fx-font-weight: bold; -} \ No newline at end of file diff --git a/src/org/controlsfx/control/maskerpane.css b/src/org/controlsfx/control/maskerpane.css deleted file mode 100644 index cf0c78d..0000000 --- a/src/org/controlsfx/control/maskerpane.css +++ /dev/null @@ -1,17 +0,0 @@ -.masker-pane {} - -.masker-pane .masker-glass { - -fx-background-color: rgba(0, 0, 0, .3); -} - -.masker-pane .masker-text { - -fx-text-fill: white; - -fx-font-weight: bold; -} - -.masker-pane .masker-center { - -fx-background-color: rgba(0, 0, 0, .6); - -fx-max-height: 1.50in; - -fx-padding: .25in; - -fx-background-radius: .1in; -} \ No newline at end of file diff --git a/src/org/controlsfx/control/masterdetailpane.css b/src/org/controlsfx/control/masterdetailpane.css deleted file mode 100644 index 82d11f1..0000000 --- a/src/org/controlsfx/control/masterdetailpane.css +++ /dev/null @@ -1,14 +0,0 @@ -.tab-pane > * > .master-detail-pane > .split-pane, -.split-pane > * > .master-detail-pane > .split-pane { - -fx-background-insets: 0, 0; - -fx-padding: 0; - } -.tab-pane.floating > * > .master-detail-pane > .split-pane { - -fx-background-insets: 0, 0; - -fx-padding: -1; -} -.titled-pane > * > * > .master-detail-pane > .split-pane { - -fx-background-color: null; - -fx-background-insets: 0, 0; - -fx-padding: 0; -} diff --git a/src/org/controlsfx/control/notificationpane.css b/src/org/controlsfx/control/notificationpane.css deleted file mode 100644 index 765ec1b..0000000 --- a/src/org/controlsfx/control/notificationpane.css +++ /dev/null @@ -1,103 +0,0 @@ -/****************************************************************************** - * - * Light theme - * - *****************************************************************************/ - -.notification-pane .notification-bar > .pane { - -fx-background-color: -fx-outer-border, -fx-inner-border, -fx-body-color; - -fx-padding: 0 7 0 7; -} - -.notification-pane.top .notification-bar > .pane { - -fx-background-insets: 0 0 0 0, 0 0 1 0, 0 0 2 0; -} - -.notification-pane.bottom .notification-bar > .pane { - -fx-background-insets: 0 0 0 0, 1 0 0 0, 2 0 0 0; -} - -.notification-pane .notification-bar > .pane .label { - -fx-font-size: 1.166667em; /*15px;*/ - -fx-text-fill: #292929; -} - - -/****************************************************************************** - * - * Dark theme - * - *****************************************************************************/ - -.notification-pane.dark .notification-bar > .pane { - -fx-background-color: linear-gradient(#595959, #474747 37%, #343434); -} - -.notification-pane.dark .notification-bar > .pane .label { - -fx-text-fill: #ebebeb; -} - - -/****************************************************************************** - * - * Drop shadow support - * - *****************************************************************************/ - -/* NotificationPane shows from the top, so put shadow at bottom of bar */ -.notification-pane.top .notification-bar > .pane { - -fx-effect: dropshadow(three-pass-box, rgba(0, 0, 0, 0.4), 11, 0.0, 0, 3); -} - -/* - * We could have a drop shadow at the top of the bar when it appears from the - * bottom, but it doesn't look right as the gradient is running in the opposite - * direction of the drop shadow. Therefore, the following is commented out, - * but it can always be re-enabled in the future if desired. - */ - /* -.notification-pane:bottom .notification-bar > .pane { - -fx-effect: dropshadow(three-pass-box, rgba(0, 0, 0, 0.4), 11, 0.0, 0, -3); -} -*/ - - - -/****************************************************************************** - * - * Close button - * - *****************************************************************************/ -.notification-pane .notification-bar > .pane .close-button { - -fx-background-color: transparent; - -fx-background-insets: 0; - -fx-background-radius: 2; - -fx-padding: 0 0 0 0; - -fx-alignment: center; -} - -.notification-pane .notification-bar > .pane .close-button:hover { - -fx-background-color: linear-gradient(#a3a3a3, #8b8b8b 34%, #777777 36%, #777777 63%, #8b8b8b 65%, #adadad); -} - -.notification-pane .notification-bar > .pane .close-button:pressed { - -fx-background-color: linear-gradient(#a3a3a3, #8b8b8b 34%, #777777 36%, #777777 63%, #8b8b8b 65%, #adadad); -} - -.notification-pane .notification-bar > .pane .close-button > .graphic { - -fx-background-color: #949494; - -fx-scale-shape: false; - -fx-padding: 4.5 4.5 4.5 4.5; /* Graphic is 9x9 px */ -} - -.notification-pane .notification-bar > .pane .close-button:hover > .graphic { - -fx-background-color: #fefeff; -} - -.notification-pane .notification-bar > .pane .close-button:pressed > .graphic { - -fx-background-color: #cfcfcf; -} - -.notification-pane .notification-bar > .pane .close-button > .graphic { - -fx-shape: "M395.992,296.758l1.794-1.794l7.292,7.292l-1.795,1.794 L395.992,296.758z M403.256,294.992l1.794,1.794l-7.292,7.292l-1.794-1.795 L403.256,294.992z"; -} \ No newline at end of file diff --git a/src/org/controlsfx/control/notificationpopup.css b/src/org/controlsfx/control/notificationpopup.css deleted file mode 100644 index a35fa15..0000000 --- a/src/org/controlsfx/control/notificationpopup.css +++ /dev/null @@ -1,79 +0,0 @@ -/****************************************************************************** - * - * Light theme - * - *****************************************************************************/ - -.notification-bar > .pane { - -fx-background-color: -fx-outer-border, -fx-inner-border, -fx-body-color; - -fx-padding: 7 7 7 7; - -fx-effect: dropshadow(three-pass-box, rgba(0, 0, 0, 0.4), 11, 0.0, 0, 3); - -fx-background-insets: 0, 1, 2; -} - -.notification-bar > .pane .title { - -fx-font-size: 1.166667em; /*15px;*/ - -fx-text-fill: #292929; - -fx-font-weight: bold; -} - -.notification-bar > .pane .label { - -fx-font-size: 1.166667em; /*15px;*/ - -fx-text-fill: #292929; - -fx-alignment: top-left; -} - -/****************************************************************************** - * - * Dark theme - * - *****************************************************************************/ - -.notification-bar.dark > .pane { - -fx-background-color: -fx-outer-border, -fx-inner-border, linear-gradient(#595959, #474747 37%, #343434); -} - -.notification-bar.dark > .pane .title, -.notification-bar.dark > .pane .label { - -fx-text-fill: #ebebeb; -} - - -/****************************************************************************** - * - * Close button - * - *****************************************************************************/ - .notification-bar > .pane .close-button { - -fx-background-color: transparent; - -fx-background-insets: 0; - -fx-background-radius: 2; - -fx-padding: 0 0 0 0; - -fx-alignment: center; -} - -.notification-bar > .pane .close-button:hover { - -fx-background-color: linear-gradient(#a3a3a3, #8b8b8b 34%, #777777 36%, #777777 63%, #8b8b8b 65%, #adadad); -} - -.notification-bar > .pane .close-button:pressed { - -fx-background-color: linear-gradient(#a3a3a3, #8b8b8b 34%, #777777 36%, #777777 63%, #8b8b8b 65%, #adadad); -} - -.notification-bar > .pane .close-button > .graphic { - -fx-background-color: #949494; - -fx-scale-shape: false; - -fx-padding: 4.5 4.5 4.5 4.5; /* Graphic is 9x9 px */ -} - -.notification-bar > .pane .close-button:hover > .graphic { - -fx-background-color: #fefeff; -} - -.notification-bar > .pane .close-button:pressed > .graphic { - -fx-background-color: #cfcfcf; -} - -.notification-bar > .pane .close-button > .graphic { - -fx-shape: "M395.992,296.758l1.794-1.794l7.292,7.292l-1.795,1.794 L395.992,296.758z M403.256,294.992l1.794,1.794l-7.292,7.292l-1.794-1.795 L403.256,294.992z"; -} \ No newline at end of file diff --git a/src/org/controlsfx/control/open-editor.png b/src/org/controlsfx/control/open-editor.png deleted file mode 100644 index 87d22c3c98b41d3264f0b8fc48f72517e2b184ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 238 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s77>k44ofy`glX=O&z`&C3 z=<CS9u(6-}Pa-P=0|RG)M`SSr1LH0bW_+=l5u{P7#5JNMI6tkVJh3R1As{g`uSCz! zHAJDzSkF|?(7@nJ(Lx3WhFDJ*#}Etu<ccpZ1l0xD89vqvZT$8B|9?pbwvYv$0^RzD zcn+v}ipZHZ++x#-*zjO~b2IY{wKo1k8f*<Ji8CbZID)UUK6!93`9O6Er_#sj8H`>T kLPwG={{R2qn1SKb*8Izc_M7f7FfcH9y85}Sb4q9e04=>t^Z)<= diff --git a/src/org/controlsfx/control/package-info.java b/src/org/controlsfx/control/package-info.java deleted file mode 100644 index f22fac2..0000000 --- a/src/org/controlsfx/control/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -/** - * A package containing a number of useful controls-related classes that do not - * exist in the base JavaFX distribution. - */ -package org.controlsfx.control; \ No newline at end of file diff --git a/src/org/controlsfx/control/plusminusslider.css b/src/org/controlsfx/control/plusminusslider.css deleted file mode 100644 index 86cb6f1..0000000 --- a/src/org/controlsfx/control/plusminusslider.css +++ /dev/null @@ -1,57 +0,0 @@ -.plus-minus-slider { - -fx-background-radius: 2.0; - -fx-border-color: -fx-box-border; - -fx-border-radius: 2.0; -} - -.plus-minus-slider:horizontal { - -fx-background-color: derive(-fx-box-border,30.0%), linear-gradient(to bottom, derive(-fx-base,-3.0%), derive(-fx-base,5.0%) 50.0%, derive(-fx-base,-3.0%)); - -fx-background-insets: 0.0, 1.0 0.0 1.0 0.0; - -fx-pref-height: 16.0; - -fx-max-height: 16.0; -} - -.plus-minus-slider:vertical { - -fx-background-color: derive(-fx-box-border,30.0%), linear-gradient(to right, derive(-fx-base,-3.0%), derive(-fx-base,5.0%) 50.0%, derive(-fx-base,-3.0%)); - -fx-background-insets: 0.0, 0.0 1.0 0.0 1.0; - -fx-pref-width: 16.0; - -fx-max-width: 16.0; -} - -.plus-minus-slider > * > .slider { - -fx-show-tick-marks: false; -} - -.plus-minus-slider > * > .slider > .track { - -fx-background-color: transparent; -} - -.plus-minus-slider > * > .slider > .thumb { - -fx-background-color: -fx-outer-border, -fx-inner-border, -fx-body-color; - -fx-background-insets: 2.0, 3.0, 4.0; - -fx-background-radius: 3.0, 2.0, 1.0; -} - -.plus-minus-slider > * > .slider:focused > .thumb { - -fx-background-color: -fx-focus-color, -fx-inner-border, -fx-body-color, -fx-faint-focus-color, -fx-body-color; - -fx-background-insets: 1.8, 3.0, 4.0, 0.6, 4.6; - -fx-background-radius: 3.0, 2.0, 1.0, 4.0, 1.0; -} - -.plus-minus-slider > * > .adjust-plus { - -fx-pref-width: 16.0; - -fx-pref-height: 16.0; - -fx-shape: "M0,3 H3 V0 H5 V3 H8 V5 H5 V8 H3 V5 H0 V3 Z"; - -fx-scale-shape: false; - -fx-effect: dropshadow(two-pass-box , -fx-shadow-highlight-color, 1.0, 0.0 , 0.0, 1.4); - -fx-background-color: -fx-mark-highlight-color,derive(-fx-base,-45.0%); -} - -.plus-minus-slider > * > .adjust-minus { - -fx-pref-width: 16.0; - -fx-pref-height: 16.0; - -fx-shape: "M0,0H8V2H0Z"; - -fx-scale-shape: false; - -fx-effect: dropshadow(two-pass-box , -fx-shadow-highlight-color, 1.0, 0.0 , 0.0, 1.4); - -fx-background-color: -fx-mark-highlight-color,derive(-fx-base,-45.0%); -} diff --git a/src/org/controlsfx/control/popover.css b/src/org/controlsfx/control/popover.css deleted file mode 100644 index c9dd527..0000000 --- a/src/org/controlsfx/control/popover.css +++ /dev/null @@ -1,36 +0,0 @@ -.popover { - -fx-background-color: transparent; -} - -.popover > .border { - -fx-stroke: linear-gradient(to bottom, rgba(0,0,0, .3), rgba(0, 0, 0, .7)) ; - -fx-stroke-width: 0.5; - -fx-fill: rgba(255.0,255.0,255.0, .95); - -fx-effect: dropshadow(gaussian, rgba(0,0,0,.2), 10.0, 0.5, 2.0, 2.0); -} - -.popover > .content { -} - -.popover > .detached { -} - -.popover > .content > .title > .text { - -fx-padding: 6.0 6.0 0.0 6.0; - -fx-text-fill: rgba(120, 120, 120, .8); - -fx-font-weight: bold; -} - -.popover > .content > .title > .icon { - -fx-padding: 6.0 0.0 0.0 10.0; -} - -.popover > .content > .title > .icon > .graphics > .circle { - -fx-fill: gray ; - -fx-effect: innershadow(gaussian, rgba(0,0,0,.2), 3, 0.5, 1.0, 1.0); -} - -.popover > .content > .title > .icon > .graphics > .line { - -fx-stroke: white ; - -fx-stroke-width: 2; -} \ No newline at end of file diff --git a/src/org/controlsfx/control/propertysheet.css b/src/org/controlsfx/control/propertysheet.css deleted file mode 100644 index 3846aca..0000000 --- a/src/org/controlsfx/control/propertysheet.css +++ /dev/null @@ -1,15 +0,0 @@ -/* Remove extraneous borders from PropertySheet */ - -.property-sheet .scroll-pane .property-pane { - -fx-background-color: -fx-background; -} - -.property-sheet .scroll-pane { - -fx-background-color: -fx-background; - -fx-background-insets: 0; - -fx-padding: 0; -} - -.property-sheet .scroll-pane .accordion { - -fx-padding: -1; -} diff --git a/src/org/controlsfx/control/rangeslider.css b/src/org/controlsfx/control/rangeslider.css deleted file mode 100644 index 373e9d5..0000000 --- a/src/org/controlsfx/control/rangeslider.css +++ /dev/null @@ -1,86 +0,0 @@ - -/******************************************************************************* - * * - * RangeSlider * - * (Largely derived from Modena styles) * - * * - ******************************************************************************/ - -.range-slider .low-thumb, -.range-slider .high-thumb { - -fx-background-color: - linear-gradient(to bottom, derive(-fx-text-box-border, -20%), derive(-fx-text-box-border, -30%)), - -fx-inner-border, - -fx-body-color; - -fx-background-insets: 0, 1, 2; - -fx-background-radius: 1.0em; /* makes sure this remains circular */ - -fx-padding: 0.583333em; /* 7 */ - -fx-effect: dropshadow(two-pass-box , rgba(0, 0, 0, 0.1), 5, 0.0 , 0, 2); -} - -.range-slider:focused .low-thumb, -.range-slider:focused .high-thumb { - -fx-background-radius: 1.0em; /* makes sure this remains circular */ -} - -.range-slider .low-thumb:focused, -.range-slider .high-thumb:focused { - -fx-background-color: - -fx-focus-color, - derive(-fx-color,-36%), - derive(-fx-color,73%), - linear-gradient(to bottom, derive(-fx-color,-19%),derive(-fx-color,61%)); - -fx-background-insets: -1.4, 0, 1, 2; - -fx-background-radius: 1.0em; /* makes sure this remains circular */ -} - -.range-slider .low-thumb:hover, -.range-slider .high-thumb:hover { - -fx-color: -fx-hover-base; -} - -.range-slider .range-bar { - -fx-background-color: -fx-focus-color; -} - -.range-slider .low-thumb:pressed, -.range-slider .high-thumb:pressed { - -fx-color: -fx-pressed-base; -} - -.range-slider .track { - -fx-background-color: - -fx-shadow-highlight-color, - linear-gradient(to bottom, derive(-fx-text-box-border, -10%), -fx-text-box-border), - linear-gradient(to bottom, - derive(-fx-control-inner-background, -9%), - derive(-fx-control-inner-background, 0%), - derive(-fx-control-inner-background, -5%), - derive(-fx-control-inner-background, -12%) - ); - -fx-background-insets: 0 0 -1 0, 0, 1; - -fx-background-radius: 0.25em, 0.25em, 0.166667em; /* 3 3 2 */ - -fx-padding: 0.25em; /* 3 */ -} - -.range-slider:vertical .track { - -fx-background-color: - -fx-shadow-highlight-color, - -fx-text-box-border, - linear-gradient(to right, - derive(-fx-control-inner-background, -9%), - -fx-control-inner-background, - derive(-fx-control-inner-background, -9%) - ); -} - -.range-slider .axis { - -fx-tick-label-fill: derive(-fx-text-background-color, 30%); - -fx-tick-length: 5px; - -fx-minor-tick-length: 3px; - -fx-border-color: null; -} - -.range-slider:disabled { - -fx-opacity: 0.4; -} diff --git a/src/org/controlsfx/control/rating.css b/src/org/controlsfx/control/rating.css deleted file mode 100644 index 393379d..0000000 --- a/src/org/controlsfx/control/rating.css +++ /dev/null @@ -1,15 +0,0 @@ -.rating > .container { - -fx-spacing: 4; -} -.rating > .container > .button { - -fx-background-color: transparent; - -fx-background-image: url("unselected-star.png"); - -fx-padding: 16 16; - -fx-background-image-repeat: no-repeat; -} -.rating > .container > .button.strong { - -fx-background-image: url("selected-star.png"); -} -.rating > .container > .button:hover { - -fx-effect: dropshadow( three-pass-box , rgba(0,0,0,0.6) , 8, 0.0 , 0 , 0 ); -} \ No newline at end of file diff --git a/src/org/controlsfx/control/segmentedbutton.css b/src/org/controlsfx/control/segmentedbutton.css deleted file mode 100644 index 0e90a1d..0000000 --- a/src/org/controlsfx/control/segmentedbutton.css +++ /dev/null @@ -1,79 +0,0 @@ -/* -------- Segmented Button ---------------- */ -.segmented-button.dark .toggle-button { - -fx-padding: 3 15 3 15; - -fx-border-color: transparent -fx-outer-border transparent transparent; -} - -.segmented-button.dark .toggle-button:focused { - -fx-background-color: - rgba(23,134,248,0.2), - -fx-focus-color, - -fx-inner-border, - -fx-body-color; -} - -.segmented-button.dark .toggle-button:selected Text { - -fx-effect: dropshadow( one-pass-box , rgba(0,0,0,0.9) , 2, 0.0 , 0 , 1 ); -} - -.segmented-button.dark .toggle-button:selected { - -fx-background-color: - -fx-shadow-highlight-color, - linear-gradient( to bottom, derive(-fx-color,-90%) 0%, derive(-fx-color,-60%) 100% ), - linear-gradient( to bottom, derive(-fx-color,-60%) 0%, derive(-fx-color,-35%) 50%, derive(-fx-color,-30%) 98%, derive(-fx-color,-50%) 100% ), - linear-gradient( to right, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0) 10%, rgba(0,0,0,0) 90%, rgba(0,0,0,0.3) 100% ); - -fx-background-insets: 0 0 -1 0, 0, 1, 1; - /* TODO: -fx-text-fill should be derived */ - -fx-text-fill: -fx-light-text-color; -} - -/* *************************** LEFT BUTTON ************************** */ -.segmented-button.dark .toggle-button.left-pill { - -fx-background-radius: 3 0 0 3; - -fx-background-insets: 0 0 -1 0, 0, 1 0 1 1, 2 0 2 2; -} - -.segmented-button.dark .toggle-button.left-pill:focused { - -fx-background-insets: -2 0 -2 -2, 0 0 0 0, 1, 2; - -fx-border-color: transparent; -} - -.segmented-button.dark .toggle-button.left-pill:selected:focused { - -fx-background-insets: 0 0 -1 0, 0, 1 0 1 1, 1 0 1 1; - -fx-border-color: transparent; -} - -/* *************************** RIGHT BUTTON ************************** */ -.segmented-button.dark .toggle-button.right-pill { - -fx-background-radius: 0 3 3 0; - -fx-background-insets: 0 0 -1 0, 0, 1 1 1 0, 2 2 2 0; - -fx-border-color: transparent; -} - -.segmented-button.dark .toggle-button.right-pill:focused { - -fx-background-insets: -2 -2 -2 0, 0, 1, 2; - -fx-border-color: transparent; -} - -.segmented-button.dark .toggle-button.right-pill:selected:focused { - -fx-background-insets: -1 -1 -1 -1, 0 0 0 -1, 1 1 1 0, 1 1 1 0; - -fx-border-color: transparent; -} - -/* *************************** CENTER BUTTON ************************** */ -.segmented-button.dark .toggle-button.center-pill { - -fx-background-radius: 0; - -fx-background-insets: 0 0 -1 0, 0, 1 0 1 0, 2 0 2 0; - -} - -.segmented-button.dark .toggle-button.center-pill:focused { - -fx-background-radius: 0; - -fx-background-insets: -2 0 -2 -2, 0 0 0 -1, 1 1 1 0, 2 2 2 1; - -fx-border-color: transparent; -} - -.segmented-button.dark .toggle-button.center-pill:selected:focused { - -fx-background-insets: -1.4 0 -1.4 -1, 0 0 0 -1, 1 1 1 0, 1 1 1 0; - -fx-border-color: transparent; -} \ No newline at end of file diff --git a/src/org/controlsfx/control/selected-star.png b/src/org/controlsfx/control/selected-star.png deleted file mode 100644 index 01b0fc0457913c694471b844d50ed84418790b24..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2118 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`MwVKyBnAcs$r9IylHmNblJdl&R0hYC z{G?O`&)mfH)S%SFl*+=BsWuD@>@PfB978H@CH?vT-=5hh;a2on_Ow6yrtnTnWGvQO z@+bXIVfVxLbASE!QDAgyi|0ABsE8-sOgEW<L&1&5*x|_6(7^wVX|9c~-$Fjd{VF~2 z$)1Dx<|PH^uQPu9_;38@Kl7w|E&&GxQ67cjgdfM7RsT=?sUUlGy}oXi;IxZrKfY&4 zG8-SZZ?oUN?qB*Oue6Ga8a-y^6D$G&=BEGjHP4?oaOB{z5ATobw=rj*%VFjEZE$eT z_s{bD%-t937}eI!y>nJqy=RMU(q6|$42&%g`AZJ8oMHU+R#(7VxqG8R@tZ}(EfSVT z<~KNVrybg9dG7!J+Uj5b-ye?rFFA7`v-3B_!}rB+|F5queD!}{)WQD==709y|NsB} z;;lSBIRd@^XSzz<s}oI{P%!5-$M<D>*FUUJlPfd${hmLpt@$;-vC?iwCZA1QOk4l6 zJ<4CP@5j&I^^dPzeLl?~bIqf~OEKrm6Ao`&ua`UjU=af&%XTLA1hz-g4r{uCS*ubG z83e>U{eCy{e|_v~X4Pi<8&?_(Zm^zPJAVSR^ppvo-U_ci^Y4GnxdR+tW@l=6&d>Xo zv}14mH<tx>Vix>5ZSd7VUuK(s-qxT0|1w(aH8R+2U|_@?d!FS;&w&F>uHX0X=lTEt zAL}ItGhzF~r;qnb<jF*6_sFsNzuEJ4iR8b1=?O{fYzErK0rtu_R`TrsZ}jK);S(P| znHnEH8@&8$LzaHB3ai3|pC?azpWpnJn^{>pz}Q-wS^2_*{|;yWOV%43Y${+hmH)$Z zxo6^y289;p8S^9~j!MMs7f!jc{mG5iy`TBr=iL52qp?v~MDPvIrCGmhB7~I<;%<Jj zwMdD%C1%CEGrsW$ufTrhq=W@A%xY7zogB6)uxl%S@4x?Fv>~pZ;S#%m1IuS-MF$PV zx$H^B9ohzr7Qa5Ks4UDc7i$o@m>$!~(K7SHjem2#UT0?eJ;hHh;gQjSr5&uZ6#|;g z4H7s0{m*oU?SGxYiJ9(m+|NC=;AO}PVGlZ~#izNH$9}$}@=xyOMbm^l_)<LNFWm3G z$oz5tq*}4&8QbKU)%UX;{;$7X@?X6TgU>$u2_cNaqU~JF%Ii4|Y&{J3?A<*7;mMV) zJn!GloxxPZDE|5W^7}XJ->3Ze{ZN)!S>rGBXGUcM`vw!IQxXYYe>hEk+~!R<U}(%y zblNy(SNS8O3#L02nD^bc+Z5Q-s`_H;j3%4I|IHny|EuEtB6C6^L*oD6;~)OZ3o|cn zU}F~US3BHjY3koN>+6NfjdM2bd+40W>6Y;8KlhOXGAEe~AN-$R|KQJo11F9b6ns_; zcqP)dl=(?UP09C1KX>-X#5nYxnQ-RFF{Yzu5}5DT{W;BWxkp>-ZDS*YCi9FL2iO{8 z8MK%iwstkNsQg<rzqdR5>Hq!r1rpWt+Wz}E9mwHXWfpm`mCIQ91}mFI>;Zi>#u5gD z?M2*%F%|`r9{!!o-s$krN7p^v*wAo+<Nt%1C)qmm6HcG=;V*w>By(fKyW=;1*U!<O zR==M~gzf6$)snZa8LroV^z!1i4Zf^xOO-eD%xntMa!z(~oHL&@<oQjejd}vjHfMN` zFgfV(A8~Vd6Y%J8Ak!yZ9bqPx7ki_UW_2ujG56&c=f=8@+*?X!f;#fO^Ai-*5|Wg% zJTADTK0LJ5P-j(Q>Z4;vT*O^^xy$ly%#u(!aVXy7!jTC-6q`80f*luX{Gayd%DJBJ z`zo1TJ1*$W`SQ)wc&_F5yWihgrkiCyKg&0(Pxx`5p7~|73D*jo#n``HJ9<f3_pQ>q zU;h5@;|~7Le>SOQ#%W)Uy5)NoF0K82j)A2qZiP+ZOSXBhf9P{61blyYtl-A;<EB1t zj?rCB*Rvb<`mTNcF)DuB`N^9Y+;%oCY(5))`qNvZjFm4%k6pTC{Ge?2!f$uBTK$o? zT*4JI$z|ItC*H8L?%!?;t~gW7n!Vt{es-D0+JuQ4Yo8RlUAmJg)z5g0AxZ918-LyN ztA~<uI35WzZ!q}B_Uzcbr4{e@o|7^3Y!zBCv$VZ$yP1f523u~W&|~YOlqu%}E;?Tb z+aNJ-L!3ew%QUGt<1?axlSO~-VcEHd#ogX#-}}aX+v~qSKH7MOE5O=Td%b<+Tkgcu z%hJBGbkuR^`2I8Mo9I&I&b;E(>QI4+t9&?;Ha%XH^g5br26v*2$H|0LhoXc1=a~)e z+?G^aci`snYdVb=+wQP^50lB$`ur<q!P$O=h)JOmCj}f=T(Rg<3iteV=}Z4Aqt8n< zO%^Q|%2}bPIAiX_#1AL`O0f6kTn(SF@0)Cv%_~Fh!j_4VuB^+-l)T$Qj}_F5bn%@N zVvzonp}6Nw)gFhX$6nm;==gWFO*!S!q|;hi6Q{0JW;C8S*=1d%kX7}%NEO>jb#wok zMJp`z_@#Z3?LqX@Myu!Blvd>)<9lp9?@Qc-iWy&u+lmuK0}sAC!M^!yTx)t)k>`SA z4?jk;m>#uZe5X@WfAFbM^@SyDiG~l`9)<@S{CFgN=KQ0|*L=^iOfNRxKDbEw<CZfj zld|2)Tv{ftDF5|gp&9>*WlSBlvdx_r`8Sw+pWO0X>{#*R{lODE7=^Z3#-w+jUab%y z#S*xw@v?l&%Z>UaYqPzdP1|oLYPTciLgsd^-^zwhAMTCY`8hXa=0mmca~)gmF|B!+ zyQ_4;%VyIj=9bY?YnGS&^hp;9?Ka)2s?lljXr=V3hxa?@?wh;gfc(GicE%NHJ(AMR vy30>Yp6I47>b*nRGhZop^_Q*xelYvqa5&So|JND@1_lOCS3j3^P6<r_1&Q+1 diff --git a/src/org/controlsfx/control/snapshot-view.css b/src/org/controlsfx/control/snapshot-view.css deleted file mode 100644 index 1aeaeee..0000000 --- a/src/org/controlsfx/control/snapshot-view.css +++ /dev/null @@ -1,4 +0,0 @@ - -.snapshot-view { - -} \ No newline at end of file diff --git a/src/org/controlsfx/control/spreadsheet/Grid.java b/src/org/controlsfx/control/spreadsheet/Grid.java deleted file mode 100644 index 53ac9e8..0000000 --- a/src/org/controlsfx/control/spreadsheet/Grid.java +++ /dev/null @@ -1,200 +0,0 @@ -/** - * Copyright (c) 2013, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.spreadsheet; - -import java.util.Collection; -import javafx.collections.ObservableList; -import javafx.event.EventHandler; -import javafx.event.EventType; -import org.controlsfx.control.spreadsheet.SpreadsheetView.SpanType; - -/** - * That class holds some {@link SpreadsheetCell} in order - * to be used by the {@link SpreadsheetView}. - * - * A Grid is used by {@link SpreadsheetView} to represent the data to show on - * screen. A default implementation is provided by {@link GridBase}, but for - * more custom purposes (e.g. loading data on demand), this Grid interface may - * prove useful. - * - * <p>A Grid at its essence consists of rows and columns. Critical to the - * SpreadsheetView is that the {@link #getRowCount() row count} and - * {@link #getColumnCount() column count} are accurately returned when requested - * (even if the data returned by {@link #getRows()} is not all fully loaded into - * memory). - * - * <p>Whilst the {@link #getRows()} return type may appear confusing, it is - * actually quite logical when you think about it: {@link #getRows()} returns an - * ObservableList of ObservableList of {@link SpreadsheetCell} instances. In other - * words, this is your classic 2D collection, where the outer ObservableList - * can be thought of as the rows, and the inner ObservableList as the columns - * within each row. Therefore, if you are wanting to iterate through all columns - * in every row of the grid, you would do something like this: - * - * - * <h3> Code Sample </h3> - * <pre> - * Grid grid = ... - * for (int row = 0; row < grid.getRowCount(); row++) { - * for (int column = 0; column < grid.getColumnCount(); column++) { - * SpreadsheetCell<?> cell = getRows().get(row).get(column); - * doStuff(cell); - * } - * } - * - * </pre> - * - * @see SpreadsheetView - * @see GridBase - * @see SpreadsheetCell - */ -public interface Grid { - /** - * This value may be returned from {@link #getRowHeight(int) } in order to - * let the system compute the best row height. - */ - public static final double AUTOFIT = -1; - - /** - * @return how many rows are inside the grid. - */ - public int getRowCount(); - - /** - * @return how many columns are inside the grid. - */ - public int getColumnCount(); - - /** - * Return an ObservableList of ObservableList of {@link SpreadsheetCell} - * instances. Refer to the {@link Grid} class javadoc for more detail. - * @return an ObservableList of ObservableList of {@link SpreadsheetCell} - * instances - */ - public ObservableList<ObservableList<SpreadsheetCell>> getRows(); - - /** - * Change the value situated at the intersection if possible. - * Verification and conversion of the value should be done before - * with {@link SpreadsheetCellType#match(Object)} - * and {@link SpreadsheetCellType#convertValue(Object)}. - * @param row - * @param column - * @param value - */ - public void setCellValue(int row, int column, Object value); - - /** - * Return the {@link SpanType} for a given cell row/column intersection. - * @param spv - * @param row - * @param column - * @return the {@link SpanType} for a given cell row/column intersection. - */ - public SpanType getSpanType(final SpreadsheetView spv, final int row, final int column); - - /** - * Return the height of a row. {@link #AUTOFIT } can be returned in order to - * let the system compute the best row height. - * - * @param row - * @return the height of a row. - */ - public double getRowHeight(int row); - - /** - * Return true if the specified row is resizable. - * @param row - * @return true if the specified row is resizable. - */ - public boolean isRowResizable(int row); - - /** - * Returns an ObservableList of string to display in the row headers. - * - * @return an ObservableList of string to display in the row headers. - */ - public ObservableList<String> getRowHeaders(); - - /** - * Returns an ObservableList of string to display in the column headers. - * - * @return an ObservableList of string to display in the column headers. - */ - public ObservableList<String> getColumnHeaders(); - - /** - * Span in row the cell situated at rowIndex and colIndex by the number - * count - * - * @param count - * @param rowIndex - * @param colIndex - */ - public void spanRow(int count, int rowIndex, int colIndex); - - /** - * Span in column the cell situated at rowIndex and colIndex by the number - * count - * - * @param count - * @param rowIndex - * @param colIndex - */ - public void spanColumn(int count, int rowIndex, int colIndex); - - /** - * This method sets the rows used by the grid, and updates the rowCount. - * @param rows - */ - public void setRows(Collection<ObservableList<SpreadsheetCell>> rows); - - /** - * Registers an event handler to this Grid. The Grid class allows - * registration of listeners which will be notified as a {@link SpreadsheetCell}'s value - * will change. - * - * @param <E> - * @param eventType the type of the events to receive by the handler - * @param eventHandler the handler to register - * @throws NullPointerException if the event type or handler is null - */ - public <E extends GridChange> void addEventHandler(EventType<E> eventType, EventHandler<E> eventHandler); - - /** - * Unregisters a previously registered event handler from this Grid. One - * handler might have been registered for different event types, so the - * caller needs to specify the particular event type from which to - * unregister the handler. - * - * @param <E> - * @param eventType the event type from which to unregister - * @param eventHandler the handler to unregister - * @throws NullPointerException if the event type or handler is null - */ - public <E extends GridChange> void removeEventHandler(EventType<E> eventType, EventHandler<E> eventHandler); -} \ No newline at end of file diff --git a/src/org/controlsfx/control/spreadsheet/GridBase.java b/src/org/controlsfx/control/spreadsheet/GridBase.java deleted file mode 100644 index 16183e2..0000000 --- a/src/org/controlsfx/control/spreadsheet/GridBase.java +++ /dev/null @@ -1,414 +0,0 @@ -/** - * Copyright (c) 2013, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.spreadsheet; - -import com.sun.javafx.event.EventHandlerManager; -import impl.org.controlsfx.spreadsheet.GridViewSkin; -import java.util.BitSet; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import javafx.beans.Observable; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.event.Event; -import javafx.event.EventDispatchChain; -import javafx.event.EventHandler; -import javafx.event.EventTarget; -import javafx.event.EventType; -import javafx.util.Callback; -import org.controlsfx.control.spreadsheet.SpreadsheetView.SpanType; - -/** - * A base implementation of the {@link Grid} interface. - * - * <h3>Row Height</h3> - * - * You can specify some row height for some of your rows at the beginning. - * You have to use the method {@link #setRowHeightCallback(javafx.util.Callback) } - * in order to specify a Callback that will give you the index of the row, and you - * will give back the height of the row. - * <br> - * If you just have a {@link Map} available, you can use the {@link MapBasedRowHeightFactory} - * that will construct the Callback for you. - -* The default height is 24.0. - * - * <h3>Cell values</h3> - * <p> - * If you want to change the value of a cell, you have to go through the API - * with {@link #setCellValue(int, int, Object)}. This method will verify that - * the value is corresponding to the {@link SpreadsheetCellType} of the cell and - * try to convert it if possible. It will also fire a {@link GridChange} event - * in order to notify all listeners that a value has changed. <br> - * <p> - * If you want to listen to those changes, you can use the - * {@link #addEventHandler(EventType, EventHandler)} and - * {@link #removeEventHandler(EventType, EventHandler)} methods. <br> - * A basic listener for implementing a undo/redo in the SpreadsheetView could be - * like that: - * - * <pre> - * Grid grid = ...; - * Stack<GridChange> undoStack = ...; - * grid.addEventHandler(GridChange.GRID_CHANGE_EVENT, new EventHandler<GridChange>() { - * - * public void handle(GridChange change) { - * undoStack.push(change); - * } - * }); - * - * </pre> - * - * - * @see Grid - * @see GridChange - */ -public class GridBase implements Grid, EventTarget { - - /*************************************************************************** - * - * Private Fields - * - **************************************************************************/ - private final ObservableList<ObservableList<SpreadsheetCell>> rows; - - private int rowCount; - private int columnCount; - private Callback<Integer, Double> rowHeightFactory; - private final BooleanProperty locked; - private final EventHandlerManager eventHandlerManager = new EventHandlerManager(this); - private final ObservableList<String> rowsHeader; - private final ObservableList<String> columnsHeader; - private BitSet resizableRow; - - /*************************************************************************** - * - * Constructor - * - **************************************************************************/ - - /** - * Creates a grid with a fixed number of rows and columns. - * - * @param rowCount - * @param columnCount - */ - public GridBase(int rowCount, int columnCount) { - this.rowCount = rowCount; - this.columnCount = columnCount; - rowsHeader = FXCollections.observableArrayList(); - columnsHeader = FXCollections.observableArrayList(); - locked = new SimpleBooleanProperty(false); - rowHeightFactory = new MapBasedRowHeightFactory(new HashMap<>()); - rows = FXCollections.observableArrayList(); - rows.addListener((Observable observable) -> { - setRowCount(rows.size()); - }); - resizableRow = new BitSet(rowCount); - resizableRow.set(0, rowCount, true); - } - - /*************************************************************************** - * - * Public Methods (Inherited from Grid) - * - **************************************************************************/ - - /** {@inheritDoc} */ - @Override - public ObservableList<ObservableList<SpreadsheetCell>> getRows() { - return rows; - } - - /** {@inheritDoc} */ - @Override - public void setCellValue(int row, int column, Object value) { - if (row < rowCount && column < columnCount && !isLocked()) { - SpreadsheetCell cell = getRows().get(row).get(column); - Object previousItem = cell.getItem(); - Object convertedValue = cell.getCellType().convertValue(value); - cell.setItem(convertedValue); - if (!java.util.Objects.equals(previousItem, cell.getItem())) { - GridChange cellChange = new GridChange(row, column, previousItem, convertedValue); - Event.fireEvent(this, cellChange); - } - } - } - - /** {@inheritDoc} */ - @Override - public int getRowCount() { - return rowCount; - } - - /** {@inheritDoc} */ - @Override - public int getColumnCount() { - return columnCount; - } - - /** {@inheritDoc} */ - @Override - public SpanType getSpanType(final SpreadsheetView spv, final int row, final int column) { - if (row < 0 || column < 0 || row >= rowCount || column >= columnCount) { - return SpanType.NORMAL_CELL; - } - - final SpreadsheetCell cell = getRows().get(row).get(column); - - final int cellColumn = cell.getColumn(); - final int cellRow = cell.getRow(); - final int cellRowSpan = cell.getRowSpan(); - - if (cellColumn == column && cellRow == row && cellRowSpan == 1) { - return SpanType.NORMAL_CELL; - } - - final int cellColumnSpan = cell.getColumnSpan(); - /** - * This is a consuming operation so we place it after the normal_cell - * case since this is the most typical case. - */ - final GridViewSkin skin = spv.getCellsViewSkin(); - final boolean containsRowMinusOne = skin == null ? true : skin.containsRow(row - 1); - if (containsRowMinusOne && cellColumnSpan > 1 && cellColumn != column && cellRowSpan > 1 - && cellRow != row) { - return SpanType.BOTH_INVISIBLE; - } else if (cellRowSpan > 1 && cellColumn == column) { - if ((cellRow == row || !containsRowMinusOne)) { - return SpanType.ROW_VISIBLE; - } else { - return SpanType.ROW_SPAN_INVISIBLE; - } - } else if (cellColumnSpan > 1 && cellColumn != column && (cellRow == row || !containsRowMinusOne)) { - return SpanType.COLUMN_SPAN_INVISIBLE; - } else { - return SpanType.NORMAL_CELL; - } - } - - /** - * Return the height of a row. - * It will first look into the {@link Callback}provided at the - * initialization. If nothing's found, {@link #AUTOFIT} will be returned. - * @param row - * @return the height of a row. - */ - @Override - public double getRowHeight(int row) { - return rowHeightFactory.call((Integer) row); - } - - /*************************************************************************** - * - * Public Methods - * - **************************************************************************/ - - /** - * Set a new {@link Callback} for this grid in order to specify height of - * each row. - * - * @param rowHeight - */ - public void setRowHeightCallback(Callback<Integer, Double> rowHeight) { - this.rowHeightFactory = rowHeight; - } - - /** {@inheritDoc} */ - @Override - public ObservableList<String> getRowHeaders() { - return rowsHeader; - } - - /** {@inheritDoc} */ - @Override - public ObservableList<String> getColumnHeaders() { - return columnsHeader; - } - - /** - * Return a BooleanProperty associated with the locked grid state. It means - * that the Grid is in a read-only mode and that no SpreadsheetCell can be - * modified, no regards for their own - * {@link SpreadsheetCell#isEditable()} state. - * - * @return a BooleanProperty associated with the locked grid state. - */ - public BooleanProperty lockedProperty() { - return locked; - } - - /** - * Return whether this Grid id locked or not. - * - * @return whether this Grid id locked or not. - */ - public boolean isLocked() { - return locked.get(); - } - - /** - * Lock or unlock this Grid. - * - * @param lock - */ - public void setLocked(Boolean lock) { - locked.setValue(lock); - } - - /** {@inheritDoc} */ - @Override - public void spanRow(int count, int rowIndex, int colIndex) { - if (count <= 0 || count > rowCount || rowIndex >= rowCount || colIndex >= columnCount) { - return; - } - final SpreadsheetCell cell = rows.get(rowIndex).get(colIndex); - final int colSpan = cell.getColumnSpan(); - final int rowSpan = count; - cell.setRowSpan(rowSpan); - for (int row = rowIndex; row < rowIndex + rowSpan && row < rowCount; ++row) { - for (int col = colIndex; col < colIndex + colSpan && col < columnCount; ++col) { - if (row != rowIndex || col != colIndex) { - rows.get(row).set(col, cell); - } - } - } - } - - /** {@inheritDoc} */ - @Override - public void spanColumn(int count, int rowIndex, int colIndex) { - if (count <= 0 || count > columnCount || rowIndex >= rowCount || colIndex >= columnCount) { - return; - } - final SpreadsheetCell cell = rows.get(rowIndex).get(colIndex); - final int colSpan = count; - final int rowSpan = cell.getRowSpan(); - cell.setColumnSpan(colSpan); - for (int row = rowIndex; row < rowIndex + rowSpan && row < rowCount; ++row) { - for (int col = colIndex; col < colIndex + colSpan && col < columnCount; ++col) { - if (row != rowIndex || col != colIndex) { - rows.get(row).set(col, cell); - } - } - } - } - - /** {@inheritDoc} */ - @Override - public void setRows(Collection<ObservableList<SpreadsheetCell>> rows) { - this.rows.clear(); - this.rows.addAll(rows); - - setRowCount(rows.size()); - setColumnCount(rowCount == 0 ? 0 : this.rows.get(0).size()); - } - - /** - * Sets the resizable state of all rows. If a bit is set to true in the - * BitSet, it means the row is resizable. - * - * The {@link BitSet#length() } must be equal to the {@link #getRowCount() } - * - * @param resizableRow - */ - public void setResizableRows(BitSet resizableRow) { - this.resizableRow = resizableRow; - } - - /** {@inheritDoc} */ - @Override - public boolean isRowResizable(int row) { - return resizableRow.get(row); - } - - /** {@inheritDoc} */ - @Override - public <E extends GridChange> void addEventHandler(EventType<E> eventType, EventHandler<E> eventHandler) { - eventHandlerManager.addEventHandler(eventType, eventHandler); - } - - /** {@inheritDoc} */ - @Override - public <E extends GridChange> void removeEventHandler(EventType<E> eventType, EventHandler<E> eventHandler) { - eventHandlerManager.removeEventHandler(eventType, eventHandler); - } - - /** {@inheritDoc} */ - @Override - public EventDispatchChain buildEventDispatchChain(EventDispatchChain tail) { - return tail.append(eventHandlerManager); - } - - /*************************************************************************** - * - * Private implementation - * - **************************************************************************/ - - /** - * Set a new rowCount for the grid. - * - * @param rowCount - */ - private void setRowCount(int rowCount) { - this.rowCount = rowCount; - } - - /** - * Set a new columnCount for the grid. - * - * @param columnCount - */ - private void setColumnCount(int columnCount) { - this.columnCount = columnCount; - } - - /** - * This class serves as a bridge between row height Callback needed by the - * GridBase and a Map<Integer,Double> that one could have (each Integer - * specify a row index and its associated height). - */ - public static class MapBasedRowHeightFactory implements Callback<Integer, Double> { - private final Map<Integer, Double> rowHeightMap; - - public MapBasedRowHeightFactory(Map<Integer, Double> rowHeightMap) { - this.rowHeightMap = rowHeightMap; - } - - @Override - public Double call(Integer index) { - Double value = rowHeightMap.get(index); - return value == null ? AUTOFIT : value; - } - - } -} diff --git a/src/org/controlsfx/control/spreadsheet/GridChange.java b/src/org/controlsfx/control/spreadsheet/GridChange.java deleted file mode 100644 index c8ee2ff..0000000 --- a/src/org/controlsfx/control/spreadsheet/GridChange.java +++ /dev/null @@ -1,126 +0,0 @@ -/** - * Copyright (c) 2013, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. * Redistributions in binary - * form must reproduce the above copyright notice, this list of conditions and - * the following disclaimer in the documentation and/or other materials provided - * with the distribution. * Neither the name of ControlsFX, any associated - * website, nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.spreadsheet; - -import java.io.Serializable; - -import javafx.event.Event; -import javafx.event.EventType; - -/** - * This class represents a single change happening in a {@link Grid}. - * - * @see Grid - * @see GridBase - */ -public class GridChange extends Event implements Serializable { - - /** - * This is the event used by {@link GridChange}. - */ - public static final EventType<GridChange> GRID_CHANGE_EVENT = new EventType<>(Event.ANY, "GridChange"); //$NON-NLS-1$ - - /** - * ************************************************************************* - * * Static field * * - ************************************************************************* - */ - private static final long serialVersionUID = 210644901287223524L; - - /** - * ************************************************************************* - * * Private Fields * * - ************************************************************************* - */ - private final int row; - private final int column; - private final Object oldValue; - private final Object newValue; - - /** - * ************************************************************************* - * * Constructor * - ************************************************************************* - */ - /** - * Constructor of a GridChange when a change inside a - * {@link SpreadsheetCell} is happening. - * - * @param row - * @param column - * @param oldValue - * @param newValue - */ - public GridChange(int row, int column, Object oldValue, Object newValue) { - super(GRID_CHANGE_EVENT); - this.row = row; - this.column = column; - this.oldValue = oldValue; - this.newValue = newValue; - } - - /** - * ************************************************************************* - * * Public methods * * - ************************************************************************* - */ - /** - * Return the row number of this change. - * - * @return the row number of this change. - */ - public int getRow() { - return row; - } - - /** - * Return the column number of this change. - * - * @return the column number of this change. - */ - public int getColumn() { - return column; - } - - /** - * Return the value before the change. - * - * @return the value before the change. - */ - public Object getOldValue() { - return oldValue; - } - - /** - * Return the value after the change. - * - * @return the value after the change. - */ - public Object getNewValue() { - return newValue; - } -} diff --git a/src/org/controlsfx/control/spreadsheet/Picker.java b/src/org/controlsfx/control/spreadsheet/Picker.java deleted file mode 100644 index 0c2762d..0000000 --- a/src/org/controlsfx/control/spreadsheet/Picker.java +++ /dev/null @@ -1,93 +0,0 @@ -/** - * Copyright (c) 2014, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.spreadsheet; - -import java.util.Collection; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; - -/** - * - * Pickers can display some Images next to the headers. <br> - * You can specify the image by providing custom StyleClass :<br> - * - * <pre> - * .picker-label{ - * -fx-graphic: url("add.png"); - * -fx-background-color: white; - * -fx-padding: 0 0 0 0; - * } - * </pre> - * - * The {@link #onClick() } method does nothing by default, so you can override it - * if you want to execute a custom action when the user will click on your Picker. - * - * <h3>Visual:</h3> <center><img src="pickers.PNG" alt="Screenshot of Picker"></center> - * - */ -public class Picker { - - private final ObservableList<String> styleClass = FXCollections.observableArrayList(); - - /** - * Default constructor, the default "picker-label" styleClass is applied. - */ - public Picker() { - this("picker-label"); //$NON-NLS-1$ - } - - /** - * Initialize this Picker with the style classes provided. - * @param styleClass - */ - public Picker(String... styleClass) { - this.styleClass.addAll(styleClass); - } - - /** - * Initialize this Picker with the style classes provided. - * @param styleClass - */ - public Picker(Collection<String> styleClass) { - this.styleClass.addAll(styleClass); - } - - - /** - * @return the style class of this picker. - */ - public final ObservableList<String> getStyleClass() { - return styleClass; - } - - /** - * This method will be called whenever the user clicks on this picker. - */ - public void onClick(){ - //no-op by default - } -} diff --git a/src/org/controlsfx/control/spreadsheet/SpreadsheetCell.java b/src/org/controlsfx/control/spreadsheet/SpreadsheetCell.java deleted file mode 100644 index 29bb9ad..0000000 --- a/src/org/controlsfx/control/spreadsheet/SpreadsheetCell.java +++ /dev/null @@ -1,333 +0,0 @@ -/** - * Copyright (c) 2014, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.spreadsheet; - -import java.util.Optional; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.ReadOnlyStringProperty; -import javafx.beans.property.StringProperty; -import javafx.collections.ObservableSet; -import javafx.event.Event; -import javafx.event.EventHandler; -import javafx.event.EventType; -import javafx.scene.Node; - -/** - * - * Interface of the cells used in the {@link SpreadsheetView}. - * - * See {@link SpreadsheetCellBase} for a complete and detailed documentation. - * @see SpreadsheetCellBase - */ -public interface SpreadsheetCell { - /** - * This EventType can be used with an {@link EventHandler} in order to catch - * when the editable state of a SpreadsheetCell is changed. - */ - public static final EventType EDITABLE_EVENT_TYPE = new EventType("EditableEventType"); //$NON-NLS-1$ - - /** - * This EventType can be used with an {@link EventHandler} in order to catch - * when the wrap text state of a SpreadsheetCell is changed. - */ - public static final EventType WRAP_EVENT_TYPE = new EventType("WrapTextEventType"); //$NON-NLS-1$ - - /** - * This EventType can be used with an {@link EventHandler} in order to catch - * when a corner state of a SpreadsheetCell is changed. - */ - public static final EventType CORNER_EVENT_TYPE = new EventType("CornerEventType"); //$NON-NLS-1$ - - /** - * This enum states the four different corner available for positioning - * some elements in a cell. - */ - public static enum CornerPosition { - - TOP_LEFT , - TOP_RIGHT , - BOTTOM_RIGHT , - BOTTOM_LEFT - } - - /** - * Verify that the upcoming cell value can be set to the current cell. This - * is currently used by the Copy/Paste. - * - * @param cell - * @return true if the upcoming cell value can be set to the current cell. - */ - public boolean match(SpreadsheetCell cell); - - /** - * Sets the value of the property Item. This should be used only at - * initialization. Prefer {@link Grid#setCellValue(int, int, Object)} after - * because it will compute correctly the modifiedCell. If - * {@link #isEditable()} return false, nothing is done. - * - * @param value - */ - public void setItem(Object value); - - /** - * Return the value contained in the cell. - * - * @return the value contained in the cell. - */ - public Object getItem(); - - /** - * The item property represents the currently-set value inside this - * SpreadsheetCell instance. - * - * @return the item property which contains the value. - */ - public ObjectProperty<Object> itemProperty(); - - /** - * Return if this cell can be edited or not. - * - * @return true if this cell is editable. - */ - public boolean isEditable(); - - /** - * Change the editable state of this cell - * - * @param editable - */ - public void setEditable(boolean editable); - - /** - * If a run of text exceeds the width of the Labeled, then this variable - * indicates whether the text should wrap onto another line. - * - * @return the value of wrapText property. - */ - public boolean isWrapText(); - - /** - * If a run of text exceeds the width of the Labeled, then this variable - * indicates whether the text should wrap onto another line. - * @param wrapText - */ - public void setWrapText(boolean wrapText); - - /** - * A string representation of the CSS style associated with this specific - * Node. This is analogous to the "style" attribute of an HTML element. Note - * that, like the HTML style attribute, this variable contains style - * properties and values and not the selector portion of a style rule. - * - * @param style - */ - public void setStyle(String style); - - /** - * A string representation of the CSS style associated with this specific - * Node. This is analogous to the "style" attribute of an HTML element. Note - * that, like the HTML style attribute, this variable contains style - * properties and values and not the selector portion of a style rule. - * - * @return The inline CSS style associated with this Node. If this Node does - * not have an inline style, an empty String is returned. - */ - public String getStyle(); - - /** - * A string representation of the CSS style associated with this specific - * Node. This is analogous to the "style" attribute of an HTML element. Note - * that, like the HTML style attribute, this variable contains style - * properties and values and not the selector portion of a style rule. - * - * @return a string representation of the CSS style - */ - public StringProperty styleProperty(); - - /** - * This activate the given cornerPosition. - * @param position - */ - public void activateCorner(CornerPosition position); - - /** - * This deactivate the given cornerPosition. - * @param position - */ - public void deactivateCorner(CornerPosition position); - - /** - * - * @param position - * @return the current state of a specific corner. - */ - public boolean isCornerActivated(CornerPosition position); - - /** - * The {@link StringProperty} linked with the format. - * - * @return The {@link StringProperty} linked with the format state. - */ - public StringProperty formatProperty(); - - /** - * Return the format of this cell or an empty string if no format has been - * specified. - * - * @return Return the format of this cell or an empty string if no format - * has been specified. - */ - public String getFormat(); - - /** - * Set a new format for this Cell. You can specify how to represent the - * value in the cell. - * - * @param format - */ - public void setFormat(String format); - - /** - * Return the StringProperty of the representation of the value. - * - * @return the StringProperty of the representation of the value. - */ - public ReadOnlyStringProperty textProperty(); - - /** - * Return the String representation currently used for display in the - * {@link SpreadsheetView}. - * - * @return text representation of the value. - */ - public String getText(); - - /** - * Return the {@link SpreadsheetCellType} of this particular cell. - * - * @return the {@link SpreadsheetCellType} of this particular cell. - */ - public SpreadsheetCellType getCellType(); - - /** - * Return the row of this cell. - * - * @return the row of this cell. - */ - public int getRow(); - - /** - * Return the column of this cell. - * - * @return the column of this cell. - */ - public int getColumn(); - - /** - * Return how much this cell is spanning in row, 1 is normal. - * - * @return how much this cell is spanning in row, 1 is normal. - */ - public int getRowSpan(); - - /** - * Sets how much this cell is spanning in row. See {@link SpreadsheetCell} - * description for information. You should use - * {@link Grid#spanRow(int, int, int)} instead of using this method - * directly. - * - * @param rowSpan - */ - public void setRowSpan(int rowSpan); - - /** - * Return how much this cell is spanning in column, 1 is normal. - * - * @return how much this cell is spanning in column, 1 is normal. - */ - public int getColumnSpan(); - - /** - * Sets how much this cell is spanning in column. See - * {@link SpreadsheetCell} description for information. You should use - * {@link Grid#spanColumn(int, int, int)} instead of using this method - * directly. - * - * @param columnSpan - */ - public void setColumnSpan(int columnSpan); - - /** - * Return an ObservableList of String of all the style class associated with - * this cell. You can easily modify its appearance by adding a style class - * (previously set in CSS). - * - * @return an ObservableList of String of all the style class - */ - public ObservableSet<String> getStyleClass(); - - /** - * @return an ObjectProperty wrapping a Node for the graphic. - */ - public ObjectProperty<Node> graphicProperty(); - - /** - * Set a graphic for this cell to display aside with the text. - * - * @param graphic - */ - public void setGraphic(Node graphic); - - /** - * Return the graphic node associated with this cell. Return null if nothing - * has been associated. - * - * @return the graphic node associated with this cell. - */ - public Node getGraphic(); - - /** - * @return the tooltip associated with this SpreadsheetCell. - */ - public Optional<String> getTooltip(); - - /** - * Registers an event handler to this SpreadsheetCell. - * @param eventType the type of the events to receive by the handler - * @param eventHandler the handler to register - * @throws NullPointerException if the event type or handler is null - */ - public void addEventHandler(EventType<Event> eventType, EventHandler<Event> eventHandler); - - /** - * Unregisters a previously registered event handler from this SpreadsheetCell. - * @param eventType the event type from which to unregister - * @param eventHandler the handler to unregister - * @throws NullPointerException if the event type or handler is null - */ - public void removeEventHandler(EventType<Event> eventType, EventHandler<Event> eventHandler); -} diff --git a/src/org/controlsfx/control/spreadsheet/SpreadsheetCellBase.java b/src/org/controlsfx/control/spreadsheet/SpreadsheetCellBase.java deleted file mode 100644 index f13634f..0000000 --- a/src/org/controlsfx/control/spreadsheet/SpreadsheetCellBase.java +++ /dev/null @@ -1,643 +0,0 @@ -/** - * Copyright (c) 2013, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.spreadsheet; - -import com.sun.javafx.event.EventHandlerManager; -import java.util.Objects; -import java.util.Optional; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.ReadOnlyStringProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.property.StringProperty; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.collections.FXCollections; -import javafx.collections.ObservableSet; -import javafx.event.Event; -import javafx.event.EventDispatchChain; -import javafx.event.EventHandler; -import javafx.event.EventTarget; -import javafx.event.EventType; -import javafx.scene.Node; -import javafx.scene.image.ImageView; - -/** - * The SpreadsheetCells serve as model for the {@link SpreadsheetView}. <br> - * You will provide them when constructing a {@link Grid}. - * - * <br> - * <h3>SpreadsheetCell Types</h3> Each SpreadsheetCell has its own - * {@link SpreadsheetCellType} which has its own {@link SpreadsheetCellEditor} - * in order to control very closely the possible modifications. - * - * <p> - * Different {@link SpreadsheetCellType SpreadsheetCellTypes} are available - * depending on the data you want to represent in your {@link SpreadsheetView}. - * You can use the different static method provided in - * {@link SpreadsheetCellType} in order to create the specialized - * SpreadsheetCell that suits your need. - * - * - * <br> - * - * <p> - * If you want to create a SpreadsheetCell of your own, you simply have to - * use one of the provided constructor. Usually you will let your {@link SpreadsheetCellType} - * create the cells. For example - * {@link SpreadsheetCellType.StringType#createCell(int, int, int, int, java.lang.String) }. - * You will also have to provide a custom {@link SpreadsheetCellEditor}. - * - * <h2>Configuration</h2> - * You will have to indicate the coordinates of the cell together with the - * {@link #setRowSpan(int) row} and {@link #setColumnSpan(int) column} span. You - * can specify if you want the cell to be editable or not using - * {@link #setEditable(boolean)}. Be advised that a cell with a rowSpan means - * that the cell will replace all the cells situated in the rowSpan range. Same - * with the column span. - * <br> - * So the best way to handle spanning is to fill your grid - * with unique cells, and then call at the end {@link GridBase#spanColumn(int, int, int)} - * or {@link GridBase#spanRow(int, int, int)}. These methods will handle the span - * for you. - * - * <br> - * - * <h3>Format</h3> - * Your cell can have its very own format. If you want to display some dates - * with different format, you just have to create a unique - * {@link SpreadsheetCellType} and then specify for each cell their format with - * {@link #setFormat(String)}. You will then have the guaranty that all your - * cells will have a LocalDate as a value, but the value will be displayed - * differently for each cell. This will also guaranty that copy/paste and other - * operation will be compatible since every cell will share the same - * {@link SpreadsheetCellType}. <br> - * Here an example : <br> - * - * - * <pre> - * SpreadsheetCell cell = SpreadsheetCellType.DATE.createCell(row, column, rowSpan, colSpan, - * LocalDate.now().plusDays((int) (Math.random() * 10))); // Random value - * // given here - * final double random = Math.random(); - * if (random < 0.25) { - * cell.setFormat("EEEE d"); - * } else if (random < 0.5) { - * cell.setFormat("dd/MM :YY"); - * } else { - * cell.setFormat("dd/MM/YYYY"); - * } - * </pre> - * - * <center><img src="dateFormat.PNG" alt="SpreadsheetCellBase with custom format"></center> - * - * <h3>Graphic</h3> - * Each cell can have a graphic to display next to the text in the cells. Just - * use the {@link #setGraphic(Node)} in order to specify the graphic you want. - * If you specify an {@link ImageView}, the SpreadsheetView will try to resize it in - * order to fit the space available in the cell. - * - * For example : - * - * <pre> - * cell.setGraphic(new ImageView(new Image(getClass().getResourceAsStream("icons/exclamation.png")))); - * </pre> - * - * <center><img src="graphicNodeToCell.png" alt="SpreadsheetCellBase with graphic"></center> <br> - * In addition to that, you can also specify another graphic property to your - * cell with {@link #activateCorner(org.controlsfx.control.spreadsheet.SpreadsheetCell.CornerPosition) }. - * This allow you to activate or deactivate some graphics on the cell in every - * corner. Right now it's a little red triangle but you can modify this in your CSS by - * using the "<b>cell-corner</b>" style class. - * - * <pre> - * .cell-corner.top-left{ - * -fx-background-color: red; - * -fx-shape : "M 0 0 L 1 0 L 0 1 z"; - * } - * </pre> - * - * <center><img src="triangleCell.PNG" alt="SpreadsheetCellBase with a styled cell-corner"></center> - * - * - * <br> - * You can also customize the tooltip of your SpreadsheetCell by specifying one - * with {@link #setTooltip(java.lang.String) }. - * - * <h3>Style with CSS</h3> - * You can style your cell by specifying some styleClass with - * {@link #getStyleClass()}. You just have to create and custom that class in - * your CSS stylesheet associated with your {@link SpreadsheetView}. Also note - * that all {@link SpreadsheetCell} have a "<b>spreadsheet-cell</b>" styleClass - * added by default. Here is a example :<br> - * - * <pre> - * cell.getStyleClass().add("row_header"); - * </pre> - * - * And in the CSS: - * - * <pre> - * .spreadsheet-cell.row_header{ - * -fx-background-color: #b4d4ad ; - * -fx-background-insets: 0, 0 1 1 0; - * -fx-alignment: center; - * } - * </pre> - * - * <h3>Examples</h3> - * Here is an example that uses all the pre-built {@link SpreadsheetCellType} - * types. The generation is random here so you will want to replace the logic to - * suit your needs. - * - * <pre> - * private SpreadsheetCell<?> generateCell(int row, int column, int rowSpan, int colSpan) { - * List<String> stringListTextCell = Arrays.asList("Shanghai","Paris","New York City","Bangkok","Singapore","Johannesburg","Berlin","Wellington","London","Montreal"); - * final double random = Math.random(); - * if (random < 0.10) { - * List<String> stringList = Arrays.asList("China","France","New Zealand","United States","Germany","Canada"); - * cell = SpreadsheetCellType.LIST(stringList).createCell(row, column, rowSpan, colSpan, stringList.get((int) (Math.random() * 6))); - * } else if (random >= 0.10 && random < 0.25) { - * cell = SpreadsheetCellType.STRING.createCell(row, column, rowSpan, colSpan,stringListTextCell.get((int)(Math.random()*10))); - * } else if (random >= 0.25 && random < 0.75) { - * cell = SpreadsheetCellType.DOUBLE.createCell(row, column, rowSpan, colSpan,(double)Math.round((Math.random()*100)*100)/100); - * } else { - * cell = SpreadsheetCellType.DATE.createCell(row, column, rowSpan, colSpan, LocalDate.now().plusDays((int)(Math.random()*10))); - * } - * return cell; - * } - * </pre> - * - * @see SpreadsheetView - * @see SpreadsheetCellEditor - * @see SpreadsheetCellType - */ -public class SpreadsheetCellBase implements SpreadsheetCell, EventTarget{ - - /*************************************************************************** - * - * Private Fields - * - **************************************************************************/ - - //The Bit position for the editable Property. - private static final int EDITABLE_BIT_POSITION = 4; - private static final int WRAP_BIT_POSITION = 5; - private final SpreadsheetCellType type; - private final int row; - private final int column; - private int rowSpan; - private int columnSpan; - private final StringProperty format; - private final StringProperty text; - private final StringProperty styleProperty; - private final ObjectProperty<Node> graphic; - private String tooltip; - /** - * This variable handles all boolean values of this SpreadsheetCell inside - * its bits. Instead of using regular boolean, we use that int so that we - * can reduce memory usage to the bare minimum. - */ - private int propertyContainer = 0; - private final EventHandlerManager eventHandlerManager = new EventHandlerManager(this); - - private ObservableSet<String> styleClass; - - /*************************************************************************** - * - * Constructor - * - **************************************************************************/ - - /** - * Constructs a SpreadsheetCell with the given configuration. - * Use the {@link SpreadsheetCellType#OBJECT} type. - * @param row - * @param column - * @param rowSpan - * @param columnSpan - */ - public SpreadsheetCellBase(final int row, final int column, final int rowSpan, final int columnSpan) { - this(row, column, rowSpan, columnSpan, SpreadsheetCellType.OBJECT); - } - - /** - * Constructs a SpreadsheetCell with the given configuration. - * - * @param row - * @param column - * @param rowSpan - * @param columnSpan - * @param type - */ - public SpreadsheetCellBase(final int row, final int column, final int rowSpan, final int columnSpan, - final SpreadsheetCellType<?> type) { - this.row = row; - this.column = column; - this.rowSpan = rowSpan; - this.columnSpan = columnSpan; - this.type = type; - text = new SimpleStringProperty(""); //$NON-NLS-1$ - format = new SimpleStringProperty(""); //$NON-NLS-1$ - graphic = new SimpleObjectProperty<>(); - format.addListener(new ChangeListener<String>() { - @Override - public void changed(ObservableValue<? extends String> arg0, String arg1, String arg2) { - updateText(); - } - }); - //Editable is true at the initialisation - setEditable(true); - getStyleClass().add("spreadsheet-cell"); //$NON-NLS-1$ - styleProperty = new SimpleStringProperty(); - } - - /*************************************************************************** - * - * Public Methods - * - **************************************************************************/ - - /** {@inheritDoc} */ - @Override - public boolean match(SpreadsheetCell cell) { - return type.match(cell); - } - - // --- item - private final ObjectProperty<Object> item = new SimpleObjectProperty<Object>(this, "item") { //$NON-NLS-1$ - @Override - protected void invalidated() { - updateText(); - } - }; - - /** {@inheritDoc} */ - @Override - public final void setItem(Object value) { - if (isEditable()) - item.set(value); - } - - /** {@inheritDoc} */ - @Override - public final Object getItem() { - return item.get(); - } - - /** {@inheritDoc} */ - @Override - public final ObjectProperty<Object> itemProperty() { - return item; - } - - /** {@inheritDoc} */ - @Override - public final boolean isEditable() { - return isSet(EDITABLE_BIT_POSITION); - } - - /** {@inheritDoc} */ - @Override - public final void setEditable(boolean editable) { - if(setMask(editable, EDITABLE_BIT_POSITION)){ - Event.fireEvent(this, new Event(EDITABLE_EVENT_TYPE)); - } - } - - /** {@inheritDoc} */ - @Override - public boolean isWrapText(){ - return isSet(WRAP_BIT_POSITION); - } - - /** {@inheritDoc} */ - @Override - public void setWrapText(boolean wrapText) { - if (setMask(wrapText, WRAP_BIT_POSITION)) { - Event.fireEvent(this, new Event(WRAP_EVENT_TYPE)); - } - } - - /** {@inheritDoc} */ - @Override - public final StringProperty formatProperty() { - return format; - } - - /** {@inheritDoc} */ - @Override - public final String getFormat() { - return format.get(); - } - - /** {@inheritDoc} */ - @Override - public final void setFormat(String format) { - formatProperty().set(format); - updateText(); - } - - /** {@inheritDoc} */ - @Override - public final ReadOnlyStringProperty textProperty() { - return text; - } - - /** {@inheritDoc} */ - @Override - public final String getText() { - return text.get(); - } - - /** {@inheritDoc} */ - @Override - public final SpreadsheetCellType getCellType() { - return type; - } - - /** {@inheritDoc} */ - @Override - public final int getRow() { - return row; - } - - /** {@inheritDoc} */ - @Override - public final int getColumn() { - return column; - } - - /** {@inheritDoc} */ - @Override - public final int getRowSpan() { - return rowSpan; - } - - /** {@inheritDoc} */ - @Override - public final void setRowSpan(int rowSpan) { - this.rowSpan = rowSpan; - } - - /** {@inheritDoc} */ - @Override - public final int getColumnSpan() { - return columnSpan; - } - - /** {@inheritDoc} */ - @Override - public final void setColumnSpan(int columnSpan) { - this.columnSpan = columnSpan; - } - - /** {@inheritDoc} */ - @Override - public final ObservableSet<String> getStyleClass() { - if (styleClass == null) { - styleClass = FXCollections.observableSet(); - } - return styleClass; - } - - /** {@inheritDoc} */ - @Override - public void setStyle(String style){ - styleProperty.set(style); - } - - /** {@inheritDoc} */ - @Override - public String getStyle(){ - return styleProperty.get(); - } - - /** {@inheritDoc} */ - @Override - public StringProperty styleProperty(){ - return styleProperty; - } - - /** {@inheritDoc} */ - @Override - public ObjectProperty<Node> graphicProperty() { - return graphic; - } - - /** {@inheritDoc} */ - @Override - public void setGraphic(Node graphic) { - this.graphic.set(graphic); - } - - /** {@inheritDoc} */ - @Override - public Node getGraphic() { - return graphic.get(); - } - - /** {@inheritDoc} */ - @Override - public Optional<String> getTooltip() { - return Optional.ofNullable(tooltip); - } - - /** - * Set a new tooltip for this cell. - * @param tooltip - */ - public void setTooltip(String tooltip){ - this.tooltip = tooltip; - } - - /** {@inheritDoc} */ - @Override - public void activateCorner(CornerPosition position) { - if(setMask(true, getCornerBitNumber(position))){ - Event.fireEvent(this, new Event(CORNER_EVENT_TYPE)); - } - } - - /** {@inheritDoc} */ - @Override - public void deactivateCorner(CornerPosition position) { - if(setMask(false, getCornerBitNumber(position))){ - Event.fireEvent(this, new Event(CORNER_EVENT_TYPE)); - } - } - - /** {@inheritDoc} */ - @Override - public boolean isCornerActivated(CornerPosition position) { - return isSet(getCornerBitNumber(position)); - } - - /** {@inheritDoc} */ - @Override - public EventDispatchChain buildEventDispatchChain(EventDispatchChain tail) { - return tail.append(eventHandlerManager); - } - - /*************************************************************************** - * - * Overridden Methods - * - **************************************************************************/ - - /** {@inheritDoc} */ - @Override - public String toString() { - return "cell[" + row + "][" + column + "]" + rowSpan + "-" + columnSpan; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ - } - - /** {@inheritDoc} */ - @Override - public final boolean equals(Object obj) { - if (this == obj) - return true; - if (!(obj instanceof SpreadsheetCell)) - return false; - - final SpreadsheetCell otherCell = (SpreadsheetCell) obj; - return otherCell.getRow() == row && otherCell.getColumn() == column - && Objects.equals(otherCell.getText(), getText()) - && rowSpan == otherCell.getRowSpan() - && columnSpan == otherCell.getColumnSpan() - && Objects.equals(getStyleClass(), otherCell.getStyleClass()); - } - - /** {@inheritDoc} */ - @Override - public final int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + column; - result = prime * result + row; - result = prime * result + rowSpan; - result = prime * result + columnSpan; - result = prime * result + Objects.hashCode(getText()); - result = prime * result + Objects.hashCode(getStyleClass()); - return result; - } - - /** - * Registers an event handler to this SpreadsheetCell. The SpreadsheetCell class allows - * registration of listeners which will be notified when a corner state of - * the editable state of this SpreadsheetCell have changed. - * - * @param eventType the type of the events to receive by the handler - * @param eventHandler the handler to register - * @throws NullPointerException if the event type or handler is null - */ - @Override - public void addEventHandler(EventType<Event> eventType, EventHandler<Event> eventHandler) { - eventHandlerManager.addEventHandler(eventType, eventHandler); - } - - /** - * Unregisters a previously registered event handler from this SpreadsheetCell. One - * handler might have been registered for different event types, so the - * caller needs to specify the particular event type from which to - * unregister the handler. - * - * @param eventType the event type from which to unregister - * @param eventHandler the handler to unregister - * @throws NullPointerException if the event type or handler is null - */ - @Override - public void removeEventHandler(EventType<Event> eventType, EventHandler<Event> eventHandler) { - eventHandlerManager.removeEventHandler(eventType, eventHandler); - } - - /*************************************************************************** - * - * Private Implementation - * - **************************************************************************/ - - /** - * Update the text for the SpreadsheetView. - */ - @SuppressWarnings("unchecked") - private void updateText() { - if(getItem() == null){ - text.setValue(""); //$NON-NLS-1$ - }else if (!("").equals(getFormat())) { //$NON-NLS-1$ - text.setValue(type.toString(getItem(), getFormat())); - } else { - text.setValue(type.toString(getItem())); - } - } - - /** - * Return the Bit position for each corner. - * @param position - * @return - */ - private int getCornerBitNumber(CornerPosition position) { - switch (position) { - case TOP_LEFT: - return 0; - - case TOP_RIGHT: - return 1; - - case BOTTOM_RIGHT: - return 2; - - case BOTTOM_LEFT: - default: - return 3; - } - } - - /** - * Set the specified bit position at the value specified by flag. - * @param flag - * @param position - * @return whether a change has really occured. - */ - private boolean setMask(boolean flag, int position) { - int oldCorner = propertyContainer; - if (flag) { - propertyContainer |= (1 << position); - } else { - propertyContainer &= ~(1 << position); - } - return propertyContainer != oldCorner; - } - - /** - * @param mask - * @param position - * @return whether the specified bit position is true. - */ - private boolean isSet(int position) { - return (propertyContainer & (1 << position)) != 0; - } -} diff --git a/src/org/controlsfx/control/spreadsheet/SpreadsheetCellEditor.java b/src/org/controlsfx/control/spreadsheet/SpreadsheetCellEditor.java deleted file mode 100644 index 2c4aec7..0000000 --- a/src/org/controlsfx/control/spreadsheet/SpreadsheetCellEditor.java +++ /dev/null @@ -1,927 +0,0 @@ -/** - * Copyright (c) 2013, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.spreadsheet; - -import impl.org.controlsfx.i18n.Localization; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.text.NumberFormat; -import java.text.ParseException; -import java.text.ParsePosition; -import java.time.LocalDate; -import java.util.List; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.event.EventHandler; -import javafx.scene.control.ComboBox; -import javafx.scene.control.Control; -import javafx.scene.control.DatePicker; -import javafx.scene.control.IndexRange; -import javafx.scene.control.TextArea; -import javafx.scene.control.TextField; -import javafx.scene.input.KeyCode; -import javafx.scene.input.KeyEvent; -import javafx.util.StringConverter; - -/** - * - * SpreadsheetCellEditor are used by {@link SpreadsheetCellType} and - * {@link SpreadsheetCell} in order to control how each value will be entered. <br> - * - * <h3>General behavior:</h3> Editors will be displayed if the user double-click - * in an editable cell ( see {@link SpreadsheetCell#setEditable(boolean)} ). <br> - * If the user does anything outside the editor, the editor <b> will be forced - * </b> to try to commit the edition and close itself. If the value is not - * valid, the editor will cancel the value and close itself. The editor is just - * here to allow communication between the user and the {@link SpreadsheetView}. - * It will just be given a value, and it will just give back another one after. - * The policy regarding validation of a given value is defined in - * {@link SpreadsheetCellType#match(Object)}. - * - * If the value doesn't meet the requirements when saving the cell, nothing - * happens and the editor keeps editing. <br> - * You can abandon a current modification by pressing "esc" key. <br> - * - * You can specify a maximum height to your spreadsheetCellEditor with {@link #getMaxHeight() - * }. This can be used in order to control the display of your editor. If they - * should grow or not in a big cell. (for example a {@link TextAreaEditor} want - * to grow with the cell in order to take full space for display. - * <br> - * <h3>Specific behavior:</h3> This class offers some static classes in order to - * create a {@link SpreadsheetCellEditor}. Here are their properties: <br> - * - * <ul> - * <li> {@link StringEditor}: Basic {@link TextField}, can accept all data and - * save it as a string.</li> - * <li> {@link ListEditor}: Display a {@link ComboBox} with the different values. - * </li> - * <li> {@link DoubleEditor}: Display a {@link TextField} which accepts only - * double value. If the entered value is incorrect, the background will turn red - * so that the user will know in advance if the data will be saved or not.</li> - * <li> {@link IntegerEditor}: Display a {@link TextField} which accepts only - * Integer value. If the entered value is incorrect, the background will turn red - * so that the user will know in advance if the data will be saved or not.</li> - * <li> {@link DateEditor}: Display a {@link DatePicker}.</li> - * <li> {@link ObjectEditor}: Display a {@link TextField} , accept an Object.</li> - * </ul> - * - * <br> - * <h3>Creating your editor:</h3> You can of course create your own - * {@link SpreadsheetCellEditor} for displaying other controls.<br> - * - * You just have to override the four abstract methods. <b>Remember</b> that you - * will never call those methods directly. They will be called by the - * {@link SpreadsheetView} when needed. - * <ul> - * <li> {@link #startEdit(Object)}: You will configure your control with the - * given value which is {@link SpreadsheetCell#getItem()} converted to an - * object. You do not instantiate your control here, you do it in the - * constructor.</li> - * <li> {@link #getEditor()}: You will return which control you're using (for - * display).</li> - * <li> {@link #getControlValue()}: You will return the value inside your editor - * in order to submit it for validation.</li> - * <li> {@link #end()}: When editing is finished, you can properly close your own - * control.</li> - * </ul> - * <br> - * Keep in mind that you will interact only with {@link #endEdit(boolean)} where - * a <b>true</b> value means you want to commit, and a <b>false</b> means you - * want to cancel. The {@link SpreadsheetView} will handle all the rest for you - * and call your methods at the right moment. <br> - * - * <h3>Use case :</h3> <center><img src="editorScheme.png" alt="Use case of SpreadsheetCellEditor"></center> - * - * <h3>Visual:</h3> - * <table style="border: 1px solid gray;" summary="Screenshots of various SpreadsheetCellEditor"> - * <tr> - * <td valign="center" style="text-align:right;"><strong>String</strong></td> - * <td><center><img src="textEditor.png" alt="Screenshot of SpreadsheetCellEditor.StringEditor"></center></td> - * </tr> - * <tr> - * <td valign="center" style="text-align:right;"><strong>List</strong></td> - * <td><center><img src="listEditor.png" alt="Screenshot of SpreadsheetCellEditor.ListEditor"></center></td> - * </tr> - * <tr> - * <td valign="center" style="text-align:right;"><strong>Double</strong></td> - * <td><center><img src="doubleEditor.png" alt="Screenshot of SpreadsheetCellEditor.DoubleEditor"></center></td> - * </tr> - * <tr> - * <td valign="center" style="text-align:right;"><strong>Date</strong></td> - * <td><center><img src="dateEditor.png" alt="Screenshot of SpreadsheetCellEditor.DateEditor"></center></td> - * </tr> - * </table> - * - * - * @see SpreadsheetView - * @see SpreadsheetCell - * @see SpreadsheetCellType - */ -public abstract class SpreadsheetCellEditor { - private static final double MAX_EDITOR_HEIGHT = 50.0; - - private static final DecimalFormat decimalFormat = new DecimalFormat("#.##########"); //$NON-NLS-1$ - SpreadsheetView view; - - /*************************************************************************** - * * Constructor * * - **************************************************************************/ - - /** - * Construct the SpreadsheetCellEditor. - * - * @param view - */ - public SpreadsheetCellEditor(SpreadsheetView view) { - this.view = view; - } - - /*************************************************************************** - * * Public Final Methods * * - **************************************************************************/ - /** - * Whenever you want to stop the edition, you call that method.<br> - * True means you're trying to commit the value, then - * {@link SpreadsheetCellType#convertValue(Object)} will be called in order - * to verify that the value is correct.<br> - * False means you're trying to cancel the value and it will be follow by - * {@link #end()}.<br> - * See SpreadsheetCellEditor description - * - * @param b - * true means commit, false means cancel - */ - public final void endEdit(boolean b) { - view.getCellsViewSkin().getSpreadsheetCellEditorImpl().endEdit(b); - } - - /*************************************************************************** - * * Public Abstract Methods * * - **************************************************************************/ - /** - * This method will be called when edition start.<br> - * You will then do all the configuration of your editor. - * - * @param item - */ - public abstract void startEdit(Object item); - - /** - * Return the control used for controlling the input. This is called at the - * beginning in order to display your control in the cell. - * - * @return the control used. - */ - public abstract Control getEditor(); - - /** - * Return the value within your editor as a string. This will be used by the - * {@link SpreadsheetCellType#convertValue(Object)} in order to compute - * whether the value is valid regarding the {@link SpreadsheetCellType} - * policy. - * - * @return the value within your editor as a string. - */ - public abstract String getControlValue(); - - /** - * This method will be called at the end of edition.<br> - * You will be offered the possibility to do the configuration post editing. - */ - public abstract void end(); - - /*************************************************************************** - * * Public Methods * * - **************************************************************************/ - /** - * Return the maximum height of the editor. - * @return 50 by default. - */ - public double getMaxHeight(){ - return MAX_EDITOR_HEIGHT; - } - - /** - * A {@link SpreadsheetCellEditor} for - * {@link SpreadsheetCellType.ObjectType} typed cells. It displays a - * {@link TextField} where the user can type different values. - */ - public static class ObjectEditor extends SpreadsheetCellEditor { - - /*************************************************************************** - * * Private Fields * * - **************************************************************************/ - private final TextField tf; - - /*************************************************************************** - * * Constructor * * - **************************************************************************/ - /** - * Constructor for the ObjectEditor.. - * @param view The SpreadsheetView - */ - public ObjectEditor(SpreadsheetView view) { - super(view); - tf = new TextField(); - } - - /*************************************************************************** - * * Public Methods * * - **************************************************************************/ - @Override - public void startEdit(Object value) { - if(value == null) tf.setText(""); - else if (value instanceof String) { - tf.setText(value.toString()); - } - attachEnterEscapeEventHandler(); - - tf.requestFocus(); - tf.end(); - } - - @Override - public String getControlValue() { - return tf.getText(); - } - - @Override - public void end() { - tf.setOnKeyPressed(null); - } - - @Override - public TextField getEditor() { - return tf; - } - - /*************************************************************************** - * * Private Methods * * - **************************************************************************/ - - private void attachEnterEscapeEventHandler() { - tf.setOnKeyPressed(new EventHandler<KeyEvent>() { - @Override - public void handle(KeyEvent t) { - if (t.getCode() == KeyCode.ENTER) { - endEdit(true); - } else if (t.getCode() == KeyCode.ESCAPE) { - endEdit(false); - } - } - }); - } - } - - /** - * A {@link SpreadsheetCellEditor} for - * {@link SpreadsheetCellType.StringType} typed cells. It displays a - * {@link TextField} where the user can type different values. - */ - public static class StringEditor extends SpreadsheetCellEditor { - /*************************************************************************** - * * Private Fields * * - **************************************************************************/ - private final TextField tf; - - /*************************************************************************** - * * Constructor * * - **************************************************************************/ - /** - * Constructor for the StringEditor. - * @param view The SpreadsheetView - */ - public StringEditor(SpreadsheetView view) { - super(view); - tf = new TextField(); - } - - /*************************************************************************** - * * Public Methods * * - **************************************************************************/ - @Override - public void startEdit(Object value) { - - if (value instanceof String || value == null) { - tf.setText((String) value); - } - attachEnterEscapeEventHandler(); - - tf.requestFocus(); - tf.selectAll(); - } - - @Override - public String getControlValue() { - return tf.getText(); - } - - @Override - public void end() { - tf.setOnKeyPressed(null); - } - - @Override - public TextField getEditor() { - return tf; - } - - /*************************************************************************** - * * Private Methods * * - **************************************************************************/ - - private void attachEnterEscapeEventHandler() { - tf.setOnKeyPressed(new EventHandler<KeyEvent>() { - @Override - public void handle(KeyEvent t) { - if (t.getCode() == KeyCode.ENTER) { - endEdit(true); - } else if (t.getCode() == KeyCode.ESCAPE) { - endEdit(false); - } - } - }); - } - } - - - /** - * A {@link SpreadsheetCellEditor} for - * {@link SpreadsheetCellType.StringType} typed cells. It displays a - * {@link TextField} where the user can type different values. - */ - public static class TextAreaEditor extends SpreadsheetCellEditor { - - /** - * ************************************************************************* - * * Private Fields * * - * ************************************************************************ - */ - private final TextArea textArea; - - /** - * ************************************************************************* - * * Constructor * * - * ************************************************************************ - */ - /** - * Constructor for the StringEditor. - * - * @param view The SpreadsheetView - */ - public TextAreaEditor(SpreadsheetView view) { - super(view); - textArea = new TextArea(); - textArea.setWrapText(true); - //The textArea is not respecting the maxHeight if we are not setting the min.. - textArea.minHeightProperty().bind(textArea.maxHeightProperty()); - } - - /** - * ************************************************************************* - * * Public Methods * * - * ************************************************************************ - */ - @Override - public void startEdit(Object value) { - if (value instanceof String || value == null) { - textArea.setText((String) value); - } - attachEnterEscapeEventHandler(); - - textArea.requestFocus(); - textArea.selectAll(); - } - - @Override - public String getControlValue() { - return textArea.getText(); - } - - @Override - public void end() { - textArea.setOnKeyPressed(null); - } - - @Override - public TextArea getEditor() { - return textArea; - } - - @Override - public double getMaxHeight() { - return Double.MAX_VALUE; - } - - /** - * ************************************************************************* - * * Private Methods * * - * ************************************************************************ - */ - private void attachEnterEscapeEventHandler() { - - textArea.setOnKeyPressed(new EventHandler<KeyEvent>() { - @Override - public void handle(KeyEvent keyEvent) { - if (keyEvent.getCode() == KeyCode.ENTER) { - if (keyEvent.isShiftDown()) { - //if shift is down, we insert a new line. - textArea.replaceSelection("\n"); //$NON-NLS-1$ - } else { - endEdit(true); - } - } else if (keyEvent.getCode() == KeyCode.ESCAPE) { - endEdit(false); - }else if(keyEvent.getCode() == KeyCode.TAB){ - if (keyEvent.isShiftDown()) { - //if shift is down, we insert a tab. - textArea.replaceSelection("\t"); //$NON-NLS-1$ - keyEvent.consume(); - } else { - endEdit(true); - } - } - } - }); - } - } - - /** - * A {@link SpreadsheetCellEditor} for - * {@link SpreadsheetCellType.DoubleType} typed cells. It displays a - * {@link TextField} where the user can type different numbers. Only numbers - * will be stored. <br> - * Moreover, the {@link TextField} will turn red if the value currently - * entered if incorrect. - */ - public static class DoubleEditor extends SpreadsheetCellEditor { - - /*************************************************************************** - * * private Fields * * - **************************************************************************/ - private final TextField tf; - - /*************************************************************************** - * * Constructor * * - **************************************************************************/ - /** - * Constructor for the DoubleEditor. - * @param view The SpreadsheetView. - */ - public DoubleEditor(SpreadsheetView view) { - super(view); - tf = new TextField() { - - @Override - public void insertText(int index, String text) { - String fixedText = fixText(text); - super.insertText(index, fixedText); - } - - @Override - public void replaceText(int start, int end, String text) { - String fixedText = fixText(text); - super.replaceText(start, end, fixedText); - } - - @Override - public void replaceText(IndexRange range, String text) { - replaceText(range.getStart(), range.getEnd(), text); - } - - private String fixText(String text) { - DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(Localization.getLocale()); - text = text.replace(' ', '\u00a0');//$NON-NLS-1$ - return text.replaceAll("\\.", Character.toString(symbols.getDecimalSeparator()));//$NON-NLS-1$ - } - }; - } - - /*************************************************************************** - * * Public Methods * * - **************************************************************************/ - /** {@inheritDoc} */ - @Override - public void startEdit(Object value) { - if (value instanceof Double) { - //We want to set the text in its proper form regarding the Locale. - decimalFormat.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Localization.getLocale())); - tf.setText(((Double) value).isNaN() ? "" : decimalFormat.format(value)); //$NON-NLS-1$ - } else { - tf.setText(null); - } - - tf.getStyleClass().removeAll("error"); //$NON-NLS-1$ - attachEnterEscapeEventHandler(); - - tf.requestFocus(); - tf.selectAll(); - } - - /** {@inheritDoc} */ - @Override - public void end() { - tf.setOnKeyPressed(null); - } - - /** {@inheritDoc} */ - @Override - public TextField getEditor() { - return tf; - } - - /** {@inheritDoc} */ - @Override - public String getControlValue() { - NumberFormat format = NumberFormat.getInstance(Localization.getLocale()); - ParsePosition parsePosition = new ParsePosition(0); - if (tf.getText() != null) { - Number number = format.parse(tf.getText(), parsePosition); - if (number != null && parsePosition.getIndex() == tf.getText().length()) { - return String.valueOf(number.doubleValue()); - } - } - return tf.getText(); - } - - /*************************************************************************** - * * Private Methods * * - **************************************************************************/ - - private void attachEnterEscapeEventHandler() { - tf.setOnKeyPressed(new EventHandler<KeyEvent>() { - @Override - public void handle(KeyEvent t) { - if (t.getCode() == KeyCode.ENTER) { - try { - if (tf.getText().equals("")) { //$NON-NLS-1$ - endEdit(true); - } else { - tryParsing(); - endEdit(true); - } - } catch (Exception e) { - } - - } else if (t.getCode() == KeyCode.ESCAPE) { - endEdit(false); - } - } - }); - - tf.setOnKeyReleased(new EventHandler<KeyEvent>() { - @Override - public void handle(KeyEvent t) { - try { - if (tf.getText().equals("")) { //$NON-NLS-1$ - tf.getStyleClass().removeAll("error"); //$NON-NLS-1$ - } else { - tryParsing(); - tf.getStyleClass().removeAll("error"); //$NON-NLS-1$ - } - } catch (Exception e) { - tf.getStyleClass().add("error"); //$NON-NLS-1$ - } - } - }); - } - - private void tryParsing() throws ParseException { - NumberFormat format = NumberFormat.getNumberInstance(Localization.getLocale()); - ParsePosition parsePosition = new ParsePosition(0); - format.parse(tf.getText(), parsePosition); - if (parsePosition.getIndex() != tf.getText().length()) { - throw new ParseException("Invalid input", parsePosition.getIndex()); - } - } - } - - /** - * A {@link SpreadsheetCellEditor} for - * {@link SpreadsheetCellType.DoubleType} typed cells. It displays a - * {@link TextField} where the user can type different numbers. Only numbers - * will be stored. <br> - * Moreover, the {@link TextField} will turn red if the value currently - * entered if incorrect. - */ - public static class IntegerEditor extends SpreadsheetCellEditor { - - /*************************************************************************** - * * Private Fields * * - **************************************************************************/ - private final TextField tf; - - /*************************************************************************** - * * Constructor * * - **************************************************************************/ - /** - * Constructor for the IntegerEditor. - * @param view the SpreadsheetView - */ - public IntegerEditor(SpreadsheetView view) { - super(view); - tf = new TextField(); - } - - /*************************************************************************** - * * Public Methods * * - **************************************************************************/ - /** {@inheritDoc} */ - @Override - public void startEdit(Object value) { - if (value instanceof Integer) { - tf.setText(Integer.toString((Integer) value)); - } else { - tf.setText(null); - } - - tf.getStyleClass().removeAll("error"); //$NON-NLS-1$ - attachEnterEscapeEventHandler(); - - tf.requestFocus(); - tf.selectAll(); - } - - /** {@inheritDoc} */ - @Override - public void end() { - tf.setOnKeyPressed(null); - } - - /** {@inheritDoc} */ - @Override - public TextField getEditor() { - return tf; - } - - /** {@inheritDoc} */ - @Override - public String getControlValue() { - return tf.getText(); - } - - /*************************************************************************** - * * Private Methods * * - **************************************************************************/ - - private void attachEnterEscapeEventHandler() { - tf.setOnKeyPressed(new EventHandler<KeyEvent>() { - @Override - public void handle(KeyEvent t) { - if (t.getCode() == KeyCode.ENTER) { - try { - if (tf.getText().equals("")) { //$NON-NLS-1$ - endEdit(true); - } else { - Integer.parseInt(tf.getText()); - endEdit(true); - } - } catch (Exception e) { - } - - } else if (t.getCode() == KeyCode.ESCAPE) { - endEdit(false); - } - } - }); - tf.setOnKeyReleased(new EventHandler<KeyEvent>() { - @Override - public void handle(KeyEvent t) { - try { - if (tf.getText().equals("")) { //$NON-NLS-1$ - tf.getStyleClass().removeAll("error"); //$NON-NLS-1$ - } else { - Integer.parseInt(tf.getText()); - tf.getStyleClass().removeAll("error"); //$NON-NLS-1$ - } - } catch (Exception e) { - tf.getStyleClass().add("error"); //$NON-NLS-1$ - } - } - }); - } - } - - /** - * - * A {@link SpreadsheetCellEditor} for {@link SpreadsheetCellType.ListType} - * typed cells. It displays a {@link ComboBox} where the user can choose a - * value. - */ - public static class ListEditor<R> extends SpreadsheetCellEditor { - /*************************************************************************** - * * Private Fields * * - **************************************************************************/ - private final List<String> itemList; - private final ComboBox<String> cb; - private String originalValue; - - /*************************************************************************** - * * Constructor * * - **************************************************************************/ - - /** - * Constructor for the ListEditor. - * @param view The SpreadsheetView - * @param itemList The items to display in the editor. - */ - public ListEditor(SpreadsheetView view, final List<String> itemList) { - super(view); - this.itemList = itemList; - cb = new ComboBox<String>(); - cb.setVisibleRowCount(5); - } - - /*************************************************************************** - * * Public Methods * * - **************************************************************************/ - - /** {@inheritDoc} */ - @Override - public void startEdit(Object value) { - if (value instanceof String) { - originalValue = value.toString(); - } else { - originalValue = null; - } - ObservableList<String> items = FXCollections.observableList(itemList); - cb.setItems(items); - cb.setValue(originalValue); - - attachEnterEscapeEventHandler(); - cb.show(); - cb.requestFocus(); - } - - /** {@inheritDoc} */ - @Override - public void end() { - cb.setOnKeyPressed(null); - } - - /** {@inheritDoc} */ - @Override - public ComboBox<String> getEditor() { - return cb; - } - - /** {@inheritDoc} */ - @Override - public String getControlValue() { - return cb.getSelectionModel().getSelectedItem(); - } - - /*************************************************************************** - * * Private Methods * * - **************************************************************************/ - - private void attachEnterEscapeEventHandler() { - - cb.setOnKeyPressed(new EventHandler<KeyEvent>() { - @Override - public void handle(KeyEvent t) { - if (t.getCode() == KeyCode.ESCAPE) { - cb.setValue(originalValue); - endEdit(false); - } else if (t.getCode() == KeyCode.ENTER) { - endEdit(true); - } - } - }); - } - } - - /** - * A {@link SpreadsheetCellEditor} for {@link SpreadsheetCellType.DateType} - * typed cells. It displays a {@link DatePicker} where the user can choose a - * date through a visual calendar. - */ - public static class DateEditor extends SpreadsheetCellEditor { - - /*************************************************************************** - * * Private Fields * * - **************************************************************************/ - private final DatePicker datePicker; - private EventHandler<KeyEvent> eh; - private ChangeListener<LocalDate> cl; - /** - * This is needed because "endEdit" will call our "end" method too late - * when pressing enter, so several "endEdit" will be called. So this - * prevent that to happen. - */ - private boolean ending = false; - - /*************************************************************************** - * * Constructor * * - **************************************************************************/ - /** - * Constructor for the DateEditor. - * @param view the SpreadsheetView - * @param converter A Converter for converting a date to a String. - */ - public DateEditor(SpreadsheetView view, StringConverter<LocalDate> converter) { - super(view); - datePicker = new DatePicker(); - datePicker.setConverter(converter); - } - - /*************************************************************************** - * * Public Methods * * - **************************************************************************/ - /** {@inheritDoc} */ - @Override - public void startEdit(Object value) { - if (value instanceof LocalDate) { - datePicker.setValue((LocalDate) value); - } - attachEnterEscapeEventHandler(); - datePicker.show(); - datePicker.getEditor().requestFocus(); - } - - /** {@inheritDoc} */ - @Override - public void end() { - if (datePicker.isShowing()) { - datePicker.hide(); - } - datePicker.removeEventFilter(KeyEvent.KEY_PRESSED, eh); - datePicker.valueProperty().removeListener(cl); - } - - /** {@inheritDoc} */ - @Override - public DatePicker getEditor() { - return datePicker; - } - - /** {@inheritDoc} */ - @Override - public String getControlValue() { - return datePicker.getEditor().getText(); - } - - /*************************************************************************** - * * Private Methods * * - **************************************************************************/ - - private void attachEnterEscapeEventHandler() { - /** - * We need to add an EventFilter because otherwise the DatePicker - * will block "escape" and "enter". But when "enter" is hit, we need - * to runLater the commit because the value has not yet hit the - * DatePicker itself. - */ - eh = new EventHandler<KeyEvent>() { - @Override - public void handle(KeyEvent t) { - if (t.getCode() == KeyCode.ENTER) { - ending = true; - endEdit(true); - ending = false; - } else if (t.getCode() == KeyCode.ESCAPE) { - endEdit(false); - } - } - }; - - datePicker.addEventFilter(KeyEvent.KEY_PRESSED, eh); - - cl = new ChangeListener<LocalDate>() { - @Override - public void changed(ObservableValue<? extends LocalDate> arg0, LocalDate arg1, LocalDate arg2) { - if (!ending) - endEdit(true); - } - }; - datePicker.valueProperty().addListener(cl); - } - - } -} diff --git a/src/org/controlsfx/control/spreadsheet/SpreadsheetCellType.java b/src/org/controlsfx/control/spreadsheet/SpreadsheetCellType.java deleted file mode 100644 index 6412af6..0000000 --- a/src/org/controlsfx/control/spreadsheet/SpreadsheetCellType.java +++ /dev/null @@ -1,858 +0,0 @@ -/** - * Copyright (c) 2013, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.spreadsheet; - -import java.text.DecimalFormat; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.util.List; - -import javafx.util.StringConverter; -import javafx.util.converter.DefaultStringConverter; -import javafx.util.converter.DoubleStringConverter; -import javafx.util.converter.IntegerStringConverter; - -/** - * When instantiating a {@link SpreadsheetCell}, its SpreadsheetCellType will - * specify which values the cell can accept as user input, and which - * {@link SpreadsheetCellEditor} it will use to receive user input. <br> - * Different static methods are provided in order to give you access to basic - * types, and to create {@link SpreadsheetCell} easily: - * <ul> - * <li><b>String</b>: Accessible with - * {@link SpreadsheetCellType.StringType#createCell(int, int, int, int, String)} - * .</li> - * <li><b>List</b>: Accessible with - * {@link SpreadsheetCellType.ListType#createCell(int, int, int, int, String)}.</li> - * <li><b>Double</b>: Accessible with - * {@link SpreadsheetCellType.DoubleType#createCell(int, int, int, int, Double)} - * .</li> - * <li><b>Integer</b>: Accessible with - * {@link SpreadsheetCellType.IntegerType#createCell(int, int, int, int, Integer)} - * .</li> - * <li><b>Date</b>: Accessible with - * {@link SpreadsheetCellType.DateType#createCell(int, int, int, int, LocalDate)} - * .</li> - * </ul> - * - * <h3>Value verification</h3> You can specify two levels of verification in your - * types. <br> - * <ul> - * <li>The first one is defined by {@link #match(Object)}. It is the first level - * that tells whether or not the given value should be accepted or not. Trying - * to set a String into a Double will return false for example. This method will - * be use by the {@link SpreadsheetView} when trying to set values for example. - * <br> - * </li> - * <li>The second level is defined by {@link #isError(Object)}. This is more - * subtle and allow you to tell whether the given value is coherent or not - * regarding the policy you gave. You can just make a {@link SpreadsheetCell} - * call this method when its value has changed in order to react accordingly if - * the value is in error. (see example below).</li> - * </ul> - * <h3>Converter</h3> You will have to specify a converter for your type. It - * will handle all the conversion between your real value type (Double, Integer, - * LocalDate etc) and its string representation for the cell. <br> - * You can either use a pre-built {@link StringConverter} or our - * {@link StringConverterWithFormat}. This one just add one method ( - * {@link StringConverterWithFormat#toStringFormat(Object, String)} which will - * convert your value with a String format (found in - * {@link SpreadsheetCell#getFormat()}). - * - * <h3>Example</h3> You can create several types which are using the same - * editor. Suppose you want to handle Double values. You will implement the - * {@link #createEditor(SpreadsheetView)} method and use the - * {@link SpreadsheetCellEditor.DoubleEditor}. <br> - * - * Then for each type you will provide your own policy in {@link #match(Object)} - * and in {@link #isError(Object)}, which most of the time will use your - * {@link #converter}. <br> - * - * Here is an example of how to create a {@link StringConverterWithFormat} : - * - * - * - * <pre> - * - * StringConverterWithFormat specialConverter = new StringConverterWithFormat<Double>(new DoubleStringConverter()) { - * @Override - * public String toString(Double item) { - * //We just redirect to the other method. - * return toStringFormat(item, ""); - * } - * - * @Override - * public String toStringFormat(Double item, String format) { - * if (item == null || Double.isNaN(item)) { - * return missingLabel; // For example return something else that an empty cell. - * } else{ - * if (!("").equals(format) && !Double.isNaN(item)) { - * //We format here the value - * return new DecimalFormat(format).format(item); - * } else { - * //We call the DoubleStringConverter that we gave in argument - * return myConverter.toString(item); - * } - * } - * } - * - * @Override - * public Double fromString(String str) { - * if (str == null || str.isEmpty()) { - * return Double.NaN; - * } else { - * try { - * //Just returning the value - * Double myDouble = Double.parseDouble(str); - * return myDouble; - * - * } catch (NumberFormatException e) { - * return myConverter.fromString(str); - * } - * } - * } - * } - * - * </pre> - * - * And then suppose you only want to accept double values between 0 and 100, and - * that a value superior to 10 is abnormal. <br> - * - * <pre> - * @Override - * public boolean isError(Object value) { - * if (value instanceof Double) { - * if ((Double) value > 0 && (Double) value < 10) { - * return false; - * } - * return true; - * } - * return true; - * } - * - * @Override - * public boolean match(Object value) { - * if (value instanceof Double) { - * return true; - * } else { - * try { - * Double convertedValue = converter.fromString(value == null ? null : value.toString()); - * if (convertedValue >= 0 && convertedValue <= 100) - * return true; - * else - * return false; - * } catch (Exception e) { - * return false; - * } - * } - * } - * </pre> - * - * @see SpreadsheetView - * @see SpreadsheetCellEditor - * @see SpreadsheetCell - */ -public abstract class SpreadsheetCellType<T> { - /** An instance of converter from string to cell type. */ - protected StringConverter<T> converter; - - /** - * Default constructor. - */ - public SpreadsheetCellType() { - - } - - /** - * Constructor with the StringConverter directly provided. - * - * @param converter - * The converter to use - */ - public SpreadsheetCellType(StringConverter<T> converter) { - this.converter = converter; - } - - /** - * Creates an editor for this type of cells. - * - * @param view - * the spreadsheet that will own this editor - * @return the editor instance - */ - public abstract SpreadsheetCellEditor createEditor(SpreadsheetView view); - - /** - * Return a string representation of the given item for the - * {@link SpreadsheetView} to display using the inner - * {@link SpreadsheetCellType#converter} and the specified format. - * - * @param object - * @param format - * @return a string representation of the given item. - */ - public String toString(T object, String format) { - return toString(object); - } - - /** - * Return a string representation of the given item for the - * {@link SpreadsheetView} to display using the inner - * {@link SpreadsheetCellType#converter}. - * - * @param object - * @return a string representation of the given item. - */ - public abstract String toString(T object); - - /** - * Verify that the upcoming value can be set to the current cell. This is - * the first level of verification to prevent affecting a text to a double - * or a double to a date. For closer verification, use - * {@link #isError(Object)}. - * - * @param value - * the value to test - * @return true if it matches. - */ - public abstract boolean match(Object value); - - /** - * Returns true if the value is an error regarding the specification of its - * type. - * - * @param value - * @return true if the value is an error. - */ - public boolean isError(Object value) { - return false; - } - - /** - * - * @return true if this SpreadsheetCellType accepts Objects to be dropped on - * the {@link SpreadsheetCell}. Currently only Files can be dropped. If - * accepted, prepare to receive them in {@link #match(java.lang.Object) } - * and {@link #convertValue(java.lang.Object) }. - */ - public boolean acceptDrop() { - return false; - } - - /** - * This method will be called when a commit is happening.<br> - * This method will try to convert the value, be sure to call - * {@link #match(Object)} before to see if this method will succeed. - * - * @param value - * @return null if not valid or the correct value otherwise. - */ - public abstract T convertValue(Object value); - - /** - * The {@link SpreadsheetCell} {@link Object} type instance. - */ - public static final SpreadsheetCellType<Object> OBJECT = new ObjectType(); - - /** - * The {@link SpreadsheetCell} {@link Object} type base class. - */ - public static class ObjectType extends SpreadsheetCellType<Object> { - - public ObjectType() { - this(new StringConverterWithFormat<Object>() { - @Override - public Object fromString(String arg0) { - return arg0; - } - - @Override - public String toString(Object arg0) { - return arg0 == null ? "" : arg0.toString(); //$NON-NLS-1$ - } - }); - } - - public ObjectType(StringConverterWithFormat<Object> converter) { - super(converter); - } - - @Override - public String toString() { - return "object"; //$NON-NLS-1$ - } - - @Override - public boolean match(Object value) { - return true; - } - - /** - * Creates a cell that hold an Object at the specified position, with the - * specified row/column span. - * - * @param row - * row number - * @param column - * column number - * @param rowSpan - * rowSpan (1 is normal) - * @param columnSpan - * ColumnSpan (1 is normal) - * @param value - * the value to display - * @return a {@link SpreadsheetCell} - */ - public SpreadsheetCell createCell(final int row, final int column, final int rowSpan, final int columnSpan, - final Object value) { - SpreadsheetCell cell = new SpreadsheetCellBase(row, column, rowSpan, columnSpan, this); - cell.setItem(value); - return cell; - } - - @Override - public SpreadsheetCellEditor createEditor(SpreadsheetView view) { - return new SpreadsheetCellEditor.ObjectEditor(view); - } - - @Override - public Object convertValue(Object value) { - return value; - } - - @Override - public String toString(Object item) { - return converter.toString(item); - } - - }; - - /** - * The {@link SpreadsheetCell} {@link String} type instance. - */ - public static final StringType STRING = new StringType(); - - /** - * The {@link SpreadsheetCell} {@link String} type base class. - */ - public static class StringType extends SpreadsheetCellType<String> { - - public StringType() { - this(new DefaultStringConverter()); - } - - public StringType(StringConverter<String> converter) { - super(converter); - } - - @Override - public String toString() { - return "string"; //$NON-NLS-1$ - } - - @Override - public boolean match(Object value) { - return true; - } - - /** - * Creates a cell that hold a String at the specified position, with the - * specified row/column span. - * - * @param row - * row number - * @param column - * column number - * @param rowSpan - * rowSpan (1 is normal) - * @param columnSpan - * ColumnSpan (1 is normal) - * @param value - * the value to display - * @return a {@link SpreadsheetCell} - */ - public SpreadsheetCell createCell(final int row, final int column, final int rowSpan, final int columnSpan, - final String value) { - SpreadsheetCell cell = new SpreadsheetCellBase(row, column, rowSpan, columnSpan, this); - cell.setItem(value); - return cell; - } - - @Override - public SpreadsheetCellEditor createEditor(SpreadsheetView view) { - return new SpreadsheetCellEditor.StringEditor(view); - } - - @Override - public String convertValue(Object value) { - String convertedValue = converter.fromString(value == null ? null : value.toString()); - if (convertedValue == null || convertedValue.equals("")) { //$NON-NLS-1$ - return null; - } - return convertedValue; - } - - @Override - public String toString(String item) { - return converter.toString(item); - } - - }; - - /** - * The {@link SpreadsheetCell} {@link Double} type instance. - */ - public static final DoubleType DOUBLE = new DoubleType(); - - /** - * The {@link SpreadsheetCell} {@link Double} type base class. - */ - public static class DoubleType extends SpreadsheetCellType<Double> { - - public DoubleType() { - - this(new StringConverterWithFormat<Double>(new DoubleStringConverter()) { - @Override - public String toString(Double item) { - return toStringFormat(item, ""); //$NON-NLS-1$ - } - - @Override - public Double fromString(String str) { - if (str == null || str.isEmpty() || "NaN".equals(str)) { //$NON-NLS-1$ - return Double.NaN; - } else { - return myConverter.fromString(str); - } - } - - @Override - public String toStringFormat(Double item, String format) { - try { - if (item == null || Double.isNaN(item)) { - return ""; //$NON-NLS-1$ - } else { - return new DecimalFormat(format).format(item); - } - } catch (Exception ex) { - return myConverter.toString(item); - } - } - }); - } - - public DoubleType(StringConverter<Double> converter) { - super(converter); - } - - @Override - public String toString() { - return "double"; //$NON-NLS-1$ - } - - /** - * Creates a cell that hold a Double at the specified position, with the - * specified row/column span. - * - * @param row - * row number - * @param column - * column number - * @param rowSpan - * rowSpan (1 is normal) - * @param columnSpan - * ColumnSpan (1 is normal) - * @param value - * the value to display - * @return a {@link SpreadsheetCell} - */ - public SpreadsheetCell createCell(final int row, final int column, final int rowSpan, final int columnSpan, - final Double value) { - SpreadsheetCell cell = new SpreadsheetCellBase(row, column, rowSpan, columnSpan, this); - cell.setItem(value); - return cell; - } - - @Override - public SpreadsheetCellEditor createEditor(SpreadsheetView view) { - return new SpreadsheetCellEditor.DoubleEditor(view); - } - - @Override - public boolean match(Object value) { - if (value instanceof Double) - return true; - else { - try { - converter.fromString(value == null ? null : value.toString()); - return true; - } catch (Exception e) { - return false; - } - } - } - - @Override - public Double convertValue(Object value) { - if (value instanceof Double) - return (Double) value; - else { - try { - return converter.fromString(value == null ? null : value.toString()); - } catch (Exception e) { - return null; - } - } - } - - @Override - public String toString(Double item) { - return converter.toString(item); - } - - @Override - public String toString(Double item, String format) { - return ((StringConverterWithFormat<Double>) converter).toStringFormat(item, format); - } - }; - - /** - * The {@link SpreadsheetCell} {@link Integer} type instance. - */ - public static final IntegerType INTEGER = new IntegerType(); - - /** - * The {@link SpreadsheetCell} {@link Integer} type base class. - */ - public static class IntegerType extends SpreadsheetCellType<Integer> { - - public IntegerType() { - this(new IntegerStringConverter() { - @Override - public String toString(Integer item) { - if (item == null || Double.isNaN(item)) { - return ""; //$NON-NLS-1$ - } else { - return super.toString(item); - } - } - - @Override - public Integer fromString(String str) { - if (str == null || str.isEmpty() || "NaN".equals(str)) { //$NON-NLS-1$ - return null; - } else { - // We try to integrate Double if possible by truncating - // them - try { - Double temp = Double.parseDouble(str); - return temp.intValue(); - } catch (Exception e) { - return super.fromString(str); - } - } - } - }); - } - - public IntegerType(IntegerStringConverter converter) { - super(converter); - } - - @Override - public String toString() { - return "Integer"; //$NON-NLS-1$ - } - - /** - * Creates a cell that hold a Integer at the specified position, with the - * specified row/column span. - * - * @param row - * row number - * @param column - * column number - * @param rowSpan - * rowSpan (1 is normal) - * @param columnSpan - * ColumnSpan (1 is normal) - * @param value - * the value to display - * @return a {@link SpreadsheetCell} - */ - public SpreadsheetCell createCell(final int row, final int column, final int rowSpan, final int columnSpan, - final Integer value) { - SpreadsheetCell cell = new SpreadsheetCellBase(row, column, rowSpan, columnSpan, this); - cell.setItem(value); - return cell; - } - - @Override - public SpreadsheetCellEditor createEditor(SpreadsheetView view) { - return new SpreadsheetCellEditor.IntegerEditor(view); - } - - @Override - public boolean match(Object value) { - if (value instanceof Integer) - return true; - else { - try { - converter.fromString(value == null ? null : value.toString()); - return true; - } catch (Exception e) { - return false; - } - } - } - - @Override - public Integer convertValue(Object value) { - if (value instanceof Integer) - return (Integer) value; - else { - try { - return converter.fromString(value == null ? null : value.toString()); - } catch (Exception e) { - return null; - } - } - } - - @Override - public String toString(Integer item) { - return converter.toString(item); - } - }; - - /** - * Creates a {@link ListType}. - * - * @param items - * the list items - * @return the instance - */ - public static final ListType LIST(final List<String> items) { - return new ListType(items); - } - - /** - * The {@link SpreadsheetCell} {@link List} type base class. - */ - public static class ListType extends SpreadsheetCellType<String> { - protected final List<String> items; - - public ListType(final List<String> items) { - super(new DefaultStringConverter() { - @Override - public String fromString(String str) { - if (str != null && items.contains(str)) { - return str; - } else { - return null; - } - } - - }); - this.items = items; - } - - @Override - public String toString() { - return "list"; //$NON-NLS-1$ - } - - /** - * Creates a cell that hold a String at the specified position, with the - * specified row/column span. - * - * @param row - * row number - * @param column - * column number - * @param rowSpan - * rowSpan (1 is normal) - * @param columnSpan - * ColumnSpan (1 is normal) - * @param value - * the value to display - * @return a {@link SpreadsheetCell} - */ - public SpreadsheetCell createCell(final int row, final int column, final int rowSpan, final int columnSpan, - String value) { - SpreadsheetCell cell = new SpreadsheetCellBase(row, column, rowSpan, columnSpan, this); - if (items != null && items.size() > 0) { - if (value != null && items.contains(value)) { - cell.setItem(value); - } else { - cell.setItem(items.get(0)); - } - } - return cell; - } - - @Override - public SpreadsheetCellEditor createEditor(SpreadsheetView view) { - return new SpreadsheetCellEditor.ListEditor<>(view, items); - } - - @Override - public boolean match(Object value) { - if (value instanceof String && items.contains(value.toString())) - return true; - else - return items.contains(value == null ? null : value.toString()); - } - - @Override - public String convertValue(Object value) { - return converter.fromString(value == null ? null : value.toString()); - } - - @Override - public String toString(String item) { - return converter.toString(item); - } - } - - /** - * The {@link SpreadsheetCell} {@link LocalDate} type instance. - */ - public static final DateType DATE = new DateType(); - - /** - * The {@link SpreadsheetCell} {@link LocalDate} type base class. - */ - public static class DateType extends SpreadsheetCellType<LocalDate> { - - /** - * Creates a new DateType. - */ - public DateType() { - this(new StringConverterWithFormat<LocalDate>() { - @Override - public String toString(LocalDate item) { - return toStringFormat(item, ""); //$NON-NLS-1$ - } - - @Override - public LocalDate fromString(String str) { - try { - return LocalDate.parse(str); - } catch (Exception e) { - return null; - } - } - - @Override - public String toStringFormat(LocalDate item, String format) { - if (("").equals(format) && item != null) { //$NON-NLS-1$ - return item.toString(); - } else if (item != null) { - return item.format(DateTimeFormatter.ofPattern(format)); - } else { - return ""; //$NON-NLS-1$ - } - } - }); - } - - public DateType(StringConverter<LocalDate> converter) { - super(converter); - } - - @Override - public String toString() { - return "date"; //$NON-NLS-1$ - } - - /** - * Creates a cell that hold a LocalDate at the specified position, with the - * specified row/column span. - * - * @param row - * row number - * @param column - * column number - * @param rowSpan - * rowSpan (1 is normal) - * @param columnSpan - * ColumnSpan (1 is normal) - * @param value - * the value to display - * @return a {@link SpreadsheetCell} - */ - public SpreadsheetCell createCell(final int row, final int column, final int rowSpan, final int columnSpan, - final LocalDate value) { - SpreadsheetCell cell = new SpreadsheetCellBase(row, column, rowSpan, columnSpan, this); - cell.setItem(value); - return cell; - } - - @Override - public SpreadsheetCellEditor createEditor(SpreadsheetView view) { - return new SpreadsheetCellEditor.DateEditor(view, converter); - } - - @Override - public boolean match(Object value) { - if (value instanceof LocalDate) - return true; - else { - try { - LocalDate temp = converter.fromString(value == null ? null : value.toString()); - return temp != null; - } catch (Exception e) { - return false; - } - } - } - - @Override - public LocalDate convertValue(Object value) { - if (value instanceof LocalDate) - return (LocalDate) value; - else { - try { - return converter.fromString(value == null ? null : value.toString()); - } catch (Exception e) { - return null; - } - } - } - - @Override - public String toString(LocalDate item) { - return converter.toString(item); - } - - @Override - public String toString(LocalDate item, String format) { - return ((StringConverterWithFormat<LocalDate>) converter).toStringFormat(item, format); - } - } -} \ No newline at end of file diff --git a/src/org/controlsfx/control/spreadsheet/SpreadsheetColumn.java b/src/org/controlsfx/control/spreadsheet/SpreadsheetColumn.java deleted file mode 100644 index bf45a1e..0000000 --- a/src/org/controlsfx/control/spreadsheet/SpreadsheetColumn.java +++ /dev/null @@ -1,372 +0,0 @@ -/** - * Copyright (c) 2013, 2016 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.spreadsheet; - -import static impl.org.controlsfx.i18n.Localization.asKey; -import static impl.org.controlsfx.i18n.Localization.localize; -import impl.org.controlsfx.spreadsheet.CellView; -import java.util.List; -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; -import javafx.beans.property.DoubleProperty; -import javafx.beans.property.ReadOnlyDoubleProperty; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.collections.ObservableList; -import javafx.event.ActionEvent; -import javafx.event.EventHandler; -import javafx.scene.control.ContextMenu; -import javafx.scene.control.MenuItem; -import javafx.scene.control.TableColumn; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import javafx.stage.WindowEvent; -import org.controlsfx.tools.Utils; - -/** - * A {@link SpreadsheetView} is made up of a number of {@link SpreadsheetColumn} - * instances. - * - * <h3>Configuration</h3> SpreadsheetColumns are instantiated by the - * {@link SpreadsheetView} itself, so there is no public constructor for this - * class. To access the available columns, you need to call - * {@link SpreadsheetView#getColumns()}. - * - * <p> - * SpreadsheetColumn gives you the ability to modify some aspects of the column, - * for example the {@link #setPrefWidth(double) width} or - * {@link #setResizable(boolean) resizability} of the column. - * - * <p> - * You have the ability to fix this column at the left of the SpreadsheetView by - * calling {@link #setFixed(boolean)}. But you are strongly advised to check if - * it is possible with {@link #isColumnFixable()} before calling - * {@link #setFixed(boolean)}. Take a look at the {@link SpreadsheetView} - * description to understand the fixing constraints. - * - * <p> - * If the column can be fixed, a {@link ContextMenu} will appear if the user right-clicks on it. - * If not, nothing will appear and the user will not have the possibility to fix it. - * - * <h3>Screenshot</h3> - * The column <b>A</b> is fixed and is covering column <b>B</b> and partially - * column <b>C</b>. The context menu is being shown and offers the possibility - * to unfix the column. - * - * <br> - * <br> - * <center><img src="fixedColumn.png" alt="Screenshot of SpreadsheetColumn"></center> - * - * @see SpreadsheetView - */ -public final class SpreadsheetColumn { - - /*************************************************************************** - * * Private Fields * * - **************************************************************************/ - private final SpreadsheetView spreadsheetView; - final TableColumn<ObservableList<SpreadsheetCell>, SpreadsheetCell> column; - private final boolean canFix; - private final Integer indexColumn; - private MenuItem fixItem; - - /*************************************************************************** - * * Constructor * * - **************************************************************************/ - /** - * Creates a new SpreadsheetColumn. - * - * @param column - * @param spreadsheetView - * @param indexColumn - */ - SpreadsheetColumn(final TableColumn<ObservableList<SpreadsheetCell>, SpreadsheetCell> column, - final SpreadsheetView spreadsheetView, final Integer indexColumn, Grid grid) { - this.spreadsheetView = spreadsheetView; - this.column = column; - column.setMinWidth(0); - this.indexColumn = indexColumn; - canFix = initCanFix(grid); - - // The contextMenu creation must be on the JFX thread - CellView.getValue(() -> { - column.setContextMenu(getColumnContextMenu()); - }); - - // When changing frozen fixed columns, we need to update the ContextMenu. - spreadsheetView.fixingColumnsAllowedProperty().addListener(new ChangeListener<Boolean>() { - - @Override - public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) { - CellView.getValue(() -> { - column.setContextMenu(getColumnContextMenu()); - }); - } - }); - - // When ColumnsHeaders are changing, we update the text - grid.getColumnHeaders().addListener(new InvalidationListener() { - @Override - public void invalidated(Observable arg0) { - List<String> columnsHeader = spreadsheetView.getGrid().getColumnHeaders(); - if (columnsHeader.size() <= indexColumn) { - setText(Utils.getExcelLetterFromNumber(indexColumn)); - } else if (!columnsHeader.get(indexColumn).equals(getText())) { - setText(columnsHeader.get(indexColumn)); - } - } - }); - - // When changing rows, we re-calculate if this columns can be fixed. - grid.getRows().addListener(new InvalidationListener() { - @Override - public void invalidated(Observable arg0) { - initCanFix(grid); - } - }); - } - - /*************************************************************************** - * * Public Methods * * - **************************************************************************/ - - /** - * Return whether this column is fixed or not. - * - * @return true if this column is fixed. - */ - public boolean isFixed() { - return spreadsheetView.getFixedColumns().contains(this); - } - - /** - * Fix this column to the left if possible, although it is recommended that - * you call {@link #isColumnFixable()} before trying to fix a column. - * - * If you want to fix several columns (because of a span for example), add - * all the columns directly in {@link SpreadsheetView#getFixedColumns() }. - * Always use {@link SpreadsheetView#areSpreadsheetColumnsFixable(java.util.List) - * } before. - * - * @param fixed - */ - public void setFixed(boolean fixed) { - if (fixed) { - spreadsheetView.getFixedColumns().add(this); - } else { - spreadsheetView.getFixedColumns().removeAll(this); - } - } - - /** - * Set the width of this column. - * - * @param width - */ - public void setPrefWidth(double width) { - width = Math.ceil(width); - if (column.getPrefWidth() == width && column.getWidth() != width) { - column.impl_setWidth(width); - } else { - column.setPrefWidth(width); - } - spreadsheetView.columnWidthSet(indexColumn); - } - - /** - * Return the actual width of the column. - * - * @return the actual width of the column - */ - public double getWidth() { - return column.getWidth(); - } - - /** - * Return the Property related to the actual width of the column. - * - * @return - */ - public final ReadOnlyDoubleProperty widthProperty() { - return column.widthProperty(); - } - - /** - * Set the minimum width for this SpreadsheetColumn. - * - * @param value - */ - public final void setMinWidth(double value) { - column.setMinWidth(value); - } - - /** - * Return the minimum width for this SpreadsheetColumn. - * - * @return - */ - public final double getMinWidth() { - return column.getMinWidth(); - } - - /** - * Return the Property related to the minimum width of this - * SpreadsheetColumn. - * - * @return - */ - public final DoubleProperty minWidthProperty() { - return column.minWidthProperty(); - } - - /** - * Return the Property related to the maximum width of this - * SpreadsheetColumn. - * - * @return - */ - public final DoubleProperty maxWidthProperty() { - return column.maxWidthProperty(); - } - - /** - * Set the maximum width for this SpreadsheetColumn. - * - * @param value - */ - public final void setMaxWidth(double value) { - column.setMaxWidth(value); - } - - /** - * Return the maximum width for this SpreadsheetColumn. - * - * @return - */ - public final double getMaxWidth() { - return column.getMaxWidth(); - } - /** - * If this column can be resized by the user - * - * @param b - */ - public void setResizable(boolean b) { - column.setResizable(b); - } - - /** - * If the column is resizable, it will compute the optimum width for all the - * visible cells to be visible. - */ - public void fitColumn() { - if (column.isResizable() && spreadsheetView.getCellsViewSkin() != null) { - spreadsheetView.getCellsViewSkin().resize(column, 100); - } - } - - /** - * Indicate whether this column can be fixed or not. Call that method before - * calling {@link #setFixed(boolean)} or adding an item to - * {@link SpreadsheetView#getFixedColumns()}. - * - * A column cannot be fixed alone if any cell inside the column has a column - * span superior to one. - * - * @return true if this column is fixable. - */ - public boolean isColumnFixable() { - return canFix && spreadsheetView.isFixingColumnsAllowed(); - } - - /*************************************************************************** - * * Private Methods * * - **************************************************************************/ - private void setText(String text) { - column.setText(text); - } - - private String getText() { - return column.getText(); - } - - /** - * Generate a context Menu in order to fix/unfix some column It is shown - * when right-clicking on the column header - * - * @return a context menu. - */ - private ContextMenu getColumnContextMenu() { - if (isColumnFixable()) { - final ContextMenu contextMenu = new ContextMenu(); - - this.fixItem = new MenuItem(localize(asKey("spreadsheet.column.menu.fix"))); //$NON-NLS-1$ - contextMenu.setOnShowing(new EventHandler<WindowEvent>() { - - @Override - public void handle(WindowEvent event) { - if (!isFixed()) { - fixItem.setText(localize(asKey("spreadsheet.column.menu.fix"))); //$NON-NLS-1$ - } else { - fixItem.setText(localize(asKey("spreadsheet.column.menu.unfix"))); //$NON-NLS-1$ - } - } - }); - fixItem.setGraphic(new ImageView(new Image(getClass().getResourceAsStream("pinSpreadsheetView.png")))); //$NON-NLS-1$ - fixItem.setOnAction(new EventHandler<ActionEvent>() { - @Override - public void handle(ActionEvent arg0) { - if (!isFixed()) { - setFixed(true); - } else { - setFixed(false); - } - } - }); - contextMenu.getItems().addAll(fixItem); - - return contextMenu; - } else { - return new ContextMenu(); - } - } - - /** - * Verify that you can fix this column. - * - * @return if it's fixable. - */ - private boolean initCanFix(Grid grid) { - for (ObservableList<SpreadsheetCell> row : grid.getRows()) { - int columnSpan = row.get(indexColumn).getColumnSpan(); - if (columnSpan > 1) { - return false; - } - } - return true; - } -} diff --git a/src/org/controlsfx/control/spreadsheet/SpreadsheetView.java b/src/org/controlsfx/control/spreadsheet/SpreadsheetView.java deleted file mode 100644 index fef7658..0000000 --- a/src/org/controlsfx/control/spreadsheet/SpreadsheetView.java +++ /dev/null @@ -1,1928 +0,0 @@ -/** - * Copyright (c) 2013, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.spreadsheet; - -import static impl.org.controlsfx.i18n.Localization.asKey; -import static impl.org.controlsfx.i18n.Localization.localize; -import impl.org.controlsfx.spreadsheet.CellView; -import impl.org.controlsfx.spreadsheet.FocusModelListener; -import impl.org.controlsfx.spreadsheet.GridViewSkin; -import impl.org.controlsfx.spreadsheet.RectangleSelection.GridRange; -import impl.org.controlsfx.spreadsheet.RectangleSelection.SelectionRange; -import impl.org.controlsfx.spreadsheet.SpreadsheetGridView; -import impl.org.controlsfx.spreadsheet.SpreadsheetHandle; -import impl.org.controlsfx.spreadsheet.TableViewSpanSelectionModel; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectOutputStream; -import java.util.ArrayList; -import java.util.BitSet; -import java.util.IdentityHashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.FutureTask; -import java.util.logging.Level; -import java.util.logging.Logger; -import javafx.application.Platform; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.DoubleProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.ReadOnlyBooleanProperty; -import javafx.beans.property.ReadOnlyObjectProperty; -import javafx.beans.property.ReadOnlyObjectWrapper; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.SimpleDoubleProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.beans.value.WeakChangeListener; -import javafx.collections.FXCollections; -import javafx.collections.ListChangeListener; -import javafx.collections.ObservableList; -import javafx.collections.ObservableMap; -import javafx.event.ActionEvent; -import javafx.event.Event; -import javafx.event.EventHandler; -import javafx.event.EventType; -import javafx.event.WeakEventHandler; -import javafx.scene.Node; -import javafx.scene.control.ContextMenu; -import javafx.scene.control.Control; -import javafx.scene.control.Menu; -import javafx.scene.control.MenuItem; -import javafx.scene.control.ScrollBar; -import javafx.scene.control.SelectionMode; -import javafx.scene.control.Skin; -import javafx.scene.control.TableColumn; -import javafx.scene.control.TablePosition; -import javafx.scene.control.TableView; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import javafx.scene.input.Clipboard; -import javafx.scene.input.ClipboardContent; -import javafx.scene.input.DataFormat; -import javafx.scene.input.KeyCode; -import javafx.scene.input.KeyCodeCombination; -import javafx.scene.input.KeyCombination; -import javafx.scene.input.KeyEvent; -import javafx.stage.WindowEvent; -import javafx.util.Pair; - -import org.controlsfx.control.PropertySheet.Item; -import org.controlsfx.tools.Utils; - -/** - * The SpreadsheetView is a control similar to the JavaFX {@link TableView} - * control but with different functionalities and use cases. The aim is to have - * a powerful grid where data can be written and retrieved. - * - * <h3>Features</h3> - * <ul> - * <li>Cells can span in row and in column.</li> - * <li>Rows can be fixed to the top of the {@link SpreadsheetView} so that they - * are always visible on screen.</li> - * <li>Columns can be fixed to the left of the {@link SpreadsheetView} so that - * they are always visible on screen.</li> - * <li>A row header can be switched on in order to display the row number.</li> - * <li>Rows can be resized just like columns with click & drag.</li> - * <li>Both row and column header can be visible or invisible.</li> - * <li>Selection of several cells can be made with a click and drag.</li> - * <li>A copy/paste context menu is accessible with a right-click. The usual - * shortcuts are also working.</li> - * <li>{@link Picker} can be placed above column header or to the side of the - * row header.</li> - * </ul> - * - * <br> - * - * <h3>Fixing Rows and Columns</h3> - * <br> - * You can fix some rows and some columns by right-clicking on their header. A - * context menu will appear if it's possible to fix them. When fixed, the label - * header will then be in italic and the background will turn to dark grey. - * <br> - * You have also the possibility to fix them manually by adding and removing - * items from {@link #getFixedRows()} and {@link #getFixedColumns()}. But you - * are strongly advised to check if it's possible to do so with - * {@link SpreadsheetColumn#isColumnFixable()} for the fixed columns and with - * {@link #isRowFixable(int)} for the fixed rows. - * <br> - * - * A set of rows cannot be fixed if any cell inside these rows has a row span - * superior to the number of fixed rows. Likewise, a set of columns cannot be - * fixed if any cell inside these columns has a column span superior to the - * number of fixed columns. - * - * <br><br> - * If you want to fix several rows or columns together, and they have a span - * inside, you can call {@link #areRowsFixable(java.util.List) } or {@link #areSpreadsheetColumnsFixable(java.util.List) - * } - * to verify if you can fix them. Be sure to add them all in once otherwise the - * system will detect that a span is going out of bounds and will throw an - * exception. - * - * Calling those methods prior - * every move will ensure that no exception will be thrown. - * <br><br> - * You have also the possibility to deactivate these possibilities. For example, - * you force some row/column to be fixed and then the user cannot change the - * settings. - * <br> - * - * <h3>Headers</h3> - * <br> - * You can also access and toggle header's visibility by using the methods - * provided like {@link #setShowRowHeader(boolean) } or {@link #setShowColumnHeader(boolean) - * }. - * - * <br> - * Users can double-click on a column header will resize the column to the best - * size in order to fully see each cell in it. Same rule apply for row header. - * Also note that double-clicking on the little space between two row or two - * columns (when resizable) will also work just like Excel. - * - * <h3>Pickers</h3> - * <br> - * - * You can show some little images next to the headers. They will appear on the - * left of the VerticalHeader and on top on the HorizontalHeader. They are called - * "picker" because they were used originally for picking a row or a column to - * insert in the SpreadsheetView. - * <br> - * But you can do anything you want with it. Simply put a row or a column index - * in {@link #getRowPickers() } and {@link #getColumnPickers() } along with an - * instance of {@link Picker}. You can override the {@link Picker#onClick() } - * method in order to react when the user click on the picker. - * <br> - * The pickers will appear on the top of the column's header and on the left of - * the row's header. - * <br> - * - * <h3>Copy pasting</h3> You can copy any cell you want and paste it elsewhere. - * Be aware that only the value inside will be pasted, not the style nor the - * type. Thus the value you're trying to paste must be compatible with the - * {@link SpreadsheetCellType} of the receiving cell. Pasting a Double into a - * String will work but the reverse operation will not. - * <br> - * See {@link SpreadsheetCellType} <i>Value Verification</i> documentation for more - * information. - * <br> - * A unique cell or a selection can be copied and pasted. - * - * <br> - * <br> - * <h3>Code Samples</h3> Just like the {@link TableView}, you instantiate the - * underlying model, a {@link Grid}. You will create some rows filled with {@link SpreadsheetCell}. - * - * <br> - * <br> - * - * <pre> - * int rowCount = 15; - * int columnCount = 10; - * GridBase grid = new GridBase(rowCount, columnCount); - * - * ObservableList<ObservableList<SpreadsheetCell>> rows = FXCollections.observableArrayList(); - * for (int row = 0; row < grid.getRowCount(); ++row) { - * final ObservableList<SpreadsheetCell> list = FXCollections.observableArrayList(); - * for (int column = 0; column < grid.getColumnCount(); ++column) { - * list.add(SpreadsheetCellType.STRING.createCell(row, column, 1, 1,"value")); - * } - * rows.add(list); - * } - * grid.setRows(rows); - * - * SpreadsheetView spv = new SpreadsheetView(grid); - * - * </pre> - * - * At that moment you can span some of the cells with the convenient method - * provided by the grid. Then you just need to instantiate the SpreadsheetView. <br> - * <h3>Visual:</h3> <center><img src="spreadsheetView.png" alt="Screenshot of SpreadsheetView"></center> - * - * @see SpreadsheetCell - * @see SpreadsheetCellBase - * @see SpreadsheetColumn - * @see Grid - * @see GridBase - * @see Picker - */ -public class SpreadsheetView extends Control{ - - /*************************************************************************** - * * Static Fields * * - **************************************************************************/ - - /** - * The SpanType describes in which state each cell can be. When a spanning - * is occurring, one cell is becoming larger and the others are becoming - * invisible. Thus, that particular cell is masking the others. <br> - * <br> - * But the SpanType cannot be known in advance because it's evolving for - * each cell during the lifetime of the {@link SpreadsheetView}. Suppose you - * have a cell spanning in row, the first one is in a ROW_VISIBLE state, and - * all the other below are in a ROW_SPAN_INVISIBLE state. But if the user is - * scrolling down, the first will go out of sight. At that moment, the - * second cell is switching from ROW_SPAN_INVISIBLE state to ROW_VISIBLE - * state. <br> - * <br> - * - * <center><img src="spanType.png" alt="Screenshot of SpreadsheetView.SpanType"></center> - * Refer to {@link SpreadsheetView} for more information. - */ - public static enum SpanType { - - /** - * Visible cell, can be a unique cell (no span) or the first one inside - * a column spanning cell. - */ - NORMAL_CELL, - - /** - * Invisible cell because a cell in a NORMAL_CELL state on the left is - * covering it. - */ - COLUMN_SPAN_INVISIBLE, - - /** - * Invisible cell because a cell in a ROW_VISIBLE state on the top is - * covering it. - */ - ROW_SPAN_INVISIBLE, - - /** Visible Cell but has some cells below in a ROW_SPAN_INVISIBLE state. */ - ROW_VISIBLE, - - /** - * Invisible cell situated in diagonal of a cell in a ROW_VISIBLE state. - */ - BOTH_INVISIBLE; - } - - /** - * Default width of the VerticalHeader. - */ - private static final double DEFAULT_ROW_HEADER_WIDTH = 30.0; - /*************************************************************************** - * * Private Fields * * - **************************************************************************/ - - protected final SpreadsheetGridView cellsView;// The main cell container. - private SimpleObjectProperty<Grid> gridProperty = new SimpleObjectProperty<>(); - private DataFormat fmt; - - private final ObservableList<Integer> fixedRows = FXCollections.observableArrayList(); - private final ObservableList<SpreadsheetColumn> fixedColumns = FXCollections.observableArrayList(); - - private final BooleanProperty fixingRowsAllowedProperty = new SimpleBooleanProperty(true); - private final BooleanProperty fixingColumnsAllowedProperty = new SimpleBooleanProperty(true); - - private final BooleanProperty showColumnHeader = new SimpleBooleanProperty(true, "showColumnHeader", true); //$NON-NLS-1$ - private final BooleanProperty showRowHeader = new SimpleBooleanProperty(true, "showRowHeader", true); //$NON-NLS-1$ - - private BitSet rowFix; // Compute if we can fix the rows or not. - - private final ObservableMap<Integer, Picker> rowPickers = FXCollections.observableHashMap(); - - private final ObservableMap<Integer, Picker> columnPickers = FXCollections.observableHashMap(); - - // Properties needed by the SpreadsheetView and managed by the skin (source - // is the VirtualFlow) - private ObservableList<SpreadsheetColumn> columns = FXCollections.observableArrayList(); - private Map<SpreadsheetCellType<?>, SpreadsheetCellEditor> editors = new IdentityHashMap<>(); - private final SpreadsheetViewSelectionModel selectionModel; - - /** - * The vertical header width, just for the Label, not the Pickers. - */ - private final DoubleProperty rowHeaderWidth = new SimpleDoubleProperty(DEFAULT_ROW_HEADER_WIDTH); - - /** - * Since the default with applied to TableColumn is 80. If a user sets a - * width of 80, the column will be detected as having the default with and - * therefore will be requested to be autosized. In order to prevent that, we - * must detect which columns has been specifically set and which not. With - * that BitSet, we are able to make the difference between a "default" 80 - * width applied by the system, and a 80 width applid by a user. - */ - private final BitSet columnWidthSet = new BitSet(); - // The handle that bridges with implementation. - final SpreadsheetHandle handle = new SpreadsheetHandle() { - - @Override - protected SpreadsheetView getView() { - return SpreadsheetView.this; - } - - @Override - protected GridViewSkin getCellsViewSkin() { - return SpreadsheetView.this.getCellsViewSkin(); - } - - @Override - protected SpreadsheetGridView getGridView() { - return SpreadsheetView.this.getCellsView(); - } - - @Override - protected boolean isColumnWidthSet(int indexColumn) { - return columnWidthSet.get(indexColumn); - } - }; - - /** - * @return the inner table view skin - */ - public final GridViewSkin getCellsViewSkin() { - return (GridViewSkin) (cellsView.getSkin()); - } - - /** - * @return the inner table view - */ - final SpreadsheetGridView getCellsView() { - return cellsView; - } - - /** - * Used by {@link SpreadsheetColumn} internally in order to specify if a - * column width has been set by the user. - * - * @param indexColumn - */ - void columnWidthSet(int indexColumn) { - columnWidthSet.set(indexColumn); - } - - /*************************************************************************** - * * Constructor * * - **************************************************************************/ - - /** - * This constructor will generate sample Grid with 100 rows and 15 columns. - * All cells are typed as String (see {@link SpreadsheetCellType#STRING}). - */ - public SpreadsheetView(){ - this(getSampleGrid()); - for(SpreadsheetColumn column: getColumns()){ - column.setPrefWidth(100); - } - } - - /** - * Creates a SpreadsheetView control with the {@link Grid} specified. - * - * @param grid The Grid that contains the items to be rendered - */ - public SpreadsheetView(final Grid grid) { - super(); - //We want to recompute the rectangleHeight when a fixedRow is resized. - addEventHandler(RowHeightEvent.ROW_HEIGHT_CHANGE, (RowHeightEvent event) -> { - if(getFixedRows().contains(event.getRow()) && getCellsViewSkin() != null){ - getCellsViewSkin().computeFixedRowHeight(); - } - }); - getStyleClass().add("SpreadsheetView"); //$NON-NLS-1$ - // anonymous skin - setSkin(new Skin<SpreadsheetView>() { - @Override - public Node getNode() { - return SpreadsheetView.this.getCellsView(); - } - - @Override - public SpreadsheetView getSkinnable() { - return SpreadsheetView.this; - } - - @Override - public void dispose() { - // no-op - } - }); - - this.cellsView = new SpreadsheetGridView(handle); - getChildren().add(cellsView); - - /** - * Add a listener to the selection model in order to edit the spanned - * cells when clicked - */ - TableViewSpanSelectionModel tableViewSpanSelectionModel = new TableViewSpanSelectionModel(this,cellsView); - cellsView.setSelectionModel(tableViewSpanSelectionModel); - tableViewSpanSelectionModel.setCellSelectionEnabled(true); - tableViewSpanSelectionModel.setSelectionMode(SelectionMode.MULTIPLE); - selectionModel = new SpreadsheetViewSelectionModel(this, tableViewSpanSelectionModel); - - /** - * Set the focus model to track keyboard change and redirect focus on - * spanned cells - */ - // We add a listener on the focus model in order to catch when we are on - // a hidden cell - cellsView.getFocusModel().focusedCellProperty() - .addListener((ChangeListener<TablePosition>) (ChangeListener<?>) new FocusModelListener(this,cellsView)); - - /** - * Keyboard action, maybe use an accelerator - */ - cellsView.setOnKeyPressed(keyPressedHandler); - - /** - * ContextMenu handling. - */ - this.contextMenuProperty().addListener(new WeakChangeListener<>(contextMenuChangeListener)); - // The contextMenu creation must be on the JFX thread - CellView.getValue(() -> { - setContextMenu(getSpreadsheetViewContextMenu()); - }); - - setGrid(grid); - setEditable(true); - - // Listeners & handlers - fixedRows.addListener(fixedRowsListener); - fixedColumns.addListener(fixedColumnsListener); - } - /*************************************************************************** - * * Public Methods * * - **************************************************************************/ - - /** - * Set a new Grid for the SpreadsheetView. This will be called by default by - * {@link #SpreadsheetView(Grid)}. So this is useful when you want to - * refresh your SpreadsheetView with a new model. This will keep the state - * of your SpreadsheetView (position of the bar, number of fixedRows etc). - * - * @param grid the new Grid - */ - public final void setGrid(Grid grid) { - if(grid == null){ - return; - } - // Reactivate that after -// verifyGrid(grid); - gridProperty.set(grid); - initRowFix(grid); - - /** - * We need to verify that the previous fixedRows are still compatible - * with our new model - */ - - List<Integer> newFixedRows = new ArrayList<>(); - for (Integer rowFixed : getFixedRows()) { - if (isRowFixable(rowFixed)) { - newFixedRows.add(rowFixed); - } - } - getFixedRows().setAll(newFixedRows); - - /** - * We need to store the index of the fixedColumns and clear then because - * we will keep reference to SpreadsheetColumn that no longer exist. - */ - List<Integer> columnsFixed = new ArrayList<>(); - for (SpreadsheetColumn column : getFixedColumns()) { - columnsFixed.add(getColumns().indexOf(column)); - } - getFixedColumns().clear(); - - /** - * We try to save the width of the column as we save the height of our rows so that we preserve the state. - */ - List<Double> widthColumns = new ArrayList<>(); - for (SpreadsheetColumn column : columns) { - widthColumns.add(column.getWidth()); - } - //We need to update the focused cell afterwards - Pair<Integer, Integer> focusedPair = null; - TablePosition focusedCell = cellsView.getFocusModel().getFocusedCell(); - if (focusedCell != null && focusedCell.getRow() != -1 && focusedCell.getColumn() != -1) { - focusedPair = new Pair(focusedCell.getRow(), focusedCell.getColumn()); - } - - final Pair<Integer, Integer> finalPair = focusedPair; - - if (grid.getRows() != null) { - final ObservableList<ObservableList<SpreadsheetCell>> observableRows = FXCollections - .observableArrayList(grid.getRows()); - cellsView.getItems().clear(); - cellsView.setItems(observableRows); - - final int columnCount = grid.getColumnCount(); - columns.clear(); - for (int columnIndex = 0; columnIndex < columnCount; ++columnIndex) { - final SpreadsheetColumn spreadsheetColumn = new SpreadsheetColumn(getTableColumn(grid, columnIndex), this, columnIndex, grid); - if(widthColumns.size() > columnIndex){ - spreadsheetColumn.setPrefWidth(widthColumns.get(columnIndex)); - } - columns.add(spreadsheetColumn); - // We verify if this column was fixed before and try to re-fix - // it. - if (columnsFixed.contains((Integer) columnIndex) && spreadsheetColumn.isColumnFixable()) { - spreadsheetColumn.setFixed(true); - } - } - } - - List<Pair<Integer, Integer>> selectedCells = new ArrayList<>(); - for (TablePosition position : getSelectionModel().getSelectedCells()) { - selectedCells.add(new Pair<>(position.getRow(), position.getColumn())); - } - - - /** - * Since the TableView is added to the sceneGraph, it's not possible to - * modify the columns in another thread. We normally should call - * Platform.runLater() and exit. But in this particular case, we need to - * add the tableColumn right now. So that when we exit this "setGrid" - * method, we are sure we can manipulate all the elements. - * - * We also try to be smart here when we already have some columns in - * order to re-use them and minimize the time used to add/remove - * columns. - */ - Runnable runnable = () -> { - if (cellsView.getColumns().size() > grid.getColumnCount()) { - cellsView.getColumns().remove(grid.getColumnCount(), cellsView.getColumns().size()); - } else if (cellsView.getColumns().size() < grid.getColumnCount()) { - for (int i = cellsView.getColumns().size(); i < grid.getColumnCount(); ++i) { - cellsView.getColumns().add(columns.get(i).column); - } - } - ((TableViewSpanSelectionModel) cellsView.getSelectionModel()).verifySelectedCells(selectedCells); - //Just like the selected cell we update the focused cell. - if(finalPair != null && finalPair.getKey() < getGrid().getRowCount() && finalPair.getValue() < getGrid().getColumnCount()){ - cellsView.getFocusModel().focus(finalPair.getKey(), cellsView.getColumns().get(finalPair.getValue())); - } - }; - - if (Platform.isFxApplicationThread()) { - runnable.run(); - } else { - try { - FutureTask future = new FutureTask(runnable, null); - Platform.runLater(future); - future.get(); - } catch (InterruptedException | ExecutionException ex) { - Logger.getLogger(SpreadsheetView.class.getName()).log(Level.SEVERE, null, ex); - } - } - } - - /** - * Return a {@link TablePosition} of cell being currently edited. - * - * @return a {@link TablePosition} of cell being currently edited. - */ - public TablePosition<ObservableList<SpreadsheetCell>, ?> getEditingCell() { - return cellsView.getEditingCell(); - } - - /** - * Represents the current cell being edited, or null if there is no cell - * being edited. - * - * @return the current cell being edited, or null if there is no cell being - * edited. - */ - public ReadOnlyObjectProperty<TablePosition<ObservableList<SpreadsheetCell>, ?>> editingCellProperty() { - return cellsView.editingCellProperty(); - } - - /** - * Return an ObservableList of the {@link SpreadsheetColumn} used. This list - * is filled automatically by the SpreadsheetView. Adding and removing - * columns should be done in the model {@link Grid}. - * - * @return An ObservableList of the {@link SpreadsheetColumn} - */ - public final ObservableList<SpreadsheetColumn> getColumns() { - return columns; - } - - /** - * Return the model Grid used by the SpreadsheetView - * - * @return the model Grid used by the SpreadsheetView - */ - public final Grid getGrid() { - return gridProperty.get(); - } - - /** - * Return a {@link ReadOnlyObjectProperty} containing the current Grid - * used in the SpreadsheetView. - * @return a {@link ReadOnlyObjectProperty}. - */ - public final ReadOnlyObjectProperty<Grid> gridProperty() { - return gridProperty; - } - - /** - * You can fix or unfix a row by modifying this list. Call - * {@link #isRowFixable(int)} before trying to fix a row. See - * {@link SpreadsheetView} description for information. - * - * @return an ObservableList of integer representing the fixedRows. - */ - public ObservableList<Integer> getFixedRows() { - return fixedRows; - } - - /** - * Indicate whether a row can be fixed or not. Call that method before - * adding an item with {@link #getFixedRows()} . - * - * A row cannot be fixed alone if any cell inside the row has a row span - * superior to one. - * - * @param row - * @return true if the row can be fixed. - */ - public boolean isRowFixable(int row) { - return row >= 0 && row < rowFix.size() && isFixingRowsAllowed() ? rowFix.get(row) : false; - } - - /** - * Indicates whether a List of rows can be fixed or not. - * - * A set of rows cannot be fixed if any cell inside these rows has a row - * span superior to the number of fixed rows. - * - * @param list - * @return true if the List of row can be fixed together. - */ - public boolean areRowsFixable(List<? extends Integer> list) { - if(list == null || list.isEmpty() || !isFixingRowsAllowed()){ - return false; - } - final Grid grid = getGrid(); - final int rowCount = grid.getRowCount(); - final ObservableList<ObservableList<SpreadsheetCell>> rows = grid.getRows(); - for (Integer row : list) { - if (row == null || row < 0 || row >= rowCount) { - return false; - } - //If this row is not fixable, we need to identify the maximum span - if (!isRowFixable(row)) { - int maxSpan = 1; - List<SpreadsheetCell> gridRow = rows.get(row); - for (SpreadsheetCell cell : gridRow) { - //If the original row is not within this range, there is not need to look deeper. - if (!list.contains(cell.getRow())) { - return false; - } - //We only want to consider the original cell. - if (cell.getRowSpan() > maxSpan && cell.getRow() == row) { - maxSpan = cell.getRowSpan(); - } - } - //Then we need to verify that all rows within that span are fixed. - int count = row + maxSpan - 1; - for (int index = row + 1; index <= count; ++index) { - if (!list.contains(index)) { - return false; - } - } - } - } - return true; - } - - /** - * Return whether change to Fixed rows are allowed. - * - * @return whether change to Fixed rows are allowed. - */ - public boolean isFixingRowsAllowed() { - return fixingRowsAllowedProperty.get(); - } - - /** - * If set to true, user will be allowed to fix and unfix the rows. - * - * @param b - */ - public void setFixingRowsAllowed(boolean b) { - fixingRowsAllowedProperty.set(b); - } - - /** - * Return the Boolean property associated with the allowance of fixing or - * unfixing some rows. - * - * @return the Boolean property associated with the allowance of fixing or - * unfixing some rows. - */ - public ReadOnlyBooleanProperty fixingRowsAllowedProperty() { - return fixingRowsAllowedProperty; - } - - /** - * You can fix or unfix a column by modifying this list. Call - * {@link SpreadsheetColumn#isColumnFixable()} on the column before adding - * an item. - * - * @return an ObservableList of the fixed columns. - */ - public ObservableList<SpreadsheetColumn> getFixedColumns() { - return fixedColumns; - } - - /** - * Indicate whether this column can be fixed or not. If you have a - * {@link SpreadsheetColumn}, call - * {@link SpreadsheetColumn#isColumnFixable()} on it directly. Call that - * method before adding an item with {@link #getFixedColumns()} . - * - * @param columnIndex - * @return true if the column if fixable - */ - public boolean isColumnFixable(int columnIndex) { - return columnIndex >= 0 && columnIndex < getColumns().size() && isFixingColumnsAllowed() - ? getColumns().get(columnIndex).isColumnFixable() : false; - } - - /** - * Indicates whether a List of {@link SpreadsheetColumn} can be fixed or - * not. - * - * A set of columns cannot be fixed if any cell inside these columns has a - * column span superior to the number of fixed columns. - * - * @param list - * @return true if the List of columns can be fixed together. - */ - public boolean areSpreadsheetColumnsFixable(List<? extends SpreadsheetColumn> list) { - List<Integer> newList = new ArrayList<>(); - for (SpreadsheetColumn column : list) { - if (column != null) { - newList.add(columns.indexOf(column)); - } - } - return areColumnsFixable(newList); - } - - /** - * This method is the same as {@link #areSpreadsheetColumnsFixable(java.util.List) - * } but is using a List of {@link SpreadsheetColumn} indexes. - * - * A set of columns cannot be fixed if any cell inside these columns has a - * column span superior to the number of fixed columns. - * - * @param list - * @return true if the List of columns can be fixed together. - */ - public boolean areColumnsFixable(List<? extends Integer> list) { - if (list == null || list.isEmpty() || !isFixingRowsAllowed()) { - return false; - } - final Grid grid = getGrid(); - final int columnCount = grid.getColumnCount(); - final ObservableList<ObservableList<SpreadsheetCell>> rows = grid.getRows(); - for (Integer columnIndex : list) { - if (columnIndex == null || columnIndex < 0 || columnIndex >= columnCount) { - return false; - } - //If this column is not fixable, we need to identify the maximum span - if (!isColumnFixable(columnIndex)) { - int maxSpan = 1; - SpreadsheetCell cell; - for (List<SpreadsheetCell> row : rows) { - cell = row.get(columnIndex); - //If the original column is not within this range, there is not need to look deeper. - if (!list.contains(cell.getColumn())) { - return false; - } - //We only want to consider the original cell. - if (cell.getColumnSpan() > maxSpan && cell.getColumn() == columnIndex) { - maxSpan = cell.getColumnSpan(); - } - } - //Then we need to verify that all columns within that span are fixed. - int count = columnIndex + maxSpan - 1; - for (int index = columnIndex + 1; index <= count; ++index) { - if (!list.contains(index)) { - return false; - } - } - } - } - return true; - } - - /** - * Return whether change to Fixed columns are allowed. - * - * @return whether change to Fixed columns are allowed. - */ - public boolean isFixingColumnsAllowed() { - return fixingColumnsAllowedProperty.get(); - } - - /** - * If set to true, user will be allowed to fix and unfix the columns. - * - * @param b - */ - public void setFixingColumnsAllowed(boolean b) { - fixingColumnsAllowedProperty.set(b); - } - - /** - * Return the Boolean property associated with the allowance of fixing or - * unfixing some columns. - * - * @return the Boolean property associated with the allowance of fixing or - * unfixing some columns. - */ - public ReadOnlyBooleanProperty fixingColumnsAllowedProperty() { - return fixingColumnsAllowedProperty; - } - - /** - * Activate and deactivate the Column Header - * - * @param b - */ - public final void setShowColumnHeader(final boolean b) { - showColumnHeader.setValue(b); - } - - /** - * Return if the Column Header is showing. - * - * @return a boolean telling whether the column Header is shown - */ - public final boolean isShowColumnHeader() { - return showColumnHeader.get(); - } - - /** - * BooleanProperty associated with the column Header. - * - * @return the BooleanProperty associated with the column Header. - */ - public final BooleanProperty showColumnHeaderProperty() { - return showColumnHeader; - } - - /** - * Activate and deactivate the Row Header. - * - * @param b - */ - public final void setShowRowHeader(final boolean b) { - showRowHeader.setValue(b); - } - - /** - * Return if the row Header is showing. - * - * @return a boolean telling if the row Header is being shown - */ - public final boolean isShowRowHeader() { - return showRowHeader.get(); - } - - /** - * BooleanProperty associated with the row Header. - * - * @return the BooleanProperty associated with the row Header. - */ - public final BooleanProperty showRowHeaderProperty() { - return showRowHeader; - } - - /** - * This DoubleProperty represents the with of the rowHeader. This is just - * representing the width of the Labels, not the pickers. - * - * @return A DoubleProperty. - */ - public final DoubleProperty rowHeaderWidthProperty(){ - return rowHeaderWidth; - } - - /** - * Specify a new width for the row header. - * - * @param value - */ - public final void setRowHeaderWidth(double value){ - rowHeaderWidth.setValue(value); - } - - /** - * - * @return the current width of the row header. - */ - public final double getRowHeaderWidth(){ - return rowHeaderWidth.get(); - } - - /** - * @return An ObservableMap with the row index as key and the Picker as a - * value. - */ - public ObservableMap<Integer, Picker> getRowPickers() { - return rowPickers; - } - - /** - * @return An ObservableMap with the column index as key and the Picker as a - * value. - */ - public ObservableMap<Integer, Picker> getColumnPickers() { - return columnPickers; - } - - /** - * This method will compute the best height for each line. That is to say - * a height where each content of each cell could be fully visible.\n - * Use this method wisely because it can degrade performance on great grid. - */ - public void resizeRowsToFitContent() { - if (getCellsViewSkin() != null) { - getCellsViewSkin().resizeRowsToFitContent(); - } - } - - /** - * This method will first apply {@link #resizeRowsToFitContent() } and then - * take the highest height and apply it to every row.\n - * Just as {@link #resizeRowsToFitContent() }, this method can be degrading - * your performance on great grid. - */ - public void resizeRowsToMaximum(){ - if (getCellsViewSkin() != null) { - getCellsViewSkin().resizeRowsToMaximum(); - } - } - - /** - * This method will wipe all changes made to the row's height and set all row's - * height back to their default height defined in the model Grid. - */ - public void resizeRowsToDefault() { - if (getCellsViewSkin() != null) { - getCellsViewSkin().resizeRowsToDefault(); - } - } - - /** - * @param row - * @return the height of a particular row of the SpreadsheetView. - */ - public double getRowHeight(int row) { - //Sometime, the skin is not initialised yet.. - if (getCellsViewSkin() == null) { - return getGrid().getRowHeight(row); - } else { - return getCellsViewSkin().getRowHeight(row); - } - } - - /** - * Return the selectionModel used by the SpreadsheetView. - * - * @return {@link SpreadsheetViewSelectionModel} - */ - public SpreadsheetViewSelectionModel getSelectionModel() { - return selectionModel; - } - - /** - * Scrolls the SpreadsheetView so that the given row is visible. - * @param row - */ - public void scrollToRow(int row){ - cellsView.scrollTo(row); - } - - /** - * Same method as {@link ScrollBar#setValue(double) } on the verticalBar. - * - * @param value - */ - public void setVBarValue(double value) { - if (getCellsViewSkin() == null) { - Platform.runLater(() -> { - setVBarValue(value); - }); - return; - } - getCellsViewSkin().getVBar().setValue(value); - } - - /** - * Same method as {@link ScrollBar#setValue(double) } on the verticalBar. - * - * @param value - */ - public void setHBarValue(double value) { - setHBarValue(value,0); - } - - private void setHBarValue(double value, int attempt) { - if(attempt > 10){ - return; - } - if (getCellsViewSkin() == null) { - final int newAttempt = ++attempt; - Platform.runLater(() -> { - setHBarValue(value, newAttempt); - }); - return; - } - getCellsViewSkin().setHbarValue(value); - } - - /** - * Return the value of the vertical scrollbar. See {@link ScrollBar#getValue() - * } - * - * @return - */ - public double getVBarValue() { - if (getCellsViewSkin() != null && getCellsViewSkin().getVBar() != null) { - return getCellsViewSkin().getVBar().getValue(); - } - return 0.0; - } - - /** - * Return the value of the horizontal scrollbar. See {@link ScrollBar#getValue() - * } - * - * @return - */ - public double getHBarValue() { - if (getCellsViewSkin() != null && getCellsViewSkin().getHBar() != null) { - return getCellsViewSkin().getHBar().getValue(); - } - return 0.0; - } - - /** - * Scrolls the SpreadsheetView so that the given {@link SpreadsheetColumn} is visible. - * @param column - */ - public void scrollToColumn(SpreadsheetColumn column){ - cellsView.scrollToColumn(column.column); - } - - /** - * - * Scrolls the SpreadsheetView so that the given column index is visible. - * - * @param columnIndex - * - */ - public void scrollToColumnIndex(int columnIndex) { - cellsView.scrollToColumnIndex(columnIndex); - } - - /** - * Return the editor associated with the CellType. (defined in - * {@link SpreadsheetCellType#createEditor(SpreadsheetView)}. FIXME Maybe - * keep the editor references inside the SpreadsheetCellType - * - * @param cellType - * @return the editor associated with the CellType. - */ - public final Optional<SpreadsheetCellEditor> getEditor(SpreadsheetCellType<?> cellType) { - if(cellType == null){ - return Optional.empty(); - } - SpreadsheetCellEditor cellEditor = editors.get(cellType); - if (cellEditor == null) { - cellEditor = cellType.createEditor(this); - if(cellEditor == null){ - return Optional.empty(); - } - editors.put(cellType, cellEditor); - } - return Optional.of(cellEditor); - } - - /** - * Sets the value of the property editable. - * - * @param b - */ - public final void setEditable(final boolean b) { - cellsView.setEditable(b); - } - - /** - * Gets the value of the property editable. - * - * @return a boolean telling if the SpreadsheetView is editable. - */ - public final boolean isEditable() { - return cellsView.isEditable(); - } - - /** - * Specifies whether this SpreadsheetView is editable - only if the - * SpreadsheetView, and the {@link SpreadsheetCell} within it are both - * editable will a {@link SpreadsheetCell} be able to go into its editing - * state. - * - * @return the BooleanProperty associated with the editableProperty. - */ - public final BooleanProperty editableProperty() { - return cellsView.editableProperty(); - } - - /** - * This Node is shown to the user when the SpreadsheetView has no content to show. - */ - public final ObjectProperty<Node> placeholderProperty() { - return cellsView.placeholderProperty(); - } - - /** - * Sets the value of the placeholder property - * - * @param placeholder the node to show when the SpreadsheetView has no content to show. - */ - public final void setPlaceholder(final Node placeholder) { - cellsView.setPlaceholder(placeholder); - } - - /** - * Gets the value of the placeholder property. - * - * @return the Node used as a placeholder that is shown when the SpreadsheetView has no content to show. - */ - public final Node getPlaceholder() { - return cellsView.getPlaceholder(); - } - - - /*************************************************************************** - * COPY / PASTE METHODS - **************************************************************************/ - - /** - * Put the current selection into the ClipBoard. This can be overridden by - * developers for custom behavior. - */ - public void copyClipboard() { - checkFormat(); - - final ArrayList<GridChange> list = new ArrayList<>(); - final ObservableList<TablePosition> posList = getSelectionModel().getSelectedCells(); - - for (final TablePosition<?, ?> p : posList) { - SpreadsheetCell cell = getGrid().getRows().get(p.getRow()).get(p.getColumn()); - // Using SpreadsheetCell change to stock the information - // FIXME a dedicated class should be used - /** - * We need to add every cell contained in a span otherwise the - * rectangles computed when pasting will be wrong. - */ - for (int row = 0; row < cell.getRowSpan(); ++row) { - for (int col = 0; col < cell.getColumnSpan(); ++col) { - try { - new ObjectOutputStream(new ByteArrayOutputStream()).writeObject(cell.getItem()); - list.add(new GridChange(cell.getRow() + row, cell.getColumn() + col, null, cell.getItem() == null ? null : cell.getItem())); - } catch (IOException exception) { - list.add(new GridChange(cell.getRow() + row, cell.getColumn() + col, null, cell.getItem() == null ? null : cell.getItem().toString())); - } - } - } - } - final ClipboardContent content = new ClipboardContent(); - content.put(fmt, list); - Clipboard.getSystemClipboard().setContent(content); - } - - /** - * Paste one value from the clipboard over the whole selection. - * @param change - */ - private void pasteOneValue(GridChange change) { - for (TablePosition position : getSelectionModel().getSelectedCells()) { - tryPasteCell(position.getRow(), position.getColumn(), change.getNewValue()); - } - } - - /** - * Try to paste the given value into the given position. - * @param row - * @param column - * @param value - */ - private void tryPasteCell(int row, int column, Object value) { - final SpanType type = getSpanType(row, column); - if (type == SpanType.NORMAL_CELL || type == SpanType.ROW_VISIBLE) { - SpreadsheetCell cell = getGrid().getRows().get(row).get(column); - boolean succeed = cell.getCellType().match(value); - if (succeed) { - getGrid().setCellValue(cell.getRow(), cell.getColumn(), - cell.getCellType().convertValue(value)); - } - } - } - - /** - * Try to paste the values given into the selection. If both selection are - * rectangles and the number of rows of the source is equal of the numbers - * of rows of the target AND number of columns of the target is a multiple - * of the number of columns of the source, then we can paste. - * - * Same goes if we invert the rows and columns. - * @param list - */ - private void pasteMixedValues(ArrayList<GridChange> list) { - SelectionRange sourceSelectionRange = new SelectionRange(); - sourceSelectionRange.fillGridRange(list); - - //It means we have a rectangle. - if (sourceSelectionRange.getRange() != null) { - SelectionRange targetSelectionRange = new SelectionRange(); - targetSelectionRange.fill(cellsView.getSelectionModel().getSelectedCells()); - if (targetSelectionRange.getRange() != null) { - //If both selection are rectangle - GridRange sourceRange = sourceSelectionRange.getRange(); - GridRange targetRange = targetSelectionRange.getRange(); - int sourceRowGap = sourceRange.getBottom() - sourceRange.getTop() + 1; - int targetRowGap = targetRange.getBottom() - targetRange.getTop() + 1; - - int sourceColumnGap = sourceRange.getRight() - sourceRange.getLeft() + 1; - int targetColumnGap = targetRange.getRight() - targetRange.getLeft() + 1; - - final int offsetRow = targetRange.getTop() - sourceRange.getTop(); - final int offsetCol = targetRange.getLeft() - sourceRange.getLeft(); - - //If the numbers of rows are the same and the targetColumnGap is a multiple of sourceColumnGap - if ((sourceRowGap == targetRowGap || targetRowGap == 1) && (targetColumnGap % sourceColumnGap) == 0) { - for (final GridChange change : list) { - int row = change.getRow() + offsetRow; - int column = change.getColumn() + offsetCol; - do { - if (row < getGrid().getRowCount() && column < getGrid().getColumnCount() - && row >= 0 && column >= 0) { - tryPasteCell(row, column, change.getNewValue()); - } - } while ((column = column + sourceColumnGap) <= targetRange.getRight()); - } - //If the numbers of columns are the same and the targetRowGap is a multiple of sourceRowGap - } else if ((sourceColumnGap == targetColumnGap || targetColumnGap == 1) && (targetRowGap % sourceRowGap) == 0) { - for (final GridChange change : list) { - - int row = change.getRow() + offsetRow; - int column = change.getColumn() + offsetCol; - do { - if (row < getGrid().getRowCount() && column < getGrid().getColumnCount() - && row >= 0 && column >= 0) { - tryPasteCell(row, column, change.getNewValue()); - } - } while ((row = row + sourceRowGap) <= targetRange.getBottom()); - } - } - } - } - } - - /** - * If we have several source values to paste into one cell, we do it. - * - * @param list - */ - private void pasteSeveralValues(ArrayList<GridChange> list) { - // TODO algorithm very bad - int minRow = getGrid().getRowCount(); - int minCol = getGrid().getColumnCount(); - int maxRow = 0; - int maxCol = 0; - for (final GridChange p : list) { - final int tempcol = p.getColumn(); - final int temprow = p.getRow(); - if (tempcol < minCol) { - minCol = tempcol; - } - if (tempcol > maxCol) { - maxCol = tempcol; - } - if (temprow < minRow) { - minRow = temprow; - } - if (temprow > maxRow) { - maxRow = temprow; - } - } - - final TablePosition<?, ?> p = cellsView.getFocusModel().getFocusedCell(); - - final int offsetRow = p.getRow() - minRow; - final int offsetCol = p.getColumn() - minCol; - final int rowCount = getGrid().getRowCount(); - final int columnCount = getGrid().getColumnCount(); - int row; - int column; - - for (final GridChange change : list) { - row = change.getRow() + offsetRow; - column = change.getColumn() + offsetCol; - if (row < rowCount && column < columnCount - && row >= 0 && column >= 0) { - tryPasteCell(row, column, change.getNewValue()); - } - } - } - - /** - * Try to paste the clipBoard to the specified position. Try to paste the - * current selection into the Grid. If the two contents are not matchable, - * then it's not pasted. This can be overridden by developers for custom - * behavior. - */ - public void pasteClipboard() { - // FIXME Maybe move editableProperty to the model.. - List<TablePosition> selectedCells = cellsView.getSelectionModel().getSelectedCells(); - if (!isEditable() || selectedCells.isEmpty()) { - return; - } - - checkFormat(); - final Clipboard clipboard = Clipboard.getSystemClipboard(); - - if (clipboard.getContent(fmt) != null) { - - @SuppressWarnings("unchecked") - final ArrayList<GridChange> list = (ArrayList<GridChange>) clipboard.getContent(fmt); - if (list.size() == 1) { - pasteOneValue(list.get(0)); - } else if (selectedCells.size() > 1) { - pasteMixedValues(list); - } else { - pasteSeveralValues(list); - } - // To be improved - } else if (clipboard.hasString()) { - ArrayList<GridChange> list = new ArrayList<>(); - String str = clipboard.getString(); - - String[] lines = str.split("\r"); - for(int i = 0; i < lines.length; ++i) { - String line = lines[i]; - String[] cells = line.split("\t"); - - for(int j = 0; j < cells.length; ++ j) { - String cell = cells[j]; - list.add(new GridChange(i, j, cell, cell)); - } - - } - - if (list.size() == 1) { - pasteOneValue(list.get(0)); - } else if (selectedCells.size() > 1) { - pasteMixedValues(list); - } else { - pasteSeveralValues(list); - } - - /* - final TablePosition<?,?> p = - cellsView.getFocusModel().getFocusedCell(); - // - SpreadsheetCell stringCell = - SpreadsheetCellType.STRING.createCell(0, 0, 1, 1, - clipboard.getString()); - getGrid().getRows().get(p.getRow()).get(p.getColumn()).match(stringCell);*/ - } - } - - /** - * Create a menu on rightClick with two options: Copy/Paste This can be - * overridden by developers for custom behavior. - * - * @return the ContextMenu to use. - */ - public ContextMenu getSpreadsheetViewContextMenu() { - final ContextMenu contextMenu = new ContextMenu(); - - final MenuItem copyItem = new MenuItem(localize(asKey("spreadsheet.view.menu.copy"))); //$NON-NLS-1$ - copyItem.setGraphic(new ImageView(new Image(SpreadsheetView.class - .getResourceAsStream("copySpreadsheetView.png")))); //$NON-NLS-1$ - copyItem.setAccelerator(new KeyCodeCombination(KeyCode.C, KeyCombination.SHORTCUT_DOWN)); - copyItem.setOnAction(new EventHandler<ActionEvent>() { - @Override - public void handle(ActionEvent e) { - copyClipboard(); - } - }); - - final MenuItem pasteItem = new MenuItem(localize(asKey("spreadsheet.view.menu.paste"))); //$NON-NLS-1$ - pasteItem.setGraphic(new ImageView(new Image(SpreadsheetView.class - .getResourceAsStream("pasteSpreadsheetView.png")))); //$NON-NLS-1$ - pasteItem.setAccelerator(new KeyCodeCombination(KeyCode.V, KeyCombination.SHORTCUT_DOWN)); - pasteItem.setOnAction(new EventHandler<ActionEvent>() { - @Override - public void handle(ActionEvent e) { - pasteClipboard(); - } - }); - - final Menu cornerMenu = new Menu(localize(asKey("spreadsheet.view.menu.comment"))); //$NON-NLS-1$ - cornerMenu.setGraphic(new ImageView(new Image(SpreadsheetView.class - .getResourceAsStream("comment.png")))); //$NON-NLS-1$ - - final MenuItem topLeftItem = new MenuItem(localize(asKey("spreadsheet.view.menu.comment.top-left"))); //$NON-NLS-1$ - topLeftItem.setOnAction(new EventHandler<ActionEvent>() { - - @Override - public void handle(ActionEvent t) { - TablePosition<ObservableList<SpreadsheetCell>, ?> pos = cellsView.getFocusModel().getFocusedCell(); - SpreadsheetCell cell = getGrid().getRows().get(pos.getRow()).get(pos.getColumn()); - cell.activateCorner(SpreadsheetCell.CornerPosition.TOP_LEFT); - } - }); - final MenuItem topRightItem = new MenuItem(localize(asKey("spreadsheet.view.menu.comment.top-right"))); //$NON-NLS-1$ - topRightItem.setOnAction(new EventHandler<ActionEvent>() { - - @Override - public void handle(ActionEvent t) { - TablePosition<ObservableList<SpreadsheetCell>, ?> pos = cellsView.getFocusModel().getFocusedCell(); - SpreadsheetCell cell = getGrid().getRows().get(pos.getRow()).get(pos.getColumn()); - cell.activateCorner(SpreadsheetCell.CornerPosition.TOP_RIGHT); - } - }); - final MenuItem bottomRightItem = new MenuItem(localize(asKey("spreadsheet.view.menu.comment.bottom-right"))); //$NON-NLS-1$ - bottomRightItem.setOnAction(new EventHandler<ActionEvent>() { - - @Override - public void handle(ActionEvent t) { - TablePosition<ObservableList<SpreadsheetCell>, ?> pos = cellsView.getFocusModel().getFocusedCell(); - SpreadsheetCell cell = getGrid().getRows().get(pos.getRow()).get(pos.getColumn()); - cell.activateCorner(SpreadsheetCell.CornerPosition.BOTTOM_RIGHT); - } - }); - final MenuItem bottomLeftItem = new MenuItem(localize(asKey("spreadsheet.view.menu.comment.bottom-left"))); //$NON-NLS-1$ - bottomLeftItem.setOnAction(new EventHandler<ActionEvent>() { - - @Override - public void handle(ActionEvent t) { - TablePosition<ObservableList<SpreadsheetCell>, ?> pos = cellsView.getFocusModel().getFocusedCell(); - SpreadsheetCell cell = getGrid().getRows().get(pos.getRow()).get(pos.getColumn()); - cell.activateCorner(SpreadsheetCell.CornerPosition.BOTTOM_LEFT); - } - }); - - cornerMenu.getItems().addAll(topLeftItem, topRightItem, bottomRightItem, bottomLeftItem); - - contextMenu.getItems().addAll(copyItem, pasteItem, cornerMenu); - return contextMenu; - } - - /** - * This method is called when pressing the "delete" key on the - * SpreadsheetView. This will erase the values of selected cells. This can - * be overridden by developers for custom behavior. - */ - public void deleteSelectedCells() { - for (TablePosition<ObservableList<SpreadsheetCell>, ?> position : getSelectionModel().getSelectedCells()) { - getGrid().setCellValue(position.getRow(), position.getColumn(), null); - } - } - - /** - * Return the {@link SpanType} of a cell, this is a shorcut for - * {@link Grid#getSpanType(org.controlsfx.control.spreadsheet.SpreadsheetView, int, int) }. - * - * @param row - * @param column - * @return The {@link SpanType} of a cell - */ - public SpanType getSpanType(final int row, final int column) { - if (getGrid() == null) { - return SpanType.NORMAL_CELL; - } - return getGrid().getSpanType(this, row, column); - } - - /*************************************************************************** - * * Private/Protected Implementation * * - **************************************************************************/ - - /** - * This is called when setting a Grid. The main idea is to re-use - * TableColumn if possible. Because we can have a great amount of time spent - * in com.sun.javafx.css.StyleManager.forget when removing lots of columns - * and adding new ones. So if we already have some, we can just re-use them - * so we avoid doign all the fuss with the TableColumns. - * - * @param grid - * @param columnIndex - * @return - */ - private TableColumn<ObservableList<SpreadsheetCell>, SpreadsheetCell> getTableColumn(Grid grid, int columnIndex) { - - TableColumn<ObservableList<SpreadsheetCell>, SpreadsheetCell> column; - - String columnHeader = grid.getColumnHeaders().size() > columnIndex ? grid - .getColumnHeaders().get(columnIndex) : Utils.getExcelLetterFromNumber(columnIndex); - - if (columnIndex < cellsView.getColumns().size()) { - column = (TableColumn<ObservableList<SpreadsheetCell>, SpreadsheetCell>) cellsView.getColumns().get(columnIndex); - column.setText(columnHeader); - } else { - column = new TableColumn<>(columnHeader); - - column.setEditable(true); - // We don't want to sort the column - column.setSortable(false); - - column.impl_setReorderable(false); - - // We assign a DataCell for each Cell needed (MODEL). - column.setCellValueFactory((TableColumn.CellDataFeatures<ObservableList<SpreadsheetCell>, SpreadsheetCell> p) -> { - if (columnIndex >= p.getValue().size()) { - return null; - } - return new ReadOnlyObjectWrapper<>(p.getValue().get(columnIndex)); - }); - // We create a SpreadsheetCell for each DataCell in order to - // specify how to represent the DataCell(VIEW) - column.setCellFactory((TableColumn<ObservableList<SpreadsheetCell>, SpreadsheetCell> p) -> new CellView(handle)); - } - return column; - } - - /** - * This static method creates a sample Grid with 100 rows and 15 columns. - * All cells are typed as String. - * - * @return the sample Grid - * @see SpreadsheetCellType#STRING - */ - private static Grid getSampleGrid() { - GridBase gridBase = new GridBase(100, 15); - List<ObservableList<SpreadsheetCell>> rows = FXCollections.observableArrayList(); - - for (int row = 0; row < gridBase.getRowCount(); ++row) { - ObservableList<SpreadsheetCell> currentRow = FXCollections.observableArrayList(); - for (int column = 0; column < gridBase.getColumnCount(); ++column) { - currentRow.add(SpreadsheetCellType.STRING.createCell(row, column, 1, 1, "toto")); - } - rows.add(currentRow); - } - gridBase.setRows(rows); - return gridBase; - } - - private void initRowFix(Grid grid) { - ObservableList<ObservableList<SpreadsheetCell>> rows = grid.getRows(); - rowFix = new BitSet(rows.size()); - rows: - for (int r = 0; r < rows.size(); ++r) { - ObservableList<SpreadsheetCell> row = rows.get(r); - for (SpreadsheetCell cell : row) { - if (cell.getRowSpan() > 1) { - continue rows; - } - } - rowFix.set(r); - } - } - - /** - * Verify that the grid is well-formed. Can be quite time-consuming I guess - * so I would like it not to be compulsory.. - * - * @param grid - */ - private void verifyGrid(Grid grid) { - verifyColumnSpan(grid); - } - - private void verifyColumnSpan(Grid grid) { - for (int i = 0; i < grid.getRows().size(); ++i) { - ObservableList<SpreadsheetCell> row = grid.getRows().get(i); - int count = 0; - for (int j = 0; j < row.size(); ++j) { - if (row.get(j).getColumnSpan() == 1) { - ++count; - } else if (row.get(j).getColumnSpan() > 1) { - ++count; - SpreadsheetCell currentCell = row.get(j); - for (int k = j + 1; k < currentCell.getColumn() + currentCell.getColumnSpan(); ++k) { - if (!row.get(k).equals(currentCell)) { - throw new IllegalStateException("\n At row " + i + " and column " + j //$NON-NLS-1$ //$NON-NLS-2$ - + ": this cell is in the range of a columnSpan but is different. \n" //$NON-NLS-1$ - + "Every cell in a range of a ColumnSpan must be of the same instance."); //$NON-NLS-1$ - } - ++count; - ++j; - } - } else { - throw new IllegalStateException("\n At row " + i + " and column " + j //$NON-NLS-1$ //$NON-NLS-2$ - + ": this cell has a negative columnSpan"); //$NON-NLS-1$ - } - } - if (count != grid.getColumnCount()) { - throw new IllegalStateException("The row" + i //$NON-NLS-1$ - + " has a number of cells different of the columnCount declared in the grid."); //$NON-NLS-1$ - } - } - } - - private void checkFormat() { - if ((fmt = DataFormat.lookupMimeType("SpreadsheetView")) == null) { //$NON-NLS-1$ - fmt = new DataFormat("SpreadsheetView"); //$NON-NLS-1$ - } - } - - /** - * ********************************************************************* * - * private listeners - * ******************************************************************** - */ - - private final ListChangeListener<Integer> fixedRowsListener = new ListChangeListener<Integer>() { - @Override - public void onChanged(ListChangeListener.Change<? extends Integer> c) { - while (c.next()) { - if (c.wasAdded()) { - List<? extends Integer> newRows = c.getAddedSubList(); - if(!areRowsFixable(newRows)){ - throw new IllegalArgumentException(computeReason(newRows)); - } - FXCollections.sort(fixedRows); - } - - if(c.wasRemoved()){ - //Handle this case. - } - } - } - }; - - private String computeReason(List<? extends Integer> list) { - String reason = "\n A row cannot be fixed. \n"; //$NON-NLS-1$ - - for (Integer row : list) { - //If this row is not fixable, we need to identify the maximum span - if (!isRowFixable(row)) { - - int maxSpan = 1; - List<SpreadsheetCell> gridRow = getGrid().getRows().get(row); - for (SpreadsheetCell cell : gridRow) { - if(!list.contains(cell.getRow())){ - reason += "The row " + row + " is inside a row span and the starting row " + cell.getRow() + " is not fixed.\n"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - } - //We only want to consider the original cell. - if (cell.getRowSpan() > maxSpan && cell.getRow() == row) { - maxSpan = cell.getRowSpan(); - } - } - //Then we need to verify that all rows within that span are fixed. - int count = row + maxSpan - 1; - for (int index = row + 1; index < count; ++index) { - if (!list.contains(index)) { - reason += "One cell on the row " + row + " has a row span of " + maxSpan + ". " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - + "But the row " + index + " contained within that span is not fixed.\n"; //$NON-NLS-1$ //$NON-NLS-2$ - } - } - } - } - return reason; - } - - private final ListChangeListener<SpreadsheetColumn> fixedColumnsListener = new ListChangeListener<SpreadsheetColumn>() { - @Override - public void onChanged(ListChangeListener.Change<? extends SpreadsheetColumn> c) { - while (c.next()) { - if (c.wasAdded()) { - List<? extends SpreadsheetColumn> newColumns = c.getAddedSubList(); - if (!areSpreadsheetColumnsFixable(newColumns)) { - List<Integer> newList = new ArrayList<>(); - for (SpreadsheetColumn column : newColumns) { - if (column != null) { - newList.add(columns.indexOf(column)); - } - } - throw new IllegalArgumentException(computeReason(newList)); - } - } - } - } - - private String computeReason(List<Integer> list) { - - String reason = "\n This column cannot be fixed."; //$NON-NLS-1$ - final ObservableList<ObservableList<SpreadsheetCell>> rows = getGrid().getRows(); - for (Integer columnIndex : list) { - //If this row is not fixable, we need to identify the maximum span - if (!isColumnFixable(columnIndex)) { - int maxSpan = 1; - SpreadsheetCell cell; - for (List<SpreadsheetCell> row : rows) { - cell = row.get(columnIndex); - //If the original column is not within this range, there is not need to look deeper. - if (!list.contains(cell.getColumn())) { - reason += "The column " + columnIndex + " is inside a column span and the starting column " + cell.getColumn() + " is not fixed.\n"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - } - //We only want to consider the original cell. - if (cell.getColumnSpan() > maxSpan && cell.getColumn() == columnIndex) { - maxSpan = cell.getColumnSpan(); - } - } - //Then we need to verify that all columns within that span are fixed. - int count = columnIndex + maxSpan - 1; - for (int index = columnIndex + 1; index < count; ++index) { - if (!list.contains(index)) { - reason += "One cell on the column " + columnIndex + " has a column span of " + maxSpan + ". " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - + "But the column " + index + " contained within that span is not fixed.\n"; //$NON-NLS-1$ //$NON-NLS-2$ - } - } - } - } - return reason; - } - }; - - private final ChangeListener<ContextMenu> contextMenuChangeListener = new ChangeListener<ContextMenu>() { - - @Override - public void changed(ObservableValue<? extends ContextMenu> arg0, ContextMenu oldContextMenu, final ContextMenu newContextMenu) { - if(oldContextMenu !=null){ - oldContextMenu.setOnShowing(null); - } - if(newContextMenu != null){ - newContextMenu.setOnShowing(new WeakEventHandler<>(hideContextMenuEventHandler)); - } - } - }; - - private final EventHandler<WindowEvent> hideContextMenuEventHandler = new EventHandler<WindowEvent>() { - @Override - public void handle(WindowEvent arg0) { - // We don't want to open a contextMenu when editing - // because editors - // have their own contextMenu - if (getEditingCell() != null) { - // We're being reactive but we want to be pro-active - // so we may need a work-around. - Platform.runLater(()->{ - getContextMenu().hide(); - }); - } - } - }; - - private final EventHandler<KeyEvent> keyPressedHandler = (KeyEvent keyEvent) -> { - TablePosition<ObservableList<SpreadsheetCell>, ?> position = getSelectionModel().getFocusedCell(); - // Go to the next row only if we're not editing - if (getEditingCell() == null && KeyCode.ENTER.equals(keyEvent.getCode())) { - if (position != null) { - if(keyEvent.isShiftDown()){ - getSelectionModel().clearAndSelectPreviousCell(); - }else{ - getSelectionModel().clearAndSelectNextCell(); - } - //We consume the event because we don't want to go in edition - keyEvent.consume(); - } - getCellsViewSkin().scrollHorizontally(); - // Go to next cell - } else if (getEditingCell() == null && KeyCode.TAB.equals(keyEvent.getCode())) { - if (position != null) { - if (keyEvent.isShiftDown()) { - getSelectionModel().clearAndSelectLeftCell(); - } else { - getSelectionModel().clearAndSelectRightCell(); - } - } - //We consume the event because we don't want to loose focus - keyEvent.consume(); - getCellsViewSkin().scrollHorizontally(); - // We want to erase values when delete key is pressed. - } else if (KeyCode.DELETE.equals(keyEvent.getCode())) { - deleteSelectedCells(); - /** - * We want NOT to go in edition if we're pressing SHIFT and if we're - * using the navigation keys. But we still want the user to go in - * edition with SHIFT and some letters for example if he wants a - * capital letter. - * FIXME Add a test to prevent the Shift fail case. - */ - }else if (keyEvent.getCode() != KeyCode.SHIFT && !keyEvent.isShortcutDown() - && !keyEvent.getCode().isNavigationKey() - && keyEvent.getCode() != KeyCode.ESCAPE) { - getCellsView().edit(position.getRow(), position.getTableColumn()); - } - }; - - /** - * This event is thrown on the SpreadsheetView when the user resize a row - * with its mouse. - */ - public static class RowHeightEvent extends Event { - - /** - * This is the event used by {@link RowHeightEvent}. - */ - public static final EventType<RowHeightEvent> ROW_HEIGHT_CHANGE = new EventType<>(Event.ANY, "RowHeightChange"); //$NON-NLS-1$ - - private final int row; - private final double height; - - public RowHeightEvent(int row, double height) { - super(ROW_HEIGHT_CHANGE); - this.row = row; - this.height = height; - } - - /** - * Return the row index that has been resized. - * @return the row index that has been resized. - */ - public int getRow() { - return row; - } - - /** - * Return the new height for this row. - * @return the new height for this row. - */ - public double getHeight() { - return height; - } - } - - /** - * This event is thrown on the SpreadsheetView when the user resize a column - * with its mouse. - */ - public static class ColumnWidthEvent extends Event { - - /** - * This is the event used by {@link ColumnWidthEvent}. - */ - public static final EventType<ColumnWidthEvent> COLUMN_WIDTH_CHANGE = new EventType<>(Event.ANY, "ColumnWidthChange"); //$NON-NLS-1$ - - private final int column; - private final double width; - - public ColumnWidthEvent(int column, double width) { - super(COLUMN_WIDTH_CHANGE); - this.column = column; - this.width = width; - } - - /** - * Return the column index that has been resized. - * @return the column index that has been resized. - */ - public int getColumn() { - return column; - } - - /** - * Return the new width for this column. - * @return the new width for this column. - */ - public double getWidth() { - return width; - } - } - - public void addedSkin(GridViewSkin viewSkin) { - // TODO Auto-generated method stub - - } -} diff --git a/src/org/controlsfx/control/spreadsheet/SpreadsheetViewSelectionModel.java b/src/org/controlsfx/control/spreadsheet/SpreadsheetViewSelectionModel.java deleted file mode 100644 index 9561180..0000000 --- a/src/org/controlsfx/control/spreadsheet/SpreadsheetViewSelectionModel.java +++ /dev/null @@ -1,237 +0,0 @@ -/** - * Copyright (c) 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.spreadsheet; - -import impl.org.controlsfx.spreadsheet.FocusModelListener; -import impl.org.controlsfx.spreadsheet.TableViewSpanSelectionModel; -import java.util.Arrays; -import java.util.List; -import javafx.collections.ObservableList; -import javafx.scene.control.SelectionMode; -import javafx.scene.control.TablePosition; -import javafx.scene.control.TableView; -import javafx.util.Pair; - -/** - * - * This class provides basic support for common interaction on the - * {@link SpreadsheetView}. - * - * Due to the complexity induced by cell's span, it is not possible to give a - * full access to selectionModel like in the {@link TableView}. - */ -public class SpreadsheetViewSelectionModel { - - private final TableViewSpanSelectionModel selectionModel; - private final SpreadsheetView spv; - - SpreadsheetViewSelectionModel(SpreadsheetView spv, TableViewSpanSelectionModel selectionModel) { - this.spv = spv; - this.selectionModel = selectionModel; - } - - /** - * Clears all selection, and then selects the cell at the given row/column intersection. - * @param row - * @param column - */ - public final void clearAndSelect(int row, SpreadsheetColumn column) { - selectionModel.clearAndSelect(row, column.column); - } - - /** - * Selects the cell at the given row/column intersection. - * @param row - * @param column - */ - public final void select(int row, SpreadsheetColumn column) { - selectionModel.select(row,column.column); - } - - /** - * Clears the selection model of all selected indices. - */ - public final void clearSelection() { - selectionModel.clearSelection(); - } - - /** - * A read-only ObservableList representing the currently selected cells in this SpreadsheetView. - * @return A read-only ObservableList. - */ - public final ObservableList<TablePosition> getSelectedCells() { - return selectionModel.getSelectedCells(); - } - - /** - * Select all the possible cells. - */ - public final void selectAll() { - selectionModel.selectAll(); - } - - /** - * Return the position of the cell that has current focus. - * @return the position of the cell that has current focus. - */ - public final TablePosition getFocusedCell(){ - return selectionModel.getTableView().getFocusModel().getFocusedCell(); - } - - /** - * Causes the cell at the given index to receive the focus. - * @param row The row index of the item to give focus to. - * @param column The column of the item to give focus to. Can be null. - */ - public final void focus(int row, SpreadsheetColumn column){ - selectionModel.getTableView().getFocusModel().focus(row, column.column); - } - - /** - * Specifies the selection mode to use in this selection model. The - * selection mode specifies how many items in the underlying data model can - * be selected at any one time. By default, the selection mode is - * {@link SelectionMode#MULTIPLE}. - * - * @param value - */ - public final void setSelectionMode(SelectionMode value) { - selectionModel.setSelectionMode(value); - } - - /** - * Return the selectionMode currently used. - * - * @return the selectionMode currently used. - */ - public SelectionMode getSelectionMode() { - return selectionModel.getSelectionMode(); - } - - - /** - * Use this method to select discontinuous cells. - * - * The {@link Pair} must contain the row index as key and the column index - * as value. This is useful when you want to select a great amount of cell - * because it will be more efficient than calling - * {@link #select(int, org.controlsfx.control.spreadsheet.SpreadsheetColumn) }. - * - * @param selectedCells - */ - public void selectCells(List<Pair<Integer, Integer>> selectedCells) { - selectionModel.verifySelectedCells(selectedCells); - } - - /** - * Use this method to select discontinuous cells. - * - * The {@link Pair} must contain the row index as key and the column index - * as value. This is useful when you want to select a great amount of cell - * because it will be more efficient than calling - * {@link #select(int, org.controlsfx.control.spreadsheet.SpreadsheetColumn) }. - * @param selectedCells - */ - public void selectCells(Pair<Integer, Integer>... selectedCells) { - selectionModel.verifySelectedCells(Arrays.asList(selectedCells)); - } - - /** - * Selects the cells in the range (minRow, minColumn) to (maxRow, maxColumn), inclusive. - * @param minRow - * @param minColumn - * @param maxRow - * @param maxColumn - */ - public void selectRange(int minRow, SpreadsheetColumn minColumn, int maxRow, SpreadsheetColumn maxColumn) { - selectionModel.selectRange(minRow, minColumn.column, maxRow, maxColumn.column); - } - - /** - * Clear the current selection and select the cell on the left of the - * current focused cell. If the cell is the first one on a row, the last - * cell of the preceding row is selected. - */ - public void clearAndSelectLeftCell() { - TablePosition<ObservableList<SpreadsheetCell>, ?> position = getFocusedCell(); - int row = position.getRow(); - int column = position.getColumn(); - column -= 1; - if (column < 0) { - if (row == 0) { - column++; - } else { - column = spv.getGrid().getColumnCount() - 1; - row--; - } - } - clearAndSelect(row, spv.getColumns().get(column)); - } - - /** - * Clear the current selection and select the cell on the right of the - * current focused cell. If the cell is the last one on a row, the first - * cell of the next row is selected. - */ - public void clearAndSelectRightCell() { - TablePosition<ObservableList<SpreadsheetCell>, ?> position = getFocusedCell(); - int row = position.getRow(); - int column = position.getColumn(); - column += 1; - if (column >= spv.getColumns().size()) { - if (row == spv.getGrid().getRowCount() - 1) { - column--; - } else { - column = 0; - row++; - } - } - clearAndSelect(row, spv.getColumns().get(column)); - } - - /** - * Clear the current selection and select the cell on the previous row. - */ - public void clearAndSelectPreviousCell() { - TablePosition<ObservableList<SpreadsheetCell>, ?> position = getFocusedCell(); - int nextRow = FocusModelListener.getPreviousRowNumber(position, selectionModel.getTableView()); - if (nextRow >= 0) { - clearAndSelect(nextRow, spv.getColumns().get(position.getColumn())); - } - } - - /** - * Clear the current selection and select the cell on the next row. - */ - public void clearAndSelectNextCell() { - TablePosition<ObservableList<SpreadsheetCell>, ?> position = getFocusedCell(); - int nextRow = FocusModelListener.getNextRowNumber(position, selectionModel.getTableView()); - if (nextRow < spv.getGrid().getRowCount()) { - clearAndSelect(nextRow, spv.getColumns().get(position.getColumn())); - } - } -} diff --git a/src/org/controlsfx/control/spreadsheet/StringConverterWithFormat.java b/src/org/controlsfx/control/spreadsheet/StringConverterWithFormat.java deleted file mode 100644 index d0b4d41..0000000 --- a/src/org/controlsfx/control/spreadsheet/StringConverterWithFormat.java +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Copyright (c) 2013, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.spreadsheet; - -import javafx.util.StringConverter; - -/** - * This class is used by some of the {@link SpreadsheetCellType} in order to use - * a specific format.<br> - * - * Since the format is specified in the {@link SpreadsheetCell}, we need a - * converter which provide a runtime method {@link #toStringFormat(Object, String)}.<br> - * - * This class provide two constructors: - * <ul> - * <li>A default one where you implement the three abstract methods.</li> - * <li>Another one which takes another StringConverter. This is useful when you just want to implement - * the {@link #toStringFormat(Object, String)} and let the other converter handle the other methods.</li> - * </ul> - * - * @see SpreadsheetCellType - * - * @param <T> - */ -public abstract class StringConverterWithFormat<T> extends StringConverter<T> { - - protected StringConverter<T> myConverter; - - /** - * Default constructor. - */ - public StringConverterWithFormat() { - super(); - } - - /** - * This constructor allow to use another StringConverter. - * @param specificStringConverter - */ - public StringConverterWithFormat(StringConverter<T> specificStringConverter) { - myConverter = specificStringConverter; - } - - /** - * Converts the object provided into its string form with the specified format. - * @param value - * @param format - * @return a string containing the converted value with the specified format. - */ - public String toStringFormat(T value, String format) { - return toString(value); - } -} diff --git a/src/org/controlsfx/control/spreadsheet/comment.png b/src/org/controlsfx/control/spreadsheet/comment.png deleted file mode 100644 index 974c85b3a2c677ffedde2e977ce1224c5491e16e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 673 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>l<H3=9nHC7!;n?DrVu1z1H^6<VERU|`boba4!^IK6f9?(8X! zB1h}X)Aqedo6I}IMcVb^-HwiqFh+UTIGt+;_dDdUWLtZ8|KV=xT^q`!`b<@c%TaM| zhLG}!SxRonH_qDao4Hf${w#^3UV999=Is1_r<$+)fxPp-Zy%Cke>WA$Ip5>Bx?25- z?tweAjN&HQbEbt)?c8MW-*Nr+n>&|pIeo5zMRnCuSz(=@?986u-#&c2sk$K{&2=RY z=jYeG%e8I`yMLY*r@Vw~rPfL<$A`1OzgbdQ^-^9=_vEEUPO)pV`;XMkwFy44a8(6s z|D({4h4WVkPF=e#`2e3>w)?8QG}n!7-JN&myxBO-<p49A!K}Ms3JhW=q#c*I>RyqH z(-w92P4)2b`J9%-baurRrz2entUOJEjx0J&!V3jOx))rMnpwH%5yKo_XTKJPoGnb( zSh&=*Ik@7crUhgf3W>~N>}@<`d5X_r@!uyp5{(=#tyKX{Zc})I&o1E*2o2b{B`Rmu z&CsQCpS~YVa@pWkFiF+=<gyJZlVaT4j1!iuwu+mUYaA%1rCJ&K{pe8_5$>7nf4r_7 zT+*DVD3*WGaQ05qr=Nb`i8%cIjbujZ{1@t-!UhpFFXl^Gt6pYEdzid!mcIY?`QKH0 z*KD|KYwe|!V7Me|#nsD)Co8K@w*LIy<o1!ByuMwT*_8(2*1M&JW*yx7Z=TpPmae<o zN*Oy_1#(NxOLW7$KE3&F|9IB?#oybD%=ay^{G8Ujba(g>{d~>ajC!&s->cfi1^)B? a!;l~UVXwJr%Mu0#1_n=8KbLh*2~7Z%lpO8= diff --git a/src/org/controlsfx/control/spreadsheet/copySpreadsheetView.png b/src/org/controlsfx/control/spreadsheet/copySpreadsheetView.png deleted file mode 100644 index de6c54def339045f2f05589b2a7588582e393074..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 518 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7&w9EzhE&{|I{9qYAqRou z>8??Z6MnU>5Mi~g2y^5S)x7w{_m`5~7sX#3T^(V`{Zm(nzL)FLjq2ja`tUn?_wEUk zBG$e=u;Fyt=h;8cpIKD2^UssdKO-zQ{H^0}KKNks)vS#N6F!LgNoa|6JE;gI^4aHX zkCx~^ZZQA+?Ynv3#n>x<n>&cO8c6kCIA%8c>^oht(=`?{bvy39`<~Bm{<D*b)L%vg zp=FmfTXW2$U+GQfuG)J~;PX4C#sl1}B3!MD88|n^tzYS{CTuX%rzBQKENS`Whkxqo zWuJboY<#?9F@q(?az3lMe82wMWtd1!>b#L-W;x~bQ@=EY_3WKF1`-K7V}deQU*(eO zJ*IprZL@o~hU>kzWhMSrNoKQON-_$qznW!pD#eKD^rkZp`;R;|lj>zCcPv~Uwf2+7 zTtDuI1wX<$k9hE|30v(Hwm0s1pw`r1!VOz4=WW+c3FJJP62#H!l+IYO=3v@p&2uYS zDs1K*++3$T@#LzjS?dLyv{s5ek@+sSCvH7cz{-${Cm$>HKDKgC^>WpJ{k3X}hl&(m zyR)F*+OW(2PV?Hk$jL72N@qHnw2^=L<xG3^)gfAcSqylZKg_XzFfaaes^{vO{`*Hh ai|b{Wvp*{1E@xn1VDNPHb6Mw<&;$U3|K!;K diff --git a/src/org/controlsfx/control/spreadsheet/package-info.java b/src/org/controlsfx/control/spreadsheet/package-info.java deleted file mode 100644 index 15373ae..0000000 --- a/src/org/controlsfx/control/spreadsheet/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -/** - * A package containing model and view related classes used by the - * {@link org.controlsfx.control.spreadsheet.SpreadsheetView} control. - */ -package org.controlsfx.control.spreadsheet; \ No newline at end of file diff --git a/src/org/controlsfx/control/spreadsheet/pasteSpreadsheetView.png b/src/org/controlsfx/control/spreadsheet/pasteSpreadsheetView.png deleted file mode 100644 index 62286418d514b129a875e4e075dcd38ee8d13277..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 639 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!to+&o<zLn>~yPV&tV4iq?^ z{!MxIvaZ~P%Wnl~ibij=t+=$>t5cyuV9$*uSy}wInw#27SF&?TFI{Q6B<zvnk+3Ua zQ<4<e7jnk2d{l}O2o|X75D>W%U~u#9_nQ36+jD#mM7Dh|yMHGCe}0<4zm4WUuOFUt z%k1CN&+W&bCvDvRLH_X6-4o|6XuGb_Xy(BAuZ52<w`RJ`)IT|IIYsZE^k@i(`nPfA z5%={r8s-df=Unr6<g9F4J01u$e0t_L;i^K$Dken@XNR(eP3cdMUjDiIV{12W!}FIb zD!-hOox4fgspGkfhUcW$HTLzzMF)3mmB?h!S$=-jakunRua&c3Sn%E0_EzpwN@9Gs zyt$Rt?)&T}yb(IOQ@sLKh9vP6%wtTGVvyo~QZLr^V`qR$h$vTUUW`}&Y~_hd*dOFY zim@;;ns+eIX55j!`DR?qyx9p2nXxRK4XakoW8y1(zdKYsavEy_zn-Ck#jGz3cUT!} zTE8;aaQ*raS#`+9&TKJrfc}QC)w#?CD;PL9;){32$lH0w8XQjcj4jiS3xB}Q5gK>9 zh9T@oU5$yXssE86t4*3AQ>t#Sy1FX7IgR064tsX?d^Uq(+njl`YF2!H`B+}mHH~Xk zo_Gt>#%sc{JhP*iUcWx7c*dtU=G`mV9eb<aCz^dep|yr7HS1S<e-87Hv)ekW@7C0n z%1cf6d-o&k-%{lpZ<P|ltJAY<$_$m(DfHy)c5k0z&=KmZA{5Kv`=;($-0=thm{;na utSPc=wc<;BH(}be2k%4E+7kEt;(mMHYfo_7!ix+H3=E#GelF{r5}E)<=NI4r diff --git a/src/org/controlsfx/control/spreadsheet/picker.png b/src/org/controlsfx/control/spreadsheet/picker.png deleted file mode 100644 index 69a1701e57f3d10dec30f6658e17e4040fd6a81e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 382 zcmeAS@N?(olHy`uVBq!ia0y~yU;weXIM^5%7<!G)?`2?MU`z6LcVYMsf(!O8pUl9( zz**oCS<Jw|dkuscC*)VoVPIfjFY)wsWxvPD&Mzx};=S7=1_nlMPZ!4!iOabYHu@b( z5OF)7`=3e3+raSEt7mF<49tdnENpjW?|fmDkc|DJc&CCnaYExk@dFkT;*zC{mpDY% z-+JA2t1*9<`TfX!%1<u6;=5Zg^9tjiqK`Z4tEc@dQ{#8r_;vlQ<I1d6&DUiWZg6M? z80hWV_u266y9=>LuEqZk{kJe{v9UwL+DYQGZYr(3Kj*sJyyr}({^hZreei3M8Ka_K zkeu9cUS%fFRW+?*p{mD>qL=xkPkTRgQ+Qzk%aW_Iy8?4+1p`*Znfa^b&-Xs2|GwQ} zg65R2xQuIDObu?!{dX$dn5v|7@N(?u{H>FvpEWq2Tp}YY5}C@SF#AhN*)PNW?_HO# iQ_h*rop|pO|Gaq_Y%&wy>oPDfFnGH9xvX<aXaWF^G@3U6 diff --git a/src/org/controlsfx/control/spreadsheet/pinSpreadsheetView.png b/src/org/controlsfx/control/spreadsheet/pinSpreadsheetView.png deleted file mode 100644 index 6304b62b82f938fbad45fb32ef4495a818be2d1d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 525 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7uXwsRhE&{|dSQRIRH6j? zhxaF!x+N94oGkQU;*+)N@IG*fFZR)toWJs$#Ec~}7G7Cmc1v}O^TH4TadT${g(L?K z6AuM@E%jp_@22oIe!JwoHQmqh_1@a)daBE>zyD&#fByHw%6PW&C7K+HGoA_A{wwhD zefnqZHUEf~pW79yZ9K0ZI`nIaf`P4P)3uzsblZ7Lf3J#?=00H~zsuaX_(^PJq8bxp zNqPA~IXS2IW%lg8pHEge2+Z>@x^u0>faBWpX1%VA`STX7&0JQUckZV{U|m1UlAk|A z@7$>=`uVrOVy;9?{Nmcu*60O)J0{%xD6OM+?%Vlu=Oo(%Wpua?8+_>fX4&U$^QI*3 z#;+q)8X^*N=G4eA^z%AM@472r_p?TSy1ri9wub#bi)wtLtgSaLKly~s?TFBd5G|K8 zPm|)km!4%jZFKjc!0o4-GNlDvCr<hPEor9Dv$qpfc4nNO!&W7gaDypptCZ&3_xU!_ z(bewWRpM>TFD{7w+SX9D*RSj7qcjzvN`LQbufN{=mQfOGp3B(l)~q7bY5s-tw$1t1 zU5mcFpS77q#Z&2HMa}8}jU$I27TC`|JLx}DN~GG)nt!ERqiUymE$z5EM|FbV^6=15 h+YYzI(<LU_H=aB#7__i`2Ll5GgQu&X%Q~loCIFy*?pgo< diff --git a/src/org/controlsfx/control/spreadsheet/spreadsheet.css b/src/org/controlsfx/control/spreadsheet/spreadsheet.css deleted file mode 100644 index 516d395..0000000 --- a/src/org/controlsfx/control/spreadsheet/spreadsheet.css +++ /dev/null @@ -1,150 +0,0 @@ -.cell-spreadsheet .table-row-cell { - -fx-background-color: transparent; -} - -/* NORMAL CELL */ -.spreadsheet-cell:filled:selected, -.spreadsheet-cell:filled:focused:selected, -.spreadsheet-cell:filled:focused:selected:hover { - -fx-background-color: #8cb1ff; - -fx-border-color: #a9a9a9; - -fx-border-width : 0.5px; - -fx-text-fill: -fx-selection-bar-text; - -} -.spreadsheet-cell:hover, -.spreadsheet-cell:filled:focused { - -fx-background-color: #988490; - -fx-text-fill: -fx-text-inner-color; - -fx-background-insets: 0, 0 0 1 0; -} - -.spreadsheet-cell{ - -fx-padding: 0 0 0 0.2em; - -fx-border-color: black; - -fx-border-width : 0.3px; - -fx-background-color: -fx-table-cell-border-color,white; -} - -.tooltip { - -fx-background-radius: 0px; - -fx-background-color: - linear-gradient(#cec340, #a59c31), - linear-gradient(#fefefc, #e6dd71), - linear-gradient(#fef592, #e5d848); - -fx-background-insets: 0,1,2; - -fx-padding: 0.333333em 0.666667em 0.333333em 0.666667em; /* 4 8 4 8 */ - -fx-effect: dropshadow( three-pass-box , rgba(0,0,0,0.6) , 8, 0.0 , 0 , 0 ); - -fx-text-fill:black; -} - -/* FIXED HEADERS */ -VerticalHeader > Label.fixed{ - -fx-background-color: -fx-box-border, lightgray; - -fx-font-style : italic; -} - -HorizontalHeaderColumn > TableColumnHeader.column-header.table-column.fixed{ - -fx-background-color: -fx-box-border, lightgray; - -fx-font-style : italic; -} - -/* HORIZONTAL AND VERTICAL HEADER SELECTION */ -VerticalHeader > Label , -HorizontalHeaderColumn > TableColumnHeader.column-header.table-column{ - -fx-background-color: -fx-box-border, #F3F3F3; - -fx-background-insets: 0, 0 1 1 0, 1 2 2 1; - -fx-font-weight: bold; - -fx-size: 2em; - -fx-text-fill: -fx-selection-bar-text; - -fx-alignment: center; - -fx-font-style : normal; -} - -VerticalHeader > Label.selected{ - -fx-background-color: #8FB1E8; - -fx-text-fill :white; -} - -HorizontalHeaderColumn > TableColumnHeader.column-header.table-column.selected, -HorizontalHeaderColumn > TableColumnHeader.column-header.table-column.selected > Label -{ - -fx-background-color:#8FB1E8; - -fx-text-fill :white; -} - -/* HORIZONTAL HEADER VISIBILITY */ -.column-header-background.invisible { visibility: hidden; -fx-padding: -1em; } - -.cell-corner{ - -fx-background-color: red; -} - -.cell-corner.top-left{ - -fx-shape : "M 0 0 L 1 0 L 0 1 z"; -} - -.cell-corner.top-right{ - -fx-shape : "M 0 0 L -1 0 L 0 1 z"; -} - -.cell-corner.bottom-right{ - -fx-shape : "M 0 0 L -1 0 L 0 -1 z"; -} - -.cell-corner.bottom-left{ - -fx-shape : "M 0 0 L 1 0 L 0 -1 z"; -} - -.indicationLabel{ - -fx-font-style : italic; -} - -/* PICKERS */ -.picker-label{ - -fx-graphic: url("picker.png"); - -fx-background-color: white; - -fx-padding: 0 0 0 0; - -fx-alignment: center; -} - -.picker-label:hover{ - /*-fx-effect:dropshadow(gaussian, black, 10, 0.1, 0, 0);*/ - -fx-cursor:hand; -} - -/* We don't want to show the white background both for TextField -and textArea. We want it to be transparent just like Excel. - -Also we need to shift to the left the editor a bit*/ -CellView > .text-input.text-field{ - -fx-padding : 0 0 0 -0.2em; - -fx-background-color: transparent; -} -CellView > .text-input.text-area, -CellView > TextArea .scroll-pane > .viewport{ - -fx-background-color: transparent; -} - -/* I shift by 3px, it's not clean but it works for normal row (24px) as it -centers the textArea.*/ -CellView > TextArea .scroll-pane{ - -fx-padding : 3px 0 0 -0.15em; -} - -CellView > TextArea .scroll-pane > .viewport .content{ - -fx-padding : 0 0 0 0; - -fx-background-color: transparent; -} -/* The scrollBars must always have the same size because we may have -really big font in the editor (48px) and the scrollBars become obese otherwise.*/ -CellView >TextArea .scroll-bar:vertical , -CellView >TextArea .scroll-bar:horizontal { - -fx-font-size : 1em; -} - -.selection-rectangle{ - -fx-fill : transparent; - -fx-stroke : black; - -fx-stroke-width : 2; -} diff --git a/src/org/controlsfx/control/statusbar.css b/src/org/controlsfx/control/statusbar.css deleted file mode 100644 index 09f669d..0000000 --- a/src/org/controlsfx/control/statusbar.css +++ /dev/null @@ -1,6 +0,0 @@ -.status-bar { - -fx-padding: 4px; - -fx-pref-height: 30px; - -fx-background-color: lightgray, -fx-body-color; - -fx-background-insets: 0, 1 -} diff --git a/src/org/controlsfx/control/table/TableFilter.java b/src/org/controlsfx/control/table/TableFilter.java deleted file mode 100644 index f2672cc..0000000 --- a/src/org/controlsfx/control/table/TableFilter.java +++ /dev/null @@ -1,225 +0,0 @@ -/** - * Copyright (c) 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.table; - -import impl.org.controlsfx.table.ColumnFilter; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.collections.transformation.FilteredList; -import javafx.collections.transformation.SortedList; -import javafx.scene.control.TableColumn; -import javafx.scene.control.TableView; - -import java.util.Optional; -import java.util.function.BiPredicate; -import java.util.stream.Collectors; -import java.util.stream.*; - -/**Applies a filtering control to a provided {@link TableView} instance. - * The filter will be applied immediately on construction, and - * can be made visible by right-clicking the desired column to filter on. - *<br><br> - *<b>Features</b><br> - *-Convenient filter control holds a checklist of distinct items to include/exclude, much like an Excel filter.<br> - *-New/removed records will be captured by the filter control and reflect new or removed values from checklist. - *-Filters on more than one column are combined to only display mutually inclusive records on the client's TableView. - * @param <T> - */ -public final class TableFilter<T> { - - private final TableView<T> tableView; - private final ObservableList<T> backingList; - private final FilteredList<T> filteredList; - - private final ObservableList<ColumnFilter<T,?>> columnFilters = FXCollections.observableArrayList(); - - - /** - * Use TableFilter.forTableView() factory and leverage Builder - */ - @Deprecated - public TableFilter(TableView<T> tableView) { - this(tableView,false); - } - - private TableFilter(TableView<T> tableView, boolean isLazy) { - this.tableView = tableView; - backingList = tableView.getItems(); - filteredList = new FilteredList<>(new SortedList<>(backingList)); - SortedList<T> sortedControlList = new SortedList<>(this.filteredList); - - filteredList.setPredicate(v -> true); - - sortedControlList.comparatorProperty().bind(tableView.comparatorProperty()); - tableView.setItems(sortedControlList); - - applyForAllColumns(isLazy); - tableView.getStylesheets().add("/impl/org/controlsfx/table/tablefilter.css"); - - if (!isLazy) { - columnFilters.forEach(ColumnFilter::initialize); - } - } - - /** - * Allows specifying a different behavior for the search box on the TableFilter. - * By default, the contains() method on a String is used to evaluate the search box input to qualify the distinct filter values. - * But you can specify a different behavior by providing a simple BiPredicate argument to this method. - * The BiPredicate argument allows you take the input value and target value and use a lambda to evaluate a boolean. - * For instance, you can implement a comparison by assuming the input value is a regular expression, and call matches() - * on the target value to see if it aligns to the pattern. - * @param searchStrategy - */ - public void setSearchStrategy(BiPredicate<String,String> searchStrategy) { - columnFilters.forEach(cf -> cf.setSearchStrategy(searchStrategy)); - } - /** - * Returns the backing {@link ObservableList} originally provided to the constructor. - * @return ObservableList - */ - public ObservableList<T> getBackingList() { - return backingList; - } - /** - * Returns the {@link FilteredList} used by this TableFilter and is backing the {@link TableView}. - * @return FilteredList - */ - public FilteredList<T> getFilteredList() { - return filteredList; - } - /** - * @treatAsPrivate - */ - private void applyForAllColumns(boolean isLazy) { - columnFilters.setAll(tableView.getColumns().stream().flatMap(this::extractNestedColumns) - .map(c -> new ColumnFilter<>(this, c)).collect(Collectors.toList())); - } - private <S> Stream<TableColumn<T,?>> extractNestedColumns(TableColumn<T,S> tableColumn) { - if (tableColumn.getColumns().size() == 0) { - return Stream.of(tableColumn); - } else { - return tableColumn.getColumns().stream().flatMap(this::extractNestedColumns); - } - } - - /** - * Programmatically selects value for the specified TableColumn - */ - public void selectValue(TableColumn<?,?> column, Object value) { - columnFilters.stream().filter(c -> c.getTableColumn() == column) - .forEach(c -> c.selectValue(value)); - } - /** - * Programmatically unselects value for the specified TableColumn - */ - public void unselectValue(TableColumn<?,?> column, Object value) { - columnFilters.stream().filter(c -> c.getTableColumn() == column) - .forEach(c -> c.unselectValue(value)); - } - - /** - * Programmatically selects all values for the specified TableColumn - - */ - public void selectAllValues(TableColumn<?,?> column) { - columnFilters.stream().filter(c -> c.getTableColumn() == column) - .forEach(ColumnFilter::selectAllValues); - } - - /** - * Programmatically unselect all values for the specified TableColumn - */ - public void unSelectAllValues(TableColumn<?,?> column) { - columnFilters.stream().filter(c -> c.getTableColumn() == column) - .forEach(ColumnFilter::unSelectAllValues); - } - public void executeFilter() { - if (columnFilters.stream().filter(ColumnFilter::isFiltered).findAny().isPresent()) { - filteredList.setPredicate(item -> !columnFilters.stream() - .filter(cf -> !cf.evaluate(item)) - .findAny().isPresent()); - } - else { - resetFilter(); - } - } - public void resetFilter() { - filteredList.setPredicate(item -> true); - } - /** - * @treatAsPrivate - */ - public TableView<T> getTableView() { - return tableView; - } - /** - * @treatAsPrivate - */ - public ObservableList<ColumnFilter<T,?>> getColumnFilters() { - return columnFilters; - } - /** - * @treatAsPrivate - */ - public Optional<ColumnFilter<T,?>> getColumnFilter(TableColumn<T,?> tableColumn) { - return columnFilters.stream().filter(f -> f.getTableColumn().equals(tableColumn)).findAny(); - } - public boolean isDirty() { - return columnFilters.stream().filter(ColumnFilter::isFiltered).findAny().isPresent(); - } - - /** - * Returns a TableFilter.Builder to configure a TableFilter on the specified TableView. Call apply() to initialize and return the TableFilter - * @param tableView - * @param <T> - */ - public static <T> Builder<T> forTableView(TableView<T> tableView) { - return new Builder<T>(tableView); - } - - /** - * A Builder for a TableFilter against a specified TableView - * @param <T> - */ - public static final class Builder<T> { - - private final TableView<T> tableView; - private volatile boolean lazyInd = false; - - private Builder(TableView<T> tableView) { - this.tableView = tableView; - } - public Builder<T> lazy(boolean isLazy) { - this.lazyInd = isLazy; - return this; - } - public TableFilter<T> apply() { - return new TableFilter<>(tableView, lazyInd); - } - } - -} diff --git a/src/org/controlsfx/control/table/TableRowExpanderColumn.java b/src/org/controlsfx/control/table/TableRowExpanderColumn.java deleted file mode 100644 index c7af39f..0000000 --- a/src/org/controlsfx/control/table/TableRowExpanderColumn.java +++ /dev/null @@ -1,325 +0,0 @@ -/** - * Copyright (c) 2016 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.table; - -import impl.org.controlsfx.skin.ExpandableTableRowSkin; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.geometry.Insets; -import javafx.scene.Node; -import javafx.scene.control.*; -import javafx.util.Callback; - -import java.util.HashMap; -import java.util.Map; - -/** - * The TableRowExpanderColumn enables a TableView to provide an expandable editor below each table row. - * The column itself contains a toggle button that on click will show an editor for the current row right below the - * columns. Example: - * - * <pre> - * TableRowExpanderColumn<Customer> expander = new TableRowExpanderColumn<>(param -> { - * HBox editor = new HBox(10); - * TextField text = new TextField(param.getValue().getName()); - * Button save = new Button("Save customer"); - * save.setOnAction(event -> { - * save(); - * param.toggleExpanded(); - * }); - * editor.getChildren().addAll(text, save); - * return editor; - * }); - * - * tableView.getColumns().add(expander); - * </pre> - * - * You can provide a custom cellFactory to customize the toggle button. A typical custom toggle cell implementation - * would look like this: - * - * <pre> - * public class MyCustomToggleCell<S> extends TableCell<S, Boolean> { - * private Button button = new Button(); - * - * public MyCustomToggleCell(TableRowExpanderColumn<S> column) { - * button.setOnAction(event -> column.toggleExpanded(getIndex())); - * } - * - * protected void updateItem(Boolean expanded, boolean empty) { - * super.updateItem(expanded, empty); - * if (expanded == null || empty) { - * setGraphic(null); - * } else { - * button.setText(expanded ? "Collapse" : "Expand"); - * setGraphic(button); - * } - * } - * } - * </pre> - * - * The custom toggle cell utilizes the {@link TableRowExpanderColumn#toggleExpanded(int)} method to toggle - * the row expander instead of param.toggleExpanded() like the editor does. - * - * @param <S> The item type of the TableView - */ -public final class TableRowExpanderColumn<S> extends TableColumn<S, Boolean> { - private static final String STYLE_CLASS = "expander-column"; - private static final String EXPANDER_BUTTON_STYLE_CLASS = "expander-button"; - - private final Map<S, Node> expandedNodeCache = new HashMap<>(); - private final Map<S, BooleanProperty> expansionState = new HashMap<>(); - private Callback<TableRowDataFeatures<S>, Node> expandedNodeCallback; - - /** - * Returns a Boolean property that can be used to manipulate the expanded state for a row - * corresponding to the given item value. - * - * @param item The item corresponding to a table row - * @return The boolean property - */ - public BooleanProperty getExpandedProperty(S item) { - BooleanProperty value = expansionState.get(item); - if (value == null) { - value = new SimpleBooleanProperty(item, "expanded", false) { - /** - * When the expanded state change we refresh the tableview. - * If the expanded state changes to false we remove the cached expanded node. - */ - @Override - protected void invalidated() { - getTableView().refresh(); - if (!getValue()) expandedNodeCache.remove(getBean()); - } - }; - expansionState.put(item, value); - } - return value; - } - - /** - * Get or create and cache the expanded node for a given item. - * - * @param tableRow The table row, used to find the item index - * @return The expanded node for the given item - */ - public Node getOrCreateExpandedNode(TableRow<S> tableRow) { - int index = tableRow.getIndex(); - if (index > -1 && index < getTableView().getItems().size()) { - S item = getTableView().getItems().get(index); - Node node = expandedNodeCache.get(item); - if (node == null) { - node = expandedNodeCallback.call(new TableRowDataFeatures<>(tableRow, this, item)); - expandedNodeCache.put(item, node); - } - return node; - } - return null; - } - - /** - * Return the expanded node for the given item, if it exists. - * - * @param item The item corresponding to a table row - * @return The expanded node, if it exists. - */ - public Node getExpandedNode(S item) { - return expandedNodeCache.get(item); - } - - /** - * Create a row expander column that can be added to the TableView list of columns. - * - * The expandedNodeCallback is expected to return a Node representing the editor that should appear below the - * table row when the toggle button within the expander column is clicked. - * - * Once this column is assigned to a TableView, it will automatically install a custom row factory for the TableView - * so that it can configure a TableRow with the {@link impl.org.controlsfx.skin.ExpandableTableRowSkin}. It is within the skin that the actual - * rendering of the expanded node occurs. - * - * @see TableRowExpanderColumn - * @see TableRowDataFeatures - * - * @param expandedNodeCallback - */ - public TableRowExpanderColumn(Callback<TableRowDataFeatures<S>, Node> expandedNodeCallback) { - this.expandedNodeCallback = expandedNodeCallback; - - getStyleClass().add(STYLE_CLASS); - setCellValueFactory(param -> getExpandedProperty(param.getValue())); - setCellFactory(param -> new ToggleCell()); - installRowFactoryOnTableViewAssignment(); - } - - /** - * Install the row factory on the TableView when this column is assigned to a TableView. - */ - private void installRowFactoryOnTableViewAssignment() { - tableViewProperty().addListener((observable, oldValue, newValue) -> { - if (newValue != null) { - getTableView().setRowFactory(param -> new TableRow<S>() { - @Override - protected Skin<?> createDefaultSkin() { - return new ExpandableTableRowSkin<>(this, TableRowExpanderColumn.this); - } - }); - } - }); - } - - /** - * The default toggle cell creates a button with a + or - sign as the text, - * depending on the expanded state of the row it represents. - * - * You can use this as a starting point to implement a custom toggle cell. - */ - private final class ToggleCell extends TableCell<S, Boolean> { - private Button button = new Button(); - - public ToggleCell() { - button.setFocusTraversable(false); - button.getStyleClass().add(EXPANDER_BUTTON_STYLE_CLASS); - button.setPrefSize(16, 16); - button.setPadding(new Insets(0)); - button.setOnAction(event -> toggleExpanded(getIndex())); - } - - @Override - protected void updateItem(Boolean expanded, boolean empty) { - super.updateItem(expanded, empty); - if (expanded == null || empty) { - setGraphic(null); - } else { - button.setText(expanded ? "-" : "+"); - setGraphic(button); - } - } - } - - /** - * Toggle the expanded state of the row at the given index. - * - * @param index The index of the row you want to toggle expansion for. - */ - public void toggleExpanded(int index) { - BooleanProperty expanded = (BooleanProperty) getCellObservableValue(index); - expanded.setValue(!expanded.getValue()); - } - - /** - * This object is passed to the expanded node callback when it is time to create a Node to represent the - * expanded editor of a certain row. The most important method is {@link #getValue()}} which returns the - * object represented by the current row. - * - * Further more, the {@link #expandedProperty()} returns a boolean property indicating the current expansion - * state of the current row. You can use this, or the {@link #toggleExpanded()} method to toggle and inspect - * the expanded state of the row, for example if you want an action inside the row editor to contract the editor. - * - * @param <S> The type of items in the TableView - */ - public static final class TableRowDataFeatures<S> { - private TableRow<S> tableRow; - private TableRowExpanderColumn<S> tableColumn; - private BooleanProperty expandedProperty; - private S value; - - public TableRowDataFeatures(TableRow<S> tableRow, TableRowExpanderColumn<S> tableColumn, S value) { - this.tableRow = tableRow; - this.tableColumn = tableColumn; - this.expandedProperty = (BooleanProperty) tableColumn.getCellObservableValue(tableRow.getIndex()); - this.value = value; - } - - /** - * Return the current TableRow. It is safe to assume that the index returned by {@link TableRow#getIndex()} is - * correct as long as you use it for the initial node creation. It is not safe to trust the result of this call - * at any later time, for example in a button action within the row editor. - * - * @return The current TableRow - */ - public TableRow<S> getTableRow() { - return tableRow; - } - - /** - * Return the TableColumn which contains the toggle button. Normally you would not need to use this directly, - * but rather consult the {@link #expandedProperty()} for inspection and mutation of the toggled state of this row. - * - * @return The TableColumn which contains the toggle button - */ - public TableRowExpanderColumn<S> getTableColumn() { - return tableColumn; - } - - /** - * The expanded property can be used to inspect or mutate the toggled state of this row editor. You can also - * listen for changes to it's state if needed. - * - * @return The expanded property - */ - public BooleanProperty expandedProperty() { - return expandedProperty; - } - - /** - * Toggle the expanded state of this row editor. - */ - public void toggleExpanded() { - BooleanProperty expanded = expandedProperty(); - expanded.setValue(!expanded.getValue()); - } - - /** - * Returns a boolean indicating if the current row is expanded or not - * - * @return A boolean indicating the expanded state of the current editor - */ - public Boolean isExpanded() { - return expandedProperty().getValue(); - } - - /** - * Set the expanded state. This will update the {@link #expandedProperty()} accordingly. - * - * @param expanded Wheter the row editor should be expanded or not - */ - public void setExpanded(Boolean expanded) { - expandedProperty().setValue(expanded); - } - - /** - * The value represented by the current table row. It is important that the value has valid equals/hashCode - * methods, as the row value is used to keep track of the node editor for each row. - * - * @return The value represented by the current table row - */ - public S getValue() { - return value; - } - - } - -} diff --git a/src/org/controlsfx/control/table/TableViewUtils.java b/src/org/controlsfx/control/table/TableViewUtils.java deleted file mode 100644 index 94a020e..0000000 --- a/src/org/controlsfx/control/table/TableViewUtils.java +++ /dev/null @@ -1,138 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.table; - -import java.lang.reflect.Field; -import java.util.function.Consumer; - -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; -import javafx.collections.ObservableList; -import javafx.scene.Node; -import javafx.scene.control.ContextMenu; -import javafx.scene.control.Control; -import javafx.scene.control.MenuItem; -import javafx.scene.control.Skin; -import javafx.scene.control.TableView; -import javafx.scene.control.TreeTableView; - -import com.sun.javafx.scene.control.skin.TableHeaderRow; -import com.sun.javafx.scene.control.skin.TableViewSkin; -import com.sun.javafx.scene.control.skin.TableViewSkinBase; - -/** - * A utility class for API revolving around the JavaFX {@link TableView} and - * {@link TreeTableView} controls. - */ -// not public as not ready for 8.20.7 -final class TableViewUtils { - - /** - * Call this method to be able to programatically manipulate the - * {@link TableView#tableMenuButtonVisibleProperty() TableView menu button} - * (assuming it is visible). This allows developers to, for example, add in - * new {@link MenuItem}. - */ - public static void modifyTableMenu(final TableView<?> tableView, final Consumer<ContextMenu> consumer) { - modifyTableMenu((Control)tableView, consumer); - } - - /** - * Call this method to be able to programatically manipulate the - * {@link TreeTableView#tableMenuButtonVisibleProperty() TreeTableView menu button} - * (assuming it is visible). This allows developers to, for example, add in - * new {@link MenuItem}. - */ - public static void modifyTableMenu(final TreeTableView<?> treeTableView, final Consumer<ContextMenu> consumer) { - modifyTableMenu((Control)treeTableView, consumer); - } - - private static void modifyTableMenu(final Control control, final Consumer<ContextMenu> consumer) { - if (control.getScene() == null) { - control.sceneProperty().addListener(new InvalidationListener() { - @Override public void invalidated(Observable o) { - control.sceneProperty().removeListener(this); - modifyTableMenu(control, consumer); - } - }); - - return; - } - - Skin<?> skin = control.getSkin(); - if (skin == null) { - control.skinProperty().addListener(new InvalidationListener() { - @Override public void invalidated(Observable o) { - control.skinProperty().removeListener(this); - modifyTableMenu(control, consumer); - } - }); - - return; - } - - doModify(skin, consumer); - } - - private static void doModify(Skin<?> skin, Consumer<ContextMenu> consumer) { - if (! (skin instanceof TableViewSkinBase)) return; - - TableViewSkin<?> tableSkin = (TableViewSkin<?>)skin; - TableHeaderRow headerRow = getHeaderRow(tableSkin); - if (headerRow == null) return; - - ContextMenu contextMenu = getContextMenu(headerRow); - consumer.accept(contextMenu); - } - - private static TableHeaderRow getHeaderRow(TableViewSkin<?> tableSkin) { - ObservableList<Node> children = tableSkin.getChildren(); - for (int i = 0, max = children.size(); i < max; i++) { - Node child = children.get(i); - if (child instanceof TableHeaderRow) return (TableHeaderRow) child; - } - return null; - } - - private static ContextMenu getContextMenu(TableHeaderRow headerRow) { - try { - Field privateContextMenuField = TableHeaderRow.class.getDeclaredField("columnPopupMenu"); //$NON-NLS-1$ - privateContextMenuField.setAccessible(true); - ContextMenu contextMenu = (ContextMenu) privateContextMenuField.get(headerRow); - return contextMenu; - } catch (IllegalArgumentException ex) { - ex.printStackTrace(); - } catch (IllegalAccessException ex) { - ex.printStackTrace(); - } catch (NoSuchFieldException ex) { - ex.printStackTrace(); - } catch (SecurityException ex) { - ex.printStackTrace(); - } - return null; - } -} diff --git a/src/org/controlsfx/control/table/model/JavaFXTableModel.java b/src/org/controlsfx/control/table/model/JavaFXTableModel.java deleted file mode 100644 index b595123..0000000 --- a/src/org/controlsfx/control/table/model/JavaFXTableModel.java +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.table.model; - -import javafx.scene.control.TableView; - -/** - * - */ -//not public as not ready for 8.20.7 -interface JavaFXTableModel<T> { - public T getValueAt(int rowIndex, int columnIndex); - - public void setValueAt(T value, int rowIndex, int columnIndex); - - public int getRowCount(); - - public int getColumnCount(); - - public String getColumnName(int columnIndex); - - public void sort(TableView<TableModelRow<T>> table); -} diff --git a/src/org/controlsfx/control/table/model/JavaFXTableModels.java b/src/org/controlsfx/control/table/model/JavaFXTableModels.java deleted file mode 100644 index 734e123..0000000 --- a/src/org/controlsfx/control/table/model/JavaFXTableModels.java +++ /dev/null @@ -1,100 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.table.model; - -import java.util.ArrayList; -import java.util.List; - -import javafx.scene.control.TableColumn; -import javafx.scene.control.TableColumn.SortType; -import javafx.scene.control.TableView; - -import javax.swing.RowSorter.SortKey; -import javax.swing.SortOrder; -import javax.swing.table.TableModel; -import javax.swing.table.TableRowSorter; - -/** - * - */ -//not public as not ready for 8.20.7 -class JavaFXTableModels { - - /** - * Swing - */ - public static <S> JavaFXTableModel<S> wrap(final TableModel tableModel) { - - return new JavaFXTableModel<S>() { - final TableRowSorter<TableModel> sorter; - - { - sorter = new TableRowSorter<>(tableModel); - } - - @SuppressWarnings("unchecked") - @Override public S getValueAt(int rowIndex, int columnIndex) { - return (S) tableModel.getValueAt(sorter.convertRowIndexToView(rowIndex), columnIndex); - } - - @Override public void setValueAt(S value, int rowIndex, int columnIndex) { - tableModel.setValueAt(value, rowIndex, columnIndex); - } - - @Override public int getRowCount() { - return tableModel.getRowCount(); - } - - @Override public int getColumnCount() { - return tableModel.getColumnCount(); - } - - @Override public String getColumnName(int columnIndex) { - return tableModel.getColumnName(columnIndex); - } - - @Override public void sort(TableView<TableModelRow<S>> table) { - List<SortKey> sortKeys = new ArrayList<>(); - - for (TableColumn<TableModelRow<S>, ?> column : table.getSortOrder()) { - final int columnIndex = table.getVisibleLeafIndex(column); - final SortType sortType = column.getSortType(); - SortOrder sortOrder = sortType == SortType.ASCENDING ? SortOrder.ASCENDING : - sortType == SortType.DESCENDING ? SortOrder.DESCENDING : - SortOrder.UNSORTED; - SortKey sortKey = new SortKey(columnIndex, sortOrder); - sortKeys.add(sortKey); - - sorter.setComparator(columnIndex, column.getComparator()); - } - - sorter.setSortKeys(sortKeys); - sorter.sort(); - } - }; - } -} diff --git a/src/org/controlsfx/control/table/model/TableModelRow.java b/src/org/controlsfx/control/table/model/TableModelRow.java deleted file mode 100644 index 0eaa638..0000000 --- a/src/org/controlsfx/control/table/model/TableModelRow.java +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.table.model; - -/** - */ -class TableModelRow<S> { - private final int columnCount; - private final JavaFXTableModel<S> tableModel; - private final int row; - - TableModelRow(JavaFXTableModel<S> tableModel, int row) { - this.row = row; - this.tableModel = tableModel; - this.columnCount = tableModel.getColumnCount(); - } - - public Object get(int column) { - return column < 0 || column >= columnCount ? null : this.tableModel.getValueAt(row, column); - } - - @Override public String toString() { - String text = "Row " + row + ": [ "; //$NON-NLS-1$ //$NON-NLS-2$ - - for (int col = 0; col < columnCount; col++) { - text += get(col); - - if (col < (columnCount - 1)) { - text += ", "; //$NON-NLS-1$ - } - } - - text += " ]"; //$NON-NLS-1$ - return text; - } -} diff --git a/src/org/controlsfx/control/table/model/TableModelTableView.java b/src/org/controlsfx/control/table/model/TableModelTableView.java deleted file mode 100644 index 596a8d5..0000000 --- a/src/org/controlsfx/control/table/model/TableModelTableView.java +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.table.model; - -import com.sun.javafx.scene.control.ReadOnlyUnbackedObservableList; -import javafx.scene.control.TableColumn; -import javafx.scene.control.TableView; - -/** - * - */ -//not public as not ready for 8.20.7 -class TableModelTableView<S> extends TableView<TableModelRow<S>> { - - public TableModelTableView(final JavaFXTableModel<S> tableModel) { - // create a dummy items list of the appropriate size, where the returned - // value is the index of the row - setItems(new ReadOnlyUnbackedObservableList<TableModelRow<S>>() { - @Override public TableModelRow<S> get(int row) { - if (row < 0 || row >= tableModel.getRowCount()) return null; - TableModelRow<S> backingRow = new TableModelRow<>(tableModel, row); - return backingRow; - } - - @Override public int size() { - return tableModel.getRowCount(); - } - }); - - setSortPolicy(table -> { - tableModel.sort(table); - return true; - }); - - // create columns from the table model - for (int i = 0; i < tableModel.getColumnCount(); i++) { - TableColumn<TableModelRow<S>,?> column = new TableColumn<>(tableModel.getColumnName(i)); - column.setCellValueFactory(new TableModelValueFactory<>(tableModel, i)); - getColumns().add(column); - } - } -} diff --git a/src/org/controlsfx/control/table/model/TableModelValueFactory.java b/src/org/controlsfx/control/table/model/TableModelValueFactory.java deleted file mode 100644 index bc098b9..0000000 --- a/src/org/controlsfx/control/table/model/TableModelValueFactory.java +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.table.model; - -import javafx.beans.property.ReadOnlyObjectWrapper; -import javafx.beans.value.ObservableValue; -import javafx.scene.control.TableColumn; -import javafx.util.Callback; -import javafx.scene.control.TableColumn.CellDataFeatures; - -/** - * - */ -//not public as not ready for 8.20.7 -class TableModelValueFactory<S, T> implements Callback<CellDataFeatures<TableModelRow<S>, T>, ObservableValue<T>> { - @SuppressWarnings("unused") - private final JavaFXTableModel<S> _tableModel; - private final int _columnIndex; - - public TableModelValueFactory(JavaFXTableModel<S> tableModel, int columnIndex) { - _tableModel = tableModel; - _columnIndex = columnIndex; - } - - @SuppressWarnings("unchecked") - @Override public ObservableValue<T> call(TableColumn.CellDataFeatures<TableModelRow<S>, T> cdf) { - TableModelRow<S> row = cdf.getValue(); - T valueAt = (T) row.get(_columnIndex); - return valueAt instanceof ObservableValue ? ((ObservableValue<T>) valueAt) : new ReadOnlyObjectWrapper<>(valueAt); - } -} diff --git a/src/org/controlsfx/control/taskprogressview.css b/src/org/controlsfx/control/taskprogressview.css deleted file mode 100644 index 2c88aba..0000000 --- a/src/org/controlsfx/control/taskprogressview.css +++ /dev/null @@ -1,53 +0,0 @@ - -.task-progress-view { - -fx-background-color: white; -} - -.task-progress-view > * > .label { - -fx-text-fill: gray; - -fx-font-size: 18.0; - -fx-alignment: center; - -fx-padding: 10.0 0.0 5.0 0.0; -} - -.task-progress-view > * > .list-view { - -fx-border-color: transparent; - -fx-background-color: transparent; -} - -.task-title { - -fx-font-weight: bold; -} - -.task-progress-bar .bar { - -fx-padding: 6px; - -fx-background-radius: 0; - -fx-border-radius: 0; -} - -.task-progress-bar .track { - -fx-background-radius: 0; -} - -.task-message { -} - -.task-list-cell { - -fx-background-color: transparent; - -fx-padding: 4 10 8 10; - -fx-border-color: transparent transparent linear-gradient(from 0.0% 0.0% to 100.0% 100.0%, transparent, rgba(0.0,0.0,0.0,0.2), transparent) transparent; -} - -.task-list-cell-empty { - -fx-background-color: transparent; - -fx-border-color: transparent; -} - -.task-cancel-button { - -fx-base-color: red; - -fx-font-size: .75em; - -fx-font-weight: bold; - -fx-padding: 4px; - -fx-border-radius: 0; - -fx-background-radius: 0; -} \ No newline at end of file diff --git a/src/org/controlsfx/control/textfield/AutoCompletionBinding.java b/src/org/controlsfx/control/textfield/AutoCompletionBinding.java deleted file mode 100644 index f851ea0..0000000 --- a/src/org/controlsfx/control/textfield/AutoCompletionBinding.java +++ /dev/null @@ -1,558 +0,0 @@ -/** - * Copyright (c) 2014, 2016 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.textfield; - -import com.sun.javafx.event.EventHandlerManager; -import impl.org.controlsfx.skin.AutoCompletePopup; -import impl.org.controlsfx.skin.AutoCompletePopupSkin; -import javafx.application.Platform; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.ObjectPropertyBase; -import javafx.concurrent.Task; -import javafx.event.*; -import javafx.scene.Node; -import javafx.scene.control.ListView; -import javafx.scene.control.Skin; -import javafx.util.Callback; -import javafx.util.StringConverter; - -import java.util.Collection; -import javafx.beans.property.DoubleProperty; -import javafx.beans.property.IntegerProperty; - -/** - * The AutoCompletionBinding is the abstract base class of all auto-completion bindings. - * This class is the core logic for the auto-completion feature but highly customizable. - * - * <p>To use the autocompletion functionality, refer to the {@link TextFields} class. - * - * The popup size can be modified through its {@link #setVisibleRowCount(int) } - * for the height and all the usual methods for the width. - * - * @param <T> Model-Type of the suggestions - * @see TextFields - */ -public abstract class AutoCompletionBinding<T> implements EventTarget { - - - /*************************************************************************** - * * - * Private fields * - * * - **************************************************************************/ - private final Node completionTarget; - private final AutoCompletePopup<T> autoCompletionPopup; - private final Object suggestionsTaskLock = new Object(); - - private FetchSuggestionsTask suggestionsTask = null; - private Callback<ISuggestionRequest, Collection<T>> suggestionProvider = null; - private boolean ignoreInputChanges = false; - private long delay = 250; - - /*************************************************************************** - * * - * Constructors * - * * - **************************************************************************/ - - - /** - * Creates a new AutoCompletionBinding - * - * @param completionTarget The target node to which auto-completion shall be added - * @param suggestionProvider The strategy to retrieve suggestions - * @param converter The converter to be used to convert suggestions to strings - */ - protected AutoCompletionBinding(Node completionTarget, - Callback<ISuggestionRequest, Collection<T>> suggestionProvider, - StringConverter<T> converter){ - - this.completionTarget = completionTarget; - this.suggestionProvider = suggestionProvider; - this.autoCompletionPopup = new AutoCompletePopup<>(); - this.autoCompletionPopup.setConverter(converter); - - autoCompletionPopup.setOnSuggestion(sce -> { - try{ - setIgnoreInputChanges(true); - completeUserInput(sce.getSuggestion()); - fireAutoCompletion(sce.getSuggestion()); - hidePopup(); - }finally{ - // Ensure that ignore is always set back to false - setIgnoreInputChanges(false); - } - }); - } - - /*************************************************************************** - * * - * Public API * - * * - **************************************************************************/ - - /** - * Specifies whether the PopupWindow should be hidden when an unhandled - * escape key is pressed while the popup has focus. - * - * @param value - */ - public void setHideOnEscape(boolean value) { - autoCompletionPopup.setHideOnEscape(value); - } - - /** - * Set the current text the user has entered - * @param userText - */ - public final void setUserInput(String userText){ - if(!isIgnoreInputChanges()){ - onUserInputChanged(userText); - } - } - - /** - * Sets the delay in ms between a key press and the suggestion popup being displayed. - * - * @param delay - */ - public final void setDelay(long delay) { - this.delay = delay; - } - - /** - * Gets the target node for auto completion - * @return the target node for auto completion - */ - public Node getCompletionTarget(){ - return completionTarget; - } - - /** - * Disposes the binding. - */ - public abstract void dispose(); - - - /** - * Set the maximum number of rows to be visible in the popup when it is - * showing. - * - * @param value - */ - public final void setVisibleRowCount(int value) { - autoCompletionPopup.setVisibleRowCount(value); - } - - /** - * Return the maximum number of rows to be visible in the popup when it is - * showing. - * - * @return the maximum number of rows to be visible in the popup when it is - * showing. - */ - public final int getVisibleRowCount() { - return autoCompletionPopup.getVisibleRowCount(); - } - - /** - * Return an property representing the maximum number of rows to be visible - * in the popup when it is showing. - * - * @return an property representing the maximum number of rows to be visible - * in the popup when it is showing. - */ - public final IntegerProperty visibleRowCountProperty() { - return autoCompletionPopup.visibleRowCountProperty(); - } - - /** - * Sets the prefWidth of the popup. - * - * @param value - */ - public final void setPrefWidth(double value) { - autoCompletionPopup.setPrefWidth(value); - } - - /** - * Return the pref width of the popup. - * - * @return the pref width of the popup. - */ - public final double getPrefWidth() { - return autoCompletionPopup.getPrefWidth(); - } - - /** - * Return the property associated with the pref width. - * @return - */ - public final DoubleProperty prefWidthProperty() { - return autoCompletionPopup.prefWidthProperty(); - } - - /** - * Sets the minWidth of the popup. - * - * @param value - */ - public final void setMinWidth(double value) { - autoCompletionPopup.setMinWidth(value); - } - - /** - * Return the min width of the popup. - * - * @return the min width of the popup. - */ - public final double getMinWidth() { - return autoCompletionPopup.getMinWidth(); - } - - /** - * Return the property associated with the min width. - * @return - */ - public final DoubleProperty minWidthProperty() { - return autoCompletionPopup.minWidthProperty(); - } - - /** - * Sets the maxWidth of the popup. - * - * @param value - */ - public final void setMaxWidth(double value) { - autoCompletionPopup.setMaxWidth(value); - } - - /** - * Return the max width of the popup. - * - * @return the max width of the popup. - */ - public final double getMaxWidth() { - return autoCompletionPopup.getMaxWidth(); - } - - /** - * Return the property associated with the max width. - * @return - */ - public final DoubleProperty maxWidthProperty() { - return autoCompletionPopup.maxWidthProperty(); - } - - /*************************************************************************** - * * - * Protected methods * - * * - **************************************************************************/ - - /** - * Complete the current user-input with the provided completion. - * Sub-classes have to provide a concrete implementation. - * @param completion - */ - protected abstract void completeUserInput(T completion); - - - /** - * Show the auto completion popup - */ - protected void showPopup(){ - autoCompletionPopup.show(completionTarget); - selectFirstSuggestion(autoCompletionPopup); - } - - /** - * Hide the auto completion targets - */ - protected void hidePopup(){ - autoCompletionPopup.hide(); - } - - protected void fireAutoCompletion(T completion){ - Event.fireEvent(this, new AutoCompletionEvent<>(completion)); - } - - - /*************************************************************************** - * * - * Private methods * - * * - **************************************************************************/ - - /** - * Selects the first suggestion (if any), so the user can choose it - * by pressing enter immediately. - */ - private void selectFirstSuggestion(AutoCompletePopup<?> autoCompletionPopup){ - Skin<?> skin = autoCompletionPopup.getSkin(); - if(skin instanceof AutoCompletePopupSkin){ - AutoCompletePopupSkin<?> au = (AutoCompletePopupSkin<?>)skin; - ListView<?> li = (ListView<?>)au.getNode(); - if(li.getItems() != null && !li.getItems().isEmpty()){ - li.getSelectionModel().select(0); - } - } - } - - /** - * Occurs when the user text has changed and the suggestions require an update - * @param userText - */ - private final void onUserInputChanged(final String userText){ - synchronized (suggestionsTaskLock) { - if(suggestionsTask != null && suggestionsTask.isRunning()){ - // cancel the current running task - suggestionsTask.cancel(); - } - // create a new fetcher task - suggestionsTask = new FetchSuggestionsTask(userText, delay); - new Thread(suggestionsTask).start(); - } - } - - /** - * Shall changes to the user input be ignored? - * @return - */ - private boolean isIgnoreInputChanges(){ - return ignoreInputChanges; - } - - /** - * If IgnoreInputChanges is set to true, all changes to the user input are - * ignored. This is primary used to avoid self triggering while - * auto completing. - * @param state - */ - private void setIgnoreInputChanges(boolean state){ - ignoreInputChanges = state; - } - - /*************************************************************************** - * * - * Inner classes and interfaces * - * * - **************************************************************************/ - - - /** - * Represents a suggestion fetch request - * - */ - public static interface ISuggestionRequest { - /** - * Is this request canceled? - * @return {@code true} if the request is canceled, otherwise {@code false} - */ - public boolean isCancelled(); - - /** - * Get the user text to which suggestions shall be found - * @return {@link String} containing the user text - */ - public String getUserText(); - } - - - - /** - * This task is responsible to fetch suggestions asynchronous - * by using the current defined suggestionProvider - * - */ - private class FetchSuggestionsTask extends Task<Void> implements ISuggestionRequest { - private final String userText; - private final long delay; - - public FetchSuggestionsTask(String userText, long delay){ - this.userText = userText; - this.delay = delay; - } - - @Override - protected Void call() throws Exception { - Callback<ISuggestionRequest, Collection<T>> provider = suggestionProvider; - if(provider != null){ - long startTime = System.currentTimeMillis(); - final Collection<T> fetchedSuggestions = provider.call(this); - long sleepTime = startTime + delay - System.currentTimeMillis(); - if (sleepTime > 0 && !isCancelled()) { - Thread.sleep(sleepTime); - } - if(!isCancelled()){ - Platform.runLater(() -> { - if(fetchedSuggestions != null && !fetchedSuggestions.isEmpty()){ - autoCompletionPopup.getSuggestions().setAll(fetchedSuggestions); - showPopup(); - }else{ - // No suggestions found, so hide the popup - hidePopup(); - } - }); - } - }else { - // No suggestion provider - hidePopup(); - } - return null; - } - - @Override - public String getUserText() { - return userText; - } - } - - /*************************************************************************** - * * - * Events * - * * - **************************************************************************/ - - - // --- AutoCompletionEvent - - /** - * Represents an Event which is fired after an auto completion. - */ - @SuppressWarnings("serial") - public static class AutoCompletionEvent<TE> extends Event { - - /** - * The event type that should be listened to by people interested in - * knowing when an auto completion has been performed. - */ - @SuppressWarnings("rawtypes") - public static final EventType<AutoCompletionEvent> AUTO_COMPLETED = new EventType<>("AUTO_COMPLETED"); //$NON-NLS-1$ - - private final TE completion; - - /** - * Creates a new event that can subsequently be fired. - */ - public AutoCompletionEvent(TE completion) { - super(AUTO_COMPLETED); - this.completion = completion; - } - - /** - * Returns the chosen completion. - */ - public TE getCompletion() { - return completion; - } - } - - - private ObjectProperty<EventHandler<AutoCompletionEvent<T>>> onAutoCompleted; - - /** - * Set a event handler which is invoked after an auto completion. - * @param value - */ - public final void setOnAutoCompleted(EventHandler<AutoCompletionEvent<T>> value) { - onAutoCompletedProperty().set( value); - } - - public final EventHandler<AutoCompletionEvent<T>> getOnAutoCompleted() { - return onAutoCompleted == null ? null : onAutoCompleted.get(); - } - - public final ObjectProperty<EventHandler<AutoCompletionEvent<T>>> onAutoCompletedProperty() { - if (onAutoCompleted == null) { - onAutoCompleted = new ObjectPropertyBase<EventHandler<AutoCompletionEvent<T>>>() { - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Override protected void invalidated() { - eventHandlerManager.setEventHandler( - AutoCompletionEvent.AUTO_COMPLETED, - (EventHandler<AutoCompletionEvent>)(Object)get()); - } - - @Override - public Object getBean() { - return AutoCompletionBinding.this; - } - - @Override - public String getName() { - return "onAutoCompleted"; //$NON-NLS-1$ - } - }; - } - return onAutoCompleted; - } - - - /*************************************************************************** - * * - * EventTarget Implementation * - * * - **************************************************************************/ - - final EventHandlerManager eventHandlerManager = new EventHandlerManager(this); - - /** - * Registers an event handler to this EventTarget. The handler is called when the - * menu item receives an {@code Event} of the specified type during the bubbling - * phase of event delivery. - * - * @param <E> the specific event class of the handler - * @param eventType the type of the events to receive by the handler - * @param eventHandler the handler to register - * @throws NullPointerException if the event type or handler is null - */ - public <E extends Event> void addEventHandler(EventType<E> eventType, EventHandler<E> eventHandler) { - eventHandlerManager.addEventHandler(eventType, eventHandler); - } - - /** - * Unregisters a previously registered event handler from this EventTarget. One - * handler might have been registered for different event types, so the - * caller needs to specify the particular event type from which to - * unregister the handler. - * - * @param <E> the specific event class of the handler - * @param eventType the event type from which to unregister - * @param eventHandler the handler to unregister - * @throws NullPointerException if the event type or handler is null - */ - public <E extends Event> void removeEventHandler(EventType<E> eventType, EventHandler<E> eventHandler) { - eventHandlerManager.removeEventHandler(eventType, eventHandler); - } - - /** {@inheritDoc} */ - @Override public EventDispatchChain buildEventDispatchChain(EventDispatchChain tail) { - return tail.prepend(eventHandlerManager); - } - - -} diff --git a/src/org/controlsfx/control/textfield/CustomPasswordField.java b/src/org/controlsfx/control/textfield/CustomPasswordField.java deleted file mode 100644 index 0265dd6..0000000 --- a/src/org/controlsfx/control/textfield/CustomPasswordField.java +++ /dev/null @@ -1,171 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.textfield; - -import impl.org.controlsfx.skin.CustomTextFieldSkin; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.scene.Node; -import javafx.scene.control.PasswordField; -import javafx.scene.control.Skin; - -/** - * A base class for people wanting to customize a {@link PasswordField} to contain nodes - * inside the input field area itself, without being on top of the users typed-in text. - * - * <p>Whilst not exactly the same, refer to the {@link CustomTextField} javadoc - * for a screenshot and more detail. The obvious difference is that of course - * the CustomPasswordField masks the input from users, but in all other ways - * is equivalent to {@link CustomTextField}. - * - * @see CustomPasswordField - * @see TextFields - */ -public class CustomPasswordField extends PasswordField { - - /************************************************************************** - * - * Private fields - * - **************************************************************************/ - - - - - /************************************************************************** - * - * Constructors - * - **************************************************************************/ - - /** - * Instantiates a default CustomPasswordField. - */ - public CustomPasswordField() { - getStyleClass().addAll("custom-text-field", "custom-password-field"); //$NON-NLS-1$ //$NON-NLS-2$ - } - - - - /************************************************************************** - * - * Properties - * - **************************************************************************/ - - // --- left - private ObjectProperty<Node> left = new SimpleObjectProperty<>(this, "left"); //$NON-NLS-1$ - - /** - * Property representing the {@link Node} that is placed on the left of - * the password field. - * @return An ObjectProperty. - */ - public final ObjectProperty<Node> leftProperty() { - return left; - } - - /** - * - * @return The {@link Node} that is placed on the left of - * the password field. - */ - public final Node getLeft() { - return left.get(); - } - - /** - * Sets the {@link Node} that is placed on the left of - * the password field. - * @param value - */ - public final void setLeft(Node value) { - left.set(value); - } - - - // --- right - private ObjectProperty<Node> right = new SimpleObjectProperty<>(this, "right"); //$NON-NLS-1$ - - /** - * Property representing the {@link Node} that is placed on the right of - * the password field. - * @return An ObjectProperty. - */ - public final ObjectProperty<Node> rightProperty() { - return right; - } - - /** - * - * @return The {@link Node} that is placed on the right of - * the password field. - */ - public final Node getRight() { - return right.get(); - } - - /** - * Sets the {@link Node} that is placed on the right of - * the password field. - * @param value - */ - public final void setRight(Node value) { - right.set(value); - } - - - - /************************************************************************** - * - * Public API - * - **************************************************************************/ - - /** - * {@inheritDoc} - */ - @Override protected Skin<?> createDefaultSkin() { - return new CustomTextFieldSkin(this) { - @Override public ObjectProperty<Node> leftProperty() { - return CustomPasswordField.this.leftProperty(); - } - - @Override public ObjectProperty<Node> rightProperty() { - return CustomPasswordField.this.rightProperty(); - } - }; - } - - /** - * {@inheritDoc} - */ - @Override public String getUserAgentStylesheet() { - return CustomTextField.class.getResource("customtextfield.css").toExternalForm(); //$NON-NLS-1$ - } - -} diff --git a/src/org/controlsfx/control/textfield/CustomTextField.java b/src/org/controlsfx/control/textfield/CustomTextField.java deleted file mode 100644 index 5eb1ce6..0000000 --- a/src/org/controlsfx/control/textfield/CustomTextField.java +++ /dev/null @@ -1,178 +0,0 @@ -/** - * Copyright (c) 2013, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.textfield; - -import impl.org.controlsfx.skin.CustomTextFieldSkin; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.scene.Node; -import javafx.scene.control.Skin; -import javafx.scene.control.TextField; - -/** - * A base class for people wanting to customize a {@link TextField} to contain nodes - * inside the text field itself, without being on top of the users typed-in text. - * - * <h3>Screenshot</h3> - * <p>The following screenshot is taken from the HelloControlsFX sample application, - * and shows a normal TextField, with a {@link TextFields#createClearableTextField() clearable text field}, - * followed by three CustomTextFields. Note what happens with long text input - - * it is prevented from going beneath the left and right graphics. Of course, if - * the keyboard caret moves to the right, the text will become visible, but this - * is because it will all scroll to the left (as is the case in a normal {@link TextField}). - * - * <br> - * <center> - * <img src="customTextField.png" alt="Screenshot of CustomTextField"> - * </center> - * - * @see TextFields - * @see CustomPasswordField - */ -public class CustomTextField extends TextField { - - /************************************************************************** - * - * Private fields - * - **************************************************************************/ - - - - - /************************************************************************** - * - * Constructors - * - **************************************************************************/ - - /** - * Instantiates a default CustomTextField. - */ - public CustomTextField() { - getStyleClass().add("custom-text-field"); //$NON-NLS-1$ - } - - - - /************************************************************************** - * - * Properties - * - **************************************************************************/ - - // --- left - private ObjectProperty<Node> left = new SimpleObjectProperty<>(this, "left"); //$NON-NLS-1$ - - /** - * - * @return An ObjectProperty wrapping the {@link Node} that is placed - * on the left ofthe text field. - */ - public final ObjectProperty<Node> leftProperty() { - return left; - } - - /** - * - * @return the {@link Node} that is placed on the left of - * the text field. - */ - public final Node getLeft() { - return left.get(); - } - - /** - * Sets the {@link Node} that is placed on the left of - * the text field. - * @param value - */ - public final void setLeft(Node value) { - left.set(value); - } - - - // --- right - private ObjectProperty<Node> right = new SimpleObjectProperty<>(this, "right"); //$NON-NLS-1$ - - /** - * Property representing the {@link Node} that is placed on the right of - * the text field. - * @return An ObjectProperty. - */ - public final ObjectProperty<Node> rightProperty() { - return right; - } - - /** - * - * @return The {@link Node} that is placed on the right of - * the text field. - */ - public final Node getRight() { - return right.get(); - } - - /** - * Sets the {@link Node} that is placed on the right of - * the text field. - * @param value - */ - public final void setRight(Node value) { - right.set(value); - } - - - - /************************************************************************** - * - * Public API - * - **************************************************************************/ - - /** - * {@inheritDoc} - */ - @Override protected Skin<?> createDefaultSkin() { - return new CustomTextFieldSkin(this) { - @Override public ObjectProperty<Node> leftProperty() { - return CustomTextField.this.leftProperty(); - } - - @Override public ObjectProperty<Node> rightProperty() { - return CustomTextField.this.rightProperty(); - } - }; - } - - /** - * {@inheritDoc} - */ - @Override public String getUserAgentStylesheet() { - return CustomTextField.class.getResource("customtextfield.css").toExternalForm(); //$NON-NLS-1$ - } -} diff --git a/src/org/controlsfx/control/textfield/TextFields.java b/src/org/controlsfx/control/textfield/TextFields.java deleted file mode 100644 index 3f8d7ab..0000000 --- a/src/org/controlsfx/control/textfield/TextFields.java +++ /dev/null @@ -1,190 +0,0 @@ -/** - * Copyright (c) 2014, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.control.textfield; - -import impl.org.controlsfx.autocompletion.AutoCompletionTextFieldBinding; -import impl.org.controlsfx.autocompletion.SuggestionProvider; - -import java.util.Arrays; -import java.util.Collection; - -import javafx.animation.FadeTransition; -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; -import javafx.beans.property.ObjectProperty; -import javafx.scene.Cursor; -import javafx.scene.Node; -import javafx.scene.control.PasswordField; -import javafx.scene.control.TextField; -import javafx.scene.layout.Region; -import javafx.scene.layout.StackPane; -import javafx.util.Callback; -import javafx.util.Duration; -import javafx.util.StringConverter; - -import org.controlsfx.control.textfield.AutoCompletionBinding.ISuggestionRequest; - -/** - * A class containing useful customizations for the JavaFX {@link TextField}. - * Note that this class is experimental and the API may change in future - * releases. Note also that this class makes use of the {@link CustomTextField} - * class. - * - * @see CustomTextField - */ -public class TextFields { - private static final Duration FADE_DURATION = Duration.millis(350); - - private TextFields() { - // no-op - } - - /*************************************************************************** - * * - * Search fields * - * * - **************************************************************************/ - - /** - * Creates a TextField that shows a clear button inside the TextField (on - * the right hand side of it) when text is entered by the user. - */ - public static TextField createClearableTextField() { - CustomTextField inputField = new CustomTextField(); - setupClearButtonField(inputField, inputField.rightProperty()); - return inputField; - } - - /** - * Creates a PasswordField that shows a clear button inside the PasswordField - * (on the right hand side of it) when text is entered by the user. - */ - public static PasswordField createClearablePasswordField() { - CustomPasswordField inputField = new CustomPasswordField(); - setupClearButtonField(inputField, inputField.rightProperty()); - return inputField; - } - - private static void setupClearButtonField(TextField inputField, ObjectProperty<Node> rightProperty) { - inputField.getStyleClass().add("clearable-field"); //$NON-NLS-1$ - - Region clearButton = new Region(); - clearButton.getStyleClass().addAll("graphic"); //$NON-NLS-1$ - StackPane clearButtonPane = new StackPane(clearButton); - clearButtonPane.getStyleClass().addAll("clear-button"); //$NON-NLS-1$ - clearButtonPane.setOpacity(0.0); - clearButtonPane.setCursor(Cursor.DEFAULT); - clearButtonPane.setOnMouseReleased(e -> inputField.clear()); - clearButtonPane.managedProperty().bind(inputField.editableProperty()); - clearButtonPane.visibleProperty().bind(inputField.editableProperty()); - - rightProperty.set(clearButtonPane); - - final FadeTransition fader = new FadeTransition(FADE_DURATION, clearButtonPane); - fader.setCycleCount(1); - - inputField.textProperty().addListener(new InvalidationListener() { - @Override public void invalidated(Observable arg0) { - String text = inputField.getText(); - boolean isTextEmpty = text == null || text.isEmpty(); - boolean isButtonVisible = fader.getNode().getOpacity() > 0; - - if (isTextEmpty && isButtonVisible) { - setButtonVisible(false); - } else if (!isTextEmpty && !isButtonVisible) { - setButtonVisible(true); - } - } - - private void setButtonVisible( boolean visible ) { - fader.setFromValue(visible? 0.0: 1.0); - fader.setToValue(visible? 1.0: 0.0); - fader.play(); - } - }); - } - - /*************************************************************************** - * * - * Auto-completion * - * * - **************************************************************************/ - - /** - * Create a new auto-completion binding between the given textField and the - * given suggestion provider. - * - * The {@link TextFields} API has some suggestion-provider builder methods - * for simple use cases. - * - * @param textField The {@link TextField} to which auto-completion shall be added - * @param suggestionProvider A suggestion-provider strategy to use - * @param converter The converter to be used to convert suggestions to strings - */ - public static <T> AutoCompletionBinding<T> bindAutoCompletion(TextField textField, - Callback<ISuggestionRequest, Collection<T>> suggestionProvider, - StringConverter<T> converter) { - return new AutoCompletionTextFieldBinding<>(textField, - suggestionProvider, converter); - } - - /** - * Create a new auto-completion binding between the given textField and the - * given suggestion provider. - * - * The {@link TextFields} API has some suggestion-provider builder methods - * for simple use cases. - * - * @param textField The {@link TextField} to which auto-completion shall be added - * @param suggestionProvider A suggestion-provider strategy to use - * @return The AutoCompletionBinding - */ - public static <T> AutoCompletionBinding<T> bindAutoCompletion(TextField textField, - Callback<ISuggestionRequest, Collection<T>> suggestionProvider){ - return new AutoCompletionTextFieldBinding<>(textField, suggestionProvider); - } - - /** - * Create a new auto-completion binding between the given {@link TextField} - * using the given auto-complete suggestions - * - * @param textField The {@link TextField} to which auto-completion shall be added - * @param possibleSuggestions Possible auto-complete suggestions - * @return The AutoCompletionBinding - */ - public static <T> AutoCompletionBinding<T> bindAutoCompletion( - TextField textField, @SuppressWarnings("unchecked") T... possibleSuggestions) { - return bindAutoCompletion(textField, Arrays.asList(possibleSuggestions)); - } - - public static <T> AutoCompletionBinding<T> bindAutoCompletion( - TextField textField, Collection<T> possibleSuggestions) { - return new AutoCompletionTextFieldBinding<>(textField, - SuggestionProvider.create(possibleSuggestions)); - } -} - diff --git a/src/org/controlsfx/control/textfield/autocompletion.css b/src/org/controlsfx/control/textfield/autocompletion.css deleted file mode 100644 index 2e22806..0000000 --- a/src/org/controlsfx/control/textfield/autocompletion.css +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Style based on Modena.css combo-box-popup style - */ - -.auto-complete-popup > .list-view { - -fx-background-color: - linear-gradient(to bottom, - derive(-fx-color,-17%), - derive(-fx-color,-30%) - ), - -fx-control-inner-background; - -fx-background-insets: -1 -2 -1 -1, 0 -1 0 0; - -fx-effect: dropshadow( gaussian , rgba(0,0,0,0.2) , 12, 0.0 , 0 , 8 ); -} -.auto-complete-popup > .list-view > .virtual-flow > .clipped-container > .sheet > .list-cell { - -fx-padding: 4 0 4 5; - /* No alternate highlighting */ - -fx-background: -fx-control-inner-background; -} -.auto-complete-popup > .list-view > .virtual-flow > .clipped-container > .sheet > .list-cell:filled:selected { - -fx-background: -fx-selection-bar-non-focused; - -fx-background-color: -fx-background; -} -.auto-complete-popup > .list-view > .virtual-flow > .clipped-container > .sheet > .list-cell:filled:hover, -.auto-complete-popup > .list-view > .virtual-flow > .clipped-container > .sheet > .list-cell:filled:selected:hover { - -fx-background: -fx-accent; - -fx-background-color: -fx-selection-bar; -} -.auto-complete-popup > .list-view > .placeholder > .label { - -fx-text-fill: derive(-fx-control-inner-background,-30%); -} \ No newline at end of file diff --git a/src/org/controlsfx/control/textfield/customtextfield.css b/src/org/controlsfx/control/textfield/customtextfield.css deleted file mode 100644 index f8e08cf..0000000 --- a/src/org/controlsfx/control/textfield/customtextfield.css +++ /dev/null @@ -1,89 +0,0 @@ -/************************************************************************** - * - * CustomTextField - * - **************************************************************************/ - -.custom-text-field { - -fx-text-fill: -fx-text-inner-color; - -fx-highlight-fill: derive(-fx-control-inner-background,-20%); - -fx-highlight-text-fill: -fx-text-inner-color; - -fx-prompt-text-fill: derive(-fx-control-inner-background,-30%); - -fx-background-color: linear-gradient(to bottom, derive(-fx-text-box-border, -10%), -fx-text-box-border), - linear-gradient(from 0px 0px to 0px 5px, derive(-fx-control-inner-background, -9%), -fx-control-inner-background); - -fx-background-insets: 0, 1; - -fx-background-radius: 3, 2; - -} - -/* -.custom-text-field { - -fx-background-color: null; - -fx-background-insets: 0; -} -*/ -.custom-text-field:no-side-nodes { - -fx-padding: 0.333333em 0.583em 0.333333em 0.583em; -} - -.custom-text-field:left-node-visible { - -fx-padding: 0.333333em 0.583em 0.333333em 0; -} - -.custom-text-field:right-node-visible { - -fx-padding: 0.333333em 0 0.333333em 0.583em; -} - -.custom-text-field:left-node-visible:right-node-visible { - -fx-padding: 0.333333em 0 0.333333em 0; -} - -.custom-text-field:left-node-visible .left-pane { - -fx-padding: 0 3 0 3; -} - -.custom-text-field:right-node-visible .right-pane { - -fx-padding: 0 3 0 3; -} - -.custom-text-field:focused, -.custom-text-field:text-field-has-focus { - -fx-highlight-fill: -fx-accent; - -fx-highlight-text-fill: white; - -fx-background-color: - -fx-focus-color, - -fx-control-inner-background, - -fx-faint-focus-color, - linear-gradient(from 0px 0px to 0px 5px, derive(-fx-control-inner-background, -9%), -fx-control-inner-background); - -fx-background-insets: -0.2, 1, -1.4, 3; - -fx-background-radius: 3, 2, 4, 0; - -fx-prompt-text-fill: transparent; -} - - - - -/************************************************************************** - * - * Clearable Text / Password Field - * - **************************************************************************/ - -.clearable-field .clear-button { - -fx-padding: 0 3 0 0; -} - -.clearable-field .clear-button > .graphic { - -fx-background-color: #949494; - -fx-scale-shape: false; - -fx-padding: 4.5 4.5 4.5 4.5; /* Graphic is 9x9 px */ - -fx-shape: "M395.992,296.758l1.794-1.794l7.292,7.292l-1.795,1.794 L395.992,296.758z M403.256,294.992l1.794,1.794l-7.292,7.292l-1.794-1.795 L403.256,294.992z"; -} - -.clearable-field .clear-button:hover > .graphic { - -fx-background-color: #ee4444; -} - -.clearable-field .clear-button:pressed > .graphic { - -fx-background-color: #ff1111; -} \ No newline at end of file diff --git a/src/org/controlsfx/control/textfield/package-info.java b/src/org/controlsfx/control/textfield/package-info.java deleted file mode 100644 index f7985d8..0000000 --- a/src/org/controlsfx/control/textfield/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * A package containing a number of useful classes related to text input. - */ -package org.controlsfx.control.textfield; \ No newline at end of file diff --git a/src/org/controlsfx/control/toggleswitch.css b/src/org/controlsfx/control/toggleswitch.css deleted file mode 100644 index 022de66..0000000 --- a/src/org/controlsfx/control/toggleswitch.css +++ /dev/null @@ -1,51 +0,0 @@ -/******************************************************************************* - * * - * ToggleSwitch * - * * - ******************************************************************************/ -.toggle-switch{ - -thumb-move-animation-time: 200; -} - -.toggle-switch .text { - -fx-font-size: 1em; - -fx-text-fill: -fx-text-base-color; -} - -.toggle-switch .thumb { - -fx-background-color: linear-gradient(to bottom, derive(-fx-text-box-border, -20%), derive(-fx-text-box-border, -30%)), - -fx-inner-border, - -fx-body-color; - -fx-background-insets: 0, 1, 2; - -fx-background-radius: 1.0em; /* large value to make sure this remains circular */ - -fx-padding: 0.75em; - -fx-alignment: CENTER; - -fx-content-display: LEFT; -} - -.toggle-switch .thumb-area{ - -fx-background-radius: 1em; - -fx-background-color: linear-gradient(to bottom, derive(-fx-text-box-border, -20%), derive(-fx-text-box-border, -30%)), #f5f5f5; - -fx-background-insets: 0, 1; -} - -.toggle-switch:hover .thumb{ - -fx-color: -fx-hover-base -} - -.toggle-switch:selected .thumb-area{ - -fx-background-color: linear-gradient(to bottom, derive(-fx-text-box-border, -20%), derive(-fx-text-box-border, -30%)), - linear-gradient(to bottom, derive(#0b99c9, 30%), #0b99c9); - -fx-background-insets: 0, 1; - -} - -.toggle-switch .thumb-area -{ - -fx-padding: 0.75em 1.333333em 0.75em 1.333333em; /* 7 16 7 16 */ -} - -.toggle-switch:disabled -{ - -fx-opacity: 0.4; -} diff --git a/src/org/controlsfx/control/unselected-star.png b/src/org/controlsfx/control/unselected-star.png deleted file mode 100644 index 774c240118b6220c788fe44dd97c8af2fdd4430f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2252 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`MwVKyBnAcs$r9IylHmNblJdl&R0hYC z{G?O`&)mfH)S%SFl*+=BsWuD@9C@BDjv*DdlK%YvZ_jL$&}5i*f8SPK7vrXoJ3EW3 zZ|<-Ezy9;5qMJ>j8#dJZ)YR8kvnhPU;@!ZIbR_H8v$N85Wu>LAjW^ER-&eakB{|vJ zIWjVG#rpN{^&(Dpi~C16OsZE=St8BA)WN9I&@<n5cPabK^E@Gux;i==y4%~0zaH%l z&*S0AS#MwaOW^piW0%T5JUAG(<J3~`=Q7p5zGUiNI2R=_ckbN1tZ$rV7^k0mQ^&aE zN8^ms*REYFxV^3QykijqW6MMSk^?PgW?B?JidLBB7TEaa(eCp6ca^`soGVN*T=w(x z^M8LoKEAy?eEmGx<kY8sKE9W~eVbqYUR>qRPdBF@J9g~<g@($CCl?n_|NY~~kGf`` zzu(`_zw!C`cbmC$YeNp?O_(rYyP&{>-`c9GM;Q*ynRDj8!=wUtHFb6G2AjiY{zNx) zzSK9raHU?OkB6UszND1YE{PLQ*^=(Pc=1AC;jDsX1H&PX_LafQm5Ln$3z<7Y6PXSO zq#cmtIk98=_VA}SH(RH_zq@;<{E2_f-m-1nQPI(koSOD_cAt*FzyE*#A9gkoV`Jvm z&FuU>{W6yOI5f<+@7ndt$j9~u!-4}3-@H+|CU5_*J|QXT=ix(#n0N%z*wob2*xcOQ zHuxS`kox2Icm2cj?dv5P8IKk|J|?=gnce^8;vEY%Z1~`rl=Nd({eO#lA3uHi_x#C| z6b4DQD@Q*3{avo`?@-y>Tb0uvAJ<>@_51huV;<TLjx*=m@7MVJp}>%dH$gx|Bt<}2 znEA4ToxZ;M?|rrEB?+?*TJqd%`0?Y%gkQhreDCS8Kk7H{PWq;_vt?!r3fkAKIdbOE zp)0=i|Ns41vQY86TqOS;ZioGwX3m(AGS{;Bnb3saq8;}cK3XgMV?AQypu=*c$w9x6 zd2fmIiua5j@(v8gRxR7wslbyz>&>~c=~qgcT|X{%WA(k^5X;4_xai5Fg<O}MGxg+H z`Qy5t%-Y<3tRX~kd6Uu?1-ZZMPE(`~HZQz(Y>U9st@4wW-8}14UYq8-K~bgjL27z> z*}Yo(dCzAi|17w}!NVXZuR7yq-y(6B=7uTfpKtB$)fcsS{deETAJ_CvzWiZNcD|pU zmN#9|L-@bz&vOlHe9xY{ryF?c_WL(4tG>kAv&Xu!^sFx^Qxkgj*W*c&;Dg63-vu89 zi;Kq>x}IX(s=rGnWpkwYOrH%AI%(Onu5DTKENt(-{e8M@uS2pr1U|N`(n@Dy^lYx^ zK7Cq#sn^n9Iu4ql8f(`FWlhcAI$!J;&!<0+ouZRuy!gwvZ?AuE#rL`W@WBhGPOa+d zkgw8AF`7AfWym9Eo4lI4H*ac3Pusgvqf4P{(Q^iS!Kk&<I3jng(YUnp=g;MWS6=3X z^Exc~+*bItcU^q7_G!oH(9lMKM{jR#(>0OeeNt=?rLkuZyIxE6u7;yulRg%E2Bs*T z-gH3rk7~e$+5G&%_ix=Y|NG+MJTs=p<`cH}KR=(T<2fn4hHq}c;)~w<*&Z>3pR-^n zd9mxv`(0)po8{Bi2o}u|dzhru^@M@T=Hhhj<mANxD$7n8*-kxeyEAz0wPzdtBvk#H zR$p|f;=IIH<x?ux?7kK>x^Ld{rG|UbU7v-j74i?mBco5bE4*%PZ9P8wWy!D7>pPYC z^cF+}SH!g+O<aDv-FZXd494A=vz{r>%YA-Fo-u3vw0UZa3{K5`natqb+_f}FD!JiB zQ^Qd$6%iq)9`0tr?JXyoT5}Q(I*F}`*pQeQvEd>64h0ntg$GUU4gww=BFv16s!9P; znT~QxFCV}1d8=^*&op<XlP}+v?708^?B4sf&wXO-Uc7j*ql2$2_2OIm_i3@QcaOFR zy<c(Mxw`uI?UN@B3#+Q`w7-A9PWpLN4@X~Be8i6*y*G1W7FyiCz3xqC=gfa?ZEdes zAKO*Ln46nhyL72**ow173JO0ncDWs9*?xPnsm-687jN9i_^r>nW!tt%PP$<sHqT3T zP3cVt5K`@w=w{Ju3|~F-!Dm_N-MfE#HprQnn##tmY?wAp%qoG^VP8+vmy%{P<I5sO z5|^Ca78@Rj$Osf+p3uQk!CRKq7%|1P^G^WB{4<5K?#z{4e(Pn)r`xyv>WYiCRp#%# zd1K?wot8&FIQm};kBf`S+8Xt3;)CfLzxWSyw7ax$^t;S)5o<Qo<5|Wj?C-w*=FGHX z>b*L*5`=nX3M~&bPbz6za53BD)s&w<Tdy2EsA#QbV;#$=BPqLl;UuB#sJOU){6)$$ z<PRh(TDnU;XYH0@Jig$&a7_0M>6=Ui^SLfCbvhVj{9${hI#J$9QNtmqnXk2#b$4b- zN!PO*8<tu>|Hd$@Bj-a#WTfEflPBkWt>D|&?ldQSX^{7V?*^GHjU3Yjln)6`D06xE zd}C_o%9U1|4{!XJk&w_LccD!!Zg+_Awd>a>@9PT>-~UU6<CpH6*PJIJf+XTJoeJx{ zia5j>3y-=4+L)A-)vZ{vv~B<Vom;dg#B+rSe0crt-MiQ~v%7?Xl7uWTX&3b^nYAR; z<dW%MzwaOa_dKiE>%Ltu`E~rs$6^ZJg@t9`Y~O@hY?^y&m1b}2-cVP^`!CIpy1Iyk zojPGqRWa}Bm221T?U}N*`|s+ND=U)>?l>)0?PzomSad2|@^kiu$xO$8P8Jit?vtDx zY`J5(mS*LyNz<qA7UXN+^WwCy1iyV{*0Cl>k0<jEZ*-k?v3e!bl*OT;p{d3*FZEr? z($tmVTjJ+ecXHP3=zZ_Y-uF+~&(t>6(%XA=m%-K7Uw4U%ojzPT`|K~?_GaVRm-nt- zEq%1(_V4FAj%7NzrSq*1nmTo=?Tzn$_U_%=U$%Si@ux*QQzvU5Q;@Lyb8)*Sqk^>S zo<*(4FGuT4n=TQreB3WQTwJuG;+d?TA7cvJyAua%ji$5&osqaKKC$l6lcbO$#m=I{ ilK<)jAIcf`Gp_u5)8xfjK|KZr1_n=8KbLh*2~7Y1Cr~~B diff --git a/src/org/controlsfx/dialog/CommandLinksDialog.java b/src/org/controlsfx/dialog/CommandLinksDialog.java deleted file mode 100644 index 4d2e0e5..0000000 --- a/src/org/controlsfx/dialog/CommandLinksDialog.java +++ /dev/null @@ -1,298 +0,0 @@ -/** - * Copyright (c) 2014, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.dialog; - -import static impl.org.controlsfx.i18n.Localization.getString; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javafx.beans.binding.DoubleBinding; -import javafx.collections.ListChangeListener; -import javafx.geometry.Insets; -import javafx.geometry.Pos; -import javafx.geometry.VPos; -import javafx.scene.Node; -import javafx.scene.control.Button; -import javafx.scene.control.ButtonBar.ButtonData; -import javafx.scene.control.ButtonType; -import javafx.scene.control.Dialog; -import javafx.scene.control.DialogPane; -import javafx.scene.control.Label; -import javafx.scene.image.ImageView; -import javafx.scene.layout.GridPane; -import javafx.scene.layout.Pane; -import javafx.scene.layout.Priority; - -public class CommandLinksDialog extends Dialog<ButtonType> { - - public static class CommandLinksButtonType { - private final ButtonType buttonType; - private final String longText; - private final Node graphic; - private boolean isHidden = false; - - public CommandLinksButtonType(String text, boolean isDefault ) { - this(new ButtonType(text, buildButtonData(isDefault)), null); - } - - public CommandLinksButtonType(String text, String longText, boolean isDefault) { - this(new ButtonType(text, buildButtonData(isDefault)), longText, null); - } - - public CommandLinksButtonType(String text, String longText, Node graphic, boolean isDefault) { - this(new ButtonType(text, buildButtonData(isDefault)), longText, graphic); - } - - private CommandLinksButtonType(ButtonType buttonType) { - this(buttonType, null); - } - - private CommandLinksButtonType(ButtonType buttonType, String longText) { - this(buttonType, longText, null); - } - - private CommandLinksButtonType(ButtonType buttonType, String longText, Node graphic) { - this.buttonType = buttonType; - this.longText = longText; - this.graphic = graphic; - - } - - private static ButtonData buildButtonData( boolean isDeafault) { - return isDeafault? ButtonData.OK_DONE :ButtonData.OTHER; - } - - private static CommandLinksButtonType buildHiddenCancelLink() { - CommandLinksButtonType link = new CommandLinksButtonType(new ButtonType("",ButtonData.CANCEL_CLOSE)); - link.isHidden = true; - return link; - } - - public ButtonType getButtonType() { - return buttonType; - } - - public Node getGraphic() { - return graphic; - } - - public String getLongText() { - return longText; - } - } - - - private final static int gapSize = 10; - - private final Map<ButtonType, CommandLinksButtonType> typeMap; - - private Label contentTextLabel; - - private GridPane grid = new GridPane() { - @Override protected double computePrefWidth(double height) { - boolean isDefault = true; - double pw = 0; - - for (ButtonType buttonType : getDialogPane().getButtonTypes()) { - Button button = (Button) getDialogPane().lookupButton(buttonType); - double buttonPrefWidth = button.getGraphic().prefWidth(-1); - - if (isDefault) { - pw = buttonPrefWidth; - isDefault = false; - } else { - pw = Math.min(pw, buttonPrefWidth); - } - } - return pw + gapSize; - } - - @Override protected double computePrefHeight(double width) { - double ph = getDialogPane().getHeader() == null ? 0 : 10; - - for (ButtonType buttonType : getDialogPane().getButtonTypes()) { - Button button = (Button) getDialogPane().lookupButton(buttonType); - ph += button.prefHeight(width) + gapSize; - } - - // TODO remove magic number - return ph * 1.2; - } - }; - - public CommandLinksDialog(CommandLinksButtonType... links) { - this(Arrays.asList(links)); - } - - public CommandLinksDialog(List<CommandLinksButtonType> links) { - this.grid.setHgap(gapSize); - this.grid.setVgap(gapSize); - this.grid.getStyleClass().add("container"); //$NON-NLS-1$ - - final DialogPane dialogPane = new DialogPane() { - @Override protected Node createButtonBar() { - return null; - } - - @Override protected Node createButton(ButtonType buttonType) { - return createCommandLinksButton(buttonType); - } - }; - setDialogPane(dialogPane); - - setTitle(getString("Dialog.info.title")); //$NON-NLS-1$ - dialogPane.getStyleClass().add("command-links-dialog"); //$NON-NLS-1$ - dialogPane.getStylesheets().add(getClass().getResource("dialogs.css").toExternalForm()); //$NON-NLS-1$ - dialogPane.getStylesheets().add(getClass().getResource("commandlink.css").toExternalForm()); //$NON-NLS-1$ - - // create a map from ButtonType -> CommandLinkButtonType, and put the - // ButtonType values into the dialog pane - - typeMap = new HashMap<>(); - for (CommandLinksButtonType link : links) { - addLinkToDialog(dialogPane,link); - } - addLinkToDialog(dialogPane,CommandLinksButtonType.buildHiddenCancelLink()); - - updateGrid(); - dialogPane.getButtonTypes().addListener((ListChangeListener<? super ButtonType>)c -> updateGrid()); - - contentTextProperty().addListener(o -> updateContentText()); - } - - private void addLinkToDialog(DialogPane dialogPane, CommandLinksButtonType link) { - typeMap.put(link.getButtonType(), link); - dialogPane.getButtonTypes().add(link.getButtonType()); - } - - private void updateContentText() { - String contentText = getDialogPane().getContentText(); - grid.getChildren().remove(contentTextLabel); - if (contentText != null && ! contentText.isEmpty()) { - if (contentTextLabel != null) { - contentTextLabel.setText(contentText); - } else { - contentTextLabel = new Label(getDialogPane().getContentText()); - contentTextLabel.getStyleClass().add("command-link-message"); //$NON-NLS-1$ - } - grid.add(contentTextLabel, 0, 0); - } - } - - private void updateGrid() { - grid.getChildren().clear(); - - // add the message to the top of the dialog - updateContentText(); - - // then build all the buttons - int row = 1; - for (final ButtonType buttonType : getDialogPane().getButtonTypes()) { - if (buttonType == null) continue; - - final Button button = (Button)getDialogPane().lookupButton(buttonType); - - GridPane.setHgrow(button, Priority.ALWAYS); - GridPane.setVgrow(button, Priority.ALWAYS); - grid.add(button, 0, row++); - } - -// // last button gets some extra padding (hacky) -// GridPane.setMargin(buttons.get(buttons.size() - 1), new Insets(0,0,10,0)); - - getDialogPane().setContent(grid); - getDialogPane().requestLayout(); - } - - private Button createCommandLinksButton(ButtonType buttonType) { - // look up the CommandLinkButtonType for the given ButtonType - CommandLinksButtonType commandLink = typeMap.getOrDefault(buttonType, new CommandLinksButtonType(buttonType)); - - - // put the content inside a button - final Button button = new Button(); - button.getStyleClass().addAll("command-link-button"); //$NON-NLS-1$ - button.setMaxHeight(Double.MAX_VALUE); - button.setMaxWidth(Double.MAX_VALUE); - button.setAlignment(Pos.CENTER_LEFT); - - final ButtonData buttonData = buttonType.getButtonData(); - button.setDefaultButton(buttonData != null && buttonData.isDefaultButton()); - button.setOnAction(ae -> setResult(buttonType)); - - final Label titleLabel = new Label(commandLink.getButtonType().getText() ); - titleLabel.minWidthProperty().bind(new DoubleBinding() { - { - bind(titleLabel.prefWidthProperty()); - } - - @Override protected double computeValue() { - return titleLabel.getPrefWidth() + 400; - } - }); - titleLabel.getStyleClass().addAll("line-1"); //$NON-NLS-1$ - titleLabel.setWrapText(true); - titleLabel.setAlignment(Pos.TOP_LEFT); - GridPane.setVgrow(titleLabel, Priority.NEVER); - - Label messageLabel = new Label(commandLink.getLongText() ); - messageLabel.getStyleClass().addAll("line-2"); //$NON-NLS-1$ - messageLabel.setWrapText(true); - messageLabel.setAlignment(Pos.TOP_LEFT); - messageLabel.setMaxHeight(Double.MAX_VALUE); - GridPane.setVgrow(messageLabel, Priority.SOMETIMES); - - Node commandLinkImage = commandLink.getGraphic(); - Node view = commandLinkImage == null ? - new ImageView(CommandLinksDialog.class.getResource("arrow-green-right.png").toExternalForm()) : //$NON-NLS-1$ - commandLinkImage; - Pane graphicContainer = new Pane(view); - graphicContainer.getStyleClass().add("graphic-container"); //$NON-NLS-1$ - GridPane.setValignment(graphicContainer, VPos.TOP); - GridPane.setMargin(graphicContainer, new Insets(0,10,0,0)); - - GridPane grid = new GridPane(); - grid.minWidthProperty().bind(titleLabel.prefWidthProperty()); - grid.setMaxHeight(Double.MAX_VALUE); - grid.setMaxWidth(Double.MAX_VALUE); - grid.getStyleClass().add("container"); //$NON-NLS-1$ - grid.add(graphicContainer, 0, 0, 1, 2); - grid.add(titleLabel, 1, 0); - grid.add(messageLabel, 1, 1); - - button.setGraphic(grid); - button.minWidthProperty().bind(titleLabel.prefWidthProperty()); - - if (commandLink.isHidden) { - button.setVisible(false); - button.setPrefHeight(1); - } - return button; - } -} diff --git a/src/org/controlsfx/dialog/DialogUtils.java b/src/org/controlsfx/dialog/DialogUtils.java deleted file mode 100644 index 21fdd4c..0000000 --- a/src/org/controlsfx/dialog/DialogUtils.java +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Copyright (c) 2014 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.dialog; - -import javafx.scene.control.ButtonType; -import javafx.scene.control.Dialog; -import javafx.scene.control.DialogPane; -import javafx.scene.control.ButtonBar.ButtonData; - -// package scope -class DialogUtils { - - static void forcefullyHideDialog(javafx.scene.control.Dialog<?> dialog) { - // for the dialog to be able to hide, we need a cancel button, - // so lets put one in now and then immediately call hide, and then - // remove the button again (if necessary). - DialogPane dialogPane = dialog.getDialogPane(); - if (containsCancelButton(dialog)) { - dialog.hide(); - return; - } - - dialogPane.getButtonTypes().add(ButtonType.CANCEL); - dialog.hide(); - dialogPane.getButtonTypes().remove(ButtonType.CANCEL); - } - - static boolean containsCancelButton(Dialog<?> dialog) { - DialogPane dialogPane = dialog.getDialogPane(); - for (ButtonType type : dialogPane.getButtonTypes()) { - if (type.getButtonData() == ButtonData.CANCEL_CLOSE) { - return true; - } - } - return false; - } -} diff --git a/src/org/controlsfx/dialog/ExceptionDialog.java b/src/org/controlsfx/dialog/ExceptionDialog.java deleted file mode 100644 index 816b513..0000000 --- a/src/org/controlsfx/dialog/ExceptionDialog.java +++ /dev/null @@ -1,84 +0,0 @@ -/** - * Copyright (c) 2014 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.dialog; - -import static impl.org.controlsfx.i18n.Localization.getString; -import static impl.org.controlsfx.i18n.Localization.localize; - -import java.io.PrintWriter; -import java.io.StringWriter; - -import javafx.scene.control.ButtonType; -import javafx.scene.control.Dialog; -import javafx.scene.control.DialogPane; -import javafx.scene.control.Label; -import javafx.scene.control.TextArea; -import javafx.scene.layout.GridPane; -import javafx.scene.layout.Priority; - -public class ExceptionDialog extends Dialog<ButtonType> { - - public ExceptionDialog(final Throwable exception) { - final DialogPane dialogPane = getDialogPane(); - - setTitle(getString("exception.dlg.title")); //$NON-NLS-1$ - dialogPane.setHeaderText(getString("exception.dlg.header")); //$NON-NLS-1$ - dialogPane.getStyleClass().add("exception-dialog"); //$NON-NLS-1$ - dialogPane.getStylesheets().add(ProgressDialog.class.getResource("dialogs.css").toExternalForm()); //$NON-NLS-1$ - dialogPane.getButtonTypes().addAll(ButtonType.OK); - - // --- content - String contentText = getContentText(); - dialogPane.setContent(new Label(contentText != null && ! contentText.isEmpty() ? - contentText : exception.getMessage())); - - // --- expandable content - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - exception.printStackTrace(pw); - String exceptionText = sw.toString(); - - Label label = new Label( localize(getString("exception.dlg.label"))); //$NON-NLS-1$ - - TextArea textArea = new TextArea(exceptionText); - textArea.setEditable(false); - textArea.setWrapText(true); - - textArea.setMaxWidth(Double.MAX_VALUE); - textArea.setMaxHeight(Double.MAX_VALUE); - GridPane.setVgrow(textArea, Priority.ALWAYS); - GridPane.setHgrow(textArea, Priority.ALWAYS); - - GridPane root = new GridPane(); - root.setMaxWidth(Double.MAX_VALUE); - root.add(label, 0, 0); - root.add(textArea, 0, 1); - - - dialogPane.setExpandableContent(root); - } -} diff --git a/src/org/controlsfx/dialog/FontSelectorDialog.java b/src/org/controlsfx/dialog/FontSelectorDialog.java deleted file mode 100644 index f725ae1..0000000 --- a/src/org/controlsfx/dialog/FontSelectorDialog.java +++ /dev/null @@ -1,367 +0,0 @@ -/** - * Copyright (c) 2014 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.dialog; - -import static impl.org.controlsfx.i18n.Localization.asKey; -import static impl.org.controlsfx.i18n.Localization.localize; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.function.Predicate; - -import javafx.application.Platform; -import javafx.beans.binding.DoubleBinding; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.collections.FXCollections; -import javafx.collections.transformation.FilteredList; -import javafx.geometry.Pos; -import javafx.scene.control.ButtonType; -import javafx.scene.control.Dialog; -import javafx.scene.control.DialogPane; -import javafx.scene.control.Label; -import javafx.scene.control.ListCell; -import javafx.scene.control.ListView; -import javafx.scene.layout.ColumnConstraints; -import javafx.scene.layout.GridPane; -import javafx.scene.layout.Priority; -import javafx.scene.layout.RowConstraints; -import javafx.scene.layout.StackPane; -import javafx.scene.shape.Rectangle; -import javafx.scene.text.Font; -import javafx.scene.text.FontPosture; -import javafx.scene.text.FontWeight; -import javafx.scene.text.Text; -import javafx.util.Callback; - -public class FontSelectorDialog extends Dialog<Font> { - - private FontPanel fontPanel; - - public FontSelectorDialog(Font defaultFont) { - fontPanel = new FontPanel(); - fontPanel.setFont(defaultFont); - - setResultConverter(dialogButton -> dialogButton == ButtonType.OK ? fontPanel.getFont() : null); - - final DialogPane dialogPane = getDialogPane(); - - setTitle(localize(asKey("font.dlg.title"))); //$NON-NLS-1$ - dialogPane.setHeaderText(localize(asKey("font.dlg.header"))); //$NON-NLS-1$ - dialogPane.getStyleClass().add("font-selector-dialog"); //$NON-NLS-1$ - dialogPane.getStylesheets().add(FontSelectorDialog.class.getResource("dialogs.css").toExternalForm()); //$NON-NLS-1$ - dialogPane.getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL); - dialogPane.setContent(fontPanel); - } - - - - /************************************************************************** - * - * Support classes - * - **************************************************************************/ - - /** - * Font style as combination of font weight and font posture. - * Weight does not have to be there (represented by null) - * Posture is required, null posture is converted to REGULAR - */ - private static class FontStyle implements Comparable<FontStyle> { - - private FontPosture posture; - private FontWeight weight; - - public FontStyle( FontWeight weight, FontPosture posture ) { - this.posture = posture == null? FontPosture.REGULAR: posture; - this.weight = weight; - } - - public FontStyle() { - this( null, null); - } - - public FontStyle(String styles) { - this(); - String[] fontStyles = (styles == null? "": styles.trim().toUpperCase()).split(" "); //$NON-NLS-1$ //$NON-NLS-2$ - for ( String style: fontStyles) { - FontWeight w = FontWeight.findByName(style); - if ( w != null ) { - weight = w; - } else { - FontPosture p = FontPosture.findByName(style); - if ( p != null ) posture = p; - } - } - } - - public FontStyle(Font font) { - this( font.getStyle()); - } - - public FontPosture getPosture() { - return posture; - } - - public FontWeight getWeight() { - return weight; - } - - - @Override public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((posture == null) ? 0 : posture.hashCode()); - result = prime * result + ((weight == null) ? 0 : weight.hashCode()); - return result; - } - - @Override public boolean equals(Object that) { - if (this == that) - return true; - if (that == null) - return false; - if (getClass() != that.getClass()) - return false; - FontStyle other = (FontStyle) that; - if (posture != other.posture) - return false; - if (weight != other.weight) - return false; - return true; - } - - private static String makePretty(Object o) { - String s = o == null? "": o.toString(); //$NON-NLS-1$ - if ( !s.isEmpty()) { - s = s.replace("_", " "); //$NON-NLS-1$ //$NON-NLS-2$ - s = s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase(); - } - return s; - } - - @Override public String toString() { - return String.format("%s %s", makePretty(weight), makePretty(posture) ).trim(); //$NON-NLS-1$ - } - - private <T extends Enum<T>> int compareEnums( T e1, T e2) { - if ( e1 == e2 ) return 0; - if ( e1 == null ) return -1; - if ( e2 == null ) return 1; - return e1.compareTo(e2); - } - - @Override public int compareTo(FontStyle fs) { - int result = compareEnums(weight,fs.weight); - return ( result != 0 )? result: compareEnums(posture,fs.posture); - } - - } - - - private static class FontPanel extends GridPane { - private static final double HGAP = 10; - private static final double VGAP = 5; - - private static final Predicate<Object> MATCH_ALL = new Predicate<Object>() { - @Override public boolean test(Object t) { - return true; - } - }; - - private static final Double[] fontSizes = new Double[] {8d,9d,11d,12d,14d,16d,18d,20d,22d,24d,26d,28d,36d,48d,72d}; - - private static List<FontStyle> getFontStyles( String fontFamily ) { - Set<FontStyle> set = new HashSet<>(); - for (String f : Font.getFontNames(fontFamily)) { - set.add(new FontStyle(f.replace(fontFamily, ""))); //$NON-NLS-1$ - } - - List<FontStyle> result = new ArrayList<>(set); - Collections.sort(result); - return result; - - } - - - private final FilteredList<String> filteredFontList = new FilteredList<>(FXCollections.observableArrayList(Font.getFamilies()), MATCH_ALL); - private final FilteredList<FontStyle> filteredStyleList = new FilteredList<>(FXCollections.<FontStyle>observableArrayList(), MATCH_ALL); - private final FilteredList<Double> filteredSizeList = new FilteredList<>(FXCollections.observableArrayList(fontSizes), MATCH_ALL); - - private final ListView<String> fontListView = new ListView<>(filteredFontList); - private final ListView<FontStyle> styleListView = new ListView<>(filteredStyleList); - private final ListView<Double> sizeListView = new ListView<>(filteredSizeList); - private final Text sample = new Text(localize(asKey("font.dlg.sample.text"))); //$NON-NLS-1$ - - public FontPanel() { - setHgap(HGAP); - setVgap(VGAP); - setPrefSize(500, 300); - setMinSize(500, 300); - - ColumnConstraints c0 = new ColumnConstraints(); - c0.setPercentWidth(60); - ColumnConstraints c1 = new ColumnConstraints(); - c1.setPercentWidth(25); - ColumnConstraints c2 = new ColumnConstraints(); - c2.setPercentWidth(15); - getColumnConstraints().addAll(c0, c1, c2); - - RowConstraints r0 = new RowConstraints(); - r0.setVgrow(Priority.NEVER); - RowConstraints r1 = new RowConstraints(); - r1.setVgrow(Priority.NEVER); - RowConstraints r2 = new RowConstraints(); - r2.setFillHeight(true); - r2.setVgrow(Priority.NEVER); - RowConstraints r3 = new RowConstraints(); - r3.setPrefHeight(250); - r3.setVgrow(Priority.NEVER); - getRowConstraints().addAll(r0, r1, r2, r3); - - // layout hello.dialog - add(new Label(localize(asKey("font.dlg.font.label"))), 0, 0); //$NON-NLS-1$ - // fontSearch.setMinHeight(Control.USE_PREF_SIZE); - // add( fontSearch, 0, 1); - add(fontListView, 0, 1); - fontListView.setCellFactory(new Callback<ListView<String>, ListCell<String>>() { - @Override public ListCell<String> call(ListView<String> listview) { - return new ListCell<String>() { - @Override protected void updateItem(String family, boolean empty) { - super.updateItem(family, empty); - - if (! empty) { - setFont(Font.font(family)); - setText(family); - } else { - setText(null); - } - } - }; - } - }); - - - ChangeListener<Object> sampleRefreshListener = new ChangeListener<Object>() { - @Override public void changed(ObservableValue<? extends Object> arg0, Object arg1, Object arg2) { - refreshSample(); - } - }; - - fontListView.selectionModelProperty().get().selectedItemProperty().addListener( new ChangeListener<String>() { - - @Override public void changed(ObservableValue<? extends String> arg0, String arg1, String arg2) { - String fontFamily = listSelection(fontListView); - styleListView.setItems(FXCollections.<FontStyle>observableArrayList(getFontStyles(fontFamily))); - refreshSample(); - }}); - - add( new Label(localize(asKey("font.dlg.style.label"))), 1, 0); //$NON-NLS-1$ - // postureSearch.setMinHeight(Control.USE_PREF_SIZE); - // add( postureSearch, 1, 1); - add(styleListView, 1, 1); - styleListView.selectionModelProperty().get().selectedItemProperty().addListener(sampleRefreshListener); - - add( new Label(localize(asKey("font.dlg.size.label"))), 2, 0); //$NON-NLS-1$ - // sizeSearch.setMinHeight(Control.USE_PREF_SIZE); - // add( sizeSearch, 2, 1); - add(sizeListView, 2, 1); - sizeListView.selectionModelProperty().get().selectedItemProperty().addListener(sampleRefreshListener); - - final double height = 45; - final DoubleBinding sampleWidth = new DoubleBinding() { - { - bind(fontListView.widthProperty(), styleListView.widthProperty(), sizeListView.widthProperty()); - } - - @Override protected double computeValue() { - return fontListView.getWidth() + styleListView.getWidth() + sizeListView.getWidth() + 3 * HGAP; - } - }; - StackPane sampleStack = new StackPane(sample); - sampleStack.setAlignment(Pos.CENTER_LEFT); - sampleStack.setMinHeight(height); - sampleStack.setPrefHeight(height); - sampleStack.setMaxHeight(height); - sampleStack.prefWidthProperty().bind(sampleWidth); - Rectangle clip = new Rectangle(0, height); - clip.widthProperty().bind(sampleWidth); - sampleStack.setClip(clip); - add(sampleStack, 0, 3, 1, 3); - } - - public void setFont(final Font font) { - final Font _font = font == null ? Font.getDefault() : font; - if (_font != null) { - selectInList( fontListView, _font.getFamily() ); - selectInList( styleListView, new FontStyle(_font)); - selectInList( sizeListView, _font.getSize() ); - } - } - - public Font getFont() { - try { - FontStyle style = listSelection(styleListView); - if ( style == null ) { - return Font.font( - listSelection(fontListView), - listSelection(sizeListView)); - - } else { - return Font.font( - listSelection(fontListView), - style.getWeight(), - style.getPosture(), - listSelection(sizeListView)); - } - - } catch( Throwable ex ) { - return null; - } - } - - private void refreshSample() { - sample.setFont(getFont()); - } - - private <T> void selectInList( final ListView<T> listView, final T selection ) { - Platform.runLater(new Runnable() { - @Override public void run() { - listView.scrollTo(selection); - listView.getSelectionModel().select(selection); - } - }); - } - - private <T> T listSelection(final ListView<T> listView) { - return listView.selectionModelProperty().get().getSelectedItem(); - } - } -} diff --git a/src/org/controlsfx/dialog/LoginDialog.java b/src/org/controlsfx/dialog/LoginDialog.java deleted file mode 100644 index 018f748..0000000 --- a/src/org/controlsfx/dialog/LoginDialog.java +++ /dev/null @@ -1,152 +0,0 @@ -/** - * Copyright (c) 2014, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.dialog; - -import static impl.org.controlsfx.i18n.Localization.getString; -import javafx.application.Platform; -import javafx.scene.control.Button; -import javafx.scene.control.ButtonBar.ButtonData; -import javafx.scene.control.ButtonType; -import javafx.scene.control.Dialog; -import javafx.scene.control.DialogPane; -import javafx.scene.control.Label; -import javafx.scene.image.ImageView; -import javafx.scene.layout.VBox; -import javafx.util.Callback; -import javafx.util.Pair; - -import org.controlsfx.control.textfield.CustomPasswordField; -import org.controlsfx.control.textfield.CustomTextField; -import org.controlsfx.control.textfield.TextFields; -import org.controlsfx.validation.ValidationSupport; -import org.controlsfx.validation.Validator; - -public class LoginDialog extends Dialog<Pair<String,String>> { - - private final ButtonType loginButtonType; - private final CustomTextField txUserName; - private final CustomPasswordField txPassword; - - @SuppressWarnings("deprecation") - public LoginDialog(final Pair<String,String> initialUserInfo, final Callback<Pair<String,String>, Void> authenticator) { - final DialogPane dialogPane = getDialogPane(); - - setTitle(getString("login.dlg.title")); //$NON-NLS-1$ - dialogPane.setHeaderText(getString("login.dlg.header")); //$NON-NLS-1$ - dialogPane.getStyleClass().add("login-dialog"); //$NON-NLS-1$ - dialogPane.getStylesheets().add(LoginDialog.class.getResource("dialogs.css").toExternalForm()); //$NON-NLS-1$ - dialogPane.getButtonTypes().addAll(ButtonType.CANCEL); - - - - - - txUserName = (CustomTextField) TextFields.createClearableTextField(); - - txUserName.setLeft(new ImageView(LoginDialog.class.getResource("/org/controlsfx/dialog/user.png").toExternalForm())); //$NON-NLS-1$ - - txPassword = (CustomPasswordField) TextFields.createClearablePasswordField(); - txPassword.setLeft(new ImageView(LoginDialog.class.getResource("/org/controlsfx/dialog/lock.png").toExternalForm())); //$NON-NLS-1$ - - Label lbMessage= new Label(""); //$NON-NLS-1$ - lbMessage.getStyleClass().addAll("message-banner"); //$NON-NLS-1$ - lbMessage.setVisible(false); - lbMessage.setManaged(false); - - final VBox content = new VBox(10); - content.getChildren().add(lbMessage); - content.getChildren().add(txUserName); - content.getChildren().add(txPassword); - - dialogPane.setContent(content); - - loginButtonType = new javafx.scene.control.ButtonType(getString("login.dlg.login.button"), ButtonData.OK_DONE); //$NON-NLS-1$ - dialogPane.getButtonTypes().addAll(loginButtonType); - Button loginButton = (Button) dialogPane.lookupButton(loginButtonType); - loginButton.setOnAction(actionEvent -> { - try { - if (authenticator != null ) { - authenticator.call(new Pair<>(txUserName.getText(), txPassword.getText())); - } - lbMessage.setVisible(false); - lbMessage.setManaged(false); - hide(); -// dlg.setResult(this); - } catch( Throwable ex ) { - lbMessage.setVisible(true); - lbMessage.setManaged(true); - lbMessage.setText(ex.getMessage()); -// sizeToScene(); -// dlg.shake(); - ex.printStackTrace(); - } - }); - -// final Dialog dlg = buildDialog(Type.LOGIN); -// dlg.setContent(content); - -// dlg.setResizable(false); -// dlg.setIconifiable(false); -// if ( dlg.getGraphic() == null ) { -// dlg.setGraphic( new ImageView( DialogResources.getImage("login.icon"))); -// } -// dlg.getActions().setAll(actionLogin, ACTION_CANCEL); - String userNameCation = getString("login.dlg.user.caption"); //$NON-NLS-1$ - String passwordCaption = getString("login.dlg.pswd.caption"); //$NON-NLS-1$ - txUserName.setPromptText(userNameCation); - txUserName.setText(initialUserInfo == null ? "" : initialUserInfo.getKey()); //$NON-NLS-1$ - txPassword.setPromptText(passwordCaption); - txPassword.setText(new String(initialUserInfo == null ? "" : initialUserInfo.getValue())); //$NON-NLS-1$ - - ValidationSupport validationSupport = new ValidationSupport(); - Platform.runLater( () -> { - String requiredFormat = "'%s' is required"; //$NON-NLS-1$ - validationSupport.registerValidator(txUserName, Validator.createEmptyValidator( String.format( requiredFormat, userNameCation ))); - validationSupport.registerValidator(txPassword, Validator.createEmptyValidator(String.format( requiredFormat, passwordCaption ))); -// loginButton.disabledProperty().bind(validationSupport.invalidProperty()); - txUserName.requestFocus(); - } ); - - - setResultConverter(dialogButton -> dialogButton == loginButtonType ? - new Pair<>(txUserName.getText(), txPassword.getText()) : null); - -// return Optional.ofNullable( -// dlg.show() == actionLogin? -// new Pair<String,String>(txUserName.getText(), txPassword.getText()): -// null); - } - - - - /************************************************************************** - * - * Support classes - * - **************************************************************************/ - -} diff --git a/src/org/controlsfx/dialog/ProgressDialog.java b/src/org/controlsfx/dialog/ProgressDialog.java deleted file mode 100644 index f57707e..0000000 --- a/src/org/controlsfx/dialog/ProgressDialog.java +++ /dev/null @@ -1,215 +0,0 @@ -/** - * Copyright (c) 2014, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.dialog; - -import static impl.org.controlsfx.i18n.Localization.getString; -import javafx.application.Platform; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.concurrent.Worker; -import javafx.concurrent.Worker.State; -import javafx.geometry.Insets; -import javafx.scene.control.Dialog; -import javafx.scene.control.DialogPane; -import javafx.scene.control.Label; -import javafx.scene.control.ProgressBar; -import javafx.scene.layout.Region; -import javafx.scene.layout.VBox; - -public class ProgressDialog extends Dialog<Void> { - - - public ProgressDialog(final Worker<?> worker) { - if (worker != null - && (worker.getState() == State.CANCELLED - || worker.getState() == State.FAILED - || worker.getState() == State.SUCCEEDED)) { - return; - } - setResultConverter(dialogButton -> null); - - final DialogPane dialogPane = getDialogPane(); - - setTitle(getString("progress.dlg.title")); //$NON-NLS-1$ - dialogPane.setHeaderText(getString("progress.dlg.header")); //$NON-NLS-1$ - dialogPane.getStyleClass().add("progress-dialog"); //$NON-NLS-1$ - dialogPane.getStylesheets().add(ProgressDialog.class.getResource("dialogs.css").toExternalForm()); //$NON-NLS-1$ - - final Label progressMessage = new Label(); - progressMessage.textProperty().bind(worker.messageProperty()); - - final WorkerProgressPane content = new WorkerProgressPane(this); - content.setMaxWidth(Double.MAX_VALUE); - content.setWorker(worker); - - VBox vbox = new VBox(10, progressMessage, content); - vbox.setMaxWidth(Double.MAX_VALUE); - vbox.setPrefSize(300, 100); - /** - * The content Text cannot be set before the constructor and since we - * set a Content Node, the contentText will not be shown. If we want to - * let the user display a content text, we must recreate it. - */ - Label contentText = new Label(); - contentText.setWrapText(true); - vbox.getChildren().add(0, contentText); - contentText.textProperty().bind(dialogPane.contentTextProperty()); - dialogPane.setContent(vbox); - } - - - - /************************************************************************** - * - * Support classes - * - **************************************************************************/ - - /** - * The WorkerProgressPane takes a {@link Dialog} and a {@link Worker} - * and links them together so the dialog is shown or hidden depending - * on the state of the worker. The WorkerProgressPane also includes - * a progress bar that is automatically bound to the progress property - * of the worker. The way in which the WorkerProgressPane shows and - * hides its worker's dialog is consistent with the expected behavior - * for {@link #showWorkerProgress(Worker)}. - */ - private static class WorkerProgressPane extends Region { - private Worker<?> worker; - - private boolean dialogVisible = false; - private boolean cancelDialogShow = false; - - private ChangeListener<Worker.State> stateListener = new ChangeListener<Worker.State>() { - @Override public void changed(ObservableValue<? extends State> observable, State old, State value) { - switch(value) { - case CANCELLED: - case FAILED: - case SUCCEEDED: - if(!dialogVisible) { - cancelDialogShow = true; - end(); - } else if(old == State.SCHEDULED || old == State.RUNNING) { - end(); - } - break; - case SCHEDULED: - begin(); - break; - default: //no-op - } - } - }; - - public final void setWorker(final Worker<?> newWorker) { - if (newWorker != worker) { - if (worker != null) { - worker.stateProperty().removeListener(stateListener); - end(); - } - - worker = newWorker; - - if (newWorker != null) { - newWorker.stateProperty().addListener(stateListener); - if (newWorker.getState() == Worker.State.RUNNING || newWorker.getState() == Worker.State.SCHEDULED) { - // It is already running - begin(); - } - } - } - } - - // If the progress indicator changes, then we need to re-initialize - // If the worker changes, we need to re-initialize - - private final ProgressDialog dialog; - private final ProgressBar progressBar; - - public WorkerProgressPane(ProgressDialog dialog) { - this.dialog = dialog; - - this.progressBar = new ProgressBar(); - progressBar.setMaxWidth(Double.MAX_VALUE); - getChildren().add(progressBar); - - if (worker != null) { - progressBar.progressProperty().bind(worker.progressProperty()); - } - } - - private void begin() { - // Platform.runLater needs to be used to show the dialog because - // the call begin() is going to be occurring when the worker is - // notifying state listeners about changes. If Platform.runLater - // is not used, the call to show() will cause the worker to get - // blocked during notification and it will prevent the worker - // from performing any additional notification for state changes. - // - // Sine the dialog is hidden as a result of a change in worker - // state, calling show() without wrapping it in Platform.runLater - // will cause the progress dialog to run forever when the dialog - // is attached to workers that start out with a state of READY. - // - // This also creates a case where the worker's state can change - // to finished before the dialog is shown, resulting in an - // an attempt to hide the dialog before it is shown. It's - // necessary to track whether or not this occurs, so flags are - // set to indicate if the dialog is visible and if if the call - // to show should still be allowed. - cancelDialogShow = false; - - Platform.runLater(() -> { - if(!cancelDialogShow) { - progressBar.progressProperty().bind(worker.progressProperty()); - dialogVisible = true; - dialog.show(); - } - }); - } - - private void end() { - progressBar.progressProperty().unbind(); - dialogVisible = false; - DialogUtils.forcefullyHideDialog(dialog); - } - - @Override protected void layoutChildren() { - if (progressBar != null) { - Insets insets = getInsets(); - double w = getWidth() - insets.getLeft() - insets.getRight(); - double h = getHeight() - insets.getTop() - insets.getBottom(); - - double prefH = progressBar.prefHeight(-1); - double x = insets.getLeft() + (w - w) / 2.0; - double y = insets.getTop() + (h - prefH) / 2.0; - - progressBar.resizeRelocate(x, y, w, prefH); - } - } - } -} diff --git a/src/org/controlsfx/dialog/Wizard.java b/src/org/controlsfx/dialog/Wizard.java deleted file mode 100644 index ee6c080..0000000 --- a/src/org/controlsfx/dialog/Wizard.java +++ /dev/null @@ -1,737 +0,0 @@ -/** - * Copyright (c) 2014, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.dialog; - -import static impl.org.controlsfx.i18n.Localization.asKey; -import static impl.org.controlsfx.i18n.Localization.localize; -import impl.org.controlsfx.ImplUtils; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Optional; -import java.util.Stack; -import java.util.function.BooleanSupplier; - -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.property.StringProperty; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.collections.ObservableMap; -import javafx.event.ActionEvent; -import javafx.event.EventHandler; -import javafx.geometry.Rectangle2D; -import javafx.scene.Node; -import javafx.scene.control.Button; -import javafx.scene.control.ButtonBar.ButtonData; -import javafx.scene.control.ButtonType; -import javafx.scene.control.Dialog; -import javafx.scene.control.DialogPane; -import javafx.scene.layout.Pane; -import javafx.stage.Screen; -import javafx.stage.Window; - -import org.controlsfx.tools.ValueExtractor; -import org.controlsfx.validation.ValidationSupport; - -/** - * <p>The API for creating multi-page Wizards, based on JavaFX {@link Dialog} API.<br> - * Wizard can be setup in following few steps:</p> - * <ul> - * <li>Design wizard pages by inheriting them from {@link WizardPane}</li> - * <li>Define wizard flow by implementing {@link Wizard.Flow}</li> - * <li>Create and instance of the Wizard and assign flow to it</li> - * <li>Execute the wizard using showAndWait method</li> - * <li>Values can be extracted from settings map by calling getSettings - * </ul> - * <p>For simple, linear wizards, the {@link LinearFlow} can be used. - * It is a flow based on a collection of wizard pages. Here is the example:</p> - * - * <pre>{@code // Create pages. Here for simplicity we just create and instance of WizardPane. - * WizardPane page1 = new WizardPane(); - * WizardPane page2 = new WizardPane(); - * WizardPane page2 = new WizardPane(); - * - * // create wizard - * Wizard wizard = new Wizard(); - * - * // create and assign the flow - * wizard.setFlow(new LinearFlow(page1, page2, page3)); - * - * // show wizard and wait for response - * wizard.showAndWait().ifPresent(result -> { - * if (result == ButtonType.FINISH) { - * System.out.println("Wizard finished, settings: " + wizard.getSettings()); - * } - * });}</pre> - * - * <p>For more complex wizard flows we suggest to create a custom ones, describing page traversal logic. - * Here is a simplified example: </p> - * - * <pre>{@code Wizard.Flow branchingFlow = new Wizard.Flow() { - * public Optional<WizardPane> advance(WizardPane currentPage) { - * return Optional.of(getNext(currentPage)); - * } - * - * public boolean canAdvance(WizardPane currentPage) { - * return currentPage != page3; - * } - * - * private WizardPane getNext(WizardPane currentPage) { - * if ( currentPage == null ) { - * return page1; - * } else if ( currentPage == page1) { - * // skipNextPage() does not exist - this just represents that you - * // can add a conditional statement here to change the page. - * return page1.skipNextPage()? page3: page2; - * } else { - * return page3; - * } - * } - * };}</pre> - */ -public class Wizard { - - - /************************************************************************** - * - * Private fields - * - **************************************************************************/ - - private Dialog<ButtonType> dialog; - - private final ObservableMap<String, Object> settings = FXCollections.observableHashMap(); - - private final Stack<WizardPane> pageHistory = new Stack<>(); - - private Optional<WizardPane> currentPage = Optional.empty(); - - private final BooleanProperty invalidProperty = new SimpleBooleanProperty(false); - - // Read settings activated by default for backward compatibility - private final BooleanProperty readSettingsProperty = new SimpleBooleanProperty(true); - - private final ButtonType BUTTON_PREVIOUS = new ButtonType(localize(asKey("wizard.previous.button")), ButtonData.BACK_PREVIOUS); //$NON-NLS-1$ - private final EventHandler<ActionEvent> BUTTON_PREVIOUS_ACTION_HANDLER = actionEvent -> { - actionEvent.consume(); - currentPage = Optional.ofNullable( pageHistory.isEmpty()? null: pageHistory.pop() ); - updatePage(dialog,false); - }; - - private final ButtonType BUTTON_NEXT = new ButtonType(localize(asKey("wizard.next.button")), ButtonData.NEXT_FORWARD); //$NON-NLS-1$ - private final EventHandler<ActionEvent> BUTTON_NEXT_ACTION_HANDLER = actionEvent -> { - actionEvent.consume(); - currentPage.ifPresent(page->pageHistory.push(page)); - currentPage = getFlow().advance(currentPage.orElse(null)); - updatePage(dialog,true); - }; - - private final StringProperty titleProperty = new SimpleStringProperty(); - - - /************************************************************************** - * - * Constructors - * - **************************************************************************/ - - /** - * Creates an instance of the wizard without an owner. - */ - public Wizard() { - this(null); - } - - /** - * Creates an instance of the wizard with the given owner. - * @param owner The object from which the owner window is deduced (typically - * this is a Node, but it may also be a Scene or a Stage). - */ - public Wizard(Object owner) { - this(owner, ""); //$NON-NLS-1$ - } - - /** - * Creates an instance of the wizard with the given owner and title. - * - * @param owner The object from which the owner window is deduced (typically - * this is a Node, but it may also be a Scene or a Stage). - * @param title The wizard title. - */ - public Wizard(Object owner, String title) { - - invalidProperty.addListener( (o, ov, nv) -> validateActionState()); - - dialog = new Dialog<>(); - dialog.titleProperty().bind(this.titleProperty); - setTitle(title); - - Window window = null; - if ( owner instanceof Window) { - window = (Window)owner; - } else if ( owner instanceof Node ) { - window = ((Node)owner).getScene().getWindow(); - } - - dialog.initOwner(window); - } - - - - /************************************************************************** - * - * Public API - * - **************************************************************************/ - -// /** -// * Shows the wizard but does not wait for a user response (in other words, -// * this brings up a non-blocking dialog). Users of this API must either -// * poll the {@link #resultProperty() result property}, or else add a listener -// * to the result property to be informed of when it is set. -// */ -// public final void show() { -// dialog.show(); -// } - - /** - * Shows the wizard and waits for the user response (in other words, brings - * up a blocking dialog, with the returned value the users input). - * - * @return An {@link Optional} that contains the result. - */ - public final Optional<ButtonType> showAndWait() { - return dialog.showAndWait(); - } - - /** - * @return {@link Dialog#resultProperty()} of the {@link Dialog} representing this {@link Wizard}. - */ - public final ObjectProperty<ButtonType> resultProperty() { - return dialog.resultProperty(); - } - - /** - * The settings map is the place where all data from pages is kept once the - * user moves on from the page, assuming there is a {@link ValueExtractor} - * that is capable of extracting a value out of the various fields on the page. - */ - public final ObservableMap<String, Object> getSettings() { - return settings; - } - - - - /************************************************************************** - * - * Properties - * - **************************************************************************/ - - // --- title - - /** - * Return the titleProperty of the wizard. - */ - public final StringProperty titleProperty() { - return titleProperty; - } - - /** - * Return the title of the wizard. - */ - public final String getTitle() { - return titleProperty.get(); - } - - /** - * Change the Title of the wizard. - * @param title - */ - public final void setTitle( String title ) { - titleProperty.set(title); - } - - // --- flow - /** - * The {@link Flow} property represents the flow of pages in the wizard. - */ - private ObjectProperty<Flow> flow = new SimpleObjectProperty<Flow>(new LinearFlow()) { - @Override protected void invalidated() { - updatePage(dialog,false); - } - - @Override public void set(Flow flow) { - super.set(flow); - pageHistory.clear(); - if ( flow != null ) { - currentPage = flow.advance(currentPage.orElse(null)); - updatePage(dialog,true); - } - }; - }; - - public final ObjectProperty<Flow> flowProperty() { - return flow; - } - - /** - * Returns the currently set {@link Flow}, which represents the flow of - * pages in the wizard. - */ - public final Flow getFlow() { - return flow.get(); - } - - /** - * Sets the {@link Flow}, which represents the flow of pages in the wizard. - */ - public final void setFlow(Flow flow) { - this.flow.set(flow); - } - - - // --- Properties - private static final Object USER_DATA_KEY = new Object(); - - // A map containing a set of properties for this Wizard - private ObservableMap<Object, Object> properties; - - /** - * Returns an observable map of properties on this Wizard for use primarily - * by application developers - not to be confused with the - * {@link #getSettings()} map that represents the values entered by the user - * into the wizard. - * - * @return an observable map of properties on this Wizard for use primarily - * by application developers - */ - public final ObservableMap<Object, Object> getProperties() { - if (properties == null) { - properties = FXCollections.observableMap(new HashMap<>()); - } - return properties; - } - - /** - * Tests if this Wizard has properties. - * @return true if this Wizard has properties. - */ - public boolean hasProperties() { - return properties != null && !properties.isEmpty(); - } - - - // --- UserData - /** - * Convenience method for setting a single Object property that can be - * retrieved at a later date. This is functionally equivalent to calling - * the getProperties().put(Object key, Object value) method. This can later - * be retrieved by calling {@link #getUserData()}. - * - * @param value The value to be stored - this can later be retrieved by calling - * {@link #getUserData()}. - */ - public void setUserData(Object value) { - getProperties().put(USER_DATA_KEY, value); - } - - /** - * Returns a previously set Object property, or null if no such property - * has been set using the {@link #setUserData(Object)} method. - * - * @return The Object that was previously set, or null if no property - * has been set or if null was set. - */ - public Object getUserData() { - return getProperties().get(USER_DATA_KEY); - } - - /** - * Sets the value of the property {@code invalid}. - * - * @param invalid The new validation state - * {@link #invalidProperty() } - */ - public final void setInvalid(boolean invalid) { - invalidProperty.set(invalid); - } - - /** - * Gets the value of the property {@code invalid}. - * - * @return The validation state - * @see #invalidProperty() - */ - public final boolean isInvalid() { - return invalidProperty.get(); - } - - /** - * Property for overriding the individual validation state of this {@link Wizard}. - * Setting {@code invalid} to true will disable the next/finish Button and the user - * will not be able to advance to the next page of the {@link Wizard}. Setting - * {@code invalid} to false will enable the next/finish Button. <br> - * <br> - * For example you can use the {@link ValidationSupport#invalidProperty()} of a - * page and bind it to the {@code invalid} property: <br> - * {@code - * wizard.invalidProperty().bind(page.validationSupport.invalidProperty()); - * } - * - * @return The validation state property - */ - public final BooleanProperty invalidProperty() { - return invalidProperty; - } - - /** - * Sets the value of the property {@code readSettings}. - * - * @param readSettings The new read-settings state - * @see #readSettingsProperty() - */ - public final void setReadSettings(boolean readSettings) { - readSettingsProperty.set(readSettings); - } - - /** - * Gets the value of the property {@code readSettings}. - * - * @return The read-settings state - * @see #readSettingsProperty() - */ - public final boolean isReadSettings() { - return readSettingsProperty.get(); - } - - /** - * Property for overriding the individual read-settings state of this {@link Wizard}. - * Setting {@code readSettings} to true will enable the value extraction for this - * {@link Wizard}. Setting {@code readSettings} to false will disable the value - * extraction for this {@link Wizard}. - * - * @return The readSettings state property - */ - public final BooleanProperty readSettingsProperty() { - return readSettingsProperty; - } - - - - /************************************************************************** - * - * Private implementation - * - **************************************************************************/ - - private void updatePage(Dialog<ButtonType> dialog, boolean advancing) { - Flow flow = getFlow(); - if (flow == null) { - return; - } - - Optional<WizardPane> prevPage = Optional.ofNullable( pageHistory.isEmpty()? null: pageHistory.peek()); - prevPage.ifPresent( page -> { - // if we are going forward in the wizard, we read in the settings - // from the page and store them in the settings map. - // If we are going backwards, we do nothing - // This is only performed if readSettings is true. - if (advancing && isReadSettings()) { - readSettings(page); - } - - // give the previous wizard page a chance to update the pages list - // based on the settings it has received - page.onExitingPage(this); - }); - - currentPage.ifPresent(currentPage -> { - // put in default actions - List<ButtonType> buttons = currentPage.getButtonTypes(); - if (! buttons.contains(BUTTON_PREVIOUS)) { - buttons.add(BUTTON_PREVIOUS); - Button button = (Button)currentPage.lookupButton(BUTTON_PREVIOUS); - button.addEventFilter(ActionEvent.ACTION, BUTTON_PREVIOUS_ACTION_HANDLER); - } - if (! buttons.contains(BUTTON_NEXT)) { - buttons.add(BUTTON_NEXT); - Button button = (Button)currentPage.lookupButton(BUTTON_NEXT); - button.addEventFilter(ActionEvent.ACTION, BUTTON_NEXT_ACTION_HANDLER); - } - if (! buttons.contains(ButtonType.FINISH)) buttons.add(ButtonType.FINISH); - if (! buttons.contains(ButtonType.CANCEL)) buttons.add(ButtonType.CANCEL); - - // then give user a chance to modify the default actions - currentPage.onEnteringPage(this); - - // Remove from DecorationPane which has been created by e.g. validation - if (currentPage.getParent() != null && currentPage.getParent() instanceof Pane) { - Pane parentOfCurrentPage = (Pane) currentPage.getParent(); - parentOfCurrentPage.getChildren().remove(currentPage); - } - - // Get current position and size - double previousX = dialog.getX(); - double previousY = dialog.getY(); - double previousWidth = dialog.getWidth(); - double previousHeight = dialog.getHeight(); - // and then switch to the new pane - dialog.setDialogPane(currentPage); - // Resize Wizard to new page - Window wizard = currentPage.getScene().getWindow(); - wizard.sizeToScene(); - // Center resized Wizard to previous position - - - if (!Double.isNaN(previousX) && !Double.isNaN(previousY)) { - double newWidth = dialog.getWidth(); - double newHeight = dialog.getHeight(); - int newX = (int) (previousX + (previousWidth / 2.0) - (newWidth / 2.0)); - int newY = (int) (previousY + (previousHeight / 2.0) - (newHeight / 2.0)); - - ObservableList<Screen> screens = Screen.getScreensForRectangle(previousX, previousY, 1, 1); - Screen screen = screens.isEmpty() ? Screen.getPrimary() : screens.get(0); - Rectangle2D scrBounds = screen.getBounds(); - int minX = (int)Math.round(scrBounds.getMinX()); - int maxX = (int)Math.round(scrBounds.getMaxX()); - int minY = (int)Math.round(scrBounds.getMinY()); - int maxY = (int)Math.round(scrBounds.getMaxY()); - if(newX + newWidth > maxX) { - newX = maxX - (int)Math.round(newWidth); - } - if(newY + newHeight > maxY) { - newY = maxY - (int)Math.round(newHeight); - } - if(newX < minX) { - newX = minX; - } - if(newY < minY) { - newY = minY; - } - - dialog.setX(newX); - dialog.setY(newY); - } - }); - - validateActionState(); - } - - private void validateActionState() { - final List<ButtonType> currentPaneButtons = dialog.getDialogPane().getButtonTypes(); - - if (getFlow().canAdvance(currentPage.orElse(null))) { - currentPaneButtons.remove(ButtonType.FINISH); - } else { - currentPaneButtons.remove(BUTTON_NEXT); - } - - validateButton( BUTTON_PREVIOUS, () -> pageHistory.isEmpty()); - validateButton( BUTTON_NEXT, () -> invalidProperty.get()); - validateButton( ButtonType.FINISH, () -> invalidProperty.get()); - - } - - // Functional design allows to delay condition evaluation until it is actually needed - private void validateButton( ButtonType buttonType, BooleanSupplier condition) { - Button btn = (Button)dialog.getDialogPane().lookupButton(buttonType); - if ( btn != null ) { - Node focusOwner = (btn.getScene() != null) ? btn.getScene().getFocusOwner() : null; - btn.setDisable(condition.getAsBoolean()); - if(focusOwner != null) { - focusOwner.requestFocus(); - } - } - } - - private int settingCounter; - private void readSettings(WizardPane page) { - // for now we cannot know the structure of the page, so we just drill down - // through the entire scenegraph (from page.content down) until we get - // to the leaf nodes. We stop only if we find a node that is a - // ValueContainer (either by implementing the interface), or being - // listed in the internal valueContainers map. - - settingCounter = 0; - checkNode(page.getContent()); - } - - private boolean checkNode(Node n) { - boolean success = readSetting(n); - - if (success) { - // we've added the setting to the settings map and we should stop drilling deeper - return true; - } else { - /** - * go into children of this node (if possible) and see if we can get - * a value from them (recursively) We use reflection to fix - * https://bitbucket.org/controlsfx/controlsfx/issue/412 . - */ - List<Node> children = ImplUtils.getChildren(n, true); - - // we're doing a depth-first search, where we stop drilling down - // once we hit a successful read - boolean childSuccess = false; - for (Node child : children) { - childSuccess |= checkNode(child); - } - return childSuccess; - } - } - - private boolean readSetting(Node n) { - if (n == null) { - return false; - } - - Object setting = ValueExtractor.getValue(n); - - if (setting != null) { - // save it into the settings map. - // if the node has an id set, we will use that as the setting name - String settingName = n.getId(); - - // but if the id is not set, we will use a generic naming scheme - if (settingName == null || settingName.isEmpty()) { - settingName = "page_" /*+ previousPageIndex*/ + ".setting_" + settingCounter; //$NON-NLS-1$ //$NON-NLS-2$ - } - - getSettings().put(settingName, setting); - - settingCounter++; - } - - return setting != null; - } - - - - /************************************************************************** - * - * Support classes - * - **************************************************************************/ - - - /** - * Represents the page flow of the wizard. It defines only methods required - * to move forward in the wizard logic, as backward movement is automatically - * handled by wizard itself, using internal page history. - */ - public interface Flow { - - /** - * Advances the wizard to the next page if possible. - * - * @param currentPage The current wizard page - * @return {@link Optional} value containing the next wizard page. - */ - Optional<WizardPane> advance(WizardPane currentPage); - - /** - * Check if advancing to the next page is possible - * - * @param currentPage The current wizard page - * @return true if it is possible to advance to the next page, false otherwise. - */ - boolean canAdvance(WizardPane currentPage); - } - - - /** - * LinearFlow is an implementation of the {@link Wizard.Flow} interface, - * designed to support the most common type of wizard flow - namely, a linear - * wizard page flow (i.e. through all pages in the order that they are specified). - * Therefore, this {@link Flow} implementation simply traverses a collections of - * {@link WizardPane WizardPanes}. - * - * <p>For example of how to use this API, please refer to the {@link Wizard} - * documentation</p> - * - * @see Wizard - * @see WizardPane - */ - public static class LinearFlow implements Wizard.Flow { - - private final List<WizardPane> pages; - - /** - * Creates a new LinearFlow instance that will allow for stepping through - * the given collection of {@link WizardPane} instances. - */ - public LinearFlow( Collection<WizardPane> pages ) { - this.pages = new ArrayList<>(pages); - } - - /** - * Creates a new LinearFlow instance that will allow for stepping through - * the given varargs array of {@link WizardPane} instances. - */ - public LinearFlow( WizardPane... pages ) { - this( Arrays.asList(pages)); - } - - /** {@inheritDoc} */ - @Override public Optional<WizardPane> advance(WizardPane currentPage) { - int pageIndex = pages.indexOf(currentPage); - return Optional.ofNullable( pages.get(++pageIndex) ); - } - - /** {@inheritDoc} */ - @Override public boolean canAdvance(WizardPane currentPage) { - int pageIndex = pages.indexOf(currentPage); - return pages.size()-1 > pageIndex; - } - } - - - - /************************************************************************** - * - * Methods for the sake of unit tests - * - **************************************************************************/ - - /** - * @return The {@link Dialog} representing this {@link Wizard}. <br> - * This is actually for {@link Dialog} reading-purposes, e.g. - * unit testing the {@link DialogPane} content. - */ - Dialog<ButtonType> getDialog() { - return dialog; - } - -} diff --git a/src/org/controlsfx/dialog/WizardPane.java b/src/org/controlsfx/dialog/WizardPane.java deleted file mode 100644 index 4379b33..0000000 --- a/src/org/controlsfx/dialog/WizardPane.java +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Copyright (c) 2014, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.dialog; - -import javafx.scene.control.DialogPane; - -/** - * WizardPane is the base class for all wizard pages. The API is essentially - * the {@link DialogPane}, with the addition of convenience methods related - * to {@link #onEnteringPage(Wizard) entering} and - * {@link #onExitingPage(Wizard) exiting} the page. - */ -public class WizardPane extends DialogPane { - - /** - * Creates an instance of wizard pane. - */ - public WizardPane() { - getStylesheets().add(Wizard.class.getResource("wizard.css").toExternalForm()); - getStyleClass().add("wizard-pane"); - } - - /** - * Called on entering a page. This is a good place to read values from wizard settings - * and assign them to controls on the page - * @param wizard which page will be used on - */ - public void onEnteringPage(Wizard wizard) { - // no-op - } - - /** - * Called on existing the page. - * This is a good place to read values from page controls and store them in wizard settings - * @param wizard which page was used on - */ - public void onExitingPage(Wizard wizard) { - // no-op - } -} diff --git a/src/org/controlsfx/dialog/arrow-green-right.png b/src/org/controlsfx/dialog/arrow-green-right.png deleted file mode 100644 index 63b675cd66fc900476e853e2fa5b8ff0462dcfca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3526 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7I14-?iy0WWg+Z8+Vb&Z8 z1_mzwOlRkSfQ<Z-{NjxK0tHWJXN7{I{ItxRR0f8MTXTccLxNw5*?zzG#mT#)VTyNt zkSK>jkW+Vq$V4?QMNR>)4#kBxMFS5Cy1KGRpIFer+}GF8BO0i~)5Udz{fXkDzUIXp zU8jCOtX`abZO`{-Xa8-zZufl6=ee8DvmfB#ndV^}XxhND(n(J6LG$q=#~wb>b7<sJ zDPR!b*qowR{8yQg;YXc~jkeMO_I(VD6_>d=7!LT(K42iz{-6Jq)65vgh8D&HB@->Y zIT}P59IE=9mN7WEF*eMdp%%=rfQ2F9baK*Th5%iL1oir7ml+!7{+L<K$Phh6QIv7P zL<R-n)D9Ph3~Pop=fk>O86pfAMAE#ESTfwuWiapzPxD~du$|$+IRWlX3>-WR27w)| znhY$}3<)Qcl`9xpW-^GleG0evsJ%|$xfTOM#mr4MJ5?-Q8>2aN3)#cN_2e|pd5UX` zm?bhL&T`N@R5?@9sL_P~!RIp!3=1ZT3O;E5{I}v9-@0?>%=)(R#p}M>&-Py_De3XQ zr{`A}I503gEUCNrPe*^VRD(5JL+-yts_$4b;<y)-e(z4(#P6_`VZqB=;hzgYVdJ`R z!p@sFpFVkV!|RAsbmFP-+JEVX;tz!X&G}hp^XL252m2nWG#bS=y0iRvaOlhzpQSSA zCvmnU-FepU{%1S)|39*qm5z8O?TpY8c^oKI*yl2<=d;mLrB0_wnnzVH{ZDyxU*|Wo z-F;Jr4Ow=K)f07B#3nO;^Hvv#C^_)xI|IX~-T4QvXmBt$WHdiKU;h8S{a^P5stgTj zo|6h07~))1^g>Q;wm;6nz~Hi=QEP*v^p}GYItSQf4zk`k$o(h5ti?&?$RQ^IC$5wR znW6;EHBC+$ZD%*gY9;7jaga4R5SY<6xqwgaQ0NXm+XDVyi5&9|YV2v`WN|#fA)Kgq ztAjDAD?+)CLwsiI55<EXEJEEX3MV^60+qZcntB)pb%iK|ddPmVEn>24k8#^I(fR~~ zQPZEcJ?@568aD;nUg6p5ymN)QREygp?h7d;hO_#`7R<g-v_;Cc$86#A3#&8uZ}r<b zA2&GgLW14+NRENtvBORqEp#|1C!gM^w1#K(F{uq<YnXR;eoa2Vv7AMy(e(hQ8B4j7 zLZY0bM}$v=-wlry3Nk7tg10!$Ihk7m52-6nUg5n(ZI|HBBN9nQhV2m^I?C6C`i1oc zsym#In5zhNIvc6)oWSI{aY@J}p-XO;@`99K>a3h?;vuCx`Q)vX>`m;JQ*;!xPqaRn z`{eKw<0sNj6hB3C%}sJBT=FCMkw(y|EHBBY0#8kzvZc;2atvKOE9mZug&~5b{ZUS9 z7j6q$AK1P^*rarp<=JL2Pw%B`7frn^l_8$-J#+nwl3jv#r^@+FzYu=u^h@^_(_b)u zDd*vB6Ky`;k**;*TY_C8U9wza{S2RFl9#(BkB1nT8@`_Ld?x?Q{Ll!kZCW*=6HjqX z^_r?SRa#3wWaX-5tM0Ah4*eW@I;4MPTyX6=w@~BY$16FnOj{kgYHq;mVCmrWmDVfT zSEaAW53yfT7x}l7E%LC>VSnc(feSXqKi+dpfje1pbA^s#Ht*`T(nixGY8%hqtSQsl zJ>#$J?rz&vD;HWi8+#dtZw~rACC#4w@r=SBb4vU;pKC0i{<*H}p2&O6N1D>hOni14 zrp9Einl^n}#A=V#fveqL?=@TZcKO_8dtG-&{%+)RJnp3)qwb#Ge~xwT^WdAocb9W5 z7xT5X`npbURrXTpg}YtK_vbBtH)GzuxQ2N?`OEKB?tT7CrdI!N$lu&w%fGtwM6hk< zQDM8yb56qMsA*xojjaCh+aCj+V-GtxFHM}9IQ?PE#GMyy7GHJib>r{JJQnj<<#Fz@ z++&N?*whr&ynSE!zMB=~yK|Z5GHV}epW|oGoLzMG+Dy~gwuaY@p3i<h`}*wr+Y_QH zqI9;c*tR3pbJLTkWs&c;?a6D6vW#3B5gHY{*=_CIwW`;4uid>|aQRNZ$$qQnT}wZ_ z;p4WG+g5Iu-0<`U+wFDRa<|ncrYDJ~Z$G;3@Vm)-C)e((?fq-Z&f9*IZ?$ZcY+dn| zA`z=Ft9!G~&3R{Ed-Th+m-^`u=LOE+Fn+vE__XGc%(=m{FT1CUr|&Fo{@l^s>D_c% zZ@Qh{Z0TcnPwai-Rr0kk_F>hfuXAT_o_*-;ireeonZ3(=*M4XI8I$>%^CFFlFC0GM z{2=h@MSJe~Qw_53uc`BQ_HRtz`dnE*S$|^q+Upy(FD+m7J@LJ`-8Z|U`H$@$+nC=o zx)&LL#{9tc6WdSwAI_f_-+JG<Uip8@|Em8N8J0JwGNv<kHaa#&GyVQiRin7S&)({G z>bFfd-#Ydz*y$+h*x$6a>FL3>iWw)~OjxV<{rQY@6VGMxwFcC^xORa(@mXT`;W{4m z*7nx$Hv7JUjtHrXhSN>UFWzx3zVGtOWtz*q+3AM<mg{xBOttJ*>1Em6GT&vg%l?>N zTI89l5pyFvbG&6N^|aQR<>l<V|L5)J_D6FcaX+pWpP_#uwxDw1xkF!Cmy4~`6VkDo z=HS!eXEEi2qkz^5u^!b=!sV)cT$P7p52Y*VUo^Yeal<)AOV00;hn8>Eq&E}ym{zJB zHD0RobZ3kD$_aaXczy29wwfn4t4tx+$kuAFVe_Pk6AGPHDf&*{mi{XJSz6iYHL0ze z{vFNh-mWh<mHlM)<_T+9BXzm9IW2n;5~Xoni+xjiYIxfIvz@0br>&l+efI5{&8Kcp zFrV{&{{Oc^hlCzZ+P1XKJ6u;b;@RFcS(ck@3M+4OJr-rvZVO{uW3!`cn^x{s|J859 zr?0Eqt5)Tk-57W9RMWw&jM=ZbL%E)|*1o=T{cWs&gns1xt%<+d=1SX%c6O~3xh+0j zwEl+1or<T@?fIwn&%85b%gWV9cBY(9yOj3w**)EP(R|ZZO@B6>FOT=;tu4Iw!?wKr z`pxyW{`9jNw|6&hbKbdlzs-(4smo8EJ8NwpvLxh7$gdEycbD#NO}zdi@8Ub@>OJ2~ z-dw#Mz32O1yOaBFhcbrxUQN52`rGsO=I{3FI#<2?G3|G5>{`Fv!nennFERgRSLWMx zedm>{vX^W_g8Hv%zjo(4F2C>J-1p_Wyk@+iy>pH|QZ8_*eDd-;=l$<;yjHi$daBnv zWWOw5CYvs+pXD^`(=4~y!LxoxCq?h_KVx_C+N*n2f81}&^UpD{iLCVc9C9-A*2|{L zlhZ$)@0mMwZf%|3&pQdX7j3J4o_y|p7JvTxT>>Q!FS-8jer~<T`drMX9VMSO-F_+@ zz9W3rdaL-{S0%4({!PB@e|-0x-Luy1jLF{lu4?br>a_1KrRSNSyZdEt<wvpq*RIa9 zw7t9cb5;KLqu;;Y7rR?mr2hBZ>D@QW)!(h%<G&~Vi^E&To6dLJui8idyL03Ho%*Z; z<qJMvyyO0zt+o05zlmS_`JGw&XZD|N<86CA&%(~q@{xVf-<N-uJD*QEuQpHo-=cq~ z*NKbi*ZsKq`ue$xGcGQi{%QK;{kb(u|Gql#T5|pEV~38(?K@dvY#8???DyM)<#)<u z-!Hz;@BgGmp<d&E#?OskgD))qJy~+{<o_(pGd}-GHrBn(z`($g?&#~tz_78e=6B#^ z1_lO&WRD<U28JqC28M=a28N&i85kN~GBA`HFfhDIU|_JC!N4G%KPmpG8v_H=Lr)jS zkcwM9lTT;Iu!<b3FMl`J$0u#s%&udTj$N5G!|oDS)Kb%36IZctZsq7&uv({S_A~#C z%>v<u3XI}@LPAbLN4OSFm?*GV;jL5iH4_tq{uGXr2kuyx=PjGLv-o*wKlg0KTAe=+ zbol1HFF*IFrh}uMJD{z-ee2n?XCF^Xt=+PH`}do-Zbg|tU^Y4M`NW^c4ZXd*`!i>W z%O003j}2dSb=8~q@6YS%=*(fC#qd7ygz#<O%Wt%%pWZLIO)>v$+?4WXRjTplyv=6+ zP0Y%AWqP1q;!}s@ha-<a&I?*8GIxi$-YbqpeF}3QPFD#()tM+^e)!>s*25EaSxWWV z%|4lO@AT86_)x8>El(qa{%qUH_fqb?$lYtM*S{WD{6F*a&p!@Zqe^9tPjp(SFfG+{ zZP?`G`?m4zUwr0G^D$IzOT05@&YT+A584gtv(N66=4#E0{rU6pu>@y<^~X;K#&;<1 zQ$BO-S?AM7GA~L_Ybwd#TeN8U{>Ye^ITzU2*+bV~uXg;qaqGn8o~(Uruin;{RerwC z@3HUy_2qy6{$*XecCBw{=+_-ve*C<j_2KcZywE_A{b{q7iF6-rskS_L^@XWZlz?v_ z=SoMWRr6n-VJb}D{m%CKm7{YvZ(cHK<?UVT?uRp!mX>Z^zIbu+f}J~mb}iD-7wdM- zxvf^PrZs#~xM%oghB+VSJ~=;qdF1cM?`~YW6m-O(Cs#D!(#tQ+AzEL{t>*qaYI4^4 z?c2BNU5eYk{`n@pWU5StR{AWfowbjuAN_YpcXM}te&}IAPHpX7n+gTq43;K`*VnFH zJMpEtLtwYc5k1fFPr@6seoyjItCyFOdd2R?be_?7R!7Go4O0gO@dDSB&!3F*Ka@RQ zT_MssKkmn@S)pF8N)tPO{`{#ifjwuzCl@h>_n$s}x;c05+}Ev657*`1?!0^V?$Mbu zXExrucdyt%TcF}cE0=%gX7&%gy}hMJk~ZoKcOL1TI(6##-@ktClAkBbAjNm+%X@~L YO*?kKtzIe1z`(%Z>FVdQ&MBb@0D+OQQ2+n{ diff --git a/src/org/controlsfx/dialog/commandlink.css b/src/org/controlsfx/dialog/commandlink.css deleted file mode 100644 index af693b3..0000000 --- a/src/org/controlsfx/dialog/commandlink.css +++ /dev/null @@ -1,71 +0,0 @@ -/******************************************************************************* - * * - * Command Link * - * * - ******************************************************************************/ - /* For the text displayed above command-link buttons (but below the header) */ -.command-links-dialog.dialog-pane > .container > .command-link-message { - -fx-font-size: 1.25em; -} - -.command-links-dialog.dialog-pane > .container > .command-link-button { - -fx-padding: 10 10 10 10; - -fx-background-color: transparent; - -fx-background-insets: 0; - -fx-border-color: transparent; - -fx-border-width: 1; - -fx-border-radius: 3px; -} - -.command-links-dialog.dialog-pane > .container > .command-link-button:hover { - -fx-border-color: -fx-box-border; - -fx-background-color: linear-gradient(to bottom, - white, - derive(-fx-box-border, 60%) - ); -} - -.command-links-dialog.dialog-pane > .container > .command-link-button:armed { - -fx-background-color: linear-gradient(to bottom, - white, - derive(-fx-box-border, 40%) - ); -} - -.command-links-dialog.dialog-pane > .container > .command-link-button:default { - -fx-border-color: -fx-default-button; - -fx-background-color: linear-gradient(to bottom, - white, - derive(-fx-default-button, 80%) - ); -} - -.command-links-dialog.dialog-pane > .container > .command-link-button:default:hover { - -fx-border-color: -fx-default-button; - -fx-background-color: linear-gradient(to bottom, - white, - derive(-fx-default-button, 60%) - ); -} - -.command-links-dialog.dialog-pane > .container > .command-link-button:default:armed { - -fx-border-color: -fx-default-button; - -fx-background-color: linear-gradient(to bottom, - white, - derive(-fx-default-button, 40%) - ); -} - -.command-links-dialog.dialog-pane > .container > .command-link-button > .container > .line-1 { - -fx-font-size: 1.25em; - -fx-padding: -5 0 0 5; -} - -.command-links-dialog.dialog-pane > .container > .command-link-button > .container > .line-2 { - -fx-font-size: 1em; - -fx-padding: 0 0 0 5; -} - -.command-links-dialog.dialog-pane > .container > .command-link-button > .container > .graphic-container { - -fx-padding: 10 10 0 0 -} \ No newline at end of file diff --git a/src/org/controlsfx/dialog/dialog-confirm.png b/src/org/controlsfx/dialog/dialog-confirm.png deleted file mode 100644 index adb569bece45425ad0742a5b894ae9766596efe9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3901 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4mJh`hH$2z?F<b3ES@foAr)~~qbjF}KArkM zbZ=Gmdz)FycHdmGFj6+fP~a?s5EJJMfkZ#18HN>28tkro>K7k0%`|SDDbcI4;)vv< zBNi-kk}VQ$^dzu}h~D(wpr}=1Wwv)i$@l8N*Q!EI_eU?^<@eM#d%M-=<1y#n*Sxpg z_w?VpPgno$%R0JArzS2?gCXS5a|h)=eyfGV5(TU#7AFX(C3ZeA?)p_ZMXkm~z`-!k zk!P-1?yV`m-|w&gcdS?X{k?6ux1HDT`}OLv{{BCo_~%!@+j;f%wY9rzUtU_e+1uOO zol(N$i{hat@73)l>pf~bpY^t3amAN?zu(O^Nk2DdeXpGDueMdIRyj80hKZlE*nT#} zXl3#9b91c<A05f|xBK~IpK<!R8kPmU9ztx#XZ%-Zk<tFy`N%;bz;kt7^|v=S?{~Q^ z{>yW?;ed&6V|Zm|EYqr0r_y(S{aIt=wtn?$>rY37{r{Alo~C=8Ax1HXPw;iUZi`9` zgNRVGdCrZ3^xE3L?_9gZ*6Qi$y_@d0d}4oy*3+i@pQFDUbN+a_Q$P3Kp32v+*YE#l z;#^?Vu+Jr6VT~VC-kR>Kr`3FCnasO(Ygf_JQ>C@PzsXKm{$Y7rd5+%n%NGCV+}&Ni ze^2J+WltGab$IyiT=-4t-d~sds@~Ji+}WCa{o2FB?fwZorw_?@=a^|vn|k4+Q=PEu z!H;qIJ0{%Md}#e{$K#26tH1vX*yAfwBgDB?{M2;&Z#R;==U2U2dA8@PSL6}q^{k3Y zg|YY368_(`sQY<M_0Nx~ZZ>~^r|l{Eqjk?}zRRq;CccwpCd8ba?;T~>P;}YXT-U1h z*OzCrX3Y}R>-2xgC?9xCw@|Nq=2xFvO@EHEB!vb(+bbsff6H>oV)K8T-rG$QK2Nmh zGmrGp6f`OM_3^f`=by*#+<fZanC$!d+5XYb!)Gt}T2DM`t;eaKm7TqRNA2%#^DU$E zA{KseIWT*JD<}fDq@A55|FPQP&>?S!eWz=_zGZv&_q<z8y}R(AhfIGC`<niEr>p#N zuKx9ed*W=5j~Pz=ajNucgiWqQ*g45g_GkS^r(C>h@x_rT{^!NOKaT>0bu?nFgSM;8 z5a(xpaX&UGTVB{|VIwp9HJi_8jP12`baYBZ$`l_eaohc^k}jK*cYMmNA|L7au7>z# zuBp>ZC-^*F@Y?G4scTsW-1ReM7H8IlOqre#7Abg)xAW2V<@%3~ZkPI)Umn-3cyYpn z38s5~B^>LK<equsy?*?@KhGKT1b6n=@>y8>J^lChcl{xYm<joUf%g_Q%iX)$^sT4s z^~xF*p|({kRF)~ry>>~rX-himR2bp9<wAeKf%a+NMAoSl$t+&5V1vNJ0EPet+u6>w zmqq7TT<_V+omKewgV1-&LmONTBt%Ypzj8m2PtK--#i8lG?{tTI&8uEKo1H)Jmk_JN zf!Q%hfm6fwJYSmj<BwvG<R$UO1s_5aq|`Qbmi1_d8+_iysG;Ax!20KlAfEH@?c0Ct zXnM3r=_8Nli;kn#A5VR(`cv^yLs4;_Ky6Dy_v7RJ?-N&UVscRCd~x?_gPV(d<&%k_ zJQEq#>U!;-kn(prbNIw<OcGWbWGv$uR?cZ^$y;cgt2EUo`Qn$T@SpDt7VMGW*WD$T z{5vyauavvaQsvx;0A@uWxzJwry4dz#+Ar5VDZ4HftL8Jq;PtlKd9$C?+O4SED4#Z` zHu2Gs&daF{<p%5t;ju#M`mc7RImExXFyTt$xiy_GZ5Mn^jurh_u#tD~#NE$&TBrIh zQl98K=keq@?#i7HuhwpObMvx+ZpXnlTX&Z%%vc@1ejmSs<ipe78)WV3{S}Kt*-8(t zE4)$v`Xe9D%AQ-((k+w|wexT08l@lnz*@Ltov6~>l{(*K_cq*@v1(tvQRI`V$OVH{ zMor&bqzct)mQPq9$n=n-=}iCG{rLh+aY9Ttr>gZ!8mBQdG&o)SbZEJYmRH~n?wL>S z_a9rpcG%!g;)T}+Z<EeW;WxM$)yC<}`>0%A<)hzW&nu=&6SVBA*`xM<_P_D<K}m>P z_k*dkx|H6m&2~EQh0*Wh@pl{(kJQWj;-2Os&9Z-0MQP*wL$AKCK0Qs>nq6UO<stPG zQMEa)uC7aiQ+7_MxKpdvcBxLZr(Rw}wm{o2bME<NE0xx@Uzo9NfmloKQjtl)o7n2g z-<<#P?ajsyr=C{aIyZmKBxaohW-O9Ve0X;)eHh*@Rq(v$;HGKPoGnid@i6RHxMkx1 z!{yoe`Ts+gtCU%DZ@1s}WWuu2(nD8{20d`PbnDdS{k}(j#){^1C~7Hr&PXnL?Q_BF z$?4to?-rPgrsyzFd+fRUX~o(1$NvTEMtpm!n0NEyQt8v(g*GBnw`|`Y|3+znz`}oj zfAc>-bm?TPz>V^4m+zTfev~EKcj;TwI`J=a8rS40ou0;J(JI}0z-4aO%ETuNGX9ly z#nxvu>j!adkbhp#o78_^)8g`tlQPBv-?Trx66I=D^0~TD=ivSC&l>ixSfQaMyGP)g z(D}^OB5izK0#i<1Qp~FM`c<{}p@4DGi{(o{zPW3DK>O13cj@<B+67x?89f!}G_B@& zW0}DsYtqrR__?(~smsb-kN1h0A08aMx@hxtW+~1o&!!(xl8wBXShJ}wx$yMj6#=i@ zT&DX7Nxxg+djFBZo=-2h-9N;OmuMVhno+<Z{QodVSJ$!Ao*K%hAJ{JQvX_fhRWrTn zeBk)5<vVt7&apW>ZQhH$6Bf)nct*-T%~yhB{hP|?Hg!b{IK5Ud1c=tGvG{-W$}}<A zoQkinE-&}r`C?5~`-W#63#1bz>Z}CUzsOt@Z^0JVscIDQ_0R5}-%3(P(zAbd@`x-j zp6k4iqf>x2DZJeCKu_?6UJ>>aa$)bkn)8N;M@Zb-&k}cY!()+In;kWx9Aa)CR$<~6 zO+EPTRBg=Cj&pJRPdpYJewlDsRbUIl;U6N;wg(7*RgUkQ)9?6|J+(3JTym0w$)mPj z@#*^Ud4hBI%3bhW;CsWe;BIK#ib6f>yH#%+yDkZQdirLm&IyKwOPfC}J9+Ft$10`w zS9`kK+S=SM-t<<G?mikdr&{{^J2y5z*)SE)O#fSxIr24k#;@#t=$-xTLEHOx2gEz2 z_wSc}yD9fq%0D@a2(BFptGfP3M25alTmM2?z_RR3g!4Z3Nz47_TItB{nb5d7>u|$7 zrOuq~)yp1fybJc6B_FX)L0IQdYmT9wgzAn3;tvn|DE@iKVZwXi#(8y@&UYs}*m-<p zW8dAajA7E%)#bIh5yO&@A;*+?&rasS*OQ0eh@|{|9M;t8^JxFd3m@{_orEr|wm8Td z@;oeDWKz9Y{aMWwI=o2_TeMy_u6@5{fg$7WRc9rGk_6sNo_vkvjGoY<H8YuuB6a3j zoye{gPd`7eR@mW=YC@odkyZZfDEmJj4%_oco8?RrP`IQ1z&3bs#IGc6pZXbzIw~@& zv$=G$6c=3jWOw=-Ly_7#-QbVwz14R7+?C_TJ1x(yOZY6C&s3EXg}J7j@<v({PDX4v z9QW_y<$CKy{Aw}5N^Bxb-$H$+`~B8n5c;`$g5wbhH})ly#f=Vj?2}r?^GSJnhxeqe zrz<T4J~6v0vbH8Ftx)jEvomha@98hod_O7HVr5g@B|%P)digG8EiWZ0B}dUZ-x~GG z)y~Gj6<?$m?^)U`u;C!nx~b(M?vDS&T+iOFw0^($`@P)U+}yP)5BP*8c3wN9<K8*T zLGNbf<PR4=6`Ao*b_qzDZMdY1HS^xYtEwlaPh?(FaQUcr+5H3u*N#)|xlCFjZGDq` zlWv~L4!CWfBz$7~zeZ;EZ5HAOESdBe6PXpf+kCCd-`#m*Fs)_EHMIb-O&@+-U;V(l zRAIW;jcDy9X(x@hI(^cYtCIh@>Foncjo94+bAnu>W|xSCnYBhH|4KN!=i$1qn(O$& z*TwwoV4oS!)FGHw{@qDUFnM|W=UX+2m6bmOo{K#3v)B}KnE%<A!;AN{dLM3BCgQ-T z!t&$hCi~SsU*^6yOHP>o-QfMPsE#)^k7c&a&uNU3Xmz}F$ab}~$LY#l#?3zI>g(iX z4h7$re7?5rX_hO;jT;-2kE`92H0@ld+x5E9Mn9z^?cQJeb3NuM3z*HPEaT-(yll?C zz#-rL_|w%H{YwS?B|MfqEm)_poNWS^>&Ir>uQNXFeLLgN-unq}*M0V2^LjHm%qV$* z@zlo_vbjaZ7q7Lgj~73Bty=98$FlD~UI;y4D{f-{H9h8a{UvU`on9;#>R(@5`~7~^ z>$Tb^tp0lms<f}x<bM4<?#S$~nm-N+vNSnH#W!p1bXYWLf}2_H^y6Ih?M_9zIBic? zUYcV((<So2fm1h~Kb$=|^}{?iNuzg1#k5<Nv2u&)JUaY($rH`ecM}_Gos`-3emo}a z|7q6KY?X&X0s(in>%2Ej|8V*Gtin%=Rea(bSWIRwVe)i({zs=>PT8GFa?+(hF_Vo2 zMfE!KEm`c2erfAnZKHT!c*~zl;&By;_6=sQvTGjQUGaS91jY*|qIa3*@Bdp?Kd<3f zHMec-^}FQ^%D;bpeDmmF$5P%m)%tzc&&9YE>vV5(>D&L3<AU;0M^V*QyBO;Q5}(z= z68<c3dS3F}@?zvPX)`9TX~&Pbul(c4Alq{Dc6rLZ)yJIV7Oa1Gy0>1;zvIy(#`jCb zkMgeGlXM|kWLK`8OJ(})GR_ZaOXj{mE2mIqExv1)>r36n8X>_&U6vaseP3N(>=-}& zli%wqXO4=86Z1Sf9>qOnUAuPe^YFD%TPIzA<<7X}x%T~Fj;GI^4!oTH#Cvc2+K7#d zW=_^$y>6YHhtQ@S-UmFL%msG~znAtp<n6%mvL@i|{@3evo5k%ad0G2B@u_mj6HkB7 zH^q}IUMM_S(4e8LC13O5;LV!2GY>Z}x)ONL`%rf3`#pM$`kY-y&8IBCzAkq6+b1U{ zmoh|kT1-^A<Z{fhOXcjnJxP~jetcda6#3}WudlDa_emHg$=;5=bMKX9p<mz1hXp&X zCq&*k7w+Ny{Os)Q52r=vRn9s!zf{DWGydK!sfFLH*ymJVRuDY-+2z3FxlD^@XgvM> z=*8RZ_wDk2eR;WckD-Pt*Ni_8H*MM^a9{sPMEugq9^XwNotq!!KANvM$D-!P2iDF) zc21?I3a>ZTG<jH6UO23G<+F6vAywhB6F+R19OBd5uU<Z7kNr1+B^^sHFY8<rUMX(7 zf9?C34*HW~7>++(b>MU4M*)Laix!y(Tg{uwjsMSoy8rqm+kNdse>DaM1_n=8KbLh* G2~7Y=q=%^h diff --git a/src/org/controlsfx/dialog/dialog-error.png b/src/org/controlsfx/dialog/dialog-error.png deleted file mode 100644 index 769d7df7113350020cf67b19aad6629f68732a49..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2561 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4mJh`hH$2z?F<Z@Cp=voLn`9#Mpoxc2^F)S z>&~8~xux}8+3clLf?kwqzDyH!z8X5|Sk@zEWv4qGQnwx%-wItEc#Wg*<Ja~p?x7jd z%`PsF<?WJ0GC6MAE8KL|*fH%=)QSzMnc0pnL~fn)Nk9MoiS^5q$IVlsj--57+keOU z`|jd*@9%uxk^aoP^Z4U0`|mKF)bV<FEOvt6q<@#TaU@IB+H_tH<yKL$Yu#<*W~SV2 z*gVl|`nFz!UlQt)e|z$tSxhJ}wJ&kjoqRqbDmHd+;_GW`t@&gu3JMYu9+dnMGJn&! zcZ2#jHuiS!1Kq2m4$P~PDqq^#+FE~WPvz(N;<`~G%g!floRLscaz*R+=H6O6dEa?9 zk`oMXy}P?RI&4kE#-*D#e}3=sMR&dJ>oP@eIraa?SFKw0YS*q^sV`r?l&r8bGIF|@ z5#s64=#qT9`mDMtGq2Z~IhK>177DZ;erUXP>sEPFQ&Ur+i{^XuW_dK$*!@h^)zz(M zt>ox-Q40H^zpUlcsk3L7&Y2?<xM<CqH~Bf8{XcH<hcQZTn7X^{Z4~eJgEn_uS*vEq ze15mn<#V2@&GA=@Hkd6q|M}CW1uZ**D=U9mDcxGum@BIBY{5@&XXnFO-lryY&aw4w zzI#{1vb-;-#;!3X;)__Fz2LL0D|L?aH*qfNx3qOQsKC11-(7#2yp+_Xzbkj_h`6(I z*|N0c<mAUy)2=VO>Grv%%+=L(;yi_A3@pNCuYdeVwz_sl=SfW?!_Nv~`@_>`X+37( z{_a1^rS7@$H3!Kc?*^60U5tkho17|K`dFg>;$zEir}q8II<@bel|Y-&qCXcGyRTfa zqT|3s(GzUxDY|=4H1({RG-*=ISu+Jbht6%f(Jwxv&kr=Pl~pTVo){_29O*V^>i37g z*Q|(UWLV-DQax8(`{2}w#(QsXyH0#5D*7bd@<DOmTE1)xnawiilvg=)7%pD0;DPxy zb63f-+0ODc4l5-kl}uPa?~*j*Yi-$MrfR~)Dr4UDx~f!mf_c{p>xI|<R`2^a%V_<s zu0M?pp9ED82*${sQ?^TP3^{8P*7?u5T|tJWBzQ*jg!;q0Q{p2v^#qQ}%$EKf_-^qY z$ts6uXCwB{FZ}t`r1YWFRBf(FTBjte>hA2?q`}blfa~16trJxH^?T=7GBYLxnebjY zbUS}}r1@Q!Mh6F-OIvei3w-!!)hXOIS=OXus>B_aj&uV9{!jMrZZK*m&NnRQZok?) zHM;2NoJrxS5596(eGxGG-DjO~ZSD3|i%e#V9^CQzw7#RmiQ^S>k2UO?qqKU@oMnb4 zzW%A<otys1Km5&C8R>m#ig(df4VEbGBVSBp7+HPn>Q4$)=85X=`I#13{-j$!L*&TW zlZ;+<$F^P%`eu6FW8U`Psh@17y#M=3yI1tftVdUcPHHA}u2k5{*2I_0Eo$?7T6D_a zhv)6ZuWxkp>4`56I~lo0qCIIo=Y=bK6^eg+$(;22*a^w$Oj%Yl$~G)-57OW5Q?ony zvRYuqJ=^aM9lS;dbGGqKdGqIq@NUJYcPo^i#?|lLb+)qlTOrTagRF&(f4>Oxe*LbT z>U``-tcUa;`!ff1q>3kA{r7ISfR5LVuXXCB=OTB7<lXSw_vgZcqWw=T8gEz3P0<&& z|M+sbNy#S_S2p&I4DZs`uFy02r@&@1dBGHm>(|w%-S~dVdy?Jr`{ncJ?bBFPdvR0h zhL)c6yJgZRs^1mAIn2NE_1^C)Z-32+j@u--<~3J>K5LEmriMP>W|5N*o7Md;yi=dQ z#8!U~L(wBCDgLgV<@Y>W*K|x>c~r{lOCPWFioaj4YaV)O<hohR?|$cQk$wiba)HBB z%>M7by>EKF*u(HOak_i0^LH;iC6kx2KySyQU}Mjh2QTbq+UvRSg}TU*D5e$mRazUT z-{m~NuI5|hZpkWhmw(@DKF#&@Ef5!AKOi#OTP%2jc88%{xj=UBBJ~u}4L_b86>t5r z==nTngX&4g|CHzNag^odP5#sqv)1kLDu#)?NhQKuNgQr7bIgOUZ`x4z&NJ>QSLK|2 zj3<;eZ+M03HkdtBaI<Pj=y}`rF6<cN-}dG6f|jo3zPY>Unf)gYQTs0eN}slQZ8c<7 zS>LdGiCk%2!3%!L?M$ELt9!iU>+k%_PE3AiGhM6l0pqOgSyNT{UqtxFpS;Z=x1aTb z`&=Q3b;<Ru3;({m=)Q8vwrj?ZcQD`7GFrc^jqBYm?o<np=!oxIynOC339R^PbK-Yn zK*uw?KN}9rRSG?3A79z}ZEgJfl`K(#p`xPqs@F$^J3hN-xNiC$ZpLW>M;>l@IJrPI zLUF=0H`h1Ei{)wpPR?uJyMCWn_3Kv|^6??REkCbd$}4iMnJgX_-hDg6ID3td@aonH zhD|;ZQx&JM)nrx1ghem>_GN$VXWw7fqw^1XE&A~9SJlk_w!ilYZJNQZUG!$l=kGqn z;zh#6iVW&}ssbhZAH^qG#>|OK3~LPAw<Jnhs>MdiPptHu+`f(9t>2}be4V~SNhfPo z_1Tt78mBTtIxRdk7+229T$7o4=iK(!2g~m{DlA$x<&pnyjmPrm?ft7G1%-v*mHhs^ zW5REB)h6wlKRY5Gyt$pPT-+gj)7Q#8_Ym*ugBIWPTV7wkI<NHglbcQI^ENy=T5I*{ z_2hzuD)~t!Yh$-~_6qS`PUQ2M^XAR(_u|=K3hw?t{QLdw`nwBMyqa24**zY<V>sBn zey>}u&gI3u`^ADTt#U~?CE|bZ_>I_*itEREXEe12Wc8fnWJ~09Xu2PJ^p)NH!kmh& zCnF=bi7^Rj2_*JBkWcs*ZGCuGz^^+yqn=ILEt{J&<z7@rgGw~_ec?D?{^Vaxtk+tf z@G-g<u%=5NIoz{P*}YFDo%PLs=O@qaA1b~PTKBT-=w<)QOENF#hzYSC5R5r^Gq-W_ z+O=!{YwGIiwh5(MX0K4?`nk#R_dMgCs7FDJ>ia*;OlL{)vwv_U{sG6jLy@8##mT(C zXV0E(JxxD;pG3afty{MY?3b~`J8gcqZ}y?LZ$)G!K6n+z?OnIgV+Wtz{NOORg)4*4 zpKe<jvu{D8a{1o}H3!9I_U_$#<?h|JhjQm1x#PONe0j-%&#dkBXJ?tV9Q%9X*4AwH z@^^PEcNIN7rEP3%?Cf{p#+0<<;`4U@_!_3jdGFMzQ@?_j`{ky8+S{4;C~pt%5pL5O z#`UEi(o}fO4JLlqUUZ~bIBxx3t%dqO5Ae$H-d_^G`PKi=4SOYZ^{UQIlgQ|d+x+kT z{ug1ae|j=|Y@YXem?^gl7RBfv{gQHwVdg!hyebEu%wsRwC2f0x{r3Gge{7=sOd-qC znQ_85>m|)EbkF=zahrAdbyaKpbDL+i3d?6lM+C72Fyt8>>3FfHHH=R}eN)4E=DN4S w2iI^)NM<Z%Gi(h#Q+I9Sp}M}^9RJ0yU!A-BdfA+M1_lNOPgg&ebxsLQ0G%%6H~;_u diff --git a/src/org/controlsfx/dialog/dialog-information.png b/src/org/controlsfx/dialog/dialog-information.png deleted file mode 100644 index a220108dcf27810ecab177dd7969c7d3d05eae99..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3594 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4mJh`hH$2z?F<aO7d>4ZLn`8~&g3qLb^UvM z|MxrY@Ag*SpKbE~!lVgFFP*&(nqBl_7qI574M^|mFI)78f$Px%G56zECk!$~T?;jS z{P?fUy41=mx+}O;VpVR&!6sc!GZockp0``JRocD#J?HWJ-8$*#zW80zd~5OeTur)v z-npB9|H$o5FYiCTE%%SU`2D3UA3PWzh)V9_%V?N#LL_p{TkjX9ZV!?ca?aB3>e6ye z{O9{Jd)kbQNtdoKcWM3;{mWdR?Z6I>4--}}9tgTP>)EqsySL}w{&t{|nZ549&6__@ z+}xaAKgUN+esRUw`#<dO9j^Y#Ge1>2=k<P3#wKIkESF-|l$WvPcekc|d~`J2MQNfC z(~M;=#cu4o{<<|$V%4{wH95@A&d%xlayB=%rk<Y0yu1AUKkJ6F!1*7R=xt?u_h+5J z+2~Cvo|m7UojrT@tXXy^?q7asqVaJXb8h6c;N9yZ4?WzV%utq{{rX|AwE4Sf99x+( zgumVn(woZI@||&owvNu8e=C>Ii`t)bwCnYe*>z6KgI4NzWLYU|oNZsUNU5uSd3?pg z)^PKj8yj*<N=oz_wzujQZ%l6Z;K;!J?A+Yl-@aat|9|Y%RPEVM%<T`p%-y+chSI8c zR+epVf8RUSU$&>w_xvB`*>%Mn{kH$r{#9%czq?$$a(=Ns!!n^hdHcSP9}Deor^&zR zuHE#$+sNT?{O+o+ufG2N{{H`~r_<x@CeK@Z=Rx}}zsK`*t3Pi1UEe?L{rf}f|6l40 zzgNZn_pm2V-?9t$%)4aScNN}0|NWsb|J#Gx=hgAHSGUc5{<6b3{oI2mCnwL)Y^~ks z|E<<ex##nev!P7;%YJ`*TP`9Z;!?tA{UG-^`^K!x#Th^E`R%!A+wp1@*P0z0Ik%hE zi`@Tr$M?tn-m^cRUY}j~|5xgcugg>;ia!UL=<Q>hyiA_|-?#ZY9)ApzncDHPLqV*2 z;r8v*la&wI-87dxQRK+>f-zcs;hxIZ*VexNTUS5fr=NeOa=~@~|6Qi{Ys6}s4RvOi zv&;XxaCL@pwb&_dt_>MsjCPj-dOX(2yDnPR#vv9j=$d$=J;PB?>Q(wf=j*Y}4sjyi z^J_)#3nrJi9IVS=u|2=<q=T4ItOtvhMMC+zJ3m=hD$j}K@asJuyyIc^`A0whx*IND z#8kX)PH)#IBNpbkCqFcpc~c#mG*XQurxtD2E}r=Kdl%2W#p_O=I#uv=4r_+J;NiFZ zTa_jTt~^;6V)gX-bN3StVn)8X4&Q9-`#19z+sX9{J00{_x%A`2UjN05zw2nNUL6=} z8+=H%>HLQS+D0YW%N&I7=|;PrYrAu-+I3Z1JkP3Gq5Xo|?9y_7XD74Fmz0oTkUZg} zcDC#u$CZM4&qF-V2e+jET61p;GqbaB$F!-74WiiApYPPN(4J(NeDlSN{#3~i`X|3m zIWSX9VS7e8W7~ls*QHZEsy-E*pS;%3%Gb}&X<5jGR-csF*BJhK%|AVT3XhJxw1Q3P z_i58FT&v~!IZ@*fYv9i74NYQ2!7d-RTu{9%*2kw(xJ18gV?@x>I}aZ}_UhcC=@xNf zhDh(mtDkk6dhU2w?rLvf-?slDPmbT_6h+~iCoJw}ZD~8ryf4vG*`V}B!0}E&o9*9M zG>9wBh-Z?BYZ7+Q)D6&Fe{{=&aM3H-wPJm9yo7ulbfq*tm;|VlMoBMV&25(mY_!d_ z&DfbJWb9oW`lP+R-BE4R$xV+n8qVo3e_6HZ)j8|;F=y<b9(}~KqJ3U1>xZ9L*F5~l z`oflJqnH4b;eX$X60MKr^Cga431Ev<P<dY}sd%w~XQPbs62(F{LAlC(%=W+kC_Oze zaiXAzxOnx6ZP8r?A9Zu*&34+kDC*?aHW#IbJ~Q*b@g?7XC@1kSse;MzquIkyE(?PY zCDlo{@;&U@_pH$5d%*nEF(z2}&{y7_5tjD+lRbquPU)<;Rid=8S0K{I)zeZ~GM}T` z+U;Z5{vxG_8G<Rwi_^|}EnLx(VHZBNxw-jV&Hpprb2ro~Hi|b)skoJWSfF5j;>(%t zr3)@So7QT)A!teO@;ld)9NPE_lpc!JOV9I2G?~}Nd%&cr;@tzzn&P*iDS>QLrcIkR zA#i=%@hyz!x>pz7-BrrXQ1HdNd+mPNms7WJ9(v5L$$vc9Q{?&2yO)>kntsvTHOA<* z+0;ANH@2)?H2sp>2EWcm&(3=%7qT2<ou{!XJD%@bDbJw`a|^7}6&FhcXr8d$CL+tY z;d()BZEfegZ&#Yt*^*yKO1K$BscztMDy_+~&}(A}m?Ym|=D?p;9mOocSh%g}{0qs~ zUn+#0A8Stale;SxA<bB_*I1?PXrL&kAy-#-Ps-IZlJm2z&i1-3{`qSu>$Gq86eHUB zw;ktRWDsp4+@^9TMB{<0iGPnK$AgpN)gM;xJ^oPi2CsMahn2@p=`g=2U3PM2;9R|J zS;5=iCTeMUvYvi?{G#yV6@6_l1CF}7ZOTg9p*%tR=Y0JzE4D9l=LLM&_O?Q_ZQ4p( zQU941igAm6R6FPj^W52!;1*^Q_fBTn_qjJagRbXQbO#C?4D0!OcydemF=5HAjB(o; z83QA($*~&MT1of+n`n_EapHx@!s!~R44cfISRS12nkDdl(*=%PhT9i5L|yn`Rcf+h z)l{2p5)%rJG4d)XN17JfWNSXW=XujgNbGsd#Oqt1DIO?kb$DlMm@1K%aksB;0<Xn` zbtXmkPVAajWH?>u=#k&acS<fZtXiYtA(Y}1e8kO>dCt+>C9UU+ZC++hVc^?x`}4ai zh0VbmbVJ+@@!8xw;SpxEo7cc~@}_qZ)3@$Vc5p59Fl9QO@-B$wx|@X0(v`d$LeE{| zI4;21#GGHT>EYe$Zzk7<Pk&}9xB#s6c*9Zor>tgi(b2DY9^DlE`QgU0Ey@CO;&`18 z?DR3<(D+mkcCtx*!CK`5S1xKURX$J^RpC2j;y&XU<&j4ukK}as++uirhvP_}taX{0 zy1M(_6-ogj4!NEZ2A8LNzP99hO<ez^_#Vbh(~i5G>uYcn4w)%8&nS4uCL{UjXHP6= z^pOX})})(;4)YJrnN<5iu<69V>z<2`Sw3x;%4FnO=FtCn>EZ)ZYqDO26mZ>ZSe1KP zZO3hnf9oDD6wePn5G@%fWnR1C*2(`43JhXrE4t1+U)Rd^RP-;K|Cto-@I%2&)2?0* zeOSKMmT3yh85N)Ys0%B%23*KD;L_4MbTYNc`0$M?o(=Nqy$%_yvrTVr*s=Hh*2_P> zY^qZKpUH6ZgvYftN9UYd9cL-~I%Z!@W#>8TE9W^D7nW&$EAKsQ@YtZHuJOU7rewww z7w?^45xUAf<>j36V+_3uWY+KIW!Us^qUVEYu2*N+Z$2{f(oClmW#!1tWhqs)wVyiG z=UHfk-4+!U^^>|=?#*0N#ucW;m+~m!z_ME>1Uy`o)DsjmxK5e|d+leRV-mDU=QxAb z>WF1c=N+Z^x9b#E&#y59Ic{ZHN^Q)lQ;|<M9Xobx_0E;gE-l(+(NXHVwW8`j=Mvkv zf}5foPghQ#ohWofY0IfX(;DL}rSn}3z1JSx+@x#e{!%;p*~6|?O2>cCx%G6zYlE97 zEUr$QWPbeUt1`JQ?{06;&-3-|jd!z+co!Sj{;pi@!>5ggGnk~F&$d+8`T4$8>V%}T znZBdWic^7?FJ8TB8JYaxw0Rhp$dvH<9qlrD=Y{QL51(=kt@yFImn()pVcTRi;f69J zzv>;U`}L-stUR;5GVJEnt4DW+n@-!-aNe$tBX)UkgFVlWrl4+~{SJ)r5it$7rMd4O zf7!?Jc;CJ^uiGVf)t^u7OMZBU>CN35?L(Gztm`W`WM5x*Ep&C5Eyn}ZhrYhmYZm2a zJk~5MFE96xjg>7bE)KQ$%l6@ad`!!-UrY+NinCZIDZRXNYRS%H<>!CD(=>T~OUYus z|HiozVLEFLbn~xwI`FzMsQp8V0{6_A56}O)T|2Lwx6$fU^R=6s)7@{~x@94EgoC+% z+nMA3-%66JSNCuRpS{^|y`T9wPtVby3F{b}U$gCf)$DQJM~;s_!lB5?R{TTCho#Rf zf4oay7dl(*`@@X}Je-I1PdF{({$;m-KScb)lo{-68Jc8eW$(<kdOb<_FsIG0<=d}b z^MAzrqozTzX?mw$fo@Q+S~lxDS2p?hh+g)*=#E{doR<6gP2VK7V6)Js+M1%{eX?Kv z2|hgIlYijL@z>dv7fx;V;>)VN@#Mvgml9>NQU@BhvweKO+3?1Ptn<=*_E+wtF5YLu zfBISIgUQ~n4VEuEakr0&zt!o~XI)+0+bsY18U88ubbkNa>Ly(%>fZ@AZr{@1zkbbW z*5CfiJ?Mqhj44))<!+O-1fIGkUYYWYvw$(n`?GAqccYn)d)N$~&oq1c_H8}ehh=U1 zzs#TUW9qW~`{%Q7I5%awZo2U#U0ZF>ke{{<%;l^6eZ>DSoXyMWvE0N)@7~M8`X`gk zx4GA`o0^%q3GCo@yt`j;)`1WMi9Ij+Yg%?Iyxf~HH)E=dk*!i(b>uza^qklyA?N4K zn6crh&E;t!o1aQ=)IE07=*Qa-Emu8NyTj=>*=}FTWz(C|uK8u3eaY*`@3aDS{m)dq zI8rPvSNq|ML;iuQW)rM6^W1jKdp;>*y;ilW`q%Fdf2jVwu$I62uinp?>v7>{JDzkZ zEiwx9(AMF~YG~1TcPaDYh76}EVyQ06UeEHf-a2i=tYE1J6Bi{mt%*IQxaPIhgQn#? z<!_CqJ=!}j$74oR*te}szMYfS+`Y74b&FB(GJ)Je#-9<p*WLZ(AGmw|LCXa*bNsbu k<~iTpIxRK*@FV-4KIvlt8|o%AFfcH9y85}Sb4q9e0QrgAIsgCw diff --git a/src/org/controlsfx/dialog/dialog-warning.png b/src/org/controlsfx/dialog/dialog-warning.png deleted file mode 100644 index a374f4f7075eb7a97d5f69ddeeaca35be7ab8ad8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2443 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4mJh`hH$2z?F<Z@L7py-Ar)~~BWry^Zi?E! zPi{+fXnPqX$jY{4cjQkE!$m7siw1gUO;z*#UvT?}V6X4hAFh9H{5|Z_TR8hmcJ7h` zdEtwEXWv*-_BUhJE!|#@YgaGj1)c6X85AKV(9C3f=FIHM&vsSkEWUqCbCZxrP`CZ~ z<X+|bd#``ay}$GMz0VIyV%z_x3nuclJhsTvS)sYYDvKd>CU^SB%{e<dW;Nekx*|Jp zzw|Y&D!2C;K1B>i%<pxb4e##mE}vsv{_e`%-R1R0R#w0GURl1nY+U7@oRL$+ctmP` zm#=GS=~wCUcXur7UR+q1uOGi}PmG9by8=gFS65dN$S|H>-t(Sz4Fw)k@||~9eSNj> z%9W7glhyqb3JL_=+}xaQ-M`OYTU(p3F+#?q?bxL`AMPwM-f-b%$+}hR*Z-IMcG)0> z!Cafsc*^t2fKbu4wl)O`o@Ey!W;qv6=4|NkUVirGl`CJ`u4Zkm-Wz8$O;VP*>DI%C zi4Get%gpl5R$*mmZ}L6ZCu?mM78)ArF-as<r=j(86Gz-D_XdS&8GL7#nr5s`F>sit zZC(8>r&s5+h}q+N*Y_rT{?D7!80Nvh&9SXWn&pFQ%jDZ{+qU1gi+0Yw5EZY%@a%8x z?{B#g9ZiL~pX?g0UgnweiKoO@>F7U$C5jUB<kLGCQquJ!JhIQUu-38N)3+>p^MdV@ zUFXBvm-Y+?6)%L^uS(HaZpYgF=K_P*qoSP;)|zMU_smv3#dNn-=wsc<dA8MAhO^&% z`u%r7rql(iU1AKi3j`hb?bN3yv%LPnf4qUi?swRQl8MLKOAa=%7JPVcaM`hA$I2NN zIJ?h$yIVkVjeF((FE1`G4((bbq3Ecv<zm>DT9$N<C4rYYTe!qt$}242$EVW68pX|6 z!@)3rVc*#@4o;RsPiobx{!4d@>+7+ID1Y0jutIseM#-U9-8{-i#j{-B-*<c<nk;8H zWB&YjkL*jgj(mtQNN}8b_TF)`L%$C$v}e}PyWl+U`N7A}ADY)cY)FYVb%<KUwqSCV zV}bI8o>v!aL~dQ++<d_Qp)I3;wYBxyGrwJ3U0a{^o_@*5@?m*les<lD=gypRUu~{` zYv0#VK4-V2;wck*K5pamhUBWhzrN}}&Wv`Or*wWMzwZAB><dmRAJ}-~_;WpT{z*p| zJF9yR#T$QXTvy#7?|Pu`y#!BRZ?EbRCVN%}8@c~Z-rn7xKRi5qf6<NQ%^er{SBWpV zr}jxltGm*kC6$xWCfqXN7XKBkxCy)KS@!4|s;iu7l3<t7EPr^YwX$Nd&ao{!+l=^A zt=JCye(A6H;SFDhnL3BQ?h(mp0(qf=7giX!u{tdOXyO0$yYjQVKf2Ag{(B32>c1St zqNFJH!{Vm9!~5>-d3TGhUAeO6?CH~|)fsf&uihkWGyk8Gh*;P6{Q?sIIHqj$3s@TW zp>p1&aA)Z&wwKtuehW`<elOqJ<L=1to^kolp1lt3N*gznzrV-Z)9NBAAi*rIA2;Xw zkB^ThfwJb@f6UKxvzD%#-z-+rsJN?1u8v3Lu>Yk6n=iAeyi1a|`|h;mMVGYW6=m+@ zJ*F?+s-K*gSjx-GTc4`qGo5i>rTl5fja#=~-C6nh*{M5s?$j_HIOHB~qfk1(owKD& z+{4>jnfI%@(9-o2BMiPdDF`sE5tZQn`7uHup1~uf>gT7_-v<sjXkOc#ePe3lQva39 zC+@M=WSD(c?49(z`BPZ8Z9D$haPtLgN$x)^$GCSaJaT(`zO{MYogHNt7r9olG*re1 z?-BU%$F{*!%ZW*ogDG=`{Y)17e3rQHo3HqU-kuWqz}GO}ka0uI?y|Fer8y_p#qJIZ zjxl<?lJ|>QgPMKwO`+IA#g1JaTIZgBZjI;&*B4;$-ts7g`>0)=<BB7%>*SsmrR`Z( zaUuDAkecGZ#Az&yCJf6xpY@1LXJtF!mBplBW^SJT?c29$dH46#nl5#GRvWbRee9Qi z!D)ZiY*P4s&2`GW7dv+7NbndaNW9j}&CNY`>eMMyOH0e0C)#fQ=2(#Eb!_?aRfd0m z=v)!z<~cGYLLe~Mr!sy=`TKc)4>q%}Ph$Hawd`WY9{#_)3)tHewSppzxODm7tg+V> zThn?xQb|Ef?W{-0#HYrO4cS+3-MY0kGBR?v{~U{twR`L&O1S3m{MxU@5F&nNX+e@& zN{Ag3Z&1%FU1eovJ{gMwM#q4w-#Yt*YBL0nUz(~NUcobe(Om2Db%(TBDr;?O*rcA{ zs5o{=gT>C;f6eUfd7R&w7(XofwPDNWt5>h?-Bb7XSLlq&InT~|Ulld~VOJ9<^y1*z zHNQDq3iU)pM2@^;WosxoJx#Z!y83tcxA*tsJ?Ar=t(0f0H_d%-FUxqNZqAfnm(vg4 zFP@kCtTQr!p}^t6v$L};D-xsom***NN|f-wC*D3QVb`T=d>=M+Px;lkp<rHwfrCbu z&|xNKg=tf#3NA8o^4OSv?)RY&?}fYmUKM5V?($eU|3=&d_WuqHXELX54Cu;A&I~!Y zB{O<g$xH2!*JY)pu1oyx{Z&*^isWmE|1XiIGV6EpgW~OyM};k?<-}}EIy&k1_xIZa zzHDeZwlDAQuJ9GYweJ}pC`1aC)aKk{XA{`-Xit}~+Si{2I<=WMH>Gw*RHYsZmfn!x zn9_N5qs_C=Hk|*Cs`JmD{?YvWE5?IaTf0mSJS<>HRTOh$j22zts;ltB`ong&ZWry{ zdiyu@+S`@MbS7vsDb{xG{Ab3s_{*0sB8S>fUG(&s%w^D0*D-yExvJ+QD=RCBN8;N) z&OcjY!)ZKk>mrS|SKNOV{k5BS%Kq^4xrbH;FMsgm<>jLC^6z`rMsE*GNl&+4F)68D z%Sn;pnc2V1GyD6~S|t6i&XPXAMvbLJKKHvZ16S|MmoGi<ZpplyUAFu0(lcj#Ze1wh zQj=v#b`6~J;N)a=`vXx=)fh??8Ri;S&V00L%bq<omwTnn>l)?<6fwGnhB7&Acls>< z{!HAg&FRmAM4WGTx8KOukKI)w$#Co9G()j;pPM^B-1_tL^Y?j{#m~wstm?0{FIx1% zQ(%u^Pr|<c=5+zTAD^14?azGR^@^2gvn83+ZgG@}W$|T|?Kqn<|K{2FHy)Aqmk3-n zx|kg8ymf`$@3+pfCNCKtO**Ke!@Y5l-L4(m7v1t$JdfM(?~QaO=5!+;*U+R}H|&1v zwmNz|yzh9qdgd(-HlOdxeUeAA*p?Oc^qI|R>Hf6KO0eNYx$ufSy^MeCHnJLLo~V_5 RXJBAp@O1TaS?83{1OUg^i?ILz diff --git a/src/org/controlsfx/dialog/dialogs.css b/src/org/controlsfx/dialog/dialogs.css deleted file mode 100644 index 2e93ee5..0000000 --- a/src/org/controlsfx/dialog/dialogs.css +++ /dev/null @@ -1,13 +0,0 @@ -.progress-dialog.dialog-pane { - -fx-graphic: url("dialog-information.png"); -} - -.font-selector-dialog.dialog-pane, -.login-dialog.dialog-pane, -.command-links-dialog.dialog-pane { - -fx-graphic: url("dialog-confirm.png"); -} - -.exception-dialog.dialog-pane { - -fx-graphic: url("dialog-error.png"); -} \ No newline at end of file diff --git a/src/org/controlsfx/dialog/fewer-details.png b/src/org/controlsfx/dialog/fewer-details.png deleted file mode 100644 index c45d4ac09eaa74b5ab9894fa5eef2f28e9c46376..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 933 zcmeAS@N?(olHy`uVBq!ia0y~yU=Rgi4mJh`hLz$=r!g=vFct^7J29*~C-ahlfq^C6 z(btiIVPik{pF~y$1_p&>k04(LhAK4%hK3dfhF=T}3=J<B7)lKo7+xhXFj&oCU=S~u zvn$Ysfq_A?#5JNMI6tkVJh3R1As{g`uSCz!HAJDzSkF|?c)`oas|*ZG|2$nBLoEDj zr~3LwIf}G(>&-IBbh@OLyDR_FT<-F}tg&CrOD@-6%JaO^`%!#_qfn=Y>Oq0n1wR_) z6;`Ndm@Znu;_^}W#7mpyXP!2>O@4f5r}5`A)%SK5f7ny?@cpMxpEgU%8B8?!c)i8o z?(45zlAkYJdj6BMZTh<er=2n1jyx`$IcLt4jT;R={;aum>G@vC|Ebr$%&y3Pl>2*T zT{`pag}q0UjEszwK7al^>HPCR)wN;X(Z4QcgdCrle($f@$BnwLmS^r?k;QFeZ~y(w z*|VMo5>r;M)@C)8;@!D_|Mc6pqj&D!J-NM|J=1J<(CVuxRaH?l>dVTmU7x*@IqlG+ zM~e>0$;*qn+_`hdV{hE`9sBlO<9*A<&CShac7fl&Ce=WMOY?%(W&;N?Hi4;EvqIl8 z^d(&@|C#Ai-|p_?wop1PG?94~BjcJ7t)jxhg|(CSRh@Zgm8q|<zxwBjEe@+Y?4)`5 z_^hOvOc)H)6_zhwKFifYM$BT>w0dD-;i7_q1?>r!T^JqiF>Y~`&ku~$n)>9)6PNkr zWo0aV%(AkwSFbQe?VrcI>tG7ghaW#87DwoC$*^0Qm@KKA$kn`r{mNQ_(!I4)(u^cS zPexh9dNCRnl$3nY5%^zqaE0&Eph;)bmIi2)Xdms4(Ob^-@!DPq?|?1)_pjHjT`jTN z%*?Fh?6+^*diwjzrxayP^l;H-$P;IF`1|hNx>brF1Y2cPBG;~8|61MD*!Z$#ZM4mg za~>02D_oXb&Q$l9>>&8++O=ybrKO>+GIDaKK725ke{=piZim7LX$z9_^ZmDN+h$^B zZf?q;I@vRH+onxQoi0wtPiAFhof4aF&UZzO`JKVkPU+^4D>iloux4atdNTKKWV?N< zeE<2Kzr{{)Kkf}%>7cOSzMQ=2Qof}P0baWf+_>`o`)#eSkC!H$=Y4&c%O;6A=!mhy z93!(c=gz&V*gbER({_vH)4uUZT>icCLrvZt5iNV&zhzJB->zD?ZQj4_2Wq3f-Ha_b uYiuvbU^nwe)}!5>`L@No>K6ZF+<g7U#tGi9wHO!}7(8A5T-G@yGywq3?4VTu diff --git a/src/org/controlsfx/dialog/license.txt b/src/org/controlsfx/dialog/license.txt deleted file mode 100644 index 07c519b..0000000 --- a/src/org/controlsfx/dialog/license.txt +++ /dev/null @@ -1,7 +0,0 @@ -Some of these images are from the Oxygen icon set. -Oxygen icons are licensed under the -Creative Common Attribution-ShareAlike 3.0 License -http://creativecommons.org/licenses/by-sa/3.0/ - -For reference, these dialog icons were taken from -http://websvn.kde.org/trunk/KDE/kdebase/runtime/pics/oxygen/?pathrev=706996 \ No newline at end of file diff --git a/src/org/controlsfx/dialog/lock.png b/src/org/controlsfx/dialog/lock.png deleted file mode 100644 index 9a7a9f651dd1c5e06ba6823b44e19deb60f1e6d4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 242 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG zEcbMA46*2aJIR~tkb{7WywLTkwvI=)v|n6u)mwP{L;37Cu4fLq8Ay~SuAIEl)cKm2 z$kCE=(JvPglG#KWgt@OS+Q6XoKx_lkG~Z_;7N<9`{d(lKHOM%A<E4bWFGc!4TKx=6 zrpWa+G?#qQR+u=ihe7>qR2$0-X6C)i9rQV7cmyjje>?E>=ABPJU;EzqseR>J*O43i u8NKxftRLJu6#Y5HMo;$}+Z>xajH!WUPv*FKKW1QHVDNPHb6Mw<&;$Tu-D95s diff --git a/src/org/controlsfx/dialog/more-details.png b/src/org/controlsfx/dialog/more-details.png deleted file mode 100644 index b8896c70d7c216137b48d95a346c37f59a7b9588..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 912 zcmeAS@N?(olHy`uVBq!ia0y~yU=Rgi4mJh`hLz$=r!g=vFct^7J29*~C-ahlfq^C6 z(btiIVPik{pF~y$1_p&>k04(LhAK4%hK3dfhF=T}3=J<B7)lKo7+xhXFj&oCU=S~u zvn$Ysfq_A?#5JNMI6tkVJh3R1As{g`uSCz!HAJDzSkF|?c)`oas|*ZGFFjoxLoEEK zPRaD1?I>`3_L8*;nH&EK?9=}_i}9=P2jPqWMMXDG7nk@IfsaMsv+y^i?|CHJ8@TMZ zw6TBqK__{Md2?;+tUu4c%X>9zYk<3Z`-lHeYQOyaSHJcC;hc{@e^zE>WqAp8wtV^a z%}Yn@vc28kyg#?wrT4Z!>hJIO_V@4a>Fqsv?i^p_iPNXM|9vdpIj7I~{MXu#4^Mqw zcs0w^#K=f#Wr$Z^UY^L69J8k%KL)<~y35AK#$)lt3D2LW@7%X<T8fe88GBn>-g*gB zVKsGi(QjYAEKzv#?_b=zckiy`<>!|=-%dzMaypoAWY&K0;lo7Ms1!El6oUqr%F@!M zMGWdm*Vq$G7HVW1Nm2Te$d<^%!S><Pr=WA^&Rr>gx%yZm%eu|EX=!dp)x8>Cv`v%P z=g9DIvtjX#4?liHY?hFf6}9LSUl{Q4-@m$>ckf>9^kER|b-Vh)`E++T_ut32C5&Wc zWiyXtXJ<39&kM7c>(740;L8-9k#MX=;qQyef`SEQ6%`r<P0ClVUR@fhCd#JkEAKPq z{ol!xg(KtRuWLkdt2b<7R$$Yb+V$rB`{HDiSoxIPU%U}IVyVf=&e!*Jis*VRoz!%3 zT6D19^isvl-w8El>W8LI6^)FExnjEI_pe|7+`O)Cy1B-Sp{BYzdfT>bDaFOcEA$dp z`6halS5`)fiHR)<(0DP?Yx(7{zt^*01@#u3yJN~Lwy~hJG?aI)rUL867tfwQPtD8o zYrb*&_T+c(@>G8RdG_wJMS*cgn?@%~bW~K3vTt`zSy|YppL_b0FFts%z*bLiFGJZ@ zi!FB&<J9=94+;0Wx`Z?=TfY421diN^YfHc1{v$1FbIwnim7kY4bCpb1m)nwtjwvOL z8($tc(6Be??f;tSO700vy*C;}F7gP3y0!VJEq=WAyUCl>-?zS5Ic+&xzNr3r>+>Cj z|0;g|e7rsG-+HtCU&9wT-j022UViN+fBM`PuYH#+dbYXan}7QLsO+W$o?q;Xg$^8T UJr<nBz`(%Z>FVdQ&MBb@0EM!jYybcN diff --git a/src/org/controlsfx/dialog/package-info.java b/src/org/controlsfx/dialog/package-info.java deleted file mode 100644 index 0d1019c..0000000 --- a/src/org/controlsfx/dialog/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -/** - * A package containing a powerful (yet easy to use) dialogs API for showing - * modal dialogs in JavaFX-based applications. - */ -package org.controlsfx.dialog; \ No newline at end of file diff --git a/src/org/controlsfx/dialog/user.png b/src/org/controlsfx/dialog/user.png deleted file mode 100644 index 2bf6711963aceab5b3e5fc2fd255dfc519e3f32c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 420 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7Sc;uILpV4%IBGajIv5xj zI14-?iy0VL@<5pJ!s1OC3=9mCC9V-A!TD(=<%vb94CUqJdYO6I#mR{Use1WE>9gP2 zNHH)lDtfv&hFJ9WUbfY94HRL0@IFrXgK?X?OFEZTuUFHI##b{NJEFFnXJ`=&;Ns;K z>{L)%cwu$OwnLS3s_#v_ankc$Z1(!n;_q?GJ2@&%eJ>x@T2}g+kzMfP4M$}sqs)uP z8HzKw^YjY;@=Z6DNw5^wO<<RvapJ?%E4QDq{dL;YcH*4%HSWp(K76m1;5o@MPlT;; z_M-HLxY=ym!g+EIWz>qiua3yPyyZRDr<F+oN#!##6_xC`i#8=)IM_C8+a-?O|BvkB zowe+xgzFJQJ>wTziT0*fw(Ju&i#D`BJMX;qADwqA*B8p9*M(O!p1dXH-qhl1BYpND z_cXVrDXu>Su8SsC<`t^+7o}~Qx-Uey?vd#2O{cH?DV%F=*st01P?xu8|DJR44f3}Z Vd~P}%&%nUI;OXk;vd$@?2>>4MsW<=t diff --git a/src/org/controlsfx/dialog/wizard-page.png b/src/org/controlsfx/dialog/wizard-page.png deleted file mode 100644 index 3c86ba7d4deffabfb3fda82e60f6318eefddace7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5830 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4mJh`hH$2z?F<ZDj+xHR0iMpz3IRp=X_+~x z3=AH;bElPu1m6^EKfl*}?*$<x1=TN7Rh$Z!tUW|o0y{k$0+`xb)XH2~-9!X6!%{*H zFuJ!ZCA*4nH#a3+=lmoPaO_~9i|f<7J=vV^*P4F5H|y{5$on^+Z@+#s{eA8AT?_$# znph5%L@+j(EQ}C&_xfOrknrgv-<c!?82KU?4?IjuV{!lC!gS@&UfY>7S9l!T{Oz4y zL(1;kI{O3Eim&~zpQvQ+tir~?<$Bf3rcO=#DbtkT%||7T{<EC=GF8*4&Cp0}A?Kns zN{^4M&-u3enfC6JGp4IOStu2GPI8aQyq?_w_hzX+T-?L5FlL78gY?BU?5TT0JZCXH z{jPEO@{c(_3<e@I<Ig--TbR>n<SHWhuJaQU1ILsjmV1i$x_??`%wwonmj0xRrPDKM znc(#qnNMGwNc;71bMVh3L+vSteIIsI_?-W;g{RLzykUL*G*?E|$lRG36W^|tdHXi< z+Ov$G`)}Tts|)^Xd!p)h=ts3T=jS>0%!|CA^Jb0yUNMGmDp9j#H}9Jo%CIGu&Ee_8 zHU94v7(THwY`Hh*vs_zF+@vFqc+|PO-@M5wW}Kg`r~ShG_xz^(Q~TR2zt24V?su5= zGI9GxWlvG#RM)4=mM`;mIdg`GZ~FO^zuyJ^KR#fYdG_RCojLOlh<|K-5gPbn3TI1a z#_m>|#)t`eDO@e}S0C0(n5nZ%*3Hcp$taCysBN_j*x|{3BHxz5S(#ZS&%TPO_I0#? zA=in0dotEeTwmO8RQ2!qFL~~muDpjnj!MDLzVY;@6sa!Kkz9PgCFdZM&;<691zaYL zdIn573A{25#s$px6c}0>JOr4hG3$9SWje5Ia<sd_z~yLogR!hRtAOE3W7P!~zb3N+ zwiuT11H1*?JPqy+Tx|!v4H)k=W^y!r5D;DDxN3sf68@P^*94@aI4YeT11v<Ck2-fw z5SZlf^Mcw639aT;3!MXOzbKbT?c#`S{<VPpf`SR#U&h)N!5K`K6M1hiY-_l=!CHpH z{m|(LE)}A4*u@Xre(1GB%#LsSA@PUO9~g96;}1>da5%xie9<j}L;9nO(}V~WMnT2w ziAqbDR=Uobz_&ztXRpV^!Y9mZ?F$oUNQfPieB2({^Drqa@mi9X!PObbGs1ktpP8iz z7&rcGTAFlq<FW|#HTGqkW`eVOb&rH4^e04bn7)zuM&cW58NTBOBp=BX)a{UnG0HPt z$FiOOde82L*N1r@s(q~3qjgW@eG~t|;txqRiu<_gW$NYb_sbvKuReh@iY2>=UvZj( zN{&j1fE34bj=wE}hfD$+SNNAGwFy)niAmDj*muKmkEe{9-((TbHWl$870sDj8bds@ zlw#Fv)%Ge*K53QWUL+Ce5a+*6WxhhZD*q(=fGHYkBK}@7u1+`oEWLI*R60~TFAd^d zk#{9x)r?(pqx|=})OywGyH7Tr{(1W2lWQlho|rxL_4I00|0&m}mrsw^o39?PSnu_3 z*`FOufd?H91~)F=5Vp|m;g&<Tt)8y47EMj+NSc+@nbiEq^k|^!o=J_9whQ^Mba=Vp zlIl`LDW}UzD=+QX;=9G_R_ZMSS$Fd#zb{XIdGw3?i@jesQ&m%=pK3gnc`EgE^Qj=V zLk0;yjDsYX_Dt^C-P8Zs<k`;ikI&yWTb~*Ce~;$WpIUiZHB*(QrcGs>+P}&tH2<o| z)w!#3SNUHt$WqHn%(|KN`>NjR-t)`Pm(M#tH{Rs`lRxdRHtg!G+VLyv>)}_nuO>^) zlG-OFDHSR;-Q<|5<gC0|CucpK_1xt6mW(Lwtt?Sbqn>Y#GnhK_-I<Uy)y>_O3)ilD zyIl98-IBYjZPzBR*c_3**l+VW;n+!f(dLfZW3~sEJNbL-N9f0|4}8DSE^z+Z`Ahb@ z?~krOb>M=+t%PpJ*#}oF>{_@#abDu$hsnyTCa%7ywK!_A^)ZX&ZG~MQ?H)&~ZRniq zImxs4q;K$zEB8VYcAejHo+tZRhMLK0)7{4xZMYK|xyJ3<0?WfTCu$Z~&i<**ZQC8u zJy-0mSiH_#onYP9I`Wa4k*pE9TV8GWb@<kiS=q74wa44C9w%=;x9sk-t!r26-Y?t# zw$^%9?1sByyZv^b|Hk)C>9^W%Lw4KtiuS#H-*1$ZY3y#Py(;+n#ls!vKK49jSFcvz zc-eFL{kf6nG|%y#Tg=TP{z3eTu0+wr!iPI#iYDr%==H=`6fC?FdVA{QsMo*F_+IaQ zUUnq+$lV*ZH~;SVt<CSvKheGW_>|?7pG%$Rj_a7dK73;M`t6gxC%w;lzueBsuG6m9 zPIzD0zSXt*KN9~k{Vn@-_w)4+&wpM2?ayMtvWD{o*Af;tmN0fZZX-@1)>4+k2N@6U zZj#r(6t5C<MU2Vmk8@e84W}tjtmv;|2|XQ?HEM4vcZ62dRg|;nCb_yeAKC5Ef8x>! z_wHUXZ?ST>lkP`due$rXR=ZAj^`0J~6S?_`TTfJv!ZKSid1=vVm9nCh-!I+uZh!pd z5!d5)dd4x+Hov)5wDsxA)92Ssh(8!vs3j*YFMD6$f2Z)Fl}~-veTm;${*>kV<lXJR zCp|x={k->M?2ptx6IrIWY-+jaGW|$wXR_xyPf^duO#Y5rACzv2|J3+o<&+6i7Hb-> zytwjgX3LfzTP{1PCU$Mmjy1Mb->ZMvWU+zsu2Y#;--QY<a=19rN2540ZTF16e?DJ5 zdQ@hsHb-)A&f0V@-92^wslYRW&%QjF^(61K?8(n3f7h9&nU<HP?<@P)_UEAKyKKI- zt=HDY+}`O|9(!=t!>{{Z_vb3)dffbQ+U<02s`UN5u6tJk7X)tDmyogf{j+0EJDma_ z?$tdP&6jgDM>OZ{-L%bXvu;mUio5tV>GY$nNB*jJCcVBNSsVWI?wM~bZ}%?!w)A)T zgEEftJ9l61`W!JcDKhTng>?^N*FHV-Y0;<cyTjk?3rmbHOyJM#PwC%cv|`g<uk~5( zSC_w9@~Tm)f7Y|Tud27doqOx}?d$vR=hk0l>}5X6ZYL)qv#0*V_kirRj=4t@?>t;{ z`26cduXgQEuaB>HdF%0U;(7O0_oc@V^_O0?zH;4sh4~b-L%oxZZG2pKJpb>5ug=xN zt6v5fFW&is#X`~Y<D=t0<loQZvAJ2<RlDk?`rrBAwq1zoiduN>&b7{MOUyE>eX8%j zY`8pE_MEJ){p|lWUwXdHoVEE>y7&2s=S1hswwzyH_sQv4>&Na+@ph~561!bno?M!{ zZo|5JryHlQkNdc@Xyxs_zyE|zU!A_rGS<3wZtdQ;ZGU^O$?cvuE&fei=F6?`bN9Y1 z*!*|e<F$SJSZkmEiv6vB@7u20r+xqDN;7w}{d%Xjulj%79ov_+_x@gFU&$Y5f2PXf zZ^qx`H;)&obNOq{TV=oY@6{jI(^l^N@@B#Hg!7v_()-(XIP3qP`g6ViVb=32&uhDF zaeL*y*8P0X&z`$g8^0X=aJpyu<;Si2HUDk<KK0`2`E}*L_ogSEJn|v?;_I3AUiVh) zv;1}KTki9e7f&viXTD#yyzAcTefHlP|1SKU{N?z>mv8)k_)neRYhPZ&`R7xGT5j62 z``=qW|2DFUtYcu{aqx6;49Q@98=0LGa$MAI_v^b~xeab~`{v}#`ta@6#Hd>rPF%3h zoH}L7lx-d>Lqat}x}>gn)w**1@mRz#aZ>!$OD-$9UOH!LtMW2URnwZfsww&tgV$Tr z1f8b%>;w8AZomHe?%VHkcXsZ}Zr=FN{lCGty`Swq*FK*!)7n_ONdL~|1F@M0%ER~C z&ef0E5nyd;xzlv=$tyqp{_{HWbVZ+qZ&i(5yv<y{?aFy)PM);fRQC23oBwxfzk8yL zO@3;Vtr@ed9rQJ{w78x<ecIZ5aKQ)009Ll7rm|l>eSK<dY;2QOhGcO}egD8RAUL@A zc*?sDhv48~Rfae0FLG5?RUf)`i?J3J7e8Nm)I~{AVbZIYFFg+!wKFvyc=zhnt8bN@ zj*lw^8=_gHrKG+&KHfb|FIK9@Magl(jQ2Al-!jHID0QYYy}X{Co&DXR&S>>Totc)x z8F_hnGiS`Oh>D1iSi54yiS6$aQ~UjwJY8J;x5((4e(c`Im#hsM)fZkp%Iz$q$>m+C z;%^qFKdt?m{=_>0W`(;V)6<{7`0$}XM}#Xka&wyR`l+_jHtI~hy}es6{9`Ye{wVeI zwAMXL(N=9w&EIc7-R}E$(hQ%&O9Wni?mD}`^0dHG<3sxc4yecXh@B4Z4?VT&X=_|z z(bH2?JMZ1QXBYAC;?6U??>!=$a@rmw-uiXw)F~&QpzVLR{%hG&xg@l&wupBE!|n50 zN2DH3{m4+>lKMc8K}}M?@T*e%zZ#c$_kKxg#tLn7KGiF2ZuIu;+rtItcio;?z_@d- zE$6PYH*Q2YhlYmE6t~&>_s~IZBO5!;2PLfh1q>m43QJ@nyzN+e8N9R3cnL98Yo7Re zn%nx?!M)RFSncs#w0QC3EDM=+bI;D*Bzy7gI%ZbJe;R7p8^!<3|94OG{Jx7UA2b{I zH5lvr?jK>?|6<9uB@@aym3qC-UXIfF&U!)qsdDF*Q%iEBE!1MCN$jY&@#*D9UCueS z)n)&iSh*L)&413Yes8&_(G??yADk_(LdA;?D7`Ol*m#b?v{YqzrBI6OZ!7+{pKevp z@0!kXT#YT^rn&5nv&CN|8(-Um%_+W^vE{%zvy$2A_d5=Ldf{}|iut!~rqIQDf!+Le zvYK3;8pqW?-fJoOs@n6rB1Xe^dz19VwP*G`P*V7GihosX`J-1N-ACOv7_HrZv;0tv z*786JdHMVP-^6Ux-+X32mn^ujZ26Yuw@Nx9ocP1VPj25IqIEU&=4$Wa=N*4u{oV2B z`K1jXYkOWU{`>LN5(b%<KDXHIGUvwczx&y8?u{b>QBhKdUTu+IyWg01Re(#FMeVN= zU7x+Yb7S^bfBujv**ag#V@sOP|E<r|CpuivKc5q;SH1uD0iF*s3BIn4dv+C1&8fCX ziaArLd}>43mUl;wHYVS4&^h9gv+c|=V-AKp=QeHHw8779%Ok7$HzC{C-M9KF!yOU6 zan|zEqGpBG3s>xvs_X7+#ov~meEhrF$?p1`sTMIE#m{CQ*G>tolrzbD))2@Qdw!;{ z*1>ke>XMwaPF9seN0wckcb$i6#qB=P0}77M*6!a{c(l33Wa(~$T=w>abxO0`e~H(> zoHYIa9Yy=v*PCjX!aaR{r6{R>TK`P&=gEVoFBwlb^5x?}F7ME3eq~I{ZK7BXMjYHB zbbMRl$45sQ&rE%5mj76XDgE4>N`cv{Sj&=+y*=1|LrOx|I@Y6!zxmjeIgzmuU;2+Z zdLA}@E3~pyp|aLQ^?#mRig0ADypF?z$V~x>PY><6^2<HKqNA~KMn|v2)&rHPf(KY` zalPHW@BH4gENV0Kcx3`iTW8dl8GQN})so2&_I8(;QRO*hwr%WArQS_pYd6oyoXTyy z*f+^&@o(+7E#hkgRNQ8#&v9k=nc?Wz_}kZB^0l+z)?Aj$Q-91*nx^P^IlC#7`OJC+ zpSjkKfnmX+4d;|(_X<m`E}gS2tgUOgkF0j{Sw+Jc4ZSKGU32Gs{F1sw==IuY`S+6L zmqfhhToL2UY~%2~C6ck1$x+&yNAt?ErFp*lT(m!Lefn`3WA5z4a@U*`DW@N5E2de@ z^O)Z4_+>(i+*GY2m6d`UR?Jb?l-{9gwpnbF!33?-1&;GLa~{j^8l_ESc9qVS<qFd~ zJyqT|Y*mtetnBp1&kH1yol63m_!5}PkIXC#yj^@a=j6?qH!iffhnlAd9?;Z&wAEq$ zyXTzu6fU1oD7i6#sVUlQs=9$tMEpc;efyn0T*b^rCetSEeP5PUoh&(_Y@x(NKJoCn z`wI%q&6Lf~Fjk+tHZPLJW|K)~%jdT|?s|F3OJ+Rm_*0&=_L!LBWY5!Gk7O!e&Q1*y z;5)$(w($AC3yQISJ^u<xn+G!LMTpz9Zs?jQJp0a>axq4oSlb)SJJ)&@Oj4>~JM}QV z&P(ak)!aFP9)6w*=OuFIS1$_jkNbOg@~6%Bw|aYDpP_v6#F7|c4QEz`vL~5yCQfn< zE}nEF;i}y7$!?J>3<mRD8IC*f%J46^!WU*|o>&oa?8ck7XP5Q3n61~I@<~-u_3NeG zg==h%P2ZWhxb(&`fwqjiR~$E<9x!45>e+d;VNSDd-xBFf91FJ0y)JJy#l1+jfNd+E z^V?bVs!J7a91O|&U81GBb!w&7vW2-J=Sq8|EH$<-sNCbi_CKvZ_0&ogF@Mb_i5vy9 zD_d{dJl0`a(ZkEjyYuqA=V6<71soQ5mvJ^LfHiP-A8Sd%6G<iRGhDShrEh02g&$bq z5Y4*IaFRy&b(b?+q9!qg1WMXk8=rQ_$+(?S^lYvxgKPWmU%z66KYUX-a#`#j$E@Gw zR|S%<PAX*G+M(L0Z@&Hb*XQg{-`1C%KKYrMp}Bs-f>aTMB(~ROVTMs|-cEMbts5;> z*rW??_&Y6h&zV;!*4Qg;Zg${&TS4`*+={Os1<tKxS$}XVgYSDAP4{fBBCp-<_U|Td z?~9#yS@(u?<Ag{C1=r5a>o>}LuG(<1=<@t1r!X_O<?G@*I=5FI$v7~hT#QkS@rL!^ zzkl6aPrSbov{WoWw~GDZ7FH&KE9;t!TCPofek%RF{)DGTBV1$34Z{-b79Y7eEo`Yw zmh3^v=4t=#g|FVyp`WB=w*7$T8HEPf`;8Sge({&p_H6%oN_^U`XK4!yncbr!mo!Xu zS@2Q5zINxHP034bzIx0Ies+fWTe|$Dt23VTn$Gag-uYt2w{sm41uv&I{FVs_0F_}T zf<C1j;ZpBnDt>kTUTUE4?kOOnpustJPgz06q`Ev4j<vsf+;)~0sarP8sC3|V;L}~$ zpP7Bi=-1U}Gt3xjgjD!^%jK_K4l;JCt*uqH%X)5}b7MmOcQ>0W|Nl(yeYJj9?KN%D z%XjncXn2@c9}td|xg>n6_u-PbgD;pCr0_%tJxzYzrg}2?_UhePcbsjfp9@~@*Sp~E zuU)%#eS4XZ9?`&iLqIkzKQq&Cvt;U?l3QPU*?sE!-d<gHRVB7b%<)dKt>WA3Zm9(- zEA^6elJA^rDqY+7&x_-dW!v|r*N={NFFsOa{DGx7m}$)c&J6Rs<4L)>x$o{hI_a+U zr2T%>N_o$w2S?H_e4YL7vEtIYvp*9~ZsaRpUe=dk`FpkEi=suFEZcZxstXDX*mSCM zZhrZ(OfN<HV2SFEq|5_X<0SJ=-q}{N{CRz?U)yoDtt(3v|NgqHeKY9f!=p~Sx*xCI z(ie6)O6U0DpI;w+zn-2cmtDtZzaZu)zuMM<r_uL9g0HQ4_~YZ_tr0U{g|Cl`eWAK= z`tEl7srzetq`8?28?+?-io`yq96iuuWb|82_i%T7<+_478}6NsZ92a9jX})vywA_h zM!w$nHv92yp#<ki2NL8Tls7&S)eiH?<qtfbJ-yle_7{eE9=qoAv!=5LHkmcgh>xgS zvg6$CrI*6CZ`<aVaP_70eD{3zd9}}68hBs&{g9G7deDk%dQrIgHAA1j2QI4HbbWiI zlImBoC_3q#)=tC6|6Zlp7Zhx5yym_>e!tx5^XKmy&AvTD@ND%tmK!oEO+Q#u<)__< z-QXs$Uy|ivTwLX6zsIwcf9NW3u6^zAW3l5sW5svr66?m#N(rqWts5J^GygFY;7rbA zDVUwO`ngDdPY*|p?NNOl`#BS~{tokgn#1(Iqe1k<PR97s`n0FA&knV6AGX>3sGZaH z@Frb;r9YvQ45uA+DK9S<+J5ervG#WM;*X`)&%XRv$5GKb*P`%|V@8oSgX_bjsS%E+ z0_7jFxJmXm7B2az+Ut1R-7NRkm-zhu)i0~1e%NO|sJ~o)^Fx&Vm&pta3=E#GelF{r G5}E+$Ni4nq diff --git a/src/org/controlsfx/dialog/wizard.css b/src/org/controlsfx/dialog/wizard.css deleted file mode 100644 index d8e2689..0000000 --- a/src/org/controlsfx/dialog/wizard.css +++ /dev/null @@ -1,3 +0,0 @@ -.wizard-pane { - -fx-graphic: url("wizard-page.png"); -} \ No newline at end of file diff --git a/src/org/controlsfx/glyphfont/FontAwesome.java b/src/org/controlsfx/glyphfont/FontAwesome.java deleted file mode 100644 index 1404e26..0000000 --- a/src/org/controlsfx/glyphfont/FontAwesome.java +++ /dev/null @@ -1,723 +0,0 @@ -/** - * Copyright (c) 2013,2014 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.glyphfont; - -import java.io.InputStream; -import java.util.Arrays; - - -/** - * Defines a {@link GlyphFont} for the FontAwesome font set (see - * <a href="http://fortawesome.github.io/Font-Awesome/">the FontAwesome website</a> - * for more details). Note that at present the FontAwesome font is not distributed - * with ControlsFX, and is, by default, instead loaded from a CDN at runtime. - * - * <p>To use FontAwesome (or indeed any glyph font) in your JavaFX application, - * you firstly have to get access to the FontAwesome glyph font. You do this by - * doing the following: - * - * <pre>GlyphFont fontAwesome = GlyphFontRegistry.font("FontAwesome");</pre> - * - * <p>This code works because all glyph fonts are found dynamically at runtime - * by the {@link GlyphFontRegistry} class, so you can simply request the font - * set you want from there. - * - * <p>Once the font set has been loaded, you can simply start creating - * {@link Glyph} nodes and place them in your user interface. For example: - * - * <pre>new Button("", fontAwesome.create(\uf013).fontColor(Color.RED));</pre> - * - * <p>Of course, this requires you to know that <code>\uf013</code> maps to - * a 'gear' icon, which is not always intuitive (especially when you re-read the - * code in the future). A simpler approach is to do the following: - * - * <pre>new Button("", fontAwesome.create(FontAwesome.Glyph.GEAR));</pre> - * or - * <pre>new Button("", fontAwesome.create("GEAR"));</pre> - * - * It is possible to achieve the same result without creating a reference to icon font by simply using - * {@link org.controlsfx.glyphfont.Glyph} constructor - * - * <pre>new Button("", new Glyph("FontAwesome","GEAR");</pre> - * - * You can use the above Glyph class also in FXML and set the - * fontFamily and icon property there. - * - * @see GlyphFont - * @see GlyphFontRegistry - * @see Glyph - */ -public class FontAwesome extends GlyphFont { - - private static String fontName = "FontAwesome"; //$NON-NLS-1$ - - - /** - * The individual glyphs offered by the FontAwesome font. - */ - public static enum Glyph implements INamedCharacter { - - ADJUST('\uf042'), - ADN('\uf170'), - ALIGN_CENTER('\uf037'), - ALIGN_JUSTIFY('\uf039'), - ALIGN_LEFT('\uf036'), - ALIGN_RIGHT('\uf038'), - AMBULANCE('\uf0F9'), - ANCHOR('\uf13D'), - ANDROID('\uf17B'), - ANGELLIST('\uf209'), - ANGLE_DOUBLE_DOWN('\uf103'), - ANGLE_DOUBLE_LEFT('\uf100'), - ANGLE_DOUBLE_RIGHT('\uf101'), - ANGLE_DOUBLE_UP('\uf102'), - ANGLE_DOWN('\uf107'), - ANGLE_LEFT('\uf104'), - ANGLE_RIGHT('\uf105'), - ANGLE_UP('\uf106'), - APPLE('\uf179'), - ARCHIVE('\uf187'), - AREA_CHART('\uf1FE'), - ARROW_CIRCLE_DOWN('\uf0AB'), - ARROW_CIRCLE_LEFT('\uf0A8'), - ARROW_CIRCLE_O_DOWN('\uf01A'), - ARROW_CIRCLE_O_LEFT('\uf190'), - ARROW_CIRCLE_O_RIGHT('\uf18E'), - ARROW_CIRCLE_O_UP('\uf01B'), - ARROW_CIRCLE_RIGHT('\uf0A9'), - ARROW_CIRCLE_UP('\uf0AA'), - ARROW_DOWN('\uf063'), - ARROW_LEFT('\uf060'), - ARROW_RIGHT('\uf061'), - ARROW_UP('\uf062'), - ARROWS('\uf047'), - ARROWS_ALT('\uf0B2'), - ARROWS_H('\uf07E'), - ARROWS_V('\uf07D'), - ASTERISK('\uf069'), - AT('\uf1FA'), - AUTOMOBILE('\uf1B9'), - BACKWARD('\uf04A'), - BAN('\uf05E'), - BANK('\uf19C'), - BAR_CHART('\uf080'), - BAR_CHART_O('\uf080'), - BARCODE('\uf02A'), - BARS('\uf0C9'), - BED('\uf236'), - BEER('\uf0FC'), - BEHANCE('\uf1B4'), - BEHANCE_SQUARE('\uf1B5'), - BELL('\uf0F3'), - BELL_O('\uf0A2'), - BELL_SLASH('\uf1F6'), - BELL_SLASH_O('\uf1F7'), - BICYCLE('\uf206'), - BINOCULARS('\uf1E5'), - BIRTHDAY_CAKE('\uf1FD'), - BITBUCKET('\uf171'), - BITBUCKET_SQUARE('\uf172'), - BITCOIN('\uf15A'), - BOLD('\uf032'), - BOLT('\uf0E7'), - BOMB('\uf1E2'), - BOOK('\uf02D'), - BOOKMARK('\uf02E'), - BOOKMARK_ALT('\uf097'), - BRIEFCASE('\uf0B1'), - BTC('\uf15A'), - BUG('\uf188'), - BUILDING('\uf1AD'), - BUILDING_ALT('\uf0F7'), - BULLHORN('\uf0A1'), - BULLSEYE('\uf140'), - BUS('\uf207'), - BUYSELLADS('\uf20D'), - CAB('\uf1BA'), - CALCULATOR('\uf1EC'), - CALENDAR('\uf073'), - CALENDAR_ALT('\uf133'), - CAMERA('\uf030'), - CAMERA_RETRO('\uf083'), - CAR('\uf1B9'), - CARET_DOWN('\uf0D7'), - CARET_LEFT('\uf0D9'), - CARET_RIGHT('\uf0DA'), - CARET_SQUARE_ALT_DOWN('\uf150'), - CARET_SQUARE_ALT_LEFT('\uf191'), - CARET_SQUARE_ALT_RIGHT('\uf152'), - CARET_SQUARE_ALT_UP('\uf151'), - CARET_UP('\uf0D8'), - CART_ARROW_DOWN('\uf218'), - CART_PLUS('\uf217'), - CC('\uf20A'), - CC_AMEX('\uf1F3'), - CC_DISCOVER('\uf1F2'), - CC_MASTERCARD('\uf1F1'), - CC_PAYPAL('\uf1F4'), - CC_STRIPE('\uf1F5'), - CC_VISA('\uf1F0'), - CERTIFICATE('\uf0A3'), - CHAIN('\uf0C1'), - CHAIN_BROKEN('\uf127'), - CHECK('\uf00C'), - CHECK_CIRCLE('\uf058'), - CHECK_CIRCLE_ALT('\uf05D'), - CHECK_SQUARE('\uf14A'), - CHECK_SQUARE_ALT('\uf046'), - CHEVRON_CIRCLE_DOWN('\uf13A'), - CHEVRON_CIRCLE_LEFT('\uf137'), - CHEVRON_CIRCLE_RIGHT('\uf138'), - CHEVRON_CIRCLE_UP('\uf139'), - CHEVRON_DOWN('\uf078'), - CHEVRON_LEFT('\uf053'), - CHEVRON_RIGHT('\uf054'), - CHEVRON_UP('\uf077'), - CHILD('\uf1AE'), - CIRCLE('\uf111'), - CIRCLE_ALT('\uf10C'), - CIRCLE_ALT_NOTCH('\uf1CE'), - CIRCLE_THIN('\uf1DB'), - CLIPBOARD('\uf0EA'), - CLOCK_ALT('\uf017'), - CLOSE('\uf00D'), - CLOUD('\uf0C2'), - CLOUD_DOWNLOAD('\uf0ED'), - CLOUD_UPLOAD('\uf0EE'), - CNY('\uf157'), - CODE('\uf121'), - CODE_FORK('\uf126'), - CODEPEN('\uf1CB'), - COFFEE('\uf0F4'), - COG('\uf013'), - COGS('\uf085'), - COLUMNS('\uf0DB'), - COMMENT('\uf075'), - COMMENT_ALT('\uf0E5'), - COMMENTS('\uf086'), - COMMENTS_ALT('\uf0E6'), - COMPASS('\uf14E'), - COMPRESS('\uf066'), - CONNECTDEVELOP('\uf20E'), - COPY('\uf0C5'), - COPYRIGHT('\uf1F9'), - CREDIT_CARD('\uf09D'), - CROP('\uf125'), - CROSSHAIRS('\uf05B'), - CSS3('\uf13C'), - CUBE('\uf1B2'), - CUBES('\uf1B3'), - CUT('\uf0C4'), - CUTLERY('\uf0F5'), - DASHBOARD('\uf0E4'), - DASHCUBE('\uf210'), - DATABASE('\uf1C0'), - DEDENT('\uf03B'), - DELICIOUS('\uf1A5'), - DESKTOP('\uf108'), - DEVIANTART('\uf1BD'), - DIAMOND('\uf219'), - DIGG('\uf1A6'), - DOLLAR('\uf155'), - DOT_CIRCLE_ALT('\uf192'), - DOWNLOAD('\uf019'), - DRIBBBLE('\uf17D'), - DROPBOX('\uf16B'), - DRUPAL('\uf1A9'), - EDIT('\uf044'), - EJECT('\uf052'), - ELLIPSIS_H('\uf141'), - ELLIPSIS_V('\uf142'), - EMPIRE('\uf1D1'), - ENVELOPE('\uf0E0'), - ENVELOPE_ALT('\uf003'), - ENVELOPE_SQUARE('\uf199'), - ERASER('\uf12D'), - EUR('\uf153'), - EURO('\uf153'), - EXCHANGE('\uf0EC'), - EXCLAMATION('\uf12A'), - EXCLAMATION_CIRCLE('\uf06A'), - EXCLAMATION_TRIANGLE('\uf071'), - EXPAND('\uf065'), - EXTERNAL_LINK('\uf08E'), - EXTERNAL_LINK_SQUARE('\uf14C'), - EYE('\uf06E'), - EYE_SLASH('\uf070'), - EYEDROPPER('\uf1FB'), - FACEBOOK('\uf09A'), - FACEBOOK_F('\uf09A'), - FACEBOOK_ALTFFICIAL('\uf230'), - FACEBOOK_SQUARE('\uf082'), - FAST_BACKWARD('\uf049'), - FAST_FORWARD('\uf050'), - FAX('\uf1AC'), - FEMALE('\uf182'), - FIGHTER_JET('\uf0FB'), - FILE('\uf15B'), - FILE_ARCHIVE_ALT('\uf1C6'), - FILE_AUDIO_ALT('\uf1C7'), - FILE_CODE_ALT('\uf1C9'), - FILE_EXCEL_ALT('\uf1C3'), - FILE_IMAGE_ALT('\uf1C5'), - FILE_MOVIE_ALT('\uf1C8'), - FILE_ALT('\uf016'), - FILE_PDF_ALT('\uf1C1'), - FILE_PHOTO_ALT('\uf1C5'), - FILE_PICTURE_ALT('\uf1C5'), - FILE_POWERPOINT_ALT('\uf1C4'), - FILE_SOUND_ALT('\uf1C7'), - FILE_TEXT('\uf15C'), - FILE_TEXT_ALT('\uf0F6'), - FILE_VIDEO_ALT('\uf1C8'), - FILE_WORD_ALT('\uf1C2'), - FILE_ZIP_ALT('\uf1C6'), - FILES_ALT('\uf0C5'), - FILM('\uf008'), - FILTER('\uf0B0'), - FIRE('\uf06D'), - FIRE_EXTINGUISHER('\uf134'), - FLAG('\uf024'), - FLAG_CHECKERED('\uf11E'), - FLAG_ALT('\uf11D'), - FLASH('\uf0E7'), - FLASK('\uf0C3'), - FLICKR('\uf16E'), - FLOPPY_ALT('\uf0C7'), - FOLDER('\uf07B'), - FOLDER_ALT('\uf114'), - FOLDER_OPEN('\uf07C'), - FOLDER_OPEN_ALT('\uf115'), - FONT('\uf031'), - FORUMBEE('\uf211'), - FORWARD('\uf04E'), - FOURSQUARE('\uf180'), - FROWN_ALT('\uf119'), - FUTBOL_ALT('\uf1E3'), - GAMEPAD('\uf11B'), - GAVEL('\uf0E3'), - GBP('\uf154'), - GE('\uf1D1'), - GEAR('\uf013'), - GEARS('\uf085'), - GENDERLESS('\uf1DB'), - GIFT('\uf06B'), - GIT('\uf1D3'), - GIT_SQUARE('\uf1D2'), - GITHUB('\uf09B'), - GITHUB_ALT('\uf113'), - GITHUB_SQUARE('\uf092'), - GITTIP('\uf184'), - GLASS('\uf000'), - GLOBE('\uf0AC'), - GOOGLE('\uf1A0'), - GOOGLE_PLUS('\uf0D5'), - GOOGLE_PLUS_SQUARE('\uf0D4'), - GOOGLE_WALLET('\uf1EE'), - GRADUATION_CAP('\uf19D'), - GRATIPAY('\uf184'), - GROUP('\uf0C0'), - H_SQUARE('\uf0FD'), - HACKER_NEWS('\uf1D4'), - HAND_ALT_DOWN('\uf0A7'), - HAND_ALT_LEFT('\uf0A5'), - HAND_ALT_RIGHT('\uf0A4'), - HAND_ALT_UP('\uf0A6'), - HDD_ALT('\uf0A0'), - HEADER('\uf1DC'), - HEADPHONES('\uf025'), - HEART('\uf004'), - HEART_ALT('\uf08A'), - HEARTBEAT('\uf21E'), - HISTORY('\uf1DA'), - HOME('\uf015'), - HOSPITAL_ALT('\uf0F8'), - HOTEL('\uf236'), - HTML5('\uf13B'), - ILS('\uf20B'), - IMAGE('\uf03E'), - INBOX('\uf01C'), - INDENT('\uf03C'), - INFO('\uf129'), - INFO_CIRCLE('\uf05A'), - INR('\uf156'), - INSTAGRAM('\uf16D'), - INSTITUTION('\uf19C'), - IOXHOST('\uf208'), - ITALIC('\uf033'), - JOOMLA('\uf1AA'), - JPY('\uf157'), - JSFIDDLE('\uf1CC'), - KEY('\uf084'), - KEYBOARD_ALT('\uf11C'), - KRW('\uf159'), - LANGUAGE('\uf1AB'), - LAPTOP('\uf109'), - LASTFM('\uf202'), - LASTFM_SQUARE('\uf203'), - LEAF('\uf06C'), - LEANPUB('\uf212'), - LEGAL('\uf0E3'), - LEMON_ALT('\uf094'), - LEVEL_DOWN('\uf149'), - LEVEL_UP('\uf148'), - LIFE_BOUY('\uf1CD'), - LIFE_BUOY('\uf1CD'), - LIFE_RING('\uf1CD'), - LIFE_SAVER('\uf1CD'), - LIGHTBULB_ALT('\uf0EB'), - LINE_CHART('\uf201'), - LINK('\uf0C1'), - LINKEDIN('\uf0E1'), - LINKEDIN_SQUARE('\uf08C'), - LINUX('\uf17C'), - LIST('\uf03A'), - LIST_ALT('\uf022'), - LIST_OL('\uf0CB'), - LIST_UL('\uf0CA'), - LOCATION_ARROW('\uf124'), - LOCK('\uf023'), - LONG_ARROW_DOWN('\uf175'), - LONG_ARROW_LEFT('\uf177'), - LONG_ARROW_RIGHT('\uf178'), - LONG_ARROW_UP('\uf176'), - MAGIC('\uf0D0'), - MAGNET('\uf076'), - MAIL_FORWARD('\uf064'), - MAIL_REPLY('\uf112'), - MAIL_REPLY_ALL('\uf122'), - MALE('\uf183'), - MAP_MARKER('\uf041'), - MARS('\uf222'), - MARS_DOUBLE('\uf227'), - MARS_STROKE('\uf229'), - MARS_STROKE_H('\uf22B'), - MARS_STROKE_V('\uf22A'), - MAXCDN('\uf136'), - MEANPATH('\uf20C'), - MEDIUM('\uf23A'), - MEDKIT('\uf0FA'), - MEH_ALT('\uf11A'), - MERCURY('\uf223'), - MICROPHONE('\uf130'), - MICROPHONE_SLASH('\uf131'), - MINUS('\uf068'), - MINUS_CIRCLE('\uf056'), - MINUS_SQUARE('\uf146'), - MINUS_SQUARE_ALT('\uf147'), - MOBILE('\uf10B'), - MOBILE_PHONE('\uf10B'), - MONEY('\uf0D6'), - MOON_ALT('\uf186'), - MORTAR_BOARD('\uf19D'), - MOTORCYCLE('\uf21C'), - MUSIC('\uf001'), - NAVICON('\uf0C9'), - NEUTER('\uf22C'), - NEWSPAPER_ALT('\uf1EA'), - OPENID('\uf19B'), - OUTDENT('\uf03B'), - PAGELINES('\uf18C'), - PAINT_BRUSH('\uf1FC'), - PAPER_PLANE('\uf1D8'), - PAPER_PLANE_ALT('\uf1D9'), - PAPERCLIP('\uf0C6'), - PARAGRAPH('\uf1DD'), - PASTE('\uf0EA'), - PAUSE('\uf04C'), - PAW('\uf1B0'), - PAYPAL('\uf1ED'), - PENCIL('\uf040'), - PENCIL_SQUARE('\uf14B'), - PENCIL_SQUARE_ALT('\uf044'), - PHONE('\uf095'), - PHONE_SQUARE('\uf098'), - PHOTO('\uf03E'), - PICTURE_ALT('\uf03E'), - PIE_CHART('\uf200'), - PIED_PIPER('\uf1A7'), - PIED_PIPER_ALT('\uf1A8'), - PINTEREST('\uf0D2'), - PINTEREST_P('\uf231'), - PINTEREST_SQUARE('\uf0D3'), - PLANE('\uf072'), - PLAY('\uf04B'), - PLAY_CIRCLE('\uf144'), - PLAY_CIRCLE_ALT('\uf01D'), - PLUG('\uf1E6'), - PLUS('\uf067'), - PLUS_CIRCLE('\uf055'), - PLUS_SQUARE('\uf0FE'), - PLUS_SQUARE_ALT('\uf196'), - POWER_OFF('\uf011'), - PRINT('\uf02F'), - PUZZLE_PIECE('\uf12E'), - QQ('\uf1D6'), - QRCODE('\uf029'), - QUESTION('\uf128'), - QUESTION_CIRCLE('\uf059'), - QUOTE_LEFT('\uf10D'), - QUOTE_RIGHT('\uf10E'), - RA('\uf1D0'), - RANDOM('\uf074'), - REBEL('\uf1D0'), - RECYCLE('\uf1B8'), - REDDIT('\uf1A1'), - REDDIT_SQUARE('\uf1A2'), - REFRESH('\uf021'), - REMOVE('\uf00D'), - RENREN('\uf18B'), - REORDER('\uf0C9'), - REPEAT('\uf01E'), - REPLY('\uf112'), - REPLY_ALL('\uf122'), - RETWEET('\uf079'), - RMB('\uf157'), - ROAD('\uf018'), - ROCKET('\uf135'), - ROTATE_LEFT('\uf0E2'), - ROTATE_RIGHT('\uf01E'), - ROUBLE('\uf158'), - RSS('\uf09E'), - RSS_SQUARE('\uf143'), - RUB('\uf158'), - RUBLE('\uf158'), - RUPEE('\uf156'), - SAVE('\uf0C7'), - SCISSORS('\uf0C4'), - SEARCH('\uf002'), - SEARCH_MINUS('\uf010'), - SEARCH_PLUS('\uf00E'), - SELLSY('\uf213'), - SEND('\uf1D8'), - SEND_ALT('\uf1D9'), - SERVER('\uf233'), - SHARE('\uf064'), - SHARE_ALT('\uf1E0'), - SHARE_ALT_SQUARE('\uf1E1'), - SHARE_SQUARE('\uf14D'), - SHARE_SQUARE_ALT('\uf045'), - SHEKEL('\uf20B'), - SHEQEL('\uf20B'), - SHIELD('\uf132'), - SHIP('\uf21A'), - SHIRTSINBULK('\uf214'), - SHOPPING_CART('\uf07A'), - SIGN_IN('\uf090'), - SIGN_OUT('\uf08B'), - SIGNAL('\uf012'), - SIMPLYBUILT('\uf215'), - SITEMAP('\uf0E8'), - SKYATLAS('\uf216'), - SKYPE('\uf17E'), - SLACK('\uf198'), - SLIDERS('\uf1DE'), - SLIDESHARE('\uf1E7'), - SMILE_ALT('\uf118'), - SOCCER_BALL_ALT('\uf1E3'), - SORT('\uf0DC'), - SORT_ALPHA_ASC('\uf15D'), - SORT_ALPHA_DESC('\uf15E'), - SORT_AMOUNT_ASC('\uf160'), - SORT_AMOUNT_DESC('\uf161'), - SORT_ASC('\uf0DE'), - SORT_DESC('\uf0DD'), - SORT_DOWN('\uf0DD'), - SORT_NUMERIC_ASC('\uf162'), - SORT_NUMERIC_DESC('\uf163'), - SORT_UP('\uf0DE'), - SOUNDCLOUD('\uf1BE'), - SPACE_SHUTTLE('\uf197'), - SPINNER('\uf110'), - SPOON('\uf1B1'), - SPOTIFY('\uf1BC'), - SQUARE('\uf0C8'), - SQUARE_ALT('\uf096'), - STACK_EXCHANGE('\uf18D'), - STACK_OVERFLOW('\uf16C'), - STAR('\uf005'), - STAR_HALF('\uf089'), - STAR_HALF_EMPTY('\uf123'), - STAR_HALF_FULL('\uf123'), - STAR_HALF_ALT('\uf123'), - STAR_ALT('\uf006'), - STEAM('\uf1B6'), - STEAM_SQUARE('\uf1B7'), - STEP_BACKWARD('\uf048'), - STEP_FORWARD('\uf051'), - STETHOSCOPE('\uf0F1'), - STOP('\uf04D'), - STREET_VIEW('\uf21D'), - STRIKETHROUGH('\uf0CC'), - STUMBLEUPON('\uf1A4'), - STUMBLEUPON_CIRCLE('\uf1A3'), - SUBSCRIPT('\uf12C'), - SUBWAY('\uf239'), - SUITCASE('\uf0F2'), - SUN_ALT('\uf185'), - SUPERSCRIPT('\uf12B'), - SUPPORT('\uf1CD'), - TABLE('\uf0CE'), - TABLET('\uf10A'), - TACHOMETER('\uf0E4'), - TAG('\uf02B'), - TAGS('\uf02C'), - TASKS('\uf0AE'), - TAXI('\uf1BA'), - TENCENT_WEIBO('\uf1D5'), - TERMINAL('\uf120'), - TEXT_HEIGHT('\uf034'), - TEXT_WIDTH('\uf035'), - TH('\uf00A'), - TH_LARGE('\uf009'), - TH_LIST('\uf00B'), - THUMB_TACK('\uf08D'), - THUMBS_DOWN('\uf165'), - THUMBS_ALT_DOWN('\uf088'), - THUMBS_ALT_UP('\uf087'), - THUMBS_UP('\uf164'), - TICKET('\uf145'), - TIMES('\uf00D'), - TIMES_CIRCLE('\uf057'), - TIMES_CIRCLE_ALT('\uf05C'), - TINT('\uf043'), - TOGGLE_DOWN('\uf150'), - TOGGLE_LEFT('\uf191'), - TOGGLE_OFF('\uf204'), - TOGGLE_ON('\uf205'), - TOGGLE_RIGHT('\uf152'), - TOGGLE_UP('\uf151'), - TRAIN('\uf238'), - TRANSGENDER('\uf224'), - TRANSGENDER_ALT('\uf225'), - TRASH('\uf1F8'), - TRASH_ALT('\uf014'), - TREE('\uf1BB'), - TRELLO('\uf181'), - TROPHY('\uf091'), - TRUCK('\uf0D1'), - TRY('\uf195'), - TTY('\uf1E4'), - TUMBLR('\uf173'), - TUMBLR_SQUARE('\uf174'), - TURKISH_LIRA('\uf195'), - TWITCH('\uf1E8'), - TWITTER('\uf099'), - TWITTER_SQUARE('\uf081'), - UMBRELLA('\uf0E9'), - UNDERLINE('\uf0CD'), - UNDO('\uf0E2'), - UNIVERSITY('\uf19C'), - UNLINK('\uf127'), - UNLOCK('\uf09C'), - UNLOCK_ALT('\uf13E'), - UNSORTED('\uf0DC'), - UPLOAD('\uf093'), - USD('\uf155'), - USER('\uf007'), - USER_MD('\uf0F0'), - USER_PLUS('\uf234'), - USER_SECRET('\uf21B'), - USER_TIMES('\uf235'), - USERS('\uf0C0'), - VENUS('\uf221'), - VENUS_DOUBLE('\uf226'), - VENUS_MARS('\uf228'), - VIACOIN('\uf237'), - VIDEO_CAMERA('\uf03D'), - VIMEO_SQUARE('\uf194'), - VINE('\uf1CA'), - VK('\uf189'), - VOLUME_DOWN('\uf027'), - VOLUME_OFF('\uf026'), - VOLUME_UP('\uf028'), - WARNING('\uf071'), - WECHAT('\uf1D7'), - WEIBO('\uf18A'), - WEIXIN('\uf1D7'), - WHATSAPP('\uf232'), - WHEELCHAIR('\uf193'), - WIFI('\uf1EB'), - WINDOWS('\uf17A'), - WON('\uf159'), - WORDPRESS('\uf19A'), - WRENCH('\uf0AD'), - XING('\uf168'), - XING_SQUARE('\uf169'), - YAHOO('\uf19E'), - YELP('\uf1E9'), - YEN('\uf157'), - YOUTUBE('\uf167'), - YOUTUBE_PLAY('\uf16A'), - YOUTUBE_SQUARE('\uf166'); - - private final char ch; - - /** - * Creates a named Glyph mapped to the given character - * @param ch - */ - Glyph( char ch ) { - this.ch = ch; - } - - @Override - public char getChar() { - return ch; - } - }; - - /** - * Do not call this constructor directly - instead access the - * {@link FontAwesome.Glyph} public static enumeration method to create the glyph nodes), or - * use the {@link GlyphFontRegistry} class to get access. - * - * Note: Do not remove this public constructor since it is used by the service loader! - */ - public FontAwesome() { - this("http://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.3.0/fonts/fontawesome-webfont.ttf"); //$NON-NLS-1$ - } - - /** - * Creates a new FontAwesome instance which uses the provided font source. - * @param url - */ - public FontAwesome(String url){ - super(fontName, 14, url, true); - registerAll(Arrays.asList(Glyph.values())); - } - - /** - * Creates a new FontAwesome instance which uses the provided font source. - * @param is - */ - public FontAwesome(InputStream is){ - super(fontName, 14, is, true); - registerAll(Arrays.asList(Glyph.values())); - } - -} diff --git a/src/org/controlsfx/glyphfont/Glyph.java b/src/org/controlsfx/glyphfont/Glyph.java deleted file mode 100644 index 8bb8c72..0000000 --- a/src/org/controlsfx/glyphfont/Glyph.java +++ /dev/null @@ -1,350 +0,0 @@ -/** - * Copyright (c) 2013, 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.glyphfont; - -import java.util.Optional; - -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.collections.ObservableList; -import javafx.scene.Node; -import javafx.scene.control.Label; -import javafx.scene.paint.*; -import javafx.scene.text.Font; - -import org.controlsfx.control.action.Action; -import org.controlsfx.tools.Duplicatable; - -/** - * Represents one glyph from the font. - * The glyph is actually a label showing one character from the specified font. It can be used as 'graphic' on any UI - * control or {@link Action}. It can also directly be used in FXML. - * - * Examples: - * - * <pre>{@code - * new Button("", new Glyph("FontAwesome", "BEER")) - * }</pre> - * - * <pre>{@code - * new Button("", new Glyph("FontAwesome", FontAwesome.Glyph.BEER)) - * }</pre> - * - * Thy Glyph-Class also offers a fluent API to customize the look of the Glyph. - * For example, you can set the color {@link #color(javafx.scene.paint.Color)} or - * also add effects such as {@link #useHoverEffect()} - * - * <p>An ability to retrieve glyph node by combination of font name and glyph name - * extends to the {@link org.controlsfx.control.action.ActionProxy} graphic attribute, where the "font>" - * prefix should be used. For more information see {@link org.controlsfx.control.action.ActionProxy}. - * - */ -public class Glyph extends Label implements Duplicatable<Glyph> { - - /*************************************************************************** - * * - * Static creators * - * * - **************************************************************************/ - - /** - * Retrieve glyph by font name and glyph name using one string - * where font name an glyph name are separated by pipe. - * - * @param fontAndGlyph The font and glyph separated by a pipe. Example: "FontAwesome|STAR" - * @return A instance of a Glyph node - */ - public static Glyph create(String fontAndGlyph) { - String[] args = fontAndGlyph.split("\\|"); //$NON-NLS-1$ - return new Glyph(args[0], args[1]); - } - - - /*************************************************************************** - * * - * Private fields * - * * - **************************************************************************/ - - public final static String DEFAULT_CSS_CLASS = "glyph-font"; //$NON-NLS-1$ - public final static String STYLE_GRADIENT = "gradient"; //$NON-NLS-1$ - public final static String STYLE_HOVER_EFFECT = "hover-effect"; //$NON-NLS-1$ - - private final ObjectProperty<Object> icon = new SimpleObjectProperty<>(); - - /*************************************************************************** - * * - * Constructors * - * * - **************************************************************************/ - - /** - * Empty Constructor (used by FXML) - */ - public Glyph(){ - getStyleClass().add(DEFAULT_CSS_CLASS); - - icon.addListener(x -> updateIcon()); - fontProperty().addListener(x -> updateIcon()); - } - - /** - * Creates a new Glyph - * @param fontFamily The family name of the font. Example: "FontAwesome" - * @param unicode The Unicode character of the glyph - */ - public Glyph(String fontFamily, char unicode) { - this(); - setFontFamily(fontFamily); - setTextUnicode(unicode); - } - - /** - * Creates a new Glyph - * @param fontFamily The family name of the font. Example: "FontAwesome" - * @param icon The icon - which can be the name (String) or Enum value. - * Example: FontAwesome.Glyph.BEER - */ - public Glyph(String fontFamily, Object icon) { - this(); - setFontFamily(fontFamily); - setIcon(icon); - } - - /*************************************************************************** - * * - * Public API * - * * - **************************************************************************/ - - /** - * Sets the glyph icon font family - * @param fontFamily A font family name - * @return Returns this instance for fluent API - */ - public Glyph fontFamily(String fontFamily){ - setFontFamily(fontFamily); - return this; - } - - /** - * Sets the glyph color - * @param color - * @return Returns this instance for fluent API - */ - public Glyph color(Color color){ - setColor(color); - return this; - } - - /** - * Sets glyph size - * @param size - * @return Returns this instance for fluent API - */ - public Glyph size(double size) { - setFontSize(size); - return this; - } - - /** - * Sets glyph size using size factor based on default font size - * @param factor - * @return Returns this instance for fluent API - */ - public Glyph sizeFactor(int factor) { - Optional.ofNullable(GlyphFontRegistry.font(getFont().getFamily())).ifPresent( glyphFont ->{ - setFontSize(glyphFont.getDefaultSize()* (factor < 1? 1: factor)); - }); - return this; - } - - - - /** - * Adds the hover effect style - * @return Returns this instance for fluent API - */ - public Glyph useHoverEffect(){ - this.getStyleClass().add(Glyph.STYLE_HOVER_EFFECT); - return this; - } - - /** - * Adds the gradient effect style - * @return Returns this instance for fluent API - */ - public Glyph useGradientEffect(){ - - if(getTextFill() instanceof Color){ - Color currentColor = (Color)getTextFill(); - - /* - TODO - Do this in code: - -fx-text-fill: linear-gradient(to bottom, derive(-fx-text-fill,20%) 10%, derive(-fx-text-fill,-40%) 80%); - */ - Stop[] stops = new Stop[] { new Stop(0, Color.BLACK), new Stop(1, currentColor)}; - LinearGradient lg1 = new LinearGradient(0, 0, 1, 0, true, CycleMethod.NO_CYCLE, stops); - setTextFill(lg1); - } - - this.getStyleClass().add(Glyph.STYLE_GRADIENT); - return this; - } - - - /** - * Allows glyph duplication. Since in the JavaFX scenegraph it is not possible to insert the same - * {@link Node} in multiple locations at the same time, this method allows for glyph reuse in several places - */ - @Override public Glyph duplicate() { - Paint color = getTextFill(); - Object icon = getIcon(); - ObservableList<String> classes = getStyleClass(); - return new Glyph(){{ - setIcon(icon); - setTextFill(color); - getStyleClass().addAll(classes); - }} - .fontFamily(getFontFamily()) - .size(getFontSize()); - } - - /*************************************************************************** - * * - * Properties * - * * - **************************************************************************/ - - /** - * Sets the font family of this glyph - * Font size is reset to default glyph font size - */ - public void setFontFamily(String family){ - if( !getFont().getFamily().equals(family)){ - Optional.ofNullable(GlyphFontRegistry.font(family)).ifPresent( glyphFont -> { - glyphFont.ensureFontIsLoaded(); // Make sure font is loaded - Font newFont = Font.font(family, glyphFont.getDefaultSize()); // Reset to default font size - setFont(newFont); - }); - } - } - - /** - * Gets the font family of this glyph - */ - public String getFontFamily(){ - return getFont().getFamily(); - } - - /** - * Sets the font size of this glyph - */ - public void setFontSize(double size){ - Font newFont = Font.font(getFont().getFamily(), size); - setFont(newFont); - } - - /** - * Gets the font size of this glyph - */ - public double getFontSize(){ - return getFont().getSize(); - } - - /** - * Set the Color of this Glyph - */ - public void setColor(Color color){ - setTextFill(color); - } - - /** - * The icon name property. - * - * This must either be a Glyph-Name (either string or enum value) known by the GlyphFontRegistry. - * Alternatively, you can directly submit a unicode character here. - */ - public ObjectProperty<Object> iconProperty(){ - return icon; - } - - /** - * Set the icon to display. - * @param iconValue This can either be the Glyph-Name, Glyph-Enum Value or a unicode character representing the sign. - */ - public void setIcon(Object iconValue){ - icon.set(iconValue); - } - - public Object getIcon(){ - return icon.get(); - } - - /*************************************************************************** - * * - * Private methods * - * * - **************************************************************************/ - - - /** - * This updates the text with the correct unicode value - * so that the desired icon is displayed. - */ - private void updateIcon(){ - - Object iconValue = getIcon(); - - if(iconValue != null) { - if(iconValue instanceof Character){ - setTextUnicode((Character)iconValue); - }else { - GlyphFont glyphFont = GlyphFontRegistry.font(getFontFamily()); - if (glyphFont != null) { - String name = iconValue.toString(); - Character unicode = glyphFont.getCharacter(name); - if (unicode != null) { - setTextUnicode(unicode); - } else { - // Could not find a icon with this name - setText(name); - } - } - } - } - } - - /** - * Sets the given char as text - * @param unicode - */ - private void setTextUnicode(char unicode){ - setText(String.valueOf(unicode)); - } -} \ No newline at end of file diff --git a/src/org/controlsfx/glyphfont/GlyphFont.java b/src/org/controlsfx/glyphfont/GlyphFont.java deleted file mode 100644 index ea355cd..0000000 --- a/src/org/controlsfx/glyphfont/GlyphFont.java +++ /dev/null @@ -1,245 +0,0 @@ -/** - * Copyright (c) 2013, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.glyphfont; - -import com.sun.javafx.css.StyleManager; -import javafx.scene.text.Font; - -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; - -/** - * Represents a glyph font, which can be loaded locally or from a specified URL. - * {@link Glyph}s can be created easily using specified character defined in the - * font. For example, \uf013 in FontAwesome is used to represent - * a gear icon. - * - * <p>To simplify glyph customization, methods can be chained, for example: - * - * <pre> - * Glyph glyph = fontAwesome.create('\uf013').size(28).color(Color.RED); //GEAR - * </pre> - * - * <p>Here's a screenshot of two font packs being used to render images into - * JavaFX Button controls: - * - * <br> - * <center><img src="glyphFont.png" alt="Screenshot of GlyphFont"></center> - */ -public class GlyphFont { - - static { - StyleManager.getInstance().addUserAgentStylesheet( - GlyphFont.class.getResource("glyphfont.css").toExternalForm()); //$NON-NLS-1$ - } - - /*************************************************************************** - * * - * Private fields * - * * - **************************************************************************/ - - private final Map<String, Character> namedGlyphs = new HashMap<>(); - private final Runnable fontLoader; - private final String fontName; - private final double defaultSize; - - private boolean fontLoaded = false; - - - /*************************************************************************** - * * - * Constructors * - * * - **************************************************************************/ - - /** - * Loads glyph font from specified {@link InputStream} - * @param fontName glyph font name - * @param defaultSize default font size - * @param in input stream to load the font from - */ - public GlyphFont( String fontName, int defaultSize, final InputStream in) { - this(fontName, defaultSize, in, false); - } - - /** - * Load glyph font from specified URL. - * Example for a local file: - * "file:///C:/Users/Bob/Fonts/icomoon.ttf" - * "file:///Users/Bob/Fonts/icomoon.ttf" - * - * @param fontName glyph font name - * @param defaultSize default font size - * @param urlStr A URL to load the font from - */ - public GlyphFont( String fontName, int defaultSize, final String urlStr) { - this(fontName, defaultSize, urlStr, false); - } - - /** - * Loads glyph font from specified {@link InputStream} - * @param fontName glyph font name - * @param defaultSize default font size - * @param in input stream to load the font from - * @param lazyLoad If true, the font will only be loaded when accessed - */ - public GlyphFont( String fontName, int defaultSize, final InputStream in, boolean lazyLoad) { - this(fontName, defaultSize, () -> { - Font.loadFont(in, -1); - }, lazyLoad); - } - - /** - * Load glyph font from specified URL. - * Example for a local file: - * "file:///C:/Users/Bob/Fonts/icomoon.ttf" - * "file:///Users/Bob/Fonts/icomoon.ttf" - * - * @param fontName glyph font name - * @param defaultSize default font size - * @param urlStr A URL to load the font from - * @param lazyLoad If true, the font will only be loaded when accessed - */ - public GlyphFont( String fontName, int defaultSize, final String urlStr, boolean lazyLoad) { - this(fontName, defaultSize, () -> { - Font.loadFont(urlStr, -1); - }, lazyLoad); - } - - /** - * Creates a GlyphFont - * @param fontName - * @param defaultSize - * @param fontLoader - * @param lazyLoad - */ - private GlyphFont(String fontName, int defaultSize, Runnable fontLoader, boolean lazyLoad){ - this.fontName = fontName; - this.defaultSize = defaultSize; - this.fontLoader = fontLoader; - - if(!lazyLoad){ - ensureFontIsLoaded(); - } - } - - /*************************************************************************** - * * - * Public API * - * * - **************************************************************************/ - - /** - * Returns font name - * @return font name - */ - public String getName() { - return fontName; - } - - /** - * Returns the default font size - * @return default font size - */ - public double getDefaultSize() { - return defaultSize; - } - - - /** - * Creates an instance of {@link Glyph} using specified font character - * @param character font character - * @return instance of {@link Glyph} - */ - public Glyph create(char character) { - return new Glyph(fontName, character); - } - - /** - * Creates an instance of {@link Glyph} using glyph name - * @param glyphName glyph name - * @return glyph by its name or null if name is not found - */ - public Glyph create(String glyphName) { - return new Glyph(fontName, glyphName); - } - - /** - * Creates an instance of {@link Glyph} using a known Glyph enum value - * @param glyph - */ - public Glyph create(Enum<?> glyph) { - return new Glyph(fontName, glyph); - } - - /** - * Returns the character code which is mapped to this Name. - * If no match is found, NULL is returned. - * @param glyphName - */ - public Character getCharacter(String glyphName){ - return namedGlyphs.get(glyphName.toUpperCase()); - } - - - /** - * Registers all given characters with their name. - * @param namedCharacters - */ - public void registerAll(Iterable<? extends INamedCharacter> namedCharacters){ - for (INamedCharacter e: namedCharacters) { - register(e.name(), e.getChar()); - } - } - - /** - * Registers the given name-character mapping - * @param name - * @param character - */ - public void register(String name, Character character){ - namedGlyphs.put(name.toUpperCase(), character); - } - - /*************************************************************************** - * * - * Internal methods * - * * - **************************************************************************/ - - /** - * Ensures that the font is loaded - */ - synchronized void ensureFontIsLoaded(){ - if ( !fontLoaded ) { - fontLoader.run(); - fontLoaded = true; - } - } -} diff --git a/src/org/controlsfx/glyphfont/GlyphFontRegistry.java b/src/org/controlsfx/glyphfont/GlyphFontRegistry.java deleted file mode 100644 index cc9d433..0000000 --- a/src/org/controlsfx/glyphfont/GlyphFontRegistry.java +++ /dev/null @@ -1,127 +0,0 @@ -/** - * Copyright (c) 2013,2014 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.glyphfont; - - -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; -import java.util.ServiceLoader; - -/** - * The glyph font registry automatically registers available fonts using a - * {@link ServiceLoader} facility, however it is also possible to register - * glyph fonts manually using the provided - * {@link GlyphFontRegistry#register(GlyphFont)} method. - * - * <p>Once registered, fonts can be requested by name using the - * {@link GlyphFontRegistry#font(String)} method. - * - * Please refer to the {@link GlyphFont} documentation - * to learn how to use a font. - * - */ -public final class GlyphFontRegistry { - - /*************************************************************************** - * * - * Private fields * - * * - **************************************************************************/ - - private static Map<String, GlyphFont> fontMap = new HashMap<>(); - - /*************************************************************************** - * * - * Constructors * - * * - **************************************************************************/ - - static { - // find all classes that implement GlyphFont and register them now - ServiceLoader<GlyphFont> loader = ServiceLoader.load(GlyphFont.class); - for (GlyphFont font : loader) { - GlyphFontRegistry.register(font); - } - } - - /** - * Private constructor since static class - */ - private GlyphFontRegistry() { - // no-op - } - - /*************************************************************************** - * * - * Public API * - * * - **************************************************************************/ - - /** - * Registers the specified font as default GlyphFont - * @param familyName The name of this font. - * @param uri The location where it can be loaded from. - * @param defaultSize The default font size - */ - public static void register(String familyName, String uri, int defaultSize){ - register(new GlyphFont(familyName, defaultSize, uri)); - } - - /** - * Registers the specified font as default GlyphFont - * @param familyName The name of this font. - * @param in Inputstream of the font data - * @param defaultSize The default font size - */ - public static void register(String familyName, InputStream in, int defaultSize){ - register(new GlyphFont(familyName, defaultSize, in)); - } - - /** - * Registers the specified font - * @param font - */ - public static void register( GlyphFont font ) { - if (font != null ) { - fontMap.put( font.getName(), font ); - } - } - - /** - * Retrieve font by its family name - * @param familyName family name of the font - * @return font or null if not found - */ - public static GlyphFont font( String familyName ) { - GlyphFont font = fontMap.get(familyName); - if(font != null) { - font.ensureFontIsLoaded(); - } - return font; - } -} diff --git a/src/org/controlsfx/glyphfont/INamedCharacter.java b/src/org/controlsfx/glyphfont/INamedCharacter.java deleted file mode 100644 index 60b7069..0000000 --- a/src/org/controlsfx/glyphfont/INamedCharacter.java +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.glyphfont; - -/** - * Represents a named character. - * This interface is usually implemented by a Enum - * which holds all characters of a specific font. - */ -public interface INamedCharacter { - /** - * Gets the name of this character - */ - String name(); - - /** - * Gets the character value - */ - char getChar(); -} diff --git a/src/org/controlsfx/glyphfont/glyphfont.css b/src/org/controlsfx/glyphfont/glyphfont.css deleted file mode 100644 index 2803ef3..0000000 --- a/src/org/controlsfx/glyphfont/glyphfont.css +++ /dev/null @@ -1,16 +0,0 @@ - -.glyph-font { - -} - -.glyph-font.gradient{ - -fx-effect: innershadow( three-pass-box , derive(-fx-text-fill,-70%) , 0.1em, 0.0 , 0.07em, 0.07em ); -} - -.glyph-font.hover-effect:hover{ - -fx-effect: dropshadow( three-pass-box , derive(-fx-text-fill,0%) , 0.01em, 0.0 , 0, 0); -} - -.glyph-font.hover-effect:selected{ - -fx-effect: dropshadow( three-pass-box , derive(-fx-text-fill,0%) , 0.01em, 0.0 , 0, 0); -} \ No newline at end of file diff --git a/src/org/controlsfx/glyphfont/package-info.java b/src/org/controlsfx/glyphfont/package-info.java deleted file mode 100644 index a4cee16..0000000 --- a/src/org/controlsfx/glyphfont/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -/** - * A package containing a number of useful code related to loading and using - * font packs whose characters are actually images. - */ -package org.controlsfx.glyphfont; \ No newline at end of file diff --git a/src/org/controlsfx/property/BeanProperty.java b/src/org/controlsfx/property/BeanProperty.java deleted file mode 100644 index 3415253..0000000 --- a/src/org/controlsfx/property/BeanProperty.java +++ /dev/null @@ -1,208 +0,0 @@ -/** - * Copyright (c) 2013, 2015, 2016 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.property; - -import java.beans.FeatureDescriptor; -import java.beans.PropertyDescriptor; -import java.beans.PropertyVetoException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Optional; - -import org.controlsfx.control.PropertySheet; -import org.controlsfx.control.PropertySheet.Item; -import org.controlsfx.property.editor.PropertyEditor; - -import impl.org.controlsfx.i18n.Localization; -import javafx.beans.value.ObservableValue; -import javafx.scene.control.Alert; - -/** - * A convenience class for creating a {@link Item} for use in the - * {@link PropertySheet} control based on a property belonging to a - * JavaBean - simply provide a {@link PropertyDescriptor} and the rest will be - * taken care of automatically. - * - * @see Item - * @see PropertySheet - * @see PropertyDescriptor - */ -public class BeanProperty implements PropertySheet.Item { - - /** - * Unique identifier to provide a custom category label within - * {@link PropertySheet.Item#getCategory()}. - * - * How to use it: with a PropertyDescriptor, provide the custom category - * through a a named attribute - * {@link FeatureDescriptor#setValue(String, Object)}. - * - * <pre> - * final PropertyDescriptor propertyDescriptor = new PropertyDescriptor("yourProperty", YourBean.class); - * propertyDescriptor.setDisplayName("Your Display Name"); - * propertyDescriptor.setShortDescription("Your explanation about this property."); - * // then provide a custom category - * propertyDescriptor.setValue(BeanProperty.CATEGORY_LABEL_KEY, "Your custom category"); - * </pre> - */ - public static final String CATEGORY_LABEL_KEY = "propertysheet.item.category.label"; - - private final Object bean; - private final PropertyDescriptor beanPropertyDescriptor; - private final Method readMethod; - private boolean editable = true; - private Optional<ObservableValue<? extends Object>> observableValue = Optional.empty(); - - public BeanProperty(final Object bean, final PropertyDescriptor propertyDescriptor) { - this.bean = bean; - this.beanPropertyDescriptor = propertyDescriptor; - this.readMethod = propertyDescriptor.getReadMethod(); - if (this.beanPropertyDescriptor.getWriteMethod() == null) { - this.setEditable(false); - } - - this.findObservableValue(); - } - - /** {@inheritDoc} */ - @Override public String getName() { - return this.beanPropertyDescriptor.getDisplayName(); - } - - /** {@inheritDoc} */ - @Override public String getDescription() { - return this.beanPropertyDescriptor.getShortDescription(); - } - - /** {@inheritDoc} */ - @Override public Class<?> getType() { - return this.beanPropertyDescriptor.getPropertyType(); - } - - /** {@inheritDoc} */ - @Override public Object getValue() { - try { - return this.readMethod.invoke(this.bean); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - e.printStackTrace(); - return null; - } - } - - /** {@inheritDoc} */ - @Override public void setValue(final Object value) { - final Method writeMethod = this.beanPropertyDescriptor.getWriteMethod(); - if ( writeMethod != null ) { - try { - writeMethod.invoke(this.bean, value); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - e.printStackTrace(); - } catch (final Throwable e) { - if (e instanceof PropertyVetoException) { - final Alert alert = new Alert(Alert.AlertType.ERROR); - alert.setTitle(Localization.localize(Localization.asKey("bean.property.change.error.title")));//$NON-NLS-1$ - alert.setHeaderText(Localization.localize(Localization.asKey("bean.property.change.error.masthead")));//$NON-NLS-1$ - alert.setContentText(e.getLocalizedMessage()); - alert.showAndWait(); - } else { - throw e; - } - } - } - } - - /** {@inheritDoc} */ - @Override public String getCategory() { - String category = (String) this.beanPropertyDescriptor.getValue(BeanProperty.CATEGORY_LABEL_KEY); - - // fall back to default behavior if there is no category provided. - if (category == null) { - category = Localization.localize(Localization.asKey(this.beanPropertyDescriptor.isExpert() - ? "bean.property.category.expert" : "bean.property.category.basic")); //$NON-NLS-1$ //$NON-NLS-2$ - } - return category; - } - - /** - * @return The object passed in to the constructor of the BeanProperty. - */ - public Object getBean() { - return this.bean; - } - - /** - * @return The {@link PropertyDescriptor} passed in to the constructor of - * the BeanProperty. - */ - public PropertyDescriptor getPropertyDescriptor() { - return this.beanPropertyDescriptor; - } - - /** {@inheritDoc} */ - @SuppressWarnings({ "unchecked" }) - @Override public Optional<Class<? extends PropertyEditor<?>>> getPropertyEditorClass() { - - if ((this.beanPropertyDescriptor.getPropertyEditorClass() != null) && - PropertyEditor.class.isAssignableFrom(this.beanPropertyDescriptor.getPropertyEditorClass())) { - - return Optional.of((Class<PropertyEditor<?>>)this.beanPropertyDescriptor.getPropertyEditorClass()); - } - - return Item.super.getPropertyEditorClass(); - } - - /** {@inheritDoc} */ - @Override public boolean isEditable() { - return this.editable; - } - - /** - * @param editable Whether this property should be editable in the PropertySheet. - */ - public void setEditable(final boolean editable) { - this.editable = editable; - } - - /** {@inheritDoc} */ - @Override public Optional<ObservableValue<? extends Object>> getObservableValue() { - return this.observableValue; - } - - private void findObservableValue() { - try { - final String propName = this.beanPropertyDescriptor.getName() + "Property"; - final Method m = this.getBean().getClass().getMethod(propName); - final Object val = m.invoke(this.getBean()); - if ((val != null) && (val instanceof ObservableValue)) { - this.observableValue = Optional.of((ObservableValue<?>) val); - } - } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { - //Logger.getLogger(BeanProperty.class.getName()).log(Level.SEVERE, null, ex); - // ignore it... - } - } -} diff --git a/src/org/controlsfx/property/BeanPropertyUtils.java b/src/org/controlsfx/property/BeanPropertyUtils.java deleted file mode 100644 index b88093b..0000000 --- a/src/org/controlsfx/property/BeanPropertyUtils.java +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Copyright (c) 2013, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.property; - -import java.beans.BeanInfo; -import java.beans.IntrospectionException; -import java.beans.Introspector; -import java.beans.PropertyDescriptor; -import java.util.function.Predicate; - -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.event.EventHandler; - -import org.controlsfx.control.PropertySheet; -import org.controlsfx.control.PropertySheet.Item; - -/** - * Convenience utility class for creating {@link PropertySheet} instances based - * on a JavaBean. - */ -public final class BeanPropertyUtils { - - private BeanPropertyUtils() { - // no op - } - - /** - * Given a JavaBean, this method will return a list of {@link Item} intances, - * which may be directly placed inside a {@link PropertySheet} (via its - * {@link PropertySheet#getItems() items list}. - * <p> - * This method will not return read-only properties. - * - * @param bean The JavaBean that should be introspected and be editable via - * a {@link PropertySheet}. - * @return A list of {@link Item} instances representing the properties of the - * JavaBean. - */ - public static ObservableList<Item> getProperties(final Object bean) { - return getProperties(bean, (p) -> {return true;} ); - } - - /** - * Given a JavaBean, this method will return a list of {@link Item} intances, - * which may be directly placed inside a {@link PropertySheet} (via its - * {@link PropertySheet#getItems() items list}. - * - * @param bean The JavaBean that should be introspected and be editable via - * a {@link PropertySheet}. - * @param test Predicate to test whether the property should be included in the - * list of results. - * @return A list of {@link Item} instances representing the properties of the - * JavaBean. - */ - public static ObservableList<Item> getProperties(final Object bean, Predicate<PropertyDescriptor> test) { - ObservableList<Item> list = FXCollections.observableArrayList(); - try { - BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass(), Object.class); - for (PropertyDescriptor p : beanInfo.getPropertyDescriptors()) { - if (test.test(p)) { - list.add(new BeanProperty(bean, p)); - } - } - } catch (IntrospectionException e) { - e.printStackTrace(); - } - - return list; - } - -} diff --git a/src/org/controlsfx/property/editor/AbstractObjectField.java b/src/org/controlsfx/property/editor/AbstractObjectField.java deleted file mode 100644 index d6f3941..0000000 --- a/src/org/controlsfx/property/editor/AbstractObjectField.java +++ /dev/null @@ -1,91 +0,0 @@ -/** - * Copyright (c) 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.property.editor; - -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.property.StringProperty; -import javafx.scene.Cursor; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import javafx.scene.input.MouseButton; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Priority; -import javafx.scene.layout.StackPane; - -import org.controlsfx.control.textfield.CustomTextField; - -// package-private for now... -abstract class AbstractObjectField<T> extends HBox { - - //TODO: Replace with CSS - private static final Image image = new Image(AbstractObjectField.class.getResource("/org/controlsfx/control/open-editor.png").toExternalForm()); //$NON-NLS-1$ - - private final CustomTextField textField = new CustomTextField(); - - private ObjectProperty<T> objectProperty = new SimpleObjectProperty<>(); - - public AbstractObjectField() { - super(1); - textField.setEditable(false); - textField.setFocusTraversable(false); - - StackPane button = new StackPane(new ImageView(image)); - button.setCursor(Cursor.DEFAULT); - - button.setOnMouseReleased(e -> { - if ( MouseButton.PRIMARY == e.getButton() ) { - final T result = edit(objectProperty.get()); - if (result != null) { - objectProperty.set(result); - } - } - }); - - textField.setRight(button); - getChildren().add(textField); - HBox.setHgrow(textField, Priority.ALWAYS); - - objectProperty.addListener((o, oldValue, newValue) -> textProperty().set(objectToString(newValue))); - } - - protected StringProperty textProperty() { - return textField.textProperty(); - } - - public ObjectProperty<T> getObjectProperty() { - return objectProperty; - } - - protected String objectToString(T object) { - return object == null ? "" : object.toString(); //$NON-NLS-1$ - } - - protected abstract Class<T> getType(); - - protected abstract T edit(T object); -} diff --git a/src/org/controlsfx/property/editor/AbstractPropertyEditor.java b/src/org/controlsfx/property/editor/AbstractPropertyEditor.java deleted file mode 100644 index 5a3cc80..0000000 --- a/src/org/controlsfx/property/editor/AbstractPropertyEditor.java +++ /dev/null @@ -1,139 +0,0 @@ -/** - * Copyright (c) 2013, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.property.editor; - -import javafx.beans.value.ObservableValue; -import javafx.scene.Node; - -import org.controlsfx.control.PropertySheet.Item; - -/** - * An abstract implementation of the {@link PropertyEditor} interface. - * - * @param <T> The type of the property being edited. - * @param <C> The type of Node that is used to edit this property. - */ -public abstract class AbstractPropertyEditor<T, C extends Node> implements PropertyEditor<T> { - - /************************************************************************** - * - * Private fields - * - **************************************************************************/ - - private final Item property; - private final C control; - private boolean suspendUpdate; - - - /************************************************************************** - * - * Constructors - * - **************************************************************************/ - - /** - * Creates an editable AbstractPropertyEditor instance for the given property - * using the given editing control. - * - * @param property The property that the instance is responsible for editing. - * @param control The control that is responsible for editing the property. - */ - public AbstractPropertyEditor(Item property, C control) { - this(property, control, ! property.isEditable()); - } - - /** - * Creates an AbstractPropertyEditor instance for the given property - * using the given editing control. It may be read-only or editable, based - * on the readonly boolean parameter being true or false. - * - * @param property The property that the instance is responsible for editing. - * @param control The control that is responsible for editing the property. - * @param readonly Specifies whether the editor should allow input or not. - */ - public AbstractPropertyEditor(Item property, C control, boolean readonly) { - this.control = control; - this.property = property; - if (! readonly) { - getObservableValue().addListener((ObservableValue<? extends Object> o, Object oldValue, Object newValue) -> { - if (! suspendUpdate) { - suspendUpdate = true; - AbstractPropertyEditor.this.property.setValue(getValue()); - suspendUpdate = false; - } - }); - - if (property.getObservableValue().isPresent()) { - property.getObservableValue().get().addListener((ObservableValue<? extends Object> o, Object oldValue, Object newValue) -> { - if (! suspendUpdate) { - suspendUpdate = true; - AbstractPropertyEditor.this.setValue((T) property.getValue()); - suspendUpdate = false; - } - }); - } - - } - } - - - - /************************************************************************** - * - * Public API - * - **************************************************************************/ - - /** - * Returns an {@link ObservableValue} of the property that this property - * editor is responsible for editing. This is the editor's value, e.g. a - * TextField's textProperty(). - */ - protected abstract ObservableValue<T> getObservableValue(); - - /** - * Returns the property that this property editor is responsible for editing. - */ - public final Item getProperty() { - return property; - } - - /** - * {@inheritDoc} - */ - @Override public C getEditor() { - return control; - } - - /** - * {@inheritDoc} - */ - @Override public T getValue() { - return getObservableValue().getValue(); - } -} diff --git a/src/org/controlsfx/property/editor/DefaultPropertyEditorFactory.java b/src/org/controlsfx/property/editor/DefaultPropertyEditorFactory.java deleted file mode 100644 index 36b483b..0000000 --- a/src/org/controlsfx/property/editor/DefaultPropertyEditorFactory.java +++ /dev/null @@ -1,115 +0,0 @@ -/** - * Copyright (c) 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.property.editor; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.time.LocalDate; -import java.util.Arrays; -import java.util.Optional; - -import javafx.scene.paint.Color; -import javafx.scene.paint.Paint; -import javafx.scene.text.Font; -import javafx.util.Callback; - -import org.controlsfx.control.PropertySheet; -import org.controlsfx.control.PropertySheet.Item; - -/** - * A default implementation of the {@link Callback} type required by the - * {@link PropertySheet} - * {@link PropertySheet#propertyEditorFactory() property editor factory}. By - * default this is the implementation used by PropertySheet, but developers may - * choose to provide their own, or more likely, extend this implementation - * and override the {@link DefaultPropertyEditorFactory#call(org.controlsfx.control.PropertySheet.Item) } method to - * add in support for additional editor types. - * - * @see PropertySheet - */ -public class DefaultPropertyEditorFactory implements Callback<Item, PropertyEditor<?>> { - - @Override public PropertyEditor<?> call(Item item) { - Class<?> type = item.getType(); - - //TODO: add support for char and collection editors - - if (item.getPropertyEditorClass().isPresent()) { - Optional<PropertyEditor<?>> ed = Editors.createCustomEditor(item); - if (ed.isPresent()) return ed.get(); - } - - if (/*type != null &&*/ type == String.class) { - return Editors.createTextEditor(item); - } - - if (/*type != null &&*/ isNumber(type)) { - return Editors.createNumericEditor(item); - } - - if (/*type != null &&*/(type == boolean.class || type == Boolean.class)) { - return Editors.createCheckEditor(item); - } - - if (/*type != null &&*/type == LocalDate.class) { - return Editors.createDateEditor(item); - } - - if (/*type != null &&*/type == Color.class || type == Paint.class) { - return Editors.createColorEditor(item); - } - - if (type != null && type.isEnum()) { - return Editors.createChoiceEditor(item, Arrays.<Object>asList(type.getEnumConstants())); - } - - if (/*type != null &&*/type == Font.class) { - return Editors.createFontEditor(item); - } - - return null; - } - - private static Class<?>[] numericTypes = new Class[]{ - byte.class, Byte.class, - short.class, Short.class, - int.class, Integer.class, - long.class, Long.class, - float.class, Float.class, - double.class, Double.class, - BigInteger.class, BigDecimal.class - }; - - // there should be better ways to do this - private static boolean isNumber(Class<?> type) { - if ( type == null ) return false; - for (Class<?> cls : numericTypes) { - if ( type == cls ) return true; - } - return false; - } -} diff --git a/src/org/controlsfx/property/editor/Editors.java b/src/org/controlsfx/property/editor/Editors.java deleted file mode 100644 index c742d49..0000000 --- a/src/org/controlsfx/property/editor/Editors.java +++ /dev/null @@ -1,232 +0,0 @@ -/** - * Copyright (c) 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.property.editor; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.time.LocalDate; -import java.util.Collection; -import java.util.Optional; - -import javafx.application.Platform; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.StringProperty; -import javafx.beans.value.ObservableValue; -import javafx.collections.FXCollections; -import javafx.scene.control.CheckBox; -import javafx.scene.control.ColorPicker; -import javafx.scene.control.ComboBox; -import javafx.scene.control.DatePicker; -import javafx.scene.control.TextField; -import javafx.scene.control.TextInputControl; -import javafx.scene.paint.Color; -import javafx.scene.text.Font; - -import org.controlsfx.control.PropertySheet; -import org.controlsfx.control.PropertySheet.Item; -import org.controlsfx.dialog.FontSelectorDialog; - -@SuppressWarnings("deprecation") -public class Editors { - - private Editors() { - // no op - } - - public static final PropertyEditor<?> createTextEditor( Item property ) { - - return new AbstractPropertyEditor<String, TextField>(property, new TextField()) { - - { enableAutoSelectAll(getEditor()); } - - @Override protected StringProperty getObservableValue() { - return getEditor().textProperty(); - } - - @Override public void setValue(String value) { - getEditor().setText(value); - } - }; - } - - @SuppressWarnings("unchecked") - public static final PropertyEditor<?> createNumericEditor( Item property ) { - - return new AbstractPropertyEditor<Number, NumericField>(property, new NumericField( (Class<? extends Number>) property.getType())) { - - private Class<? extends Number> sourceClass = (Class<? extends Number>) property.getType(); //Double.class; - - { enableAutoSelectAll(getEditor()); } - - @Override protected ObservableValue<Number> getObservableValue() { - return getEditor().valueProperty(); - } - - @Override public Number getValue() { - try { - return sourceClass.getConstructor(String.class).newInstance(getEditor().getText()); - } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException - | NoSuchMethodException | SecurityException e) { - e.printStackTrace(); - return null; - } - } - - @Override public void setValue(Number value) { - sourceClass = (Class<? extends Number>) value.getClass(); - getEditor().setText(value.toString()); - } - - }; - } - - public static final PropertyEditor<?> createCheckEditor( Item property ) { - - return new AbstractPropertyEditor<Boolean, CheckBox>(property, new CheckBox()) { - - @Override protected BooleanProperty getObservableValue() { - return getEditor().selectedProperty(); - } - - @Override public void setValue(Boolean value) { - getEditor().setSelected((Boolean)value); - } - }; - - } - - public static final <T> PropertyEditor<?> createChoiceEditor( Item property, final Collection<T> choices ) { - - return new AbstractPropertyEditor<T, ComboBox<T>>(property, new ComboBox<T>()) { - - { getEditor().setItems(FXCollections.observableArrayList(choices)); } - - @Override protected ObservableValue<T> getObservableValue() { - return getEditor().getSelectionModel().selectedItemProperty(); - } - - @Override public void setValue(T value) { - getEditor().getSelectionModel().select(value); - } - }; - } - - public static final PropertyEditor<?> createColorEditor( Item property ) { - return new AbstractPropertyEditor<Color, ColorPicker>(property, new ColorPicker()) { - - @Override protected ObservableValue<Color> getObservableValue() { - return getEditor().valueProperty(); - } - - @Override public void setValue(Color value) { - getEditor().setValue((Color) value); - } - }; - } - - - public static final PropertyEditor<?> createDateEditor( Item property ) { - return new AbstractPropertyEditor<LocalDate, DatePicker>(property, new DatePicker()) { - - //TODO: Provide date picker customization support - - @Override protected ObservableValue<LocalDate> getObservableValue() { - return getEditor().valueProperty(); - } - - @Override public void setValue(LocalDate value) { - getEditor().setValue((LocalDate) value); - } - }; - } - - public static final PropertyEditor<?> createFontEditor( Item property ) { - - return new AbstractPropertyEditor<Font, AbstractObjectField<Font>>(property, new AbstractObjectField<Font>() { - @Override protected Class<Font> getType() { - return Font.class; - } - - @Override protected String objectToString(Font font) { - return font == null? "": String.format("%s, %.1f", font.getName(), font.getSize()); //$NON-NLS-1$ //$NON-NLS-2$ - } - - @Override protected Font edit(Font font) { - FontSelectorDialog dlg = new FontSelectorDialog(font); - Optional<Font> optionalFont = dlg.showAndWait(); - return optionalFont.get(); - } - }) { - - @Override protected ObservableValue<Font> getObservableValue() { - return getEditor().getObjectProperty(); - } - - @Override public void setValue(Font value) { - getEditor().getObjectProperty().set(value); - } - }; - - } - - /** - * Static method used to create an instance of the custom editor returned - * via a call to {@link Item#getPropertyEditorClass() } - * - * The class returned must declare a constructor that takes a single - * parameter of type PropertySheet.Item into which the parameter supplied - * to this method will be passed. - * - * @param property The {@link Item} that this editor will be - * associated with. - * @return The {@link PropertyEditor} wrapped in an {@link Optional} - */ - public static final Optional<PropertyEditor<?>> createCustomEditor(final Item property ) { - return property.getPropertyEditorClass().map(cls -> { - try { - Constructor<?> cn = cls.getConstructor(PropertySheet.Item.class); - if (cn != null) { - return (PropertyEditor<?>) cn.newInstance(property); - } - } catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { - ex.printStackTrace(); - } - return null; - }); - } - - private static void enableAutoSelectAll(final TextInputControl control) { - control.focusedProperty().addListener((ObservableValue<? extends Boolean> o, Boolean oldValue, Boolean newValue) -> { - if (newValue) { - Platform.runLater(() -> { - control.selectAll(); - }); - } - }); - } - -} diff --git a/src/org/controlsfx/property/editor/NumericField.java b/src/org/controlsfx/property/editor/NumericField.java deleted file mode 100644 index c90f413..0000000 --- a/src/org/controlsfx/property/editor/NumericField.java +++ /dev/null @@ -1,150 +0,0 @@ -/** - * Copyright (c) 2015 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.property.editor; - -import java.math.BigInteger; - -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; -import javafx.beans.binding.NumberExpression; -import javafx.beans.property.SimpleDoubleProperty; -import javafx.beans.property.SimpleLongProperty; -import javafx.beans.value.ObservableValue; -import javafx.scene.control.IndexRange; -import javafx.scene.control.TextField; - -/* - * TODO replace this with proper API when it becomes available: - * https://javafx-jira.kenai.com/browse/RT-30881 - */ -class NumericField extends TextField { - - private final NumericValidator<? extends Number> value ; - - public NumericField( Class<? extends Number> cls ) { - - if ( cls == byte.class || cls == Byte.class || cls == short.class || cls == Short.class || - cls == int.class || cls == Integer.class || cls == long.class || cls == Long.class || - cls == BigInteger.class) { - value = new LongValidator(this); - } else { - value = new DoubleValidator(this); - } - - textProperty().addListener(new InvalidationListener() { - @Override public void invalidated(Observable arg0) { - value.setValue(value.toNumber(getText())); - } - }); - - } - - public final ObservableValue<Number> valueProperty() { - return value; - } - - @Override public void replaceText(int start, int end, String text) { - if (replaceValid(start, end, text)) { - super.replaceText(start, end, text); - } - } - - @Override public void replaceSelection(String text) { - IndexRange range = getSelection(); - if (replaceValid(range.getStart(), range.getEnd(), text)) { - super.replaceSelection(text); - } - } - - private Boolean replaceValid(int start, int end, String fragment) { - try { - String newText = getText().substring(0, start) + fragment + getText().substring(end); - if (newText.isEmpty()) return true; - value.toNumber(newText); - return true; - } catch( Throwable ex ) { - return false; - } - } - - - private static abstract interface NumericValidator<T extends Number> extends NumberExpression { - void setValue(Number num); - T toNumber(String s); - - } - - static class DoubleValidator extends SimpleDoubleProperty implements NumericValidator<Double>{ - - private NumericField field; - - public DoubleValidator(NumericField field) { - super(field, "value", 0.0); //$NON-NLS-1$ - this.field = field; - } - - @Override protected void invalidated() { - field.setText(Double.toString(get())); - } - - @Override - public Double toNumber(String s) { - if ( s == null || s.trim().isEmpty() ) return 0d; - String d = s.trim(); - if ( d.endsWith("f") || d.endsWith("d") || d.endsWith("F") || d.endsWith("D") ) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ - throw new NumberFormatException("There should be no alpha symbols"); //$NON-NLS-1$ - } - return new Double(d); - }; - - } - - - static class LongValidator extends SimpleLongProperty implements NumericValidator<Long>{ - - private NumericField field; - - public LongValidator(NumericField field) { - super(field, "value", 0l); //$NON-NLS-1$ - this.field = field; - } - - @Override protected void invalidated() { - field.setText(Long.toString(get())); - } - - @Override - public Long toNumber(String s) { - if ( s == null || s.trim().isEmpty() ) return 0l; - String d = s.trim(); - return new Long(d); - }; - - } - - -} \ No newline at end of file diff --git a/src/org/controlsfx/property/editor/PropertyEditor.java b/src/org/controlsfx/property/editor/PropertyEditor.java deleted file mode 100644 index 58dbf36..0000000 --- a/src/org/controlsfx/property/editor/PropertyEditor.java +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Copyright (c) 2013, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.property.editor; - -import org.controlsfx.control.PropertySheet; - -import javafx.scene.Node; - -/** - * The base interface for all editors used by the {@link PropertySheet} control. - * - * @param <T> The type of the property that the PropertyEditor is responsible - * for editing. - */ -public interface PropertyEditor<T> { - - /** - * Returns the editor responsible for editing this property. - */ - public Node getEditor(); - - /** - * Returns the current value in the editor - this may not be the value of - * the property itself! - */ - public T getValue(); - - /** - * Sets the value to display in the editor - this may not be the value of - * the property itself - and the property value will not change! - */ - public void setValue(T value); -} diff --git a/src/org/controlsfx/property/editor/package-info.java b/src/org/controlsfx/property/editor/package-info.java deleted file mode 100644 index 67fd7df..0000000 --- a/src/org/controlsfx/property/editor/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -/** - * A package containing a number of useful editor classes related to the - * {@link org.controlsfx.control.PropertySheet} control. - */ -package org.controlsfx.property.editor; \ No newline at end of file diff --git a/src/org/controlsfx/property/package-info.java b/src/org/controlsfx/property/package-info.java deleted file mode 100644 index 366b5b5..0000000 --- a/src/org/controlsfx/property/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -/** - * A package containing a number of useful classes related to the - * {@link org.controlsfx.control.PropertySheet} control. - */ -package org.controlsfx.property; \ No newline at end of file diff --git a/src/org/controlsfx/tools/Borders.java b/src/org/controlsfx/tools/Borders.java deleted file mode 100644 index 542c2f4..0000000 --- a/src/org/controlsfx/tools/Borders.java +++ /dev/null @@ -1,807 +0,0 @@ -/** - * Copyright (c) 2013, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.tools; - -import javafx.geometry.Insets; -import javafx.scene.Node; -import javafx.scene.control.Label; -import javafx.scene.layout.*; -import javafx.scene.paint.Color; - -import javax.swing.*; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * A utility class that allows you to wrap JavaFX {@link Node Nodes} with a border, - * in a way somewhat analogous to the Swing {@link BorderFactory} (although with - * less options as a lot of what the Swing BorderFactory offers resulted in - * ugly borders!). - * - * <p>The Borders class provides a fluent API for specifying the properties of - * each border. It is possible to create multiple borders around a Node simply - * by continuing to call additional methods before you call the final - * {@link Borders#build()} method. To use the Borders class, you simply call - * {@link Borders#wrap(Node)}, passing in the Node you wish to wrap the border(s) - * around. - * - * <h3>Examples</h3> - * <p>Firstly, lets wrap a JavaFX Button node with a simple line border that looks - * like the following: - * - * <br> - * <center><img src="borders-lineBorder.png" alt="Screenshot of Borders.LineBorders"></center> - * - * <p>Here's the code:</p> - * - * <pre> - * {@code - * Button button = new Button("Hello World!"); - * Node wrappedButton = Borders.wrap(button).lineBorder().buildAll(); - * }</pre> - * - * <p>Easy, isn't it!? You can make the border look a little nicer by replacing - * the line border with an {@link EtchedBorders etched border}. An etched border - * has a subtle inner (or outer) line that makes the border stand out a bit more, - * like this: - * - * <br> - * <center><img src="borders-etchedBorder.png" alt="Screenshot of Borders.EtchedBorders"></center> - * - * <p>Now that's one good looking border! Here's the code:</p> - * - * <pre> - * {@code - * Button button = new Button("Hello World!"); - * Node wrappedButton = Borders.wrap(button).etchedBorder().buildAll(); - * }</pre> - * - * <p>In some circumstances you want to have multiple borders. For example, - * you might two line borders. That's easy: - * - * <br> - * <center><img src="borders-twoLines.png" alt="Screenshot of two Borders.LineBorders"></center> - * - * <pre> - * {@code - * Node wrappedButton = Borders.wrap(button) - * .lineBorder().color(Color.RED).build() - * .lineBorder().color(Color.GREEN).build() - * .build(); - * }</pre> - * - * <p>You simply chain the borders together, going from inside to outside!</p> - * - * <p>Because of all the configuration options it isn't possible to list all the - * functionality of all the border types, so refer to the rest of the javadocs - * for inspiration.</p> - */ -public final class Borders { - - /************************************************************************** - * - * Static fields - * - **************************************************************************/ - - private static final Color DEFAULT_BORDER_COLOR = Color.DARKGRAY; - - - - /************************************************************************** - * - * Internal fields - * - **************************************************************************/ - - private final Node node; - private final List<Border> borders; - - - - /************************************************************************** - * - * Fluent API entry method(s) - * - **************************************************************************/ - - public static Borders wrap(Node n) { - return new Borders(n); - } - - - - /************************************************************************** - * - * Private Constructor - * - **************************************************************************/ - - private Borders(Node n) { - this.node = n; - this.borders = new ArrayList<>(); - } - - - - /************************************************************************** - * - * Fluent API - * - **************************************************************************/ - - /** - * Often times it is useful to have a bit of whitespace around a Node, to - * separate it from what it is next to. Call this method to begin building - * a border that will wrap the node with a given amount of whitespace - * (which can vary between the top, right, bottom, and left sides). - */ - public EmptyBorders emptyBorder() { - return new EmptyBorders(this); - } - - /** - * The etched border look is essentially equivalent to the {@link #lineBorder()} - * look, except rather than one line, there are two. What is commonly done in - * this circumstance is that one of the lines is a very light colour (commonly - * white), which gives a nice etched look. Refer to the API in {@link EtchedBorders} - * for more information. - */ - public EtchedBorders etchedBorder() { - return new EtchedBorders(this); - } - - /** - * Creates a nice, simple border around the node. Note that there are many - * configuration options in {@link LineBorders}, so explore it carefully. - */ - public LineBorders lineBorder() { - return new LineBorders(this); - } - - /** - * Allows for developers to develop custom {@link Border} implementations, - * and to wrap them around a Node. Note that of course this is mostly - * redundant (as you could just call {@link Border#wrap(Node)} directly). - * The only benefit is if you're creating a compound border consisting of - * multiple borders, and you want your custom border included as part of - * this. - */ - public Borders addBorder(Border border) { - borders.add(border); - return this; - } - - /** - * Returns the original node wrapped in zero or more borders, as specified - * using the fluent API. - */ - public Node build() { - // we iterate through the borders list in reverse order - Node bundle = node; - for (int i = borders.size() - 1; i >= 0; i--) { - Border border = borders.get(i); - bundle = border.wrap(bundle); - } - return bundle; - } - - - - /************************************************************************** - * - * Support classes - * - **************************************************************************/ - - /** - * A fluent API that is only indirectly instantiable via the {@link Borders} - * fluent API, and which allows for an {@link Borders#emptyBorder() empty border} - * to be wrapped around a given Node. - */ - public class EmptyBorders { - private final Borders parent; - - private double top; - private double right; - private double bottom; - private double left; - - // private on purpose - this class is not directly instantiable. - private EmptyBorders(Borders parent) { - this.parent = parent; - } - - /** - * Specifies that the wrapped Node should have the given padding around - * all four sides of itself. - */ - public EmptyBorders padding(double padding) { - return padding(padding, padding, padding, padding); - } - - /** - * Specifies that the wrapped Node should be wrapped with the given - * padding for each of its four sides, going in the order top, right, - * bottom, and finally left. - */ - public EmptyBorders padding(double top, double right, double bottom, double left) { - this.top = top; - this.right = right; - this.bottom = bottom; - this.left = left; - return this; - } - - /** - * Builds the {@link Border} and {@link Borders#addBorder(Border) adds it} - * to the list of borders to wrap around the given Node (which will be - * constructed and returned when {@link Borders#build()} is called. - */ - public Borders build() { - parent.addBorder(new StrokeBorder(null, buildStroke())); - return parent; - } - - /** - * A convenience method, this is equivalent to calling - * {@link #build()} followed by {@link Borders#build()}. In other words, - * calling this will return the original Node wrapped in all its borders - * specified. - */ - public Node buildAll() { - build(); - return parent.build(); - } - - private BorderStroke buildStroke() { - return new BorderStroke( - null, - BorderStrokeStyle.NONE, - null, - new BorderWidths(top, right, bottom, left), - Insets.EMPTY); - } - } - - /** - * A fluent API that is only indirectly instantiable via the {@link Borders} - * fluent API, and which allows for an {@link Borders#etchedBorder() etched border} - * to be wrapped around a given Node. - */ - public class EtchedBorders { - private final Borders parent; - - private String title; - private boolean raised = false; - - private double outerTopPadding = 10; - private double outerRightPadding = 10; - private double outerBottomPadding = 10; - private double outerLeftPadding = 10; - - private double innerTopPadding = 15; - private double innerRightPadding = 15; - private double innerBottomPadding = 15; - private double innerLeftPadding = 15; - - private double topLeftRadius = 0; - private double topRightRadius = 0; - private double bottomRightRadius = 0; - private double bottomLeftRadius = 0; - - private Color highlightColor = DEFAULT_BORDER_COLOR; - private Color shadowColor = Color.WHITE; - - // private on purpose - this class is not directly instantiable. - private EtchedBorders(Borders parent) { - this.parent = parent; - } - - /** - * Specifies the highlight colour to use in the etched border. - */ - public EtchedBorders highlight(Color highlight) { - this.highlightColor = highlight; - return this; - } - - /** - * Specifies the shadow colour to use in the etched border. - */ - public EtchedBorders shadow(Color shadow) { - this.shadowColor = shadow; - return this; - } - - /** - * Specifies the order in which the highlight and shadow colours are - * placed. A raised etched border has the shadow colour on the outside - * of the border, whereas a non-raised (or lowered) etched border has - * the shadow colour on the inside of the border. - */ - public EtchedBorders raised() { - raised = true; - return this; - } - - /** - * If desired, this specifies the title text to show in this border. - */ - public EtchedBorders title(String title) { - this.title = title; - return this; - } - - /** - * Specifies the outer padding of the four lines of this border. - */ - public EtchedBorders outerPadding(double padding) { - return outerPadding(padding, padding, padding, padding); - } - - /** - * Specifies that the line wrapping the node should have outer padding - * as specified, with each padding being independently configured, going - * in the order top, right, bottom, and left. - */ - public EtchedBorders outerPadding(double topPadding, double rightPadding, double bottomPadding, double leftPadding) { - this.outerTopPadding = topPadding; - this.outerRightPadding = rightPadding; - this.outerBottomPadding = bottomPadding; - this.outerLeftPadding = leftPadding; - - return this; - } - - /** - * Specifies the inner padding of the four lines of this border. - */ - public EtchedBorders innerPadding(double padding) { - return innerPadding(padding, padding, padding, padding); - } - - /** - * Specifies that the line wrapping the node should have inner padding - * as specified, with each padding being independently configured, going - * in the order top, right, bottom, and left. - */ - public EtchedBorders innerPadding(double topPadding, double rightPadding, double bottomPadding, double leftPadding) { - this.innerTopPadding = topPadding; - this.innerRightPadding = rightPadding; - this.innerBottomPadding = bottomPadding; - this.innerLeftPadding = leftPadding; - - return this; - } - - /** - * Specifies the radius of the four corners of the lines of this border. - */ - public EtchedBorders radius(double radius) { - return radius(radius, radius, radius, radius); - } - - /** - * Specifies that the etched line wrapping the node should have corner radii - * as specified, with each radius being independently configured, going - * in the order top-left, top-right, bottom-right, and finally bottom-left. - */ - public EtchedBorders radius(double topLeft, double topRight, double bottomRight, double bottomLeft) { - this.topLeftRadius = topLeft; - this.topRightRadius = topRight; - this.bottomRightRadius = bottomRight; - this.bottomLeftRadius = bottomLeft; - return this; - } - - /** - * Builds the {@link Border} and {@link Borders#addBorder(Border) adds it} - * to the list of borders to wrap around the given Node (which will be - * constructed and returned when {@link Borders#build()} is called. - */ - public Borders build() { - Color inner = raised ? shadowColor : highlightColor; - Color outer = raised ? highlightColor : shadowColor; - BorderStroke innerStroke = new BorderStroke( - inner, - BorderStrokeStyle.SOLID, - new CornerRadii(topLeftRadius, topRightRadius, bottomRightRadius, bottomLeftRadius, false), - new BorderWidths(1)); - BorderStroke outerStroke = new BorderStroke( - outer, - BorderStrokeStyle.SOLID, - new CornerRadii(topLeftRadius, topRightRadius, bottomRightRadius, bottomLeftRadius, false), - new BorderWidths(1), - new Insets(1)); - - BorderStroke outerPadding = new EmptyBorders(parent) - .padding(outerTopPadding, outerRightPadding, outerBottomPadding, outerLeftPadding) - .buildStroke(); - - BorderStroke innerPadding = new EmptyBorders(parent) - .padding(innerTopPadding, innerRightPadding, innerBottomPadding, innerLeftPadding) - .buildStroke(); - - parent.addBorder(new StrokeBorder(null, outerPadding)); - parent.addBorder(new StrokeBorder(title, innerStroke, outerStroke)); - parent.addBorder(new StrokeBorder(null, innerPadding)); - - return parent; - } - - /** - * A convenience method, this is equivalent to calling - * {@link #build()} followed by {@link Borders#build()}. In other words, - * calling this will return the original Node wrapped in all its borders - * specified. - */ - public Node buildAll() { - build(); - return parent.build(); - } - } - - /** - * A fluent API that is only indirectly instantiable via the {@link Borders} - * fluent API, and which allows for a {@link Borders#lineBorder() line border} - * to be wrapped around a given Node. - */ - public class LineBorders { - private final Borders parent; - - private String title; - - private BorderStrokeStyle strokeStyle = BorderStrokeStyle.SOLID; - - private Color topColor = DEFAULT_BORDER_COLOR; - private Color rightColor = DEFAULT_BORDER_COLOR; - private Color bottomColor = DEFAULT_BORDER_COLOR; - private Color leftColor = DEFAULT_BORDER_COLOR; - - private double outerTopPadding = 10; - private double outerRightPadding = 10; - private double outerBottomPadding = 10; - private double outerLeftPadding = 10; - - private double innerTopPadding = 15; - private double innerRightPadding = 15; - private double innerBottomPadding = 15; - private double innerLeftPadding = 15; - - private double topThickness = 1; - private double rightThickness = 1; - private double bottomThickness = 1; - private double leftThickness = 1; - - private double topLeftRadius = 0; - private double topRightRadius = 0; - private double bottomRightRadius = 0; - private double bottomLeftRadius = 0; - - // private on purpose - this class is not directly instantiable. - private LineBorders(Borders parent) { - this.parent = parent; - } - - /** - * Specifies the colour to use for all four sides of this border. - */ - public LineBorders color(Color color) { - return color(color, color, color, color); - } - - /** - * Specifies that the wrapped Node should be wrapped with the given - * colours for each of its four sides, going in the order top, right, - * bottom, and finally left. - */ - public LineBorders color(Color topColor, Color rightColor, Color bottomColor, Color leftColor) { - this.topColor = topColor; - this.rightColor = rightColor; - this.bottomColor = bottomColor; - this.leftColor = leftColor; - return this; - } - - /** - * Specifies which {@link BorderStrokeStyle} to use for this line border. - * By default this is {@link BorderStrokeStyle#SOLID}, but you can use - * any other style (such as {@link BorderStrokeStyle#DASHED}, - * {@link BorderStrokeStyle#DOTTED}, or a custom style built using - * {@link BorderStrokeStyle#BorderStrokeStyle(javafx.scene.shape.StrokeType, javafx.scene.shape.StrokeLineJoin, javafx.scene.shape.StrokeLineCap, double, double, List)}. - */ - public LineBorders strokeStyle(BorderStrokeStyle strokeStyle) { - this.strokeStyle = strokeStyle; - return this; - } - - /** - * Specifies the inner padding of the four lines of this border. - */ - public LineBorders outerPadding(double padding) { - return outerPadding(padding, padding, padding, padding); - } - - /** - * Specifies that the line wrapping the node should have outer padding - * as specified, with each padding being independently configured, going - * in the order top, right, bottom, and left. - */ - public LineBorders outerPadding(double topPadding, double rightPadding, double bottomPadding, double leftPadding) { - this.outerTopPadding = topPadding; - this.outerRightPadding = rightPadding; - this.outerBottomPadding = bottomPadding; - this.outerLeftPadding = leftPadding; - - return this; - } - - /** - * Specifies the outer padding of the four lines of this border. - */ - public LineBorders innerPadding(double padding) { - return innerPadding(padding, padding, padding, padding); - } - - /** - * Specifies that the line wrapping the node should have inner padding - * as specified, with each padding being independently configured, going - * in the order top, right, bottom, and left. - */ - public LineBorders innerPadding(double topPadding, double rightPadding, double bottomPadding, double leftPadding) { - this.innerTopPadding = topPadding; - this.innerRightPadding = rightPadding; - this.innerBottomPadding = bottomPadding; - this.innerLeftPadding = leftPadding; - - return this; - } - - /** - * Specifies the thickness of the line to use on all four sides of this - * border. - */ - public LineBorders thickness(double thickness) { - return thickness(thickness, thickness, thickness, thickness); - } - - /** - * Specifies that the wrapped Node should be wrapped with the given - * line thickness for each of its four sides, going in the order top, right, - * bottom, and finally left. - */ - public LineBorders thickness(double topThickness, double rightThickness, double bottomThickness, double leftThickness) { - this.topThickness = topThickness; - this.rightThickness = rightThickness; - this.bottomThickness = bottomThickness; - this.leftThickness = leftThickness; - return this; - } - - /** - * Specifies the radius of the four corners of the line of this border. - */ - public LineBorders radius(double radius) { - return radius(radius, radius, radius, radius); - } - - /** - * Specifies that the line wrapping the node should have corner radii - * as specified, with each radius being independently configured, going - * in the order top-left, top-right, bottom-right, and finally bottom-left. - */ - public LineBorders radius(double topLeft, double topRight, double bottomRight, double bottomLeft) { - this.topLeftRadius = topLeft; - this.topRightRadius = topRight; - this.bottomRightRadius = bottomRight; - this.bottomLeftRadius = bottomLeft; - return this; - } - - /** - * If desired, this specifies the title text to show in this border. - */ - public LineBorders title(String title) { - this.title = title; - return this; - } - - /** - * Builds the {@link Border} and {@link Borders#addBorder(Border) adds it} - * to the list of borders to wrap around the given Node (which will be - * constructed and returned when {@link Borders#build()} is called. - */ - public Borders build() { - BorderStroke borderStroke = new BorderStroke( - topColor, rightColor, bottomColor, leftColor, - strokeStyle, strokeStyle, strokeStyle, strokeStyle, - new CornerRadii(topLeftRadius, topRightRadius, bottomRightRadius, bottomLeftRadius, false), - new BorderWidths(topThickness, rightThickness, bottomThickness, leftThickness), - null); - - BorderStroke outerPadding = new EmptyBorders(parent) - .padding(outerTopPadding, outerRightPadding, outerBottomPadding, outerLeftPadding) - .buildStroke(); - - BorderStroke innerPadding = new EmptyBorders(parent) - .padding(innerTopPadding, innerRightPadding, innerBottomPadding, innerLeftPadding) - .buildStroke(); - - parent.addBorder(new StrokeBorder(null, outerPadding)); - parent.addBorder(new StrokeBorder(title, borderStroke)); - parent.addBorder(new StrokeBorder(null, innerPadding)); - - return parent; - } - - /** - * A convenience method, this is equivalent to calling - * {@link #build()} followed by {@link Borders#build()}. In other words, - * calling this will return the original Node wrapped in all its borders - * specified. - */ - public Node buildAll() { - build(); - return parent.build(); - } - } - - - - /************************************************************************** - * - * Support interfaces - * - **************************************************************************/ - - /** - * The public interface used by the {@link Borders} API to wrap nodes with - * zero or more Border implementations. ControlsFX ships with a few - * Border implementations (current {@link EmptyBorders}, {@link LineBorders}, - * and {@link EtchedBorders}). As noted in {@link Borders#addBorder(Border)}, - * this interface is relatively pointless, unless you plan to wrap a node - * with multiple borders and you want to use a custom {@link Border} - * implementation for at least one border. In this case, you can simply - * call {@link Borders#addBorder(Border)} with your custom border, when - * appropriate. - */ - @FunctionalInterface - public static interface Border { - - /** - * Given a {@link Node}, this method should return a Node that contains - * the original Node and also has wrapped it with an appropriate border. - */ - public Node wrap(Node n); - } - - - - /************************************************************************** - * - * Private support classes - * - **************************************************************************/ - - // --- Border implementations - private static class StrokeBorder implements Border { - private static final int TITLE_PADDING = 3; - private static final double GAP_PADDING = TITLE_PADDING * 2 - 1; - - private final String title; - private final BorderStroke[] borderStrokes; - - public StrokeBorder(String title, BorderStroke... borderStrokes) { - this.title = title; - this.borderStrokes = borderStrokes; - } - - @Override public Node wrap(final Node n) { - StackPane pane = new StackPane() { - Label titleLabel; - - { - // add in the node we are wrapping - getChildren().add(n); - - - // if the title string is set, then also add in the title label - if (title != null) { - titleLabel = new Label(title); - - // give the text a bit of space on the left... - titleLabel.setPadding(new Insets(0, 0, 0, TITLE_PADDING)); - getChildren().add(titleLabel); - } - } - - @Override protected void layoutChildren() { - super.layoutChildren(); - - if (titleLabel != null) { - // layout the title label - final double labelHeight = titleLabel.prefHeight(-1); - final double labelWidth = titleLabel.prefWidth(labelHeight) + TITLE_PADDING; - titleLabel.resize(labelWidth, labelHeight); - titleLabel.relocate(TITLE_PADDING * 2, -labelHeight / 2.0 - 1); - - List<BorderStroke> newBorderStrokes = new ArrayList<>(2); - - // create a line gap for the title label - for (BorderStroke bs : borderStrokes) { - List<Double> dashList = new ArrayList<>(); - - // Create a dash list for the line gap or add it at the beginning of an existing dash list. This gap should be wide enough for the title label. - if (bs.getTopStyle().getDashArray().isEmpty()) - dashList.addAll(Arrays.asList(GAP_PADDING, labelWidth, Double.MAX_VALUE)); - else { // dash pattern exists - // insert gap in existing dash pattern and multiply original pattern so that gap does not show more then once - double origDashWidth = bs.getTopStyle().getDashArray().stream().mapToDouble(d -> d).sum(); - - if (origDashWidth > GAP_PADDING) { - dashList.add(GAP_PADDING); - dashList.add(labelWidth); - } else { // need to insert dash pattern before the gap - int no = (int) (GAP_PADDING / origDashWidth); - - for (int i = 0; i < no; i++) - dashList.addAll(bs.getTopStyle().getDashArray()); - - if ((dashList.size() & 1) == 0) // if size is even number, add one more element because gap must be at odd index to be transparent - dashList.add(0d); - - dashList.add(labelWidth + GAP_PADDING - no * origDashWidth); - } - - for (int i = 0; i < (getWidth() - labelWidth - origDashWidth) / origDashWidth; i++) - dashList.addAll(bs.getTopStyle().getDashArray()); - } - - // create new border stroke style for the top border line with new dash list - BorderStrokeStyle topStrokeStyle = new BorderStrokeStyle( - bs.getTopStyle().getType(), bs.getTopStyle().getLineJoin(), bs.getTopStyle().getLineCap(), - bs.getTopStyle().getMiterLimit(), bs.getTopStyle().getDashOffset(), dashList); - - // change existing border stroke to utilize new top border line stroke style - newBorderStrokes.add(new BorderStroke( - bs.getTopStroke(), bs.getRightStroke(), bs.getBottomStroke(), bs.getLeftStroke(), - topStrokeStyle, bs.getRightStyle(), bs.getBottomStyle(), bs.getLeftStyle(), - bs.getRadii(), bs.getWidths(), null)); - } - - setBorder(new javafx.scene.layout.Border(newBorderStrokes.toArray(new BorderStroke[newBorderStrokes.size()]))); - } - } - }; - - pane.setBorder(new javafx.scene.layout.Border(borderStrokes)); - return pane; - } - } -} diff --git a/src/org/controlsfx/tools/Duplicatable.java b/src/org/controlsfx/tools/Duplicatable.java deleted file mode 100644 index 1fd50fd..0000000 --- a/src/org/controlsfx/tools/Duplicatable.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright (c) 2013, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.tools; - -import javafx.scene.Node; - -/** - * An interface used in ControlsFX to represent something that can be duplicated, - * as in the JavaFX scenegraph it is not possible to insert the same - * {@link Node} in multiple locations at the same time. Therefore, to work - * around this the node may implement this interface to duplicate itself. - * - * @param <T> The node type - */ -@FunctionalInterface -public interface Duplicatable<T> { - T duplicate(); -} diff --git a/src/org/controlsfx/tools/Platform.java b/src/org/controlsfx/tools/Platform.java deleted file mode 100644 index 3a0eae7..0000000 --- a/src/org/controlsfx/tools/Platform.java +++ /dev/null @@ -1,84 +0,0 @@ -/** - * Copyright (c) 2013, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.tools; - -import java.security.AccessController; -import java.security.PrivilegedAction; - -/** - * Represents operating system with appropriate properties - * - */ -public enum Platform { - - WINDOWS("windows"), //$NON-NLS-1$ - OSX("mac"), //$NON-NLS-1$ - UNIX("unix"), //$NON-NLS-1$ - UNKNOWN(""); //$NON-NLS-1$ - - private static Platform current = getCurrentPlatform(); - - private String platformId; - - Platform( String platformId ) { - this.platformId = platformId; - } - - /** - * Returns platform id. Usually used to specify platform dependent styles - * @return platform id - */ - public String getPlatformId() { - return platformId; - } - - /** - * @return the current OS. - */ - public static Platform getCurrent() { - return current; - } - - private static Platform getCurrentPlatform() { - String osName = System.getProperty("os.name"); - if ( osName.startsWith("Windows") ) return WINDOWS; - if ( osName.startsWith("Mac") ) return OSX; - if ( osName.startsWith("SunOS") ) return UNIX; - if ( osName.startsWith("Linux") ) { - String javafxPlatform = AccessController.doPrivileged(new PrivilegedAction<String>() { - @Override - public String run() { - return System.getProperty("javafx.platform"); - } - }); - if (! ( "android".equals(javafxPlatform) || "Dalvik".equals(System.getProperty("java.vm.name")) ) ) // if not Android - return UNIX; - } - return UNKNOWN; - } - -} diff --git a/src/org/controlsfx/tools/SVGLoader.java b/src/org/controlsfx/tools/SVGLoader.java deleted file mode 100644 index c25ecb1..0000000 --- a/src/org/controlsfx/tools/SVGLoader.java +++ /dev/null @@ -1,227 +0,0 @@ -/** - * Copyright (c) 2013, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.tools; - -import java.net.URL; - -import javafx.beans.value.ChangeListener; -import javafx.concurrent.Worker.State; -import javafx.geometry.Rectangle2D; -import javafx.scene.Scene; -import javafx.scene.SnapshotParameters; -import javafx.scene.SnapshotResult; -import javafx.scene.image.ImageView; -import javafx.scene.image.WritableImage; -import javafx.scene.paint.Color; -import javafx.scene.web.WebEngine; -import javafx.scene.web.WebView; -import javafx.stage.Stage; -import javafx.util.Callback; - -import com.sun.javafx.webkit.Accessor; -import com.sun.webkit.WebPage; - -/** - * Convenience class that will attempt to load a given URL as an .svg file. - */ -class SVGLoader { - - private SVGLoader() { - // no-op - } - - /** - * This method will attempt to load the given svgImage URL into an ImageView - * node that will be provided asynchronously via the provided - * {@link Callback}, and it will be sized to the given prefWidth / prefHeight. - * - * <p>Note that it is valid to pass in -1 to prefWidth and / or prefHeight as - * an indicator to the SVG loader. If both values are -1, the default width - * of the SVG will be used. If one of the values is -1, then the SVG will - * be sized to ensure that it remains proportional. - * - * @param svgImage The image to load. - * @param prefWidth The preferred width of the image when loaded, or -1 if - * there is no preferred width. - * @param prefHeight The preferred height of the image when loaded, or -1 if - * there is no preferred height. - * @param callback The {@link Callback} that will be called when the SVG - * image is loaded, where the {@link ImageView} containing the rendered - * image will be available. - */ - public static void loadSVGImage(final URL svgImage, - final double prefWidth, - final double prefHeight, - final Callback<ImageView, Void> callback) { - loadSVGImage(svgImage, prefWidth, prefHeight, callback, null); - } - - /** - * This method will attempt to load the given svgImage URL into the provided - * {@link WritableImage}, with the SVG scaled to fit the size of the - * WritableImage. - * - * @param svgImage The image to load. - * @param outputImage The location to write the loaded image once it has - * been rendered (it will not happen synchronously). - * @throws NullPointerException The outputImage argument must be non-null. - */ - public static void loadSVGImage(final URL svgImage, - final WritableImage outputImage) { - if (outputImage == null) { - throw new NullPointerException("outputImage can not be null"); //$NON-NLS-1$ - } - final double w = outputImage.getWidth(); - final double h = outputImage.getHeight(); - loadSVGImage(svgImage, w, h, null, outputImage); - } - - public static void loadSVGImage(final URL svgImage, - final double prefWidth, - final double prefHeight, - final Callback<ImageView, Void> callback, - final WritableImage outputImage) { - final WebView view = new WebView(); - final WebEngine eng = view.getEngine(); - - // using non-public API to ensure background transparency - final WebPage webPage = Accessor.getPageFor(eng); - webPage.setBackgroundColor(webPage.getMainFrame(), 0xffffff00); - webPage.setOpaque(webPage.getMainFrame(), false); - // end of non-public API - - // temporary scene / stage - final Scene scene = new Scene(view); - final Stage stage = new Stage(); - stage.setScene(scene); - stage.setWidth(0); - stage.setHeight(0); - stage.setOpacity(0); - stage.show(); - -// String svgString = readFile(svgImage); - - String content = - "<html>" + //$NON-NLS-1$ - "<body style=\"margin-top: 0px; margin-bottom: 30px; margin-left: 0px; margin-right: 0px; padding: 0;\">" + //$NON-NLS-1$ -// "<div style=\"width: " + prefWidth + "; height: " + prefHeight + ";\">" + - "<img id=\"svgImage\" style=\"display: block;float: top;\" width=\"" + prefWidth + "\" height=\"" + prefHeight + "\" src=\"" + svgImage.toExternalForm() + "\" />" + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ -// svgString + -// "</div>" + - "</body>" + //$NON-NLS-1$ - "</head>"; //$NON-NLS-1$ - - - - eng.loadContent(content); - - eng.getLoadWorker().stateProperty().addListener(new ChangeListener<State>() { - @Override public void changed(javafx.beans.value.ObservableValue<? extends State> o, State oldValue, State newValue) { - if (newValue == State.SUCCEEDED) { - -// HTMLImageElement svgImageElement = (HTMLImageElement) getSvgDom(eng); -// System.out.println(svgImageElement.getAttributes()); - - final double svgWidth = prefWidth >= 0 ? prefWidth : getSvgWidth(eng); - final double svgHeight = prefHeight >= 0 ? prefWidth : getSvgHeight(eng); - - SnapshotParameters params = new SnapshotParameters(); - params.setFill(Color.TRANSPARENT); - params.setViewport(new Rectangle2D(0, 0, svgWidth, svgHeight)); - - view.snapshot(new Callback<SnapshotResult, Void>() { - @Override public Void call(SnapshotResult param) { - WritableImage snapshot = param.getImage(); - ImageView image = new ImageView(snapshot); - - if (callback != null) { - callback.call(image); - } - - stage.hide(); - return null; - } - }, params, outputImage); - } - } - }); - } - -// private static String readFile(URL url) { -// try { -// FileInputStream stream = new FileInputStream(new File(url.toURI())); -// try { -// FileChannel fc = stream.getChannel(); -// MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()); -// return Charset.defaultCharset().decode(bb).toString(); -// } -// finally { -// stream.close(); -// } -// } catch (Exception e) { -// e.printStackTrace(); -// } -// return null; -// } - - private static double getSvgWidth(WebEngine webEngine) { - Object result = getSvgDomProperty(webEngine, "offsetWidth"); //$NON-NLS-1$ - if (result instanceof Integer) { - return (Integer) result; - } - return -1; - } - - private static double getSvgHeight(WebEngine webEngine) { - Object result = getSvgDomProperty(webEngine, "offsetHeight"); //$NON-NLS-1$ - if (result instanceof Integer) { - return (Integer) result; - } - return -1; - } - - private static Object getSvgDomProperty(final WebEngine webEngine, final String property) { - return webEngine.executeScript("document.getElementById('svgImage')." + property); //$NON-NLS-1$ - } - -// private static HTMLImageElement getSvgDom(WebEngine webEngine) { -// return (HTMLImageElement) webEngine.executeScript("document.getElementById('svgImage')"); -// } -// -// private static void printDocument(Document doc, OutputStream out) throws IOException, TransformerException { -// TransformerFactory tf = TransformerFactory.newInstance(); -// Transformer transformer = tf.newTransformer(); -// transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); -// transformer.setOutputProperty(OutputKeys.METHOD, "xml"); -// transformer.setOutputProperty(OutputKeys.INDENT, "yes"); -// transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); -// transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); -// -// transformer.transform(new DOMSource(doc), -// new StreamResult(new OutputStreamWriter(out, "UTF-8"))); -// } -} diff --git a/src/org/controlsfx/tools/Utils.java b/src/org/controlsfx/tools/Utils.java deleted file mode 100644 index a7b236d..0000000 --- a/src/org/controlsfx/tools/Utils.java +++ /dev/null @@ -1,113 +0,0 @@ -/** - * Copyright (c) 2014, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.tools; - -import java.util.Iterator; - -import javafx.scene.Node; -import javafx.stage.PopupWindow; -import javafx.stage.Window; - -public class Utils { - - /** - * Will return a {@link Window} from an object if any can be found. {@code null} - * value can be given, the program will then try to find the focused window - * among those available. - * - * @param owner the object whose window is to be found. - * @return the window of the given object. - */ - public static Window getWindow(Object owner) throws IllegalArgumentException { - if (owner == null) { - Window window = null; - // lets just get the focused stage and show the dialog in there - @SuppressWarnings("deprecation") - Iterator<Window> windows = Window.impl_getWindows(); - while (windows.hasNext()) { - window = windows.next(); - if (window.isFocused() && !(window instanceof PopupWindow)) { - break; - } - } - return window; - } else if (owner instanceof Window) { - return (Window) owner; - } else if (owner instanceof Node) { - return ((Node) owner).getScene().getWindow(); - } else { - throw new IllegalArgumentException("Unknown owner: " + owner.getClass()); //$NON-NLS-1$ - } - } - - /** - * Return a letter (just like Excel) associated with the number. When the - * number is under 26, a simple letter is returned. When the number is - * superior, concatenated letters are returned. - * - * - * For example: 0 -> A 1 -> B 26 -> AA 32 -> AG 45 -> AT - * - * - * @param number the number whose Excel Letter is to be found. - * @return a letter (like) associated with the number. - */ - public static final String getExcelLetterFromNumber(int number) { - String letter = ""; //$NON-NLS-1$ - // Repeatedly divide the number by 26 and convert the - // remainder into the appropriate letter. - while (number >= 0) { - final int remainder = number % 26; - letter = (char) (remainder + 'A') + letter; - number = number / 26 - 1; - } - - return letter; - } - - /** - * Simple utility function which clamps the given value to be strictly - * between the min and max values. - */ - public static double clamp(double min, double value, double max) { - if (value < min) return min; - if (value > max) return max; - return value; - } - - /** - * Utility function which returns either {@code less} or {@code more} - * depending on which {@code value} is closer to. If {@code value} - * is perfectly between them, then either may be returned. - */ - public static double nearest(double less, double value, double more) { - double lessDiff = value - less; - double moreDiff = more - value; - if (lessDiff < moreDiff) return less; - return more; - } -} diff --git a/src/org/controlsfx/tools/ValueExtractor.java b/src/org/controlsfx/tools/ValueExtractor.java deleted file mode 100644 index b64b4ed..0000000 --- a/src/org/controlsfx/tools/ValueExtractor.java +++ /dev/null @@ -1,170 +0,0 @@ -/** - * Copyright (c) 2014 ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.tools; - -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.function.Predicate; - -import javafx.beans.value.ObservableValue; -import javafx.collections.FXCollections; -import javafx.scene.Node; -import javafx.scene.control.CheckBox; -import javafx.scene.control.ChoiceBox; -import javafx.scene.control.ColorPicker; -import javafx.scene.control.ComboBox; -import javafx.scene.control.Control; -import javafx.scene.control.DatePicker; -import javafx.scene.control.ListView; -import javafx.scene.control.MultipleSelectionModel; -import javafx.scene.control.RadioButton; -import javafx.scene.control.SelectionMode; -import javafx.scene.control.Slider; -import javafx.scene.control.TableView; -import javafx.scene.control.TextInputControl; -import javafx.scene.control.TreeTableView; -import javafx.scene.control.TreeView; -import javafx.util.Callback; - -public class ValueExtractor { - - private static class ObservableValueExtractor { - - public final Predicate<Control> applicability; - public final Callback<Control, ObservableValue<?>> extraction; - - public ObservableValueExtractor( Predicate<Control> applicability, Callback<Control, ObservableValue<?>> extraction ) { - this.applicability = Objects.requireNonNull(applicability); - this.extraction = Objects.requireNonNull(extraction); - } - - } - - private static List<ObservableValueExtractor> extractors = FXCollections.observableArrayList(); - - /** - * Add "obervable value extractor" for custom controls. - * @param test applicability test - * @param extract extraction of observable value - */ - public static void addObservableValueExtractor( Predicate<Control> test, Callback<Control, ObservableValue<?>> extract ) { - extractors.add( new ObservableValueExtractor(test, extract)); - } - - static { - addObservableValueExtractor( c -> c instanceof TextInputControl, c -> ((TextInputControl)c).textProperty()); - addObservableValueExtractor( c -> c instanceof ComboBox, c -> ((ComboBox<?>)c).valueProperty()); - addObservableValueExtractor( c -> c instanceof ChoiceBox, c -> ((ChoiceBox<?>)c).valueProperty()); - addObservableValueExtractor( c -> c instanceof CheckBox, c -> ((CheckBox)c).selectedProperty()); - addObservableValueExtractor( c -> c instanceof Slider, c -> ((Slider)c).valueProperty()); - addObservableValueExtractor( c -> c instanceof ColorPicker, c -> ((ColorPicker)c).valueProperty()); - addObservableValueExtractor( c -> c instanceof DatePicker, c -> ((DatePicker)c).valueProperty()); - - addObservableValueExtractor( c -> c instanceof ListView, c -> ((ListView<?>)c).itemsProperty()); - addObservableValueExtractor( c -> c instanceof TableView, c -> ((TableView<?>)c).itemsProperty()); - - // FIXME: How to listen for TreeView changes??? - //addObservableValueExtractor( c -> c instanceof TreeView, c -> ((TreeView<?>)c).Property()); - } - - - - public static final Optional<Callback<Control, ObservableValue<?>>> getObservableValueExtractor(final Control c) { - for( ObservableValueExtractor e: extractors ) { - if ( e.applicability.test(c)) return Optional.of(e.extraction); - } - return Optional.empty(); - } - - - private static class NodeValueExtractor { - - public final Predicate<Node> applicability; - public final Callback<Node, Object> extraction; - - public NodeValueExtractor( Predicate<Node> applicability, Callback<Node, Object> extraction ) { - this.applicability = Objects.requireNonNull(applicability); - this.extraction = Objects.requireNonNull(extraction); - } - - } - - - private static final List<NodeValueExtractor> valueExtractors = FXCollections.observableArrayList(); - - static { - addValueExtractor( n -> n instanceof CheckBox, cb -> ((CheckBox)cb).isSelected()); - addValueExtractor( n -> n instanceof ChoiceBox, cb -> ((ChoiceBox<?>)cb).getValue()); - addValueExtractor( n -> n instanceof ComboBox, cb -> ((ComboBox<?>)cb).getValue()); - addValueExtractor( n -> n instanceof DatePicker, dp -> ((DatePicker)dp).getValue()); - addValueExtractor( n -> n instanceof RadioButton, rb -> ((RadioButton)rb).isSelected()); - addValueExtractor( n -> n instanceof Slider, sl -> ((Slider)sl).getValue()); - addValueExtractor( n -> n instanceof TextInputControl, ta -> ((TextInputControl)ta).getText()); - - addValueExtractor( n -> n instanceof ListView, lv -> { - MultipleSelectionModel<?> sm = ((ListView<?>)lv).getSelectionModel(); - return sm.getSelectionMode() == SelectionMode.MULTIPLE ? sm.getSelectedItems() : sm.getSelectedItem(); - }); - addValueExtractor( n -> n instanceof TreeView, tv -> { - MultipleSelectionModel<?> sm = ((TreeView<?>)tv).getSelectionModel(); - return sm.getSelectionMode() == SelectionMode.MULTIPLE ? sm.getSelectedItems() : sm.getSelectedItem(); - }); - addValueExtractor( n -> n instanceof TableView, tv -> { - MultipleSelectionModel<?> sm = ((TableView<?>)tv).getSelectionModel(); - return sm.getSelectionMode() == SelectionMode.MULTIPLE ? sm.getSelectedItems() : sm.getSelectedItem(); - }); - addValueExtractor( n -> n instanceof TreeTableView, tv -> { - MultipleSelectionModel<?> sm = ((TreeTableView<?>)tv).getSelectionModel(); - return sm.getSelectionMode() == SelectionMode.MULTIPLE ? sm.getSelectedItems() : sm.getSelectedItem(); - }); - } - - private ValueExtractor() { - // no-op - } - - public static void addValueExtractor(Predicate<Node> test, Callback<Node, Object> extractor) { - valueExtractors.add(new NodeValueExtractor(test, extractor)); - } - - /** - * Attempts to return a value for the given Node. This is done by checking - * the map of value extractors, contained within this class. This - * map contains value extractors for common UI controls, but more extractors - * can be added by calling {@link #addObservableValueExtractor(Predicate, Callback)}. - * - * @param n The node from whom a value will hopefully be extracted. - * @return The value of the given node. - */ - public static Object getValue(Node n) { - for( NodeValueExtractor nve: valueExtractors ) { - if ( nve.applicability.test(n)) return nve.extraction.call(n); - } - return null; - } -} \ No newline at end of file diff --git a/src/org/controlsfx/tools/package-info.java b/src/org/controlsfx/tools/package-info.java deleted file mode 100644 index af1fe9a..0000000 --- a/src/org/controlsfx/tools/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * A package containing a number of useful utility methods. - */ -package org.controlsfx.tools; \ No newline at end of file diff --git a/src/org/controlsfx/validation/Severity.java b/src/org/controlsfx/validation/Severity.java deleted file mode 100644 index ab51e3e..0000000 --- a/src/org/controlsfx/validation/Severity.java +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.validation; - -/** - * Defines severity of validation messages - */ -public enum Severity { - - ERROR, - WARNING - -} diff --git a/src/org/controlsfx/validation/SimpleValidationMessage.java b/src/org/controlsfx/validation/SimpleValidationMessage.java deleted file mode 100644 index 314d67b..0000000 --- a/src/org/controlsfx/validation/SimpleValidationMessage.java +++ /dev/null @@ -1,95 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.validation; - -import javafx.scene.control.Control; - -/** - * Internal implementation of simple validation message - */ -class SimpleValidationMessage implements ValidationMessage { - - private final String text; - private final Severity severity; - private final Control target; - - public SimpleValidationMessage( Control target, String text, Severity severity ) { - this.text = text; - this.severity = severity == null? Severity.ERROR: severity; - this.target = target; - } - - @Override public Control getTarget() { - return target; - } - - @Override public String getText() { - return text; - } - - @Override public Severity getSeverity() { - return severity; - } - - @Override public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result - + ((severity == null) ? 0 : severity.hashCode()); - result = prime * result + ((target == null) ? 0 : target.hashCode()); - result = prime * result + ((text == null) ? 0 : text.hashCode()); - return result; - } - - @Override public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - SimpleValidationMessage other = (SimpleValidationMessage) obj; - if (severity != other.severity) - return false; - if (target == null) { - if (other.target != null) - return false; - } else if (!target.equals(other.target)) - return false; - if (text == null) { - if (other.text != null) - return false; - } else if (!text.equals(other.text)) - return false; - return true; - } - - @Override public String toString() { - return String.format("%s(%s)", severity, text); //$NON-NLS-1$ - } - -} diff --git a/src/org/controlsfx/validation/ValidationMessage.java b/src/org/controlsfx/validation/ValidationMessage.java deleted file mode 100644 index 4b836d6..0000000 --- a/src/org/controlsfx/validation/ValidationMessage.java +++ /dev/null @@ -1,91 +0,0 @@ -/** - * Copyright (c) 2014, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.validation; - -import java.util.Comparator; - -import javafx.scene.control.Control; - -/** - * Interface to define basic contract for validation message - */ -public interface ValidationMessage extends Comparable<ValidationMessage>{ - - public static final Comparator<ValidationMessage> COMPARATOR = new Comparator<ValidationMessage>() { - - @Override - public int compare(ValidationMessage vm1, ValidationMessage vm2) { - if ( vm1 == vm2 ) return 0; - if ( vm1 == null) return 1; - if ( vm2 == null) return -1; - return vm1.compareTo(vm2); - } - }; - - /** - * Message text - * @return message text - */ - public String getText(); - - /** - * Message {@link Severity} - * @return message severity - */ - public Severity getSeverity(); - - - /** - * Message target - {@link Control} which message is related to . - * @return message target - */ - public Control getTarget(); - - /** - * Factory method to create a simple error message - * @param target message target - * @param text message text - * @return error message - */ - public static ValidationMessage error( Control target, String text ) { - return new SimpleValidationMessage(target, text, Severity.ERROR); - } - - /** - * Factory method to create a simple warning message - * @param target message target - * @param text message text - * @return warning message - */ - public static ValidationMessage warning( Control target, String text ) { - return new SimpleValidationMessage(target, text, Severity.WARNING); - } - - @Override default public int compareTo(ValidationMessage msg) { - return msg == null || getTarget() != msg.getTarget() ? -1: getSeverity().compareTo(msg.getSeverity()); - } -} diff --git a/src/org/controlsfx/validation/ValidationResult.java b/src/org/controlsfx/validation/ValidationResult.java deleted file mode 100644 index 460bb3f..0000000 --- a/src/org/controlsfx/validation/ValidationResult.java +++ /dev/null @@ -1,276 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.validation; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import javafx.scene.control.Control; - -/** - * Validation result. Can generally be thought of a collection of validation messages. - * Allows for quick an painless accumulation of the messages. - * Also provides ability to combine validation results - */ -public class ValidationResult { - - private List<ValidationMessage> errors = new ArrayList<>(); - private List<ValidationMessage> warnings = new ArrayList<>(); - - /** - * Creates empty validation result - */ - public ValidationResult() {} - - /** - * Factory method to create validation result out of one message - * @param target validation target - * @param text message text - * @param severity message severity - * @param condition condition on which message will be added to validation result - * @return New instance of validation result - */ - public static final ValidationResult fromMessageIf( Control target, String text, Severity severity, boolean condition ) { - return new ValidationResult().addMessageIf(target, text, severity, condition); - } - - /** - * Factory method to create validation result out of one error - * @param target validation target - * @param text message text - * @param condition condition on which message will be added to validation result - * @return New instance of validation result - */ - public static final ValidationResult fromErrorIf( Control target, String text, boolean condition ) { - return new ValidationResult().addErrorIf(target, text, condition); - } - - /** - * Factory method to create validation result out of one warning - * @param target validation target - * @param text message text - * @param condition condition on which message will be added to validation result - * @return New instance of validation result - */ - public static final ValidationResult fromWarningIf( Control target, String text, boolean condition ) { - return new ValidationResult().addWarningIf(target, text, condition); - } - - /** - * Factory method to create validation result out of one error - * @param target validation target - * @param text message text - * @return New instance of validation result - */ - public static final ValidationResult fromError( Control target, String text ) { - return fromMessages( ValidationMessage.error(target, text)); - } - - /** - * Factory method to create validation result out of one warning - * @param target validation target - * @param text message text - * @return New instance of validation result - */ - public static final ValidationResult fromWarning( Control target, String text ) { - return fromMessages( ValidationMessage.warning(target, text)); - } - - /** - * Factory method to create validation result out of several messages - * @param messages - * @return New instance of validation result - */ - public static final ValidationResult fromMessages( ValidationMessage... messages ) { - return new ValidationResult().addAll(messages); - } - - /** - * Factory method to create validation result out of collection of messages - * @param messages - * @return New instance of validation result - */ - public static final ValidationResult fromMessages( Collection<? extends ValidationMessage> messages ) { - return new ValidationResult().addAll(messages); - } - - /** - * Factory method to create validation result out of several validation results - * @param results results - * @return New instance of validation result, combining all into one - */ - public static final ValidationResult fromResults( ValidationResult... results ) { - return new ValidationResult().combineAll(results); - } - - /** - * Factory method to create validation result out of collection of validation results - * @param results results - * @return New instance of validation result, combining all into one - */ - public static final ValidationResult fromResults( Collection<ValidationResult> results ) { - return new ValidationResult().combineAll(results); - } - - /** - * Creates a copy of validation result - * @return copy of validation result - */ - public ValidationResult copy() { - return ValidationResult.fromMessages(getMessages()); - } - - /** - * Add one message to validation result - * @param message validation message - * @return updated validation result - */ - public ValidationResult add( ValidationMessage message ) { - - if ( message != null ) { - switch( message.getSeverity() ) { - case ERROR : errors.add( message); break; - case WARNING: warnings.add(message); break; - } - } - - return this; - } - - /** - * Add one message to validation result with condition - * @param target validation target - * @param text message text - * @param severity message severity - * @param condition condition on which message will be added - * @return updated validation result - */ - public ValidationResult addMessageIf( Control target, String text, Severity severity, boolean condition) { - return condition? add( new SimpleValidationMessage(target, text, severity)): this; - } - - /** - * Add one error to validation result with condition - * @param target validation target - * @param text message text - * @param condition condition on which error will be added - * @return updated validation result - */ - public ValidationResult addErrorIf( Control target, String text, boolean condition) { - return addMessageIf(target,text,Severity.ERROR,condition); - } - - /** - * Add one warning to validation result with condition - * @param target validation target - * @param text message text - * @param condition condition on which warning will be added - * @return updated validation result - */ - public ValidationResult addWarningIf( Control target, String text, boolean condition) { - return addMessageIf(target,text,Severity.WARNING,condition); - } - - /** - * Add collection of validation messages - * @param messages - * @return updated validation result - */ - public ValidationResult addAll( Collection<? extends ValidationMessage> messages ) { - messages.stream().forEach( msg-> add(msg)); - return this; - } - - /** - * Add several validation messages - * @param messages - * @return updated validation result - */ - public ValidationResult addAll( ValidationMessage... messages ) { - return addAll(Arrays.asList(messages)); - } - - /** - * Combine validation result with another. This will create a new instance of combined validation result - * @param validationResult - * @return new instance of combined validation result - */ - public ValidationResult combine( ValidationResult validationResult ) { - return validationResult == null? copy(): copy().addAll(validationResult.getMessages()); - } - - /** - * Combine validation result with others. This will create a new instance of combined validation result - * @param validationResults - * @return new instance of combined validation result - */ - public ValidationResult combineAll( Collection<ValidationResult> validationResults ) { - return validationResults.stream().reduce(copy(), (x,r) -> { - return r == null? x: x.addAll(r.getMessages()); - }); - } - - /** - * Combine validation result with others. This will create a new instance of combined validation result - * @param validationResults - * @return new instance of combined validation result - */ - public ValidationResult combineAll( ValidationResult... validationResults ) { - return combineAll( Arrays.asList(validationResults)); - } - - /** - * Retrieve errors represented by validation result - * @return collection of errors - */ - public Collection<ValidationMessage> getErrors() { - return Collections.unmodifiableList(errors); - } - - /** - * Retrieve warnings represented by validation result - * @return collection of warnings - */ - public Collection<ValidationMessage> getWarnings() { - return Collections.unmodifiableList(warnings); - } - - /** - * Retrieve all messages represented by validation result - * @return collection of messages - */ - public Collection<ValidationMessage> getMessages() { - List<ValidationMessage> messages = new ArrayList<>(); - messages.addAll(errors); - messages.addAll(warnings); - return Collections.unmodifiableList(messages); - } - -} diff --git a/src/org/controlsfx/validation/ValidationSupport.java b/src/org/controlsfx/validation/ValidationSupport.java deleted file mode 100644 index bd70c06..0000000 --- a/src/org/controlsfx/validation/ValidationSupport.java +++ /dev/null @@ -1,329 +0,0 @@ -/** - * Copyright (c) 2014, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.validation; - -import java.util.Collections; -import java.util.Optional; -import java.util.Set; -import java.util.WeakHashMap; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Consumer; -import java.util.function.Predicate; - -import javafx.application.Platform; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.ReadOnlyBooleanProperty; -import javafx.beans.property.ReadOnlyObjectProperty; -import javafx.beans.property.ReadOnlyObjectWrapper; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.value.ObservableValue; -import javafx.collections.FXCollections; -import javafx.collections.MapChangeListener; -import javafx.collections.ObservableMap; -import javafx.collections.ObservableSet; -import javafx.scene.control.Control; -import javafx.util.Callback; - -import org.controlsfx.tools.ValueExtractor; -import org.controlsfx.validation.decoration.GraphicValidationDecoration; -import org.controlsfx.validation.decoration.ValidationDecoration; - -/** - * Provides validation support for UI components. The idea is create an instance of this class the component group, usually a panel.<br> - * Once created, {@link Validator}s can be registered for components, to provide the validation: - * - * <pre> - * ValidationSupport validationSupport = new ValidationSupport(); - * validationSupport.registerValidator(textField, Validator.createEmptyValidator("Text is required")); - * validationSupport.registerValidator(combobox, Validator.createEmptyValidator( "ComboBox Selection required")); - * validationSupport.registerValidator(checkBox, (Control c, Boolean newValue) -> - * ValidationResult.fromErrorIf( c, "Checkbox should be checked", !newValue) - * ); - * </pre> - * - * validationResultProperty provides an ability to react on overall validation result changes: - * <pre> - * validationSupport.validationResultProperty().addListener( (o, oldValue, newValue) -> - messageList.getItems().setAll(newValue.getMessages())); - * </pre> - * - * Standard JavaFX UI controls are supported out of the box. There is also an ability to add support for custom controls. - * To do that "observable value extractor" should be added for specific controls. Such "extractor" consists of two functional interfaces: - * a {@link Predicate} to check the applicability of the control and a {@link Callback} to extract control's observable value. - * Here is an sample of internal registration of such "extractor" for a few controls : - * <pre> - * ValueExtractor.addObservableValueExtractor( c -> c instanceof TextInputControl, c -> ((TextInputControl)c).textProperty()); - * ValueExtractor.addObservableValueExtractor( c -> c instanceof ComboBox, c -> ((ComboBox<?>)c).getValue()); - * </pre> - * - */ -public class ValidationSupport { - - - private static final String CTRL_REQUIRED_FLAG = "$org.controlsfx.validation.required$"; //$NON-NLS-1$ - - /** - * Set control's required flag - * @param c control - * @param required flag - */ - public static void setRequired( Control c, boolean required ) { - c.getProperties().put(CTRL_REQUIRED_FLAG, required); - } - - /** - * Check control's required flag - * @param c control - * @return true if required - */ - public static boolean isRequired( Control c ) { - Object value = c.getProperties().get(CTRL_REQUIRED_FLAG); - return value instanceof Boolean? (Boolean)value: false; - } - - private ObservableSet<Control> controls = FXCollections.observableSet(); - private ObservableMap<Control,ValidationResult> validationResults = - FXCollections.observableMap(new WeakHashMap<>()); - - - private AtomicBoolean dataChanged = new AtomicBoolean(false); - - /** - * Creates validation support instance. <br> - * If initial decoration is desired invoke {@link #initInitialDecoration()}. - */ - public ValidationSupport() { - - validationResultProperty().addListener( (o, oldValue, validationResult) -> { - invalidProperty.set(!validationResult.getErrors().isEmpty()); - redecorate(); - }); - - // notify validation result observers - validationResults.addListener( (MapChangeListener.Change<? extends Control, ? extends ValidationResult> change) -> - validationResultProperty.set(ValidationResult.fromResults(validationResults.values())) - ); - - } - - /** - * Activates the initial decoration of validated controls. <br> - * By default the decoration will only be applied after the first change of one validated controls value. - */ - public void initInitialDecoration() { - dataChanged.set(true); - redecorate(); - } - - /** - * Redecorates all known components - * Only decorations related to validation are affected - */ - // TODO needs optimization - public void redecorate() { - Optional<ValidationDecoration> odecorator = Optional.ofNullable(getValidationDecorator()); - for (Control target : getRegisteredControls()) { - odecorator.ifPresent( decorator -> { - decorator.removeDecorations(target); - decorator.applyRequiredDecoration(target); - if ( dataChanged.get() && isErrorDecorationEnabled()) { - getHighestMessage(target).ifPresent(msg -> decorator.applyValidationDecoration(msg)); - } - }); - } - } - - private BooleanProperty errorDecorationEnabledProperty = new SimpleBooleanProperty(true) { - protected void invalidated() { - redecorate(); - }; - }; - - public BooleanProperty errorDecorationEnabledProperty() { - return errorDecorationEnabledProperty; - } - - public void setErrorDecorationEnabled(boolean enabled) { - errorDecorationEnabledProperty.set(enabled); - } - - private boolean isErrorDecorationEnabled() { - return errorDecorationEnabledProperty.get(); - } - - - - private ReadOnlyObjectWrapper<ValidationResult> validationResultProperty = - new ReadOnlyObjectWrapper<>(); - - - /** - * Retrieves current validation result - * @return validation result - */ - public ValidationResult getValidationResult() { - return validationResultProperty.get(); - } - - /** - * Can be used to track validation result changes - * @return The Validation result property. - */ - public ReadOnlyObjectProperty<ValidationResult> validationResultProperty() { - return validationResultProperty.getReadOnlyProperty(); - } - - private BooleanProperty invalidProperty = new SimpleBooleanProperty(); - - /** - * Returns current validation state. - * @return true if there is at least one error - */ - public Boolean isInvalid() { - return invalidProperty.get(); - } - - /** - * Validation state property - * @return validation state property - */ - public ReadOnlyBooleanProperty invalidProperty() { - return invalidProperty; - } - - - private ObjectProperty<ValidationDecoration> validationDecoratorProperty = - new SimpleObjectProperty<ValidationDecoration>(this, "validationDecorator", new GraphicValidationDecoration()) { //$NON-NLS-1$ - @Override protected void invalidated() { - // when the decorator changes, rerun the decoration to update the visuals immediately. - redecorate(); - } - }; - - /** - * @return The Validation decorator property - */ - public ObjectProperty<ValidationDecoration> validationDecoratorProperty() { - return validationDecoratorProperty; - } - - /** - * Returns current validation decorator - * @return current validation decorator or null if none - */ - public ValidationDecoration getValidationDecorator() { - return validationDecoratorProperty.get(); - } - - /** - * Sets new validation decorator - * @param decorator new validation decorator. Null value is valid - no decoration will occur - */ - public void setValidationDecorator( ValidationDecoration decorator ) { - validationDecoratorProperty.set(decorator); - } - - - /** - * Registers {@link Validator} for specified control with additional possiblity to mark control as required or not. - * @param c control to validate - * @param required true if controls should be required - * @param validator {@link Validator} to be used - * @return true if registration is successful - */ - @SuppressWarnings("unchecked") - public <T> boolean registerValidator( final Control c, boolean required, final Validator<T> validator ) { - - Optional.ofNullable(c).ifPresent( ctrl -> { - ctrl.getProperties().addListener( new MapChangeListener<Object,Object>(){ - - @Override - public void onChanged( - javafx.collections.MapChangeListener.Change<? extends Object, ? extends Object> change) { - - if ( CTRL_REQUIRED_FLAG.equals(change.getKey())) { - redecorate(); - } - } - - }); - }); - - setRequired( c, required ); - - return ValueExtractor.getObservableValueExtractor(c).map( e -> { - - ObservableValue<T> observable = (ObservableValue<T>) e.call(c); - - Consumer<T> updateResults = value -> { - Platform.runLater(() -> validationResults.put(c, validator.apply(c, value))); - }; - - controls.add(c); - - observable.addListener( (o,oldValue,newValue) -> { - dataChanged.set(true); - updateResults.accept(newValue); - }); - updateResults.accept(observable.getValue()); - - return e; - - }).isPresent(); - } - - /** - * Registers {@link Validator} for specified control and makes control required - * @param c control to validate - * @param validator {@link Validator} to be used - * @return true if registration is successful - */ - public <T> boolean registerValidator( final Control c, final Validator<T> validator ) { - return registerValidator(c, true, validator); - } - - /** - * Returns currently registered controls - * @return set of currently registered controls - */ - public Set<Control> getRegisteredControls() { - return Collections.unmodifiableSet(controls); - } - - /** - * Returns optional highest severity message for a control - * @param target control - * @return Optional highest severity message for a control - */ - public Optional<ValidationMessage> getHighestMessage(Control target) { - return Optional.ofNullable(validationResults.get(target)).flatMap( result -> - result.getMessages().stream().max(ValidationMessage.COMPARATOR) - ); - } -} diff --git a/src/org/controlsfx/validation/Validator.java b/src/org/controlsfx/validation/Validator.java deleted file mode 100644 index 3a7aeaa..0000000 --- a/src/org/controlsfx/validation/Validator.java +++ /dev/null @@ -1,158 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.validation; - -import java.util.Collection; -import java.util.function.BiFunction; -import java.util.function.Predicate; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import javafx.scene.control.Control; - -/** - * Interface defining the contract for validation of specific component - * This interface is a {@link BiFunction} which when given the control and its current value - * computes the validation result - * - * @param <T> type of the controls value - */ -public interface Validator<T> extends BiFunction<Control, T, ValidationResult> { - - /** - * Combines the given validators into a single Validator instance. - * @param validators the validators to combine - * @return a Validator instance - */ - @SafeVarargs - static <T> Validator<T> combine(Validator<T>... validators) { - return (control, value) -> Stream.of(validators) - .map(validator -> validator.apply(control, value)) - .collect(Collectors.reducing(new ValidationResult(), ValidationResult::combine)); - } - - /** - * Factory method to create a validator, which checks if value exists. - * @param message text of a message to be created if value is invalid - * @param severity severity of a message to be created if value is invalid - * @return new validator - */ - public static <T> Validator<T> createEmptyValidator(final String message, final Severity severity) { - return (c, value) -> { - boolean condition = value instanceof String ? value.toString().trim().isEmpty() : value == null; - return ValidationResult.fromMessageIf(c, message, severity, condition); - }; - } - - /** - * Factory method to create a validator, which checks if value exists. - * Error is created if not if value does not exist - * @param message of a error to be created if value is invalid - * @return new validator - */ - public static <T> Validator<T> createEmptyValidator(final String message) { - return createEmptyValidator(message, Severity.ERROR); - } - - /** - * Factory method to create a validator, which if value exists in the provided collection. - * @param values text of a message to be created if value is not found - * @param severity severity of a message to be created if value is found - * @return new validator - */ - public static <T> Validator<T> createEqualsValidator(final String message, final Severity severity, final Collection<T> values) { - return (c, value) -> ValidationResult.fromMessageIf(c,message,severity, !values.contains(value)); - } - - /** - * Factory method to create a validator, which checks if value exists in the provided collection. - * Error is created if not found - * @param message text of a error to be created if value is not found - * @param values - * @return new validator - */ - public static <T> Validator<T> createEqualsValidator(final String message, final Collection<T> values) { - return createEqualsValidator(message, Severity.ERROR, values); - } - - /** - * Factory method to create a validator, which evaluates the value validity with a given predicate. - * Error is created if the evaluation is <code>false</code>. - * @param message text of a message to be created if value is invalid - * @param predicate the predicate to be used for the value validity evaluation. - * @return new validator - */ - static <T> Validator<T> createPredicateValidator(Predicate<T> predicate, String message) { - return createPredicateValidator(predicate, message, Severity.ERROR); - } - - /** - * Factory method to create a validator, which evaluates the value validity with a given predicate. - * Error is created if the evaluation is <code>false</code>. - * @param message text of a message to be created if value is invalid - * @param predicate the predicate to be used for the value validity evaluation. - * @param severity severity of a message to be created if value is invalid - * @return new validator - */ - static <T> Validator<T> createPredicateValidator(Predicate<T> predicate, String message, Severity severity) { - return (control, value) -> ValidationResult.fromMessageIf( - control, message, - severity, - predicate.test(value) == false); - } - - /** - * Factory method to create a validator, which checks the value against a given regular expression. - * Error is created if the value is <code>null</code> or the value does not match the pattern. - * @param message text of a message to be created if value is invalid - * @param regex the regular expression the value has to match - * @param severity severity of a message to be created if value is invalid - * @return new validator - */ - public static Validator<String> createRegexValidator(final String message, final String regex, final Severity severity) { - return (c, value) -> { - boolean condition = value == null ? true : !Pattern.matches(regex, value); - return ValidationResult.fromMessageIf(c, message, severity, condition); - }; - } - - /** - * Factory method to create a validator, which checks the value against a given regular expression. - * Error is created if the value is <code>null</code> or the value does not match the pattern. - * @param message text of a message to be created if value is invalid - * @param regex the regular expression the value has to match - * @param severity severity of a message to be created if value is invalid - * @return new validator - */ - public static Validator<String> createRegexValidator(final String message, final Pattern regex, final Severity severity) { - return (c, value) -> { - boolean condition = value == null ? true : !regex.matcher(value).matches(); - return ValidationResult.fromMessageIf(c, message, severity, condition); - }; - } -} diff --git a/src/org/controlsfx/validation/decoration/AbstractValidationDecoration.java b/src/org/controlsfx/validation/decoration/AbstractValidationDecoration.java deleted file mode 100644 index f717852..0000000 --- a/src/org/controlsfx/validation/decoration/AbstractValidationDecoration.java +++ /dev/null @@ -1,105 +0,0 @@ -/** - * Copyright (c) 2014, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.validation.decoration; - -import java.util.Collection; -import java.util.List; - -import javafx.scene.control.Control; - -import org.controlsfx.control.decoration.Decoration; -import org.controlsfx.control.decoration.Decorator; -import org.controlsfx.validation.ValidationMessage; -import org.controlsfx.validation.ValidationSupport; - -/** - * Implements common functionality for validation decorators. - * This class intended as a base for custom validation decorators - * Custom validation decorator should define only two things: - * how 'validation' and 'required' decorations should be created - * <br> - * See {@link GraphicValidationDecoration} or {@link StyleClassValidationDecoration} for examples of such implementations. - * - */ -public abstract class AbstractValidationDecoration implements ValidationDecoration { - - private static final String VALIDATION_DECORATION = "$org.controlsfx.decoration.vaidation$"; //$NON-NLS-1$ - - private static boolean isValidationDecoration( Decoration decoration) { - return decoration != null && decoration.getProperties().get(VALIDATION_DECORATION) == Boolean.TRUE; - } - - private static void setValidationDecoration( Decoration decoration ) { - if ( decoration != null ) { - decoration.getProperties().put(VALIDATION_DECORATION, Boolean.TRUE); - } - } - - protected abstract Collection<Decoration> createValidationDecorations(ValidationMessage message); - protected abstract Collection<Decoration> createRequiredDecorations(Control target); - - /** - * Removes all validation related decorations from the target - * @param target control - */ - @Override - public void removeDecorations(Control target) { - List<Decoration> decorations = Decorator.getDecorations(target); - if ( decorations != null ) { - // conversion to array is a trick to prevent concurrent modification exception - for ( Decoration d: Decorator.getDecorations(target).toArray(new Decoration[0]) ) { - if (isValidationDecoration(d)) Decorator.removeDecoration(target, d); - } - } - } - - /* - * (non-Javadoc) - * @see org.controlsfx.validation.decorator.ValidationDecorator#applyValidationDecoration(org.controlsfx.validation.ValidationMessage) - */ - @Override - public void applyValidationDecoration(ValidationMessage message) { - createValidationDecorations(message).stream().forEach( d -> decorate( message.getTarget(), d )); - } - - /* - * (non-Javadoc) - * @see org.controlsfx.validation.decorator.ValidationDecorator#applyRequiredDecoration(javafx.scene.control.Control) - */ - @Override - public void applyRequiredDecoration(Control target) { - if ( ValidationSupport.isRequired(target)) { - createRequiredDecorations(target).stream().forEach( d -> decorate( target, d )); - } - } - - private void decorate( Control target, Decoration d ) { - setValidationDecoration(d); // mark as validation specific decoration - Decorator.addDecoration(target, d); - } - -} diff --git a/src/org/controlsfx/validation/decoration/CompoundValidationDecoration.java b/src/org/controlsfx/validation/decoration/CompoundValidationDecoration.java deleted file mode 100644 index 6ba3722..0000000 --- a/src/org/controlsfx/validation/decoration/CompoundValidationDecoration.java +++ /dev/null @@ -1,93 +0,0 @@ -/** - * Copyright (c) 2014, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.validation.decoration; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -import javafx.scene.control.Control; - -import org.controlsfx.control.decoration.Decoration; -import org.controlsfx.validation.ValidationMessage; - -/** - * Validation decoration to combine several existing decorations into one. - * Here is example of combining {@link GraphicValidationDecoration} and {@link StyleClassValidationDecoration} - * <br> <br> - * <img src="CompoundValidationDecoration.png" alt="Screenshot of CompoundValidationDecoration"> - * - * - */ -public class CompoundValidationDecoration extends AbstractValidationDecoration { - - private final Set<ValidationDecoration> decorators = new HashSet<>(); - - /** - * Creates an instance of validator using a collection of validators - * @param decorators collection of validators - */ - public CompoundValidationDecoration(Collection<ValidationDecoration> decorators) { - this.decorators.addAll(decorators); - } - - /** - * Creates an instance of validator using a set of validators - * @param decorators set of validators - */ - public CompoundValidationDecoration(ValidationDecoration... decorators) { - this(Arrays.asList(decorators)); - } - - /** - * {@inheritDoc} - */ - @Override - public void applyRequiredDecoration(Control target) { - this.decorators.stream().forEach( d -> d.applyRequiredDecoration(target)); - } - - /** - * {@inheritDoc} - */ - @Override - public void applyValidationDecoration(ValidationMessage message) { - this.decorators.stream().forEach( d -> d.applyValidationDecoration(message)); - } - - @Override - protected Collection<Decoration> createValidationDecorations(ValidationMessage message) { - return Collections.emptyList(); - } - - @Override - protected Collection<Decoration> createRequiredDecorations(Control target) { - return Collections.emptyList(); - } -} diff --git a/src/org/controlsfx/validation/decoration/GraphicValidationDecoration.java b/src/org/controlsfx/validation/decoration/GraphicValidationDecoration.java deleted file mode 100644 index c405cea..0000000 --- a/src/org/controlsfx/validation/decoration/GraphicValidationDecoration.java +++ /dev/null @@ -1,127 +0,0 @@ -/** - * Copyright (c) 2014, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.validation.decoration; - - -import java.util.Arrays; -import java.util.Collection; - -import javafx.geometry.Pos; -import javafx.scene.Node; -import javafx.scene.control.Control; -import javafx.scene.control.Label; -import javafx.scene.control.Tooltip; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; - -import org.controlsfx.control.decoration.Decoration; -import org.controlsfx.control.decoration.GraphicDecoration; -import org.controlsfx.validation.Severity; -import org.controlsfx.validation.ValidationMessage; - -/** - * Validation decorator to decorate validation state using images. - * <br> - * Validation icons are shown in the bottom-left corner of the control as it is seems to be the most - * logical location for such information. - * Required components are marked at the top-left corner with small red triangle. - * Here is example of such decoration - * <br> <br> - * <img src="GraphicValidationDecorationWithTooltip.png" alt="Screenshot of GraphicValidationDecoration"> - * - */ -public class GraphicValidationDecoration extends AbstractValidationDecoration { - - // TODO we shouldn't hardcode this - defer to CSS eventually - - private static final Image ERROR_IMAGE = new Image(GraphicValidationDecoration.class.getResource("/impl/org/controlsfx/control/validation/decoration-error.png").toExternalForm()); //$NON-NLS-1$ - private static final Image WARNING_IMAGE = new Image(GraphicValidationDecoration.class.getResource("/impl/org/controlsfx/control/validation/decoration-warning.png").toExternalForm()); //$NON-NLS-1$ - private static final Image REQUIRED_IMAGE = new Image(GraphicValidationDecoration.class.getResource("/impl/org/controlsfx/control/validation/required-indicator.png").toExternalForm()); //$NON-NLS-1$ - - private static final String SHADOW_EFFECT = "-fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.8), 10, 0, 0, 0);"; //$NON-NLS-1$ - private static final String POPUP_SHADOW_EFFECT = "-fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.8), 5, 0, 0, 5);"; //$NON-NLS-1$ - private static final String TOOLTIP_COMMON_EFFECTS = "-fx-font-weight: bold; -fx-padding: 5; -fx-border-width:1;"; //$NON-NLS-1$ - - private static final String ERROR_TOOLTIP_EFFECT = POPUP_SHADOW_EFFECT + TOOLTIP_COMMON_EFFECTS - + "-fx-background-color: FBEFEF; -fx-text-fill: cc0033; -fx-border-color:cc0033;"; //$NON-NLS-1$ - - private static final String WARNING_TOOLTIP_EFFECT = POPUP_SHADOW_EFFECT + TOOLTIP_COMMON_EFFECTS - + "-fx-background-color: FFFFCC; -fx-text-fill: CC9900; -fx-border-color: CC9900;"; //$NON-NLS-1$ - - /** - * Creates default instance - */ - public GraphicValidationDecoration() { - - } - - // TODO write javadoc that users should override these methods to customise - // the error / warning / success nodes to use - protected Node createErrorNode() { - return new ImageView(ERROR_IMAGE); - } - - protected Node createWarningNode() { - return new ImageView(WARNING_IMAGE); - } - - private Node createDecorationNode(ValidationMessage message) { - Node graphic = Severity.ERROR == message.getSeverity() ? createErrorNode() : createWarningNode(); - graphic.setStyle(SHADOW_EFFECT); - Label label = new Label(); - label.setGraphic(graphic); - label.setTooltip(createTooltip(message)); - label.setAlignment(Pos.CENTER); - return label; - } - - protected Tooltip createTooltip(ValidationMessage message) { - Tooltip tooltip = new Tooltip(message.getText()); - tooltip.setOpacity(.9); - tooltip.setAutoFix(true); - tooltip.setStyle( Severity.ERROR == message.getSeverity()? ERROR_TOOLTIP_EFFECT: WARNING_TOOLTIP_EFFECT); - return tooltip; - } - - /** - * {@inheritDoc} - */ - @Override - protected Collection<Decoration> createValidationDecorations(ValidationMessage message) { - return Arrays.asList(new GraphicDecoration(createDecorationNode(message),Pos.BOTTOM_LEFT)); - } - - /** - * {@inheritDoc} - */ - @Override - protected Collection<Decoration> createRequiredDecorations(Control target) { - return Arrays.asList(new GraphicDecoration(new ImageView(REQUIRED_IMAGE),Pos.TOP_LEFT, REQUIRED_IMAGE.getWidth()/2, REQUIRED_IMAGE.getHeight()/2)); - } - - -} diff --git a/src/org/controlsfx/validation/decoration/StyleClassValidationDecoration.java b/src/org/controlsfx/validation/decoration/StyleClassValidationDecoration.java deleted file mode 100644 index 01f0b81..0000000 --- a/src/org/controlsfx/validation/decoration/StyleClassValidationDecoration.java +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Copyright (c) 2014, 2015, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.validation.decoration; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; - -import javafx.scene.control.Control; - -import org.controlsfx.control.decoration.Decoration; -import org.controlsfx.control.decoration.StyleClassDecoration; -import org.controlsfx.validation.Severity; -import org.controlsfx.validation.ValidationMessage; - -/** - * Validation decorator to decorate component validation state using two - * CSS classes for errors and warnings. - * Here is example of such decoration - * <br> <br> - * <img src="StyleClassValidationDecoration.png" alt="Screenshot of StyleClassValidationDecoration"> - */ -public class StyleClassValidationDecoration extends AbstractValidationDecoration { - - private final String errorClass; - private final String warningClass; - - /** - * Creates a default instance of a decorator - */ - public StyleClassValidationDecoration() { - this(null,null); - } - - /** - * Creates an instance of validator using custom class names - * @param errorClass class name for error decoration - * @param warningClass class name for warning decoration - */ - public StyleClassValidationDecoration(String errorClass, String warningClass) { - this.errorClass = errorClass != null? errorClass : "error"; //$NON-NLS-1$ - this.warningClass = warningClass != null? warningClass : "warning"; //$NON-NLS-1$ - } - - - @Override - protected Collection<Decoration> createValidationDecorations(ValidationMessage message) { - return Arrays.asList(new StyleClassDecoration( Severity.ERROR == message.getSeverity()? errorClass:warningClass)); - } - - @Override - protected Collection<Decoration> createRequiredDecorations(Control target) { - return Collections.emptyList(); - } - -} diff --git a/src/org/controlsfx/validation/decoration/ValidationDecoration.java b/src/org/controlsfx/validation/decoration/ValidationDecoration.java deleted file mode 100644 index a6fab8c..0000000 --- a/src/org/controlsfx/validation/decoration/ValidationDecoration.java +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Copyright (c) 2014, ControlsFX - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of ControlsFX, any associated website, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.controlsfx.validation.decoration; - -import javafx.scene.control.Control; - -import org.controlsfx.validation.ValidationMessage; - -/** - * Contract for validation decorators. - * Classes implementing this interface are used for decorating components with error/warning conditions, if such exists. - * They also used for marking 'required' components. - */ -public interface ValidationDecoration { - - /** - * Removes all validation specific decorations from the target control. - * Non-validation specific decorations are left untouched. - * @param target - */ - void removeDecorations(Control target); - - /** - * Applies validation decoration based on a given validation message - * @param message validation message - */ - void applyValidationDecoration(ValidationMessage message); - - - /** - * Applies 'required' decoration to a given control - * @param target control - */ - void applyRequiredDecoration(Control target); -} diff --git a/src/org/controlsfx/validation/decoration/package-info.java b/src/org/controlsfx/validation/decoration/package-info.java deleted file mode 100644 index de37a25..0000000 --- a/src/org/controlsfx/validation/decoration/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * A package containing decoration API specific to the validation framework. - */ -package org.controlsfx.validation.decoration; \ No newline at end of file diff --git a/src/org/controlsfx/validation/package-info.java b/src/org/controlsfx/validation/package-info.java deleted file mode 100644 index db054a1..0000000 --- a/src/org/controlsfx/validation/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -/** - * A package containing validation-related API (that is, API to allow for developers - * to easily validate user input, and to provide visual feedback on the results). - */ -package org.controlsfx.validation; \ No newline at end of file -- GitLab