From 9a1f824bc5e2261f295df3c97ceaa580e15ad9a9 Mon Sep 17 00:00:00 2001
From: Robert Goldmann <deadlocker@gmx.de>
Date: Sun, 17 Sep 2017 14:11:23 +0200
Subject: [PATCH] #96 - added tags to filter

---
 .../budgetmaster/logic/FilterSettings.java    |  48 +++-
 .../logic/payment/PaymentHandler.java         |  34 ++-
 .../budgetmaster/logic/tag/TagHandler.java    |  12 +
 .../resources/languages/_de.properties        |   3 +
 .../resources/languages/_en.properties        |   3 +
 .../ui/controller/Controller.java             |   3 +-
 .../ui/controller/FilterController.java       |  86 ++++++-
 .../budgetmaster/ui/fxml/FilterGUI.fxml       | 239 +++++++++++-------
 8 files changed, 319 insertions(+), 109 deletions(-)

diff --git a/src/de/deadlocker8/budgetmaster/logic/FilterSettings.java b/src/de/deadlocker8/budgetmaster/logic/FilterSettings.java
index 7a72815d0..c016f5a2c 100644
--- a/src/de/deadlocker8/budgetmaster/logic/FilterSettings.java
+++ b/src/de/deadlocker8/budgetmaster/logic/FilterSettings.java
@@ -10,9 +10,10 @@ public class FilterSettings
 	private boolean isMonthlyRepeatingAllowed;
 	private boolean isRepeatingEveryXDaysAllowed;
 	private ArrayList<Integer> allowedCategoryIDs;
+	private ArrayList<Integer> allowedTagIDs;
 	private String name;
 
-	public FilterSettings(boolean isIncomeAllowed, boolean isPaymentAllowed, boolean isNoRepeatingAllowed, boolean isMonthlyRepeatingAllowed, boolean isRepeatingEveryXDaysAllowed, ArrayList<Integer> allowedCategoryIDs, String name)
+	public FilterSettings(boolean isIncomeAllowed, boolean isPaymentAllowed, boolean isNoRepeatingAllowed, boolean isMonthlyRepeatingAllowed, boolean isRepeatingEveryXDaysAllowed, ArrayList<Integer> allowedCategoryIDs, ArrayList<Integer> allowedTagIDs, String name)
 	{
 		this.isIncomeAllowed = isIncomeAllowed;
 		this.isPaymentAllowed = isPaymentAllowed;
@@ -20,6 +21,7 @@ public class FilterSettings
 		this.isMonthlyRepeatingAllowed = isMonthlyRepeatingAllowed;
 		this.isRepeatingEveryXDaysAllowed = isRepeatingEveryXDaysAllowed;
 		this.allowedCategoryIDs = allowedCategoryIDs;
+		this.allowedTagIDs = allowedTagIDs;
 		this.name = name;
 	}
 
@@ -31,6 +33,7 @@ public class FilterSettings
 		this.isMonthlyRepeatingAllowed = true;
 		this.isRepeatingEveryXDaysAllowed = true;
 		this.allowedCategoryIDs = null;
+		this.allowedTagIDs = null;
 		this.name = null;
 	}
 
@@ -93,6 +96,16 @@ public class FilterSettings
 	{
 		this.allowedCategoryIDs = allowedCategoryIDs;
 	}
+	
+	public ArrayList<Integer> getAllowedTagIDs()
+	{
+		return allowedTagIDs;
+	}
+
+	public void setAllowedTagIDs(ArrayList<Integer> allowedTagIDs)
+	{
+		this.allowedTagIDs = allowedTagIDs;
+	}
 
 	public String getName()
 	{
@@ -102,12 +115,13 @@ public class FilterSettings
 	public void setName(String name)
 	{
 		this.name = name;
-	}
+	}	
 
+	@Override
 	public String toString()
 	{
 		return "FilterSettings [isIncomeAllowed=" + isIncomeAllowed + ", isPaymentAllowed=" + isPaymentAllowed + ", isNoRepeatingAllowed=" + isNoRepeatingAllowed + ", isMonthlyRepeatingAllowed=" + isMonthlyRepeatingAllowed + ", isRepeatingEveryXDaysAllowed=" + isRepeatingEveryXDaysAllowed
-				+ ", allowedCategoryIDs=" + allowedCategoryIDs + ", name=" + name + "]";
+				+ ", allowedCategoryIDs=" + allowedCategoryIDs + ", allowedTagIDs=" + allowedTagIDs + ", name=" + name + "]";
 	}
 
 	public boolean equals(Object other)
@@ -166,7 +180,33 @@ public class FilterSettings
 						return true;		
 					}
 				}				
-			}				
+			}
+			
+			if(allowedTagIDs == null)
+			{
+				if(otherSettings.getAllowedTagIDs() != null)
+				{
+					return false;				
+				}
+				else
+				{
+					return true;
+				}
+			}
+			else 
+			{
+				if(otherSettings.getAllowedTagIDs() == null)
+				{
+					return false;
+				}
+				else
+				{					
+					if(allowedTagIDs.equals(otherSettings.getAllowedTagIDs())) 
+					{
+						return true;		
+					}
+				}
+			}
 		}			
 			
 		return false;
diff --git a/src/de/deadlocker8/budgetmaster/logic/payment/PaymentHandler.java b/src/de/deadlocker8/budgetmaster/logic/payment/PaymentHandler.java
index bbbd83432..a47320061 100644
--- a/src/de/deadlocker8/budgetmaster/logic/payment/PaymentHandler.java
+++ b/src/de/deadlocker8/budgetmaster/logic/payment/PaymentHandler.java
@@ -6,6 +6,7 @@ import java.util.Comparator;
 import java.util.stream.Collectors;
 
 import de.deadlocker8.budgetmaster.logic.FilterSettings;
+import de.deadlocker8.budgetmaster.logic.tag.TagHandler;
 
 public class PaymentHandler
 {
@@ -152,13 +153,44 @@ public class PaymentHandler
 		return new ArrayList<>();
 	}
 	
-	public void filter(FilterSettings filterSettings)
+	private ArrayList<Payment> filterByTag(FilterSettings filterSettings, ArrayList<Payment> paymentsList, TagHandler tagHandler) throws Exception
+	{		
+		if(filterSettings.getAllowedTagIDs() == null)			
+		{
+			return paymentsList;
+		}
+		
+		if(filterSettings.getAllowedTagIDs().size() == 0)
+		{
+			return new ArrayList<>();
+		}
+		
+		ArrayList<Payment> filteredPayments = new ArrayList<>();
+		for(Payment currentPayment : paymentsList)
+		{
+			ArrayList<Integer> paymentTagIDs = tagHandler.getTagIDs(currentPayment);
+			
+			for(Integer tagID : filterSettings.getAllowedTagIDs())
+			{
+				if(paymentTagIDs.contains(tagID))
+				{
+					filteredPayments.add(currentPayment);
+					break;
+				}
+			}
+		}
+		
+		return filteredPayments;		
+	}
+	
+	public void filter(FilterSettings filterSettings, TagHandler tagHandler) throws Exception
 	{
 		ArrayList<Payment> filteredPayments = filterByType(filterSettings, payments);
 		filteredPayments = filterByType(filterSettings, filteredPayments);
 		filteredPayments = filterByRepeating(filterSettings, filteredPayments);
 		filteredPayments = filterByCategory(filterSettings, filteredPayments);
 		filteredPayments = filterByName(filterSettings, filteredPayments);
+		filteredPayments = filterByTag(filterSettings, filteredPayments, tagHandler);
 		
 		payments = filteredPayments;
 	}
diff --git a/src/de/deadlocker8/budgetmaster/logic/tag/TagHandler.java b/src/de/deadlocker8/budgetmaster/logic/tag/TagHandler.java
index 6ea0b5a8f..d4f0f1731 100644
--- a/src/de/deadlocker8/budgetmaster/logic/tag/TagHandler.java
+++ b/src/de/deadlocker8/budgetmaster/logic/tag/TagHandler.java
@@ -50,4 +50,16 @@ public class TagHandler
 		
 		return sb.toString();
 	}
+	
+	public ArrayList<Integer> getTagIDs(Payment payment) throws Exception
+	{
+		ArrayList<Tag> tags = getTags(payment);
+		ArrayList<Integer> ids = new ArrayList<>();
+		for(Tag currentTag : tags)
+		{
+			ids.add(currentTag.getID());
+		}
+		
+		return ids;
+	}
 }
\ No newline at end of file
diff --git a/src/de/deadlocker8/budgetmaster/resources/languages/_de.properties b/src/de/deadlocker8/budgetmaster/resources/languages/_de.properties
index fa670423f..a92ec778d 100644
--- a/src/de/deadlocker8/budgetmaster/resources/languages/_de.properties
+++ b/src/de/deadlocker8/budgetmaster/resources/languages/_de.properties
@@ -226,6 +226,9 @@ filter.categories=Kategorien
 filter.categories.button.all=Alle
 filter.categories.button.none=Keine
 filter.name=Name
+filter.tags=Tags
+filter.tags.button.all=Alle
+filter.tags.button.none=Keine
 filter.button.reset=Zur�cksetzen
 filter.button.filter=Filtern
 
diff --git a/src/de/deadlocker8/budgetmaster/resources/languages/_en.properties b/src/de/deadlocker8/budgetmaster/resources/languages/_en.properties
index 254b8bdba..aefaa2180 100644
--- a/src/de/deadlocker8/budgetmaster/resources/languages/_en.properties
+++ b/src/de/deadlocker8/budgetmaster/resources/languages/_en.properties
@@ -226,6 +226,9 @@ filter.categories=Categories
 filter.categories.button.all=All
 filter.categories.button.none=None
 filter.name=Name
+filter.tags=Tags
+filter.tags.button.all=All
+filter.tags.button.none=None
 filter.button.reset=Reset
 filter.button.filter=Filter
 
diff --git a/src/de/deadlocker8/budgetmaster/ui/controller/Controller.java b/src/de/deadlocker8/budgetmaster/ui/controller/Controller.java
index 210d70e90..d365de4af 100644
--- a/src/de/deadlocker8/budgetmaster/ui/controller/Controller.java
+++ b/src/de/deadlocker8/budgetmaster/ui/controller/Controller.java
@@ -15,6 +15,7 @@ import de.deadlocker8.budgetmaster.logic.payment.Payment;
 import de.deadlocker8.budgetmaster.logic.payment.PaymentHandler;
 import de.deadlocker8.budgetmaster.logic.serverconnection.ExceptionHandler;
 import de.deadlocker8.budgetmaster.logic.serverconnection.ServerConnection;
+import de.deadlocker8.budgetmaster.logic.tag.TagHandler;
 import de.deadlocker8.budgetmaster.logic.updater.Updater;
 import de.deadlocker8.budgetmaster.logic.updater.VersionInformation;
 import de.deadlocker8.budgetmaster.logic.utils.Colors;
@@ -582,7 +583,7 @@ public class Controller extends BaseController
 				categoryHandler = new CategoryHandler(connection.getCategories());
 				
 				categoryBudgets = connection.getCategoryBudgets(currentDate.getYear(), currentDate.getMonthOfYear());	
-				paymentHandler.filter(newFilterSettings);
+				paymentHandler.filter(newFilterSettings, new TagHandler(settings));
 
 				Platform.runLater(() -> {
 					if(modalStage != null)
diff --git a/src/de/deadlocker8/budgetmaster/ui/controller/FilterController.java b/src/de/deadlocker8/budgetmaster/ui/controller/FilterController.java
index c54675d6a..531ba2697 100644
--- a/src/de/deadlocker8/budgetmaster/ui/controller/FilterController.java
+++ b/src/de/deadlocker8/budgetmaster/ui/controller/FilterController.java
@@ -4,6 +4,8 @@ import java.util.ArrayList;
 
 import de.deadlocker8.budgetmaster.logic.FilterSettings;
 import de.deadlocker8.budgetmaster.logic.category.Category;
+import de.deadlocker8.budgetmaster.logic.serverconnection.ServerTagConnection;
+import de.deadlocker8.budgetmaster.logic.tag.Tag;
 import de.deadlocker8.budgetmaster.logic.utils.Colors;
 import de.deadlocker8.budgetmaster.logic.utils.Helpers;
 import de.deadlocker8.budgetmaster.logic.utils.Strings;
@@ -13,17 +15,21 @@ import javafx.fxml.FXML;
 import javafx.scene.Node;
 import javafx.scene.control.Button;
 import javafx.scene.control.CheckBox;
+import javafx.scene.control.ScrollPane;
 import javafx.scene.control.TextField;
 import javafx.scene.input.KeyCode;
 import javafx.scene.layout.VBox;
 import javafx.scene.paint.Color;
 import javafx.stage.Modality;
 import javafx.stage.Stage;
+import logger.Logger;
 import tools.ConvertTo;
 import tools.Localization;
 
 public class FilterController extends BaseController implements Styleable
 {
+	@FXML private ScrollPane scrollPane;
+	@FXML private VBox vboxMain;
 	@FXML private CheckBox checkBoxIncome;
 	@FXML private CheckBox checkBoxPayment;
 	@FXML private CheckBox checkBoxNoRepeating;
@@ -31,15 +37,19 @@ public class FilterController extends BaseController implements Styleable
 	@FXML private CheckBox checkBoxRepeatEveryXDays;
 	@FXML private VBox vboxCategories;
 	@FXML private TextField textFieldSearch;
+	@FXML private VBox vboxTags;
 	@FXML private Button buttonCancel;
 	@FXML private Button buttonReset;
 	@FXML private Button buttonFilter;
 	@FXML private Button buttonCategoryAll;
 	@FXML private Button buttonCategoryNone;
+	@FXML private Button buttonTagsAll;
+	@FXML private Button buttonTagsNone;
 
 	private Stage parentStage;
 	private Controller controller;
 	private FilterSettings filterSetttings;
+	private ArrayList<Tag> allTags;
 	
 	public FilterController(Stage parentStage, Controller controller, FilterSettings filterSettings)
 	{
@@ -57,7 +67,9 @@ public class FilterController extends BaseController implements Styleable
 		stage.initModality(Modality.APPLICATION_MODAL);	
 		stage.setTitle(Localization.getString(Strings.TITLE_FILTER));
 		stage.getIcons().add(controller.getIcon());
-		stage.setResizable(false);		
+		stage.setResizable(true);
+		stage.setMinHeight(600);
+		stage.setMinWidth(475);
 	}
 
 	@Override
@@ -74,13 +86,34 @@ public class FilterController extends BaseController implements Styleable
 			vboxCategories.getChildren().add(newCheckBox);
 		}
 		
+		try
+		{
+			ServerTagConnection connection = new ServerTagConnection(controller.getSettings());
+			allTags = connection.getTags();
+			for(Tag currentTag : allTags)
+			{
+				CheckBox newCheckBox = new CheckBox();
+				newCheckBox.setText(currentTag.getName());
+				newCheckBox.setUserData(currentTag.getID());
+				newCheckBox.setStyle("-fx-font-size: 14;");
+				vboxTags.getChildren().add(newCheckBox);
+			}
+		}
+		catch(Exception e)
+		{
+			//ERRORHANDLING
+			Logger.error(e);
+		}
+	
 		textFieldSearch.setOnKeyPressed((event)->{
             if(event.getCode().equals(KeyCode.ENTER))
             {
             	filter();
             }
 	    });
-
+		
+		vboxMain.prefWidthProperty().bind(scrollPane.widthProperty().subtract(25));
+		vboxMain.prefHeightProperty().bind(scrollPane.heightProperty().subtract(5));
 		preselect();
 	}
 
@@ -93,7 +126,6 @@ public class FilterController extends BaseController implements Styleable
 		checkBoxRepeatEveryXDays.setSelected(filterSetttings.isRepeatingEveryXDaysAllowed());
 
 		ArrayList<Integer> allowedCategoryIDs = filterSetttings.getAllowedCategoryIDs();
-
 		for(Node node : vboxCategories.getChildren())
 		{
 			CheckBox currentCheckBox = (CheckBox)node;
@@ -102,6 +134,16 @@ public class FilterController extends BaseController implements Styleable
 				currentCheckBox.setSelected(true);
 			}
 		}
+		
+		ArrayList<Integer> allowedTagIDs = filterSetttings.getAllowedTagIDs();
+		for(Node node : vboxTags.getChildren())
+		{
+			CheckBox currentCheckBox = (CheckBox)node;
+			if(allowedTagIDs == null || allowedTagIDs.contains(currentCheckBox.getUserData()))
+			{
+				currentCheckBox.setSelected(true);
+			}
+		}
 
 		textFieldSearch.setText(filterSetttings.getName());
 	}
@@ -135,8 +177,23 @@ public class FilterController extends BaseController implements Styleable
 		{
 			name = null;
 		}
+		
+		ArrayList<Integer> allowedTagIDs = new ArrayList<>();
+		for(Node node : vboxTags.getChildren())
+		{
+			CheckBox currentCheckBox = (CheckBox)node;
+			if(currentCheckBox.isSelected())
+			{
+				allowedTagIDs.add((int)currentCheckBox.getUserData());
+			}
+		}
+
+		if(allowedTagIDs.size() == allTags.size())
+		{
+			allowedTagIDs = null;
+		}
 
-		FilterSettings newFilterSettings = new FilterSettings(isIncomeAllowed, isPaymentAllowed, isNoRepeatingAllowed, isMonthlyRepeatingAllowed, isRepeatingEveryXDaysAllowed, allowedCategoryIDs, name);
+		FilterSettings newFilterSettings = new FilterSettings(isIncomeAllowed, isPaymentAllowed, isNoRepeatingAllowed, isMonthlyRepeatingAllowed, isRepeatingEveryXDaysAllowed, allowedCategoryIDs, allowedTagIDs, name);
 		controller.setFilterSettings(newFilterSettings);
 		controller.refresh(newFilterSettings);		
 		getStage().close();
@@ -170,18 +227,37 @@ public class FilterController extends BaseController implements Styleable
 			((CheckBox)node).setSelected(false);
 		}
 	}
+	
+	public void enableAllTags()
+	{
+		for(Node node : vboxTags.getChildren())
+		{
+			((CheckBox)node).setSelected(true);
+		}
+	}
+	
+	public void disableAllTags()
+	{
+		for(Node node : vboxTags.getChildren())
+		{
+			((CheckBox)node).setSelected(false);
+		}
+	}
 
 	@Override
 	public void applyStyle()
 	{
 		buttonCancel.setGraphic(Helpers.getFontIcon(FontIconType.TIMES, 17, Color.WHITE));
 		buttonReset.setGraphic(Helpers.getFontIcon(FontIconType.UNDO, 17, Color.WHITE));		
-		buttonFilter.setGraphic(Helpers.getFontIcon(FontIconType.FILTER, 17, Color.WHITE));
+		buttonFilter.setGraphic(Helpers.getFontIcon(FontIconType.FILTER, 17, Color.WHITE));		
 
+		scrollPane.setStyle("-fx-background-color: transparent");
 		buttonCancel.setStyle("-fx-background-color: " + ConvertTo.toRGBHexWithoutOpacity(Colors.BACKGROUND_BUTTON_BLUE) + "; -fx-text-fill: white; -fx-font-weight: bold; -fx-font-size: 15;");
 		buttonReset.setStyle("-fx-background-color: " + ConvertTo.toRGBHexWithoutOpacity(Colors.BACKGROUND_BUTTON_BLUE) + "; -fx-text-fill: white; -fx-font-weight: bold; -fx-font-size: 15;");
 		buttonFilter.setStyle("-fx-background-color: " + ConvertTo.toRGBHexWithoutOpacity(Colors.BACKGROUND_BUTTON_BLUE) + "; -fx-text-fill: white; -fx-font-weight: bold; -fx-font-size: 15;");
 		buttonCategoryAll.setStyle("-fx-background-color: " + ConvertTo.toRGBHexWithoutOpacity(Colors.BACKGROUND_BUTTON_BLUE) + "; -fx-text-fill: white; -fx-font-weight: bold; -fx-font-size: 13;");
 		buttonCategoryNone.setStyle("-fx-background-color: " + ConvertTo.toRGBHexWithoutOpacity(Colors.BACKGROUND_BUTTON_BLUE) + "; -fx-text-fill: white; -fx-font-weight: bold; -fx-font-size: 13;");
+		buttonTagsAll.setStyle("-fx-background-color: " + ConvertTo.toRGBHexWithoutOpacity(Colors.BACKGROUND_BUTTON_BLUE) + "; -fx-text-fill: white; -fx-font-weight: bold; -fx-font-size: 13;");
+		buttonTagsNone.setStyle("-fx-background-color: " + ConvertTo.toRGBHexWithoutOpacity(Colors.BACKGROUND_BUTTON_BLUE) + "; -fx-text-fill: white; -fx-font-weight: bold; -fx-font-size: 13;");
 	}
 }
\ No newline at end of file
diff --git a/src/de/deadlocker8/budgetmaster/ui/fxml/FilterGUI.fxml b/src/de/deadlocker8/budgetmaster/ui/fxml/FilterGUI.fxml
index 64fe45b30..41999d4ad 100644
--- a/src/de/deadlocker8/budgetmaster/ui/fxml/FilterGUI.fxml
+++ b/src/de/deadlocker8/budgetmaster/ui/fxml/FilterGUI.fxml
@@ -14,128 +14,171 @@
 
 <AnchorPane prefHeight="600.0" prefWidth="450.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1">
    <children>
-      <VBox prefHeight="273.0" prefWidth="465.0" spacing="25.0" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="14.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="14.0">
-         <children>
-            <Label text="%filter.headline">
-               <font>
-                  <Font name="System Bold" size="18.0" />
-               </font>
-            </Label>
-            <VBox prefHeight="15.0" prefWidth="422.0" spacing="10.0">
+      <ScrollPane fx:id="scrollPane" hbarPolicy="NEVER" layoutX="14.0" layoutY="14.0" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="14.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="14.0">
+         <content>
+            <VBox fx:id="vboxMain" prefHeight="567.0" prefWidth="409.0" spacing="15.0">
                <children>
-                  <Label text="%filter.type">
+                  <Label text="%filter.headline">
                      <font>
-                        <Font name="System Bold" size="16.0" />
+                        <Font name="System Bold" size="18.0" />
                      </font>
+                     <VBox.margin>
+                        <Insets bottom="-5.0" />
+                     </VBox.margin>
                   </Label>
-                  <HBox prefHeight="10.0" prefWidth="422.0" spacing="25.0">
+                  <VBox prefHeight="15.0" prefWidth="422.0" spacing="5.0">
                      <children>
-                        <CheckBox fx:id="checkBoxIncome" mnemonicParsing="false" text="%filter.type.income">
+                        <Label text="%filter.type">
                            <font>
-                              <Font size="14.0" />
+                              <Font name="System Bold" size="16.0" />
                            </font>
-                        </CheckBox>
-                        <CheckBox fx:id="checkBoxPayment" mnemonicParsing="false" text="%filter.type.payment">
+                        </Label>
+                        <HBox prefHeight="10.0" prefWidth="422.0" spacing="25.0">
+                           <children>
+                              <CheckBox fx:id="checkBoxIncome" mnemonicParsing="false" text="%filter.type.income">
+                                 <font>
+                                    <Font size="14.0" />
+                                 </font>
+                              </CheckBox>
+                              <CheckBox fx:id="checkBoxPayment" mnemonicParsing="false" text="%filter.type.payment">
+                                 <font>
+                                    <Font size="14.0" />
+                                 </font>
+                              </CheckBox>
+                           </children>
+                        </HBox>
+                     </children>
+                  </VBox>
+                  <VBox prefHeight="33.0" prefWidth="422.0" spacing="5.0">
+                     <children>
+                        <Label text="%filter.repeating">
                            <font>
-                              <Font size="14.0" />
+                              <Font name="System Bold" size="16.0" />
                            </font>
-                        </CheckBox>
+                        </Label>
+                        <HBox spacing="10.0">
+                           <children>
+                              <CheckBox fx:id="checkBoxNoRepeating" mnemonicParsing="false" text="%filter.repeating.none">
+                                 <font>
+                                    <Font size="14.0" />
+                                 </font>
+                              </CheckBox>
+                              <CheckBox fx:id="checkBoxMonthlyRepeating" mnemonicParsing="false" text="%filter.repeating.monthday">
+                                 <font>
+                                    <Font size="14.0" />
+                                 </font>
+                              </CheckBox>
+                              <CheckBox fx:id="checkBoxRepeatEveryXDays" mnemonicParsing="false" text="%filter.repeating.interval">
+                                 <font>
+                                    <Font size="14.0" />
+                                 </font>
+                              </CheckBox>
+                           </children>
+                        </HBox>
                      </children>
-                  </HBox>
-               </children>
-            </VBox>
-            <VBox prefHeight="33.0" prefWidth="422.0" spacing="10.0">
-               <children>
-                  <Label text="%filter.repeating">
-                     <font>
-                        <Font name="System Bold" size="16.0" />
-                     </font>
-                  </Label>
-                  <CheckBox fx:id="checkBoxNoRepeating" mnemonicParsing="false" text="%filter.repeating.none">
-                     <font>
-                        <Font size="14.0" />
-                     </font>
-                  </CheckBox>
-                  <CheckBox fx:id="checkBoxMonthlyRepeating" mnemonicParsing="false" text="%filter.repeating.monthday">
-                     <font>
-                        <Font size="14.0" />
-                     </font>
-                  </CheckBox>
-                  <CheckBox fx:id="checkBoxRepeatEveryXDays" mnemonicParsing="false" text="%filter.repeating.interval">
-                     <font>
-                        <Font size="14.0" />
-                     </font>
-                  </CheckBox>
-               </children>
-            </VBox>
-            <VBox prefHeight="150.0" prefWidth="422.0" spacing="10.0">
-               <children>
-                  <HBox spacing="10.0">
+                  </VBox>
+                  <VBox prefHeight="150.0" prefWidth="422.0" spacing="5.0" VBox.vgrow="ALWAYS">
                      <children>
-                        <Label text="%filter.categories">
+                        <HBox spacing="10.0">
+                           <children>
+                              <Label text="%filter.categories">
+                                 <font>
+                                    <Font name="System Bold" size="16.0" />
+                                 </font>
+                              </Label>
+                              <Region prefWidth="200.0" HBox.hgrow="ALWAYS" />
+                              <Button fx:id="buttonCategoryAll" mnemonicParsing="false" onAction="#enableAllCategories" text="%filter.categories.button.all">
+                                 <font>
+                                    <Font name="System Bold" size="13.0" />
+                                 </font>
+                              </Button>
+                              <Button fx:id="buttonCategoryNone" mnemonicParsing="false" onAction="#disableAllCategories" text="%filter.categories.button.none">
+                                 <font>
+                                    <Font name="System Bold" size="13.0" />
+                                 </font>
+                              </Button>
+                           </children>
+                        </HBox>
+                        <ScrollPane prefHeight="88.0" prefWidth="409.0" VBox.vgrow="ALWAYS">
+                           <content>
+                              <VBox fx:id="vboxCategories" spacing="5.0" />
+                           </content>
+                        </ScrollPane>
+                     </children>
+                  </VBox>
+                  <VBox prefHeight="33.0" prefWidth="422.0" spacing="5.0">
+                     <children>
+                        <Label text="%filter.name">
                            <font>
                               <Font name="System Bold" size="16.0" />
                            </font>
                         </Label>
-                        <Region prefWidth="200.0" HBox.hgrow="ALWAYS" />
-                        <Button fx:id="buttonCategoryAll" mnemonicParsing="false" onAction="#enableAllCategories" text="%filter.categories.button.all">
+                        <TextField fx:id="textFieldSearch" />
+                     </children>
+                  </VBox>
+                  <VBox prefHeight="150.0" prefWidth="422.0" spacing="5.0" VBox.vgrow="ALWAYS">
+                     <children>
+                        <HBox spacing="10.0">
+                           <children>
+                              <Label text="%filter.tags">
+                                 <font>
+                                    <Font name="System Bold" size="16.0" />
+                                 </font>
+                              </Label>
+                              <Region prefWidth="200.0" HBox.hgrow="ALWAYS" />
+                              <Button fx:id="buttonTagsAll" mnemonicParsing="false" onAction="#enableAllTags" text="%filter.categories.button.all">
+                                 <font>
+                                    <Font name="System Bold" size="13.0" />
+                                 </font>
+                              </Button>
+                              <Button fx:id="buttonTagsNone" mnemonicParsing="false" onAction="#disableAllTags" text="%filter.categories.button.none">
+                                 <font>
+                                    <Font name="System Bold" size="13.0" />
+                                 </font>
+                              </Button>
+                           </children>
+                        </HBox>
+                        <ScrollPane prefHeight="85.0" prefWidth="409.0" VBox.vgrow="ALWAYS">
+                           <content>
+                              <VBox fx:id="vboxTags" spacing="5.0" />
+                           </content>
+                        </ScrollPane>
+                     </children>
+                  </VBox>
+                  <HBox alignment="CENTER" prefHeight="30.0" prefWidth="465.0" spacing="10.0">
+                     <children>
+                        <Button fx:id="buttonCancel" mnemonicParsing="false" onAction="#cancel" text="%cancel">
                            <font>
-                              <Font name="System Bold" size="13.0" />
+                              <Font name="System Bold" size="14.0" />
                            </font>
                         </Button>
-                        <Button fx:id="buttonCategoryNone" mnemonicParsing="false" onAction="#disableAllCategories" text="%filter.categories.button.none">
+                        <Button fx:id="buttonReset" mnemonicParsing="false" onAction="#reset" text="%filter.button.reset">
                            <font>
-                              <Font name="System Bold" size="13.0" />
+                              <Font name="System Bold" size="14.0" />
                            </font>
+                           <HBox.margin>
+                              <Insets left="25.0" />
+                           </HBox.margin>
+                        </Button>
+                        <Button fx:id="buttonFilter" mnemonicParsing="false" onAction="#filter" text="%filter.button.filter">
+                           <font>
+                              <Font name="System Bold" size="14.0" />
+                           </font>
+                           <HBox.margin>
+                              <Insets left="25.0" />
+                           </HBox.margin>
                         </Button>
                      </children>
+                     <VBox.margin>
+                        <Insets top="10.0" />
+                     </VBox.margin>
                   </HBox>
-                  <ScrollPane prefHeight="93.0" prefWidth="422.0" VBox.vgrow="ALWAYS">
-                     <content>
-                        <VBox fx:id="vboxCategories" spacing="5.0" />
-                     </content>
-                  </ScrollPane>
-               </children>
-            </VBox>
-            <VBox prefHeight="33.0" prefWidth="422.0" VBox.vgrow="ALWAYS">
-               <children>
-                  <Label text="%filter.name">
-                     <font>
-                        <Font name="System Bold" size="16.0" />
-                     </font>
-                  </Label>
-                  <TextField fx:id="textFieldSearch" />
                </children>
+               <padding>
+                  <Insets bottom="15.0" />
+               </padding>
             </VBox>
-            <HBox alignment="CENTER" prefHeight="30.0" prefWidth="465.0" spacing="10.0">
-               <children>
-                  <Button fx:id="buttonCancel" mnemonicParsing="false" onAction="#cancel" text="%cancel">
-                     <font>
-                        <Font name="System Bold" size="14.0" />
-                     </font>
-                  </Button>
-                  <Button fx:id="buttonReset" mnemonicParsing="false" onAction="#reset" text="%filter.button.reset">
-                     <font>
-                        <Font name="System Bold" size="14.0" />
-                     </font>
-                     <HBox.margin>
-                        <Insets left="25.0" />
-                     </HBox.margin>
-                  </Button>
-                  <Button fx:id="buttonFilter" mnemonicParsing="false" onAction="#filter" text="%filter.button.filter">
-                     <font>
-                        <Font name="System Bold" size="14.0" />
-                     </font>
-                     <HBox.margin>
-                        <Insets left="25.0" />
-                     </HBox.margin>
-                  </Button>
-               </children>
-               <VBox.margin>
-                  <Insets top="10.0" />
-               </VBox.margin>
-            </HBox>
-         </children>
-      </VBox>
+         </content>
+      </ScrollPane>
    </children>
 </AnchorPane>
-- 
GitLab