001: /*
002: * Copyright (c) 2004-2006, Jean-François Brazeau. All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * 1. Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * 2. Redistributions in binary form must reproduce the above copyright
011: * notice, this list of conditions and the following disclaimer in the
012: * documentation and/or other materials provided with the distribution.
013: *
014: * 3. The name of the author may not be used to endorse or promote products
015: * derived from this software without specific prior written permission.
016: *
017: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
018: * IMPLIEDWARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
019: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
020: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
021: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
022: * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
023: * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
024: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
025: * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
026: * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: */
028: package jfb.tools.activitymgr.ui.dialogs;
029:
030: import java.util.ArrayList;
031:
032: import jfb.tools.activitymgr.core.ModelMgr;
033: import jfb.tools.activitymgr.core.beans.Task;
034: import jfb.tools.activitymgr.ui.TasksUI.ITaskListener;
035: import jfb.tools.activitymgr.ui.util.ITaskSelectionListener;
036: import jfb.tools.activitymgr.ui.util.SafeRunner;
037: import jfb.tools.activitymgr.ui.util.TaskFinderPanel;
038:
039: import org.apache.log4j.Logger;
040: import org.eclipse.jface.viewers.StructuredSelection;
041: import org.eclipse.jface.viewers.TreeViewer;
042: import org.eclipse.swt.SWT;
043: import org.eclipse.swt.events.MouseAdapter;
044: import org.eclipse.swt.events.MouseEvent;
045: import org.eclipse.swt.layout.FillLayout;
046: import org.eclipse.swt.layout.GridData;
047: import org.eclipse.swt.widgets.Composite;
048: import org.eclipse.swt.widgets.Control;
049: import org.eclipse.swt.widgets.Group;
050: import org.eclipse.swt.widgets.Shell;
051: import org.eclipse.swt.widgets.Table;
052: import org.eclipse.swt.widgets.Tree;
053: import org.eclipse.swt.widgets.TreeItem;
054:
055: public class TaskChooserTreeWithHistoryDialog extends AbstractDialog
056: implements ITaskListener {
057:
058: /** Logger */
059: private static Logger log = Logger
060: .getLogger(TaskChooserTreeWithHistoryDialog.class);
061:
062: /** Arbre contenant la liste des tâches */
063: private TaskChooserTree tasksTree;
064:
065: /** Tableau contenant les dernières taches sélectionnées */
066: private TaskChooserTable previouslySelectedTasksTable;
067:
068: /** Valideur */
069: private ITaskChooserValidator validator;
070:
071: /** Panneau de recherche de tache */
072: private TaskFinderPanel taskFinderPanel;
073:
074: /** Liste des sélections précédentes */
075: private ArrayList previouslySelectedTasks = new ArrayList();
076:
077: /**
078: * Constructeur par défaut.
079: * @param parentShell shell parent.
080: */
081: public TaskChooserTreeWithHistoryDialog(Shell parentShell) {
082: super (parentShell, "Choose a task", null, null);
083: setShellStyle(SWT.RESIZE | SWT.DIALOG_TRIM
084: | SWT.APPLICATION_MODAL);
085: }
086:
087: /* (non-Javadoc)
088: * @see jfb.tools.activitymgr.ui.util.AbstractDialog#validateUserEntry()
089: */
090: protected Object validateUserEntry() throws DialogException {
091: log.debug("validateUserEntry");
092: Task selectedTask = null;
093: Tree tree = tasksTree.getTreeViewer().getTree();
094: TreeItem[] selection = tree.getSelection();
095: if (selection.length > 0)
096: selectedTask = (Task) selection[0].getData();
097: log.debug("Selected task = " + selectedTask);
098: if (selectedTask == null)
099: throw new DialogException("Please choose a task", null);
100: if (validator != null)
101: validator.validateChoosenTask(selectedTask);
102: // Suppression puis enregistrement de la tache dans l'historique
103: // (la suppression permet de garantir que la tache soit la première
104: // dans l'historique)
105: previouslySelectedTasks.remove(selectedTask);
106: if (!previouslySelectedTasks.contains(selectedTask))
107: previouslySelectedTasks.add(selectedTask);
108: // Purge de la liste si + de 20 valeurs
109: if (previouslySelectedTasks.size() == 21)
110: previouslySelectedTasks.remove(20);
111: // Validation du choix de la tache
112: return selectedTask;
113: }
114:
115: /* (non-Javadoc)
116: * @see jfb.tools.activitymgr.ui.util.AbstractDialog#createDialogArea(org.eclipse.swt.widgets.Composite)
117: */
118: protected Control createDialogArea(Composite parent) {
119: Composite parentComposite = (Composite) super
120: .createDialogArea(parent);
121:
122: // Panneau permettant de recherche une tache
123: taskFinderPanel = new TaskFinderPanel(parentComposite);
124: GridData gridData = new GridData(SWT.FILL, SWT.NONE, true,
125: false);
126: gridData.horizontalSpan = 2;
127: taskFinderPanel.setLayoutData(gridData);
128: taskFinderPanel.addTaskListener(new ITaskSelectionListener() {
129: public void taskSelected(Task selectedTask) {
130: selectTaskInTree(selectedTask);
131: }
132: });
133:
134: // Montre-t-on le panneau contenant l'hitorique des sélections ?
135: boolean showHistoryPanel = (previouslySelectedTasks.size() != 0);
136:
137: // Arbre contenant les taches
138: gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
139: if (!showHistoryPanel)
140: gridData.horizontalSpan = 2;
141: Group taskTreeGroup = new Group(parentComposite, SWT.NONE);
142: taskTreeGroup.setText("Task tree");
143: taskTreeGroup.setLayoutData(gridData);
144: taskTreeGroup.setLayout(new FillLayout());
145: tasksTree = new TaskChooserTree(taskTreeGroup, null);
146: TreeViewer viewer = tasksTree.getTreeViewer();
147: viewer.getTree().addMouseListener(new MouseAdapter() {
148: public void mouseDoubleClick(MouseEvent e) {
149: okPressed();
150: }
151: });
152: Task lastValue = (Task) getValue();
153: if (lastValue != null) {
154: viewer.setSelection(new StructuredSelection(lastValue));
155: }
156:
157: // Zone de sélection des taches précédemment sélectionnées
158: if (showHistoryPanel) {
159: gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
160: Group lastSelectionsGroup = new Group(parentComposite,
161: SWT.NONE);
162: lastSelectionsGroup.setText("Previous selection(s)");
163: lastSelectionsGroup.setLayoutData(gridData);
164: lastSelectionsGroup.setLayout(new FillLayout());
165: // Récupération de l'hitorique avec tri inversé (le premier arrivé est affiché en dernier)
166: Task[] history = (Task[]) previouslySelectedTasks
167: .toArray(new Task[previouslySelectedTasks.size()]);
168: Task[] _history = new Task[history.length];
169: for (int i = 0; i < history.length; i++)
170: _history[history.length - i - 1] = history[i];
171: previouslySelectedTasksTable = new TaskChooserTable(
172: lastSelectionsGroup, null, _history);
173: final Table table = previouslySelectedTasksTable
174: .getTableViewer().getTable();
175: table.addMouseListener(new MouseAdapter() {
176: public void mouseDoubleClick(MouseEvent e) {
177: mouseDown(e);
178: StructuredSelection selection = (StructuredSelection) previouslySelectedTasksTable
179: .getTableViewer().getSelection();
180: if (selection.getFirstElement() != null)
181: okPressed();
182: }
183:
184: public void mouseDown(MouseEvent e) {
185: StructuredSelection selection = (StructuredSelection) previouslySelectedTasksTable
186: .getTableViewer().getSelection();
187: if (selection != null) {
188: Task selectedTask = (Task) selection
189: .getFirstElement();
190: if (selectedTask != null)
191: selectTaskInTree(selectedTask);
192: }
193: }
194: });
195: }
196:
197: // Retour du composant parent
198: return parentComposite;
199: }
200:
201: /**
202: * Sélectionne la tache spécifiée dans l'arbre des taches.
203: * @param selectedTask la tache à sélectionner.
204: */
205: private void selectTaskInTree(Task selectedTask) {
206: TreeViewer treeViewer = tasksTree.getTreeViewer();
207: treeViewer.setSelection(new StructuredSelection(selectedTask));
208: treeViewer.getTree().setFocus();
209: }
210:
211: /**
212: * @param validator le nouveau valideur.
213: */
214: public void setValidator(ITaskChooserValidator validator) {
215: this .validator = validator;
216: }
217:
218: /* (non-Javadoc)
219: * @see jfb.tools.activitymgr.ui.TasksUI.TaskListener#taskAdded(jfb.tools.activitymgr.core.beans.Task)
220: */
221: public void taskAdded(Task task) {
222: // Quand une tache est ajoutée, elle ne peut pas être présente dans l'historique
223: // des taches => donc rien à faire
224: }
225:
226: /* (non-Javadoc)
227: * @see jfb.tools.activitymgr.ui.TasksUI.TaskListener#taskRemoved(jfb.tools.activitymgr.core.beans.Task)
228: */
229: public void taskRemoved(final Task removedTask) {
230: new SafeRunner() {
231: protected Object runUnsafe() throws Exception {
232: // Parcours des taches présentes dans le tableau
233: int itemIdxToRemove = -1;
234: for (int i = 0; i < previouslySelectedTasks.size(); i++) {
235: Task currentTask = (Task) previouslySelectedTasks
236: .get(i);
237: // Cas ou la tache supprimée est dans le tableau
238: // dans ce cas, on sauvegarde le N° pour effectuer
239: // la suppression par la suite
240: if (currentTask.getId() == removedTask.getId()) {
241: itemIdxToRemove = i;
242: }
243: // Autre cas : la tache supprimée est la soeur d'une des taches parent
244: // de la tache en cours ; c'est le cas si le chemin de la tache en cours
245: // commence par le chemin de la tache qui a été supprimée
246: else if (currentTask.getPath().startsWith(
247: removedTask.getPath())) {
248: String removedTaskFullpath = removedTask
249: .getFullPath();
250: String removedTaskSisterFullPath = currentTask
251: .getFullPath().substring(0,
252: removedTaskFullpath.length());
253: // La tache n'est impactée que si sa tache parent se trouvant être la soeur de
254: // celle qui a été supprimée possède un numéro supérieur à celui de la
255: // tache supprimée
256: if (removedTaskSisterFullPath
257: .compareTo(removedTaskFullpath) > 0) {
258: // Dans ce cas il faut mettre à jour le chemin de la tache
259: currentTask = ModelMgr.getTask(currentTask
260: .getId());
261: previouslySelectedTasks.set(i, currentTask);
262: }
263: }
264: }
265: // Si on a trouvé l'item supprimé, on le supprime
266: if (itemIdxToRemove >= 0)
267: previouslySelectedTasks.remove(itemIdxToRemove);
268: return null;
269: }
270: }.run(getParentShell());
271: }
272:
273: /* (non-Javadoc)
274: * @see jfb.tools.activitymgr.ui.TasksUI.TaskListener#taskUpdated(jfb.tools.activitymgr.core.beans.Task)
275: */
276: public void taskUpdated(Task updatedTask) {
277: boolean found = false;
278: for (int i = 0; !found && i < previouslySelectedTasks.size(); i++) {
279: Task currentTask = (Task) previouslySelectedTasks.get(i);
280: found = currentTask.getId() == updatedTask.getId();
281: if (found)
282: previouslySelectedTasks.set(i, updatedTask);
283: }
284: }
285:
286: /* (non-Javadoc)
287: * @see jfb.tools.activitymgr.ui.TasksUI.ITaskListener#taskMoved(java.lang.String, jfb.tools.activitymgr.core.beans.Task)
288: */
289: public void taskMoved(final String oldTaskFullpath,
290: final Task movedTask) {
291: new SafeRunner() {
292: protected Object runUnsafe() throws Exception {
293: // Déduction de l'ancien chemin de la tache à partir de l'ancien
294: // chemin complet
295: String oldTaskPath = oldTaskFullpath.substring(0,
296: oldTaskFullpath.length() - 2);
297: for (int i = 0; i < previouslySelectedTasks.size(); i++) {
298: Task currentTask = (Task) previouslySelectedTasks
299: .get(i);
300: // Cas ou la tache modifiée est dans la liste
301: if (currentTask.getId() == movedTask.getId()) {
302: previouslySelectedTasks.set(i, movedTask);
303: }
304: // Autre cas : la tache a déplacée est une tache
305: // parent de la tache en cours
306: else if (currentTask.getPath().startsWith(
307: oldTaskFullpath)) {
308: currentTask = ModelMgr.getTask(currentTask
309: .getId());
310: previouslySelectedTasks.set(i, currentTask);
311: }
312: // Autre cas : la tache déplacée est la soeur d'une des taches parent
313: // de la tache en cours
314: else if (currentTask.getPath().startsWith(
315: oldTaskPath)) {
316: currentTask = ModelMgr.getTask(currentTask
317: .getId());
318: previouslySelectedTasks.set(i, currentTask);
319: }
320: }
321: return null;
322: }
323:
324: }.run(getParentShell());
325: }
326:
327: }
|