Skip to content

Commit

Permalink
Merge pull request #4243 from Black09/directoryprovider-extensions
Browse files Browse the repository at this point in the history
Better caching and updating for dynamic list provider
  • Loading branch information
jmarshallnz committed Feb 28, 2014
2 parents 871acc7 + 6c22dd5 commit 3ada898
Show file tree
Hide file tree
Showing 9 changed files with 174 additions and 49 deletions.
14 changes: 9 additions & 5 deletions xbmc/guilib/GUIBaseContainer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -800,18 +800,22 @@ void CGUIBaseContainer::AllocResources()
{
CGUIControl::AllocResources();
CalculateLayout();
UpdateListProvider(true);
if (m_listProvider)
{
UpdateListProvider(true);
SelectItem(m_listProvider->GetDefaultItem());
}
}

void CGUIBaseContainer::FreeResources(bool immediately)
{
CGUIControl::FreeResources(immediately);
if (m_listProvider)
{
Reset();
m_listProvider->Reset();
if (immediately)
Reset();

m_listProvider->Reset(immediately);
}
m_scroller.Stop();
}
Expand Down Expand Up @@ -867,11 +871,11 @@ void CGUIBaseContainer::UpdateVisibility(const CGUIListItem *item)
UpdateListProvider();
}

void CGUIBaseContainer::UpdateListProvider(bool refreshItems)
void CGUIBaseContainer::UpdateListProvider(bool forceRefresh /* = false */)
{
if (m_listProvider)
{
if (m_listProvider->Update(refreshItems))
if (m_listProvider->Update(forceRefresh))
{
// save the current item
int currentItem = GetSelectedItem();
Expand Down
2 changes: 1 addition & 1 deletion xbmc/guilib/GUIBaseContainer.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ class CGUIBaseContainer : public IGUIContainer
virtual int GetCurrentPage() const;
bool InsideLayout(const CGUIListItemLayout *layout, const CPoint &point) const;
virtual void OnFocus();
void UpdateListProvider(bool refreshItems = false);
void UpdateListProvider(bool forceRefresh = false);

int ScrollCorrectionRange() const;
inline float Size() const;
Expand Down
151 changes: 117 additions & 34 deletions xbmc/listproviders/DirectoryProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,28 +26,25 @@
#include "utils/StringUtils.h"
#include "utils/TimeUtils.h"
#include "utils/XMLUtils.h"
#include "utils/StringUtils.h"
#include "utils/URIUtils.h"
#include "utils/log.h"
#include "threads/SingleLock.h"
#include "ApplicationMessenger.h"
#include "FileItem.h"
#include "video/VideoThumbLoader.h"
#include "music/MusicThumbLoader.h"
#include "pictures/PictureThumbLoader.h"
#include "boost/make_shared.hpp"
#include "interfaces/AnnouncementManager.h"

using namespace std;
using namespace XFILE;
using namespace ANNOUNCEMENT;

class CDirectoryJob : public CJob
{
public:
typedef enum
{
VIDEO,
AUDIO,
PICTURE,
PROGRAM
} InfoTagType;

CDirectoryJob(const std::string &url, int parentID) : m_url(url), m_parentID(parentID) { };
virtual ~CDirectoryJob() {};

Expand Down Expand Up @@ -105,7 +102,7 @@ class CDirectoryJob : public CJob
initThumbLoader<CProgramThumbLoader>(PROGRAM);
return m_thumbloaders[PROGRAM];
}

template<class CThumbLoaderClass>
void initThumbLoader(InfoTagType type)
{
Expand All @@ -119,6 +116,14 @@ class CDirectoryJob : public CJob

const std::vector<CGUIStaticItemPtr> &GetItems() const { return m_items; }
const std::string &GetTarget() const { return m_target; }
std::vector<InfoTagType> GetItemTypes(std::vector<InfoTagType> &itemTypes) const
{
itemTypes.clear();
for (std::map<InfoTagType, boost::shared_ptr<CThumbLoader> >::const_iterator
i = m_thumbloaders.begin(); i != m_thumbloaders.end(); ++i)
itemTypes.push_back(i->first);
return itemTypes;
}
private:
std::string m_url;
std::string m_target;
Expand All @@ -130,11 +135,12 @@ class CDirectoryJob : public CJob
CDirectoryProvider::CDirectoryProvider(const TiXmlElement *element, int parentID)
: IListProvider(parentID),
m_updateTime(0),
m_invalid(false),
m_updateState(OK),
m_isDbUpdating(false),
m_isAnnounced(false),
m_jobID(0)
{
assert(element);

if (!element->NoChildren())
{
const char *target = element->Attribute("target");
Expand All @@ -146,36 +152,69 @@ CDirectoryProvider::CDirectoryProvider(const TiXmlElement *element, int parentID

CDirectoryProvider::~CDirectoryProvider()
{
Reset();
Reset(true);
}

bool CDirectoryProvider::Update(bool refresh)
bool CDirectoryProvider::Update(bool forceRefresh)
{
bool changed = refresh;
// we never need to force refresh here
bool changed = false;
bool fireJob = false;
{
CSingleLock lock(m_section);
changed |= m_invalid;
m_invalid = false;
if (m_updateState == DONE)
changed = true;
else if (m_updateState == PENDING)
fireJob = true;
m_updateState = OK;
}

// update the URL and fire off a new job if needed
CStdString value(m_url.GetLabel(m_parentID, false));
if (value != m_currentUrl)
{
m_currentUrl = value;

// fire job
CSingleLock lock(m_section);
if (m_jobID)
CJobManager::GetInstance().CancelJob(m_jobID);
m_jobID = CJobManager::GetInstance().AddJob(new CDirectoryJob(m_currentUrl, m_parentID), this);
}
if (fireJob || UpdateURL())
FireJob();

for (vector<CGUIStaticItemPtr>::iterator i = m_items.begin(); i != m_items.end(); ++i)
changed |= (*i)->UpdateVisibility(m_parentID);
return changed; // TODO: Also returned changed if properties are changed (if so, need to update scroll to letter).
}

void CDirectoryProvider::Announce(AnnouncementFlag flag, const char *sender, const char *message, const CVariant &data)
{
// we are only interested in library changes
if ((flag & (VideoLibrary | AudioLibrary)) == 0)
return;

{
CSingleLock lock(m_section);
// we don't need to refresh anything if there are no fitting
// items in this list provider for the announcement flag
if (((flag & VideoLibrary) &&
(std::find(m_itemTypes.begin(), m_itemTypes.end(), VIDEO) == m_itemTypes.end())) ||
((flag & AudioLibrary) &&
(std::find(m_itemTypes.begin(), m_itemTypes.end(), AUDIO) == m_itemTypes.end())))
return;

// don't update while scanning / cleaning
if (strcmp(message, "OnScanStarted") == 0 ||
strcmp(message, "OnCleanStarted") == 0)
{
m_isDbUpdating = true;
return;
}

// if there was a database update, we set the update state
// to PENDING to fire off a new job in the next update
if (strcmp(message, "OnScanFinished") == 0 ||
strcmp(message, "OnCleanFinished") == 0 ||
((strcmp(message, "OnUpdate") == 0 ||
strcmp(message, "OnRemove") == 0) && !m_isDbUpdating))
{
m_isDbUpdating = false;
m_updateState = PENDING;
}
}
}

void CDirectoryProvider::Fetch(vector<CGUIListItemPtr> &items) const
{
CSingleLock lock(m_section);
Expand All @@ -187,17 +226,23 @@ void CDirectoryProvider::Fetch(vector<CGUIListItemPtr> &items) const
}
}

void CDirectoryProvider::Reset()
void CDirectoryProvider::Reset(bool immediately /* = false */)
{
// cancel any pending jobs
CSingleLock lock(m_section);
if (m_jobID)
CJobManager::GetInstance().CancelJob(m_jobID);
m_jobID = 0;
m_items.clear();
m_currentTarget.clear();
m_currentUrl.clear();
m_invalid = false;
// reset only if this is going to be destructed
if (immediately)
{
m_items.clear();
m_currentTarget.clear();
m_currentUrl.clear();
m_itemTypes.clear();
m_updateState = OK;
RegisterListProvider(false);
}
}

void CDirectoryProvider::OnJobComplete(unsigned int jobID, bool success, CJob *job)
Expand All @@ -207,7 +252,8 @@ void CDirectoryProvider::OnJobComplete(unsigned int jobID, bool success, CJob *j
{
m_items = ((CDirectoryJob*)job)->GetItems();
m_currentTarget = ((CDirectoryJob*)job)->GetTarget();
m_invalid = true;
((CDirectoryJob*)job)->GetItemTypes(m_itemTypes);
m_updateState = DONE;
}
m_jobID = 0;
}
Expand Down Expand Up @@ -237,5 +283,42 @@ bool CDirectoryProvider::OnClick(const CGUIListItemPtr &item)
bool CDirectoryProvider::IsUpdating() const
{
CSingleLock lock(m_section);
return m_jobID || m_invalid;
return m_jobID || (m_updateState == DONE);
}

void CDirectoryProvider::FireJob()
{
CSingleLock lock(m_section);
if (m_jobID)
CJobManager::GetInstance().CancelJob(m_jobID);
m_jobID = CJobManager::GetInstance().AddJob(new CDirectoryJob(m_currentUrl, m_parentID), this);
}

void CDirectoryProvider::RegisterListProvider(bool hasLibraryContent)
{
if (hasLibraryContent && !m_isAnnounced)
{
m_isAnnounced = true;
CAnnouncementManager::AddAnnouncer(this);
}
else if (!hasLibraryContent && m_isAnnounced)
{
m_isAnnounced = false;
m_isDbUpdating = false;
CAnnouncementManager::RemoveAnnouncer(this);
}
}

bool CDirectoryProvider::UpdateURL()
{
CStdString value(m_url.GetLabel(m_parentID, false));
if (value == m_currentUrl)
return false;

m_currentUrl = value;

// Register this provider only if we have library content
RegisterListProvider(URIUtils::IsLibraryContent(m_currentUrl));

return true;
}
36 changes: 32 additions & 4 deletions xbmc/listproviders/DirectoryProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,31 +25,59 @@
#include "guilib/GUIStaticItem.h"
#include "utils/Job.h"
#include "threads/CriticalSection.h"
#include "interfaces/IAnnouncer.h"

class TiXmlElement;

class CDirectoryProvider : public IListProvider, public IJobCallback
typedef enum
{
VIDEO,
AUDIO,
PICTURE,
PROGRAM
} InfoTagType;

class CDirectoryProvider :
public IListProvider,
public IJobCallback,
public ANNOUNCEMENT::IAnnouncer
{
public:
typedef enum
{
OK,
PENDING,
DONE
} UpdateState;

CDirectoryProvider(const TiXmlElement *element, int parentID);
virtual ~CDirectoryProvider();

virtual bool Update(bool refresh);
virtual bool Update(bool forceRefresh);
virtual void Announce(ANNOUNCEMENT::AnnouncementFlag flag, const char *sender, const char *message, const CVariant &data);
virtual void Fetch(std::vector<CGUIListItemPtr> &items) const;
virtual void Reset();
virtual void Reset(bool immediately = false);
virtual bool OnClick(const CGUIListItemPtr &item);
virtual bool IsUpdating() const;

// callback from directory job
virtual void OnJobComplete(unsigned int jobID, bool success, CJob *job);
private:
unsigned int m_updateTime;
bool m_invalid;
UpdateState m_updateState;
bool m_isDbUpdating;
bool m_isAnnounced;
unsigned int m_jobID;
CGUIInfoLabel m_url;
CGUIInfoLabel m_target;
std::string m_currentUrl;
std::string m_currentTarget; ///< \brief node.target property on the list as a whole
std::vector<CGUIStaticItemPtr> m_items;
std::vector<InfoTagType> m_itemTypes;
CCriticalSection m_section;

void FireJob();
void RegisterListProvider(bool hasLibraryContent);
bool UpdateURL();
static bool HasLibraryContent(const std::string &url);
};
5 changes: 3 additions & 2 deletions xbmc/listproviders/IListProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class IListProvider
/*! \brief Update the list content
\return true if the content has changed, false otherwise.
*/
virtual bool Update(bool refresh)=0;
virtual bool Update(bool forceRefresh)=0;

/*! \brief Fetch the current list of items.
\param items [out] the list to be filled.
Expand All @@ -61,8 +61,9 @@ class IListProvider

/*! \brief Reset the current list of items.
Derived classes may choose to ignore this.
\param immediately whether the content of the provider should be cleared.
*/
virtual void Reset() {};
virtual void Reset(bool immediately = false) {};

/*! \brief Click event on an item.
\param item the item that was clicked.
Expand Down
4 changes: 2 additions & 2 deletions xbmc/listproviders/StaticProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ CStaticListProvider::~CStaticListProvider()
{
}

bool CStaticListProvider::Update(bool refresh)
bool CStaticListProvider::Update(bool forceRefresh)
{
bool changed = refresh;
bool changed = forceRefresh;
if (!m_updateTime)
m_updateTime = CTimeUtils::GetFrameTime();
else if (CTimeUtils::GetFrameTime() - m_updateTime > 1000)
Expand Down
2 changes: 1 addition & 1 deletion xbmc/listproviders/StaticProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class CStaticListProvider : public IListProvider
CStaticListProvider(const std::vector<CGUIStaticItemPtr> &items); // for python
virtual ~CStaticListProvider();

virtual bool Update(bool refresh);
virtual bool Update(bool forceRefresh);
virtual void Fetch(std::vector<CGUIListItemPtr> &items) const;
virtual bool OnClick(const CGUIListItemPtr &item);
virtual void SetDefaultItem(int item, bool always);
Expand Down
Loading

0 comments on commit 3ada898

Please sign in to comment.