1 /******************************************************************************* 2 * Copyright (c) 2003, 2017 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 * Trevor S. Kaufman <endante@gmail.com> - bug 156152 14 *******************************************************************************/ 15 package org.eclipse.team.internal.ui.synchronize; 16 17 import java.text.DateFormat; 18 import java.util.Calendar; 19 import java.util.Date; 20 21 import org.eclipse.core.runtime.Adapters; 22 import org.eclipse.core.runtime.jobs.Job; 23 import org.eclipse.osgi.util.NLS; 24 import org.eclipse.team.internal.ui.TeamUIMessages; 25 import org.eclipse.team.internal.ui.TeamUIPlugin; 26 import org.eclipse.team.ui.synchronize.ISynchronizeParticipant; 27 import org.eclipse.ui.IMemento; 28 import org.eclipse.ui.actions.ActionFactory; 29 30 /** 31 * Schedule to refresh a subscriber at a specified interval. The schedule can be disabled or enabled 32 * and will create the refresh job. 33 * 34 * @since 3.0 35 */ 36 public class SubscriberRefreshSchedule { 37 private long refreshInterval = 3600; // 1 hour default 38 private Date refreshStart; 39 private boolean runOnce = false; 40 41 private boolean enabled = false; 42 43 private RefreshParticipantJob job; 44 45 private IRefreshable refreshable; 46 47 private IRefreshEvent lastRefreshEvent; 48 49 /** 50 * Key for settings in memento 51 */ 52 private static final String CTX_REFRESHSCHEDULE_INTERVAL = TeamUIPlugin.ID + ".CTX_REFRESHSCHEDULE_INTERVAL"; //$NON-NLS-1$ 53 54 /** 55 * Key for schedule in memento 56 */ 57 private static final String CTX_REFRESHSCHEDULE_ENABLED = TeamUIPlugin.ID + ".CTX_REFRESHSCHEDULE_ENABLED"; //$NON-NLS-1$ 58 59 /** 60 * Key for start date in memento 61 */ 62 private static final String CTX_REFRESHSCHEDULE_START = TeamUIPlugin.ID + ".CTX_REFRESHSCHEDULE_START"; //$NON-NLS-1$ 63 64 /** 65 * Key for run once in memento 66 */ 67 private static final String CTX_REFRESHSCHEDULE_RUNONCE = TeamUIPlugin.ID + ".CTX_REFRESHSCHEDULE_RUNONCE"; //$NON-NLS-1$ 68 69 private IRefreshSubscriberListener refreshSubscriberListener = new IRefreshSubscriberListener() { 70 @Override 71 public void refreshStarted(IRefreshEvent event) { 72 } 73 @Override 74 public ActionFactory.IWorkbenchAction refreshDone(final IRefreshEvent event) { 75 if (getRefreshable(event.getParticipant()) == refreshable) { 76 lastRefreshEvent = event; 77 if(enabled && event.getRefreshType() == IRefreshEvent.SCHEDULED_REFRESH) { 78 RefreshUserNotificationPolicy policy = new RefreshUserNotificationPolicy(refreshable.getParticipant()); 79 policy.refreshDone(event); 80 } 81 } 82 return null; 83 } 84 private IRefreshable getRefreshable(ISynchronizeParticipant participant) { 85 return Adapters.adapt(participant, IRefreshable.class); 86 } 87 }; 88 89 SubscriberRefreshSchedule(IRefreshable refreshable)90 public SubscriberRefreshSchedule(IRefreshable refreshable) { 91 this.refreshable = refreshable; 92 RefreshParticipantJob.addRefreshListener(refreshSubscriberListener); 93 94 // Calendar cal = Calendar.getInstance(); 95 // cal.clear(); 96 // refreshStart = cal.getTime(); 97 } 98 99 /** 100 * @return Returns the enabled. 101 */ isEnabled()102 public boolean isEnabled() { 103 return enabled; 104 } 105 106 /** 107 * @param enabled The enabled to set. 108 * @param allowedToStart Is the job allowed to start. 109 */ setEnabled(boolean enabled, boolean allowedToStart)110 public void setEnabled(boolean enabled, boolean allowedToStart) { 111 boolean wasEnabled = isEnabled(); 112 this.enabled = enabled; 113 if(enabled && ! wasEnabled) { 114 if(allowedToStart) { 115 startJob(); 116 } 117 } else { 118 stopJob(); 119 } 120 } 121 122 /** 123 * @return Returns the refreshInterval in seconds. 124 */ getRefreshInterval()125 public long getRefreshInterval() { 126 return refreshInterval; 127 } 128 getParticipant()129 public ISynchronizeParticipant getParticipant() { 130 return refreshable.getParticipant(); 131 } 132 133 /** 134 * @param refreshInterval The refreshInterval to set. 135 */ setRefreshInterval(long refreshInterval)136 public void setRefreshInterval(long refreshInterval) { 137 if(refreshInterval != getRefreshInterval()) { 138 stopJob(); 139 this.refreshInterval = refreshInterval; 140 runOnce = false; 141 if(isEnabled()) { 142 startJob(); 143 } 144 } 145 } 146 startJob()147 public void startJob() { 148 if(job == null) { 149 job = refreshable.createJob(getRefreshIntervalAsString()); 150 job.setUser(false); 151 } else if(job.getState() != Job.NONE){ 152 stopJob(); 153 } 154 job.setRefreshInterval(getRefreshInterval()); 155 job.setRestartOnCancel(true); 156 job.setReschedule(!runOnce); 157 if (refreshStart != null) { 158 job.schedule(getJobDelay()); 159 } else { 160 job.schedule(); 161 } 162 } 163 164 /** 165 * @return schedule delay in milliseconds 166 */ getJobDelay()167 private long getJobDelay() { 168 Calendar now = Calendar.getInstance(); 169 Calendar start = Calendar.getInstance(); 170 start.setTime(refreshStart); 171 while (now.after(start)) { 172 start.add(Calendar.DATE, 1); // tomorrow 173 } 174 return start.getTimeInMillis() - now.getTimeInMillis(); 175 } 176 stopJob()177 protected void stopJob() { 178 if(job != null) { 179 job.setRestartOnCancel(false /* don't restart the job */); 180 job.setReschedule(false); 181 job.cancel(); 182 job = null; 183 } 184 } 185 dispose()186 public void dispose() { 187 stopJob(); 188 RefreshParticipantJob.removeRefreshListener(refreshSubscriberListener); 189 } 190 saveState(IMemento memento)191 public void saveState(IMemento memento) { 192 memento.putString(CTX_REFRESHSCHEDULE_ENABLED, Boolean.toString(enabled)); 193 memento.putInteger(CTX_REFRESHSCHEDULE_INTERVAL, (int)refreshInterval); 194 if (refreshStart != null) 195 memento.putString(CTX_REFRESHSCHEDULE_START, Long.toString(refreshStart.getTime())); 196 memento.putString(CTX_REFRESHSCHEDULE_RUNONCE, Boolean.toString(runOnce)); 197 } 198 init(IMemento memento, IRefreshable refreshable)199 public static SubscriberRefreshSchedule init(IMemento memento, IRefreshable refreshable) { 200 SubscriberRefreshSchedule schedule = new SubscriberRefreshSchedule(refreshable); 201 if(memento != null) { 202 String enabled = memento.getString(CTX_REFRESHSCHEDULE_ENABLED); 203 int interval = memento.getInteger(CTX_REFRESHSCHEDULE_INTERVAL).intValue(); 204 String startString = memento.getString(CTX_REFRESHSCHEDULE_START); 205 String runOnce = memento.getString(CTX_REFRESHSCHEDULE_RUNONCE); 206 if (startString != null) { 207 long start = Long.parseLong(startString); 208 schedule.setRefreshStartTime(new Date(start)); 209 } 210 schedule.setRefreshInterval(interval); 211 schedule.setRunOnce("true".equals(runOnce) ? true : false); //$NON-NLS-1$ 212 schedule.setEnabled("true".equals(enabled) ? true : false, false /* don't start job */); //$NON-NLS-1$ 213 } 214 // Use the defaults if a schedule hasn't been saved or can't be found. 215 return schedule; 216 } 217 refreshEventAsString(IRefreshEvent event)218 public static String refreshEventAsString(IRefreshEvent event) { 219 if(event == null) { 220 return TeamUIMessages.SyncViewPreferencePage_lastRefreshRunNever; 221 } 222 long stopMills = event.getStopTime(); 223 StringBuilder text = new StringBuilder(); 224 if(stopMills <= 0) { 225 text.append(TeamUIMessages.SyncViewPreferencePage_lastRefreshRunNever); 226 } else { 227 Date lastTimeRun = new Date(stopMills); 228 text.append(DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT).format(lastTimeRun)); 229 } 230 int changeCount = event.getChangeDescription().getChangeCount(); 231 if (changeCount == 0) { 232 text.append(TeamUIMessages.RefreshSchedule_7); 233 } else if (changeCount == 1) { 234 text.append(NLS.bind(TeamUIMessages.RefreshSchedule_changesSingular, new String[] { Integer.toString(changeCount) })); 235 } else { 236 text.append(NLS.bind(TeamUIMessages.RefreshSchedule_changesPlural, new String[] { Integer.toString(changeCount) })); 237 } 238 return text.toString(); 239 } 240 getLastRefreshEvent()241 public IRefreshEvent getLastRefreshEvent() { 242 return lastRefreshEvent; 243 } 244 getRefreshIntervalAsString()245 private String getRefreshIntervalAsString() { 246 if (runOnce) 247 return TeamUIMessages.RefreshSchedule_16; 248 boolean hours = false; 249 long seconds = getRefreshInterval(); 250 if(seconds <= 60) { 251 seconds = 60; 252 } 253 long minutes = seconds / 60; 254 if(minutes >= 60) { 255 minutes = minutes / 60; 256 hours = true; 257 } 258 String unit; 259 if(minutes >= 1) { 260 unit = (hours ? TeamUIMessages.RefreshSchedule_9 : TeamUIMessages.RefreshSchedule_10); 261 } else { 262 unit = (hours ? TeamUIMessages.RefreshSchedule_11 : TeamUIMessages.RefreshSchedule_12); 263 } 264 return NLS.bind(TeamUIMessages.RefreshSchedule_13, new String[] { Long.toString(minutes), unit }); 265 } 266 getRefreshable()267 public IRefreshable getRefreshable() { 268 return refreshable; 269 } 270 271 /** 272 * @return The time when the job should start or <code>null</code> when it 273 * should be run immediately. 274 */ getRefreshStartTime()275 public Date getRefreshStartTime() { 276 return refreshStart; 277 } 278 setRefreshStartTime(Date refreshStart)279 public void setRefreshStartTime(Date refreshStart) { 280 if(refreshStart==null || refreshStart != getRefreshStartTime()) { 281 stopJob(); 282 this.refreshStart = refreshStart; 283 if(isEnabled()) { 284 startJob(); 285 } 286 } 287 } 288 289 /** 290 * @return Return <code>false</code> if the job should be run again when 291 * finished, or <code>true</code> otherwise. 292 */ getRunOnce()293 public boolean getRunOnce() { 294 return runOnce; 295 } 296 setRunOnce(boolean runOnce)297 public void setRunOnce(boolean runOnce) { 298 if (runOnce != getRunOnce()) { 299 stopJob(); 300 this.runOnce = runOnce; 301 if (isEnabled()) { 302 startJob(); 303 } 304 } 305 } 306 } 307