1 /*
2  *  Copyright (C) 2012-2018 Team Kodi
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 #include "GUIDialogExtendedProgressBar.h"
10 
11 #include "guilib/GUIMessage.h"
12 #include "guilib/GUIProgressControl.h"
13 #include "threads/SingleLock.h"
14 #include "threads/SystemClock.h"
15 
16 #include <cmath>
17 
18 #define CONTROL_LABELHEADER       30
19 #define CONTROL_LABELTITLE        31
20 #define CONTROL_PROGRESS          32
21 
22 #define ITEM_SWITCH_TIME_MS       2000
23 
Text(void) const24 std::string CGUIDialogProgressBarHandle::Text(void) const
25 {
26   CSingleLock lock(m_critSection);
27   std::string retVal(m_strText);
28   return retVal;
29 }
30 
SetText(const std::string & strText)31 void CGUIDialogProgressBarHandle::SetText(const std::string &strText)
32 {
33   CSingleLock lock(m_critSection);
34   m_strText = strText;
35 }
36 
SetTitle(const std::string & strTitle)37 void CGUIDialogProgressBarHandle::SetTitle(const std::string &strTitle)
38 {
39   CSingleLock lock(m_critSection);
40   m_strTitle = strTitle;
41 }
42 
SetProgress(int currentItem,int itemCount)43 void CGUIDialogProgressBarHandle::SetProgress(int currentItem, int itemCount)
44 {
45   float fPercentage = (currentItem*100.0f)/itemCount;
46   if (!std::isnan(fPercentage))
47     m_fPercentage = std::min(100.0f, fPercentage);
48 }
49 
CGUIDialogExtendedProgressBar(void)50 CGUIDialogExtendedProgressBar::CGUIDialogExtendedProgressBar(void)
51   : CGUIDialog(WINDOW_DIALOG_EXT_PROGRESS, "DialogExtendedProgressBar.xml", DialogModalityType::MODELESS)
52 {
53   m_loadType        = LOAD_ON_GUI_INIT;
54   m_iLastSwitchTime = 0;
55   m_iCurrentItem    = 0;
56 }
57 
GetHandle(const std::string & strTitle)58 CGUIDialogProgressBarHandle *CGUIDialogExtendedProgressBar::GetHandle(const std::string &strTitle)
59 {
60   CGUIDialogProgressBarHandle *handle = new CGUIDialogProgressBarHandle(strTitle);
61   {
62     CSingleLock lock(m_critSection);
63     m_handles.push_back(handle);
64   }
65 
66   Open();
67 
68   return handle;
69 }
70 
OnMessage(CGUIMessage & message)71 bool CGUIDialogExtendedProgressBar::OnMessage(CGUIMessage& message)
72 {
73   switch (message.GetMessage())
74   {
75   case GUI_MSG_WINDOW_INIT:
76     {
77       m_iLastSwitchTime = XbmcThreads::SystemClockMillis();
78       m_iCurrentItem = 0;
79       CGUIDialog::OnMessage(message);
80 
81       UpdateState(0);
82       return true;
83     }
84     break;
85   }
86 
87   return CGUIDialog::OnMessage(message);
88 }
89 
Process(unsigned int currentTime,CDirtyRegionList & dirtyregions)90 void CGUIDialogExtendedProgressBar::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions)
91 {
92   if (m_active)
93     UpdateState(currentTime);
94 
95   CGUIDialog::Process(currentTime, dirtyregions);
96 }
97 
UpdateState(unsigned int currentTime)98 void CGUIDialogExtendedProgressBar::UpdateState(unsigned int currentTime)
99 {
100   std::string strHeader;
101   std::string strTitle;
102   float  fProgress(-1.0f);
103 
104   {
105     CSingleLock lock(m_critSection);
106 
107     // delete finished items
108     for (int iPtr = m_handles.size() - 1; iPtr >= 0; iPtr--)
109     {
110       if (m_handles.at(iPtr)->IsFinished())
111       {
112         delete m_handles.at(iPtr);
113         m_handles.erase(m_handles.begin() + iPtr);
114       }
115     }
116 
117     if (!m_handles.size())
118     {
119       Close(false, 0, true, false);
120       return;
121     }
122 
123     // ensure the current item is in our range
124     if (m_iCurrentItem >= m_handles.size())
125       m_iCurrentItem = m_handles.size() - 1;
126 
127     // update the current item ptr
128     if (currentTime > m_iLastSwitchTime &&
129         currentTime - m_iLastSwitchTime >= ITEM_SWITCH_TIME_MS)
130     {
131       m_iLastSwitchTime = currentTime;
132 
133       // select next item
134       if (++m_iCurrentItem > m_handles.size() - 1)
135         m_iCurrentItem = 0;
136     }
137 
138     CGUIDialogProgressBarHandle *handle = m_handles.at(m_iCurrentItem);
139     if (handle)
140     {
141       strTitle  = handle->Text();
142       strHeader = handle->Title();
143       fProgress = handle->Percentage();
144     }
145   }
146 
147   SET_CONTROL_LABEL(CONTROL_LABELHEADER, strHeader);
148   SET_CONTROL_LABEL(CONTROL_LABELTITLE, strTitle);
149 
150   if (fProgress > -1.0f)
151   {
152     SET_CONTROL_VISIBLE(CONTROL_PROGRESS);
153     CONTROL_SELECT_ITEM(CONTROL_PROGRESS, (unsigned int)fProgress);
154   }
155 }
156