| /* |
| * Copyright 2000-2012 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.zmlx.hg4idea.status; |
| |
| import com.intellij.concurrency.JobScheduler; |
| import com.intellij.openapi.application.ApplicationManager; |
| import com.intellij.openapi.progress.ProgressIndicator; |
| import com.intellij.openapi.progress.Task; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.vcs.AbstractVcs; |
| import com.intellij.openapi.vcs.ProjectLevelVcsManager; |
| import com.intellij.openapi.vfs.VirtualFile; |
| import com.intellij.util.messages.MessageBusConnection; |
| import com.intellij.xml.util.XmlStringUtil; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| import org.zmlx.hg4idea.*; |
| import org.zmlx.hg4idea.command.HgIncomingCommand; |
| import org.zmlx.hg4idea.command.HgOutgoingCommand; |
| |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.concurrent.ScheduledFuture; |
| import java.util.concurrent.TimeUnit; |
| import java.util.concurrent.atomic.AtomicBoolean; |
| |
| /** |
| * @author Kirill Likhodedov |
| */ |
| public class HgRemoteStatusUpdater implements HgUpdater { |
| |
| private final AbstractVcs myVcs; |
| private final HgChangesetStatus myIncomingStatus; |
| private final HgChangesetStatus myOutgoingStatus; |
| private final HgProjectSettings myProjectSettings; |
| private final AtomicBoolean myUpdateStarted = new AtomicBoolean(); |
| |
| private MessageBusConnection busConnection; |
| |
| private ScheduledFuture<?> changesUpdaterScheduledFuture; |
| |
| |
| public HgRemoteStatusUpdater(@NotNull HgVcs vcs, |
| HgChangesetStatus incomingStatus, |
| HgChangesetStatus outgoingStatus, |
| HgProjectSettings projectSettings) { |
| myVcs = vcs; |
| myIncomingStatus = incomingStatus; |
| myOutgoingStatus = outgoingStatus; |
| myProjectSettings = projectSettings; |
| } |
| |
| public void update(final Project project) { |
| update(project, null); |
| } |
| |
| public void update(final Project project, @Nullable final VirtualFile root) { |
| if (!isCheckingEnabled() || myUpdateStarted.get()) { |
| return; |
| } |
| myUpdateStarted.set(true); |
| ApplicationManager.getApplication().invokeLater(new Runnable() { |
| public void run() { |
| new Task.Backgroundable(project, getProgressTitle(), true) { |
| public void run(@NotNull ProgressIndicator indicator) { |
| if (project.isDisposed()) return; |
| final VirtualFile[] roots = |
| root != null ? new VirtualFile[]{root} : ProjectLevelVcsManager.getInstance(project).getRootsUnderVcs(myVcs); |
| if (myProjectSettings.isCheckIncomingOutgoing()) { |
| updateChangesetStatus(project, roots, myIncomingStatus, true); |
| updateChangesetStatus(project, roots, myOutgoingStatus, false); |
| } |
| |
| project.getMessageBus().syncPublisher(HgVcs.STATUS_TOPIC).update(project, null); |
| |
| indicator.stop(); |
| myUpdateStarted.set(false); |
| } |
| }.queue(); |
| } |
| }); |
| } |
| |
| |
| public void activate() { |
| busConnection = myVcs.getProject().getMessageBus().connect(); |
| busConnection.subscribe(HgVcs.REMOTE_TOPIC, this); |
| |
| int checkIntervalSeconds = HgGlobalSettings.getIncomingCheckIntervalSeconds(); |
| changesUpdaterScheduledFuture = JobScheduler.getScheduler().scheduleWithFixedDelay(new Runnable() { |
| public void run() { |
| update(myVcs.getProject()); |
| } |
| }, 5, checkIntervalSeconds, TimeUnit.SECONDS); |
| } |
| |
| public void deactivate() { |
| busConnection.disconnect(); |
| |
| if (changesUpdaterScheduledFuture != null) { |
| changesUpdaterScheduledFuture.cancel(true); |
| } |
| } |
| |
| private void updateChangesetStatus(Project project, VirtualFile[] roots, HgChangesetStatus status, boolean incoming) { |
| final List<HgRevisionNumber> changesets = new LinkedList<HgRevisionNumber>(); |
| for (VirtualFile root : roots) { |
| if (incoming) { |
| changesets.addAll(new HgIncomingCommand(project).execute(root)); |
| } |
| else { |
| changesets.addAll(new HgOutgoingCommand(project).execute(root)); |
| } |
| } |
| status.setChanges(changesets.size(), new ChangesetFormatter(status, changesets)); |
| } |
| |
| private String getProgressTitle() { |
| return "Checking incoming and outgoing changes"; |
| } |
| |
| protected boolean isCheckingEnabled() { |
| return myProjectSettings.isCheckIncomingOutgoing(); |
| } |
| |
| private static final class ChangesetFormatter implements HgChangesetStatus.ChangesetWriter { |
| private final String string; |
| |
| private ChangesetFormatter(HgChangesetStatus status, List<HgRevisionNumber> changesets) { |
| StringBuilder builder = new StringBuilder(); |
| builder.append("<b>").append(status.getStatusName()).append(" changesets</b>:<br>"); |
| for (HgRevisionNumber revisionNumber : changesets) { |
| builder.append(revisionNumber.asString()).append(" ").append(revisionNumber.getCommitMessage()).append(" (") |
| .append(revisionNumber.getAuthor()).append(")<br>"); |
| } |
| string = XmlStringUtil.wrapInHtml(builder); |
| } |
| |
| public String asString() { |
| return string; |
| } |
| } |
| } |