summaryrefslogtreecommitdiffstats
path: root/dozentenmodul/src/main/java/org/openslx/dozmod
diff options
context:
space:
mode:
authorJonathan Bauer2016-01-21 18:30:16 +0100
committerJonathan Bauer2016-01-21 18:30:16 +0100
commit7e6f4a7c094ac014d1c63b163c57d62e800dfe53 (patch)
treea6a79e170dda51e9f2cbf0fbf1b1ad6cd7f5b55b /dozentenmodul/src/main/java/org/openslx/dozmod
parent[server] Add section entry to xml (diff)
downloadtutor-module-7e6f4a7c094ac014d1c63b163c57d62e800dfe53.tar.gz
tutor-module-7e6f4a7c094ac014d1c63b163c57d62e800dfe53.tar.xz
tutor-module-7e6f4a7c094ac014d1c63b163c57d62e800dfe53.zip
[client] Changed location selector from lists to tree selection
Diffstat (limited to 'dozentenmodul/src/main/java/org/openslx/dozmod')
-rw-r--r--dozentenmodul/src/main/java/org/openslx/dozmod/gui/control/JCheckBoxTree.java294
-rw-r--r--dozentenmodul/src/main/java/org/openslx/dozmod/gui/control/LocationSelector.java446
-rw-r--r--dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/LectureDetailsWindow.java15
-rw-r--r--dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/LocationSelectionWindow.java27
-rw-r--r--dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/layout/LocationSelectionWindowLayout.java13
-rw-r--r--dozentenmodul/src/main/java/org/openslx/dozmod/gui/wizard/page/LectureLocationSelectionPage.java36
-rw-r--r--dozentenmodul/src/main/java/org/openslx/dozmod/util/FormatHelper.java13
7 files changed, 558 insertions, 286 deletions
diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/control/JCheckBoxTree.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/control/JCheckBoxTree.java
new file mode 100644
index 00000000..0936e584
--- /dev/null
+++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/control/JCheckBoxTree.java
@@ -0,0 +1,294 @@
+package org.openslx.dozmod.gui.control;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.util.EventListener;
+import java.util.EventObject;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+
+import javax.swing.JCheckBox;
+import javax.swing.JPanel;
+import javax.swing.JTree;
+import javax.swing.event.EventListenerList;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeSelectionModel;
+import javax.swing.tree.TreeCellRenderer;
+import javax.swing.tree.TreeModel;
+import javax.swing.tree.TreeNode;
+import javax.swing.tree.TreePath;
+
+import org.openslx.bwlp.thrift.iface.Location;
+import org.openslx.dozmod.util.FormatHelper;
+
+/**
+ * Credits to 'SomethingSomething': http://stackoverflow.com/a/21851201
+ * With minor changes:
+ * TODO
+ */
+public class JCheckBoxTree extends JTree {
+
+ private static final long serialVersionUID = -4194122328392241790L;
+
+ JCheckBoxTree selfPointer = this;
+
+ // Defining data structure that will enable to fast check-indicate the state
+ // of each node
+ // It totally replaces the "selection" mechanism of the JTree
+ private class CheckedNode {
+ boolean isSelected;
+ boolean hasChildren;
+ boolean allChildrenSelected;
+
+ public CheckedNode(boolean isSelected_, boolean hasChildren_,
+ boolean allChildrenSelected_) {
+ isSelected = isSelected_;
+ hasChildren = hasChildren_;
+ allChildrenSelected = allChildrenSelected_;
+ }
+ }
+
+ HashMap<TreePath, CheckedNode> nodesCheckingState;
+ HashSet<TreePath> checkedPaths = new HashSet<TreePath>();
+
+ // Defining a new event type for the checking mechanism and preparing
+ // event-handling mechanism
+ protected EventListenerList listenerList = new EventListenerList();
+
+ public class CheckChangeEvent extends EventObject {
+ private static final long serialVersionUID = -8100230309044193368L;
+
+ public CheckChangeEvent(Object source) {
+ super(source);
+ }
+ }
+
+ public interface CheckChangeEventListener extends EventListener {
+ public void checkStateChanged(CheckChangeEvent event);
+ }
+
+ public void addCheckChangeEventListener(CheckChangeEventListener listener) {
+ listenerList.add(CheckChangeEventListener.class, listener);
+ }
+
+ public void removeCheckChangeEventListener(CheckChangeEventListener listener) {
+ listenerList.remove(CheckChangeEventListener.class, listener);
+ }
+
+ void fireCheckChangeEvent(CheckChangeEvent evt) {
+ Object[] listeners = listenerList.getListenerList();
+ for (int i = 0; i < listeners.length; i++) {
+ if (listeners[i] == CheckChangeEventListener.class) {
+ ((CheckChangeEventListener) listeners[i + 1])
+ .checkStateChanged(evt);
+ }
+ }
+ }
+
+ // Override
+ public void setModel(TreeModel newModel) {
+ super.setModel(newModel);
+ resetCheckingState();
+ // expand all nodes
+ for (int i = 0; i < this.getRowCount(); i++) {
+ this.expandRow(i);
+ }
+ }
+ // Preselection stuff
+ public void setCheckedState(List<TreePath> paths) {
+ if (paths == null)
+ return;
+ for (TreePath path : paths) {
+ if (path != null)
+ checkSubTree(path, true);
+ }
+ }
+
+ // New method that returns only the checked paths (totally ignores original
+ // "selection" mechanism)
+ public TreePath[] getCheckedPaths() {
+ return checkedPaths.toArray(new TreePath[checkedPaths.size()]);
+ }
+
+ // Returns true in case that the node is selected, has children but not all
+ // of them are selected
+ public boolean isSelectedPartially(TreePath path) {
+ CheckedNode cn = nodesCheckingState.get(path);
+ return cn.isSelected && cn.hasChildren && !cn.allChildrenSelected;
+ }
+
+ private void resetCheckingState() {
+ nodesCheckingState = new HashMap<TreePath, CheckedNode>();
+ checkedPaths = new HashSet<TreePath>();
+ DefaultMutableTreeNode node = (DefaultMutableTreeNode) getModel()
+ .getRoot();
+ if (node == null) {
+ return;
+ }
+ addSubtreeToCheckingStateTracking(node);
+ }
+
+ // Creating data structure of the current model for the checking mechanism
+ private void addSubtreeToCheckingStateTracking(DefaultMutableTreeNode node) {
+ TreeNode[] path = node.getPath();
+ TreePath tp = new TreePath(path);
+ CheckedNode cn = new CheckedNode(false, node.getChildCount() > 0, false);
+ nodesCheckingState.put(tp, cn);
+ for (int i = 0; i < node.getChildCount(); i++) {
+ addSubtreeToCheckingStateTracking((DefaultMutableTreeNode) tp
+ .pathByAddingChild(node.getChildAt(i))
+ .getLastPathComponent());
+ }
+ }
+
+ // Overriding cell renderer by a class that ignores the original "selection"
+ // mechanism
+ // It decides how to show the nodes due to the checking-mechanism
+ private class CheckBoxCellRenderer extends JPanel implements
+ TreeCellRenderer {
+ private static final long serialVersionUID = -7341833835878991719L;
+ JCheckBox checkBox;
+
+ public CheckBoxCellRenderer() {
+ super();
+ this.setLayout(new BorderLayout());
+ checkBox = new JCheckBox();
+ add(checkBox, BorderLayout.CENTER);
+ setOpaque(false);
+ }
+
+ @Override
+ public Component getTreeCellRendererComponent(JTree tree, Object value,
+ boolean selected, boolean expanded, boolean leaf, int row,
+ boolean hasFocus) {
+ DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
+ Object obj = node.getUserObject();
+ TreePath tp = new TreePath(node.getPath());
+ CheckedNode cn = nodesCheckingState.get(tp);
+ if (cn == null) {
+ return this;
+ }
+ // HACK ...
+ String textString;
+ if (obj instanceof Location)
+ textString = FormatHelper.locName((Location)obj);
+ else
+ textString = obj.toString();
+ checkBox.setSelected(cn.isSelected);
+ checkBox.setText(textString);
+ checkBox.setOpaque(cn.isSelected && cn.hasChildren
+ && !cn.allChildrenSelected);
+ return this;
+ }
+ }
+
+ public JCheckBoxTree() {
+ super();
+ // Disabling toggling by double-click
+ this.setToggleClickCount(0);
+ // Overriding cell renderer by new one defined above
+ CheckBoxCellRenderer cellRenderer = new CheckBoxCellRenderer();
+ this.setCellRenderer(cellRenderer);
+ // Overriding selection model by an empty one
+ DefaultTreeSelectionModel dtsm = new DefaultTreeSelectionModel() {
+ private static final long serialVersionUID = -8190634240451667286L;
+
+ // Totally disabling the selection mechanism
+ public void setSelectionPath(TreePath path) {
+ }
+
+ public void addSelectionPath(TreePath path) {
+ }
+
+ public void removeSelectionPath(TreePath path) {
+ }
+
+ public void setSelectionPaths(TreePath[] pPaths) {
+ }
+ };
+ // Calling checking mechanism on mouse click
+ this.addMouseListener(new MouseListener() {
+ public void mouseClicked(MouseEvent arg0) {
+ TreePath tp = selfPointer.getPathForLocation(arg0.getX(),
+ arg0.getY());
+ if (tp == null) {
+ return;
+ }
+ boolean checkMode = !nodesCheckingState.get(tp).isSelected;
+ checkSubTree(tp, checkMode);
+ updatePredecessorsWithCheckMode(tp, checkMode);
+ // Firing the check change event
+ fireCheckChangeEvent(new CheckChangeEvent(new Object()));
+ // Repainting tree after the data structures were updated
+ selfPointer.repaint();
+ }
+
+ public void mouseEntered(MouseEvent arg0) {
+ }
+
+ public void mouseExited(MouseEvent arg0) {
+ }
+
+ public void mousePressed(MouseEvent arg0) {
+ }
+
+ public void mouseReleased(MouseEvent arg0) {
+ }
+ });
+ this.setSelectionModel(dtsm);
+ }
+
+ // When a node is checked/unchecked, updating the states of the predecessors
+ protected void updatePredecessorsWithCheckMode(TreePath tp, boolean check) {
+ TreePath parentPath = tp.getParentPath();
+ // If it is the root, stop the recursive calls and return
+ if (parentPath == null) {
+ return;
+ }
+ CheckedNode parentCheckedNode = nodesCheckingState.get(parentPath);
+ DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) parentPath
+ .getLastPathComponent();
+ parentCheckedNode.allChildrenSelected = true;
+ parentCheckedNode.isSelected = false;
+ for (int i = 0; i < parentNode.getChildCount(); i++) {
+ TreePath childPath = parentPath.pathByAddingChild(parentNode
+ .getChildAt(i));
+ CheckedNode childCheckedNode = nodesCheckingState.get(childPath);
+ // It is enough that even one subtree is not fully selected
+ // to determine that the parent is not fully selected
+ if (!childCheckedNode.allChildrenSelected) {
+ parentCheckedNode.allChildrenSelected = false;
+ }
+ }
+ if (parentCheckedNode.allChildrenSelected) {
+ parentCheckedNode.isSelected = true;
+ }
+ if (parentCheckedNode.isSelected) {
+ checkedPaths.add(parentPath);
+ } else {
+ checkedPaths.remove(parentPath);
+ }
+ // Go to upper predecessor
+ updatePredecessorsWithCheckMode(parentPath, check);
+ }
+
+ // Recursively checks/unchecks a subtree
+ protected void checkSubTree(TreePath tp, boolean check) {
+ CheckedNode cn = nodesCheckingState.get(tp);
+ cn.isSelected = check;
+ DefaultMutableTreeNode node = (DefaultMutableTreeNode) tp
+ .getLastPathComponent();
+ for (int i = 0; i < node.getChildCount(); i++) {
+ checkSubTree(tp.pathByAddingChild(node.getChildAt(i)), check);
+ }
+ cn.allChildrenSelected = check;
+ if (check) {
+ checkedPaths.add(tp);
+ } else {
+ checkedPaths.remove(tp);
+ }
+ }
+} \ No newline at end of file
diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/control/LocationSelector.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/control/LocationSelector.java
index cf2553e1..0d522e44 100644
--- a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/control/LocationSelector.java
+++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/control/LocationSelector.java
@@ -1,31 +1,30 @@
package org.openslx.dozmod.gui.control;
import java.awt.Component;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
+import java.util.HashMap;
import java.util.List;
+import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.DefaultListCellRenderer;
-import javax.swing.DefaultListModel;
-import javax.swing.JButton;
-import javax.swing.JCheckBox;
+import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
-import javax.swing.JScrollPane;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreeNode;
+import javax.swing.tree.TreePath;
import org.apache.log4j.Logger;
import org.openslx.bwlp.thrift.iface.Location;
+import org.openslx.dozmod.Config;
import org.openslx.dozmod.gui.Gui;
import org.openslx.dozmod.gui.helper.GridManager;
-import org.openslx.dozmod.thrift.Sorters;
import org.openslx.dozmod.thrift.cache.MetaDataCache;
import org.openslx.util.QuickTimer;
import org.openslx.util.QuickTimer.Task;
@@ -44,16 +43,13 @@ public class LocationSelector extends JPanel {
private final static Logger LOGGER = Logger
.getLogger(LocationSelector.class);
- private DefaultListModel<Location> availableLocationModel = new DefaultListModel<Location>();
- private DefaultListModel<Location> selectedLocationModel = new DefaultListModel<Location>();
-
- private JButton addAllButton = new JButton(">>");
- private JButton addButton = new JButton(">");
- private JButton removeButton = new JButton("<");
- private JButton removeAllButton = new JButton("<<");
- private JRadioButton exclusivelyButton = new JRadioButton("Veranstaltung ausschließlich in den ausgewählten Räumen anzeigen");
- private JRadioButton prioritizedButton = new JRadioButton("Veranstaltung mit höherer Priorität in den ausgewählten Räumen anzeigen");
-// private JCheckBox limitToAllowedUsers = new JCheckBox("Nur für die ausgewählten Benutzern anzeigen", false);
+ private JLabel lblError = new JLabel();
+ private JRadioButton exclusivelyButton = new JRadioButton(
+ "Veranstaltung ausschließlich in den ausgewählten Räumen anzeigen");
+ private JRadioButton prioritizedButton = new JRadioButton(
+ "Veranstaltung mit höherer Priorität in den ausgewählten Räumen anzeigen");
+ // private JCheckBox limitToAllowedUsers = new
+ // JCheckBox("Nur für die ausgewählten Benutzern anzeigen", false);
/**
* Flag for the initialization state
@@ -61,121 +57,26 @@ public class LocationSelector extends JPanel {
private boolean initDone = false;
/**
- * List of ID's of locations to set the selection to when we finished initializing
+ * List of ID's of locations to set the selection to when we finished
+ * initializing
*/
private List<Integer> preselection;
+ private JCheckBoxTree locationTree = new JCheckBoxTree();;
+ private HashMap<Integer, DefaultMutableTreeNode> locationNodesMap = new HashMap<Integer, DefaultMutableTreeNode>();
/**
* Constructor. Initializes the grid layout, the location lists and
* initializes the data
*/
public LocationSelector() {
- GridManager grid = new GridManager(this, 3);
- LocationRenderer locationRenderer = new LocationRenderer();
-
- // the available list of locations
- final JList<Location> availableLocationList = new JList<Location>();
- availableLocationList.setCellRenderer(locationRenderer);
- availableLocationList.setModel(availableLocationModel);
-
- // the selected list of locations
- final JList<Location> selectedLocationList = new JList<Location>();
- selectedLocationList.setCellRenderer(locationRenderer);
- selectedLocationList.setModel(selectedLocationModel);
-
- // the listeners for lists
- selectedLocationList.addMouseListener(new MouseAdapter() {
- public void mouseClicked(MouseEvent e) {
- if (e.getClickCount() == 2) {
- Location selection = selectedLocationList.getSelectedValue();
- if (selection != null) {
- if (selectedLocationModel.contains(selection)) {
- selectedLocationModel.removeElement(selection);
- if (!availableLocationModel.contains(selection)) {
- availableLocationModel.addElement(selection);
- }
- sortLists();
- }
- }
- }
- }
- });
-
- availableLocationList.addMouseListener(new MouseAdapter() {
- public void mouseClicked(MouseEvent e) {
- if (e.getClickCount() == 2) {
- Location selection = availableLocationList.getSelectedValue();
- if (selection != null) {
- if (!selectedLocationModel.contains(selection)) {
- selectedLocationModel.addElement(selection);
- availableLocationModel.removeElement(selection);
- }
- sortLists();
- }
- }
- }
- });
-
- // the listeners for the button panel in the middle
- addAllButton.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- moveAll(availableLocationModel, selectedLocationModel);
- }
- });
- addButton.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- addToSelection(availableLocationList.getSelectedValuesList());
- }
- });
- removeButton.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- removeFromSelection(selectedLocationList.getSelectedValuesList());
-
- }
- });
- removeAllButton.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- moveAll(selectedLocationModel, availableLocationModel);
- }
- });
-
- // the text header
- grid.add(new QLabel("Verfügbare Räume"));
- grid.skip();
- grid.add(new QLabel("Ausgewählte Räume"));
- grid.nextRow();
-
- // the available location panel
- JScrollPane availableScrollPane = new JScrollPane(availableLocationList);
- availableScrollPane.setPreferredSize(Gui.getScaledDimension(200, 150));
- grid.add(availableScrollPane).fill(true, true).expand(true, true);
-
- // the middle button panel
- JPanel buttonPanel = new JPanel();
- GridManager buttonGrid = new GridManager(buttonPanel, 1);
- buttonGrid.add(addAllButton).fill(true, false);
- buttonGrid.nextRow();
- buttonGrid.add(addButton).fill(true, false);
- buttonGrid.nextRow();
- buttonGrid.add(removeButton).fill(true, false);
- buttonGrid.nextRow();
- buttonGrid.add(removeAllButton).fill(true, false);
- buttonGrid.nextRow();
- buttonGrid.finish(true);
- grid.add(buttonPanel).fill(false, false).expand(false, false);
-
- // the selection location panel
- JScrollPane selectionScrollPane = new JScrollPane(selectedLocationList);
- selectionScrollPane.setPreferredSize(Gui.getScaledDimension(200, 150));
- grid.add(selectionScrollPane).fill(true, true).expand(true, true);
+ // build the grid
+ GridManager grid = new GridManager(this, 3);
+ grid.add(locationTree, 3).fill(true, true).expand(true, true);
grid.nextRow();
- // the radio buttons, default is to show the lecture exclusively in the selected locations
+ // the radio buttons, default is to show the lecture exclusively in the
+ // selected locations
exclusivelyButton.setSelected(true);
ButtonGroup group = new ButtonGroup();
group.add(exclusivelyButton);
@@ -186,12 +87,18 @@ public class LocationSelector extends JPanel {
radioPanel.add(prioritizedButton);
grid.add(radioPanel, 3);
grid.nextRow();
-// grid.add(limitToAllowedUsers, 3);
+ grid.add(Box.createVerticalGlue(), 3);
+ grid.nextRow();
+ grid.add(lblError, 3);
+ grid.nextRow();
grid.finish(true);
// initialise the data
init();
}
+ public JCheckBoxTree getTree() {
+ return locationTree;
+ }
/**
* Async fetching of the list of the locations from the server
@@ -219,31 +126,65 @@ public class LocationSelector extends JPanel {
}
/**
- * Getter for the available location model
+ * Sets the list of available locations. Should be called with the list of
+ * locations given by the server. This function will build the tree
+ * represented by the 'locationid'/'parentlocationid' fields of locations
+ * and set the generated tree as model for the JCheckboxTree used in the UI
+ * of this widget.
*
- * @return the locationModel of the "available location" list
+ * @param list
+ * of locations to set the available list to
+ * @return true if setting the list worked, false otherwise
*/
- public DefaultListModel<Location> getLocationModel() {
- return availableLocationModel;
- }
+ public boolean fillLocationsList(final List<Location> locations) {
+ if (locations == null)
+ return false;
- /**
- * Getter for the selected location model
- *
- * @return the locationModel of the "selected location" list
- */
- public DefaultListModel<Location> getSelectedLocationModel() {
- return selectedLocationModel;
+ DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(
+ Config.getLastSatellite());
+ DefaultTreeModel treeModel = new DefaultTreeModel(rootNode, true);
+ // build map containing the node object for each location
+ for (Location loc : locations) {
+ if (loc == null)
+ continue;
+ locationNodesMap.put(loc.getLocationId(),
+ new DefaultMutableTreeNode(loc, true));
+ }
+ // now go over nodes and insert em
+ for (Integer id : locationNodesMap.keySet()) {
+ Location location = MetaDataCache.getLocationById(id);
+ if (location == null)
+ continue;
+ // determine which node this is a child of
+ DefaultMutableTreeNode parentNode = null;
+ if (location.getParentLocationId() == 0)
+ parentNode = rootNode;
+ else
+ parentNode = locationNodesMap.get(location
+ .getParentLocationId());
+ // insert the current node in the tree model
+ treeModel.insertNodeInto(
+ locationNodesMap.get(location.getLocationId()), // what
+ parentNode, // parent?
+ parentNode.getChildCount()); // index
+
+ }
+ locationTree.setModel(treeModel);
+ locationTree.updateUI();
+ return true;
}
/**
* Setter for the "show only in selection" checkbox
*
- * @param true to enable the "limited" radio button, false to enable the other
+ * @param true to enable the "limited" radio button, false to enable the
+ * other
*/
public void setOnlyInSelection(boolean limited) {
exclusivelyButton.setSelected(limited);
+ prioritizedButton.setSelected(!limited);
}
+
/**
* Getter for the "show only in selection" checkbox
*
@@ -274,161 +215,140 @@ public class LocationSelector extends JPanel {
/**
* Gets the selected locations as a list of id's
*
- * @return list of ids of the selection as Integer, empty list if the selection is empty
+ * @return list of ids of the selection as Integer, empty list if the
+ * selection is empty
*/
public List<Integer> getSelectedLocationsAsIds() {
- if (selectedLocationModel == null || selectedLocationModel.getSize() == 0)
+ TreePath[] paths = locationTree.getCheckedPaths();
+ if (paths == null || paths.length == 0) {
return null;
-
- // prepare integer list to be returned
- List<Integer> idList = new ArrayList<Integer>(selectedLocationModel.getSize());
- // iterate over the selected location model
- Enumeration<Location> selection = selectedLocationModel.elements();
- while (selection.hasMoreElements()) {
- Location current = selection.nextElement();
- if (current == null)
+ }
+ // first try to reduce the amount of locations pushed to the server
+ // by removing those which are implicitly selected:
+ // all children of a node in the selection => keep only parent
+ List<TreePath> treePathList = minify(paths);
+
+ // now get the locationId of the nodes in the TreePath list
+ List<Integer> idList = new ArrayList<Integer>(treePathList.size());
+ // iterate over the paths
+ for (TreePath path : treePathList) {
+ if (path == null)
continue;
- idList.add(current.getLocationId());
+ DefaultMutableTreeNode currentNode = (DefaultMutableTreeNode) path
+ .getLastPathComponent();
+ if (currentNode == null)
+ continue;
+ Object currentDataObject = currentNode.getUserObject();
+ if (currentDataObject instanceof Location) {
+ Location currentLocation = (Location) currentDataObject;
+ idList.add(currentLocation.getLocationId());
+ }
}
Collections.sort(idList);
return idList;
}
- /**
- * Sets the list of available locations. Should be called with the list
- * given by the server
- *
- * @param list
- * of locations to set the available list to
- * @return true if setting the list worked, false otherwise
- */
- public boolean fillLocationsList(final List<Location> locations) {
- if (locations == null) {
- LOGGER.error("No locations returned from the metadata cache.");
- return false;
- }
- for (Location loc : locations) {
- if (loc != null) {
- availableLocationModel.addElement(loc);
- } else {
- LOGGER.error("A location returned from the server was null");
+ private List<TreePath> minify(final TreePath[] paths) {
+ // transform the array of paths to a list of leaf nodes
+ List<TreePath> leavesPathsList = new ArrayList<TreePath>();
+ for (TreePath path : paths) {
+ DefaultMutableTreeNode node = (DefaultMutableTreeNode) path
+ .getLastPathComponent();
+ if (node != null && node.isLeaf()) {
+ leavesPathsList.add(path);
}
}
- return true;
- }
-
- /**
- * Moves all elements from the available to the selected list
- *
- * @param model
- * to move from
- * @param model
- * to move to
- */
- private void moveAll(DefaultListModel<Location> from,
- DefaultListModel<Location> to) {
- for (Enumeration<Location> location = from.elements(); location
- .hasMoreElements();) {
- Location current = location.nextElement();
- to.addElement(current);
- }
- from.clear();
- sortLists();
- }
-
- /**
- * Adds the given location to the selection
- *
- * @param location
- * to add to selection
- */
- private void addToSelection(Location location) {
- if (location == null) {
- return;
- }
- List<Location> newLocations = new ArrayList<Location>();
- newLocations.add(location);
- addToSelection(newLocations);
- }
-
- /**
- * Adds the given list of locations to the selection
- *
- * @param list
- * of locations to add to the selection
- */
- private void addToSelection(List<Location> locations) {
- if (locations == null)
- return;
- // LOGGER.debug("AddToSelection: " + locations);
- for (Location location : locations) {
- selectedLocationModel.addElement(location);
- availableLocationModel.removeElement(location);
- }
- sortLists();
- }
-
- /**
- * Removes the given list of locations from the selections
- *
- * @param locations
- * to remove from the selection
- */
- private void removeFromSelection(List<Location> locations) {
- if (locations == null)
- return;
- // LOGGER.debug("RemoveFromSelection: " + locations);
- for (Location location : locations) {
- selectedLocationModel.removeElement(location);
- availableLocationModel.addElement(location);
+ // now get the root node of the tree and start a depth-first search for
+ // leaves
+ DefaultMutableTreeNode rootNode = (DefaultMutableTreeNode) locationTree
+ .getModel().getRoot();
+ Enumeration<?> depthEnum = rootNode.depthFirstEnumeration();
+ while (depthEnum.hasMoreElements()) {
+ DefaultMutableTreeNode current = (DefaultMutableTreeNode) depthEnum
+ .nextElement();
+ // descend til we found a leaf
+ if (!current.isLeaf()) {
+ continue;
+ }
+ // got a leaf, check the children of its parent
+ DefaultMutableTreeNode parent = (DefaultMutableTreeNode) current
+ .getParent();
+ // this shouldnt happen but lets be safe...
+ if (parent == null || parent.isLeaf())
+ continue;
+ // marker to see if all children are selected
+ boolean allChildrenSelected = true;
+ Enumeration<?> children = parent.children();
+ while (children.hasMoreElements()) {
+ DefaultMutableTreeNode child = (DefaultMutableTreeNode) children
+ .nextElement();
+ // check if this child is in our paths list
+ if (!leavesPathsList.contains(getPath(child))) {
+ // current child not in selection, we can stop the search of
+ // this child's parent
+ allChildrenSelected = false;
+ break;
+ }
+ }
+ // if all children were selected, remove them from the list
+ if (allChildrenSelected) {
+ LOGGER.debug("EXCLUDING FROM: " + getPath(parent));
+ Enumeration<?> enumeration = parent.children();
+ while (enumeration.hasMoreElements()) {
+ DefaultMutableTreeNode nod = (DefaultMutableTreeNode) enumeration
+ .nextElement();
+ leavesPathsList.remove(getPath(nod)); // remove already
+ // checks for
+ // existence
+ }
+ // add this parent since we had only leaves in the
+ // leavesPathList
+ leavesPathsList.add(getPath(parent));
+ }
}
- sortLists();
+ return leavesPathsList;
}
/**
- * Helper to sort both lists when changes occur. TODO: doing this via model
- * change listeners?
+ * Helper to get the TreePath of the given TreeNode
+ * @param treeNode
+ * @return
*/
- private void sortLists() {
- // sort the available location list
- List<Location> list = Collections.list(availableLocationModel.elements());
- Collections.sort(list, Sorters.locByName);
- availableLocationModel.clear();
- for (Location loc : list) {
- availableLocationModel.addElement(loc);
- }
- // sort the selected location list
- list = Collections.list(selectedLocationModel.elements());
- Collections.sort(list, Sorters.locByName);
- selectedLocationModel.clear();
- for (Location loc : list) {
- selectedLocationModel.addElement(loc);
+ public static TreePath getPath(TreeNode treeNode) {
+ List<Object> nodes = new ArrayList<Object>();
+ if (treeNode != null) {
+ nodes.add(treeNode);
+ treeNode = treeNode.getParent();
+ while (treeNode != null) {
+ nodes.add(0, treeNode);
+ treeNode = treeNode.getParent();
+ }
}
+ return nodes.isEmpty() ? null : new TreePath(nodes.toArray());
}
/**
* Internal helper to set the selection of the list of location
* corresponding the the given list of ids
- *
- * @param list of id's to set the selected locations to
+ *
+ * @param list
+ * of id's to set the selected locations to
*/
private void setSelectionInternal(List<Integer> list) {
if (list == null || list.isEmpty()) {
LOGGER.error("No list given for preselection!");
return;
}
- moveAll(selectedLocationModel, availableLocationModel);
-
- for (Integer id : preselection) {
- Location loc = MetaDataCache.getLocationById(id);
- if (loc != null) {
- addToSelection(loc);
- }
+ // get the paths in the tree of the given id list of nodes
+ List<TreePath> selectedPathsList = new ArrayList<TreePath>(list.size());
+ for (Integer id : list) {
+ DefaultMutableTreeNode current = locationNodesMap.get(id);
+ if (current == null)
+ continue;
+ TreePath path = new TreePath(current.getPath());
+ selectedPathsList.add(path);
}
- }
-
- public List<Integer> getPreselection() {
- return preselection;
+ locationTree.setCheckedState(selectedPathsList);
}
}
diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/LectureDetailsWindow.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/LectureDetailsWindow.java
index b7e509cb..00c35381 100644
--- a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/LectureDetailsWindow.java
+++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/LectureDetailsWindow.java
@@ -36,6 +36,7 @@ import org.openslx.bwlp.thrift.iface.LectureWrite;
import org.openslx.bwlp.thrift.iface.UserInfo;
import org.openslx.dozmod.gui.Gui;
import org.openslx.dozmod.gui.MainWindow;
+import org.openslx.dozmod.gui.control.JCheckBoxTree;
import org.openslx.dozmod.gui.helper.DateTimeHelper;
import org.openslx.dozmod.gui.helper.MessageType;
import org.openslx.dozmod.gui.helper.TextChangeListener;
@@ -49,6 +50,7 @@ import org.openslx.dozmod.thrift.ThriftActions;
import org.openslx.dozmod.thrift.ThriftActions.DownloadCallback;
import org.openslx.dozmod.thrift.ThriftActions.LectureMetaCallback;
import org.openslx.dozmod.thrift.ThriftError;
+import org.openslx.dozmod.thrift.cache.MetaDataCache;
import org.openslx.dozmod.thrift.cache.UserCache;
import org.openslx.dozmod.util.FormatHelper;
import org.openslx.dozmod.util.MapHelper;
@@ -201,15 +203,19 @@ public class LectureDetailsWindow extends LectureDetailsWindowLayout implements
btnLocations.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
- locationInfo = LocationSelectionWindow.open(me, lecture.locationIds, lecture.limitToLocations);
- if (locationInfo == null) {
+ LocationInfo ret = LocationSelectionWindow.open(me, locationInfo.locationList, locationInfo.limitToLocations);
+ if (ret == null) {
// nothing changed
return;
}
- LOGGER.debug("New location info: " + locationInfo);
+ // TODO check size of returns
+ locationInfo = ret;
reactToChange();
}
});
+ if (MetaDataCache.getLocations() == null)
+ btnLocations.setVisible(false);
+
btnSaveChanges.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
@@ -288,6 +294,7 @@ public class LectureDetailsWindow extends LectureDetailsWindowLayout implements
if (lecture != null) {
customPermissions = ThriftActions.getLecturePermissions(
JOptionPane.getFrameForComponent(me), lecture.lectureId);
+ locationInfo = new LocationInfo(lecture.locationIds, lecture.limitToLocations);
}
}
fillDetails();
@@ -632,6 +639,8 @@ public class LectureDetailsWindow extends LectureDetailsWindowLayout implements
txtTitle.setEditable(editable);
txtDescription.setEditable(editable);
btnLinkImage.setEnabled(editable);
+ if (MetaDataCache.getLocations() == null)
+ btnLocations.setEnabled(editable);
//TODO Temporarily disabled until implemented
chkIsExam.setEnabled(false);
diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/LocationSelectionWindow.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/LocationSelectionWindow.java
index adc48cda..ce308d90 100644
--- a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/LocationSelectionWindow.java
+++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/LocationSelectionWindow.java
@@ -8,8 +8,11 @@ import java.util.List;
import org.apache.log4j.Logger;
import org.openslx.dozmod.gui.Gui;
import org.openslx.dozmod.gui.Gui.GuiCallable;
+import org.openslx.dozmod.gui.control.JCheckBoxTree.CheckChangeEvent;
+import org.openslx.dozmod.gui.control.JCheckBoxTree.CheckChangeEventListener;
import org.openslx.dozmod.gui.helper.UiFeedback;
import org.openslx.dozmod.gui.window.layout.LocationSelectionWindowLayout;
+import org.openslx.dozmod.thrift.Session;
/**
* Minimal window containing a LocationSelector widget
@@ -20,6 +23,10 @@ import org.openslx.dozmod.gui.window.layout.LocationSelectionWindowLayout;
public class LocationSelectionWindow extends LocationSelectionWindowLayout
implements UiFeedback {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -5898656786160024212L;
private static final Logger LOGGER = Logger
.getLogger(LocationSelectionWindow.class);
private boolean apply = false;
@@ -52,6 +59,26 @@ public class LocationSelectionWindow extends LocationSelectionWindowLayout
dispose();
}
});
+
+
+ // addCheckChangeEventListener
+ locationSelector.getTree().addCheckChangeEventListener(new CheckChangeEventListener() {
+ @Override
+ public void checkStateChanged(CheckChangeEvent event) {
+ List<Integer> tempIntList = locationSelector.getSelectedLocationsAsIds();
+ if (tempIntList != null) {
+ if (tempIntList.size() > Session.getSatelliteConfig().maxLocationsPerLecture) {
+ // add error
+ btnSaveChanges.setEnabled(false);
+ lblError.setText("Zu viele Orte ausgewählt!");
+ } else {
+ btnSaveChanges.setEnabled(true);
+ lblError.setText("");
+ }
+ }
+ }
+ });
+
// btnSaveChanges.setEnabled(false);
Gui.centerShellOverShell(modalParent, this);
}
diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/layout/LocationSelectionWindowLayout.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/layout/LocationSelectionWindowLayout.java
index 47ac1691..3a3b8a5b 100644
--- a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/layout/LocationSelectionWindowLayout.java
+++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/layout/LocationSelectionWindowLayout.java
@@ -1,7 +1,7 @@
package org.openslx.dozmod.gui.window.layout;
+import java.awt.Color;
import java.awt.Window;
-import java.awt.Dialog.ModalityType;
import java.util.List;
import javax.swing.BorderFactory;
@@ -9,6 +9,7 @@ import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
+import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSeparator;
@@ -19,9 +20,14 @@ import org.openslx.dozmod.gui.helper.GridManager;
public class LocationSelectionWindowLayout extends JDialog {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -7722131149214063979L;
protected LocationSelector locationSelector;
protected JButton btnSaveChanges;
protected JButton btnClose;
+ protected JLabel lblError;
public LocationSelectionWindowLayout(Window modalParent,
List<Integer> locationList, boolean limitToLocations) {
@@ -43,14 +49,17 @@ public class LocationSelectionWindowLayout extends JDialog {
// button panel on the bottom
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
+ lblError = new JLabel();
+ lblError.setForeground(Color.red);
btnClose = new JButton("Abbrechen");
btnSaveChanges = new JButton("Übernehmen");
+ buttonPanel.add(lblError);
buttonPanel.add(Box.createHorizontalGlue());
buttonPanel.add(btnClose);
buttonPanel.add(btnSaveChanges);
grid.add(buttonPanel).fill(true, false).expand(true, false);
grid.finish(false);
- setPreferredSize(Gui.getScaledDimension(600, 350));
+ setPreferredSize(Gui.getScaledDimension(600, 600));
pack();
Gui.centerShellOverShell(modalParent, this);
}
diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/wizard/page/LectureLocationSelectionPage.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/wizard/page/LectureLocationSelectionPage.java
index e02f2829..40e1110c 100644
--- a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/wizard/page/LectureLocationSelectionPage.java
+++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/wizard/page/LectureLocationSelectionPage.java
@@ -35,24 +35,24 @@ public class LectureLocationSelectionPage extends LectureLocationSelectionPageLa
}
private boolean updateState() {
- DefaultListModel<Location> selectedLocationModel = locationSelector.getSelectedLocationModel();
- if (selectedLocationModel != null && selectedLocationModel.elements() != null) {
- // prepare the final list
- if (state.locations == null) {
- state.locations = new ArrayList<Integer>();
- } else {
- state.locations.clear();
- }
- List<Location> selectedLocationList = Collections.list(selectedLocationModel.elements());
- for (Location loc : selectedLocationList) {
- state.locations.add(loc.getLocationId());
- }
- // check the state of the checkbox only if we have a selection
- state.onlyInSelectedLocations = locationSelector.getOnlyInSelection();
- } else {
- // allow empty location selection?
- return false;
- }
+// DefaultListModel<Location> selectedLocationModel = locationSelector.getSelectedLocationModel();
+// if (selectedLocationModel != null && selectedLocationModel.elements() != null) {
+// // prepare the final list
+// if (state.locations == null) {
+// state.locations = new ArrayList<Integer>();
+// } else {
+// state.locations.clear();
+// }
+// List<Location> selectedLocationList = Collections.list(selectedLocationModel.elements());
+// for (Location loc : selectedLocationList) {
+// state.locations.add(loc.getLocationId());
+// }
+// // check the state of the checkbox only if we have a selection
+// state.onlyInSelectedLocations = locationSelector.getOnlyInSelection();
+// } else {
+// // allow empty location selection?
+// return false;
+// }
return true;
}
}
diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/util/FormatHelper.java b/dozentenmodul/src/main/java/org/openslx/dozmod/util/FormatHelper.java
index 5594be6a..34108eaa 100644
--- a/dozentenmodul/src/main/java/org/openslx/dozmod/util/FormatHelper.java
+++ b/dozentenmodul/src/main/java/org/openslx/dozmod/util/FormatHelper.java
@@ -9,6 +9,7 @@ import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.PeriodFormat;
import org.joda.time.format.PeriodFormatter;
+import org.openslx.bwlp.thrift.iface.Location;
import org.openslx.bwlp.thrift.iface.OperatingSystem;
import org.openslx.bwlp.thrift.iface.UserInfo;
@@ -149,4 +150,16 @@ public class FormatHelper {
}
return "-"; // Error
}
+
+ /**
+ * Format the given OS's name.
+ *
+ * @param OS a {@link OperatingSystem} instance
+ * @return "LastName, FirstName"
+ */
+ public static String locName(Location location) {
+ if (location == null)
+ return "Unknown";
+ return location.getLocationName();
+ }
}