Ejemplo n.º 1
0
    @CalledInAwt
    public void run() {
      myRemainingPatches.addAll(myPatches);

      final ApplyPatchStatus patchStatus = nonWriteActionPreCheck();
      final Label beforeLabel =
          LocalHistory.getInstance().putSystemLabel(myProject, "Before patch");
      final TriggerAdditionOrDeletion trigger = new TriggerAdditionOrDeletion(myProject);
      final ApplyPatchStatus applyStatus = getApplyPatchStatus(trigger);
      myStatus =
          ApplyPatchStatus.SUCCESS.equals(patchStatus)
              ? applyStatus
              : ApplyPatchStatus.and(patchStatus, applyStatus);
      // listeners finished, all 'legal' file additions/deletions with VCS are done
      trigger.processIt();
      LocalHistory.getInstance()
          .putSystemLabel(
              myProject, "After patch"); // insert a label to be visible in local history dialog
      if (myStatus == ApplyPatchStatus.FAILURE) {
        suggestRollback(myProject, Collections.singletonList(PatchApplier.this), beforeLabel);
      } else if (myStatus == ApplyPatchStatus.ABORT) {
        rollbackUnderProgress(myProject, myProject.getBaseDir(), beforeLabel);
      }
      if (myShowNotification || !ApplyPatchStatus.SUCCESS.equals(myStatus)) {
        showApplyStatus(myProject, myStatus);
      }
      refreshFiles(trigger.getAffected());
    }
 private static List<Change> filterDirectoryAndBinaryChanges(final Change[] changes) {
   final ArrayList<Change> changesList = new ArrayList<Change>();
   Collections.addAll(changesList, changes);
   for (int i = changesList.size() - 1; i >= 0; i--) {
     final Change change = changesList.get(i);
     if (directoryOrBinary(change)) {
       changesList.remove(i);
     }
   }
   return changesList;
 }
  public void initComponent() {
    if (!ApplicationManager.getApplication().isUnitTestMode()) {
      myCacheRefreshTimer =
          UIUtil.createNamedTimer(
              "TaskManager refresh",
              myConfig.updateInterval * 60 * 1000,
              new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                  if (myConfig.updateEnabled && !myUpdating) {
                    updateIssues(null);
                  }
                }
              });
      myCacheRefreshTimer.setInitialDelay(0);
      StartupManager.getInstance(myProject)
          .registerPostStartupActivity(
              new Runnable() {
                public void run() {
                  myCacheRefreshTimer.start();
                }
              });
    }

    // make sure that the default task is exist
    LocalTask defaultTask = findTask(LocalTaskImpl.DEFAULT_TASK_ID);
    if (defaultTask == null) {
      defaultTask = createDefaultTask();
      addTask(defaultTask);
    }

    // search for active task
    LocalTask activeTask = null;
    final List<LocalTask> tasks = getLocalTasks();
    Collections.sort(tasks, TASK_UPDATE_COMPARATOR);
    for (LocalTask task : tasks) {
      if (activeTask == null) {
        if (task.isActive()) {
          activeTask = task;
        }
      } else {
        task.setActive(false);
      }
    }
    if (activeTask == null) {
      activeTask = defaultTask;
    }

    myActiveTask = activeTask;
    doActivate(myActiveTask, false);
    myDispatcher.getMulticaster().taskActivated(myActiveTask);
  }
 @Override
 public LocalTask put(String key, LocalTask task) {
   LocalTask result = super.put(key, task);
   if (size() > myConfig.taskHistoryLength) {
     ArrayList<LocalTask> list = new ArrayList<LocalTask>(values());
     Collections.sort(list, TASK_UPDATE_COMPARATOR);
     for (LocalTask oldest : list) {
       if (!oldest.isDefault()) {
         remove(oldest);
         break;
       }
     }
   }
   return result;
 }
 @Override
 public void run(ContinuationContext context) {
   final ChangeListManager clManager = ChangeListManager.getInstance(myVcs.getProject());
   final LocalChangeList changeList = clManager.getChangeList(myChange);
   final ApplyPatchDifferentiatedDialog dialog =
       new ApplyPatchDifferentiatedDialog(
           myVcs.getProject(),
           new TreeConflictApplyTheirsPatchExecutor(myVcs, context, myBaseForPatch),
           Collections.<ApplyPatchExecutor>singletonList(
               new ApplyPatchSaveToFileExecutor(myVcs.getProject(), myBaseForPatch)),
           ApplyPatchMode.APPLY_PATCH_IN_MEMORY,
           myTextPatches,
           changeList);
   context.suspend();
   dialog.show();
 }
  public MergeFromTheirsResolver(
      SvnVcs vcs, TreeConflictDescription description, Change change, SvnRevisionNumber revision) {
    myVcs = vcs;
    myDescription = description;
    myChange = change;
    myCommittedRevision = revision;
    myOldFilePath = myChange.getBeforeRevision().getFile();
    myNewFilePath = myChange.getAfterRevision().getFile();
    myBaseForPatch = ChangesUtil.findValidParentAccurately(myNewFilePath);
    myOldPresentation = TreeConflictRefreshablePanel.filePath(myOldFilePath);
    myNewPresentation = TreeConflictRefreshablePanel.filePath(myNewFilePath);

    myTheirsChanges = new ArrayList<Change>();
    myTheirsBinaryChanges = new ArrayList<Change>();
    myWarnings = new ArrayList<VcsException>();
    myTextPatches = Collections.emptyList();
  }
    GitCheckinOptions(@NotNull final Project project, @NotNull CheckinProjectPanel panel) {
      super(project, panel);
      myVcs = GitVcs.getInstance(project);
      final Insets insets = new Insets(2, 2, 2, 2);
      // add authors drop down
      GridBagConstraints c = new GridBagConstraints();
      c.gridx = 0;
      c.gridy = 0;
      c.anchor = GridBagConstraints.WEST;
      c.insets = insets;
      final JLabel authorLabel = new JLabel(GitBundle.message("commit.author"));
      myPanel.add(authorLabel, c);

      c = new GridBagConstraints();
      c.anchor = GridBagConstraints.CENTER;
      c.insets = insets;
      c.gridx = 1;
      c.gridy = 0;
      c.weightx = 1;
      c.fill = GridBagConstraints.HORIZONTAL;
      final List<String> usersList = getUsersList(project);
      final Set<String> authors =
          usersList == null ? new HashSet<String>() : new HashSet<String>(usersList);
      ContainerUtil.addAll(authors, mySettings.getCommitAuthors());
      List<String> list = new ArrayList<String>(authors);
      Collections.sort(list);
      list =
          ObjectsConvertor.convert(
              list,
              new Convertor<String, String>() {
                @Override
                public String convert(String o) {
                  return StringUtil.shortenTextWithEllipsis(o, 30, 0);
                }
              });
      myAuthor = new ComboBox(ArrayUtil.toObjectArray(list));
      myAuthor.insertItemAt("", 0);
      myAuthor.setSelectedItem("");
      myAuthor.setEditable(true);
      authorLabel.setLabelFor(myAuthor);
      myAuthor.setToolTipText(GitBundle.getString("commit.author.tooltip"));
      myPanel.add(myAuthor, c);
    }
  @NotNull
  protected ChangesSelection getChangesSelection() {
    final Change leadSelection = ObjectUtils.tryCast(myViewer.getLeadSelection(), Change.class);
    List<Change> changes = getSelectedChanges();

    if (changes.size() < 2) {
      List<Change> allChanges = getAllChanges();
      if (allChanges.size() > 1 || changes.isEmpty()) {
        changes = allChanges;
      }
    }

    if (leadSelection != null) {
      int indexInSelection = changes.indexOf(leadSelection);
      if (indexInSelection == -1) {
        return new ChangesSelection(Collections.singletonList(leadSelection), 0);
      } else {
        return new ChangesSelection(changes, indexInSelection);
      }
    } else {
      return new ChangesSelection(changes, 0);
    }
  }
 public void actionPerformed(AnActionEvent e) {
   Change change = e.getData(VcsDataKeys.CURRENT_CHANGE);
   askAndMove(myProject, Collections.singletonList(change), null);
 }
Ejemplo n.º 10
0
    @Override
    public void run(ContinuationContext context) {
      final String message;
      final Intersection intersection;
      final ChangeListManager listManager = ChangeListManager.getInstance(myProject);
      final List<LocalChangeList> localChangeLists = listManager.getChangeListsCopy();

      if (myMergeAll) {
        intersection = getMergeAllIntersection(localChangeLists);
        message =
            "There are local changes that can potentially intersect with merge changes.\nDo you want to continue?";
      } else {
        intersection = checkIntersection(myLists, localChangeLists);
        message =
            "There are local changes that will intersect with merge changes.\nDo you want to continue?";
      }
      if (intersection == null || intersection.getChangesSubset().isEmpty()) return;

      final LocalChangesAction action;
      if (!myMergeAll) {
        final LocalChangesAction[] possibleResults = {
          LocalChangesAction.shelve,
          LocalChangesAction.inspect,
          LocalChangesAction.continueMerge,
          LocalChangesAction.cancel
        };
        final int result =
            Messages.showDialog(
                message,
                myTitle,
                new String[] {
                  "Shelve local changes", "Inspect changes", "Continue merge", "Cancel"
                },
                0,
                Messages.getQuestionIcon());
        action = possibleResults[result];
      } else {
        final LocalChangesAction[] possibleResults = {
          LocalChangesAction.shelve, LocalChangesAction.continueMerge, LocalChangesAction.cancel
        };
        final int result =
            Messages.showDialog(
                message,
                myTitle,
                new String[] {"Shelve local changes", "Continue merge", "Cancel"},
                0,
                Messages.getQuestionIcon());
        action = possibleResults[result];
      }
      switch (action) {
          // shelve
        case shelve:
          context.next(new ShelveLocalChanges(intersection));
          return;
          // cancel
        case cancel:
          context.cancelEverything();
          return;
          // continue
        case continueMerge:
          return;
          // inspect
        case inspect:
          final Collection<Change> changes =
              (Collection<Change>) intersection.getChangesSubset().values();
          final List<FilePath> paths = ChangesUtil.getPaths(changes);
          Collections.sort(paths, FilePathByPathComparator.getInstance());
          // todo rework message
          IntersectingLocalChangesPanel.showInVersionControlToolWindow(
              myProject,
              myTitle + ", local changes intersection",
              paths,
              "The following file(s) have local changes that will intersect with merge changes:");
          context.cancelEverything();
          return;
        default:
      }
    }
Ejemplo n.º 11
0
    // "Calculating not merged revisions"
    @Override
    public void run(ContinuationContext context) {
      if (myCopyData == null) {
        finishWithError(context, "Merge start wasn't found", true);
        return;
      }

      final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
      myIsReintegrate = myCopyData.isInvertedSense();
      if (!myWcInfo.getFormat().supportsMergeInfo()) return;
      final SvnBranchPointsCalculator.BranchCopyData data = myCopyData.getTrue();
      final long sourceLatest = data.getTargetRevision();

      final SvnCommittedChangesProvider committedChangesProvider =
          (SvnCommittedChangesProvider) myVcs.getCommittedChangesProvider();
      final ChangeBrowserSettings settings = new ChangeBrowserSettings();
      settings.CHANGE_AFTER = Long.toString(sourceLatest);
      settings.USE_CHANGE_AFTER_FILTER = true;

      String local =
          SVNPathUtil.getRelativePath(myWcInfo.getRepositoryRoot(), myWcInfo.getRootUrl());
      final String relativeLocal = (local.startsWith("/") ? local : "/" + local);

      final LinkedList<Pair<SvnChangeList, TreeStructureNode<SVNLogEntry>>> list =
          new LinkedList<Pair<SvnChangeList, TreeStructureNode<SVNLogEntry>>>();
      try {
        committedChangesProvider.getCommittedChangesWithMergedRevisons(
            settings,
            new SvnRepositoryLocation(mySourceUrl),
            0,
            new PairConsumer<SvnChangeList, TreeStructureNode<SVNLogEntry>>() {
              public void consume(SvnChangeList svnList, TreeStructureNode<SVNLogEntry> tree) {
                indicator.checkCanceled();
                if (sourceLatest >= svnList.getNumber()) return;
                list.add(new Pair<SvnChangeList, TreeStructureNode<SVNLogEntry>>(svnList, tree));
              }
            });
      } catch (VcsException e) {
        finishWithError(
            context, "Checking revisions for merge fault", Collections.singletonList(e));
      }

      indicator.setText("Checking merge information...");
      // to do not go into file system while asking something on the net
      for (Pair<SvnChangeList, TreeStructureNode<SVNLogEntry>> pair : list) {
        final SvnChangeList svnList = pair.getFirst();
        final SvnMergeInfoCache.MergeCheckResult checkResult = myMergeChecker.checkList(svnList);
        indicator.setText2("Processing revision " + svnList.getNumber());

        if (SvnMergeInfoCache.MergeCheckResult.NOT_MERGED.equals(checkResult)) {
          // additionally check for being 'local'
          final List<TreeStructureNode<SVNLogEntry>> children = pair.getSecond().getChildren();
          boolean localChange = false;
          for (TreeStructureNode<SVNLogEntry> child : children) {
            if (isLocalRevisionMergeIteration(child, relativeLocal, indicator)) {
              localChange = true;
              break;
            }
          }

          if (!localChange) {
            myNotMerged.add(svnList);
          }
        }
      }

      if (myNotMerged.isEmpty()) {
        finishWithError(context, "Everything is up-to-date", false);
        return;
      }
      context.next(new ShowRevisionSelector(myCopyData));
    }
 @NotNull
 public List<VirtualFile> getIncludedUnversionedFiles() {
   return Collections.emptyList();
 }
 @NotNull
 public List<Change> getCurrentDisplayedChanges() {
   return mySelectedChangeList != null
       ? ContainerUtil.newArrayList(mySelectedChangeList.getChanges())
       : Collections.emptyList();
 }
/** @author Dmitry Avdeev */
@State(
    name = "TaskManager",
    storages = {@Storage(file = StoragePathMacros.WORKSPACE_FILE)})
public class TaskManagerImpl extends TaskManager
    implements ProjectComponent,
        PersistentStateComponent<TaskManagerImpl.Config>,
        ChangeListDecorator {

  private static final Logger LOG = Logger.getInstance("#com.intellij.tasks.impl.TaskManagerImpl");

  private static final DecimalFormat LOCAL_TASK_ID_FORMAT = new DecimalFormat("LOCAL-00000");
  public static final Comparator<Task> TASK_UPDATE_COMPARATOR =
      new Comparator<Task>() {
        public int compare(Task o1, Task o2) {
          int i = Comparing.compare(o2.getUpdated(), o1.getUpdated());
          return i == 0 ? Comparing.compare(o2.getCreated(), o1.getCreated()) : i;
        }
      };
  private static final Convertor<Task, String> KEY_CONVERTOR =
      new Convertor<Task, String>() {
        @Override
        public String convert(Task o) {
          return o.getId();
        }
      };
  static final String TASKS_NOTIFICATION_GROUP = "Task Group";

  private final Project myProject;

  private final WorkingContextManager myContextManager;

  private final Map<String, Task> myIssueCache =
      Collections.synchronizedMap(new LinkedHashMap<String, Task>());

  private final Map<String, LocalTask> myTasks =
      Collections.synchronizedMap(
          new LinkedHashMap<String, LocalTask>() {
            @Override
            public LocalTask put(String key, LocalTask task) {
              LocalTask result = super.put(key, task);
              if (size() > myConfig.taskHistoryLength) {
                ArrayList<LocalTask> list = new ArrayList<LocalTask>(values());
                Collections.sort(list, TASK_UPDATE_COMPARATOR);
                for (LocalTask oldest : list) {
                  if (!oldest.isDefault()) {
                    remove(oldest);
                    break;
                  }
                }
              }
              return result;
            }
          });

  @NotNull private LocalTask myActiveTask = createDefaultTask();
  private Timer myCacheRefreshTimer;

  private volatile boolean myUpdating;
  private final Config myConfig = new Config();
  private final ChangeListAdapter myChangeListListener;
  private final ChangeListManager myChangeListManager;

  private final List<TaskRepository> myRepositories = new ArrayList<TaskRepository>();
  private final EventDispatcher<TaskListener> myDispatcher =
      EventDispatcher.create(TaskListener.class);
  private Set<TaskRepository> myBadRepositories = new ConcurrentHashSet<TaskRepository>();

  public TaskManagerImpl(
      Project project,
      WorkingContextManager contextManager,
      final ChangeListManager changeListManager) {

    myProject = project;
    myContextManager = contextManager;
    myChangeListManager = changeListManager;

    myChangeListListener =
        new ChangeListAdapter() {
          @Override
          public void changeListRemoved(ChangeList list) {
            LocalTask task = getAssociatedTask((LocalChangeList) list);
            if (task != null) {
              for (ChangeListInfo info : task.getChangeLists()) {
                if (Comparing.equal(info.id, ((LocalChangeList) list).getId())) {
                  info.id = "";
                }
              }
            }
          }

          @Override
          public void defaultListChanged(ChangeList oldDefaultList, ChangeList newDefaultList) {
            final LocalTask associatedTask = getAssociatedTask((LocalChangeList) newDefaultList);
            if (associatedTask != null && !getActiveTask().equals(associatedTask)) {
              ApplicationManager.getApplication()
                  .invokeLater(
                      new Runnable() {
                        public void run() {
                          activateTask(associatedTask, true);
                        }
                      },
                      myProject.getDisposed());
            }
          }
        };
  }

  @Override
  public TaskRepository[] getAllRepositories() {
    return myRepositories.toArray(new TaskRepository[myRepositories.size()]);
  }

  public <T extends TaskRepository> void setRepositories(List<T> repositories) {

    Set<TaskRepository> set = new HashSet<TaskRepository>(myRepositories);
    set.removeAll(repositories);
    myBadRepositories.removeAll(set); // remove all changed reps
    myIssueCache.clear();

    myRepositories.clear();
    myRepositories.addAll(repositories);

    reps:
    for (T repository : repositories) {
      if (repository.isShared() && repository.getUrl() != null) {
        List<TaskProjectConfiguration.SharedServer> servers = getProjectConfiguration().servers;
        TaskRepositoryType type = repository.getRepositoryType();
        for (TaskProjectConfiguration.SharedServer server : servers) {
          if (repository.getUrl().equals(server.url) && type.getName().equals(server.type)) {
            continue reps;
          }
        }
        TaskProjectConfiguration.SharedServer server = new TaskProjectConfiguration.SharedServer();
        server.type = type.getName();
        server.url = repository.getUrl();
        servers.add(server);
      }
    }
  }

  @Override
  public void removeTask(LocalTask task) {
    if (task.isDefault()) return;
    if (myActiveTask.equals(task)) {
      activateTask(myTasks.get(LocalTaskImpl.DEFAULT_TASK_ID), true);
    }
    myTasks.remove(task.getId());
    myDispatcher.getMulticaster().taskRemoved(task);
    myContextManager.removeContext(task);
  }

  @Override
  public void addTaskListener(TaskListener listener) {
    myDispatcher.addListener(listener);
  }

  @Override
  public void removeTaskListener(TaskListener listener) {
    myDispatcher.removeListener(listener);
  }

  @NotNull
  @Override
  public LocalTask getActiveTask() {
    return myActiveTask;
  }

  @Nullable
  @Override
  public LocalTask findTask(String id) {
    return myTasks.get(id);
  }

  @NotNull
  @Override
  public List<Task> getIssues(@Nullable final String query) {
    return getIssues(query, true);
  }

  @Override
  public List<Task> getIssues(@Nullable final String query, final boolean forceRequest) {
    return getIssues(query, 50, 0, forceRequest, true, new EmptyProgressIndicator());
  }

  @Override
  public List<Task> getIssues(
      @Nullable String query,
      int max,
      long since,
      boolean forceRequest,
      final boolean withClosed,
      @NotNull final ProgressIndicator cancelled) {
    List<Task> tasks = getIssuesFromRepositories(query, max, since, forceRequest, cancelled);
    if (tasks == null) return getCachedIssues(withClosed);
    myIssueCache.putAll(ContainerUtil.newMapFromValues(tasks.iterator(), KEY_CONVERTOR));
    return ContainerUtil.filter(
        tasks,
        new Condition<Task>() {
          @Override
          public boolean value(final Task task) {
            return withClosed || !task.isClosed();
          }
        });
  }

  @Override
  public List<Task> getCachedIssues() {
    return getCachedIssues(true);
  }

  @Override
  public List<Task> getCachedIssues(final boolean withClosed) {
    return ContainerUtil.filter(
        myIssueCache.values(),
        new Condition<Task>() {
          @Override
          public boolean value(final Task task) {
            return withClosed || !task.isClosed();
          }
        });
  }

  @Nullable
  @Override
  public Task updateIssue(@NotNull String id) {
    for (TaskRepository repository : getAllRepositories()) {
      if (repository.extractId(id) == null) {
        continue;
      }
      try {
        Task issue = repository.findTask(id);
        if (issue != null) {
          LocalTask localTask = findTask(id);
          if (localTask != null) {
            localTask.updateFromIssue(issue);
            return localTask;
          }
          return issue;
        }
      } catch (Exception e) {
        LOG.info(e);
      }
    }
    return null;
  }

  @Override
  public List<LocalTask> getLocalTasks() {
    return getLocalTasks(true);
  }

  @Override
  public List<LocalTask> getLocalTasks(final boolean withClosed) {
    synchronized (myTasks) {
      return ContainerUtil.filter(
          myTasks.values(),
          new Condition<LocalTask>() {
            @Override
            public boolean value(final LocalTask task) {
              return withClosed || !isLocallyClosed(task);
            }
          });
    }
  }

  @Override
  public LocalTask addTask(Task issue) {
    LocalTaskImpl task =
        issue instanceof LocalTaskImpl ? (LocalTaskImpl) issue : new LocalTaskImpl(issue);
    addTask(task);
    return task;
  }

  @Override
  public LocalTaskImpl createLocalTask(@NotNull String summary) {
    return createTask(LOCAL_TASK_ID_FORMAT.format(myConfig.localTasksCounter++), summary);
  }

  private static LocalTaskImpl createTask(@NotNull String id, @NotNull String summary) {
    LocalTaskImpl task = new LocalTaskImpl(id, summary);
    Date date = new Date();
    task.setCreated(date);
    task.setUpdated(date);
    return task;
  }

  @Override
  public LocalTask activateTask(@NotNull final Task origin, boolean clearContext) {
    LocalTask activeTask = getActiveTask();
    if (origin.equals(activeTask)) return activeTask;

    saveActiveTask();

    if (clearContext) {
      myContextManager.clearContext();
    }
    myContextManager.restoreContext(origin);

    final LocalTask task = doActivate(origin, true);

    return restoreVcsContext(task);
  }

  private LocalTask restoreVcsContext(LocalTask task) {
    if (!isVcsEnabled()) return task;

    List<ChangeListInfo> changeLists = task.getChangeLists();
    if (!changeLists.isEmpty()) {
      ChangeListInfo info = changeLists.get(0);
      LocalChangeList changeList = myChangeListManager.getChangeList(info.id);
      if (changeList == null) {
        changeList = myChangeListManager.addChangeList(info.name, info.comment);
        info.id = changeList.getId();
      }
      myChangeListManager.setDefaultChangeList(changeList);
    }

    List<BranchInfo> branches = task.getBranches(false);
    VcsTaskHandler.TaskInfo info = fromBranches(branches);

    VcsTaskHandler[] handlers = VcsTaskHandler.getAllHandlers(myProject);
    for (VcsTaskHandler handler : handlers) {
      handler.switchToTask(info);
    }
    return task;
  }

  private static VcsTaskHandler.TaskInfo fromBranches(List<BranchInfo> branches) {
    MultiMap<String, String> map = new MultiMap<String, String>();
    for (BranchInfo branch : branches) {
      map.putValue(branch.name, branch.repository);
    }
    return new VcsTaskHandler.TaskInfo(map);
  }

  public void createBranch(LocalTask task, LocalTask previousActive, String name) {
    VcsTaskHandler[] handlers = VcsTaskHandler.getAllHandlers(myProject);
    for (VcsTaskHandler handler : handlers) {
      VcsTaskHandler.TaskInfo info = handler.getActiveTask();
      if (previousActive != null) {
        addBranches(previousActive, info, false);
      }
      addBranches(task, info, true);
      addBranches(task, handler.startNewTask(name), false);
    }
  }

  public void mergeBranch(LocalTask task) {
    VcsTaskHandler.TaskInfo original = fromBranches(task.getBranches(true));
    VcsTaskHandler.TaskInfo feature = fromBranches(task.getBranches(false));

    VcsTaskHandler[] handlers = VcsTaskHandler.getAllHandlers(myProject);
    for (VcsTaskHandler handler : handlers) {
      handler.closeTask(feature, original);
    }
  }

  private static void addBranches(LocalTask task, VcsTaskHandler.TaskInfo info, boolean original) {
    List<BranchInfo> branchInfos = BranchInfo.fromTaskInfo(info, original);
    for (BranchInfo branchInfo : branchInfos) {
      task.addBranch(branchInfo);
    }
  }

  private void saveActiveTask() {
    myContextManager.saveContext(myActiveTask);
    myActiveTask.setUpdated(new Date());
  }

  private LocalTask doActivate(Task origin, boolean explicitly) {
    final LocalTaskImpl task =
        origin instanceof LocalTaskImpl ? (LocalTaskImpl) origin : new LocalTaskImpl(origin);
    if (explicitly) {
      task.setUpdated(new Date());
    }
    myActiveTask.setActive(false);
    task.setActive(true);
    addTask(task);
    if (task.isIssue()) {
      StartupManager.getInstance(myProject)
          .runWhenProjectIsInitialized(
              new Runnable() {
                public void run() {
                  ProgressManager.getInstance()
                      .run(
                          new com.intellij.openapi.progress.Task.Backgroundable(
                              myProject, "Updating " + task.getId()) {

                            public void run(@NotNull ProgressIndicator indicator) {
                              updateIssue(task.getId());
                            }
                          });
                }
              });
    }
    LocalTask oldActiveTask = myActiveTask;
    boolean isChanged = !task.equals(oldActiveTask);
    myActiveTask = task;
    if (isChanged) {
      myDispatcher.getMulticaster().taskDeactivated(oldActiveTask);
      myDispatcher.getMulticaster().taskActivated(task);
    }
    return task;
  }

  private void addTask(LocalTaskImpl task) {
    myTasks.put(task.getId(), task);
    myDispatcher.getMulticaster().taskAdded(task);
  }

  @Override
  public boolean testConnection(final TaskRepository repository) {

    TestConnectionTask task =
        new TestConnectionTask("Test connection") {
          public void run(@NotNull ProgressIndicator indicator) {
            indicator.setText("Connecting to " + repository.getUrl() + "...");
            indicator.setFraction(0);
            indicator.setIndeterminate(true);
            try {
              myConnection = repository.createCancellableConnection();
              if (myConnection != null) {
                Future<Exception> future =
                    ApplicationManager.getApplication().executeOnPooledThread(myConnection);
                while (true) {
                  try {
                    myException = future.get(100, TimeUnit.MILLISECONDS);
                    return;
                  } catch (TimeoutException ignore) {
                    try {
                      indicator.checkCanceled();
                    } catch (ProcessCanceledException e) {
                      myException = e;
                      myConnection.cancel();
                      return;
                    }
                  } catch (Exception e) {
                    myException = e;
                    return;
                  }
                }
              } else {
                try {
                  repository.testConnection();
                } catch (Exception e) {
                  LOG.info(e);
                  myException = e;
                }
              }
            } catch (Exception e) {
              myException = e;
            }
          }
        };
    ProgressManager.getInstance().run(task);
    Exception e = task.myException;
    if (e == null) {
      myBadRepositories.remove(repository);
      Messages.showMessageDialog(
          myProject, "Connection is successful", "Connection", Messages.getInformationIcon());
    } else if (!(e instanceof ProcessCanceledException)) {
      String message = e.getMessage();
      if (e instanceof UnknownHostException) {
        message = "Unknown host: " + message;
      }
      if (message == null) {
        LOG.error(e);
        message = "Unknown error";
      }
      Messages.showErrorDialog(myProject, StringUtil.capitalize(message), "Error");
    }
    return e == null;
  }

  @SuppressWarnings({"unchecked"})
  @NotNull
  public Config getState() {
    myConfig.tasks =
        ContainerUtil.map(
            myTasks.values(),
            new Function<Task, LocalTaskImpl>() {
              public LocalTaskImpl fun(Task task) {
                return new LocalTaskImpl(task);
              }
            });
    myConfig.servers = XmlSerializer.serialize(getAllRepositories());
    return myConfig;
  }

  @SuppressWarnings({"unchecked"})
  public void loadState(Config config) {
    XmlSerializerUtil.copyBean(config, myConfig);
    myTasks.clear();
    for (LocalTaskImpl task : config.tasks) {
      addTask(task);
    }

    myRepositories.clear();
    Element element = config.servers;
    List<TaskRepository> repositories = loadRepositories(element);
    myRepositories.addAll(repositories);
  }

  public static ArrayList<TaskRepository> loadRepositories(Element element) {
    ArrayList<TaskRepository> repositories = new ArrayList<TaskRepository>();
    for (TaskRepositoryType repositoryType : TaskRepositoryType.getRepositoryTypes()) {
      for (Object o : element.getChildren()) {
        if (((Element) o).getName().equals(repositoryType.getName())) {
          try {
            @SuppressWarnings({"unchecked"})
            TaskRepository repository =
                (TaskRepository)
                    XmlSerializer.deserialize((Element) o, repositoryType.getRepositoryClass());
            if (repository != null) {
              repository.setRepositoryType(repositoryType);
              repositories.add(repository);
            }
          } catch (XmlSerializationException e) {
            // ignore
            LOG.error(e.getMessage());
          }
        }
      }
    }
    return repositories;
  }

  public void projectOpened() {

    TaskProjectConfiguration projectConfiguration = getProjectConfiguration();

    servers:
    for (TaskProjectConfiguration.SharedServer server : projectConfiguration.servers) {
      if (server.type == null || server.url == null) {
        continue;
      }
      for (TaskRepositoryType<?> repositoryType : TaskRepositoryType.getRepositoryTypes()) {
        if (repositoryType.getName().equals(server.type)) {
          for (TaskRepository repository : myRepositories) {
            if (!repositoryType.equals(repository.getRepositoryType())) {
              continue;
            }
            if (server.url.equals(repository.getUrl())) {
              continue servers;
            }
          }
          TaskRepository repository = repositoryType.createRepository();
          repository.setUrl(server.url);
          myRepositories.add(repository);
        }
      }
    }

    myContextManager.pack(200, 50);

    // make sure the task is associated with default changelist
    LocalTask defaultTask = findTask(LocalTaskImpl.DEFAULT_TASK_ID);
    LocalChangeList defaultList = myChangeListManager.findChangeList(LocalChangeList.DEFAULT_NAME);
    if (defaultList != null && defaultTask != null) {
      ChangeListInfo listInfo = new ChangeListInfo(defaultList);
      if (!defaultTask.getChangeLists().contains(listInfo)) {
        defaultTask.addChangelist(listInfo);
      }
    }

    // remove already not existing changelists from tasks changelists
    for (LocalTask localTask : getLocalTasks()) {
      for (Iterator<ChangeListInfo> iterator = localTask.getChangeLists().iterator();
          iterator.hasNext(); ) {
        final ChangeListInfo changeListInfo = iterator.next();
        if (myChangeListManager.getChangeList(changeListInfo.id) == null) {
          iterator.remove();
        }
      }
    }

    myChangeListManager.addChangeListListener(myChangeListListener);
  }

  private TaskProjectConfiguration getProjectConfiguration() {
    return ServiceManager.getService(myProject, TaskProjectConfiguration.class);
  }

  public void projectClosed() {}

  @NotNull
  public String getComponentName() {
    return "Task Manager";
  }

  public void initComponent() {
    if (!ApplicationManager.getApplication().isUnitTestMode()) {
      myCacheRefreshTimer =
          UIUtil.createNamedTimer(
              "TaskManager refresh",
              myConfig.updateInterval * 60 * 1000,
              new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                  if (myConfig.updateEnabled && !myUpdating) {
                    updateIssues(null);
                  }
                }
              });
      myCacheRefreshTimer.setInitialDelay(0);
      StartupManager.getInstance(myProject)
          .registerPostStartupActivity(
              new Runnable() {
                public void run() {
                  myCacheRefreshTimer.start();
                }
              });
    }

    // make sure that the default task is exist
    LocalTask defaultTask = findTask(LocalTaskImpl.DEFAULT_TASK_ID);
    if (defaultTask == null) {
      defaultTask = createDefaultTask();
      addTask(defaultTask);
    }

    // search for active task
    LocalTask activeTask = null;
    final List<LocalTask> tasks = getLocalTasks();
    Collections.sort(tasks, TASK_UPDATE_COMPARATOR);
    for (LocalTask task : tasks) {
      if (activeTask == null) {
        if (task.isActive()) {
          activeTask = task;
        }
      } else {
        task.setActive(false);
      }
    }
    if (activeTask == null) {
      activeTask = defaultTask;
    }

    myActiveTask = activeTask;
    doActivate(myActiveTask, false);
    myDispatcher.getMulticaster().taskActivated(myActiveTask);
  }

  private static LocalTaskImpl createDefaultTask() {
    return new LocalTaskImpl(LocalTaskImpl.DEFAULT_TASK_ID, "Default task");
  }

  public void disposeComponent() {
    if (myCacheRefreshTimer != null) {
      myCacheRefreshTimer.stop();
    }
    myChangeListManager.removeChangeListListener(myChangeListListener);
  }

  public void updateIssues(final @Nullable Runnable onComplete) {
    TaskRepository first =
        ContainerUtil.find(
            getAllRepositories(),
            new Condition<TaskRepository>() {
              public boolean value(TaskRepository repository) {
                return repository.isConfigured();
              }
            });
    if (first == null) {
      myIssueCache.clear();
      if (onComplete != null) {
        onComplete.run();
      }
      return;
    }
    myUpdating = true;
    if (ApplicationManager.getApplication().isUnitTestMode()) {
      doUpdate(onComplete);
    } else {
      ApplicationManager.getApplication()
          .executeOnPooledThread(
              new Runnable() {
                public void run() {
                  doUpdate(onComplete);
                }
              });
    }
  }

  private void doUpdate(@Nullable Runnable onComplete) {
    try {
      List<Task> issues =
          getIssuesFromRepositories(
              null, myConfig.updateIssuesCount, 0, false, new EmptyProgressIndicator());
      if (issues == null) return;

      synchronized (myIssueCache) {
        myIssueCache.clear();
        for (Task issue : issues) {
          myIssueCache.put(issue.getId(), issue);
        }
      }
      // update local tasks
      synchronized (myTasks) {
        for (Map.Entry<String, LocalTask> entry : myTasks.entrySet()) {
          Task issue = myIssueCache.get(entry.getKey());
          if (issue != null) {
            entry.getValue().updateFromIssue(issue);
          }
        }
      }
    } finally {
      if (onComplete != null) {
        onComplete.run();
      }
      myUpdating = false;
    }
  }

  @Nullable
  private List<Task> getIssuesFromRepositories(
      @Nullable String request,
      int max,
      long since,
      boolean forceRequest,
      @NotNull final ProgressIndicator cancelled) {
    List<Task> issues = null;
    for (final TaskRepository repository : getAllRepositories()) {
      if (!repository.isConfigured() || (!forceRequest && myBadRepositories.contains(repository))) {
        continue;
      }
      try {
        Task[] tasks = repository.getIssues(request, max, since, cancelled);
        myBadRepositories.remove(repository);
        if (issues == null) issues = new ArrayList<Task>(tasks.length);
        if (!repository.isSupported(TaskRepository.NATIVE_SEARCH) && request != null) {
          List<Task> filteredTasks =
              TaskSearchSupport.filterTasks(request, ContainerUtil.list(tasks));
          ContainerUtil.addAll(issues, filteredTasks);
        } else {
          ContainerUtil.addAll(issues, tasks);
        }
      } catch (ProcessCanceledException ignored) {
        // OK
      } catch (Exception e) {
        String reason = "";
        // Fix to IDEA-111810
        if (e.getClass() == Exception.class) {
          // probably contains some message meaningful to end-user
          reason = e.getMessage();
        }
        //noinspection InstanceofCatchParameter
        if (e instanceof SocketTimeoutException) {
          LOG.warn("Socket timeout from " + repository);
        } else {
          LOG.warn("Cannot connect to " + repository, e);
        }
        myBadRepositories.add(repository);
        if (forceRequest) {
          notifyAboutConnectionFailure(repository, reason);
        }
      }
    }
    return issues;
  }

  private void notifyAboutConnectionFailure(final TaskRepository repository, String details) {
    Notifications.Bus.register(TASKS_NOTIFICATION_GROUP, NotificationDisplayType.BALLOON);
    String content = "<p><a href=\"\">Configure server...</a></p>";
    if (!StringUtil.isEmpty(details)) {
      content = "<p>" + details + "</p>" + content;
    }
    Notifications.Bus.notify(
        new Notification(
            TASKS_NOTIFICATION_GROUP,
            "Cannot connect to " + repository.getUrl(),
            content,
            NotificationType.WARNING,
            new NotificationListener() {
              public void hyperlinkUpdate(
                  @NotNull Notification notification, @NotNull HyperlinkEvent event) {
                TaskRepositoriesConfigurable configurable =
                    new TaskRepositoriesConfigurable(myProject);
                ShowSettingsUtil.getInstance().editConfigurable(myProject, configurable);
                if (!ArrayUtil.contains(repository, getAllRepositories())) {
                  notification.expire();
                }
              }
            }),
        myProject);
  }

  @Override
  public boolean isVcsEnabled() {
    return ProjectLevelVcsManager.getInstance(myProject).getAllActiveVcss().length > 0;
  }

  @Override
  public AbstractVcs getActiveVcs() {
    AbstractVcs[] vcss = ProjectLevelVcsManager.getInstance(myProject).getAllActiveVcss();
    if (vcss.length == 0) return null;
    for (AbstractVcs vcs : vcss) {
      if (vcs.getType() == VcsType.distributed) {
        return vcs;
      }
    }
    return vcss[0];
  }

  @Override
  public boolean isLocallyClosed(final LocalTask localTask) {
    if (isVcsEnabled()) {
      List<ChangeListInfo> lists = localTask.getChangeLists();
      if (lists.isEmpty()) return true;
      for (ChangeListInfo list : lists) {
        if (StringUtil.isEmpty(list.id)) {
          return true;
        }
      }
    }
    return false;
  }

  @Nullable
  @Override
  public LocalTask getAssociatedTask(LocalChangeList list) {
    for (LocalTask task : getLocalTasks()) {
      for (ChangeListInfo changeListInfo : task.getChangeLists()) {
        if (changeListInfo.id.equals(list.getId())) {
          return task;
        }
      }
    }
    return null;
  }

  @Override
  public void trackContext(LocalChangeList changeList) {
    ChangeListInfo changeListInfo = new ChangeListInfo(changeList);
    String changeListName = changeList.getName();
    LocalTaskImpl task = createLocalTask(changeListName);
    task.addChangelist(changeListInfo);
    addTask(task);
    if (changeList.isDefault()) {
      activateTask(task, false);
    }
  }

  @Override
  public void disassociateFromTask(LocalChangeList changeList) {
    ChangeListInfo changeListInfo = new ChangeListInfo(changeList);
    for (LocalTask localTask : getLocalTasks()) {
      if (localTask.getChangeLists().contains(changeListInfo)) {
        localTask.removeChangelist(changeListInfo);
      }
    }
  }

  public void decorateChangeList(
      LocalChangeList changeList,
      ColoredTreeCellRenderer cellRenderer,
      boolean selected,
      boolean expanded,
      boolean hasFocus) {
    LocalTask task = getAssociatedTask(changeList);
    if (task != null && task.isIssue()) {
      cellRenderer.setIcon(task.getIcon());
    }
  }

  public void createChangeList(LocalTask task, String name) {
    String comment = TaskUtil.getChangeListComment(task);
    createChangeList(task, name, comment);
  }

  private void createChangeList(LocalTask task, String name, @Nullable String comment) {
    LocalChangeList changeList = myChangeListManager.findChangeList(name);
    if (changeList == null) {
      changeList = myChangeListManager.addChangeList(name, comment);
    } else {
      final LocalTask associatedTask = getAssociatedTask(changeList);
      if (associatedTask != null) {
        associatedTask.removeChangelist(new ChangeListInfo(changeList));
      }
      changeList.setComment(comment);
    }
    task.addChangelist(new ChangeListInfo(changeList));
    myChangeListManager.setDefaultChangeList(changeList);
  }

  public String getChangelistName(Task task) {
    if (task.isIssue() && myConfig.changelistNameFormat != null) {
      return TaskUtil.formatTask(task, myConfig.changelistNameFormat);
    }
    return task.getSummary();
  }

  public String suggestBranchName(Task task) {
    if (task.isIssue() && StringUtil.isNotEmpty(task.getNumber())) {
      return task.getId().replace(' ', '-');
    } else {
      String summary = task.getSummary();
      List<String> words = StringUtil.getWordsIn(summary);
      String[] strings = ArrayUtil.toStringArray(words);
      return StringUtil.join(strings, 0, Math.min(2, strings.length), "-");
    }
  }

  @TestOnly
  public ChangeListAdapter getChangeListListener() {
    return myChangeListListener;
  }

  public static class Config {

    @Property(surroundWithTag = false)
    @AbstractCollection(surroundWithTag = false, elementTag = "task")
    public List<LocalTaskImpl> tasks = new ArrayList<LocalTaskImpl>();

    public int localTasksCounter = 1;

    public int taskHistoryLength = 50;

    public boolean updateEnabled = true;
    public int updateInterval = 20;
    public int updateIssuesCount = 100;

    // create task options
    public boolean clearContext = true;
    public boolean createChangelist = true;
    public boolean createBranch = true;

    // close task options
    public boolean closeIssue = true;
    public boolean commitChanges = true;
    public boolean mergeBranch = true;

    public boolean saveContextOnCommit = true;
    public boolean trackContextForNewChangelist = false;
    public boolean markAsInProgress = false;

    public String changelistNameFormat = "{id} {summary}";

    public boolean searchClosedTasks = false;

    @Tag("servers")
    public Element servers = new Element("servers");
  }

  private abstract class TestConnectionTask extends com.intellij.openapi.progress.Task.Modal {

    protected Exception myException;

    @Nullable protected TaskRepository.CancellableConnection myConnection;

    public TestConnectionTask(String title) {
      super(TaskManagerImpl.this.myProject, title, true);
    }

    @Override
    public void onCancel() {
      if (myConnection != null) {
        myConnection.cancel();
      }
    }
  }
}
 public List<ShelvedChangeList> getShelvedChangeLists() {
   return Collections.unmodifiableList(myShelvedChangeLists);
 }