Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve wizard interface for the task selection page #450

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.wizard.IWizard;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Shell;
Expand All @@ -21,6 +22,7 @@ public class CogniCryptWizardDialog extends WizardDialog {

public CogniCryptWizardDialog(final Shell parentShell, final IWizard newWizard) {
super(parentShell, newWizard);
this.setPageSize(new Point(400, 600));
}

@Override
Expand All @@ -29,5 +31,4 @@ protected void createButtonsForButtonBar(final Composite parent) {
final Button finishButton = getButton(IDialogConstants.FINISH_ID);
finishButton.setText("Generate");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
Expand All @@ -25,6 +24,9 @@
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Image;
Expand All @@ -33,7 +35,9 @@
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.ui.PlatformUI;
Expand All @@ -46,9 +50,10 @@

public class TaskSelectionPage extends WizardPage {

private Composite container;
private Task selectedTask = null;

private TaskItemComposite selectedTaskItem = null;
private Composite listOfTaskItems; // Row Layout Composite that holds task items composite
private List<TaskItemComposite> taskItems = new ArrayList<TaskItemComposite>(); // ArrayList of all tasks item composite

public TaskSelectionPage() {
super(Constants.SELECT_TASK);
setTitle(Constants.TASK_LIST);
Expand All @@ -58,76 +63,46 @@ public TaskSelectionPage() {

@Override
public void createControl(final Composite parent) {
final List<Task> tasks = TaskJSONReader.getTasks();

final ScrolledComposite sc = new ScrolledComposite(parent, SWT.H_SCROLL | SWT.V_SCROLL);
sc.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

this.container = new Composite(sc, SWT.NONE);
this.container.setBounds(10, 10, 450, 200);
// Make the content able to scroll
final ScrolledComposite sc = new ScrolledComposite(parent, SWT.V_SCROLL);
sc.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true));

//To display the Help view after clicking the help icon
// To display the Help view after clicking the help icon
PlatformUI.getWorkbench().getHelpSystem().setHelp(sc, "de.cognicrypt.codegenerator.TaskSelectionHelp");

final GridLayout gl = new GridLayout(2, false);
gl.verticalSpacing = -6;
this.container.setLayout(gl);

new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1);
new Label(this.container, SWT.NONE);
final Label useCaseDescriptionLabel = new Label(this.container, SWT.WRAP);
final GridData gd_selectProjectLabel = new GridData(SWT.FILL, SWT.FILL, false, false, 1, tasks.size() + 1);
gd_selectProjectLabel.heightHint = 200;
gd_selectProjectLabel.widthHint = 600;
useCaseDescriptionLabel.setLayoutData(gd_selectProjectLabel);
Font a = useCaseDescriptionLabel.getFont();
useCaseDescriptionLabel.setFont(new Font(useCaseDescriptionLabel.getDisplay(), new FontData(a.getFontData()[0].getName(), 12, SWT.None)));

final List<Button> buttons = new ArrayList<Button>();
final List<Image> unclickedImages = new ArrayList<Image>();
new Label(this.container, SWT.NONE);
for (Task ccTask : tasks) {
final Image taskImage = loadImage(ccTask.getImage());
unclickedImages.add(taskImage);

final Button taskButton = createImageButton(this.container, taskImage, ccTask.getDescription());
buttons.add(taskButton);
// listOfTaskItems will hold the selection items for all tasks
// it is attached in the ScrolledComposite
this.listOfTaskItems = new Composite(sc, SWT.NONE);

// Task items are displayed as a list in the listOfTaskItems
final GridLayout rl = new GridLayout(1, false);
this.listOfTaskItems.setLayout(rl);
this.listOfTaskItems.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, false));

// add tasks items to listOfTaskItems
for (Task ccTask: TaskJSONReader.getTasks()) {
taskItems.add(new TaskItemComposite(this.listOfTaskItems, ccTask));
}
buttons.stream().forEach(e -> e.addListener(SWT.Selection, new SelectionButtonListener(buttons, unclickedImages, tasks, useCaseDescriptionLabel)));
buttons.get(0).notifyListeners(SWT.Selection, new Event());

setControl(this.container);
new Label(this.container, SWT.NONE);
new Label(this.container, SWT.NONE);

sc.setContent(this.container);

sc.setContent(this.listOfTaskItems);
sc.setExpandHorizontal(true);
sc.setExpandVertical(true);
sc.setMinSize(this.container.computeSize(SWT.DEFAULT, SWT.DEFAULT));
setControl(sc);
}

public Task getSelectedTask() {
return this.selectedTask;
sc.setAlwaysShowScrollBars(true);
sc.addListener( SWT.Resize, event -> {
sc.setMinSize(this.listOfTaskItems.computeSize( getShell().getClientArea().width - sc.getVerticalBar().getSize().x, SWT.DEFAULT));
} );
this.setControl(sc);
}

@Override
public void setVisible(final boolean visible) {
super.setVisible(visible);
if (visible) {
this.container.setFocus();
this.listOfTaskItems.setFocus();
}
}

private Button createImageButton(final Composite container, final Image startImage, String taskName) {
final Button imageButton = new Button(container, SWT.WRAP | SWT.TOGGLE);
final Rectangle bounds = startImage.getBounds();
imageButton.setSize(bounds.width, bounds.height);
imageButton.setImage(startImage);
imageButton.setToolTipText(taskName);
return imageButton;
}

private Image loadImage(final String image) {
try {
final Bundle bundle = Platform.getBundle(Activator.PLUGIN_ID);
Expand All @@ -150,42 +125,137 @@ private Image loadImage(final String image) {
}

return null;

}

/**
* A single choice selection on all task items. When calling this method, only one task item will be selected.
*/
public void selectTaskItem(TaskItemComposite taskItem) {
// unselect other task items
for(TaskItemComposite notSelectedTaskItem: this.taskItems) {
if(notSelectedTaskItem != taskItem) {
notSelectedTaskItem.unselect();
}
}
taskItem.select();
TaskSelectionPage.this.selectedTaskItem = taskItem;

setPageComplete(true); // next button on wizard is now clickable
}

public Task getSelectedTask() {
return this.selectedTaskItem.getTask();
}


/**
* This class will append a row with a image button, title and description for a task.
* If any Element in this Composite is pressed, a ItemClickListener is triggered.
* @param listOfTaskItems is the list, where to add the item
* @param task to add in the row
*/
class TaskItemComposite extends Composite {

private Task task;
private Button button;

class SelectionButtonListener implements Listener {

private final List<Button> buttons;
private final List<Image> buttonImages;
private final List<Task> tasks;
TaskItemComposite(final Composite listOfTaskItems, Task task) {

// listOfTaskItems is filled with a Group, which has a two row grid layout.
super(listOfTaskItems, SWT.NONE);
this.setLayout(new GridLayout(1, false));
this.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false));
final Group group = new Group(this, SWT.SHADOW_ETCHED_OUT);
group.setLayout(new GridLayout(2, false));
group.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false));

// First column gets a radio button with the image
this.button = new Button(group, SWT.TOGGLE | SWT.RADIO);
this.button.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
final Image taskImage = loadImage(task.getImage());
if(taskImage == null) {
throw new IllegalArgumentException("Missing Image for Task: " + task.getName());
}
final Rectangle bounds = taskImage.getBounds();
this.button.setSize(bounds.width, bounds.height);
this.button.setImage(taskImage);

// Second column gets group with title and description
final Composite descr = new Composite(group, SWT.NONE);
descr.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false));
descr.setLayout(new GridLayout(1, false));

// title
final Label title = new Label(descr, SWT.WRAP);
title.setText(task.getDescription());
final Font boldFont = new Font( title.getDisplay(), new FontData( "Arial", 12, SWT.BOLD ) );
title.setFont(boldFont);

// description
final Label taskdescr = new Label(descr, SWT.WRAP);
final Font largeFont = new Font( descr.getDisplay(), new FontData( "Arial", 14, SWT.NONE ) );
taskdescr.setFont(largeFont);

final Color gray = Display.getCurrent().getSystemColor(SWT.COLOR_DARK_GRAY);
taskdescr.setForeground(gray);
taskdescr.setText(task.getTaskDescription());
taskdescr.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
taskdescr.pack();

this.task = task;

// click listener to all elements
// TODO: one Listener for the whole Composite would be nice
ItemClickListener listener = new ItemClickListener(this);
this.addListener(SWT.MouseUp, listener);
this.button.addListener(SWT.MouseUp, listener);
descr.addListener(SWT.MouseUp, listener);
title.addListener(SWT.MouseUp, listener);
taskdescr.addListener(SWT.MouseUp, listener);

// add dispose listener (best practice: https://www.eclipse.org/articles/swt-design-2/swt-design-2.html)
this.addDisposeListener(new DisposeListener() {

@Override
public void widgetDisposed(DisposeEvent event) {
boldFont.dispose();
largeFont.dispose();
taskImage.dispose();
}
});


}

public void select() {
this.button.setSelection(true);
}

public void unselect() {
this.button.setSelection(false);
}

public Task getTask() {
return this.task;
}

}

private final Label targetLabel;
/**
* This class listens to clicks on task item components.
*/
class ItemClickListener implements Listener {

public SelectionButtonListener(final List<Button> buttons, final List<Image> buttonImages, final List<Task> tasks, final Label targetLabel) {
if (buttons.size() != buttonImages.size() || buttons.size() != tasks.size()) {
throw new IllegalArgumentException("All arrays are required to have the same length." + "If not it indicates an incomplete setup for buttons and their images");
}
private final TaskItemComposite taskItem;

this.buttons = buttons;
this.buttonImages = buttonImages;
this.tasks = tasks;
this.targetLabel = targetLabel;
public ItemClickListener(TaskItemComposite taskItem) {
this.taskItem = taskItem;
}

@Override
public void handleEvent(final Event event) {
final Button eventButton = (Button) event.widget;
for (int i = 0; i < this.buttons.size(); i++) {
final Button curIterationButton = this.buttons.get(i);
if (eventButton.equals(curIterationButton)) {
TaskSelectionPage.this.selectedTask = this.tasks.get(i);
curIterationButton.setSelection(true);
this.targetLabel.setText(TaskSelectionPage.this.selectedTask.getTaskDescription());
setPageComplete(true);
} else {
curIterationButton.setSelection(false);
curIterationButton.setImage(this.buttonImages.get(i));
}
}
public void handleEvent(Event event) {
selectTaskItem(this.taskItem);
}
}
}