Merge pull request #161 from informatik-ag-ngl/f/notify_user_of_empty_IDGenerator

Notify user of empty IDGenerators
Added:
    automatically disabled user of posting after that condition is reached
    an infoLabel used to communicate some events with the user
    (in parts) a new UI design
    cleaned up Envoy client: no more <br><br>, is now <p>
    deleted annoying alert notifying me that I'm offline
This commit is contained in:
delvh 2020-06-27 11:31:56 +02:00 committed by GitHub
commit 6754465aff
15 changed files with 109 additions and 66 deletions

View File

@ -12,9 +12,9 @@ import envoy.data.Message.MessageStatus;
import envoy.event.MessageStatusChange; import envoy.event.MessageStatusChange;
/** /**
* Represents a chat between two {@link User}s <br> * Represents a chat between two {@link User}s
* as a list of {@link Message} objects. * as a list of {@link Message} objects.
* <br> * <p>
* Project: <strong>envoy-client</strong><br> * Project: <strong>envoy-client</strong><br>
* File: <strong>Chat.java</strong><br> * File: <strong>Chat.java</strong><br>
* Created: <strong>19 Oct 2019</strong><br> * Created: <strong>19 Oct 2019</strong><br>
@ -32,7 +32,7 @@ public final class Chat implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* Provides the list of messages that the recipient receives.<br> * Provides the list of messages that the recipient receives.<p>
* Saves the Messages in the corresponding chat at that Point. * Saves the Messages in the corresponding chat at that Point.
* *
* @param recipient the user who receives the messages * @param recipient the user who receives the messages

View File

@ -11,8 +11,8 @@ import envoy.data.LoginCredentials;
/** /**
* Implements a configuration specific to the Envoy Client with default values * Implements a configuration specific to the Envoy Client with default values
* and convenience methods.<br> * and convenience methods.
* <br> * <p>
* Project: <strong>envoy-client</strong><br> * Project: <strong>envoy-client</strong><br>
* File: <strong>ClientConfig.java</strong><br> * File: <strong>ClientConfig.java</strong><br>
* Created: <strong>01.03.2020</strong><br> * Created: <strong>01.03.2020</strong><br>

View File

@ -9,8 +9,8 @@ import envoy.event.NameChange;
/** /**
* Stores information about the current {@link User} and their {@link Chat}s. * Stores information about the current {@link User} and their {@link Chat}s.
* For message ID generation a {@link IDGenerator} is stored as well.<br> * For message ID generation a {@link IDGenerator} is stored as well.
* <br> * <p>
* Project: <strong>envoy-client</strong><br> * Project: <strong>envoy-client</strong><br>
* File: <strong>LocalDB.java</strong><br> * File: <strong>LocalDB.java</strong><br>
* Created: <strong>3 Feb 2020</strong><br> * Created: <strong>3 Feb 2020</strong><br>

View File

@ -11,8 +11,8 @@ import envoy.util.SerializationUtils;
/** /**
* Implements a {@link LocalDB} in a way that stores all information inside a * Implements a {@link LocalDB} in a way that stores all information inside a
* folder on the local file system.<br> * folder on the local file system.
* <br> * <p>
* Project: <strong>envoy-client</strong><br> * Project: <strong>envoy-client</strong><br>
* File: <strong>PersistentLocalDB.java</strong><br> * File: <strong>PersistentLocalDB.java</strong><br>
* Created: <strong>27.10.2019</strong><br> * Created: <strong>27.10.2019</strong><br>

View File

@ -11,8 +11,8 @@ import envoy.util.SerializationUtils;
/** /**
* Manages all application settings, which are different objects that can be * Manages all application settings, which are different objects that can be
* changed during runtime and serialized them by using either the file system or * changed during runtime and serialized them by using either the file system or
* the {@link Preferences} API.<br> * the {@link Preferences} API.
* <br> * <p>
* Project: <strong>envoy-client</strong><br> * Project: <strong>envoy-client</strong><br>
* File: <strong>Settings.java</strong><br> * File: <strong>Settings.java</strong><br>
* Created: <strong>11 Nov 2019</strong><br> * Created: <strong>11 Nov 2019</strong><br>

View File

@ -7,8 +7,8 @@ import javax.swing.JComponent;
/** /**
* Encapsulates a persistent value that is directly or indirectly mutable by the * Encapsulates a persistent value that is directly or indirectly mutable by the
* user.<br> * user.
* <br> * <p>
* Project: <strong>envoy-client</strong><br> * Project: <strong>envoy-client</strong><br>
* File: <strong>SettingsItem.java</strong><br> * File: <strong>SettingsItem.java</strong><br>
* Created: <strong>23.12.2019</strong><br> * Created: <strong>23.12.2019</strong><br>

View File

@ -2,8 +2,8 @@ package envoy.client.data;
/** /**
* Implements a {@link LocalDB} in a way that does not persist any information * Implements a {@link LocalDB} in a way that does not persist any information
* after application shutdown.<br> * after application shutdown.
* <br> * <p>
* Project: <strong>envoy-client</strong><br> * Project: <strong>envoy-client</strong><br>
* File: <strong>TransientLocalDB.java</strong><br> * File: <strong>TransientLocalDB.java</strong><br>
* Created: <strong>3 Feb 2020</strong><br> * Created: <strong>3 Feb 2020</strong><br>

View File

@ -8,7 +8,6 @@ import envoy.event.Event;
* Created: <strong>11.02.2020</strong><br> * Created: <strong>11.02.2020</strong><br>
* *
* @author: Maximilian K&aumlfer * @author: Maximilian K&aumlfer
*
* @since Envoy Client v0.3-alpha * @since Envoy Client v0.3-alpha
*/ */
public class SendEvent extends Event<Event<?>> { public class SendEvent extends Event<Event<?>> {

View File

@ -20,8 +20,8 @@ import envoy.util.SerializationUtils;
/** /**
* Establishes a connection to the server, performs a handshake and delivers * Establishes a connection to the server, performs a handshake and delivers
* certain objects to the server.<br> * certain objects to the server.
* <br> * <p>
* Project: <strong>envoy-client</strong><br> * Project: <strong>envoy-client</strong><br>
* File: <strong>Client.java</strong><br> * File: <strong>Client.java</strong><br>
* Created: <strong>28 Sep 2019</strong><br> * Created: <strong>28 Sep 2019</strong><br>

View File

@ -12,8 +12,8 @@ import envoy.util.EnvoyLog;
/** /**
* Implements methods to send {@link Message}s and * Implements methods to send {@link Message}s and
* {@link MessageStatusChange}s to the server or cache them inside a * {@link MessageStatusChange}s to the server or cache them inside a
* {@link LocalDB} depending on the online status.<br> * {@link LocalDB} depending on the online status.
* <br> * <p>
* Project: <strong>envoy-client</strong><br> * Project: <strong>envoy-client</strong><br>
* File: <strong>WriteProxy.java</strong><br> * File: <strong>WriteProxy.java</strong><br>
* Created: <strong>6 Feb 2020</strong><br> * Created: <strong>6 Feb 2020</strong><br>

View File

@ -7,11 +7,11 @@ import javafx.scene.image.Image;
/** /**
* Provides static utility methods for loading icons from the resource * Provides static utility methods for loading icons from the resource
* folder.<br> * folder.
* <br> * <p>
* Project: <strong>envoy-client</strong> * Project: <strong>envoy-client</strong><br>
* File: <strong>IconUtil.java</strong> * File: <strong>IconUtil.java</strong><br>
* Created: <strong>16.03.2020</strong> * Created: <strong>16.03.2020</strong><br>
* *
* @author Kai S. K. Engelbart * @author Kai S. K. Engelbart
* @since Envoy Client v0.1-beta * @since Envoy Client v0.1-beta

View File

@ -16,6 +16,7 @@ import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent; import javafx.scene.input.KeyEvent;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import envoy.client.data.Chat; import envoy.client.data.Chat;
import envoy.client.data.LocalDB; import envoy.client.data.LocalDB;
@ -62,6 +63,9 @@ public final class ChatScene {
@FXML @FXML
private Label remainingChars; private Label remainingChars;
@FXML
private Label infoLabel;
@FXML @FXML
private MenuItem deleteContactMenuItem; private MenuItem deleteContactMenuItem;
@ -70,6 +74,8 @@ public final class ChatScene {
private WriteProxy writeProxy; private WriteProxy writeProxy;
private SceneContext sceneContext; private SceneContext sceneContext;
private boolean postingPermanentlyDisabled = false;
private Chat currentChat; private Chat currentChat;
private static final Settings settings = Settings.getInstance(); private static final Settings settings = Settings.getInstance();
@ -161,6 +167,7 @@ public final class ChatScene {
userList.setItems(FXCollections.observableList(localDB.getChats().stream().map(Chat::getRecipient).collect(Collectors.toList()))); userList.setItems(FXCollections.observableList(localDB.getChats().stream().map(Chat::getRecipient).collect(Collectors.toList())));
contactLabel.setText(localDB.getUser().getName()); contactLabel.setText(localDB.getUser().getName());
MessageListCell.setUser(localDB.getUser()); MessageListCell.setUser(localDB.getUser());
if (!client.isOnline()) updateInfoLabel("You are offline", Color.YELLOW);
} }
/** /**
@ -193,7 +200,7 @@ public final class ChatScene {
remainingChars remainingChars
.setText(String.format("remaining chars: %d/%d", MAX_MESSAGE_LENGTH - messageTextArea.getText().length(), MAX_MESSAGE_LENGTH)); .setText(String.format("remaining chars: %d/%d", MAX_MESSAGE_LENGTH - messageTextArea.getText().length(), MAX_MESSAGE_LENGTH));
} }
messageTextArea.setDisable(currentChat == null); messageTextArea.setDisable(currentChat == null || postingPermanentlyDisabled);
} }
/** /**
@ -240,10 +247,18 @@ public final class ChatScene {
*/ */
@FXML @FXML
private void checkPostConditions(KeyEvent e) { private void checkPostConditions(KeyEvent e) {
if (!postingPermanentlyDisabled) {
if (!postButton.isDisabled() && (settings.isEnterToSend() && e.getCode() == KeyCode.ENTER if (!postButton.isDisabled() && (settings.isEnterToSend() && e.getCode() == KeyCode.ENTER
|| !settings.isEnterToSend() && e.getCode() == KeyCode.ENTER && e.isControlDown())) || !settings.isEnterToSend() && e.getCode() == KeyCode.ENTER && e.isControlDown()))
postMessage(); postMessage();
postButton.setDisable(messageTextArea.getText().isBlank() || currentChat == null); postButton.setDisable(messageTextArea.getText().isBlank() || currentChat == null);
} else {
final var noMoreMessaging = "Go online to send messages";
if (!infoLabel.getText().equals(noMoreMessaging))
// Informing the user that he is a f*cking moron and should use Envoy online
// because he ran out of messageIDs to use
updateInfoLabel(noMoreMessaging, Color.RED);
}
} }
/** /**
@ -282,6 +297,14 @@ public final class ChatScene {
*/ */
@FXML @FXML
private void postMessage() { private void postMessage() {
postingPermanentlyDisabled = !(client.isOnline() || localDB.getIDGenerator().hasNext());
if (postingPermanentlyDisabled) {
postButton.setDisable(true);
messageTextArea.setDisable(true);
messageTextArea.clear();
updateInfoLabel("You need to go online to send more messages", Color.RED);
return;
}
final var text = messageTextArea.getText().strip(); final var text = messageTextArea.getText().strip();
if (text.isBlank()) throw new IllegalArgumentException("A message without visible text can not be sent."); if (text.isBlank()) throw new IllegalArgumentException("A message without visible text can not be sent.");
try { try {
@ -318,6 +341,19 @@ public final class ChatScene {
*/ */
private void scrollToMessageListEnd() { messageList.scrollTo(messageList.getItems().size() - 1); } private void scrollToMessageListEnd() { messageList.scrollTo(messageList.getItems().size() - 1); }
/**
* Updates the {@code infoLabel}.
*
* @param text the text to use
* @param textfill the color in which to display information
* @since Envoy Client v0.1-beta
*/
private void updateInfoLabel(String text, Paint textfill) {
infoLabel.setText(text);
infoLabel.setTextFill(textfill);
infoLabel.setVisible(true);
}
// Context menu actions // Context menu actions
@FXML @FXML

View File

@ -164,7 +164,6 @@ public final class LoginScene {
final User clientUser = (User) localDB.getUsers().get(credentials.getIdentifier()); final User clientUser = (User) localDB.getUsers().get(credentials.getIdentifier());
if (clientUser == null) throw new EnvoyException("Could not enter offline mode: user name unknown"); if (clientUser == null) throw new EnvoyException("Could not enter offline mode: user name unknown");
client.setSender(clientUser); client.setSender(clientUser);
new Alert(AlertType.WARNING, "A connection to the server could not be established. Starting in offline mode.").showAndWait();
loadChatScene(); loadChatScene();
} catch (final Exception e) { } catch (final Exception e) {
new Alert(AlertType.ERROR, "Client error: " + e).showAndWait(); new Alert(AlertType.ERROR, "Client error: " + e).showAndWait();
@ -194,9 +193,8 @@ public final class LoginScene {
localDB.synchronize(); localDB.synchronize();
if (client.isOnline()) { if (client.isOnline()) writeProxy.flushCache();
writeProxy.flushCache(); else
} else
// Set all contacts to offline mode // Set all contacts to offline mode
localDB.getChats() localDB.getChats()
.stream() .stream()

View File

@ -1,7 +1,7 @@
/** /**
* This package contains classes used for representing the settings * This package contains classes used for representing the settings
* visually.<br> * visually.
* <br> * <p>
* Project: <strong>envoy-client</strong><br> * Project: <strong>envoy-client</strong><br>
* File: <strong>package-info.java</strong><br> * File: <strong>package-info.java</strong><br>
* Created: <strong>19 Apr 2020</strong><br> * Created: <strong>19 Apr 2020</strong><br>

View File

@ -19,27 +19,27 @@
fx:controller="envoy.client.ui.controller.ChatScene"> fx:controller="envoy.client.ui.controller.ChatScene">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" <ColumnConstraints hgrow="SOMETIMES"
maxWidth="1.7976931348623157E308" minWidth="10.0" percentWidth="20.0" maxWidth="1.7976931348623157E308" minWidth="10.0" percentWidth="25.0"
prefWidth="161.0" /> prefWidth="161.0" />
<ColumnConstraints hgrow="SOMETIMES" <ColumnConstraints hgrow="SOMETIMES"
maxWidth="1.7976931348623157E308" minWidth="10.0" percentWidth="65.0" maxWidth="1.7976931348623157E308" minWidth="10.0" percentWidth="65.0"
prefWidth="357.0" /> prefWidth="357.0" />
<ColumnConstraints hgrow="SOMETIMES" <ColumnConstraints hgrow="SOMETIMES" maxWidth="10.0"
maxWidth="1.7976931348623157E308" minWidth="6.285736083984375" minWidth="10.0" percentWidth="10.0" prefWidth="10.0" />
percentWidth="15.0" prefWidth="48.000030517578125" />
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints maxHeight="1.7976931348623157E308" <RowConstraints maxHeight="1.7976931348623157E308"
minHeight="10.0" percentHeight="10.0" prefHeight="70.0" minHeight="10.0" percentHeight="10.0" prefHeight="70.0"
vgrow="SOMETIMES" /> vgrow="SOMETIMES" />
<RowConstraints maxHeight="1.7976931348623157E308" <RowConstraints maxHeight="1.7976931348623157E308"
minHeight="10.0" percentHeight="70.0" prefHeight="326.2857404436384" minHeight="10.0" percentHeight="7.0" vgrow="SOMETIMES" />
vgrow="SOMETIMES" />
<RowConstraints maxHeight="1.7976931348623157E308" <RowConstraints maxHeight="1.7976931348623157E308"
minHeight="10.0" percentHeight="5.0" prefHeight="50.0" minHeight="10.0" percentHeight="60.0" prefHeight="50.0"
vgrow="SOMETIMES" /> vgrow="SOMETIMES" />
<RowConstraints maxHeight="50.0" minHeight="10.0"
percentHeight="2.0" prefHeight="50.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="1.7976931348623157E308" <RowConstraints maxHeight="1.7976931348623157E308"
minHeight="10.0" percentHeight="15.0" prefHeight="100.0" minHeight="10.0" percentHeight="21.0" prefHeight="100.0"
vgrow="SOMETIMES" /> vgrow="SOMETIMES" />
</rowConstraints> </rowConstraints>
<children> <children>
@ -56,7 +56,7 @@
<ContextMenu anchorLocation="CONTENT_TOP_LEFT"> <ContextMenu anchorLocation="CONTENT_TOP_LEFT">
<items> <items>
<MenuItem fx:id="deleteContactMenuItem" <MenuItem fx:id="deleteContactMenuItem"
mnemonicParsing="false" text="Delete" onAction="#deleteContact" /> mnemonicParsing="false" onAction="#deleteContact" text="Delete" />
</items> </items>
</ContextMenu> </ContextMenu>
</contextMenu> </contextMenu>
@ -72,8 +72,8 @@
</Label> </Label>
<Button fx:id="settingsButton" mnemonicParsing="true" <Button fx:id="settingsButton" mnemonicParsing="true"
onAction="#settingsButtonClicked" text="_Settings" onAction="#settingsButtonClicked" text="_Settings"
GridPane.columnIndex="1" GridPane.columnSpan="2" GridPane.halignment="RIGHT" GridPane.columnIndex="1" GridPane.columnSpan="2"
GridPane.valignment="CENTER"> GridPane.halignment="RIGHT" GridPane.valignment="CENTER">
<GridPane.margin> <GridPane.margin>
<Insets bottom="10.0" left="5.0" right="10.0" top="10.0" /> <Insets bottom="10.0" left="5.0" right="10.0" top="10.0" />
</GridPane.margin> </GridPane.margin>
@ -82,7 +82,7 @@
</padding> </padding>
</Button> </Button>
<ListView fx:id="messageList" prefHeight="257.0" <ListView fx:id="messageList" prefHeight="257.0"
prefWidth="155.0" GridPane.columnIndex="1" GridPane.columnSpan="2" prefWidth="465.0" GridPane.columnIndex="1" GridPane.columnSpan="2"
GridPane.rowIndex="1" GridPane.rowSpan="2"> GridPane.rowIndex="1" GridPane.rowSpan="2">
<GridPane.margin> <GridPane.margin>
<Insets bottom="5.0" left="5.0" right="10.0" top="5.0" /> <Insets bottom="5.0" left="5.0" right="10.0" top="5.0" />
@ -93,25 +93,25 @@
<contextMenu> <contextMenu>
<ContextMenu anchorLocation="CONTENT_TOP_LEFT"> <ContextMenu anchorLocation="CONTENT_TOP_LEFT">
<items> <items>
<MenuItem mnemonicParsing="false" text="Copy" <MenuItem mnemonicParsing="false" onAction="#copyMessage"
onAction="#copyMessage" /> text="Copy" />
<MenuItem mnemonicParsing="false" text="Delete" <MenuItem mnemonicParsing="false"
onAction="#deleteMessage" /> onAction="#deleteMessage" text="Delete" />
<MenuItem mnemonicParsing="false" text="Forward" <MenuItem mnemonicParsing="false"
onAction="#forwardMessage" /> onAction="#forwardMessage" text="Forward" />
<MenuItem mnemonicParsing="false" text="Quote" <MenuItem mnemonicParsing="false"
onAction="#quoteMessage" /> onAction="#quoteMessage" text="Quote" />
</items> </items>
</ContextMenu> </ContextMenu>
</contextMenu> </contextMenu>
</ListView> </ListView>
<Button fx:id="postButton" defaultButton="true" disable="true" <Button fx:id="postButton" defaultButton="true" disable="true"
mnemonicParsing="true" onAction="#postMessage" prefHeight="10.0" mnemonicParsing="true" onAction="#postMessage" prefHeight="10.0"
prefWidth="65.0" text="_Post" GridPane.columnIndex="2" prefWidth="75.0" text="_Post" GridPane.columnIndex="2"
GridPane.halignment="CENTER" GridPane.rowIndex="3" GridPane.halignment="CENTER" GridPane.rowIndex="4"
GridPane.valignment="CENTER"> GridPane.valignment="BOTTOM">
<GridPane.margin> <GridPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0"/> <Insets bottom="10.0" left="5.0" right="10.0" />
</GridPane.margin> </GridPane.margin>
<padding> <padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" /> <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
@ -125,8 +125,8 @@
<contextMenu> <contextMenu>
<ContextMenu anchorLocation="CONTENT_TOP_LEFT"> <ContextMenu anchorLocation="CONTENT_TOP_LEFT">
<items> <items>
<MenuItem mnemonicParsing="false" text="Copy and Send" <MenuItem mnemonicParsing="false"
onAction="#copyAndPostMessage" /> onAction="#copyAndPostMessage" text="Copy and Send" />
</items> </items>
</ContextMenu> </ContextMenu>
</contextMenu> </contextMenu>
@ -135,7 +135,7 @@
onInputMethodTextChanged="#messageTextUpdated" onInputMethodTextChanged="#messageTextUpdated"
onKeyPressed="#checkPostConditions" onKeyTyped="#checkKeyCombination" onKeyPressed="#checkPostConditions" onKeyTyped="#checkKeyCombination"
prefHeight="200.0" prefWidth="200.0" wrapText="true" prefHeight="200.0" prefWidth="200.0" wrapText="true"
GridPane.columnIndex="1" GridPane.rowIndex="3"> GridPane.columnIndex="1" GridPane.rowIndex="4">
<GridPane.margin> <GridPane.margin>
<Insets bottom="10.0" left="5.0" right="5.0" top="5.0" /> <Insets bottom="10.0" left="5.0" right="5.0" top="5.0" />
</GridPane.margin> </GridPane.margin>
@ -145,20 +145,20 @@
</TextArea> </TextArea>
<Button mnemonicParsing="true" <Button mnemonicParsing="true"
onAction="#addContactButtonClicked" text="_Add Contacts" onAction="#addContactButtonClicked" text="_Add Contacts"
GridPane.halignment="CENTER" GridPane.rowIndex="3" GridPane.halignment="CENTER" GridPane.rowIndex="4"
GridPane.valignment="CENTER"> GridPane.valignment="CENTER">
<padding> <padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" /> <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding> </padding>
<GridPane.margin> <GridPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" /> <Insets bottom="5.0" left="10.0" right="5.0" top="5.0" />
</GridPane.margin> </GridPane.margin>
</Button> </Button>
<Label id="remainingCharsLabel" fx:id="remainingChars" <Label id="remainingCharsLabel" fx:id="remainingChars"
ellipsisString="" maxHeight="30.0" maxWidth="180.0" prefHeight="30.0" ellipsisString="" maxHeight="30.0" maxWidth="180.0" prefHeight="30.0"
prefWidth="180.0" text="remaining chars: 0/x" textFill="LIME" prefWidth="180.0" text="remaining chars: 0/x" textFill="LIME"
textOverrun="LEADING_WORD_ELLIPSIS" visible="false" textOverrun="LEADING_WORD_ELLIPSIS" visible="false"
GridPane.columnIndex="1" GridPane.rowIndex="2"> GridPane.columnIndex="1" GridPane.rowIndex="3">
<GridPane.margin> <GridPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" /> <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</GridPane.margin> </GridPane.margin>
@ -174,5 +174,15 @@
wrapText="true" /> wrapText="true" />
</tooltip> </tooltip>
</Label> </Label>
<Label fx:id="infoLabel" text="Something happened"
textFill="#faa007" visible="false" GridPane.columnIndex="1"
GridPane.rowIndex="1">
<GridPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</GridPane.margin>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
</Label>
</children> </children>
</GridPane> </GridPane>