[cstdstring] demise Format, replacing with StringUtils::Format
[vuplus_xbmc] / xbmc / dialogs / GUIDialogContextMenu.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "system.h"
22 #include "GUIDialogContextMenu.h"
23 #include "guilib/GUIButtonControl.h"
24 #include "guilib/GUIControlGroupList.h"
25 #include "GUIDialogFileBrowser.h"
26 #include "GUIUserMessages.h"
27 #include "Autorun.h"
28 #include "GUIPassword.h"
29 #include "Util.h"
30 #include "utils/URIUtils.h"
31 #include "settings/MediaSourceSettings.h"
32 #include "settings/Settings.h"
33 #include "GUIDialogMediaSource.h"
34 #include "profiles/ProfilesManager.h"
35 #include "profiles/dialogs/GUIDialogLockSettings.h"
36 #include "storage/MediaManager.h"
37 #include "guilib/GUIWindowManager.h"
38 #include "guilib/Key.h"
39 #include "GUIDialogYesNo.h"
40 #include "addons/AddonManager.h"
41 #include "FileItem.h"
42 #include "filesystem/File.h"
43 #include "guilib/LocalizeStrings.h"
44 #include "TextureCache.h"
45 #include "video/windows/GUIWindowVideoBase.h"
46 #include "URL.h"
47 #include "utils/StringUtils.h"
48
49 #ifdef TARGET_WINDOWS
50 #include "WIN32Util.h"
51 #endif
52
53 using namespace std;
54
55 #define BACKGROUND_IMAGE       999
56 #if PRE_SKIN_VERSION_11_COMPATIBILITY
57 #define BACKGROUND_BOTTOM      998
58 #define BACKGROUND_TOP         997
59 #define SPACE_BETWEEN_BUTTONS    2
60 #endif
61 #define GROUP_LIST             996
62 #define BUTTON_TEMPLATE       1000
63 #define BUTTON_START          1001
64 #define BUTTON_END            (BUTTON_START + (int)m_buttons.size() - 1)
65
66 void CContextButtons::Add(unsigned int button, const CStdString &label)
67 {
68   push_back(pair<unsigned int, CStdString>(button, label));
69 }
70
71 void CContextButtons::Add(unsigned int button, int label)
72 {
73   push_back(pair<unsigned int, CStdString>(button, g_localizeStrings.Get(label)));
74 }
75
76 CGUIDialogContextMenu::CGUIDialogContextMenu(void)
77   : CGUIDialog(WINDOW_DIALOG_CONTEXT_MENU, "DialogContextMenu.xml")
78 {
79   m_clickedButton = -1;
80   m_backgroundImageSize = 0;
81   m_loadType = KEEP_IN_MEMORY;
82 }
83
84 CGUIDialogContextMenu::~CGUIDialogContextMenu(void)
85 {
86 }
87
88 bool CGUIDialogContextMenu::OnMessage(CGUIMessage &message)
89 {
90   if (message.GetMessage() == GUI_MSG_CLICKED)
91   { // someone has been clicked - deinit...
92     if (message.GetSenderId() >= BUTTON_START && message.GetSenderId() <= BUTTON_END)
93       m_clickedButton = (int)m_buttons[message.GetSenderId() - BUTTON_START].first;
94     Close();
95     return true;
96   }
97   return CGUIDialog::OnMessage(message);
98 }
99
100 bool CGUIDialogContextMenu::OnAction(const CAction& action)
101 {
102   if (action.GetID() == ACTION_CONTEXT_MENU)
103   {
104     Close();
105     return true;
106   }
107
108   return CGUIDialog::OnAction(action);
109 }
110
111 void CGUIDialogContextMenu::OnInitWindow()
112 {
113   m_clickedButton = -1;
114   // set initial control focus
115   m_lastControlID = BUTTON_START;
116   CGUIDialog::OnInitWindow();
117 }
118
119 void CGUIDialogContextMenu::SetupButtons()
120 {
121   if (!m_buttons.size())
122     return;
123
124   // disable the template button control
125   CGUIButtonControl *pButtonTemplate = (CGUIButtonControl *)GetFirstFocusableControl(BUTTON_TEMPLATE);
126   if (!pButtonTemplate) pButtonTemplate = (CGUIButtonControl *)GetControl(BUTTON_TEMPLATE);
127   if (!pButtonTemplate)
128     return;
129   pButtonTemplate->SetVisible(false);
130
131   CGUIControlGroupList* pGroupList = NULL;
132   {
133     const CGUIControl* pControl = GetControl(GROUP_LIST);
134     if (pControl && pControl->GetControlType() == GUICONTROL_GROUPLIST)
135       pGroupList = (CGUIControlGroupList*)pControl;
136   }
137
138   // add our buttons
139   for (unsigned int i = 0; i < m_buttons.size(); i++)
140   {
141     CGUIButtonControl *pButton = new CGUIButtonControl(*pButtonTemplate);
142     if (pButton)
143     { // set the button's ID and position
144       int id = BUTTON_START + i;
145       pButton->SetID(id);
146       pButton->SetVisible(true);
147       pButton->SetLabel(m_buttons[i].second);
148       if (pGroupList)
149       {
150         pButton->SetPosition(pButtonTemplate->GetXPosition(), pButtonTemplate->GetYPosition());
151         // try inserting context buttons at position specified by template
152         // button, if template button is not in grouplist fallback to adding
153         // new buttons at the end of grouplist
154         if (!pGroupList->InsertControl(pButton, pButtonTemplate))
155           pGroupList->AddControl(pButton);
156       }
157 #if PRE_SKIN_VERSION_11_COMPATIBILITY
158       else
159       {
160         pButton->SetPosition(pButtonTemplate->GetXPosition(), i*(pButtonTemplate->GetHeight() + SPACE_BETWEEN_BUTTONS));
161         pButton->SetNavigation(id - 1, id + 1, id, id);
162         AddControl(pButton);
163       }
164 #endif
165     }
166   }
167
168   CGUIControl *pControl = NULL;
169 #if PRE_SKIN_VERSION_11_COMPATIBILITY
170   if (!pGroupList)
171   {
172     // if we don't have grouplist update the navigation of the first and last buttons
173     pControl = (CGUIControl *)GetControl(BUTTON_START);
174     if (pControl)
175       pControl->SetNavigation(BUTTON_END, pControl->GetControlIdDown(), pControl->GetControlIdLeft(), pControl->GetControlIdRight());
176     pControl = (CGUIControl *)GetControl(BUTTON_END);
177     if (pControl)
178       pControl->SetNavigation(pControl->GetControlIdUp(), BUTTON_START, pControl->GetControlIdLeft(), pControl->GetControlIdRight());
179   }
180 #endif
181
182   // fix up background images placement and size
183   pControl = (CGUIControl *)GetControl(BACKGROUND_IMAGE);
184   if (pControl)
185   {
186     // first set size of background image
187     if (pGroupList)
188     {
189       if (pGroupList->GetOrientation() == VERTICAL)
190       {
191         // keep gap between bottom edges of grouplist and background image
192         pControl->SetHeight(m_backgroundImageSize - pGroupList->Size() + pGroupList->GetHeight());
193       }
194       else
195       {
196         // keep gap between right edges of grouplist and background image
197         pControl->SetWidth(m_backgroundImageSize - pGroupList->Size() + pGroupList->GetWidth());
198       }
199     }
200 #if PRE_SKIN_VERSION_11_COMPATIBILITY
201     else
202       pControl->SetHeight(m_buttons.size() * (pButtonTemplate->GetHeight() + SPACE_BETWEEN_BUTTONS));
203
204     if (pGroupList && pGroupList->GetOrientation() == HORIZONTAL)
205     {
206       // if there is grouplist control with horizontal orientation - adjust width of top and bottom background
207       CGUIControl* pControl2 = (CGUIControl *)GetControl(BACKGROUND_TOP);
208       if (pControl2)
209         pControl2->SetWidth(pControl->GetWidth());
210
211       pControl2 = (CGUIControl *)GetControl(BACKGROUND_BOTTOM);
212       if (pControl2)
213         pControl2->SetWidth(pControl->GetWidth());
214     }
215     else
216     {
217       // adjust position of bottom background
218       CGUIControl* pControl2 = (CGUIControl *)GetControl(BACKGROUND_BOTTOM);
219       if (pControl2)
220         pControl2->SetPosition(pControl2->GetXPosition(), pControl->GetYPosition() + pControl->GetHeight());
221     }
222 #endif
223   }
224
225   // update our default control
226   if (pGroupList)
227     m_defaultControl = pGroupList->GetID();
228 #if PRE_SKIN_VERSION_11_COMPATIBILITY
229   else
230   {
231     if (m_defaultControl < BUTTON_START || m_defaultControl > BUTTON_END)
232       m_defaultControl = BUTTON_START;
233     while (m_defaultControl <= BUTTON_END && !(GetControl(m_defaultControl)->CanFocus()))
234       m_defaultControl++;
235   }
236 #endif
237 }
238
239 void CGUIDialogContextMenu::SetPosition(float posX, float posY)
240 {
241   if (posY + GetHeight() > m_coordsRes.iHeight)
242     posY = m_coordsRes.iHeight - GetHeight();
243   if (posY < 0) posY = 0;
244   if (posX + GetWidth() > m_coordsRes.iWidth)
245     posX = m_coordsRes.iWidth - GetWidth();
246   if (posX < 0) posX = 0;
247 #if PRE_SKIN_VERSION_11_COMPATIBILITY
248   // we currently hack the positioning of the buttons from y position 0, which
249   // forces skinners to place the top image at a negative y value.  Thus, we offset
250   // the y coordinate by the height of the top image.
251   const CGUIControl *top = GetControl(BACKGROUND_TOP);
252   if (top)
253     posY += top->GetHeight();
254 #endif
255   CGUIDialog::SetPosition(posX, posY);
256 }
257
258 float CGUIDialogContextMenu::GetHeight() const
259 {
260   const CGUIControl *backMain = GetControl(BACKGROUND_IMAGE);
261   if (backMain)
262 #if PRE_SKIN_VERSION_11_COMPATIBILITY
263   {
264     float height = backMain->GetHeight();
265     const CGUIControl *backBottom = GetControl(BACKGROUND_BOTTOM);
266     if (backBottom)
267       height += backBottom->GetHeight();
268     const CGUIControl *backTop = GetControl(BACKGROUND_TOP);
269     if (backTop)
270       height += backTop->GetHeight();
271     return height;
272   }
273 #else
274   return backMain->GetHeight();
275 #endif
276   else
277     return CGUIDialog::GetHeight();
278 }
279
280 float CGUIDialogContextMenu::GetWidth() const
281 {
282   CGUIControl *pControl = (CGUIControl *)GetControl(BACKGROUND_IMAGE);
283   if (pControl)
284     return pControl->GetWidth();
285   else
286     return CGUIDialog::GetWidth();
287 }
288
289 bool CGUIDialogContextMenu::SourcesMenu(const CStdString &strType, const CFileItemPtr item, float posX, float posY)
290 {
291   // TODO: This should be callable even if we don't have any valid items
292   if (!item)
293     return false;
294
295   // grab our context menu
296   CContextButtons buttons;
297   GetContextButtons(strType, item, buttons);
298
299   int button = ShowAndGetChoice(buttons);
300   if (button >= 0)
301     return OnContextButton(strType, item, (CONTEXT_BUTTON)button);
302   return false;
303 }
304
305 void CGUIDialogContextMenu::GetContextButtons(const CStdString &type, const CFileItemPtr item, CContextButtons &buttons)
306 {
307   // Add buttons to the ContextMenu that should be visible for both sources and autosourced items
308   if (item && item->IsRemovable())
309   {
310     if (item->IsDVD() || item->IsCDDA())
311     {
312       // We need to check if there is a detected is inserted!
313       buttons.Add(CONTEXT_BUTTON_PLAY_DISC, 341); // Play CD/DVD!
314       if (CGUIWindowVideoBase::HasResumeItemOffset(item.get()))
315         buttons.Add(CONTEXT_BUTTON_RESUME_DISC, CGUIWindowVideoBase::GetResumeString(*(item.get())));     // Resume Disc
316
317       buttons.Add(CONTEXT_BUTTON_EJECT_DISC, 13391);  // Eject/Load CD/DVD!
318     }
319     else // Must be HDD
320     {
321       buttons.Add(CONTEXT_BUTTON_EJECT_DRIVE, 13420);  // Eject Removable HDD!
322     }
323   }
324
325
326   // Next, Add buttons to the ContextMenu that should ONLY be visible for sources and not autosourced items
327   CMediaSource *share = GetShare(type, item.get());
328
329   if (CProfilesManager::Get().GetCurrentProfile().canWriteSources() || g_passwordManager.bMasterUser)
330   {
331     if (share)
332     {
333       // Note. from now on, remove source & disable plugin should mean the same thing
334       //TODO might be smart to also combine editing source & plugin settings into one concept/dialog
335       // Note. Temporarily disabled ability to remove plugin sources until installer is operational
336
337       CURL url(share->strPath);
338       bool isAddon = ADDON::TranslateContent(url.GetProtocol()) != CONTENT_NONE;
339       if (!share->m_ignore && !isAddon)
340         buttons.Add(CONTEXT_BUTTON_EDIT_SOURCE, 1027); // Edit Source
341       else
342       {
343         ADDON::AddonPtr plugin;
344         if (ADDON::CAddonMgr::Get().GetAddon(url.GetHostName(), plugin))
345         if (plugin->HasSettings())
346           buttons.Add(CONTEXT_BUTTON_PLUGIN_SETTINGS, 1045); // Plugin Settings
347       }
348       if (type != "video")
349         buttons.Add(CONTEXT_BUTTON_SET_DEFAULT, 13335); // Set as Default
350       if (!share->m_ignore && !isAddon)
351         buttons.Add(CONTEXT_BUTTON_REMOVE_SOURCE, 522); // Remove Source
352
353       buttons.Add(CONTEXT_BUTTON_SET_THUMB, 20019);
354     }
355     if (!GetDefaultShareNameByType(type).IsEmpty())
356       buttons.Add(CONTEXT_BUTTON_CLEAR_DEFAULT, 13403); // Clear Default
357
358     buttons.Add(CONTEXT_BUTTON_ADD_SOURCE, 1026); // Add Source
359   }
360   if (share && LOCK_MODE_EVERYONE != CProfilesManager::Get().GetMasterProfile().getLockMode())
361   {
362     if (share->m_iHasLock == 0 && (CProfilesManager::Get().GetCurrentProfile().canWriteSources() || g_passwordManager.bMasterUser))
363       buttons.Add(CONTEXT_BUTTON_ADD_LOCK, 12332);
364     else if (share->m_iHasLock == 1)
365       buttons.Add(CONTEXT_BUTTON_REMOVE_LOCK, 12335);
366     else if (share->m_iHasLock == 2)
367     {
368       buttons.Add(CONTEXT_BUTTON_REMOVE_LOCK, 12335);
369
370       bool maxRetryExceeded = false;
371       if (CSettings::Get().GetInt("masterlock.maxretries") != 0)
372         maxRetryExceeded = (share->m_iBadPwdCount >= CSettings::Get().GetInt("masterlock.maxretries"));
373
374       if (maxRetryExceeded)
375         buttons.Add(CONTEXT_BUTTON_RESET_LOCK, 12334);
376       else
377         buttons.Add(CONTEXT_BUTTON_CHANGE_LOCK, 12356);
378     }
379   }
380   if (share && !g_passwordManager.bMasterUser && item->m_iHasLock == 1)
381     buttons.Add(CONTEXT_BUTTON_REACTIVATE_LOCK, 12353);
382 }
383
384 bool CGUIDialogContextMenu::OnContextButton(const CStdString &type, const CFileItemPtr item, CONTEXT_BUTTON button)
385 {
386   // Add Source doesn't require a valid share
387   if (button == CONTEXT_BUTTON_ADD_SOURCE)
388   {
389     if (CProfilesManager::Get().IsMasterProfile())
390     {
391       if (!g_passwordManager.IsMasterLockUnlocked(true))
392         return false;
393     }
394     else if (!CProfilesManager::Get().GetCurrentProfile().canWriteSources() && !g_passwordManager.IsProfileLockUnlocked())
395       return false;
396
397     return CGUIDialogMediaSource::ShowAndAddMediaSource(type);
398   }
399
400   // buttons that are available on both sources and autosourced items
401   if (!item) return false;
402
403   switch (button)
404   {
405   case CONTEXT_BUTTON_EJECT_DRIVE:
406     return g_mediaManager.Eject(item->GetPath());
407
408 #ifdef HAS_DVD_DRIVE
409   case CONTEXT_BUTTON_PLAY_DISC:
410     return MEDIA_DETECT::CAutorun::PlayDisc(item->GetPath(), true, true); // restart
411
412   case CONTEXT_BUTTON_RESUME_DISC:
413     return MEDIA_DETECT::CAutorun::PlayDisc(item->GetPath(), true, false); // resume
414
415   case CONTEXT_BUTTON_EJECT_DISC:
416     g_mediaManager.ToggleTray(g_mediaManager.TranslateDevicePath(item->GetPath())[0]);
417 #endif
418     return true;
419   default:
420     break;
421   }
422
423   // the rest of the operations require a valid share
424   CMediaSource *share = GetShare(type, item.get());
425   if (!share) return false;
426   switch (button)
427   {
428   case CONTEXT_BUTTON_EDIT_SOURCE:
429     if (CProfilesManager::Get().IsMasterProfile())
430     {
431       if (!g_passwordManager.IsMasterLockUnlocked(true))
432         return false;
433     }
434     else if (!g_passwordManager.IsProfileLockUnlocked())
435       return false;
436
437     return CGUIDialogMediaSource::ShowAndEditMediaSource(type, *share);
438
439   case CONTEXT_BUTTON_REMOVE_SOURCE:
440   {
441     if (CProfilesManager::Get().IsMasterProfile())
442     {
443       if (!g_passwordManager.IsMasterLockUnlocked(true))
444         return false;
445     }
446     else
447     {
448       if (!CProfilesManager::Get().GetCurrentProfile().canWriteSources() && !g_passwordManager.IsMasterLockUnlocked(false))
449         return false;
450       if (CProfilesManager::Get().GetCurrentProfile().canWriteSources() && !g_passwordManager.IsProfileLockUnlocked())
451         return false;
452     }
453     // prompt user if they want to really delete the source
454     if (CGUIDialogYesNo::ShowAndGetInput(751, 0, 750, 0))
455     { // check default before we delete, as deletion will kill the share object
456       CStdString defaultSource(GetDefaultShareNameByType(type));
457       if (!defaultSource.IsEmpty())
458       {
459         if (share->strName.Equals(defaultSource))
460           ClearDefault(type);
461       }
462       CMediaSourceSettings::Get().DeleteSource(type, share->strName, share->strPath);
463     }
464     return true;
465   }
466   case CONTEXT_BUTTON_SET_DEFAULT:
467     if (CProfilesManager::Get().GetCurrentProfile().canWriteSources() && !g_passwordManager.IsProfileLockUnlocked())
468       return false;
469     else if (!g_passwordManager.IsMasterLockUnlocked(true))
470       return false;
471
472     // make share default
473     SetDefault(type, share->strName);
474     return true;
475
476   case CONTEXT_BUTTON_CLEAR_DEFAULT:
477     if (CProfilesManager::Get().GetCurrentProfile().canWriteSources() && !g_passwordManager.IsProfileLockUnlocked())
478       return false;
479     else if (!g_passwordManager.IsMasterLockUnlocked(true))
480       return false;
481     // remove share default
482     ClearDefault(type);
483     return true;
484
485   case CONTEXT_BUTTON_SET_THUMB:
486     {
487       if (CProfilesManager::Get().GetCurrentProfile().canWriteSources() && !g_passwordManager.IsProfileLockUnlocked())
488         return false;
489       else if (!g_passwordManager.IsMasterLockUnlocked(true))
490         return false;
491
492       // setup our thumb list
493       CFileItemList items;
494
495       // add the current thumb, if available
496       if (!share->m_strThumbnailImage.IsEmpty())
497       {
498         CFileItemPtr current(new CFileItem("thumb://Current", false));
499         current->SetArt("thumb", share->m_strThumbnailImage);
500         current->SetLabel(g_localizeStrings.Get(20016));
501         items.Add(current);
502       }
503       else if (item->HasArt("thumb"))
504       { // already have a thumb that the share doesn't know about - must be a local one, so we mayaswell reuse it.
505         CFileItemPtr current(new CFileItem("thumb://Current", false));
506         current->SetArt("thumb", item->GetArt("thumb"));
507         current->SetLabel(g_localizeStrings.Get(20016));
508         items.Add(current);
509       }
510       // see if there's a local thumb for this item
511       CStdString folderThumb = item->GetFolderThumb();
512       if (XFILE::CFile::Exists(folderThumb))
513       {
514         CFileItemPtr local(new CFileItem("thumb://Local", false));
515         local->SetArt("thumb", folderThumb);
516         local->SetLabel(g_localizeStrings.Get(20017));
517         items.Add(local);
518       }
519       // and add a "no thumb" entry as well
520       CFileItemPtr nothumb(new CFileItem("thumb://None", false));
521       nothumb->SetIconImage(item->GetIconImage());
522       nothumb->SetLabel(g_localizeStrings.Get(20018));
523       items.Add(nothumb);
524
525       CStdString strThumb;
526       VECSOURCES shares;
527       g_mediaManager.GetLocalDrives(shares);
528       if (!CGUIDialogFileBrowser::ShowAndGetImage(items, shares, g_localizeStrings.Get(1030), strThumb))
529         return false;
530
531       if (strThumb == "thumb://Current")
532         return true;
533
534       if (strThumb == "thumb://Local")
535         strThumb = folderThumb;
536
537       if (strThumb == "thumb://None")
538         strThumb = "";
539
540       if (!share->m_ignore)
541       {
542         CMediaSourceSettings::Get().UpdateSource(type,share->strName,"thumbnail",strThumb);
543         CMediaSourceSettings::Get().Save();
544       }
545       else if (!strThumb.IsEmpty())
546       { // this is some sort of an auto-share, so store in the texture database
547         CTextureDatabase db;
548         if (db.Open())
549           db.SetTextureForPath(item->GetPath(), "thumb", strThumb);
550       }
551
552       CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0,GUI_MSG_UPDATE_SOURCES);
553       g_windowManager.SendThreadMessage(msg);
554       return true;
555     }
556
557   case CONTEXT_BUTTON_ADD_LOCK:
558     {
559       // prompt user for mastercode when changing lock settings) only for default user
560       if (!g_passwordManager.IsMasterLockUnlocked(true))
561         return false;
562
563       CStdString strNewPassword = "";
564       if (!CGUIDialogLockSettings::ShowAndGetLock(share->m_iLockMode,strNewPassword))
565         return false;
566       // password entry and re-entry succeeded, write out the lock data
567       share->m_iHasLock = 2;
568       CMediaSourceSettings::Get().UpdateSource(type, share->strName, "lockcode", strNewPassword);
569       strNewPassword = StringUtils::Format("%i", share->m_iLockMode);
570       CMediaSourceSettings::Get().UpdateSource(type, share->strName, "lockmode", strNewPassword);
571       CMediaSourceSettings::Get().UpdateSource(type, share->strName, "badpwdcount", "0");
572       CMediaSourceSettings::Get().Save();
573
574       CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0,GUI_MSG_UPDATE_SOURCES);
575       g_windowManager.SendThreadMessage(msg);
576       return true;
577     }
578   case CONTEXT_BUTTON_RESET_LOCK:
579     {
580       // prompt user for profile lock when changing lock settings
581       if (!g_passwordManager.IsMasterLockUnlocked(true))
582         return false;
583
584       CMediaSourceSettings::Get().UpdateSource(type, share->strName, "badpwdcount", "0");
585       CMediaSourceSettings::Get().Save();
586       CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0,GUI_MSG_UPDATE_SOURCES);
587       g_windowManager.SendThreadMessage(msg);
588       return true;
589     }
590   case CONTEXT_BUTTON_REMOVE_LOCK:
591     {
592       if (!g_passwordManager.IsMasterLockUnlocked(true))
593         return false;
594
595       if (!CGUIDialogYesNo::ShowAndGetInput(12335, 0, 750, 0))
596         return false;
597
598       share->m_iHasLock = 0;
599       CMediaSourceSettings::Get().UpdateSource(type, share->strName, "lockmode", "0");
600       CMediaSourceSettings::Get().UpdateSource(type, share->strName, "lockcode", "0");
601       CMediaSourceSettings::Get().UpdateSource(type, share->strName, "badpwdcount", "0");
602       CMediaSourceSettings::Get().Save();
603       CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0,GUI_MSG_UPDATE_SOURCES);
604       g_windowManager.SendThreadMessage(msg);
605       return true;
606     }
607   case CONTEXT_BUTTON_REACTIVATE_LOCK:
608     {
609       bool maxRetryExceeded = false;
610       if (CSettings::Get().GetInt("masterlock.maxretries") != 0)
611         maxRetryExceeded = (share->m_iBadPwdCount >= CSettings::Get().GetInt("masterlock.maxretries"));
612       if (!maxRetryExceeded)
613       {
614         // don't prompt user for mastercode when reactivating a lock
615         g_passwordManager.LockSource(type, share->strName, true);
616         return true;
617       }
618       return false;
619     }
620   case CONTEXT_BUTTON_CHANGE_LOCK:
621     {
622       if (!g_passwordManager.IsMasterLockUnlocked(true))
623         return false;
624
625       CStdString strNewPW;
626       CStdString strNewLockMode;
627       if (CGUIDialogLockSettings::ShowAndGetLock(share->m_iLockMode,strNewPW))
628         strNewLockMode = StringUtils::Format("%i",share->m_iLockMode);
629       else
630         return false;
631       // password ReSet and re-entry succeeded, write out the lock data
632       CMediaSourceSettings::Get().UpdateSource(type, share->strName, "lockcode", strNewPW);
633       CMediaSourceSettings::Get().UpdateSource(type, share->strName, "lockmode", strNewLockMode);
634       CMediaSourceSettings::Get().UpdateSource(type, share->strName, "badpwdcount", "0");
635       CMediaSourceSettings::Get().Save();
636       CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0,GUI_MSG_UPDATE_SOURCES);
637       g_windowManager.SendThreadMessage(msg);
638       return true;
639     }
640   default:
641     break;
642   }
643   return false;
644 }
645
646 CMediaSource *CGUIDialogContextMenu::GetShare(const CStdString &type, const CFileItem *item)
647 {
648   VECSOURCES *shares = CMediaSourceSettings::Get().GetSources(type);
649   if (!shares || !item) return NULL;
650   for (unsigned int i = 0; i < shares->size(); i++)
651   {
652     CMediaSource &testShare = shares->at(i);
653     if (URIUtils::IsDVD(testShare.strPath))
654     {
655       if (!item->IsDVD())
656         continue;
657     }
658     else
659     {
660       if (!URIUtils::CompareWithoutSlashAtEnd(testShare.strPath, item->GetPath()))
661         continue;
662     }
663     // paths match, what about share name - only match the leftmost
664     // characters as the label may contain other info (status for instance)
665     if (item->GetLabel().Left(testShare.strName.size()).Equals(testShare.strName))
666     {
667       return &testShare;
668     }
669   }
670   return NULL;
671 }
672
673 void CGUIDialogContextMenu::OnWindowLoaded()
674 {
675   m_coordX = m_posX;
676   m_coordY = m_posY;
677   
678   const CGUIControlGroupList* pGroupList = NULL;
679   const CGUIControl* pControl = GetControl(GROUP_LIST);
680   if (pControl && pControl->GetControlType() == GUICONTROL_GROUPLIST)
681     pGroupList = (CGUIControlGroupList*)pControl;
682
683   pControl = (CGUIControl *)GetControl(BACKGROUND_IMAGE);
684   if (pControl && pGroupList)
685   {
686     if (pGroupList->GetOrientation() == VERTICAL)
687       m_backgroundImageSize = pControl->GetHeight();
688     else
689       m_backgroundImageSize = pControl->GetWidth();
690   }
691
692   CGUIDialog::OnWindowLoaded();
693 }
694
695 void CGUIDialogContextMenu::OnDeinitWindow(int nextWindowID)
696 {
697   //we can't be sure that controls are removed on window unload
698   //we have to remove them to be sure that they won't stay for next use of context menu
699   for (unsigned int i = 0; i < m_buttons.size(); i++)
700   {
701     const CGUIControl *control = GetControl(BUTTON_START + i);
702     if (control)
703       RemoveControl(control);
704   }
705
706   m_buttons.clear();
707   CGUIDialog::OnDeinitWindow(nextWindowID);
708 }
709
710 CStdString CGUIDialogContextMenu::GetDefaultShareNameByType(const CStdString &strType)
711 {
712   VECSOURCES *pShares = CMediaSourceSettings::Get().GetSources(strType);
713   CStdString strDefault = CMediaSourceSettings::Get().GetDefaultSource(strType);
714
715   if (!pShares) return "";
716
717   bool bIsSourceName(false);
718   int iIndex = CUtil::GetMatchingSource(strDefault, *pShares, bIsSourceName);
719   if (iIndex < 0 || iIndex >= (int)pShares->size())
720     return "";
721
722   return pShares->at(iIndex).strName;
723 }
724
725 void CGUIDialogContextMenu::SetDefault(const CStdString &strType, const CStdString &strDefault)
726 {
727   CMediaSourceSettings::Get().SetDefaultSource(strType, strDefault);
728   CMediaSourceSettings::Get().Save();
729 }
730
731 void CGUIDialogContextMenu::ClearDefault(const CStdString &strType)
732 {
733   SetDefault(strType, "");
734 }
735
736 void CGUIDialogContextMenu::SwitchMedia(const CStdString& strType, const CStdString& strPath)
737 {
738   // create menu
739   CContextButtons choices;
740   if (!strType.Equals("music"))
741     choices.Add(WINDOW_MUSIC_FILES, 2);
742   if (!strType.Equals("video"))
743     choices.Add(WINDOW_VIDEO_FILES, 3);
744   if (!strType.Equals("pictures"))
745     choices.Add(WINDOW_PICTURES, 1);
746   if (!strType.Equals("files"))
747     choices.Add(WINDOW_FILES, 7);
748
749   int window = ShowAndGetChoice(choices);
750   if (window >= 0)
751   {
752     CUtil::DeleteDirectoryCache();
753     g_windowManager.ChangeActiveWindow(window, strPath);
754   }
755 }
756
757 int CGUIDialogContextMenu::ShowAndGetChoice(const CContextButtons &choices)
758 {
759   if (choices.size() == 0)
760     return -1;
761
762   CGUIDialogContextMenu *pMenu = (CGUIDialogContextMenu *)g_windowManager.GetWindow(WINDOW_DIALOG_CONTEXT_MENU);
763   if (pMenu)
764   {
765     if (pMenu->IsDialogRunning())
766       return -1;
767
768     pMenu->m_buttons = choices;
769     pMenu->Initialize();
770     pMenu->SetInitialVisibility();
771     pMenu->SetupButtons();
772     pMenu->PositionAtCurrentFocus();
773     pMenu->DoModal();
774     return pMenu->m_clickedButton;
775   }
776   return -1;
777 }
778
779 void CGUIDialogContextMenu::PositionAtCurrentFocus()
780 {
781   CGUIWindow *window = g_windowManager.GetWindow(g_windowManager.GetFocusedWindow());
782   if (window)
783   {
784     const CGUIControl *focusedControl = window->GetFocusedControl();
785     if (focusedControl)
786     {
787       CPoint pos = focusedControl->GetRenderPosition() + CPoint(focusedControl->GetWidth() * 0.5f, focusedControl->GetHeight() * 0.5f)
788                    + window->GetRenderPosition();
789       SetPosition(m_coordX + pos.x - GetWidth() * 0.5f, m_coordY + pos.y - GetHeight() * 0.5f);
790       return;
791     }
792   }
793   // no control to center at, so just center the window
794   CenterWindow();
795 }