| /* |
| * Copyright 2000-2009 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.jetbrains.idea.svn.history; |
| |
| import com.intellij.openapi.vcs.VcsException; |
| import com.intellij.openapi.vcs.changes.committed.ChangesBunch; |
| import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList; |
| import org.jetbrains.annotations.Nullable; |
| |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| public abstract class CachedProvider implements BunchProvider { |
| private final Iterator<ChangesBunch> myIterator; |
| private long myEarliestKeepedRevision; |
| protected ChangesBunch myAlreadyReaded; |
| protected Origin myOrigin; |
| |
| private boolean myHadBeenAccessed; |
| |
| protected CachedProvider(final Iterator<ChangesBunch> iterator, final Origin origin) { |
| myIterator = iterator; |
| myEarliestKeepedRevision = -1; |
| myAlreadyReaded = null; |
| myOrigin = origin; |
| } |
| |
| public abstract void doCacheUpdate(final List<List<Fragment>> fragments); |
| |
| protected static List<CommittedChangeList> getAllBeforeVisuallyCached(final List<List<Fragment>> fragmentsListList) { |
| final List<CommittedChangeList> lists = new ArrayList<CommittedChangeList>(); |
| // take those _after_ committed |
| for (List<Fragment> fragmentList : fragmentsListList) { |
| for (Fragment fragment : fragmentList) { |
| if (Origin.VISUAL.equals(fragment.getOrigin())) { |
| break; |
| } |
| lists.addAll(fragment.getList()); |
| } |
| } |
| |
| return lists; |
| } |
| |
| public long getEarliestRevision() { |
| if (myEarliestKeepedRevision == -1) { |
| try { |
| while (myIterator.hasNext()) { |
| final ChangesBunch changesBunch = myIterator.next(); |
| if (changesBunch == null) { |
| break; |
| } |
| addToLoaded(changesBunch); |
| final List<CommittedChangeList> list = myAlreadyReaded.getList(); |
| if (! list.isEmpty()) { |
| myEarliestKeepedRevision = list.get(0).getNumber(); |
| break; |
| } |
| } |
| } catch (SwitchRevisionsProviderException e) { |
| // means that committed cache now should be queried instead of internally cached |
| // just return -1 -> queries will be redirected |
| myEarliestKeepedRevision = -1; |
| } |
| } |
| return myEarliestKeepedRevision; |
| } |
| |
| protected void addToLoaded(final ChangesBunch loaded) { |
| myAlreadyReaded = loaded; |
| } |
| |
| @Nullable |
| public Fragment getEarliestBunchInInterval(final long earliestRevision, final long oldestRevision, final int desirableSize, |
| final boolean includeYoungest, final boolean includeOldest) throws VcsException { |
| if ((earliestRevision > getEarliestRevision()) || (earliestRevision == -1)) { |
| if (myAlreadyReaded == null) { |
| return null; |
| } |
| // just return first |
| return createFromLoaded(myAlreadyReaded, earliestRevision, oldestRevision, desirableSize, includeYoungest, includeOldest, false); |
| } |
| |
| final ChangesBunch loadedBunch = myAlreadyReaded; |
| |
| final List<CommittedChangeList> list = loadedBunch.getList(); |
| if (list.isEmpty()) { |
| return null; |
| } |
| final long oldest = list.get(list.size() - 1).getNumber(); |
| |
| if ((! includeYoungest) && (oldest == earliestRevision)) { |
| return packNext(earliestRevision, oldestRevision, desirableSize, includeOldest, loadedBunch.isConsistentWithPrevious()); |
| //} else if ((oldest <= earliestRevision) && (youngest >= earliestRevision)) { |
| } else if (oldest <= earliestRevision) { |
| return createFromLoaded(loadedBunch, earliestRevision, oldestRevision, desirableSize, includeYoungest, includeOldest, false); |
| } |
| |
| return null; |
| } |
| |
| private Fragment packNext(final long earliestRevision, final long oldestRevision, final int desirableSize, final boolean includeOldest, |
| final boolean wasConsistentWithPrevious) { |
| try { |
| if (myIterator.hasNext()) { |
| final ChangesBunch changesBunch = myIterator.next(); |
| if (changesBunch == null) { |
| return null; |
| } |
| addToLoaded(changesBunch); |
| |
| // there is no earliestRevision |
| // always consistent since there were exactly 'earliest revision' in previous potion |
| return createFromLoaded(changesBunch, earliestRevision, oldestRevision, desirableSize, true, includeOldest, wasConsistentWithPrevious); |
| } |
| } catch (SwitchRevisionsProviderException e) { |
| // means that committed cache now should be queried instead of internally cached |
| // just return null -> queries will be redirected |
| } |
| return null; |
| } |
| |
| public boolean hadBeenSuccessfullyAccessed() { |
| return myHadBeenAccessed; |
| } |
| |
| @Nullable |
| private Fragment createFromLoaded(final ChangesBunch loadedBunch, final long earliestRevision, final long oldestRevision, |
| final int desirableSize, final boolean includeYoungest, final boolean includeOldest, final boolean consistent) { |
| boolean consistentWithPrevious = loadedBunch.isConsistentWithPrevious(); |
| boolean consistentWithYounger = consistent; |
| |
| final List<CommittedChangeList> list = loadedBunch.getList(); |
| |
| final List<CommittedChangeList> sublist = new ArrayList<CommittedChangeList>(); |
| for (int i = 0; i < list.size(); i++) { |
| final CommittedChangeList changeList = list.get(i); |
| if ((! includeOldest) && (changeList.getNumber() == oldestRevision)) { |
| continue; |
| } |
| if (changeList.getNumber() == earliestRevision) { |
| consistentWithYounger = true; |
| } |
| if ((earliestRevision == -1) || (changeList.getNumber() < earliestRevision) || (includeYoungest && (changeList.getNumber() == earliestRevision))) { |
| sublist.add(changeList); |
| } |
| if ((sublist.size() == desirableSize) || (changeList.getNumber() < oldestRevision)) { |
| if (! consistentWithPrevious) { |
| consistentWithPrevious = (i > 0); |
| } |
| break; |
| } |
| } |
| if (! myHadBeenAccessed) { |
| myHadBeenAccessed = (! sublist.isEmpty()); |
| } |
| return (sublist.isEmpty()) ? null : new Fragment(myOrigin, sublist, consistentWithPrevious, consistentWithYounger, loadedBunch); |
| } |
| |
| public boolean isEmpty() { |
| return getEarliestRevision() == -1; |
| } |
| } |