Merge pull request #20 from warmuuh/feature/searchpane-refactoring

Refactored search functionality into own class.
Abstracted search functionality for implementation of Project-based workflow in the future.
This commit is contained in:
Rohit Awate 2018-07-04 17:29:18 +05:30 committed by GitHub
commit ca6bcabdb9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 481 additions and 299 deletions

2
.gitignore vendored
View file

@ -12,5 +12,5 @@ dependency-reduced-pom.xml
/BugReporter/src/META-INF/
BugReporter/src/META-INF/
Everest/
Everest/
out/

View file

@ -0,0 +1,186 @@
package com.rohitawate.everest.controllers;
import java.io.IOException;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import java.util.concurrent.ExecutionException;
import com.jfoenix.controls.JFXButton;
import com.rohitawate.everest.misc.Services;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.control.SplitPane;
import javafx.scene.control.TextField;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
public abstract class AbstractSearchablePaneController<T> implements Initializable {
@FXML
private StackPane searchPromptLayer, searchLayer, searchFailedLayer;
@FXML
private JFXButton clearSearchFieldButton;
@FXML
private TextField searchTextField;
@FXML
private VBox searchTab, searchBox, searchPane;
private List<Searchable<T>> searchableItems;
protected static class SearchEntry<T> {
private final Parent fxmlItem;
private final Searchable<T> searchable;
public SearchEntry(Parent fxmlItem, Searchable<T> searchable) {
super();
this.fxmlItem = fxmlItem;
this.searchable = searchable;
}
public Parent getFxmlItem() {
return fxmlItem;
}
public Searchable<T> getSearchable() {
return searchable;
}
}
@Override
public void initialize(URL arg0, ResourceBundle arg1) {
searchableItems = new ArrayList<>();
searchLayer.visibleProperty().bind(searchTextField.textProperty().isNotEmpty());
searchTextField.textProperty().addListener(((observable, oldValue, newValue) -> {
searchBox.getChildren().remove(0, searchBox.getChildren().size());
searchFailedLayer.setVisible(false);
List<Searchable<T>> searchResults = getSearchResults(searchTextField.getText());
//TODO: this is calculating relativityIndex again
searchResults.sort((controller1, controller2) -> {
int relativity1 = controller1.getRelativityIndex(searchTextField.getText());
int relativity2 = controller2.getRelativityIndex(searchTextField.getText());
return relativity2 - relativity1;
});
if (searchResults.size() != 0) {
for (Searchable<T> controller : searchResults) {
addSearchItem(controller.getState());
}
} else {
searchFailedLayer.setVisible(true);
}
}));
clearSearchFieldButton.setOnAction(e -> searchTextField.clear());
Platform.runLater(this::loadInitialItemsAsync);
}
private void loadInitialItemsAsync() {
Task<List<T>> entryLoader = new Task<List<T>>() {
@Override
protected List<T> call() {
return loadInitialEntries();
}
};
entryLoader.setOnSucceeded(e -> {
try {
List<T> entries = entryLoader.get();
if (entries.size() == 0) {
searchPromptLayer.setVisible(true);
return;
}
for (T state : entries)
addHistoryItem(state);
} catch (InterruptedException | ExecutionException E) {
Services.loggingService.logSevere("Task thread interrupted while populating HistoryTab.", E,
LocalDateTime.now());
}
});
entryLoader.setOnFailed(e -> Services.loggingService.logWarning("Failed to load history.",
(Exception) entryLoader.getException(), LocalDateTime.now()));
new Thread(entryLoader).start();
}
private void addSearchItem(T state) {
appendToList(state, searchBox, false);
}
protected abstract List<T> loadInitialEntries();
public void focusSearchField() {
searchTextField.requestFocus();
}
private Searchable<T> appendToList(T state, VBox layer, boolean appendToStart) {
searchPromptLayer.setVisible(false);
try {
SearchEntry<T> searchEntry = createEntryFromState(state);
if (appendToStart)
layer.getChildren().add(0, searchEntry.getFxmlItem());
else
layer.getChildren().add(searchEntry.getFxmlItem());
return searchEntry.getSearchable();
} catch (IOException e) {
Services.loggingService.logSevere("Could not append HistoryItem to list.", e, LocalDateTime.now());
}
return null;
}
protected abstract SearchEntry<T> createEntryFromState(T state) throws IOException;
public void addHistoryItem(T state) {
Searchable<T> controller = appendToList(state, searchTab, true);
searchableItems.add(controller);
}
private List<Searchable<T>> getSearchResults(String searchString) {
List<Searchable<T>> filteredList = new ArrayList<>();
for (Searchable<T> controller : searchableItems) {
int relativityIndex = controller.getRelativityIndex(searchString);
// Split the string into words and get total relativity index as sum of
// individual indices.
String words[] = searchString.split("\\s");
for (String word : words)
relativityIndex += controller.getRelativityIndex(word);
if (relativityIndex != 0)
filteredList.add(controller);
}
return filteredList;
}
public void toggleVisibilityIn(SplitPane splitPane) {
if (searchPane.isVisible()) {
searchPane = (VBox) splitPane.getItems().remove(0);
} else {
splitPane.getItems().add(0, searchPane);
}
searchPane.setVisible(!searchPane.isVisible());
}
}

View file

@ -16,21 +16,23 @@
package com.rohitawate.everest.controllers;
import com.rohitawate.everest.controllers.state.DashboardState;
import com.rohitawate.everest.controllers.state.FieldState;
import com.rohitawate.everest.misc.Services;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.Tooltip;
import javax.ws.rs.core.MediaType;
import java.net.MalformedURLException;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.ResourceBundle;
public class HistoryItemController implements Initializable {
import javax.ws.rs.core.MediaType;
import com.rohitawate.everest.controllers.state.DashboardState;
import com.rohitawate.everest.controllers.state.FieldState;
import com.rohitawate.everest.misc.Services;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.Tooltip;
public class HistoryItemController implements Initializable, Searchable<DashboardState> {
@FXML
private Label requestType, address;
@FXML

View file

@ -16,17 +16,27 @@
package com.rohitawate.everest.controllers;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.ResourceBundle;
import com.fasterxml.jackson.core.type.TypeReference;
import com.jfoenix.controls.JFXButton;
import com.rohitawate.everest.controllers.state.DashboardState;
import com.rohitawate.everest.misc.EverestUtilities;
import com.rohitawate.everest.misc.KeyMap;
import com.rohitawate.everest.misc.Services;
import com.rohitawate.everest.misc.ThemeManager;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.property.StringProperty;
import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
@ -35,19 +45,11 @@ import javafx.scene.Scene;
import javafx.scene.control.SplitPane;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseButton;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ExecutionException;
public class HomeWindowController implements Initializable {
@FXML
private StackPane homeWindowSP;
@ -55,55 +57,19 @@ public class HomeWindowController implements Initializable {
private SplitPane splitPane;
@FXML
private TabPane homeWindowTabPane;
@FXML
private TextField historyTextField;
@FXML
private VBox historyTab, searchBox, historyPane;
@FXML
private StackPane historyPromptLayer, searchLayer, searchFailedLayer;
@FXML
private JFXButton clearSearchFieldButton;
private SearchPaneController searchPaneController;
private HashMap<Tab, DashboardController> tabControllerMap;
private List<HistoryItemController> historyItemControllers;
@Override
public void initialize(URL location, ResourceBundle resources) {
// Using LinkedHashMap because they retain order
tabControllerMap = new LinkedHashMap<>();
historyItemControllers = new ArrayList<>();
recoverState();
searchLayer.visibleProperty().bind(historyTextField.textProperty().isNotEmpty());
historyTextField.textProperty().addListener(((observable, oldValue, newValue) -> {
searchBox.getChildren().remove(0, searchBox.getChildren().size());
searchFailedLayer.setVisible(false);
List<HistoryItemController> searchResults = getSearchResults(historyTextField.getText());
// Method of sorting the HistoryItemControllers
searchResults.sort((controller1, controller2) -> {
int relativity1 = controller1.getRelativityIndex(historyTextField.getText());
int relativity2 = controller2.getRelativityIndex(historyTextField.getText());
if (relativity1 < relativity2)
return 1;
else if (relativity1 > relativity2)
return -1;
else
return 0;
});
if (searchResults.size() != 0) {
for (HistoryItemController controller : searchResults) {
addSearchItem(controller.getState());
}
} else {
searchFailedLayer.setVisible(true);
}
}));
clearSearchFieldButton.setOnAction(e -> historyTextField.clear());
searchPaneController.addItemClickHandler(this::addTab);
homeWindowSP.setFocusTraversable(true);
Platform.runLater(() -> {
@ -114,32 +80,8 @@ public class HomeWindowController implements Initializable {
Stage thisStage = (Stage) homeWindowSP.getScene().getWindow();
thisStage.setOnCloseRequest(e -> saveState());
// Loads the history
Task<List<DashboardState>> historyLoader = new Task<List<DashboardState>>() {
@Override
protected List<DashboardState> call() {
return Services.historyManager.getHistory();
}
};
// Appends the history items to the HistoryTab
historyLoader.setOnSucceeded(e -> {
try {
List<DashboardState> history = historyLoader.get();
if (history.size() == 0) {
historyPromptLayer.setVisible(true);
return;
}
for (DashboardState state : history)
addHistoryItem(state);
} catch (InterruptedException | ExecutionException E) {
Services.loggingService.logSevere("Task thread interrupted while populating HistoryTab.", E, LocalDateTime.now());
}
});
historyLoader.setOnFailed(e -> Services.loggingService.logWarning(
"Failed to load history.", (Exception) historyLoader.getException(), LocalDateTime.now()));
new Thread(historyLoader).start();
});
}
@ -167,7 +109,7 @@ public class HomeWindowController implements Initializable {
homeWindowTabPane.getTabs().remove(activeTab);
tabControllerMap.remove(activeTab);
} else if (KeyMap.searchHistory.match(e)) {
historyTextField.requestFocus();
searchPaneController.focusSearchField();
} else if (KeyMap.focusParams.match(e)) {
Tab activeTab = getActiveTab();
DashboardController controller = tabControllerMap.get(activeTab);
@ -198,13 +140,7 @@ public class HomeWindowController implements Initializable {
}
private void toggleHistoryPane() {
if (historyPane.isVisible()) {
historyPane = (VBox) splitPane.getItems().remove(0);
} else {
splitPane.getItems().add(0, historyPane);
}
historyPane.setVisible(!historyPane.isVisible());
searchPaneController.toggleVisibilityIn(splitPane);
}
private void addTab() {
@ -291,57 +227,9 @@ public class HomeWindowController implements Initializable {
}
public void addHistoryItem(DashboardState state) {
HistoryItemController controller = appendToList(state, historyTab, true);
historyItemControllers.add(controller);
}
public void addHistoryItem(DashboardState state) {
searchPaneController.addHistoryItem(state);
}
private void addSearchItem(DashboardState state) {
appendToList(state, searchBox, false);
}
private HistoryItemController appendToList(DashboardState state, VBox layer, boolean appendToStart) {
historyPromptLayer.setVisible(false);
HistoryItemController controller = null;
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/homewindow/HistoryItem.fxml"));
Parent historyItem = loader.load();
controller = loader.getController();
controller.setState(state);
if (appendToStart)
layer.getChildren().add(0, historyItem);
else
layer.getChildren().add(historyItem);
// Clicking on HistoryItem opens it up in a new tab
historyItem.setOnMouseClicked(mouseEvent -> {
if (mouseEvent.getButton() == MouseButton.PRIMARY)
addTab(state);
});
} catch (IOException e) {
Services.loggingService.logSevere("Could not append HistoryItem to list.", e, LocalDateTime.now());
}
return controller;
}
private List<HistoryItemController> getSearchResults(String searchString) {
List<HistoryItemController> filteredList = new ArrayList<>();
for (HistoryItemController controller : historyItemControllers) {
int relativityIndex = controller.getRelativityIndex(searchString);
// Split the string into words and get total relativity index as the sum of individual indices.
String words[] = searchString.split("\\s");
for (String word : words)
relativityIndex += controller.getRelativityIndex(word);
if (relativityIndex != 0)
filteredList.add(controller);
}
return filteredList;
}
}

View file

@ -0,0 +1,53 @@
package com.rohitawate.everest.controllers;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Consumer;
import com.rohitawate.everest.controllers.state.DashboardState;
import com.rohitawate.everest.misc.Services;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.input.MouseButton;
import javafx.scene.layout.VBox;
public class SearchPaneController extends AbstractSearchablePaneController<DashboardState> {
private List<Consumer<DashboardState>> stateClickHandler = new LinkedList<>();
@Override
protected List<DashboardState> loadInitialEntries() {
return Services.historyManager.getHistory();
}
protected SearchEntry<DashboardState> createEntryFromState(DashboardState state) throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/homewindow/HistoryItem.fxml"));
Parent historyItem = loader.load();
HistoryItemController controller = loader.getController();
controller = loader.getController();
controller.setState(state);
// Clicking on HistoryItem opens it up in a new tab
historyItem.setOnMouseClicked(mouseEvent -> {
if (mouseEvent.getButton() == MouseButton.PRIMARY)
handleClick(state);
});
return new SearchEntry<DashboardState>(historyItem, controller);
}
private void handleClick(DashboardState state) {
for (Consumer<DashboardState> consumer : stateClickHandler) {
consumer.accept(state);
}
}
public void addItemClickHandler(Consumer<DashboardState> handler) {
stateClickHandler.add(handler);
}
}

View file

@ -0,0 +1,15 @@
package com.rohitawate.everest.controllers;
/**
* a searchable item that is used in a search-pane.
* @author pmucha
*
* @param <T>
*/
public interface Searchable<T> {
int getRelativityIndex(String searchString);
T getState();
}

View file

@ -16,6 +16,21 @@
package com.rohitawate.everest.history;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.core.MediaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rohitawate.everest.controllers.state.DashboardState;
@ -24,16 +39,6 @@ import com.rohitawate.everest.misc.EverestUtilities;
import com.rohitawate.everest.misc.Services;
import com.rohitawate.everest.settings.Settings;
import javax.ws.rs.core.MediaType;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
public class HistoryManager {
private Connection conn;
private JsonNode queries;
@ -468,4 +473,4 @@ public class HistoryManager {
}
}
}
}
}

View file

@ -264,7 +264,7 @@
-fx-background-color: #303030;
}
#historyTextField {
.searchTextField {
-fx-background-color: transparent;
-fx-text-fill: white;
}

View file

@ -1,20 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2018 Rohit Awate.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<!-- ~ Copyright 2018 Rohit Awate. ~ ~ Licensed under the Apache License,
Version 2.0 (the "License"); ~ you may not use this file except in compliance
with the License. ~ You may obtain a copy of the License at ~ ~ http://www.apache.org/licenses/LICENSE-2.0
~ ~ Unless required by applicable law or agreed to in writing, software ~
distributed under the License is distributed on an "AS IS" BASIS, ~ WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ~ See the
License for the specific language governing permissions and ~ limitations
under the License. -->
<?import com.jfoenix.controls.JFXButton?>
<?import javafx.geometry.*?>
@ -22,131 +15,20 @@
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.Font?>
<StackPane fx:id="homeWindowSP" stylesheets="@../../css/Adreana.css" xmlns="http://javafx.com/javafx/8.0.141"
xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.rohitawate.everest.controllers.HomeWindowController">
<children>
<SplitPane fx:id="splitPane" dividerPositions="0.3">
<items>
<VBox fx:id="historyPane" alignment="TOP_CENTER" maxWidth="450.0" minWidth="400.0"
SplitPane.resizableWithParent="false">
<children>
<HBox fx:id="historySearchFieldBox" alignment="CENTER" fillHeight="false">
<VBox.margin>
<Insets/>
</VBox.margin>
<children>
<ImageView fitHeight="20.0" fitWidth="20.0" pickOnBounds="true" preserveRatio="true"
HBox.hgrow="ALWAYS">
<image>
<Image url="@../../assets/Search.png"/>
</image>
</ImageView>
<TextField fx:id="historyTextField" promptText="SEARCH" HBox.hgrow="ALWAYS">
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
</padding>
</TextField>
<JFXButton fx:id="clearSearchFieldButton" ripplerFill="WHITE" HBox.hgrow="ALWAYS">
<graphic>
<ImageView fitHeight="20.0" fitWidth="20.0" pickOnBounds="true"
preserveRatio="true">
<image>
<Image url="@../../assets/BackspaceArrow.png"/>
</image>
</ImageView>
</graphic>
</JFXButton>
</children>
<padding>
<Insets bottom="10.0" left="20.0" right="20.0" top="10.0"/>
</padding>
</HBox>
<StackPane VBox.vgrow="ALWAYS">
<children>
<StackPane>
<children>
<ScrollPane fx:id="historyScrollPane" fitToHeight="true" fitToWidth="true"
hbarPolicy="NEVER">
<content>
<VBox fx:id="historyTab" alignment="TOP_CENTER" spacing="5.0">
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0"/>
</padding>
</VBox>
</content>
</ScrollPane>
<StackPane fx:id="historyPromptLayer">
<children>
<Label text="YOUR REQUESTS HISTORY WILL APPEAR HERE"
textAlignment="CENTER" textFill="#575757" wrapText="true">
<font>
<Font size="25.0"/>
</font>
</Label>
</children>
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0"/>
</padding>
</StackPane>
</children>
</StackPane>
<StackPane fx:id="searchLayer">
<children>
<VBox alignment="TOP_CENTER">
<children>
<Label graphicTextGap="10.0" text="SEARCH RESULTS" textFill="#199F6F">
<VBox.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
</VBox.margin>
<font>
<Font size="19.0"/>
</font>
</Label>
<ScrollPane fx:id="searchScrollPane" fitToHeight="true"
fitToWidth="true" hbarPolicy="NEVER">
<content>
<VBox fx:id="searchBox" alignment="TOP_CENTER" spacing="5.0">
<padding>
<Insets bottom="20.0" left="20.0" right="20.0"
top="20.0"/>
</padding>
</VBox>
</content>
</ScrollPane>
</children>
</VBox>
<StackPane fx:id="searchFailedLayer">
<children>
<VBox alignment="CENTER">
<children>
<ImageView fitHeight="100.0" fitWidth="100.0" opacity="0.51"
pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../../assets/Explosion.png"/>
</image>
</ImageView>
<Label text="NO RESULTS" textAlignment="CENTER"
textFill="#bfbfbf" wrapText="true" VBox.vgrow="ALWAYS">
<font>
<Font size="25.0"/>
</font>
</Label>
</children>
</VBox>
</children>
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0"/>
</padding>
</StackPane>
</children>
</StackPane>
</children>
</StackPane>
</children>
</VBox>
<TabPane fx:id="homeWindowTabPane" tabClosingPolicy="ALL_TABS" tabMaxHeight="30.0" tabMaxWidth="200.0"
tabMinHeight="30.0" tabMinWidth="200.0" SplitPane.resizableWithParent="false"/>
</items>
</SplitPane>
</children>
<StackPane fx:id="homeWindowSP"
stylesheets="@../../css/Adreana.css"
xmlns="http://javafx.com/javafx/8.0.141"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="com.rohitawate.everest.controllers.HomeWindowController">
<children>
<SplitPane fx:id="splitPane" dividerPositions="0.3">
<items>
<fx:include fx:id="searchPane" source="SearchPane.fxml" />
<TabPane fx:id="homeWindowTabPane"
tabClosingPolicy="ALL_TABS" tabMaxHeight="30.0" tabMaxWidth="200.0"
tabMinHeight="30.0" tabMinWidth="200.0"
SplitPane.resizableWithParent="false" />
</items>
</SplitPane>
</children>
</StackPane>

View file

@ -0,0 +1,151 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2018 Rohit Awate.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<?import com.jfoenix.controls.JFXButton?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.Font?>
<VBox fx:id="searchPane" xmlns="http://javafx.com/javafx/8.0.141"
xmlns:fx="http://javafx.com/fxml/1" alignment="TOP_CENTER" maxWidth="450.0"
minWidth="400.0" SplitPane.resizableWithParent="false" fx:controller="com.rohitawate.everest.controllers.SearchPaneController">
<children>
<HBox fx:id="historySearchFieldBox" alignment="CENTER"
fillHeight="false">
<VBox.margin>
<Insets />
</VBox.margin>
<children>
<ImageView fitHeight="20.0" fitWidth="20.0"
pickOnBounds="true" preserveRatio="true" HBox.hgrow="ALWAYS">
<image>
<Image url="@../../assets/Search.png" />
</image>
</ImageView>
<TextField fx:id="searchTextField" styleClass="searchTextField" promptText="SEARCH HISTORY"
HBox.hgrow="ALWAYS">
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</TextField>
<JFXButton fx:id="clearSearchFieldButton"
ripplerFill="WHITE" HBox.hgrow="ALWAYS">
<graphic>
<ImageView fitHeight="20.0" fitWidth="20.0"
pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../../assets/BackspaceArrow.png" />
</image>
</ImageView>
</graphic>
</JFXButton>
</children>
<padding>
<Insets bottom="10.0" left="20.0" right="20.0" top="10.0" />
</padding>
</HBox>
<StackPane VBox.vgrow="ALWAYS">
<children>
<StackPane>
<children>
<ScrollPane fx:id="historyScrollPane"
fitToHeight="true" fitToWidth="true" hbarPolicy="NEVER">
<content>
<VBox fx:id="searchTab" alignment="TOP_CENTER"
spacing="5.0">
<padding>
<Insets bottom="20.0" left="20.0" right="20.0"
top="20.0" />
</padding>
</VBox>
</content>
</ScrollPane>
<StackPane fx:id="searchPromptLayer">
<children>
<Label text="YOUR REQUESTS HISTORY WILL APPEAR HERE"
textAlignment="CENTER" textFill="#575757" wrapText="true">
<font>
<Font size="25.0" />
</font>
</Label>
</children>
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
</padding>
</StackPane>
</children>
</StackPane>
<StackPane fx:id="searchLayer">
<children>
<VBox alignment="TOP_CENTER">
<children>
<Label graphicTextGap="10.0" text="SEARCH RESULTS"
textFill="#199F6F">
<VBox.margin>
<Insets bottom="10.0" left="10.0" right="10.0"
top="10.0" />
</VBox.margin>
<font>
<Font size="19.0" />
</font>
</Label>
<ScrollPane fx:id="searchScrollPane"
fitToHeight="true" fitToWidth="true" hbarPolicy="NEVER">
<content>
<VBox fx:id="searchBox" alignment="TOP_CENTER"
spacing="5.0">
<padding>
<Insets bottom="20.0" left="20.0" right="20.0"
top="20.0" />
</padding>
</VBox>
</content>
</ScrollPane>
</children>
</VBox>
<StackPane fx:id="searchFailedLayer">
<children>
<VBox alignment="CENTER">
<children>
<ImageView fitHeight="100.0" fitWidth="100.0"
opacity="0.51" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../../assets/Explosion.png" />
</image>
</ImageView>
<Label text="NO RESULTS" textAlignment="CENTER"
textFill="#bfbfbf" wrapText="true" VBox.vgrow="ALWAYS">
<font>
<Font size="25.0" />
</font>
</Label>
</children>
</VBox>
</children>
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
</padding>
</StackPane>
</children>
</StackPane>
</children>
</StackPane>
</children>
</VBox>