Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

'Done' Button Implementation #2177

Merged
merged 20 commits into from
Sep 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion tomviz/ProgressDialogManager.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,23 @@ void ProgressDialogManager::operationStarted()
layout->addWidget(progressBar);
}
layout->addWidget(progressWidget);
if (op->supportsCancelingMidTransform()) {
if (op->supportsCompletionMidTransform()) {
// Unless widget has custom progress handling, can't done it
QDialogButtonBox* dialogButtons =
new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel,
Qt::Horizontal, progressDialog);

layout->addWidget(dialogButtons);
QObject::connect(progressDialog, &QDialog::rejected, op,
&Operator::cancelTransform);
QObject::connect(dialogButtons, &QDialogButtonBox::rejected, progressDialog,
&QDialog::reject);

QObject::connect(progressDialog, &QDialog::accepted, op,
&Operator::completionTransform);
QObject::connect(dialogButtons, &QDialogButtonBox::accepted, progressDialog,
&QDialog::accept);
} else if (op->supportsCancelingMidTransform()) {
// Unless the widget has custom progress handling, you can't cancel it.
QDialogButtonBox* dialogButtons = new QDialogButtonBox(
QDialogButtonBox::Cancel, Qt::Horizontal, progressDialog);
Expand Down
2 changes: 2 additions & 0 deletions tomviz/core/OperatorProxyBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ class OperatorProxyBase

virtual bool canceled() = 0;

virtual bool completed() = 0;

virtual void setTotalProgressSteps(int progress) = 0;

virtual int totalProgressSteps() = 0;
Expand Down
6 changes: 6 additions & 0 deletions tomviz/operators/Operator.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -217,4 +217,10 @@ void Operator::cancelTransform()
m_state = OperatorState::Canceled;
emit transformCanceled();
}

void Operator::completionTransform()
{
m_state = OperatorState::Complete;
emit transformCompleted();
}
} // namespace tomviz
25 changes: 25 additions & 0 deletions tomviz/operators/Operator.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,12 @@ class Operator : public QObject
/// can be set by the setSupportsCancel(bool) method by subclasses.
bool supportsCancelingMidTransform() const { return m_supportsCancel; }

/// Returns true if the operation supports early completion midway through the
/// applyTransform function via the cancelTransform slot.
/// Defaults to false, can be set by the setSupportsCompletion(bool)
/// method by subclasses.
bool supportsCompletionMidTransform() const { return m_supportsCompletion; }

/// Return the total number of progress updates (assuming each update
/// increments the progress from 0 to some maximum. If the operator doesn't
/// support incremental progress updates, leave value set to zero
Expand Down Expand Up @@ -234,13 +240,24 @@ class Operator : public QObject
// a request to cancel this operator has been issued.
void transformCanceled();

// Emitted when the operator is accepted before reaching a completed
// transform. The operator will still be running, so there has to be
// a request to cancel the operator as well as encourage the next
// operator to run.
void transformCompleted();

public slots:
/// Called when the 'Cancel' button is pressed on the progress dialog.
/// Subclasses overriding this method should call the base implementation
/// to ensure the operator is marked as canceled.
/// TODO: Not sure we need this/want this virtual anymore?
virtual void cancelTransform();
virtual void completionTransform();
bool isCanceled() { return m_state == OperatorState::Canceled; }

/// Distinction between this and isFinished is necessary to prevent cascading
/// errors
bool isCompleted() { return m_state == OperatorState::Complete; }
bool isFinished()
{
return m_state == OperatorState::Complete ||
Expand Down Expand Up @@ -274,11 +291,19 @@ protected slots:
/// the cancelTransform slot to listen for the cancel signal and handle it.
void setSupportsCancel(bool b) { m_supportsCancel = b; }

/// Method to set whether the operator supports early completion midway
/// through the transform method call.
/// If you set this to true, you should also override the
/// completionTransform slot to listen for the done signal and handle
/// it.
void setSupportsCompletion(bool b) { m_supportsCompletion = b; }

private:
Q_DISABLE_COPY(Operator)

QList<OperatorResult*> m_results;
bool m_supportsCancel = false;
bool m_supportsCompletion = false;
bool m_hasChildDataSource = false;
bool m_modified = true;
bool m_new = true;
Expand Down
5 changes: 5 additions & 0 deletions tomviz/operators/OperatorProxy.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ bool OperatorProxy::canceled()
return m_op->isCanceled();
}

bool OperatorProxy::completed()
{
return m_op->isCompleted();
}

void OperatorProxy::setTotalProgressSteps(int progress)
{
m_op->setTotalProgressSteps(progress);
Expand Down
2 changes: 2 additions & 0 deletions tomviz/operators/OperatorProxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ class OperatorProxy : public OperatorProxyBase

bool canceled() override;

bool completed() override;

void setTotalProgressSteps(int progress) override;

int totalProgressSteps() override;
Expand Down
15 changes: 15 additions & 0 deletions tomviz/operators/OperatorPython.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ class OperatorPython::OPInternals
Python::Module InternalModule;
Python::Function FindTransformFunction;
Python::Function IsCancelableFunction;
Python::Function IsCompletableFunction;
Python::Function DeleteModuleFunction;
};

Expand All @@ -160,6 +161,12 @@ OperatorPython::OperatorPython(DataSource* parentObject)
qCritical() << "Unable to locate is_cancelable.";
}

d->IsCompletableFunction = d->InternalModule.findFunction("is_completable");
if (!d->IsCompletableFunction.isValid()) {
qCritical() << "Unable to locate is_completable.";
return;
}

d->FindTransformFunction =
d->InternalModule.findFunction("find_transform_function");
if (!d->FindTransformFunction.isValid()) {
Expand Down Expand Up @@ -313,6 +320,7 @@ void OperatorPython::setScript(const QString& str)
m_script = str;

Python::Object result;
Python::Object resultComplete;
{
Python python;
QString moduleName = QString("tomviz_%1").arg(label());
Expand Down Expand Up @@ -353,9 +361,16 @@ void OperatorPython::setScript(const QString& str)
qCritical("Error calling is_cancelable.");
return;
}

resultComplete = d->IsCompletableFunction.call(isArgs);
if (!resultComplete.isValid()) {
qCritical("Error calling is_completable.");
return;
}
}

setSupportsCancel(result.toBool());
setSupportsCompletion(resultComplete.toBool());

emit transformModified();
}
Expand Down
5 changes: 5 additions & 0 deletions tomviz/pybind11/OperatorPythonWrapper.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ bool OperatorPythonWrapper::canceled()
return m_op->canceled();
}

bool OperatorPythonWrapper::completed()
{
return m_op->completed();
}

void OperatorPythonWrapper::setTotalProgressSteps(int progress)
{
m_op->setTotalProgressSteps(progress);
Expand Down
1 change: 1 addition & 0 deletions tomviz/pybind11/OperatorPythonWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ struct OperatorPythonWrapper
{
OperatorPythonWrapper(void* o);
bool canceled();
bool completed();
void setTotalProgressSteps(int progress);
int totalProgressSteps();
void setProgressStep(int progress);
Expand Down
1 change: 1 addition & 0 deletions tomviz/pybind11/Wrapping.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ PYBIND11_PLUGIN(_wrapping)
py::class_<OperatorPythonWrapper>(m, "OperatorPythonWrapper")
.def(py::init([](void* op) { return new OperatorPythonWrapper(op); }))
.def_property_readonly("canceled", &OperatorPythonWrapper::canceled)
.def_property_readonly("completed", &OperatorPythonWrapper::completed)
.def_property("progress_maximum",
&OperatorPythonWrapper::totalProgressSteps,
&OperatorPythonWrapper::setTotalProgressSteps)
Expand Down
8 changes: 7 additions & 1 deletion tomviz/python/Recon_ART.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import time


class ReconARTOperator(tomviz.operators.CancelableOperator):
class ReconARTOperator(tomviz.operators.CompletableOperator):

def transform(self, dataset, Niter=1, Nupdates=0, beta=1.0):
"""
Expand Down Expand Up @@ -58,9 +58,15 @@ def transform(self, dataset, Niter=1, Nupdates=0, beta=1.0):
counter = 1
for i in range(Niter):

if self.completed:
break

for s in range(Nslice):
if self.canceled:
return
elif self.completed:
break

self.progress.message = 'Iteration No.%d/%d,Slice No.%d/%d.' % (
i + 1, Niter, s + 1, Nslice) + etcMessage

Expand Down
2 changes: 1 addition & 1 deletion tomviz/python/Recon_DFT.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def transform(self, dataset):
sz = abs(np.floor(kz_new) - kz_new)
for b in range(1, 5): #bilinear extrapolation
pz, py, weight = bilinear(kz_new, ky_new, sz, sy, Ny, b)
if (py >= 0 and py < Ny and pz >= 0 and pz < np.floor( Nz / 2 + 1 )):
if 0 <= py < Ny and 0 <= pz < np.floor(Nz / 2 + 1):
w[:, py, pz] = w[:, py, pz] + weight
v[:, py, pz] = v[:, py, pz] + \
weight * pF[:, i]
Expand Down
8 changes: 7 additions & 1 deletion tomviz/python/Recon_SIRT.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import time


class ReconSirtOperator(tomviz.operators.CancelableOperator):
class ReconSirtOperator(tomviz.operators.CompletableOperator):

def transform(self, dataset, Niter=10, stepSize=0.0001,
updateMethodIndex=0, Nupdates=0):
Expand Down Expand Up @@ -65,9 +65,15 @@ def transform(self, dataset, Niter=10, stepSize=0.0001,

for i in range(Niter):

if self.completed:
break

for s in range(Nslice):

if self.canceled:
return
elif self.completed:
break

self.progress.message = 'Iteration No.%d/%d,Slice No.%d/%d.' % (
i + 1, Niter, s + 1, Nslice) + etcMessage
Expand Down
9 changes: 7 additions & 2 deletions tomviz/python/Recon_TV_minimization.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
import time


class ReconTVOperator(tomviz.operators.CancelableOperator):
class ReconTVOperator(tomviz.operators.CompletableOperator):

def transform(self, dataset, Niter=10, Nupdates=0):
def transform(self, dataset, Niter=10, Nupdates=0): # noqa: C901
"""3D Reconstruct from a tilt series using simple TV minimzation"""
self.progress.maximum = 1

Expand Down Expand Up @@ -55,12 +55,17 @@ def transform(self, dataset, Niter=10, Nupdates=0):

for i in range(Niter): #main loop

if self.completed:
break

recon_temp = recon.copy()

#ART recon
for s in range(Nslice): #
if self.canceled: #In case canceled during ART.
return
elif self.completed:
break

self.progress.message = 'Slice No.%d/%d, Iteration No.%d/%d. '\
% (s + 1, Nslice, i + 1, Niter) + etcMessage
Expand Down
14 changes: 14 additions & 0 deletions tomviz/python/tomviz/_internal.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,20 @@ def is_cancelable(transform_module):
tomviz.operators.CancelableOperator)


def is_completable(transform_module):
cls = find_operator_class(transform_module)

if cls is None:
function = find_transform_from_module(transform_module)
if not function:
raise Exception('Unable to locate function or operator class.')

return cls is not None and issubclass(
cls,
tomviz.operators.CompletableOperator
)


def find_transform_function(transform_module, op=None):

transform_function = find_transform_from_module(transform_module)
Expand Down
18 changes: 18 additions & 0 deletions tomviz/python/tomviz/operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,21 @@ def canceled(self):
:returns True if the operator has been canceled, False otherwise.
"""
return self._operator_wrapper.canceled


class CompletableOperator(CancelableOperator):
"""
A completable operator allows a user to interrupt the execution of
an operator using either "cancel" or "complete". The
completable property can be used in the transform(...) method to break out
when an operator is finished early, like if an iterative algorithm is a
reasonable quality before the designated iterations are reached. Use
similar to "cancel", but be sure to return data.
"""
@property
def completed(self):
"""
:returns True if the operator is early completed (from Button),
False otherwise
"""
return self._operator_wrapper.completed