Added ability to edit and prepare nicer views for shards.
This commit is contained in:
parent
f7df8a1eaf
commit
5ab1abbfff
|
@ -0,0 +1,107 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333333 4.2333333"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||||
|
sodipodi:docname="login_credentials_shard_node_icon.svg"
|
||||||
|
inkscape:export-filename="A:\Programming\GitHub-andrewlalis\CrystalKeep\src\main\resources\nl\andrewlalis\crystalkeep\ui\images\login_credentials_shard_node_icon.png"
|
||||||
|
inkscape:export-xdpi="192"
|
||||||
|
inkscape:export-ydpi="192">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="89.600001"
|
||||||
|
inkscape:cx="10.229603"
|
||||||
|
inkscape:cy="7.4126105"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1017"
|
||||||
|
inkscape:window-x="-8"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
units="px" />
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-292.76667)">
|
||||||
|
<path
|
||||||
|
sodipodi:type="star"
|
||||||
|
style="fill:#72deff;fill-opacity:1;stroke:none;stroke-width:0.07803907;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers fill stroke"
|
||||||
|
id="path817"
|
||||||
|
sodipodi:sides="9"
|
||||||
|
sodipodi:cx="2.1166666"
|
||||||
|
sodipodi:cy="294.93815"
|
||||||
|
sodipodi:r1="1.8178079"
|
||||||
|
sodipodi:r2="1.2179312"
|
||||||
|
sodipodi:arg1="0.52359878"
|
||||||
|
sodipodi:arg2="0.87266463"
|
||||||
|
inkscape:flatsided="false"
|
||||||
|
inkscape:rounded="0"
|
||||||
|
inkscape:randomized="0"
|
||||||
|
d="m 3.6909344,295.84704 -0.7913968,0.0241 -0.1611441,0.77519 -0.6217269,-0.49025 -0.621727,0.49025 -0.1611441,-0.77519 -0.79139678,-0.0241 0.37483979,-0.69741 -0.59076328,-0.52715 0.73543197,-0.2933 -0.11370504,-0.78356 0.75190744,0.24804 0.416557,-0.67333 0.4165569,0.67333 0.7519075,-0.24804 -0.1137051,0.78356 0.735432,0.2933 -0.5907633,0.52715 z"
|
||||||
|
inkscape:transform-center-x="0.06028767"
|
||||||
|
inkscape:transform-center-y="0.030212626" />
|
||||||
|
<g
|
||||||
|
id="g828">
|
||||||
|
<rect
|
||||||
|
y="294.87439"
|
||||||
|
x="1.5420023"
|
||||||
|
height="0.95215333"
|
||||||
|
width="1.1493286"
|
||||||
|
id="rect816"
|
||||||
|
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.05291667;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers fill stroke" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path818"
|
||||||
|
d="m 1.8074821,294.89943 v -0.43431 c 0,0 -0.016704,-0.32365 0.3236467,-0.32365 0.340351,0 0.292326,0.29233 0.292326,0.29233 v 0.47816"
|
||||||
|
style="fill:none;stroke:#000000;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||||
|
<rect
|
||||||
|
y="295.05811"
|
||||||
|
x="1.7157624"
|
||||||
|
height="0.17957026"
|
||||||
|
width="0.8018086"
|
||||||
|
id="rect820"
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.05291667;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers fill stroke" />
|
||||||
|
<rect
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.05291667;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers fill stroke"
|
||||||
|
id="rect822"
|
||||||
|
width="0.8018086"
|
||||||
|
height="0.17957026"
|
||||||
|
x="1.7157624"
|
||||||
|
y="295.41309" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 4.4 KiB |
|
@ -0,0 +1,89 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333333 4.2333333"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||||
|
sodipodi:docname="text_shard_node_icon.svg"
|
||||||
|
inkscape:export-filename="A:\Programming\GitHub-andrewlalis\CrystalKeep\src\main\resources\nl\andrewlalis\crystalkeep\ui\images\text_shard_node_icon.png"
|
||||||
|
inkscape:export-xdpi="192"
|
||||||
|
inkscape:export-ydpi="192">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="44.8"
|
||||||
|
inkscape:cx="8.2633984"
|
||||||
|
inkscape:cy="6.8552682"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1017"
|
||||||
|
inkscape:window-x="-8"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
units="px" />
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-292.76667)">
|
||||||
|
<path
|
||||||
|
sodipodi:type="star"
|
||||||
|
style="fill:#72deff;fill-opacity:1;stroke:none;stroke-width:0.07803907;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers fill stroke"
|
||||||
|
id="path817"
|
||||||
|
sodipodi:sides="9"
|
||||||
|
sodipodi:cx="2.1166666"
|
||||||
|
sodipodi:cy="294.93815"
|
||||||
|
sodipodi:r1="1.8178079"
|
||||||
|
sodipodi:r2="1.2179312"
|
||||||
|
sodipodi:arg1="0.52359878"
|
||||||
|
sodipodi:arg2="0.87266463"
|
||||||
|
inkscape:flatsided="false"
|
||||||
|
inkscape:rounded="0"
|
||||||
|
inkscape:randomized="0"
|
||||||
|
d="m 3.6909344,295.84704 -0.7913968,0.0241 -0.1611441,0.77519 -0.6217269,-0.49025 -0.621727,0.49025 -0.1611441,-0.77519 -0.79139678,-0.0241 0.37483979,-0.69741 -0.59076328,-0.52715 0.73543197,-0.2933 -0.11370504,-0.78356 0.75190744,0.24804 0.416557,-0.67333 0.4165569,0.67333 0.7519075,-0.24804 -0.1137051,0.78356 0.735432,0.2933 -0.5907633,0.52715 z"
|
||||||
|
inkscape:transform-center-x="0.06028767"
|
||||||
|
inkscape:transform-center-y="0.030212626" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:1.9992249px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.12495156"
|
||||||
|
x="1.4333378"
|
||||||
|
y="295.61206"
|
||||||
|
id="text818"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan816"
|
||||||
|
x="1.4333378"
|
||||||
|
y="295.61206"
|
||||||
|
style="stroke-width:0.12495156">A</tspan></text>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.3 KiB |
|
@ -5,4 +5,5 @@ module crystalkeep {
|
||||||
opens nl.andrewlalis.crystalkeep;
|
opens nl.andrewlalis.crystalkeep;
|
||||||
|
|
||||||
exports nl.andrewlalis.crystalkeep.control to javafx.fxml;
|
exports nl.andrewlalis.crystalkeep.control to javafx.fxml;
|
||||||
|
exports nl.andrewlalis.crystalkeep.model to javafx.fxml;
|
||||||
}
|
}
|
|
@ -29,7 +29,15 @@ public class CrystalKeep extends Application {
|
||||||
stage.setScene(scene);
|
stage.setScene(scene);
|
||||||
stage.setTitle("CrystalKeep");
|
stage.setTitle("CrystalKeep");
|
||||||
stage.sizeToScene();
|
stage.sizeToScene();
|
||||||
|
model.setActiveCluster(this.loadRootCluster());
|
||||||
|
|
||||||
|
stage.show();
|
||||||
|
|
||||||
|
MainViewController controller = loader.getController();
|
||||||
|
controller.init(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Cluster loadRootCluster() throws IOException {
|
||||||
ClusterLoader clusterLoader = new ClusterLoader();
|
ClusterLoader clusterLoader = new ClusterLoader();
|
||||||
Cluster rootCluster;
|
Cluster rootCluster;
|
||||||
try {
|
try {
|
||||||
|
@ -45,12 +53,6 @@ public class CrystalKeep extends Application {
|
||||||
clusterLoader.saveDefault(rootCluster);
|
clusterLoader.saveDefault(rootCluster);
|
||||||
System.out.println("Saved root cluster on first load.");
|
System.out.println("Saved root cluster on first load.");
|
||||||
}
|
}
|
||||||
model.setActiveCluster(rootCluster);
|
return rootCluster;
|
||||||
|
|
||||||
stage.show();
|
|
||||||
|
|
||||||
MainViewController controller = loader.getController();
|
|
||||||
controller.init(model);
|
|
||||||
System.out.println(rootCluster);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
package nl.andrewlalis.crystalkeep.control;
|
|
||||||
|
|
||||||
import javafx.fxml.FXML;
|
|
||||||
import javafx.scene.control.TreeView;
|
|
||||||
|
|
||||||
public class ClusterTreeViewController {
|
|
||||||
@FXML
|
|
||||||
TreeView<String> clusterTreeView;
|
|
||||||
}
|
|
|
@ -2,8 +2,6 @@ package nl.andrewlalis.crystalkeep.control;
|
||||||
|
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.control.Label;
|
|
||||||
import javafx.scene.control.TextArea;
|
|
||||||
import javafx.scene.control.TreeItem;
|
import javafx.scene.control.TreeItem;
|
||||||
import javafx.scene.control.TreeView;
|
import javafx.scene.control.TreeView;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
|
@ -14,10 +12,21 @@ import nl.andrewlalis.crystalkeep.model.shards.TextShard;
|
||||||
import nl.andrewlalis.crystalkeep.view.ClusterTreeItem;
|
import nl.andrewlalis.crystalkeep.view.ClusterTreeItem;
|
||||||
import nl.andrewlalis.crystalkeep.view.CrystalItemTreeCell;
|
import nl.andrewlalis.crystalkeep.view.CrystalItemTreeCell;
|
||||||
import nl.andrewlalis.crystalkeep.view.ShardTreeItem;
|
import nl.andrewlalis.crystalkeep.view.ShardTreeItem;
|
||||||
|
import nl.andrewlalis.crystalkeep.view.shard_details.LoginCredentialsPane;
|
||||||
|
import nl.andrewlalis.crystalkeep.view.shard_details.ShardPane;
|
||||||
|
import nl.andrewlalis.crystalkeep.view.shard_details.TextShardPane;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class MainViewController implements ModelListener {
|
public class MainViewController implements ModelListener {
|
||||||
|
private static final Map<Class<? extends Shard>, Class<? extends ShardPane<? extends Shard>>> shardPanesMap = new HashMap<>();
|
||||||
|
static {
|
||||||
|
shardPanesMap.put(TextShard.class, TextShardPane.class);
|
||||||
|
shardPanesMap.put(LoginCredentialsShard.class, LoginCredentialsPane.class);
|
||||||
|
}
|
||||||
|
|
||||||
private Model model;
|
private Model model;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
|
@ -30,17 +39,17 @@ public class MainViewController implements ModelListener {
|
||||||
this.model.addListener(this);
|
this.model.addListener(this);
|
||||||
this.activeClusterUpdated();
|
this.activeClusterUpdated();
|
||||||
assert(this.clusterTreeView != null);
|
assert(this.clusterTreeView != null);
|
||||||
this.clusterTreeView.setCellFactory(param -> new CrystalItemTreeCell());
|
this.clusterTreeView.setCellFactory(param -> new CrystalItemTreeCell(this.model));
|
||||||
this.clusterTreeView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
|
this.clusterTreeView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
shardDetailContainer.getChildren().clear();
|
shardDetailContainer.getChildren().clear();
|
||||||
if (newValue instanceof ShardTreeItem) {
|
if (newValue instanceof ShardTreeItem) {
|
||||||
var node = (ShardTreeItem) newValue;
|
var node = (ShardTreeItem) newValue;
|
||||||
System.out.println(node.getShard());
|
var paneClass = shardPanesMap.get(node.getShard().getClass());
|
||||||
if (node.getShard() instanceof TextShard) {
|
try {
|
||||||
shardDetailContainer.getChildren().add(new TextArea(((TextShard) node.getShard()).getText()));
|
var pane = paneClass.getDeclaredConstructor(node.getShard().getClass()).newInstance(node.getShard());
|
||||||
} else if (node.getShard() instanceof LoginCredentialsShard) {
|
shardDetailContainer.getChildren().add(pane);
|
||||||
shardDetailContainer.getChildren().add(new Label("Username: " + ((LoginCredentialsShard) node.getShard()).getUsername()));
|
} catch (Exception e) {
|
||||||
shardDetailContainer.getChildren().add(new Label("Password: " + ((LoginCredentialsShard) node.getShard()).getPassword()));
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -66,6 +75,7 @@ public class MainViewController implements ModelListener {
|
||||||
|
|
||||||
private TreeItem<CrystalItem> createNode(Cluster cluster) {
|
private TreeItem<CrystalItem> createNode(Cluster cluster) {
|
||||||
ClusterTreeItem node = new ClusterTreeItem(cluster);
|
ClusterTreeItem node = new ClusterTreeItem(cluster);
|
||||||
|
node.setExpanded(true);
|
||||||
for (Cluster child : cluster.getClustersOrdered()) {
|
for (Cluster child : cluster.getClustersOrdered()) {
|
||||||
node.getChildren().add(this.createNode(child));
|
node.getChildren().add(this.createNode(child));
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,10 +38,18 @@ public class Cluster implements Comparable<Cluster>, CrystalItem {
|
||||||
this.shards.add(shard);
|
this.shards.add(shard);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void removeShard(Shard shard) {
|
||||||
|
this.shards.remove(shard);
|
||||||
|
}
|
||||||
|
|
||||||
public void addCluster(Cluster cluster) {
|
public void addCluster(Cluster cluster) {
|
||||||
this.clusters.add(cluster);
|
this.clusters.add(cluster);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void removeCluster(Cluster cluster) {
|
||||||
|
this.clusters.remove(cluster);
|
||||||
|
}
|
||||||
|
|
||||||
public List<Cluster> getClustersOrdered() {
|
public List<Cluster> getClustersOrdered() {
|
||||||
List<Cluster> clusters = new ArrayList<>(this.getClusters());
|
List<Cluster> clusters = new ArrayList<>(this.getClusters());
|
||||||
clusters.sort(Comparator.naturalOrder());
|
clusters.sort(Comparator.naturalOrder());
|
||||||
|
|
|
@ -19,6 +19,10 @@ public class Model {
|
||||||
|
|
||||||
public void setActiveCluster(Cluster activeCluster) {
|
public void setActiveCluster(Cluster activeCluster) {
|
||||||
this.activeCluster = activeCluster;
|
this.activeCluster = activeCluster;
|
||||||
|
this.notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void notifyListeners() {
|
||||||
this.listeners.forEach(ModelListener::activeClusterUpdated);
|
this.listeners.forEach(ModelListener::activeClusterUpdated);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
package nl.andrewlalis.crystalkeep.model;
|
package nl.andrewlalis.crystalkeep.model;
|
||||||
|
|
||||||
import nl.andrewlalis.crystalkeep.model.shards.ShardType;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A shard is a single "piece" of information, such as a snippet of text, login
|
* A shard is a single "piece" of information, such as a snippet of text, login
|
||||||
* credentials, an image, or a private key. All shards within a cluster should
|
* credentials, an image, or a private key.
|
||||||
* have unique names.
|
|
||||||
* <p>
|
* <p>
|
||||||
* Due to the need to deserialize shards from byte arrays, it is required
|
* Due to the need to deserialize shards from byte arrays, it is required
|
||||||
* that this parent class holds a type discriminator value, which is used to
|
* that this parent class holds a type discriminator value, which is used to
|
||||||
|
@ -55,7 +52,7 @@ public abstract class Shard implements Comparable<Shard>, CrystalItem {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
Shard shard = (Shard) o;
|
Shard shard = (Shard) o;
|
||||||
return getName().equals(shard.getName()) && getType() == shard.getType();
|
return getName().equals(shard.getName()) && getType() == shard.getType() && getCreatedAt().equals(shard.getCreatedAt());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package nl.andrewlalis.crystalkeep.model.shards;
|
package nl.andrewlalis.crystalkeep.model;
|
||||||
|
|
||||||
import nl.andrewlalis.crystalkeep.model.Shard;
|
import nl.andrewlalis.crystalkeep.model.shards.LoginCredentialsShard;
|
||||||
|
import nl.andrewlalis.crystalkeep.model.shards.TextShard;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a distinct type of shard, and should correspond to exactly one
|
* Represents a distinct type of shard, and should correspond to exactly one
|
|
@ -3,7 +3,7 @@ package nl.andrewlalis.crystalkeep.model.serialization;
|
||||||
import nl.andrewlalis.crystalkeep.model.Cluster;
|
import nl.andrewlalis.crystalkeep.model.Cluster;
|
||||||
import nl.andrewlalis.crystalkeep.model.Shard;
|
import nl.andrewlalis.crystalkeep.model.Shard;
|
||||||
import nl.andrewlalis.crystalkeep.model.shards.LoginCredentialsShard;
|
import nl.andrewlalis.crystalkeep.model.shards.LoginCredentialsShard;
|
||||||
import nl.andrewlalis.crystalkeep.model.shards.ShardType;
|
import nl.andrewlalis.crystalkeep.model.ShardType;
|
||||||
import nl.andrewlalis.crystalkeep.model.shards.TextShard;
|
import nl.andrewlalis.crystalkeep.model.shards.TextShard;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -12,7 +12,6 @@ import java.io.OutputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package nl.andrewlalis.crystalkeep.model.shards;
|
package nl.andrewlalis.crystalkeep.model.shards;
|
||||||
|
|
||||||
import nl.andrewlalis.crystalkeep.model.Shard;
|
import nl.andrewlalis.crystalkeep.model.Shard;
|
||||||
|
import nl.andrewlalis.crystalkeep.model.ShardType;
|
||||||
import nl.andrewlalis.crystalkeep.model.serialization.ByteUtils;
|
import nl.andrewlalis.crystalkeep.model.serialization.ByteUtils;
|
||||||
import nl.andrewlalis.crystalkeep.model.serialization.ShardSerializer;
|
import nl.andrewlalis.crystalkeep.model.serialization.ShardSerializer;
|
||||||
|
|
||||||
|
@ -39,6 +40,11 @@ public class LoginCredentialsShard extends Shard {
|
||||||
return super.toString() + ", username=\"" + this.username + "\", password=\"" + this.password + "\"";
|
return super.toString() + ", username=\"" + this.username + "\", password=\"" + this.password + "\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getIconPath() {
|
||||||
|
return "/nl/andrewlalis/crystalkeep/ui/images/login_credentials_shard_node_icon.png";
|
||||||
|
}
|
||||||
|
|
||||||
public static class Serializer implements ShardSerializer<LoginCredentialsShard> {
|
public static class Serializer implements ShardSerializer<LoginCredentialsShard> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package nl.andrewlalis.crystalkeep.model.shards;
|
package nl.andrewlalis.crystalkeep.model.shards;
|
||||||
|
|
||||||
import nl.andrewlalis.crystalkeep.model.Shard;
|
import nl.andrewlalis.crystalkeep.model.Shard;
|
||||||
|
import nl.andrewlalis.crystalkeep.model.ShardType;
|
||||||
import nl.andrewlalis.crystalkeep.model.serialization.ByteUtils;
|
import nl.andrewlalis.crystalkeep.model.serialization.ByteUtils;
|
||||||
import nl.andrewlalis.crystalkeep.model.serialization.ShardSerializer;
|
import nl.andrewlalis.crystalkeep.model.serialization.ShardSerializer;
|
||||||
|
|
||||||
|
@ -29,6 +30,11 @@ public class TextShard extends Shard {
|
||||||
return super.toString() + ", text=\"" + this.text + "\"";
|
return super.toString() + ", text=\"" + this.text + "\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getIconPath() {
|
||||||
|
return "/nl/andrewlalis/crystalkeep/ui/images/text_shard_node_icon.png";
|
||||||
|
}
|
||||||
|
|
||||||
public static class Serializer implements ShardSerializer<TextShard> {
|
public static class Serializer implements ShardSerializer<TextShard> {
|
||||||
@Override
|
@Override
|
||||||
public byte[] serialize(TextShard shard) throws IOException {
|
public byte[] serialize(TextShard shard) throws IOException {
|
||||||
|
|
|
@ -5,35 +5,54 @@ import javafx.scene.control.MenuItem;
|
||||||
import javafx.scene.control.TreeCell;
|
import javafx.scene.control.TreeCell;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
import javafx.scene.image.ImageView;
|
import javafx.scene.image.ImageView;
|
||||||
|
import nl.andrewlalis.crystalkeep.model.Cluster;
|
||||||
import nl.andrewlalis.crystalkeep.model.CrystalItem;
|
import nl.andrewlalis.crystalkeep.model.CrystalItem;
|
||||||
|
import nl.andrewlalis.crystalkeep.model.Model;
|
||||||
import nl.andrewlalis.crystalkeep.model.Shard;
|
import nl.andrewlalis.crystalkeep.model.Shard;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
public class CrystalItemTreeCell extends TreeCell<CrystalItem> {
|
public class CrystalItemTreeCell extends TreeCell<CrystalItem> {
|
||||||
private final ContextMenu contextMenu;
|
private final Model model;
|
||||||
|
|
||||||
public CrystalItemTreeCell() {
|
public CrystalItemTreeCell(Model model) {
|
||||||
MenuItem item = new MenuItem("Delete");
|
this.model = model;
|
||||||
this.contextMenu = new ContextMenu(item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void updateItem(CrystalItem item, boolean empty) {
|
protected void updateItem(CrystalItem item, boolean empty) {
|
||||||
super.updateItem(item, empty);
|
super.updateItem(item, empty);
|
||||||
|
|
||||||
if (!empty) {
|
if (!empty) {
|
||||||
|
ContextMenu menu = new ContextMenu();
|
||||||
|
if (item instanceof Cluster) {
|
||||||
|
var addShardItem = new MenuItem("Add Shard");
|
||||||
|
var addClusterItem = new MenuItem("Add Cluster");
|
||||||
|
menu.getItems().addAll(addShardItem, addClusterItem);
|
||||||
|
}
|
||||||
|
var deleteItem = new MenuItem("Delete");
|
||||||
|
deleteItem.setOnAction(event -> {
|
||||||
|
if (this.getTreeItem().getParent() != null && this.getTreeItem().getParent() instanceof ClusterTreeItem) {
|
||||||
|
var cluster = ((ClusterTreeItem) this.getTreeItem().getParent()).getCluster();
|
||||||
|
if (item instanceof Shard) {
|
||||||
|
cluster.removeShard((Shard) item);
|
||||||
|
} else if (item instanceof Cluster) {
|
||||||
|
cluster.removeCluster((Cluster) item);
|
||||||
|
}
|
||||||
|
this.model.notifyListeners();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
menu.getItems().add(deleteItem);
|
||||||
this.setText(item.getName());
|
this.setText(item.getName());
|
||||||
InputStream is = getClass().getResourceAsStream(item.getIconPath());
|
InputStream is = getClass().getResourceAsStream(item.getIconPath());
|
||||||
if (is != null) {
|
if (is != null) {
|
||||||
ImageView icon = new ImageView(new Image(is));
|
ImageView icon = new ImageView(new Image(is));
|
||||||
icon.setFitHeight(16);
|
icon.setFitHeight(24);
|
||||||
icon.setPreserveRatio(true);
|
icon.setPreserveRatio(true);
|
||||||
this.setGraphic(icon);
|
this.setGraphic(icon);
|
||||||
}
|
}
|
||||||
if (item instanceof Shard) {
|
this.setContextMenu(menu);
|
||||||
this.setContextMenu(this.contextMenu);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
this.setText(null);
|
this.setText(null);
|
||||||
this.setGraphic(null);
|
this.setGraphic(null);
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
package nl.andrewlalis.crystalkeep.view.shard_details;
|
||||||
|
|
||||||
|
import javafx.geometry.Insets;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.control.CheckBox;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.PasswordField;
|
||||||
|
import javafx.scene.control.TextField;
|
||||||
|
import javafx.scene.layout.GridPane;
|
||||||
|
import javafx.scene.layout.Pane;
|
||||||
|
import nl.andrewlalis.crystalkeep.model.shards.LoginCredentialsShard;
|
||||||
|
|
||||||
|
public class LoginCredentialsPane extends ShardPane<LoginCredentialsShard> {
|
||||||
|
public LoginCredentialsPane(LoginCredentialsShard shard) {
|
||||||
|
super(shard);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Node getContent(LoginCredentialsShard shard) {
|
||||||
|
GridPane gp = new GridPane();
|
||||||
|
gp.setPadding(new Insets(5));
|
||||||
|
gp.setHgap(5);
|
||||||
|
gp.setVgap(5);
|
||||||
|
gp.add(new Label("Username"), 0, 0);
|
||||||
|
var usernameField = new TextField(shard.getUsername());
|
||||||
|
usernameField.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
shard.setUsername(newValue);
|
||||||
|
});
|
||||||
|
gp.add(usernameField, 1, 0);
|
||||||
|
gp.add(new Label("Password"), 0, 1);
|
||||||
|
var passwordField = new PasswordField();
|
||||||
|
passwordField.setText(shard.getPassword());
|
||||||
|
var rawPasswordField = new TextField(shard.getPassword());
|
||||||
|
rawPasswordField.setVisible(false);
|
||||||
|
passwordField.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
shard.setPassword(newValue);
|
||||||
|
rawPasswordField.setText(newValue);
|
||||||
|
});
|
||||||
|
rawPasswordField.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
shard.setPassword(newValue);
|
||||||
|
passwordField.setText(newValue);
|
||||||
|
});
|
||||||
|
var passwordsContainer = new Pane();
|
||||||
|
passwordsContainer.getChildren().add(passwordField);
|
||||||
|
passwordsContainer.getChildren().add(rawPasswordField);
|
||||||
|
gp.add(passwordsContainer, 1, 1);
|
||||||
|
var showPasswordCheckbox = new CheckBox("Show password");
|
||||||
|
showPasswordCheckbox.setSelected(false);
|
||||||
|
showPasswordCheckbox.selectedProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
passwordField.setVisible(!newValue);
|
||||||
|
rawPasswordField.setVisible(newValue);
|
||||||
|
});
|
||||||
|
gp.add(showPasswordCheckbox, 1, 2);
|
||||||
|
return gp;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package nl.andrewlalis.crystalkeep.view.shard_details;
|
||||||
|
|
||||||
|
import javafx.geometry.Insets;
|
||||||
|
import javafx.geometry.Orientation;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.Separator;
|
||||||
|
import javafx.scene.control.TextField;
|
||||||
|
import javafx.scene.layout.GridPane;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
|
import nl.andrewlalis.crystalkeep.model.Shard;
|
||||||
|
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
|
public abstract class ShardPane<T extends Shard> extends VBox {
|
||||||
|
public ShardPane(T shard) {
|
||||||
|
this.setSpacing(5);
|
||||||
|
GridPane gp = new GridPane();
|
||||||
|
gp.setPadding(new Insets(5));
|
||||||
|
gp.setHgap(5);
|
||||||
|
gp.setVgap(5);
|
||||||
|
gp.add(new Label("Name"), 0, 0);
|
||||||
|
var nameField = new TextField(shard.getName());
|
||||||
|
nameField.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
shard.setName(newValue);
|
||||||
|
});
|
||||||
|
gp.add(nameField, 1, 0);
|
||||||
|
gp.add(new Label("Created at"), 0, 1);
|
||||||
|
var createdAtField = new TextField(shard.getCreatedAt().format(DateTimeFormatter.ofPattern("dd MMMM yyyy HH:mm:ss")));
|
||||||
|
createdAtField.setEditable(false);
|
||||||
|
gp.add(createdAtField, 1, 1);
|
||||||
|
this.getChildren().add(gp);
|
||||||
|
this.getChildren().add(new Separator(Orientation.HORIZONTAL));
|
||||||
|
this.getChildren().add(this.getContent(shard));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract Node getContent(T shard);
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package nl.andrewlalis.crystalkeep.view.shard_details;
|
||||||
|
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.control.TextArea;
|
||||||
|
import nl.andrewlalis.crystalkeep.model.shards.TextShard;
|
||||||
|
|
||||||
|
public class TextShardPane extends ShardPane<TextShard> {
|
||||||
|
public TextShardPane(TextShard shard) {
|
||||||
|
super(shard);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Node getContent(TextShard shard) {
|
||||||
|
var textArea = new TextArea(shard.getText());
|
||||||
|
textArea.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
shard.setText(newValue);
|
||||||
|
});
|
||||||
|
return textArea;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,18 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<?import javafx.scene.control.Label?>
|
|
||||||
<?import javafx.scene.control.TreeView?>
|
|
||||||
<?import javafx.scene.layout.BorderPane?>
|
|
||||||
|
|
||||||
<BorderPane xmlns="http://javafx.com/javafx"
|
|
||||||
xmlns:fx="http://javafx.com/fxml"
|
|
||||||
fx:controller="nl.andrewlalis.crystalkeep.control.ClusterTreeViewController"
|
|
||||||
prefWidth="200.0"
|
|
||||||
>
|
|
||||||
<top>
|
|
||||||
<Label text="Clusters" BorderPane.alignment="TOP_CENTER"/>
|
|
||||||
</top>
|
|
||||||
<center>
|
|
||||||
<TreeView fx:id="clusterTreeView" prefWidth="200.0"/>
|
|
||||||
</center>
|
|
||||||
</BorderPane>
|
|
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
Loading…
Reference in New Issue