/**
* Copyright (c) 2014 - 2017 Frank Appel
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Frank Appel - initial API and implementation
*/
package com.codeaffine.eclipse.swt.widget.scrollable;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.widgets.Display;
import com.codeaffine.eclipse.swt.util.ActionScheduler;
import com.codeaffine.eclipse.swt.widget.scrollable.context.AdaptionContext;
import com.codeaffine.eclipse.swt.widget.scrollable.context.Reconciliation;
class WatchDog implements Runnable, DisposeListener {
static final int DELAY = 50;
private final NestingStructurePreserver nestingStructurePresever;
private final StructureScrollableRedrawInsurance structureScrollableRedrawInsurance;
private final ScrollBarUpdater horizontalBarUpdater;
private final ScrollBarUpdater verticalBarUpdater;
private final Reconciliation reconciliation;
private final Visibility vScrollVisibility;
private final Visibility hScrollVisibility;
private final LayoutTrigger layoutTrigger;
private final SizeObserver sizeObserver;
private final ActionScheduler scheduler;
AdaptionContext<?> context;
boolean layoutInitialized;
boolean disposed;
WatchDog( AdaptionContext<?> context,
ScrollBarUpdater horizontalUpdater,
ScrollBarUpdater verticalUpdater,
SizeObserver sizeObserver )
{
this( context,
horizontalUpdater,
verticalUpdater,
new Visibility( SWT.HORIZONTAL ),
new Visibility( SWT.VERTICAL ),
null,
new LayoutTrigger( context.getAdapter() ),
sizeObserver,
context.getReconciliation(),
new NestingStructurePreserver( context ),
new StructureScrollableRedrawInsurance( context.getScrollable() ) );
}
WatchDog( AdaptionContext<?> context,
ScrollBarUpdater horizontalBarUpdater,
ScrollBarUpdater verticalBarUpdater,
Visibility hScrollVisibility,
Visibility vScrollVisibility,
ActionScheduler actionScheduler,
LayoutTrigger layoutTrigger,
SizeObserver sizeObserver,
Reconciliation reconciliation,
NestingStructurePreserver nestingPresever,
StructureScrollableRedrawInsurance structureScrollableRedrawInsurance )
{
this.context = context;
this.horizontalBarUpdater = horizontalBarUpdater;
this.verticalBarUpdater = verticalBarUpdater;
this.hScrollVisibility = hScrollVisibility;
this.vScrollVisibility = vScrollVisibility;
this.nestingStructurePresever = nestingPresever;
this.structureScrollableRedrawInsurance = structureScrollableRedrawInsurance;
this.scheduler = ensureScheduler( actionScheduler );
this.reconciliation = reconciliation;
this.layoutTrigger = layoutTrigger;
this.sizeObserver = sizeObserver;
scheduler.schedule( DELAY );
}
@Override
public void widgetDisposed( DisposeEvent e ) {
disposed = true;
}
@Override
public void run() {
if( !disposed ) {
runWithReconciliationSuspended();
scheduler.schedule( DELAY );
}
}
private void runWithReconciliationSuspended() {
reconciliation.runWhileSuspended( () -> doRun() );
}
private void doRun() {
context.updatePreferredSize();
context = context.newContext();
if( mustLayout() ) {
layoutTrigger.pull();
context = context.newContext();
}
sizeObserver.update( context );
vScrollVisibility.update( context );
hScrollVisibility.update( context );
if( vScrollVisibility.isVisible() ) {
verticalBarUpdater.update();
}
if( hScrollVisibility.isVisible() ) {
horizontalBarUpdater.update();
}
nestingStructurePresever.run();
structureScrollableRedrawInsurance.run();
}
private boolean mustLayout() {
boolean result = !layoutInitialized
|| vScrollVisibility.hasChanged( context )
|| hScrollVisibility.hasChanged( context )
|| sizeObserver.mustLayoutAdapter( context );
layoutInitialized = true;
return result;
}
private ActionScheduler ensureScheduler( ActionScheduler actionScheduler ) {
return actionScheduler == null ? new ActionScheduler( Display.getDefault(), this ) : actionScheduler;
}
}