You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
digikam/digikam/libs/threadimageio/managedloadsavethread.cpp

363 lines
13 KiB

/* ============================================================
*
* This file is a part of digiKam project
* http://www.digikam.org
*
* Date : 2006-01-20
* Description : image file IO threaded interface.
*
* Copyright (C) 2005-2007 by Marcel Wiesweg <marcel.wiesweg@gmx.de>
* Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com>
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software Foundation;
* either version 2, or (at your option)
* any later version.
*
* This program 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 General Public License for more details.
*
* ============================================================ */
// Local includes.
#include "ddebug.h"
#include "managedloadsavethread.h"
#include "loadsavetask.h"
#include "previewtask.h"
namespace Digikam
{
ManagedLoadSaveThread::ManagedLoadSaveThread()
{
m_terminationPolicy = TerminationPolicyTerminateLoading;
}
ManagedLoadSaveThread::~ManagedLoadSaveThread()
{
LoadingTask *loadingTask;
switch (m_terminationPolicy)
{
case TerminationPolicyTerminateLoading:
{
TQMutexLocker lock(&m_mutex);
if ( (loadingTask = checkLoadingTask(m_currentTask, LoadingTaskFilterAll)) )
loadingTask->setStatus(LoadingTask::LoadingTaskStatusStopping);
removeLoadingTasks(LoadingDescription(TQString()), LoadingTaskFilterAll);
break;
}
case TerminationPolicyTerminatePreloading:
{
TQMutexLocker lock(&m_mutex);
if ( (loadingTask = checkLoadingTask(m_currentTask, LoadingTaskFilterPreloading)) )
loadingTask->setStatus(LoadingTask::LoadingTaskStatusStopping);
removeLoadingTasks(LoadingDescription(TQString()), LoadingTaskFilterPreloading);
break;
}
case TerminationPolicyWait:
break;
}
}
LoadingTask *ManagedLoadSaveThread::checkLoadingTask(LoadSaveTask *task, LoadingTaskFilter filter)
{
if (task && task->type() == LoadSaveTask::TaskTypeLoading)
{
LoadingTask *loadingTask = (LoadingTask *)task;
if (filter == LoadingTaskFilterAll)
return loadingTask;
else if (filter == LoadingTaskFilterPreloading)
if (loadingTask->status() == LoadingTask::LoadingTaskStatusPreloading)
return loadingTask;
}
return 0;
}
LoadingTask *ManagedLoadSaveThread::findExistingTask(const LoadingDescription &loadingDescription)
{
LoadingTask *loadingTask;
if (m_currentTask)
{
if (m_currentTask->type() == LoadSaveTask::TaskTypeLoading)
{
loadingTask = (LoadingTask *)m_currentTask;
LoadingDescription taskDescription = loadingTask->loadingDescription();
if (taskDescription == loadingDescription)
return loadingTask;
}
}
for (LoadSaveTask *task = m_todo.first(); task; task = m_todo.next())
{
if (task->type() == LoadSaveTask::TaskTypeLoading)
{
loadingTask = (LoadingTask *)task;
if (loadingTask->loadingDescription() == loadingDescription)
return loadingTask;
}
}
return 0;
}
void ManagedLoadSaveThread::setTerminationPolicy(TerminationPolicy terminationPolicy)
{
m_terminationPolicy = terminationPolicy;
}
void ManagedLoadSaveThread::load(LoadingDescription description, LoadingPolicy policy)
{
load(description, LoadingModeNormal, policy);
}
void ManagedLoadSaveThread::load(LoadingDescription description, LoadingMode loadingMode, LoadingPolicy policy, AccessMode accessMode)
{
TQMutexLocker lock(&m_mutex);
LoadingTask *loadingTask = 0;
LoadingTask *existingTask = findExistingTask(description);
//DDebug() << "ManagedLoadSaveThread::load " << description.filePath << ", policy " << policy << endl;
switch(policy)
{
case LoadingPolicyFirstRemovePrevious:
// reuse task if it exists
if (existingTask)
{
existingTask->setStatus(LoadingTask::LoadingTaskStatusLoading);
}
// stop current task
if (m_currentTask && m_currentTask != existingTask)
{
if ( (loadingTask = checkLoadingTask(m_currentTask, LoadingTaskFilterAll)) )
loadingTask->setStatus(LoadingTask::LoadingTaskStatusStopping);
}
//DDebug() << "LoadingPolicyFirstRemovePrevious, Existing task " << existingTask <<
//", m_currentTask " << m_currentTask << ", loadingTask " << loadingTask << endl;
// remove all loading tasks
for (LoadSaveTask *task = m_todo.first(); task; task = m_todo.next())
{
if (task != existingTask && checkLoadingTask(task, LoadingTaskFilterAll))
{
//DDebug() << "Removing task " << task << " from list" << endl;
m_todo.remove();
m_todo.prev();
}
}
// append new, exclusive loading task
if (existingTask)
break;
m_todo.append(createLoadingTask(description, false, loadingMode, accessMode));
break;
case LoadingPolicyPrepend:
if (existingTask)
{
existingTask->setStatus(LoadingTask::LoadingTaskStatusLoading);
}
// stop and postpone current task if it is a preloading task
if (m_currentTask)
{
if ( (loadingTask = checkLoadingTask(m_currentTask, LoadingTaskFilterPreloading)) )
{
loadingTask->setStatus(LoadingTask::LoadingTaskStatusStopping);
load(loadingTask->filePath(), LoadingPolicyPreload);
}
}
//DDebug() << "LoadingPolicyPrepend, Existing task " << existingTask << ", m_currentTask " << m_currentTask << endl;
// prepend new loading task
if (existingTask)
break;
m_todo.prepend(createLoadingTask(description, false, loadingMode, accessMode));
break;
case LoadingPolicyAppend:
if (existingTask)
{
existingTask->setStatus(LoadingTask::LoadingTaskStatusLoading);
}
// stop and postpone current task if it is a preloading task
if (m_currentTask)
{
if ( (loadingTask = checkLoadingTask(m_currentTask, LoadingTaskFilterPreloading)) )
{
loadingTask->setStatus(LoadingTask::LoadingTaskStatusStopping);
load(loadingTask->filePath(), LoadingPolicyPreload);
}
}
if (existingTask)
break;
//DDebug() << "LoadingPolicyAppend, Existing task " << existingTask << ", m_currentTask " << m_currentTask << endl;
// append new loading task, put it in front of preloading tasks
for (uint i = 0; i<m_todo.count(); i++)
{
LoadSaveTask *task = m_todo.at(i);
if ( (loadingTask = checkLoadingTask(task, LoadingTaskFilterPreloading)) )
{
m_todo.insert(i, createLoadingTask(description, false, loadingMode, accessMode));
break;
}
}
break;
case LoadingPolicyPreload:
// append to the very end of the list
//DDebug() << "LoadingPolicyPreload, Existing task " << existingTask << endl;
if (existingTask)
break;
m_todo.append(createLoadingTask(description, true, loadingMode, accessMode));
break;
}
m_condVar.wakeAll();
}
void ManagedLoadSaveThread::loadPreview(LoadingDescription description)
{
// This is similar to the LoadingPolicyFirstRemovePrevious policy with normal loading tasks.
// Preview threads typically only support preview tasks,
// so no need to differentiate with normal loading tasks.
TQMutexLocker lock(&m_mutex);
LoadingTask *loadingTask = 0;
LoadingTask *existingTask = findExistingTask(description);
// reuse task if it exists
if (existingTask)
{
existingTask->setStatus(LoadingTask::LoadingTaskStatusLoading);
}
// stop current task
if (m_currentTask && m_currentTask != existingTask)
{
if ( (loadingTask = checkLoadingTask(m_currentTask, LoadingTaskFilterAll)) )
loadingTask->setStatus(LoadingTask::LoadingTaskStatusStopping);
}
// remove all loading tasks
for (LoadSaveTask *task = m_todo.first(); task; task = m_todo.next())
{
if (task != existingTask && checkLoadingTask(task, LoadingTaskFilterAll))
{
m_todo.remove();
m_todo.prev();
}
}
//DDebug()<<"loadPreview for " << description.filePath << " existingTask " << existingTask << " currentTask " << m_currentTask << endl;
// append new loading task
if (existingTask)
return;
m_todo.append(new PreviewLoadingTask(this, description));
m_condVar.wakeAll();
}
LoadingTask *ManagedLoadSaveThread::createLoadingTask(const LoadingDescription &description,
bool preloading, LoadingMode loadingMode, AccessMode accessMode)
{
if (loadingMode == LoadingModeShared)
{
if (preloading)
return new SharedLoadingTask(this, description, accessMode, LoadingTask::LoadingTaskStatusPreloading);
else
return new SharedLoadingTask(this, description, accessMode);
}
else
{
if (preloading)
return new LoadingTask(this, description, LoadingTask::LoadingTaskStatusPreloading);
else
return new LoadingTask(this, description);
}
}
void ManagedLoadSaveThread::stopLoading(const TQString& filePath, LoadingTaskFilter filter)
{
TQMutexLocker lock(&m_mutex);
removeLoadingTasks(LoadingDescription(filePath), filter);
}
void ManagedLoadSaveThread::stopLoading(const LoadingDescription& desc, LoadingTaskFilter filter)
{
TQMutexLocker lock(&m_mutex);
removeLoadingTasks(desc, filter);
}
void ManagedLoadSaveThread::stopSaving(const TQString& filePath)
{
TQMutexLocker lock(&m_mutex);
// stop current task if it is matching the criteria
if (m_currentTask && m_currentTask->type() == LoadSaveTask::TaskTypeSaving)
{
SavingTask *savingTask = (SavingTask *)m_currentTask;
if (filePath.isNull() || savingTask->filePath() == filePath)
{
savingTask->setStatus(SavingTask::SavingTaskStatusStopping);
}
}
// remove relevant tasks from list
for (LoadSaveTask *task = m_todo.first(); task; task = m_todo.next())
{
if (task->type() == LoadSaveTask::TaskTypeSaving)
{
SavingTask *savingTask = (SavingTask *)m_currentTask;
if (filePath.isNull() || savingTask->filePath() == filePath)
{
m_todo.remove();
m_todo.prev();
}
}
}
}
void ManagedLoadSaveThread::removeLoadingTasks(const LoadingDescription &description, LoadingTaskFilter filter)
{
LoadingTask *loadingTask;
// stop current task if it is matching the criteria
if ( (loadingTask = checkLoadingTask(m_currentTask, filter)) )
{
if (description.filePath.isNull() || loadingTask->loadingDescription() == description)
{
loadingTask->setStatus(LoadingTask::LoadingTaskStatusStopping);
}
}
// remove relevant tasks from list
for (LoadSaveTask *task = m_todo.first(); task; task = m_todo.next())
{
if ( (loadingTask = checkLoadingTask(task, filter)) )
{
if (description.filePath.isNull() || loadingTask->loadingDescription() == description)
{
m_todo.remove();
m_todo.prev();
}
}
}
}
void ManagedLoadSaveThread::save(DImg &image, const TQString& filePath, const TQString &format)
{
TQMutexLocker lock(&m_mutex);
LoadingTask *loadingTask;
// stop and postpone current task if it is a preloading task
if (m_currentTask && (loadingTask = checkLoadingTask(m_currentTask, LoadingTaskFilterPreloading)))
{
loadingTask->setStatus(LoadingTask::LoadingTaskStatusStopping);
load(loadingTask->filePath(), LoadingPolicyPreload);
}
// append new loading task, put it in front of preloading tasks
uint i;
for (i = 0; i<m_todo.count(); i++)
{
LoadSaveTask *task = m_todo.at(i);
if ( (loadingTask = checkLoadingTask(task, LoadingTaskFilterPreloading)) )
break;
}
m_todo.insert(i, new SavingTask(this, image, filePath, format));
}
} // namespace Digikam