001: /*--------------------------------------------------------------------------*
002: | Copyright (C) 2006 Christopher Kohlhaas |
003: | |
004: | This program is free software; you can redistribute it and/or modify |
005: | it under the terms of the GNU General Public License as published by the |
006: | Free Software Foundation. A copy of the license has been included with |
007: | these distribution in the COPYING file, if not go to www.fsf.org |
008: | |
009: | As a special exception, you are granted the permissions to link this |
010: | program with every library, which license fulfills the Open Source |
011: | Definition as published by the Open Source Initiative (OSI). |
012: *--------------------------------------------------------------------------*/
013: package org.rapla.gui.internal.edit.reservation;
014:
015: import java.awt.Component;
016: import java.awt.Container;
017: import java.awt.Point;
018: import java.util.ArrayList;
019: import java.util.Arrays;
020: import java.util.Collection;
021: import java.util.Date;
022: import java.util.HashSet;
023: import java.util.Iterator;
024:
025: import javax.swing.BorderFactory;
026: import javax.swing.JComponent;
027: import javax.swing.JLabel;
028: import javax.swing.JPanel;
029: import javax.swing.table.TableColumn;
030:
031: import org.rapla.components.layout.TableLayout;
032: import org.rapla.components.util.Command;
033: import org.rapla.entities.EntityNotFoundException;
034: import org.rapla.entities.domain.Allocatable;
035: import org.rapla.entities.domain.Appointment;
036: import org.rapla.entities.domain.Reservation;
037: import org.rapla.facade.Conflict;
038: import org.rapla.facade.ModificationEvent;
039: import org.rapla.facade.ModificationListener;
040: import org.rapla.facade.ModificationModule;
041: import org.rapla.framework.RaplaContext;
042: import org.rapla.framework.RaplaException;
043: import org.rapla.gui.RaplaGUIComponent;
044: import org.rapla.gui.ReservationController;
045: import org.rapla.gui.ReservationEdit;
046: import org.rapla.gui.internal.view.ConflictInfoOldUI;
047: import org.rapla.gui.toolkit.DialogUI;
048:
049: public class ReservationControllerImpl extends RaplaGUIComponent
050: implements ModificationListener, ReservationController {
051: /** We store all open ReservationEditWindows with their reservationId
052: * in a map, to lookup if the reservation is already beeing edited.
053: That prevents editing the same Reservation in different windows
054: */
055: Collection editWindowList = new ArrayList();
056:
057: public ReservationControllerImpl(RaplaContext sm)
058: throws RaplaException {
059: super (sm);
060: getUpdateModule().addModificationListener(this );
061: }
062:
063: void addReservationEdit(ReservationEdit editWindow) {
064: editWindowList.add(editWindow);
065: }
066:
067: void removeReservationEdit(ReservationEdit editWindow) {
068: editWindowList.remove(editWindow);
069: }
070:
071: public void edit(Reservation reservation) throws RaplaException {
072: startEdit(reservation, null);
073: }
074:
075: public void edit(Appointment appointment) throws RaplaException {
076: startEdit(appointment.getReservation(), appointment);
077: }
078:
079: public ReservationEdit[] getEditWindows() {
080: return (ReservationEdit[]) editWindowList
081: .toArray(new ReservationEdit[] {});
082: }
083:
084: private ReservationEditImpl newEditWindow() throws RaplaException {
085: ReservationEditImpl c = new ReservationEditImpl(getContext());
086: return c;
087: }
088:
089: private ReservationEdit startEdit(Reservation reservation,
090: Appointment appointment) throws RaplaException {
091: // Lookup if the reservation is already beeing edited
092: ReservationEditImpl c = null;
093: Iterator it = editWindowList.iterator();
094: while (it.hasNext()) {
095: c = (ReservationEditImpl) it.next();
096: if (c.getReservation().isIdentical(reservation))
097: break;
098: else
099: c = null;
100: }
101:
102: if (c != null) {
103: c.frame.requestFocus();
104: c.frame.toFront();
105: } else {
106: c = newEditWindow();
107: ModificationModule mod = getModification();
108: boolean bNew = false;
109: if (reservation.isPersistant()) {
110: reservation = (Reservation) mod.edit(reservation);
111: } else {
112: try {
113: getModification().getPersistant(reservation);
114: } catch (EntityNotFoundException ex) {
115: bNew = true;
116: }
117: }
118: // only is allowed to exchange allocations
119: c.editReservation(reservation, appointment, bNew);
120: if (!canModify(reservation)) {
121: c.deleteButton.setEnabled(false);
122: disableComponentAndAllChildren(((ReservationEditImpl) c).appointmentEdit
123: .getComponent());
124: disableComponentAndAllChildren(((ReservationEditImpl) c).reservationInfo
125: .getComponent());
126: }
127: }
128: return c;
129: }
130:
131: static void disableComponentAndAllChildren(Container component) {
132: component.setEnabled(false);
133: Component[] components = component.getComponents();
134: for (int i = 0; i < components.length; i++) {
135: if (components[i] instanceof Container) {
136: disableComponentAndAllChildren((Container) components[i]);
137: }
138: }
139: }
140:
141: public void deleteAppointment(Appointment appointment, Date from,
142: Component sourceComponent, Point point)
143: throws RaplaException {
144: Reservation reservation = appointment.getReservation();
145: Reservation mutableReservation = (Reservation) getModification()
146: .edit(reservation);
147: Appointment app = mutableReservation
148: .findAppointment(appointment);
149:
150: if (app.getRepeating() != null) {
151: String dateString = getRaplaLocale().formatDate(from);
152: DialogUI dialog = DialogUI.create(getContext(),
153: sourceComponent, true, getString("delete"),
154: getI18n().format("delete_appointment.format",
155: dateString), new String[] {
156: getString("serie"),
157: getString("single_appointment"),
158: getString("cancel") });
159: dialog.setIcon(getIcon("icon.question"));
160: dialog.getButton(0).setIcon(getIcon("icon.repeating"));
161: dialog.getButton(2).setIcon(getIcon("icon.cancel"));
162: dialog.start(point);
163: int index = dialog.getSelectedIndex();
164: if (index == 2)
165: return;
166: if (index == 1) {
167: app.getRepeating().addException(from);
168: save(mutableReservation, sourceComponent);
169: return;
170: }
171: if (mutableReservation.getAppointments().length == 1) {
172: getModification().remove(mutableReservation);
173: return;
174: }
175: }
176:
177: // remove appointment if there are other appointments in the reservation
178: if (mutableReservation.getAppointments().length > 1) {
179: // remove all allocatables that are restricted to the removed appointment
180: Allocatable[] allocatables = mutableReservation
181: .getAllocatables();
182: for (int i = 0; i < allocatables.length; i++) {
183: Appointment[] restriction = mutableReservation
184: .getRestriction(allocatables[i]);
185: if (restriction.length == 1
186: && restriction[0].equals(app))
187: mutableReservation
188: .removeAllocatable(allocatables[i]);
189: }
190: mutableReservation.removeAppointment(app);
191: getModification().store(mutableReservation);
192: } else {
193: try {
194: DialogUI dlg = getInfoFactory().createDeleteDialog(
195: new Object[] { mutableReservation },
196: sourceComponent);
197: dlg.start();
198: if (dlg.getSelectedIndex() == 0)
199: getModification().remove(mutableReservation);
200: } catch (RaplaException ex) {
201: showException(ex, sourceComponent);
202: }
203: } // end of else
204: }
205:
206: public Appointment copyAppointment(Appointment appointment)
207: throws RaplaException {
208: return (Appointment) getModification().clone(appointment);
209: }
210:
211: public Appointment copyAppointment(Appointment appointment,
212: Date from, Component sourceComponent, Point point)
213: throws RaplaException {
214: Reservation reservation = appointment.getReservation();
215: getLogger().info(
216: "copy appointment '" + appointment
217: + "' for reservation '" + reservation + "'");
218: Appointment copy = copyAppointment(appointment);
219: if (appointment.getRepeating() != null) {
220: String dateString = getRaplaLocale().formatDate(from);
221: DialogUI dialog = DialogUI.create(getContext(),
222: sourceComponent, true, getString("copy"), getI18n()
223: .format("copy_appointment.format",
224: dateString), new String[] {
225: getString("serie"),
226: getString("single_appointment") });
227: dialog.setIcon(getIcon("icon.question"));
228: dialog.getButton(0).setIcon(getIcon("icon.repeating"));
229: dialog.start(point);
230: int index = dialog.getSelectedIndex();
231: if (index == 1) {
232: copy.setRepeatingEnabled(false);
233: copy.move(from);
234: }
235: }
236:
237: return copy;
238: }
239:
240: public void dataChanged(ModificationEvent evt)
241: throws RaplaException {
242: Iterator it = editWindowList.iterator();
243:
244: while (it.hasNext()) {
245: ReservationEditImpl c = (ReservationEditImpl) it.next();
246: c.refresh(evt);
247:
248: if (evt.hasChanged(c.getReservation())) {
249: Iterator it2 = evt.getChanged().iterator();
250: Reservation updatedReservation = null;
251:
252: while (it2.hasNext()) {
253: Object obj = it2.next();
254: if (!(obj instanceof Reservation)) {
255: continue;
256: }
257: Reservation newReservation = (Reservation) obj;
258: if (newReservation.isIdentical(c.getReservation())) {
259: updatedReservation = newReservation;
260: break;
261: }
262: }
263: if (updatedReservation != null) {
264: c.updateReservation(updatedReservation);
265: } else {
266: c.closeWindow();
267: }
268:
269: } else if (evt.isRemoved(c.getReservation())) {
270: c.deleteReservation();
271: }
272: }
273: }
274:
275: private void setRestrictions(Appointment appointment,
276: Allocatable[] restrictedAllocatables,
277: Reservation reservation) {
278: for (int i = 0; i < restrictedAllocatables.length; i++) {
279: Allocatable allocatable = restrictedAllocatables[i];
280: Appointment[] restriction = reservation
281: .getRestriction(allocatable);
282: HashSet newRestriction = new HashSet(Arrays
283: .asList(restriction));
284: newRestriction.add(appointment);
285: reservation.setRestriction(allocatable,
286: (Appointment[]) newRestriction
287: .toArray(Appointment.EMPTY_ARRAY));
288: }
289: }
290:
291: public void pasteAppointment(Appointment appointment,
292: Reservation reservation, Date start,
293: Component sourceComponent, Point point,
294: Allocatable[] restrictedAllocatables,
295: boolean asNewReservation) throws RaplaException {
296: Appointment copy = copyAppointment(appointment);
297: copy.move(start);
298: Reservation mutableReservation;
299: if (asNewReservation) {
300: mutableReservation = (Reservation) getModification().clone(
301: reservation);
302: Appointment[] appointments = mutableReservation
303: .getAppointments();
304: for (int i = 0; i < appointments.length; i++) {
305: Appointment app = appointments[i];
306: mutableReservation.removeAppointment(app);
307: }
308: } else {
309: mutableReservation = (Reservation) getModification().edit(
310: reservation);
311: }
312: mutableReservation.addAppointment(copy);
313: setRestrictions(copy, restrictedAllocatables,
314: mutableReservation);
315:
316: getLogger().info(
317: "Paste appointment '" + appointment
318: + "' for reservation '" + mutableReservation
319: + "' at " + start);
320:
321: save(mutableReservation, sourceComponent);
322: }
323:
324: public void moveAppointment(Appointment appointment, Date from,
325: Date newStart, Component sourceComponent, Point p)
326: throws RaplaException {
327: if (newStart.equals(from))
328: return;
329: getLogger().info(
330: "Moving appointment " + appointment + " from " + from
331: + " to " + newStart);
332: resizeAppointment(appointment, from, newStart, null,
333: sourceComponent, p);
334: }
335:
336: public void resizeAppointment(Appointment appointment, Date from,
337: Date newStart, Date newEnd, Component sourceComponent,
338: Point p) throws RaplaException {
339: boolean resizing = newEnd != null;
340: long start = appointment.getStart().getTime();
341: //boolean resizeFirstDay = !resizing || DateTools.isSameDay( start, newStart.getTime() );
342: Reservation reservation = appointment.getReservation();
343: Appointment copy = null;
344: boolean moveSerie = true;
345: if (appointment.getRepeating() != null) {
346: String dateString = getRaplaLocale().formatDate(from);
347: DialogUI dialog = DialogUI.create(getContext(),
348: sourceComponent, true, getString("move"), getI18n()
349: .format("move_appointment.format",
350: dateString), new String[] {
351: getString("serie"),
352: getString("single_appointment"),
353: getString("cancel") });
354: dialog.setIcon(getIcon("icon.question"));
355: dialog.getButton(0).setIcon(getIcon("icon.repeating"));
356: dialog.getButton(2).setIcon(getIcon("icon.cancel"));
357: dialog.setDefault(0);
358: dialog.start(p);
359: int index = dialog.getSelectedIndex();
360: if (index == 2 || index == -1)
361: return;
362: if (index == 1) {
363: moveSerie = false;
364: copy = copyAppointment(appointment);
365: copy.setRepeatingEnabled(false);
366: if (resizing) {
367: copy.move(newStart, newEnd);
368: } else {
369: copy.move(newStart);
370: }
371: }
372: }
373: Reservation mutableReservation = (Reservation) getModification()
374: .edit(reservation);
375: Appointment app = mutableReservation
376: .findAppointment(appointment);
377: if (app == null) {
378: getLogger().warn("Can't find the appointment!");
379: return;
380: }
381: // Move the complete serie
382: if (moveSerie) {
383: // we adjust the start end end-time of the first appointment relative to the next from time
384: if (resizing) {
385: newStart = new Date((start - from.getTime())
386: + newStart.getTime());
387: newEnd = new Date((start - from.getTime())
388: + newEnd.getTime());
389: app.move(newStart, newEnd);
390: } else {
391: newStart = new Date((start - from.getTime())
392: + newStart.getTime());
393: app.move(newStart);
394: }
395: } else {
396: mutableReservation.addAppointment(copy);
397: setRestrictions(copy, mutableReservation
398: .getRestrictedAllocatables(app), mutableReservation);
399: app.getRepeating().addException(from);
400: }
401: save(mutableReservation, sourceComponent);
402: }
403:
404: public boolean save(Reservation reservation,
405: Component sourceComponent, boolean showOnlyWhenConflicts)
406: throws RaplaException {
407: SaveCommand saveCommand = new SaveCommand(reservation);
408: save(reservation, sourceComponent, saveCommand,
409: showOnlyWhenConflicts);
410: return saveCommand.hasSaved();
411: }
412:
413: boolean save(Reservation reservation, Component sourceComponent)
414: throws RaplaException {
415: return save(reservation, sourceComponent, true);
416: }
417:
418: void save(Reservation reservation, Component sourceComponent,
419: Command saveCommand, boolean showOnlyWhenConflicts)
420: throws RaplaException {
421: Conflict[] conflicts = getQuery().getConflicts(reservation);
422: getModification().checkReservation(reservation);
423:
424: // Only show when conflicts are found ?
425: if (conflicts.length == 0 && showOnlyWhenConflicts) {
426: try {
427: saveCommand.execute();
428: } catch (Exception ex) {
429: showException(ex, sourceComponent);
430: }
431: return;
432: }
433:
434: Appointment[] appointments = reservation.getAppointments();
435: Appointment duplicatedAppointment = null;
436: for (int i = 0; i < appointments.length; i++) {
437: for (int j = i + 1; j < appointments.length; j++)
438: if (appointments[i].matches(appointments[j])) {
439: duplicatedAppointment = appointments[i];
440: break;
441: }
442: }
443:
444: JComponent infoComponent = getInfoFactory()
445: .createInfoComponent(reservation);
446: JPanel content = new JPanel();
447: content.setBorder(BorderFactory.createTitledBorder(
448: BorderFactory.createEmptyBorder(),
449: getString("confirm.dialog.question")));
450: content
451: .setLayout(new TableLayout(new double[][] {
452: { TableLayout.FILL },
453: { TableLayout.PREFERRED, TableLayout.PREFERRED,
454: TableLayout.PREFERRED, 2,
455: TableLayout.FILL } }));
456: if (duplicatedAppointment != null) {
457: JLabel warningLabel = new JLabel();
458: warningLabel.setForeground(java.awt.Color.red);
459: warningLabel.setText(getI18n().format(
460: "warning.duplicated_appointments",
461: getAppointmentFormater().getShortSummary(
462: duplicatedAppointment)));
463: content.add(warningLabel, "0,0");
464: }
465: if (conflicts.length > 0) {
466: JLabel warningLabel = new JLabel();
467: warningLabel.setText(getString("warning.conflict"));
468: warningLabel.setForeground(java.awt.Color.red);
469: content.add(warningLabel, "0,1");
470: content.add(getConflictPanel(conflicts), "0,2");
471: }
472: content.add(infoComponent, "0,4");
473: DialogUI dialog = DialogUI.create(getContext(),
474: sourceComponent, true, content, new String[] {
475: getString("save"), getString("back") });
476:
477: if (conflicts.length > 0)
478: dialog.setDefault(1);
479: dialog.getButton(0).setIcon(getIcon("icon.save"));
480: dialog.getButton(1).setIcon(getIcon("icon.cancel"));
481: dialog.setTitle(getI18n().format("confirm.dialog.title",
482: getName(reservation)));
483: dialog.start();
484: if (dialog.getSelectedIndex() == 0) {
485: try {
486: saveCommand.execute();
487: } catch (Exception ex) {
488: showException(ex, sourceComponent);
489: return;
490: }
491: }
492: }
493:
494: class SaveCommand implements Command {
495: Reservation reservation;
496: boolean saved;
497:
498: public SaveCommand(Reservation reservation) {
499: this .reservation = reservation;
500: }
501:
502: public void execute() throws RaplaException {
503: getModification().store(reservation);
504: saved = true;
505: }
506:
507: public boolean hasSaved() {
508: return saved;
509: }
510: }
511:
512: private JComponent getConflictPanel(Conflict[] conflicts)
513: throws RaplaException {
514: ConflictInfoOldUI panel = new ConflictInfoOldUI();
515: ConflictTableModel model = new ConflictTableModel(getContext(),
516: conflicts);
517: panel.getTable().setModel(model);
518: TableColumn column = panel.getTable().getColumn(
519: getString("conflict.appointment2"));
520: panel.getTable().removeColumn(column);
521: column = panel.getTable().getColumn(
522: getString("conflict.reservation1"));
523: panel.getTable().removeColumn(column);
524: return panel.getComponent();
525: }
526:
527: }
|