package bluej.groupwork.ui;
import java.io.File;
import java.io.FileFilter;
import java.util.HashMap;
import java.util.Map;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.SortType;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import bluej.Config;
import bluej.collect.DataCollector;
import bluej.groupwork.Repository;
import bluej.groupwork.StatusHandle;
import bluej.groupwork.StatusListener;
import bluej.groupwork.TeamStatusInfo;
import bluej.groupwork.TeamUtils;
import bluej.groupwork.TeamViewFilter;
import bluej.groupwork.TeamworkCommand;
import bluej.groupwork.TeamworkCommandResult;
import bluej.pkgmgr.Project;
import bluej.utility.FXWorker;
import bluej.utility.javafx.FXCustomizedDialog;
import bluej.utility.javafx.JavaFXUtil;
import threadchecker.OnThread;
import threadchecker.Tag;
| Main frame for CVS Status Dialog
|
| @author bquig
| @author Amjad Altadmri
|
@OnThread(Tag.FXPlatform)
public class StatusFrame extends FXCustomizedDialog<Void>{
private Project project;
private Repository repository;
private StatusTableModel statusModel;
private Button refreshButton;
private ActivityIndicator progressBar;
private StatusWorker worker;
private static final int MAX_ENTRIES = 20;
private final boolean isDVCS;
private TableView<TeamStatusInfo> statusTable;
| Creates a new instance of StatusFrame. Called via factory method
| getStatusWindow.
|
public StatusFrame(Project project)
{
super(null, "team.status", "team-status");
this.project = project;
isDVCS = project.getTeamSettingsController().isDVCS();
getDialogPane().setContent(makeMainPane());
prepareButtonPane();
}
@Override
protected Node wrapButtonBar(Node original)
{
makeRefreshPaneComponents();
BorderPane borderPane = new BorderPane(progressBar, null, original, null, refreshButton);
JavaFXUtil.addStyleClass(borderPane, "replacement-button-bar");
return borderPane;
}
private Node makeMainPane()
{
statusModel = isDVCS ?
new StatusTableModelDVCS(project, estimateInitialEntries()) :
new StatusTableModelNonDVCS(project, estimateInitialEntries());
statusTable = new TableView<>(statusModel.getResources());
TableColumn<TeamStatusInfo, String> firstColumn = new TableColumn<>(statusModel.getColumnName(0));
JavaFXUtil.addStyleClass(firstColumn, "team-status-firstColumn");
firstColumn.prefWidthProperty().bind(statusTable.widthProperty().multiply(0.49));
firstColumn.setCellValueFactory(v ->
new ReadOnlyStringWrapper(ResourceDescriptor.getResource(project, v.getValue(), false)));
TableColumn<TeamStatusInfo, Object> secondColumn = new TableColumn<>(statusModel.getColumnName(1));
JavaFXUtil.addStyleClass(secondColumn, "team-status-secondColumn");
secondColumn.prefWidthProperty().bind(statusTable.widthProperty().multiply(0.249));
secondColumn.setCellValueFactory(v -> new ReadOnlyObjectWrapper<>(getValueAt(v.getValue(), 1)));
secondColumn.setCellFactory(col -> new StatusTableCell(isDVCS, 1));
TableColumn<TeamStatusInfo, Object> thirdColumn = new TableColumn<>(statusModel.getColumnName(2));
JavaFXUtil.addStyleClass(thirdColumn, "team-status-thirdColumn");
thirdColumn.prefWidthProperty().bind(statusTable.widthProperty().multiply(0.249));
thirdColumn.setCellValueFactory(v -> new ReadOnlyObjectWrapper<>(getValueAt(v.getValue(), 2)));
thirdColumn.setCellFactory(col -> new StatusTableCell(isDVCS, 2));
statusTable.getColumns().setAll(firstColumn, secondColumn, thirdColumn);
statusTable.setColumnResizePolicy(TableView.UNCONSTRAINED_RESIZE_POLICY);
statusTable.setBackground(null);
JavaFXUtil.addStyleClass(statusTable, "status-table");
return new BorderPane(statusTable);
}
| Create the Refresh button and status progress bar
|
private void makeRefreshPaneComponents()
{
progressBar = new ActivityIndicator();
progressBar.setRunning(false);
BorderPane.setAlignment(progressBar, Pos.CENTER);
refreshButton = new Button(Config.getString("team.status.refresh"));
refreshButton.setDisable(true);
refreshButton.setOnAction(event -> update());
refreshButton.requestFocus();
}
| Set up the buttons panel to contain a close button, and register the close action.
|
private void prepareButtonPane()
{
getDialogPane().getButtonTypes().setAll(ButtonType.CLOSE);
this.setOnCloseRequest(event -> {
if (worker != null) {
worker.abort();
}
});
}
| Try and estimate the number of entries in status table to avoid resizing
| once repository has responded.
|
private int estimateInitialEntries()
{
int initialEntries = project.getFilesInProject(true, false).size() + 1;
if (initialEntries > MAX_ENTRIES) {
initialEntries = MAX_ENTRIES;
}
return initialEntries;
}
| Refresh the status window.
|
public void update()
{
repository = project.getRepository();
if (repository != null) {
progressBar.setRunning(true);
refreshButton.setDisable(true);
worker = new StatusWorker();
worker.start();
}
else {
hide();
}
}
| Find the table entry at a particular column for a specific info object (row).
|
| @param info the info object which occupies a row
| @param col the table column number
| @return the Object at that location in the table
|
public Object getValueAt(TeamStatusInfo info, int col)
{
switch (col) {
case 1:
return isDVCS ? info.getStatus() : info.getLocalVersion();
case 2:
return info.getStatus(!isDVCS);
default:
break;
}
return null;
}
| Inner class to do the actual cvs status call to ensure that the UI is not
| blocked during remote call
|
class StatusWorker
extends FXWorker implements StatusListener
{
ObservableList<TeamStatusInfo> resources;
TeamworkCommand command;
TeamworkCommandResult result;
boolean aborted;
FileFilter filter = project.getTeamSettingsController().getFileFilter(true, true);
public StatusWorker()
{
super();
resources = FXCollections.observableArrayList();
command = repository.getStatus(this, filter, true);
}
public void abort()
{
command.cancel();
aborted = true;
}
@OnThread(Tag.Worker)
public Object construct()
{
result = command.getResult();
return resources;
}
@OnThread(Tag.Any)
public void gotStatus(TeamStatusInfo info)
{
resources.add(info);
}
@OnThread(Tag.Any)
public void statusComplete(StatusHandle commitHandle)
{
}
public void finished()
{
progressBar.setRunning(false);
if (! aborted) {
if (result.isError()) {
StatusFrame.this.dialogThenHide(() -> TeamUtils.handleServerResponseFX(result, StatusFrame.this.asWindow()));
}
else {
resources.sort((info0, info1) -> info1.getStatus().ordinal() - info0.getStatus().ordinal());
TeamViewFilter filter = new TeamViewFilter();
resources.removeIf(info -> !filter.accept(info));
statusModel.setStatusData(resources);
Map<File, String> statusMap = new HashMap<>();
for (TeamStatusInfo s : resources)
{
statusMap.put(s.getFile(), s.getStatus().getStatusString());
}
DataCollector.teamStatusProject(project, repository, statusMap);
}
refreshButton.setDisable(false);
if (statusTable.getItems() != null ) {
statusTable.getItems().clear();
}
statusTable.refresh();
statusTable.setItems(resources);
TableColumn<TeamStatusInfo,?> secondColumn = statusTable.getColumns().get(1);
statusTable.getSortOrder().add(secondColumn);
secondColumn.setSortType(SortType.DESCENDING);
}
}
}
}
. StatusFrame
. wrapButtonBar
. makeMainPane
. makeRefreshPaneComponents
. prepareButtonPane
. estimateInitialEntries
. update
. getValueAt
top,
use,
map,
class StatusWorker
. StatusWorker
. abort
. construct
. gotStatus
. statusComplete
. finished
322 neLoCode
+ 16 LoComm