/*******************************************************************************
* ALMA - Atacama Large Millimeter Array
* Copyright (c) ESO - European Southern Observatory, 2013
* (in the framework of the ALMA collaboration).
* All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*******************************************************************************/
package alma.acs.eventbrowser.handlers;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.e4.core.di.annotations.CanExecute;
import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.core.services.events.IEventBroker;
import org.eclipse.e4.core.services.statusreporter.StatusReporter;
import org.eclipse.e4.ui.di.UISynchronize;
import org.eclipse.e4.ui.model.application.ui.menu.MHandledItem;
import org.eclipse.e4.ui.model.application.ui.menu.MItem;
import alma.acs.nsstatistics.EventModel;
import alma.acs.eventbrowser.status.StatusLineWriter;
/**
* Handler for the toggling of the various popup/part menu items that control periodic refreshing
* of the notify service data.
*/
public class PeriodicRefreshHandler {
@Inject
private UISynchronize sync;
/**
* Blocking (popup) status report.
*/
@Inject
private StatusReporter statusReporter;
@Inject
private IEventBroker eventBroker;
private EventModel eventModel;
/**
* Is <code>null</code> when periodic updating is not enabled.
*/
private NotifyServiceUpdateJob job;
public final int refreshDelaySeconds = 10;
/**
* @see #canExecute(MHandledItem)
*/
private final Map<String, MItem> menuItemsToSync = new HashMap<String, MItem>();
/**
* @see #canExecute(MHandledItem)
*/
private boolean sharedIsSelected = false;
/**
* The application model default of the first menu item that calls this handler
* is used as the default for all other menu items calling this handler.
* This way we don't have to hardcode a default value here.
*/
private boolean gotDefaultFromAppModel = false;
private StatusLineWriter statusLineWriter;
@PostConstruct
public void init() {
// System.out.println("PeriodicRefreshHandler#init called.");
try {
eventModel = EventModel.getInstance();
} catch (Throwable thr) {
thr.printStackTrace();
IStatus someStatus = statusReporter.newStatus(IStatus.ERROR, "Connection with NCs failed.", thr);
statusReporter.report(someStatus, StatusReporter.SHOW);
throw new RuntimeException(thr);
}
statusLineWriter = new StatusLineWriter(eventBroker);
}
/**
* Always returns true, since only CHECK menu items are expected to trigger the call,
* and they get selected or unselected but always are enabled.
* <p>
* Hack: We abuse this method to 'harvest' all relevant menu items in {@link #menuItemsToSync},
* so that we can later synchronize their selection state (all checked or unchecked).
* See http://www.eclipse.org/forums/index.php/t/442970/ and http://www.eclipse.org/forums/index.php/t/444326/
* and http://comments.gmane.org/gmane.comp.ide.eclipse.e4.devel/7870
* about alternative workarounds, that I found not working or uglier than this harvesting.
* There it also explains why EModelService#findElements is not working for menu items,
* and other current limitations of E4 like not having a HandlerUtil class to sync stateful menu items.
* I believe that having moved the menu items away from the java code into the e4xmi file, there
* should also be a declarative way to form synchronization groups of stateful menu items.
*/
@CanExecute
public boolean canExecute(MHandledItem handledItem) {
// first call total?
if (!gotDefaultFromAppModel) {
gotDefaultFromAppModel = true;
sharedIsSelected = handledItem.isSelected();
}
// first call from this menu item?
if (!menuItemsToSync.containsKey(handledItem.getElementId())) {
menuItemsToSync.put(handledItem.getElementId(), handledItem);
// System.out.println("canExecute called from " + handledItem.getElementId() + " which is of type " + handledItem.getClass());
handledItem.setSelected(sharedIsSelected);
}
// always enable the menu item
return true;
}
/**
* Starts a {@link NotifyServiceUpdateJob} with 10 seconds refresh period,
* which will notify the interested parts via the IEventBroker.
* <p>
* An alternative implementation could get parameter <code>@Active MPart part</code> injected
* and notify the part directly, without IEventBroker.
*/
@Execute
public void execute(MHandledItem handledItem) {
// sync menu item state
sharedIsSelected = handledItem.isSelected();
for (MItem menuItem : menuItemsToSync.values()) {
menuItem.setSelected(sharedIsSelected);
}
// start or stop the periodic refresh job
if (sharedIsSelected) {
if (job == null) {
// start periodic refreshes
job = new NotifyServiceUpdateJob(eventModel, sync, statusLineWriter, eventBroker, refreshDelaySeconds*1000);
job.schedule();
System.out.println("Scheduled refresh job.");
}
else {
System.out.println("Error: refresh job is already running!");
}
}
else {
if (job != null) {
job.cancel();
job = null;
System.out.println("Cancelled refresh job.");
}
else {
System.out.println("Error: refresh job is already cancelled!");
}
}
}
@PreDestroy
public void dispose() {
// System.out.println("PeriodicRefreshHandler#dispose called.");
if (job != null) {
job.cancel();
job = null;
}
}
}