Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Plugins drop progress dialog #1281

Merged
merged 7 commits into from

4 participants

@jmarshallnz
Owner

There's currently an issue with layered dialogs where a plugin throws up a keyboard dialog for search and the like. The dialogs involved are:

  1. Busy dialog from CDirectory::GetDirectory.
  2. Progress dialog from CPluginDirectory::WaitForScriptResult.
  3. Keyboard dialog from plugin.

The problem case is where the progress pops up after the keyboard dialog is on screen, which often happens in plugins which implement a search feature, such as youtube.

This fixes it by eliminating the progress dialog**. This isn't ideal, as we lose the progress from the plugin (such as number of items to retrieve, and progress retrieving them). I'm not sure whether or not many plugins use this or not. IMO extending busy would be a nicer way to handle this either way - plugins that take a lot of time can throw up the progress themselves should they wish to (some already do). One disadvantage with this is that it's not necessarily obvious that it can be cancelled perhaps?

An alternate fix would be to stop the progress popping up if another modal dialog pops up. Trouble with this is it's hard to determine this case nicely inside the PluginDirectory class, as the app loop is running at this point, and thus there's potential races during tests for modal dialogs, as well as the busy gets in the way.

Yet another alternate might be that the progress stuff is moved into CDirectory::GetDirectory if the directory class can be cancelled.

Comments/criticisms welcome.

**Note that we don't have the same issues with busy being on screen, as it's automatically hidden when another dialog pops up over the top of it, and also the keyboard dialog can't pop up until it's on screen, which guarantees the keyboard is on top, thus receives input.

@ghost

i see no way around this. question becomes if we should allow some backwards compat here (spec'd in addon.xml). i.e. anything running under py 2.0/1.0 will get their dialog unless specified? bit counter-productive as the bug may very well bite in those plugins, but still this is a rather harsh behaviour change...

@pieh
Collaborator

How about something like this pieh@247cdd5 ? (messy as this is just draft). It re-adds progress dialog that runs instead of busy dialog in CDirectory::GetDirectory on gui thread. Most important part are changes to IDirectory (did my best to comment them doxy style in IDirectory.h but I defenitely suck at doing that ;P)

Note: this patch is addition to commits in this PR - not usable in master

This doesn't solve plugins trying to spit their own progress dialog, dunno if we need to fix it just here or globaly (active GUIWindow being taken over by something else)

@jmarshallnz
Owner

Given that the only info we're displaying is the progress percentage, the interface could be simpler to just include that percentage, and then you could drop the lock. Also, we could potentially hook it up to the busy dialog, which is possibly a bit lighter, and doesn't have the issue with clashing with the progress. I think the existing busy could just have a percentage added to it (progress or label) easily enough without breaking skins.

@Jezz_X your thoughts?

@pieh
Collaborator

Currently we're also displaying script name in heading, "Loading directory" in first line and "Retrieved %i items" in last line, but I guess we can just drop them as they're not essential.

That struct was meant to be used generally with GUIDialogProgress so that's why I stuffed percentage,heading and lines there and placed it in IProgressCallback.h.

And as I said, this was just a draft (now i even see that I forgot to update percentage, but still updating line with items loaded count) - my main idea was to pass progress info from IDirectory to CDirectory::GetDirectory(). What dialog, how much progress info to pass? That's up to You guys.

@jmarshallnz
Owner

I like the idea of allowing feedback, but IMO the busy would work better than the main dialog overall:

Advantages:

  1. Much lighter weight.
  2. Doesn't have issue with progresses that python or other VFS's might throw up.
  3. Doesn't require progress should the VFS not provide it.
  4. Simpler code (no locking required on the progress, a single new (const) function to IDirectory to get progress).

Disadvantages:

  1. Skin change required (though it would be backcompat)
  2. Not as obvious that the process is cancellable?

I suspect number 2 isn't much of a problem - the natural thing when something is busy is to try going back? If we find it's an issue, a label could be added to the working dialog to make it clear.

@pieh
Collaborator

DialogBusy now is also cancalable (if we cancel, IDirectory continue to fetch dir, but we don't wait on it and don't care about items that will eventually be fetched), so I would remove 2. from disadvantages (or rather say it's not directly related to this). /agree with rest.

@jmarshallnz
Owner

I meant not as obvious to the user (no gigantic "Cancel" button).

I'll mock something up on the weekend unless someone beats me to it.

@vicbitter

Guys, I think commit 49cc4be is causing the problem. If you comment out the commit then the "Loading Directory" dialog is not shown over the top of the Search dialog.

@vicbitter

@jmarshallnz, I tried your commits with the "lock.leave()" commit and everything worked great. Thanks

@jmarshallnz
Owner

Ok, some work on progress bar to busy dialog can be found here (branched off here).

https://github.com/jmarshallnz/xbmc/tree/add_progress_to_busy_dialog

@Jezz_X: nasty skinning work there by me - would appreciate you having a crack. ATM it's id 10 - not sure whether to make it an infolabel or not - your thoughts?

@jmarshallnz
Owner

@JezzX: see above.

Jonathan Mar... added some commits
@jmarshallnz
Owner

@JezzX I've pulled in the confluence progress dialog addition to busy. Would appreciate you taking a look. ATM it's a fixed ID, but I could do an infolabel if you think that is more useful.

This is mostly a fix, but as it changes API, it would be nice to get this in the merge window.

@fritsch
Collaborator

@jmarshallnz:
Could you rebase it on the latest master code. We want to test it within our xvba ppa. Disappearing plugin dialogs is a great issue there.

@ghost

button is green.......

@jmarshallnz jmarshallnz was assigned
@jmarshallnz
Owner

@cptspiff: what do you think about merging as a fix (there's still issues with search dialogs popping up under the progress in current master)

Obviously the skin needs work, but I can drop 7285c2e and ask @JezzX to do it (or do it myself and thus force the issue)

@ghost

it is a fix. and it works fine i have had it in my builds for a while. green button is up for some hitting.

@jmarshallnz jmarshallnz merged commit b9d289d into from
@kib kib referenced this pull request in kib/skin.neon
Open

Replace custom progressbar with new Frodo builtin #4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 7, 2012
  1. adds prototype for cancelling directory progress from CDirectory::Get…

    Jonathan Marshall authored
    …Directory
  2. drop the progress dialog from plugins retrieving folders, preferring …

    Jonathan Marshall authored
    …to use the busy dialog from CDirectory::GetDirectory. Fixes #13244
  3. cosmetics: indenting

    Jonathan Marshall authored
  4. adds progress dialog support (id 10) to the busy dialog, and utilise …

    Jonathan Marshall authored
    …in CDirectory::GetDirectory
  5. cleanup - no need for updating labels on the progress during plugin d…

    Jonathan Marshall authored
    …irectory fetch, as it is using busy dialog now
  6. [confluence] adds progress control to busy dialog

    Jonathan Marshall authored
This page is out of date. Refresh to see the latest.
View
10 addons/skin.confluence/720p/DialogBusy.xml
@@ -39,6 +39,14 @@
<label>$LOCALIZE[31004]</label>
<font>font12</font>
</control>
+ <control type="progress" id="10">
+ <description>Progressbar</description>
+ <posx>20</posx>
+ <posy>65</posy>
+ <width>160</width>
+ <height>10</height>
+ <!-- <info>System.Progressbar</info> -->
+ </control>
</control>
</controls>
-</window>
+</window>
View
20 xbmc/dialogs/GUIDialogBusy.cpp
@@ -20,13 +20,17 @@
*/
#include "GUIDialogBusy.h"
+#include "guilib/GUIProgressControl.h"
#include "guilib/GUIWindowManager.h"
+#define PROGRESS_CONTROL 10
+
CGUIDialogBusy::CGUIDialogBusy(void)
: CGUIDialog(WINDOW_DIALOG_BUSY, "DialogBusy.xml"), m_bLastVisible(false)
{
m_loadOnDemand = false;
m_bModal = true;
+ m_progress = 0;
}
CGUIDialogBusy::~CGUIDialogBusy(void)
@@ -40,6 +44,7 @@ void CGUIDialogBusy::Show_Internal()
m_bModal = true;
m_bLastVisible = true;
m_closing = false;
+ m_progress = 0;
g_windowManager.RouteToWindow(this);
// active this window...
@@ -53,6 +58,16 @@ void CGUIDialogBusy::DoProcess(unsigned int currentTime, CDirtyRegionList &dirty
if(!visible && m_bLastVisible)
dirtyregions.push_back(m_renderRegion);
m_bLastVisible = visible;
+
+ // update the progress control if available
+ const CGUIControl *control = GetControl(PROGRESS_CONTROL);
+ if (control && control->GetControlType() == CGUIControl::GUICONTROL_PROGRESS)
+ {
+ CGUIProgressControl *progress = (CGUIProgressControl *)control;
+ progress->SetPercentage(m_progress);
+ progress->SetVisible(m_progress > 0);
+ }
+
CGUIDialog::DoProcess(currentTime, dirtyregions);
}
@@ -68,3 +83,8 @@ bool CGUIDialogBusy::OnBack(int actionID)
m_bCanceled = true;
return true;
}
+
+void CGUIDialogBusy::SetProgress(float percent)
+{
+ m_progress = percent;
+}
View
5 xbmc/dialogs/GUIDialogBusy.h
@@ -32,10 +32,15 @@ class CGUIDialogBusy: public CGUIDialog
virtual bool OnBack(int actionID);
virtual void DoProcess(unsigned int currentTime, CDirtyRegionList &dirtyregions);
virtual void Render();
+ /*! \brief set the current progress of the busy operation
+ \param progress a percentage of progress
+ */
+ void SetProgress(float progress);
bool IsCanceled() { return m_bCanceled; }
protected:
virtual void Show_Internal(); // modeless'ish
bool m_bCanceled;
bool m_bLastVisible;
+ float m_progress; ///< current progress
};
View
6 xbmc/filesystem/Directory.cpp
@@ -162,9 +162,15 @@ bool CDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items, c
{
CSingleLock lock(g_graphicsContext);
+ // update progress
+ float progress = pDirectory->GetProgress();
+ if (progress > 0)
+ dialog->SetProgress(progress);
+
if(dialog->IsCanceled())
{
cancel = true;
+ pDirectory->CancelDirectory();
break;
}
View
11 xbmc/filesystem/IDirectory.h
@@ -70,6 +70,17 @@ class IDirectory
*/
virtual bool GetDirectory(const CStdString& strPath, CFileItemList &items) = 0;
/*!
+ \brief Retrieve the progress of the current directory fetch (if possible).
+ \return the progress as a float in the range 0..100.
+ \sa GetDirectory, CancelDirectory
+ */
+ virtual float GetProgress() const { return 0.0f; };
+ /*!
+ \brief Cancel the current directory fetch (if possible).
+ \sa GetDirectory
+ */
+ virtual void CancelDirectory() { };
+ /*!
\brief Create the directory
\param strPath Directory to create.
\return Returns \e true, if directory is created or if it already exists
View
64 xbmc/filesystem/PluginDirectory.cpp
@@ -464,6 +464,7 @@ bool CPluginDirectory::WaitOnScriptResult(const CStdString &scriptPath, const CS
unsigned int startTime = XbmcThreads::SystemClockMillis();
CGUIDialogProgress *progressBar = NULL;
+ bool cancelled = false;
CLog::Log(LOGDEBUG, "%s - waiting on the %s plugin...", __FUNCTION__, scriptName.c_str());
while (true)
@@ -491,7 +492,7 @@ bool CPluginDirectory::WaitOnScriptResult(const CStdString &scriptPath, const CS
}
// check whether we should pop up the progress dialog
- if (!progressBar && XbmcThreads::SystemClockMillis() - startTime > timeBeforeProgressBar)
+ if (!retrievingDir && !progressBar && XbmcThreads::SystemClockMillis() - startTime > timeBeforeProgressBar)
{ // loading takes more then 1.5 secs, show a progress dialog
progressBar = (CGUIDialogProgress *)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
@@ -515,46 +516,35 @@ bool CPluginDirectory::WaitOnScriptResult(const CStdString &scriptPath, const CS
if (progressBar)
{ // update the progress bar and check for user cancel
- if (retrievingDir)
- {
- CStdString label;
- if (m_totalItems > 0)
- {
- label.Format(g_localizeStrings.Get(1042).c_str(), m_listItems->Size(), m_totalItems);
- progressBar->SetPercentage((int)((m_listItems->Size() * 100 ) / m_totalItems));
- progressBar->ShowProgressBar(true);
- }
- else
- label.Format(g_localizeStrings.Get(1041).c_str(), m_listItems->Size());
- progressBar->SetLine(2, label);
- }
progressBar->Progress();
if (progressBar->IsCanceled())
{ // user has cancelled our process - cancel our process
- if (!m_cancelled)
- {
- m_cancelled = true;
- startTime = XbmcThreads::SystemClockMillis();
- }
- if (m_cancelled && XbmcThreads::SystemClockMillis() - startTime > timeToKillScript)
- { // cancel our script
+ m_cancelled = true;
+ }
+ }
+ if (!cancelled && m_cancelled)
+ {
+ cancelled = true;
+ startTime = XbmcThreads::SystemClockMillis();
+ }
+ if (cancelled && XbmcThreads::SystemClockMillis() - startTime > timeToKillScript)
+ { // cancel our script
#ifdef HAS_PYTHON
- int id = g_pythonParser.getScriptId(scriptPath.c_str());
- if (id != -1 && g_pythonParser.isRunning(id))
- {
- CLog::Log(LOGDEBUG, "%s- cancelling plugin %s", __FUNCTION__, scriptName.c_str());
- g_pythonParser.stopScript(id);
- break;
- }
-#endif
- }
+ int id = g_pythonParser.getScriptId(scriptPath.c_str());
+ if (id != -1 && g_pythonParser.isRunning(id))
+ {
+ CLog::Log(LOGDEBUG, "%s- cancelling plugin %s", __FUNCTION__, scriptName.c_str());
+ g_pythonParser.stopScript(id);
+ break;
}
+#endif
}
}
+
if (progressBar)
CApplicationMessenger::Get().Close(progressBar, false, false);
- return !m_cancelled && m_success;
+ return !cancelled && m_success;
}
void CPluginDirectory::SetResolvedUrl(int handle, bool success, const CFileItem *resultItem)
@@ -626,3 +616,15 @@ void CPluginDirectory::SetProperty(int handle, const CStdString &strProperty, co
CPluginDirectory *dir = globalHandles[handle];
dir->m_listItems->SetProperty(strProperty, strValue);
}
+
+void CPluginDirectory::CancelDirectory()
+{
+ m_cancelled = true;
+}
+
+float CPluginDirectory::GetProgress() const
+{
+ if (m_totalItems > 0)
+ return (m_listItems->Size() * 100.0f) / m_totalItems;
+ return 0.0f;
+}
View
2  xbmc/filesystem/PluginDirectory.h
@@ -47,6 +47,8 @@ class CPluginDirectory : public IDirectory
virtual bool GetDirectory(const CStdString& strPath, CFileItemList& items);
virtual bool IsAllowed(const CStdString &strFile) const { return true; };
virtual bool Exists(const char* strPath) { return true; }
+ virtual float GetProgress() const;
+ virtual void CancelDirectory();
static bool RunScriptWithParams(const CStdString& strPath);
static bool GetPluginResult(const CStdString& strPath, CFileItem &resultItem);
Something went wrong with that request. Please try again.