/*
* Autopsy Forensic Browser
*
* Copyright 2015-16 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* 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.
*/
package org.sleuthkit.autopsy.timeline.ui.detailview;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import java.util.Arrays;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.OverrunStyle;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox;
import org.controlsfx.control.action.Action;
import org.controlsfx.control.action.ActionUtils;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.timeline.datamodel.EventCluster;
import org.sleuthkit.autopsy.timeline.datamodel.EventStripe;
import org.sleuthkit.autopsy.timeline.datamodel.SingleEvent;
import static org.sleuthkit.autopsy.timeline.ui.detailview.EventNodeBase.configureActionButton;
/**
* Node used in DetailsChart to represent an EventStripe.
*/
final public class EventStripeNode extends MultiEventNodeBase<EventStripe, EventCluster, EventClusterNode> {
private static final Logger LOGGER = Logger.getLogger(EventStripeNode.class.getName());
/**
* The button to expand hide stripes with this description, created lazily.
*/
private Button hideButton;
/**
* Constructor
*
* @param chartLane the DetailsChartLane this node belongs to
* @param eventStripe the EventStripe represented by this node
* @param parentNode the EventClusterNode that is the parent of this node.
*/
EventStripeNode(DetailsChartLane<?> chartLane, EventStripe eventStripe, EventClusterNode parentNode) {
super(chartLane, eventStripe, parentNode);
//setup description label
descrLabel.setTextOverrun(OverrunStyle.CENTER_ELLIPSIS);
descrLabel.setPrefWidth(USE_COMPUTED_SIZE);
setMinHeight(24);
setAlignment(subNodePane, Pos.BOTTOM_LEFT);
if (eventStripe.getClusters().size() > 1) {
for (EventCluster cluster : eventStripe.getClusters()) {
subNodes.add(createChildNode(cluster.withParent(eventStripe)));
}
//stack componenets vertically
getChildren().addAll(new VBox(infoHBox, subNodePane));
} else {
//if the stripe only has one cluster, use alternate simpler layout
EventNodeBase<?> childNode;
EventCluster cluster = Iterables.getOnlyElement(eventStripe.getClusters()).withParent(eventStripe);
if (cluster.getEventIDs().size() == 1) {
childNode = createChildNode(cluster);
} else {
//if the cluster has more than one event, add the clusters controls to this stripe node directly.
EventClusterNode eventClusterNode = (EventClusterNode) createChildNode(cluster);
eventClusterNode.installActionButtons();
controlsHBox.getChildren().addAll(eventClusterNode.getNewCollapseButton(), eventClusterNode.getNewExpandButton());
eventClusterNode.infoHBox.getChildren().remove(eventClusterNode.countLabel);
childNode = eventClusterNode;
}
//hide the cluster description
childNode.setDescriptionVisibility(DescriptionVisibility.HIDDEN);
subNodes.add(childNode);
//stack componenet in z rather than vertically
getChildren().addAll(infoHBox, subNodePane);
}
}
/**
* Get a new Action that hides stripes with the same description as this
* one.
*
* @return a new Action that hides stripes with the same description as this
* one.
*/
private Action newHideAction() {
return new HideDescriptionAction(getDescription(), getEvent().getDescriptionLoD(), chartLane.getParentChart());
}
@Override
void installActionButtons() {
super.installActionButtons();
if (chartLane.quickHideFiltersEnabled() && hideButton == null) {
hideButton = ActionUtils.createButton(newHideAction(), ActionUtils.ActionTextBehavior.HIDE);
configureActionButton(hideButton);
controlsHBox.getChildren().add(hideButton);
}
}
@Override
EventNodeBase<?> createChildNode(EventCluster cluster) {
ImmutableSet<Long> eventIDs = cluster.getEventIDs();
if (eventIDs.size() == 1) {
SingleEvent singleEvent = getController().getEventsModel().getEventById(Iterables.getOnlyElement(eventIDs)).withParent(cluster);
return new SingleEventNode(getChartLane(), singleEvent, this);
} else {
return new EventClusterNode(getChartLane(), cluster, this);
}
}
@Override
EventHandler<MouseEvent> getDoubleClickHandler() {
return mouseEvent -> {
//no-op
};
}
@Override
Iterable<? extends Action> getActions() {
return Iterables.concat(
super.getActions(),
Arrays.asList(newHideAction())
);
}
}