Merge remote-tracking branch 'origin/main' into staging
# Conflicts: # build.gradle # demo/src/test/java/Playground.java # materialfx/gradle.properties
This commit is contained in:
commit
0a04912529
75
CHANGELOG.md
75
CHANGELOG.md
@ -1,8 +1,9 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres
|
||||
to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
(Date format is dd-MM-yyyy)
|
||||
|
||||
## Type of Changes
|
||||
@ -34,6 +35,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- PositionUtils: fix compute position methods, as sometimes "getLayoutBounds().getHeight()" can return 0. Added a
|
||||
parameter to specify whether the sizes must be computed instead of using the layoutBounds
|
||||
|
||||
## [11.13.5] - 11-04-2022
|
||||
|
||||
## Changed
|
||||
|
||||
- MFXCSSBridge: do not take into account the Region's user agent stylesheet. If it's needed to specify the user agent
|
||||
the popup's getUserAgentStylesheet() method should be overridden inline, as well as for any other component that mey
|
||||
require it (see MFXComboBoxSkin as an example) (Fix for #173)
|
||||
- Adds a method to retrieve the selection values as a List (rather than getSelection().values() which returns a generic
|
||||
Collection). Also make MultipleSelectionManager use LinkedHashSet and LinkedHashMap (TreeMap was used, oversight
|
||||
sorry) to keep insertion order for selection, this also ensures that building the values List returns the selected
|
||||
values in the same exact order as in the selection Map (Enhancement for #161)
|
||||
|
||||
## Fixed
|
||||
|
||||
- MFXTextField: fixed TextFormatter not working. It must be added on the BoundTextField, for this reason, added a
|
||||
delegate property (Fix for #174)
|
||||
- MFXComboBoxSkin, MFXFilterComboBoxSkin: fixed an issue that prevented the combo box's popup from being fully
|
||||
customizable with CSS (Fix for #173)
|
||||
- MFXDatePickerSkin: initialize the picker's text if the initial date is not null (Fix for #172)
|
||||
|
||||
## [11.13.4] - 31-03-2022
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed Maven POM
|
||||
- Fixed MFXTextField bug which was causing improper text fill in specific occasions
|
||||
|
||||
## [11.13.3] - 10-03-2022
|
||||
|
||||
### Added
|
||||
@ -47,6 +75,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Improve ROADMAP
|
||||
|
||||
## [11.13.2] - 09-02-2022
|
||||
|
||||
### Added
|
||||
|
||||
- New control MFXMagnifierPane
|
||||
@ -58,12 +87,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Added new control, MFXSpinner
|
||||
|
||||
### Changed
|
||||
|
||||
- ColorUtils: changed some method to be null-safe
|
||||
- MFXFilterPaneSkin: properly compute the minimum width
|
||||
- MFXTableViewSkin: allow to drag the filter dialog
|
||||
- MFXIconWrapper: added handler to acquire focus
|
||||
|
||||
### Fixed
|
||||
|
||||
- MFXComboBoxSkin: ensure the caret position is at 0 if the combo box is not selectable
|
||||
- MFXTableViewSkin: ensure the dialog is on foreground
|
||||
- MFXTextField and all subclasses: fixed an issue with CSS and :focused PseudoClass. It was being ignored in some cases,
|
||||
@ -80,6 +111,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- ListChangeProcessor: fix findShift() method by including the given index in the count too
|
||||
|
||||
## [11.13.0] - 22-01-2022
|
||||
|
||||
_This version won't follow the above scheme as the amount of changes and commits is simply too huge and there would be
|
||||
no way to correctly show all the changes without making mistakes (duplicates, "overlapping" changes...), for this reason
|
||||
I'll try to sum up only the major changes below._
|
||||
@ -106,22 +138,29 @@ I'll try to sum up only the major changes below._
|
||||
- The Filter API has been reviewed and now it's more powerful than ever with the new MFXFilterPane.
|
||||
- The Validation API has been reviewed as well, it is as powerful as before thanks to JavaFX properties and observables,
|
||||
but it's much more flexible. It's up to the user now to decide when and how to validate a control. Also an important
|
||||
design choice has been made here. Many validation frameworks for JavaFX also offer a way to decorate a control,
|
||||
but I decided to not to that as it would violate the Single Responsibility Principle! Validation has nothing to do with UI, plus depending on the fanciness of your App it's up to
|
||||
you to decide how the validation controls will look like!
|
||||
- Dialogs and Notifications have been reviewed as well. The dialogs have been simplified, and for notifications there are now two separate systems.
|
||||
- The date picker is now on a whole new level, it's been remade from scratch and it's simply beautiful, powerful and versatile.
|
||||
- There are also new components! MFXPopup is a PopupControl that actually works. Ever tried to style a PopupControl but no matter what the CSS would not work?
|
||||
Do not worry about that never again, just use MFXPopup it's super easy thanks to my custom MFXCSSBridge (check documentation would be too much to write here haha).
|
||||
MFXPagination has been made for MFXPaginatedTableViews, remade from scratch (meaning that doesn't extend Pagination) with a stunning modern look.
|
||||
MFXTooltip, an alternative to JavaFX's tooltip, much more versatile!
|
||||
- MFXRippleGenerator has been deprecated. The ripple generation is organized to be a new API, meaning that there are now interfaces and a base abstract class from which
|
||||
you can implement new ripple generators. The new default implementation is MFXCircleRippleGenerator. The new API also allows you to create new Ripples by implementing the IRipple interface.
|
||||
It's a rather advanced API tbh, but hey, it's there, who knows maybe someday I'll need it to be like this.
|
||||
- MFXHLoader and MFXVLoader are no more. The loading API has been "extracted" to be independent from UI. MFXLoader has the same capabilities as the aforementioned controls
|
||||
but it's not a Node. It's up to the user to decide how to manage the loaded views, and how to translate the loaded beans to a Node. (see the documentation and the DemoController for an example
|
||||
on how to easily create a nav-bar even with the new API)
|
||||
- The Selection API has been reviewed as well. It also supports the "extend selection" behavior when "Shift" is pressed, like you would expect from a file manager.
|
||||
design choice has been made here. Many validation frameworks for JavaFX also offer a way to decorate a control, but I
|
||||
decided to not to that as it would violate the Single Responsibility Principle! Validation has nothing to do with UI,
|
||||
plus depending on the fanciness of your App it's up to you to decide how the validation controls will look like!
|
||||
- Dialogs and Notifications have been reviewed as well. The dialogs have been simplified, and for notifications there
|
||||
are now two separate systems.
|
||||
- The date picker is now on a whole new level, it's been remade from scratch and it's simply beautiful, powerful and
|
||||
versatile.
|
||||
- There are also new components! MFXPopup is a PopupControl that actually works. Ever tried to style a PopupControl but
|
||||
no matter what the CSS would not work? Do not worry about that never again, just use MFXPopup it's super easy thanks
|
||||
to my custom MFXCSSBridge (check documentation would be too much to write here haha). MFXPagination has been made for
|
||||
MFXPaginatedTableViews, remade from scratch (meaning that doesn't extend Pagination) with a stunning modern look.
|
||||
MFXTooltip, an alternative to JavaFX's tooltip, much more versatile!
|
||||
- MFXRippleGenerator has been deprecated. The ripple generation is organized to be a new API, meaning that there are now
|
||||
interfaces and a base abstract class from which you can implement new ripple generators. The new default
|
||||
implementation is MFXCircleRippleGenerator. The new API also allows you to create new Ripples by implementing the
|
||||
IRipple interface. It's a rather advanced API tbh, but hey, it's there, who knows maybe someday I'll need it to be
|
||||
like this.
|
||||
- MFXHLoader and MFXVLoader are no more. The loading API has been "extracted" to be independent from UI. MFXLoader has
|
||||
the same capabilities as the aforementioned controls but it's not a Node. It's up to the user to decide how to manage
|
||||
the loaded views, and how to translate the loaded beans to a Node. (see the documentation and the DemoController for
|
||||
an example on how to easily create a nav-bar even with the new API)
|
||||
- The Selection API has been reviewed as well. It also supports the "extend selection" behavior when "Shift" is pressed,
|
||||
like you would expect from a file manager.
|
||||
- There is an insane amount of new utilities, for JavaFX as well as for Java
|
||||
|
||||
Again, let me **apologize** for this messy changelist, but I promise from next version changes will be tracked properly!
|
||||
|
@ -224,7 +224,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'io.github.palexdev:materialfx:11.13.2'
|
||||
implementation 'io.github.palexdev:materialfx:11.13.5'
|
||||
}
|
||||
```
|
||||
|
||||
@ -235,7 +235,7 @@ dependencies {
|
||||
<dependency>
|
||||
<groupId>io.github.palexdev</groupId>
|
||||
<artifactId>materialfx</artifactId>
|
||||
<version>11.13.2</version>
|
||||
<version>11.13.5</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
|
@ -4,7 +4,7 @@ plugins {
|
||||
}
|
||||
|
||||
group 'io.github.palexdev'
|
||||
version '11.14.0-EA2'
|
||||
version '11.14.0-EA3'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
@ -14,7 +14,7 @@ subprojects {
|
||||
apply plugin: 'org.openjfx.javafxplugin'
|
||||
|
||||
javafx {
|
||||
version = "17.0.2"
|
||||
version = '18'
|
||||
modules = ['javafx.controls', 'javafx.fxml', 'javafx.media', 'javafx.swing', 'javafx.web']
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
import org.apache.tools.ant.taskdefs.condition.Os
|
||||
|
||||
plugins {
|
||||
id 'application'
|
||||
id 'org.beryx.jlink' version '2.25.0'
|
||||
@ -20,14 +22,28 @@ dependencies {
|
||||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
|
||||
|
||||
implementation name: 'scenicview'
|
||||
implementation "fr.brouillard.oss:cssfx:11.4.0"
|
||||
implementation("fr.brouillard.oss:cssfx:11.4.0") { exclude group: 'org.openjfx' }
|
||||
implementation 'org.kordamp.ikonli:ikonli-core:12.2.0'
|
||||
implementation 'org.kordamp.ikonli:ikonli-javafx:12.2.0'
|
||||
implementation 'org.kordamp.ikonli:ikonli-fontawesome5-pack:12.2.0'
|
||||
implementation 'io.github.palexdev:virtualizedfx:11.2.5'
|
||||
implementation 'io.github.palexdev:virtualizedfx:11.2.6'
|
||||
implementation project(':materialfx')
|
||||
}
|
||||
|
||||
compileTestJava {
|
||||
moduleOptions {
|
||||
compileOnClasspath = true
|
||||
}
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
|
||||
moduleOptions {
|
||||
runOnClasspath = true
|
||||
}
|
||||
}
|
||||
|
||||
application {
|
||||
setMainModule("MaterialFX.Demo")
|
||||
String main = project.findProperty("chooseMain").toString()
|
||||
@ -62,19 +78,21 @@ jlink {
|
||||
jdkHome = jdkDownload("https://cdn.azul.com/zulu/bin/zulu17.32.13-ca-jdk17.0.2-macosx_x64.tar.gz")
|
||||
addExtraModulePath("/home/palexdev/Documents/JavaFX_jmods/mac_x64")
|
||||
}
|
||||
|
||||
addExtraDependencies('javafx')
|
||||
}
|
||||
|
||||
|
||||
compileTestJava {
|
||||
moduleOptions {
|
||||
compileOnClasspath = true
|
||||
task doPackageAll {
|
||||
doLast {
|
||||
if (Os.isFamily(Os.FAMILY_UNIX)) {
|
||||
exec {
|
||||
executable "$projectDir/scripts/JLinkPackage.sh"
|
||||
args = ["$buildDir"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
|
||||
moduleOptions {
|
||||
runOnClasspath = true
|
||||
}
|
||||
jlinkZip.doLast {
|
||||
doPackageAll
|
||||
}
|
32
demo/scripts/JLinkPackage.sh
Executable file
32
demo/scripts/JLinkPackage.sh
Executable file
@ -0,0 +1,32 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright (C) 2022 Parisi Alessandro
|
||||
# This file is part of MaterialFX (https://github.com/palexdev/MaterialFX).
|
||||
#
|
||||
# MaterialFX is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# MaterialFX is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with MaterialFX. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# This only works on Linux and specifically my system since tar2zip is a npm module I installed to convert the tar archive
|
||||
# to zip easily.
|
||||
# I was tired of Gradle shit and also tired of learning about boring Linux commands stuff (the tar command is quantum physic
|
||||
# and the zip command on the other hand is very limited) so this is the quickest solution I came up with
|
||||
|
||||
BASE_DIR=$1
|
||||
IMG_DIR="${BASE_DIR}/image"
|
||||
OUT_DIR="${BASE_DIR}/distributions"
|
||||
|
||||
tar -C "${IMG_DIR}/MaterialFX Demo-linux-x64" --transform 'flags=r;s|.|MFXDemo_Linux|' -c . | xz -4 > "${OUT_DIR}/materialfx_demo_linux64.tar.xz"
|
||||
tar -C "${IMG_DIR}/MaterialFX Demo-mac" --transform 'flags=r;s|.|MFXDemo_Mac|' -c . | xz -4 > "${OUT_DIR}/materialfx_demo_mac64.tar.xz"
|
||||
tar -C "${IMG_DIR}/MaterialFX Demo-win" --transform 'flags=r;s|.|MFXDemo_Win|' -c . | tar2zip > "${OUT_DIR}/materialfx_demo_win64.zip"
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Parisi Alessandro
|
||||
* This file is part of MaterialFX (https://github.com/palexdev/MaterialFX).
|
||||
*
|
||||
* MaterialFX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* MaterialFX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with MaterialFX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package selection;
|
||||
|
||||
import io.github.palexdev.materialfx.selection.MultipleSelectionModel;
|
||||
import io.github.palexdev.materialfx.utils.FXCollectors;
|
||||
import javafx.collections.ObservableList;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class MultipleSelectionModelTests {
|
||||
private final ObservableList<String> strings = IntStream.rangeClosed(0, 30)
|
||||
.mapToObj(i -> "String " + i)
|
||||
.collect(FXCollectors.toList());
|
||||
private final MultipleSelectionModel<String> selectionModel = new MultipleSelectionModel<String>(strings);
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
selectionModel.clearSelection();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrder() {
|
||||
Integer[] toSelect = {0, 6, 3, 9, 6};
|
||||
selectionModel.selectIndexes(List.of(toSelect));
|
||||
|
||||
assertEquals(4, selectionModel.getSelection().size());
|
||||
|
||||
// Indexes
|
||||
int i = 0;
|
||||
Set<Integer> indexes = selectionModel.getSelection().keySet();
|
||||
for (int val : indexes) {
|
||||
assertEquals(toSelect[i], val);
|
||||
i++;
|
||||
}
|
||||
|
||||
// Values
|
||||
i = 0;
|
||||
String[] expected = {
|
||||
"String 0",
|
||||
"String 6",
|
||||
"String 3",
|
||||
"String 9"
|
||||
};
|
||||
List<String> values = selectionModel.getSelectedValues();
|
||||
for (String value : values) {
|
||||
assertEquals(expected[i], value);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
72
demo/src/test/resources/CustomCombo.css
Normal file
72
demo/src/test/resources/CustomCombo.css
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Parisi Alessandro
|
||||
* This file is part of MaterialFX (https://github.com/palexdev/MaterialFX).
|
||||
*
|
||||
* MaterialFX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* MaterialFX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with MaterialFX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
.mfx-filter-combo-box {
|
||||
-fx-background-color: derive(#323232, 20%);
|
||||
-fx-border-color: transparent;
|
||||
-mfx-caret-visible: false;
|
||||
-mfx-float-mode: disabled;
|
||||
-fx-text-fill: white;
|
||||
}
|
||||
|
||||
.mfx-filter-combo-box .caret .mfx-ripple-generator {
|
||||
-mfx-ripple-color: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.mfx-filter-combo-box .caret .mfx-font-icon {
|
||||
-mfx-color: white
|
||||
}
|
||||
|
||||
.mfx-filter-combo-box .combo-popup .search-container {
|
||||
-fx-background-color: derive(#323232, 20%);
|
||||
-fx-background-radius: 5;
|
||||
-fx-border-color: transparent;
|
||||
-fx-padding: 10 5 5 5;
|
||||
}
|
||||
|
||||
.mfx-filter-combo-box .combo-popup .search-field {
|
||||
-fx-background-color: derive(#323232, 20%);
|
||||
-fx-text-fill: white;
|
||||
}
|
||||
|
||||
.mfx-filter-combo-box .combo-popup .search-field .text-field {
|
||||
-fx-prompt-text-fill: #ebebeb;
|
||||
}
|
||||
|
||||
.mfx-filter-combo-box .combo-popup .virtual-flow {
|
||||
-fx-background-color: transparent;
|
||||
}
|
||||
|
||||
.mfx-filter-combo-box .combo-popup .virtual-flow .mfx-combo-box-cell .data-label {
|
||||
-fx-text-fill: white;
|
||||
}
|
||||
|
||||
.mfx-filter-combo-box .combo-popup .virtual-flow .mfx-combo-box-cell:hover {
|
||||
-fx-background-color: white;
|
||||
}
|
||||
|
||||
.mfx-filter-combo-box .combo-popup .virtual-flow .mfx-combo-box-cell:hover .data-label {
|
||||
-fx-text-fill: rgba(0, 0, 0, 0.87);
|
||||
}
|
||||
|
||||
.mfx-filter-combo-box .combo-popup .virtual-flow .mfx-combo-box-cell:selected {
|
||||
-fx-background-color: white;
|
||||
}
|
||||
|
||||
.mfx-filter-combo-box .combo-popup .virtual-flow .mfx-combo-box-cell:selected .data-label {
|
||||
-fx-text-fill: rgb(0, 0, 0, 0.87);
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
import org.apache.tools.ant.taskdefs.condition.Os
|
||||
|
||||
plugins {
|
||||
id 'java-library'
|
||||
id 'biz.aQute.bnd.builder' version '6.2.0'
|
||||
id 'com.vanniktech.maven.publish' version '0.19.0'
|
||||
id 'com.github.johnrengelman.shadow' version '7.1.2'
|
||||
@ -21,9 +22,12 @@ compileJava {
|
||||
|
||||
dependencies {
|
||||
testImplementation('junit:junit:4.13.2')
|
||||
implementation 'com.vanniktech:gradle-maven-publish-plugin:0.19.0'
|
||||
|
||||
implementation 'io.github.palexdev:virtualizedfx:11.2.5'
|
||||
api 'io.github.palexdev:virtualizedfx:11.2.6'
|
||||
}
|
||||
|
||||
javafx {
|
||||
configuration = 'compileOnly'
|
||||
}
|
||||
|
||||
javadoc {
|
||||
@ -70,7 +74,7 @@ jar {
|
||||
shadowJar {
|
||||
mergeServiceFiles()
|
||||
dependencies {
|
||||
include(dependency('io.github.palexdev:virtualizedfx:11.2.5'))
|
||||
include(dependency('io.github.palexdev:virtualizedfx:11.2.6'))
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,10 +99,6 @@ build {
|
||||
dependsOn shadowJar, copyJar, removeBnd
|
||||
}
|
||||
|
||||
allprojects {
|
||||
plugins.withId("com.vanniktech.maven.publish") {
|
||||
mavenPublish {
|
||||
sonatypeHost = "S01"
|
||||
}
|
||||
}
|
||||
mavenPublish {
|
||||
sonatypeHost = "S01"
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
GROUP=io.github.palexdev
|
||||
POM_ARTIFACT_ID=materialfx
|
||||
VERSION_NAME=11.14.0-EA2
|
||||
VERSION_NAME=11.14.0-EA3
|
||||
|
||||
POM_NAME=materialfx
|
||||
POM_DESCRIPTION=Material Desgin components for JavaFX
|
||||
|
@ -41,6 +41,7 @@ import javafx.scene.Node;
|
||||
import javafx.scene.control.IndexRange;
|
||||
import javafx.scene.control.Skin;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.control.TextFormatter;
|
||||
import javafx.scene.input.ContextMenuEvent;
|
||||
import javafx.scene.paint.Color;
|
||||
|
||||
@ -422,6 +423,21 @@ public class MFXTextField extends TextField implements Validated, MFXMenuControl
|
||||
boundField.replaceSelection(replacement);
|
||||
}
|
||||
|
||||
public TextFormatter<?> delegateGetTextFormatter() {
|
||||
return boundField.getTextFormatter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the {@link BoundTextField} text formatter.
|
||||
*/
|
||||
public ObjectProperty<TextFormatter<?>> delegateTextFormatterProperty() {
|
||||
return boundField.textFormatterProperty();
|
||||
}
|
||||
|
||||
public void delegateSetTextFormatter(TextFormatter<?> textFormatter) {
|
||||
boundField.setTextFormatter(textFormatter);
|
||||
}
|
||||
|
||||
public int delegateGetAnchor() {
|
||||
return boundField.getAnchor();
|
||||
}
|
||||
|
@ -22,7 +22,6 @@ import javafx.beans.InvalidationListener;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.layout.Region;
|
||||
|
||||
/**
|
||||
* Helper class which is responsible for parsing the stylesheets for a given {@link Parent}.
|
||||
@ -64,12 +63,6 @@ public class MFXCSSBridge {
|
||||
stylesheets.clear();
|
||||
if (parent == null) return;
|
||||
|
||||
if (parent instanceof Region) {
|
||||
Region region = (Region) parent;
|
||||
if (region.getUserAgentStylesheet() != null && !region.getUserAgentStylesheet().isEmpty()) {
|
||||
stylesheets.add(region.getUserAgentStylesheet());
|
||||
}
|
||||
}
|
||||
stylesheets.addAll(parent.getStylesheets());
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,9 @@ public enum Language {
|
||||
ENGLISH(Locale.ENGLISH),
|
||||
FRENCH(Locale.FRENCH),
|
||||
ITALIANO(Locale.ITALIAN),
|
||||
RUSSIAN(Locale.forLanguageTag("ru"));
|
||||
RUSSIAN(Locale.forLanguageTag("ru")),
|
||||
SIMPLIFIED_CHINESE(Locale.SIMPLIFIED_CHINESE),
|
||||
TRADITIONAL_CHINESE(Locale.TRADITIONAL_CHINESE);
|
||||
|
||||
private final Locale locale;
|
||||
|
||||
|
@ -145,10 +145,12 @@ public class MultipleSelectionManager<T> {
|
||||
if (indexes.isEmpty()) return;
|
||||
|
||||
if (allowsMultipleSelection) {
|
||||
Set<Integer> indexesSet = new HashSet<>(indexes);
|
||||
Set<Integer> indexesSet = new LinkedHashSet<>(indexes);
|
||||
Map<Integer, T> newSelection = indexesSet.stream().collect(Collectors.toMap(
|
||||
i -> i,
|
||||
i -> selectionModel.getItems().get(i)
|
||||
i -> selectionModel.getItems().get(i),
|
||||
(t, t2) -> t2,
|
||||
LinkedHashMap::new
|
||||
));
|
||||
selection.putAll(newSelection);
|
||||
} else {
|
||||
@ -254,17 +256,17 @@ public class MultipleSelectionManager<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a new observable hash map backed by a {@link TreeMap}.
|
||||
* Builds a new observable hash map backed by a {@link LinkedHashMap}.
|
||||
*/
|
||||
protected ObservableMap<Integer, T> getMap() {
|
||||
return FXCollections.observableMap(new TreeMap<>());
|
||||
return FXCollections.observableMap(new LinkedHashMap<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a new observable hash map backed by a {@link TreeMap}, initialized with the given map.
|
||||
* Builds a new observable hash map backed by a {@link LinkedHashMap}, initialized with the given map.
|
||||
*/
|
||||
protected ObservableMap<Integer, T> getMap(Map<Integer, T> map) {
|
||||
return FXCollections.observableMap(new TreeMap<>(map));
|
||||
return FXCollections.observableMap(new LinkedHashMap<>(map));
|
||||
}
|
||||
|
||||
|
||||
@ -297,6 +299,15 @@ public class MultipleSelectionManager<T> {
|
||||
this.selection.set(selection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable {@link List} containing all the selected values extracted from
|
||||
* {@link Map#values()}.
|
||||
* The values order is kept since the selection is backed by a {@link LinkedHashMap}.
|
||||
*/
|
||||
public List<T> getSelectedValues() {
|
||||
return List.copyOf(selection.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies if this model allows multiple selection or should act like
|
||||
* a SingleSelectionModel.
|
||||
|
@ -171,6 +171,14 @@ public class MultipleSelectionModel<T> extends AbstractMultipleSelectionModel<T>
|
||||
selectionManager.setSelection(newSelection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate method for {@link MultipleSelectionManager#getSelectedValues()}.
|
||||
*/
|
||||
@Override
|
||||
public List<T> getSelectedValues() {
|
||||
return selectionManager.getSelectedValues();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate method for {@link MultipleSelectionManager#allowsMultipleSelection()}.
|
||||
*/
|
||||
|
@ -21,7 +21,9 @@ package io.github.palexdev.materialfx.selection.base;
|
||||
import javafx.beans.property.MapProperty;
|
||||
import javafx.collections.ObservableMap;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Public API that every MultipleSelectionModel must implement.
|
||||
@ -108,6 +110,13 @@ public interface IMultipleSelectionModel<T> {
|
||||
*/
|
||||
void setSelection(ObservableMap<Integer, T> newSelection);
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable {@link List} containing all the selected values extracted from
|
||||
* {@link Map#values()}.
|
||||
* The values order is kept since the selection is backed by a {@link LinkedHashMap}.
|
||||
*/
|
||||
List<T> getSelectedValues();
|
||||
|
||||
/**
|
||||
* Specifies if this model allows multiple selection or should act like
|
||||
* a SingleSelectionModel.
|
||||
|
@ -58,17 +58,7 @@ public class MFXComboBoxSkin<T> extends MFXTextFieldSkin {
|
||||
public MFXComboBoxSkin(MFXComboBox<T> comboBox, BoundTextField boundField) {
|
||||
super(comboBox, boundField);
|
||||
|
||||
popup = new MFXPopup();
|
||||
popup.getStyleClass().add("combo-popup");
|
||||
popup.setPopupStyleableParent(comboBox);
|
||||
popup.setAutoHide(true);
|
||||
popup.setConsumeAutoHidingEvents(true);
|
||||
popupManager = event -> {
|
||||
if (comboBox.getItems().isEmpty()) return;
|
||||
comboBox.show();
|
||||
};
|
||||
|
||||
initialize();
|
||||
popup = createPopup();
|
||||
setBehavior();
|
||||
|
||||
T selectedItem = comboBox.getSelectedItem();
|
||||
@ -80,10 +70,6 @@ public class MFXComboBoxSkin<T> extends MFXTextFieldSkin {
|
||||
//================================================================================
|
||||
// Methods
|
||||
//================================================================================
|
||||
protected void initialize() {
|
||||
popup.setContent(createPopupContent());
|
||||
}
|
||||
|
||||
protected void setBehavior() {
|
||||
comboBehavior();
|
||||
selectionBehavior();
|
||||
@ -231,6 +217,29 @@ public class MFXComboBoxSkin<T> extends MFXTextFieldSkin {
|
||||
comboBox.getAnimationProvider().apply(icon, showing).play();
|
||||
}
|
||||
|
||||
/**
|
||||
* Responsible for creating the combo box's popup.
|
||||
*/
|
||||
protected MFXPopup createPopup() {
|
||||
MFXComboBox<T> comboBox = getComboBox();
|
||||
MFXPopup popup = new MFXPopup() {
|
||||
@Override
|
||||
public String getUserAgentStylesheet() {
|
||||
return comboBox.getUserAgentStylesheet();
|
||||
}
|
||||
};
|
||||
popup.getStyleClass().add("combo-popup");
|
||||
popup.setPopupStyleableParent(comboBox);
|
||||
popup.setAutoHide(true);
|
||||
popup.setConsumeAutoHidingEvents(true);
|
||||
popupManager = event -> {
|
||||
if (comboBox.getItems().isEmpty()) return;
|
||||
comboBox.show();
|
||||
};
|
||||
popup.setContent(createPopupContent());
|
||||
return popup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Responsible for creating the popup's content.
|
||||
*/
|
||||
@ -241,7 +250,12 @@ public class MFXComboBoxSkin<T> extends MFXTextFieldSkin {
|
||||
comboBox.itemsProperty(),
|
||||
comboBox.getCellFactory(),
|
||||
Orientation.VERTICAL
|
||||
);
|
||||
) {
|
||||
@Override
|
||||
public String getUserAgentStylesheet() {
|
||||
return comboBox.getUserAgentStylesheet();
|
||||
}
|
||||
};
|
||||
virtualFlow.cellFactoryProperty().bind(comboBox.cellFactoryProperty());
|
||||
virtualFlow.prefWidthProperty().bind(comboBox.widthProperty());
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import io.github.palexdev.materialfx.beans.NumberRange;
|
||||
import io.github.palexdev.materialfx.controls.*;
|
||||
import io.github.palexdev.materialfx.controls.cell.MFXDateCell;
|
||||
import io.github.palexdev.materialfx.utils.DateTimeUtils;
|
||||
import io.github.palexdev.materialfx.utils.ExecutionUtils;
|
||||
import io.github.palexdev.materialfx.utils.NodeUtils;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.collections.FXCollections;
|
||||
@ -99,7 +100,12 @@ public class MFXDatePickerSkin extends MFXTextFieldSkin {
|
||||
public MFXDatePickerSkin(MFXDatePicker datePicker, BoundTextField boundField) {
|
||||
super(datePicker, boundField);
|
||||
|
||||
popup = new MFXPopup();
|
||||
popup = new MFXPopup() {
|
||||
@Override
|
||||
public String getUserAgentStylesheet() {
|
||||
return datePicker.getUserAgentStylesheet();
|
||||
}
|
||||
};
|
||||
popup.getStyleClass().add("date-picker-popup");
|
||||
popup.setPopupStyleableParent(datePicker);
|
||||
popup.setAutoHide(true);
|
||||
@ -128,7 +134,20 @@ public class MFXDatePickerSkin extends MFXTextFieldSkin {
|
||||
// Methods
|
||||
//================================================================================
|
||||
protected void initialize() {
|
||||
MFXDatePicker datePicker = getDatePicker();
|
||||
popup.setContent(createPopupContent());
|
||||
|
||||
LocalDate date = datePicker.getValue();
|
||||
if (date != null) {
|
||||
updateValue(date);
|
||||
ExecutionUtils.executeWhen(
|
||||
datePicker.delegateSelectedTextProperty(),
|
||||
(oldValue, newValue) -> datePicker.positionCaret(newValue.length()),
|
||||
false,
|
||||
(oldValue, newValue) -> !newValue.isEmpty(),
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected void setBehavior() {
|
||||
@ -275,7 +294,12 @@ public class MFXDatePickerSkin extends MFXTextFieldSkin {
|
||||
protected Node createPopupContent() {
|
||||
MFXDatePicker datePicker = getDatePicker();
|
||||
|
||||
MFXComboBox<Month> monthCombo = new MFXComboBox<>(FXCollections.observableArrayList(Month.values()));
|
||||
MFXComboBox<Month> monthCombo = new MFXComboBox<>(FXCollections.observableArrayList(Month.values())) {
|
||||
@Override
|
||||
public String getUserAgentStylesheet() {
|
||||
return datePicker.getUserAgentStylesheet();
|
||||
}
|
||||
};
|
||||
monthCombo.getStyleClass().add("months-combo");
|
||||
monthCombo.converterProperty().bind(Bindings.createObjectBinding(
|
||||
() -> datePicker.getMonthConverterSupplier().get(),
|
||||
@ -288,7 +312,12 @@ public class MFXDatePickerSkin extends MFXTextFieldSkin {
|
||||
updateGrid();
|
||||
});
|
||||
|
||||
MFXComboBox<Integer> yearCombo = new MFXComboBox<>(years);
|
||||
MFXComboBox<Integer> yearCombo = new MFXComboBox<>(years) {
|
||||
@Override
|
||||
public String getUserAgentStylesheet() {
|
||||
return datePicker.getUserAgentStylesheet();
|
||||
}
|
||||
};
|
||||
yearCombo.getStyleClass().add("years-combo");
|
||||
yearCombo.selectItem(currentYearMonth.getYear());
|
||||
yearCombo.valueProperty().addListener((observable, oldValue, newValue) -> {
|
||||
|
@ -50,7 +50,6 @@ public class MFXFilterComboBoxSkin<T> extends MFXComboBoxSkin<T> {
|
||||
//================================================================================
|
||||
public MFXFilterComboBoxSkin(MFXFilterComboBox<T> comboBox, BoundTextField boundField) {
|
||||
super(comboBox, boundField);
|
||||
popup.setContent(createPopupContent());
|
||||
addListeners();
|
||||
}
|
||||
|
||||
@ -87,9 +86,6 @@ public class MFXFilterComboBoxSkin<T> extends MFXComboBoxSkin<T> {
|
||||
//================================================================================
|
||||
// Overridden Methods
|
||||
//================================================================================
|
||||
@Override
|
||||
protected void initialize() {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
@ -108,7 +104,12 @@ public class MFXFilterComboBoxSkin<T> extends MFXComboBoxSkin<T> {
|
||||
MFXFilterComboBox<T> comboBox = getComboBox();
|
||||
TransformableList<T> filterList = comboBox.getFilterList();
|
||||
|
||||
MFXTextField searchField = new MFXTextField("", I18N.getOrDefault("filterCombo.search"));
|
||||
MFXTextField searchField = new MFXTextField("", I18N.getOrDefault("filterCombo.search")) {
|
||||
@Override
|
||||
public String getUserAgentStylesheet() {
|
||||
return comboBox.getUserAgentStylesheet();
|
||||
}
|
||||
};
|
||||
searchField.getStyleClass().add("search-field");
|
||||
searchField.textProperty().bindBidirectional(comboBox.searchTextProperty());
|
||||
searchField.setMaxWidth(Double.MAX_VALUE);
|
||||
@ -142,6 +143,4 @@ public class MFXFilterComboBoxSkin<T> extends MFXComboBoxSkin<T> {
|
||||
public MFXFilterComboBox<T> getComboBox() {
|
||||
return (MFXFilterComboBox<T>) getSkinnable();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -109,6 +109,7 @@ public class MFXTextFieldSkin extends SkinBase<MFXTextField> {
|
||||
if (textField.getLeadingIcon() != null) getChildren().add(textField.getLeadingIcon());
|
||||
if (textField.getTrailingIcon() != null) getChildren().add(textField.getTrailingIcon());
|
||||
|
||||
updateTextColor(textField.getTextFill());
|
||||
addListeners();
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,10 @@
|
||||
@import "MFXTextField.css";
|
||||
|
||||
.mfx-combo-box {
|
||||
-mfx-track-color: rgb(230, 230, 230);
|
||||
-mfx-thumb-color: rgb(137, 137, 137);
|
||||
-mfx-thumb-hover-color: rgb(89, 88, 91);
|
||||
|
||||
-mfx-gap: 0;
|
||||
-fx-padding: 3 5 3 5;
|
||||
}
|
||||
@ -42,4 +46,105 @@
|
||||
|
||||
.mfx-combo-box:disabled .caret .mfx-font-icon {
|
||||
-mfx-color: #bcbcbc;
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Virtual Flow Init
|
||||
**************************************************/
|
||||
.virtual-flow {
|
||||
-fx-background-color: white;
|
||||
}
|
||||
|
||||
/* Remove JavaFX crap */
|
||||
.scroll-bar,
|
||||
.scroll-bar .decrement-arrow,
|
||||
.scroll-bar .increment-arrow {
|
||||
-fx-pref-width: 0;
|
||||
-fx-pref-height: 0;
|
||||
}
|
||||
|
||||
|
||||
.scroll-bar:horizontal .increment-button,
|
||||
.scroll-bar:horizontal .decrement-button {
|
||||
-fx-background-color: transparent;
|
||||
-fx-background-radius: 0.0em;
|
||||
-fx-padding: 0.0 0.0 10.0 0.0;
|
||||
}
|
||||
|
||||
.scroll-bar:vertical .increment-button,
|
||||
.scroll-bar:vertical .decrement-button {
|
||||
-fx-background-color: transparent;
|
||||
-fx-background-radius: 0.0em;
|
||||
-fx-padding: 0.0 10.0 0.0 0.0;
|
||||
|
||||
}
|
||||
|
||||
.scroll-bar .increment-arrow,
|
||||
.scroll-bar .decrement-arrow {
|
||||
-fx-shape: " ";
|
||||
-fx-padding: 0.15em 0.0;
|
||||
}
|
||||
|
||||
.scroll-bar:horizontal .increment-arrow,
|
||||
.scroll-bar:horizontal .decrement-arrow {
|
||||
-fx-shape: " ";
|
||||
-fx-padding: 0.0 0.05em;
|
||||
}
|
||||
|
||||
.scroll-bar:vertical .increment-arrow,
|
||||
.scroll-bar:vertical .decrement-arrow {
|
||||
-fx-shape: " ";
|
||||
-fx-padding: 0.0 0.05em;
|
||||
}
|
||||
|
||||
/* Customize ScrollBars */
|
||||
|
||||
.scroll-bar:horizontal .track {
|
||||
-fx-background-color: -mfx-track-color;
|
||||
-fx-border-color: transparent;
|
||||
-fx-background-radius: 2.0em;
|
||||
-fx-border-radius: 2.0em;
|
||||
-fx-background-insets: 3;
|
||||
}
|
||||
|
||||
.scroll-bar:vertical .track {
|
||||
-fx-background-color: -mfx-track-color;
|
||||
-fx-border-color: transparent;
|
||||
-fx-background-radius: 2.0em;
|
||||
-fx-border-radius: 2.0em;
|
||||
-fx-background-insets: 3;
|
||||
}
|
||||
|
||||
.scroll-bar .decrement-arrow,
|
||||
.scroll-bar .increment-arrow {
|
||||
-fx-pref-width: 0;
|
||||
-fx-pref-height: 0;
|
||||
}
|
||||
|
||||
.scroll-bar:vertical {
|
||||
-fx-background-color: transparent;
|
||||
-fx-pref-width: 12;
|
||||
-fx-pref-height: 12;
|
||||
-fx-padding: 5 0.5 5 0.5;
|
||||
}
|
||||
|
||||
.scroll-bar:horizontal {
|
||||
-fx-background-color: transparent;
|
||||
-fx-pref-width: 12;
|
||||
-fx-pref-height: 12;
|
||||
-fx-padding: 0.5 5 0.5 5;
|
||||
}
|
||||
|
||||
.scroll-bar:horizontal .thumb,
|
||||
.scroll-bar:vertical .thumb {
|
||||
-fx-background-color: -mfx-thumb-color;
|
||||
-fx-background-insets: 2.0, 0.0, 0.0;
|
||||
-fx-background-radius: 2.0em;
|
||||
}
|
||||
|
||||
.scroll-bar:horizontal .thumb:hover,
|
||||
.scroll-bar:vertical .thumb:hover {
|
||||
-fx-background-color: -mfx-thumb-hover-color;
|
||||
-fx-background-insets: 1.5, 0.0, 0.0;
|
||||
-fx-background-radius: 2.0em;
|
||||
}
|
@ -18,7 +18,7 @@
|
||||
|
||||
@import "Fonts.css";
|
||||
@import "MFXColors.css";
|
||||
@import "MFXTextField.css";
|
||||
@import "MFXComboBox.css";
|
||||
|
||||
/********************
|
||||
Date Picker
|
||||
|
@ -0,0 +1,106 @@
|
||||
#
|
||||
# Copyright (C) 2022 Parisi Alessandro
|
||||
# This file is part of MaterialFX (https://github.com/palexdev/MaterialFX).
|
||||
#
|
||||
# MaterialFX is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# MaterialFX is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with MaterialFX. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
##################################################
|
||||
# Controls
|
||||
##################################################
|
||||
|
||||
# Combo Box
|
||||
comboBox.contextMenu.selectFirst=选择首个
|
||||
comboBox.contextMenu.selectNext=选择下个
|
||||
comboBox.contextMenu.selectPrevious=选择上个
|
||||
comboBox.contextMenu.selectLast=选择最后
|
||||
comboBox.contextMenu.clearSelection=清空选择
|
||||
|
||||
# Filter Combo Box
|
||||
filterCombo.search=搜索……
|
||||
|
||||
# Filter Pane
|
||||
filterPane.headerText=过滤器
|
||||
filterPane.activeFilters=激活的过滤器
|
||||
filterPane.searchField=输入你的过滤器值……
|
||||
filterPane.addFilter=添加过滤器
|
||||
|
||||
# Notification Center
|
||||
notificationCenter.contextMenu.selectAll=全选
|
||||
notificationCenter.contextMenu.selectRead=选择已读
|
||||
notificationCenter.contextMenu.selectUnread=选择未读
|
||||
notificationCenter.contextMenu.clearSelection=清空选择
|
||||
notificationCenter.contextMenu.sortState=按状态排序
|
||||
notificationCenter.contextMenu.sortTime=按时间排序
|
||||
notificationCenter.contextMenu.reverseSort=逆序
|
||||
notificationCenter.contextMenu.filterRead=筛选已读
|
||||
notificationCenter.contextMenu.filterUnread=筛选未读
|
||||
notificationCenter.contextMenu.clearFilter=清除筛选器
|
||||
notificationCenter.contextMenu.clearSort=清除排序器
|
||||
notificationCenter.contextMenu.selectionSeparator=选择
|
||||
notificationCenter.contextMenu.sortingSeparator=排序
|
||||
notificationCenter.contextMenu.filterSeparator=过滤
|
||||
notificationCenter.dnd=请勿打扰
|
||||
notificationCenter.header=通知
|
||||
|
||||
# Stepper
|
||||
stepper.next=下一步
|
||||
stepper.previous=上一步
|
||||
|
||||
# Stepper Toggle
|
||||
stepperToggle.invalidFields=无效字段……
|
||||
|
||||
# Text Fields
|
||||
textField.contextMenu.copy=复制
|
||||
textField.contextMenu.cut=剪切
|
||||
textField.contextMenu.paste=粘贴
|
||||
textField.contextMenu.delete=删除
|
||||
textField.contextMenu.selectAll=全选
|
||||
textField.contextMenu.redo=重做
|
||||
textField.contextMenu.undo=撤销
|
||||
|
||||
##################################################
|
||||
# Enums
|
||||
##################################################
|
||||
chainMode.alternativeAnd=且
|
||||
chainMode.or=或
|
||||
|
||||
##################################################
|
||||
# Filters
|
||||
##################################################
|
||||
filter.is=是
|
||||
filter.isNot=不是
|
||||
filter.greater=大于
|
||||
filter.greaterEqual=大于等于
|
||||
filter.lesser=小于
|
||||
filter.lesserEqual=小于等于
|
||||
filter.contains=包含
|
||||
filter.containsIgnCase=包含 (忽略大小写)
|
||||
filter.containsAny=包含任意
|
||||
filter.containsAll=包含全部
|
||||
filter.endsWith=以……结尾
|
||||
filter.endsWithIgnCase=以……结尾 (忽略大小写)
|
||||
filter.equals=等于
|
||||
filter.equalsIgnCase=等于 (忽略大小写)
|
||||
filter.notEqual=不等于
|
||||
filter.startsWith=以……开头
|
||||
filter.startsWithIgnCase=以……开头 (忽略大小写)
|
||||
|
||||
##################################################
|
||||
# Utils
|
||||
##################################################
|
||||
stringUtil.now=刚刚
|
||||
stringUtil.minutes={0} 分钟之前
|
||||
stringUtils.hours={0} 小时之前
|
||||
stringUtils.days={0} 天之前
|
@ -0,0 +1,106 @@
|
||||
#
|
||||
# Copyright (C) 2022 Parisi Alessandro
|
||||
# This file is part of MaterialFX (https://github.com/palexdev/MaterialFX).
|
||||
#
|
||||
# MaterialFX is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# MaterialFX is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with MaterialFX. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
##################################################
|
||||
# Controls
|
||||
##################################################
|
||||
|
||||
# Combo Box
|
||||
comboBox.contextMenu.selectFirst=選擇首個
|
||||
comboBox.contextMenu.selectNext=選擇下個
|
||||
comboBox.contextMenu.selectPrevious=選擇上個
|
||||
comboBox.contextMenu.selectLast=選擇最後
|
||||
comboBox.contextMenu.clearSelection=清空選擇
|
||||
|
||||
# Filter Combo Box
|
||||
filterCombo.search=蒐索……
|
||||
|
||||
# Filter Pane
|
||||
filterPane.headerText=篩檢程式
|
||||
filterPane.activeFilters=活動的篩檢程式
|
||||
filterPane.searchField=輸入你的篩檢程式值……
|
||||
filterPane.addFilter=添加篩檢程式
|
||||
|
||||
# Notification Center
|
||||
notificationCenter.contextMenu.selectAll=全選
|
||||
notificationCenter.contextMenu.selectRead=選擇已讀
|
||||
notificationCenter.contextMenu.selectUnread=選擇未讀
|
||||
notificationCenter.contextMenu.clearSelection=清空選擇
|
||||
notificationCenter.contextMenu.sortState=按狀態排序
|
||||
notificationCenter.contextMenu.sortTime=按時間排序
|
||||
notificationCenter.contextMenu.reverseSort=逆序
|
||||
notificationCenter.contextMenu.filterRead=篩選已讀
|
||||
notificationCenter.contextMenu.filterUnread=篩選未讀
|
||||
notificationCenter.contextMenu.clearFilter=清除篩選器
|
||||
notificationCenter.contextMenu.clearSort=清除排序器
|
||||
notificationCenter.contextMenu.selectionSeparator=選擇
|
||||
notificationCenter.contextMenu.sortingSeparator=排序
|
||||
notificationCenter.contextMenu.filterSeparator=過濾
|
||||
notificationCenter.dnd=請勿打擾
|
||||
notificationCenter.header=通知
|
||||
|
||||
# Stepper
|
||||
stepper.next=下一步
|
||||
stepper.previous=上一步
|
||||
|
||||
# Stepper Toggle
|
||||
stepperToggle.invalidFields=無效欄位……
|
||||
|
||||
# Text Fields
|
||||
textField.contextMenu.copy=複製
|
||||
textField.contextMenu.cut=剪切
|
||||
textField.contextMenu.paste=粘貼
|
||||
textField.contextMenu.delete=删除
|
||||
textField.contextMenu.selectAll=全選
|
||||
textField.contextMenu.redo=重做
|
||||
textField.contextMenu.undo=撤銷
|
||||
|
||||
##################################################
|
||||
# Enums
|
||||
##################################################
|
||||
chainMode.alternativeAnd=且
|
||||
chainMode.or=或
|
||||
|
||||
##################################################
|
||||
# Filters
|
||||
##################################################
|
||||
filter.is=是
|
||||
filter.isNot=不是
|
||||
filter.greater=大於
|
||||
filter.greaterEqual=大於等於
|
||||
filter.lesser=小於
|
||||
filter.lesserEqual=小於等於
|
||||
filter.contains=包含
|
||||
filter.containsIgnCase=包含 (忽略大小寫)
|
||||
filter.containsAny=包含任意
|
||||
filter.containsAll=包含全部
|
||||
filter.endsWith=以……結尾
|
||||
filter.endsWithIgnCase=以……結尾 (忽略大小寫)
|
||||
filter.equals=等於
|
||||
filter.equalsIgnCase=等於 (忽略大小寫)
|
||||
filter.notEqual=不等於
|
||||
filter.startsWith=以……開頭
|
||||
filter.startsWithIgnCase=以……開頭 (忽略大小寫)
|
||||
|
||||
##################################################
|
||||
# Utils
|
||||
##################################################
|
||||
stringUtil.now=剛剛
|
||||
stringUtil.minutes={0} 分鐘之前
|
||||
stringUtils.hours={0} 小時之前
|
||||
stringUtils.days={0} 天之前
|
Loading…
x
Reference in New Issue
Block a user