@Override
    public void propertyChange(PropertyChangeEvent evt) {
      String propName = evt.getPropertyName();
      if (Task.COMPLETED_PROP.equals(propName)) {
        Task task = (Task) evt.getSource();
        List<Task> oldTasks, newTasks;
        synchronized (tasks) {
          oldTasks = new ArrayList<Task>(tasks);
          tasks.remove(task);
          // remove all the children tasks too
          TaskManager.this.cancelTasksByOwner(task);
          newTasks = new ArrayList<Task>(tasks);
          task.removePropertyChangeListener(taskPropListener);
        }
        firePropertyChange(REMOVE_TASK_PROP, oldTasks, newTasks);

        // unblock gui
        GUIBlocker blocker = task.getGUIBlocker();
        if (blocker != null) blocker.unblock();
      }
    }
  /**
   * Add a new task to the task manager, you can choose whether to notify the task manager
   * listeners, for example, if false, the status bar will not change.
   *
   * @param task new task
   * @param notify choose whether to notify
   */
  public void addTask(Task task, boolean notify) {
    // add task the task list
    List<Task> oldTasks, newTasks;
    synchronized (tasks) {
      oldTasks = new ArrayList<Task>(tasks);
      tasks.add(task);
      newTasks = new ArrayList<Task>(tasks);
      task.addPropertyChangeListener(taskPropListener);
    }

    // notify the status bar
    if (notify) {
      firePropertyChange(ADD_TASK_PROP, oldTasks, newTasks);
    }

    // block gui
    // ToDo: this might need a separate thread
    GUIBlocker blocker = task.getGUIBlocker();
    if (blocker != null) blocker.block();

    // execute the task
    executor.execute(task);
  }