Merge pull request #1590 from jmarshallnz/skin_setpath_specify_path
authorjmarshallnz <jcmarsha@gmail.com>
Sat, 13 Oct 2012 10:09:46 +0000 (03:09 -0700)
committerjmarshallnz <jcmarsha@gmail.com>
Sat, 13 Oct 2012 10:09:46 +0000 (03:09 -0700)
allow skin.setpath to take a second parameter of the path to search

348 files changed:
Makefile.in
XBMC-ATV2.xcodeproj/project.pbxproj
XBMC-IOS.xcodeproj/project.pbxproj
XBMC.xcodeproj/project.pbxproj
addons/library.xbmc.pvr/libXBMC_pvr.h
addons/skin.confluence/720p/DialogAlbumInfo.xml
addons/skin.confluence/720p/DialogMediaFilter.xml [new file with mode: 0644]
addons/skin.confluence/720p/DialogVideoInfo.xml
addons/skin.confluence/720p/DialogVideoScan.xml [deleted file]
addons/skin.confluence/720p/Home.xml
addons/skin.confluence/720p/IncludesBackgroundBuilding.xml
addons/skin.confluence/720p/MusicVisualisation.xml
addons/skin.confluence/720p/MyMusicNav.xml
addons/skin.confluence/720p/MyMusicSongs.xml
addons/skin.confluence/720p/MyPics.xml
addons/skin.confluence/720p/MyPrograms.xml
addons/skin.confluence/720p/MyVideoNav.xml
addons/skin.confluence/720p/PlayerControls.xml
addons/skin.confluence/720p/VideoFullScreen.xml
addons/skin.confluence/720p/VideoOSD.xml
addons/skin.confluence/720p/ViewsFileMode.xml
addons/skin.confluence/720p/ViewsPVR.xml
addons/skin.confluence/720p/ViewsVideoLibrary.xml
addons/skin.confluence/720p/custom_SkinSetting_1111.xml
addons/skin.confluence/720p/includes.xml
addons/skin.confluence/language/English/strings.po
addons/skin.confluence/media/DefaultInProgressShows.png [new file with mode: 0644]
addons/webinterface.default/addon.xml
addons/webinterface.default/icon.png
addons/webinterface.default/images/DefaultAlbumCover.png
addons/webinterface.default/images/DefaultVideo.png
addons/webinterface.default/images/close-button.png
addons/webinterface.default/images/remote.jpg
addons/webinterface.default/index.html
addons/webinterface.default/js/MediaLibrary.js
addons/webinterface.default/js/NowPlayingManager.js
addons/webinterface.default/js/iscroll.js [deleted file]
addons/webinterface.default/js/jquery-1.5.2.js [deleted file]
addons/webinterface.default/js/jquery-1.5.2.min.js [deleted file]
addons/webinterface.default/js/jquery-1.8.2.min.js [new file with mode: 0644]
addons/webinterface.default/js/jquery.lazyload.js [deleted file]
addons/webinterface.default/js/json2.js [new file with mode: 0644]
addons/webinterface.default/js/xbmc.launcher.js
addons/webinterface.default/js/xbmc.rpc.js [new file with mode: 0644]
configure.in
language/English/strings.po
lib/addons/library.xbmc.pvr/libXBMC_pvr.cpp
lib/libUPnP/Platinum/Source/Core/PltService.cpp
lib/libUPnP/Platinum/Source/Core/PltService.h
lib/libUPnP/Platinum/Source/Core/PltStateVariable.cpp
lib/libUPnP/Platinum/Source/Core/PltStateVariable.h
lib/libUPnP/Platinum/Source/Devices/MediaServer/PltDidl.h
lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaItem.cpp
lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaItem.h
lib/libUPnP/Platinum/Source/Devices/MediaServer/PltSyncMediaBrowser.cpp
lib/libUPnP/Platinum/Source/Devices/MediaServer/PltSyncMediaBrowser.h
lib/libcec/Makefile
lib/libshairport/011_fix_ipv4_fallback.patch [new file with mode: 0644]
lib/libshairport/Makefile
media/Fonts/teletext.ttf
project/BuildDependencies/scripts/libcec_d.txt
project/VS2010Express/XBMC.vcxproj
project/VS2010Express/XBMC.vcxproj.filters
system/library/video_flat/movies.xml
system/library/video_flat/musicvideos.xml
system/library/video_flat/tvshows.xml
system/peripherals.xml
tools/android/depends/libshairport/011_fix_ipv4_fallback.patch [new file with mode: 0644]
tools/android/depends/libshairport/Makefile
tools/android/depends/taglib/Makefile
tools/darwin/depends/Makefile.in
tools/darwin/depends/libcec/Makefile
tools/darwin/depends/libjpeg-turbo-native/Makefile [new file with mode: 0644]
tools/darwin/depends/liblzo2-native/Makefile [new file with mode: 0644]
tools/darwin/depends/libpng-native/Makefile [new file with mode: 0644]
tools/darwin/depends/libsdl-native/01-SDL_SetWidthHeight.patch [new file with mode: 0644]
tools/darwin/depends/libsdl-native/02-mmx.patch [new file with mode: 0644]
tools/darwin/depends/libsdl-native/Makefile [new file with mode: 0644]
tools/darwin/depends/libsdl_image-native/Makefile [new file with mode: 0644]
tools/darwin/depends/libshairport/011_fix_ipv4_fallback.patch [new file with mode: 0644]
tools/darwin/depends/libshairport/Makefile
tools/darwin/depends/libtiff-native/Makefile [new file with mode: 0644]
tools/darwin/depends/xbmc-pvr-addons/Makefile
tools/darwin/depends/xbmc/Makefile
tools/rbp/depends/libshairport/011_fix_ipv4_fallback.patch [new file with mode: 0644]
tools/rbp/depends/libshairport/Makefile
xbmc/Application.cpp
xbmc/Application.h
xbmc/ApplicationMessenger.cpp
xbmc/ApplicationMessenger.h
xbmc/AutoSwitch.cpp
xbmc/DbUrl.h
xbmc/Favourites.cpp
xbmc/FileItem.cpp
xbmc/FileItem.h
xbmc/GUIInfoManager.cpp
xbmc/GUIInfoManager.h
xbmc/MediaSource.cpp
xbmc/PartyModeManager.cpp
xbmc/PartyModeManager.h
xbmc/PlayListPlayer.cpp
xbmc/PlayListPlayer.h
xbmc/TextureCache.cpp
xbmc/TextureCache.h
xbmc/ThumbLoader.cpp
xbmc/ThumbLoader.h
xbmc/Util.cpp
xbmc/Util.h
xbmc/XBApplicationEx.cpp
xbmc/XBApplicationEx.h
xbmc/addons/AddonCallbacks.h
xbmc/addons/AddonCallbacksGUI.cpp
xbmc/addons/AddonCallbacksPVR.cpp
xbmc/addons/AddonCallbacksPVR.h
xbmc/addons/AddonDll.h
xbmc/addons/ScreenSaver.cpp
xbmc/addons/Visualisation.cpp
xbmc/addons/include/xbmc_addon_types.h
xbmc/addons/include/xbmc_pvr_dll.h
xbmc/addons/include/xbmc_pvr_types.h
xbmc/cores/AudioEngine/Utils/AEChannelInfo.cpp
xbmc/cores/AudioEngine/Utils/AEChannelInfo.h
xbmc/cores/DllLoader/exports/emu_msvcrt.cpp
xbmc/cores/IPlayer.h
xbmc/cores/VideoRenderers/BaseRenderer.h
xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
xbmc/cores/VideoRenderers/LinuxRendererGL.h
xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
xbmc/cores/VideoRenderers/LinuxRendererGLES.h
xbmc/cores/VideoRenderers/WinRenderer.cpp
xbmc/cores/amlplayer/AMLPlayer.cpp
xbmc/cores/amlplayer/AMLPlayer.h
xbmc/cores/dvdplayer/DVDAudio.cpp
xbmc/cores/dvdplayer/DVDAudio.h
xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxBXA.h
xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp
xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStream.h
xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamHTSP.cpp
xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamHTSP.h
xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamPVRManager.cpp
xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamPVRManager.h
xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamTV.h
xbmc/cores/dvdplayer/DVDPlayer.cpp
xbmc/cores/dvdplayer/DVDPlayer.h
xbmc/cores/dvdplayer/DVDPlayerAudio.cpp
xbmc/cores/dvdplayer/DVDPlayerAudio.h
xbmc/cores/omxplayer/OMXPlayer.cpp
xbmc/cores/omxplayer/OMXPlayer.h
xbmc/cores/paplayer/BXAcodec.cpp [deleted file]
xbmc/cores/paplayer/BXAcodec.h [deleted file]
xbmc/cores/paplayer/CodecFactory.cpp
xbmc/cores/paplayer/Makefile.in
xbmc/dbwrappers/Database.cpp
xbmc/dbwrappers/Database.h
xbmc/dbwrappers/mysqldataset.cpp
xbmc/dialogs/GUIDialogContextMenu.cpp
xbmc/dialogs/GUIDialogFavourites.cpp
xbmc/dialogs/GUIDialogMediaFilter.cpp [new file with mode: 0644]
xbmc/dialogs/GUIDialogMediaFilter.h [new file with mode: 0644]
xbmc/dialogs/GUIDialogMediaSource.cpp
xbmc/dialogs/Makefile
xbmc/filesystem/AddonsDirectory.cpp
xbmc/filesystem/AndroidAppDirectory.cpp
xbmc/filesystem/CacheStrategy.cpp
xbmc/filesystem/CurlFile.cpp
xbmc/filesystem/File.cpp
xbmc/filesystem/HTSPDirectory.cpp
xbmc/filesystem/HTSPSession.cpp
xbmc/filesystem/MultiPathDirectory.cpp
xbmc/filesystem/MultiPathDirectory.h
xbmc/filesystem/MusicDatabaseDirectory.cpp
xbmc/filesystem/MusicDatabaseDirectory/DirectoryNodeOverview.cpp
xbmc/filesystem/MusicDatabaseDirectory/DirectoryNodeSingles.cpp
xbmc/filesystem/MythDirectory.cpp
xbmc/filesystem/MythDirectory.h
xbmc/filesystem/MythSession.cpp
xbmc/filesystem/NptXbmcFile.cpp
xbmc/filesystem/PVRDirectory.cpp
xbmc/filesystem/PVRDirectory.h
xbmc/filesystem/PluginDirectory.cpp
xbmc/filesystem/RSSDirectory.cpp
xbmc/filesystem/SmartPlaylistDirectory.cpp
xbmc/filesystem/SmartPlaylistDirectory.h
xbmc/filesystem/SourcesDirectory.cpp
xbmc/filesystem/UPnPDirectory.cpp
xbmc/filesystem/VideoDatabaseDirectory.cpp
xbmc/guilib/GUIControl.h
xbmc/guilib/GUIFontManager.cpp
xbmc/guilib/GUIFontManager.h
xbmc/guilib/GUIListItem.cpp
xbmc/guilib/GUIListItem.h
xbmc/guilib/GUISliderControl.cpp
xbmc/guilib/GUISliderControl.h
xbmc/guilib/GUIStaticItem.cpp
xbmc/guilib/GUIWindow.cpp
xbmc/guilib/GUIWindow.h
xbmc/guilib/Key.h
xbmc/guilib/Texture.cpp
xbmc/input/ButtonTranslator.cpp
xbmc/interfaces/AnnouncementManager.cpp
xbmc/interfaces/Builtins.cpp
xbmc/interfaces/http-api/HttpApi.cpp [deleted file]
xbmc/interfaces/http-api/HttpApi.h [deleted file]
xbmc/interfaces/http-api/Makefile [deleted file]
xbmc/interfaces/http-api/XBMCConfiguration.cpp [deleted file]
xbmc/interfaces/http-api/XBMCConfiguration.h [deleted file]
xbmc/interfaces/http-api/XBMChttp.cpp [deleted file]
xbmc/interfaces/http-api/XBMChttp.h [deleted file]
xbmc/interfaces/json-rpc/AudioLibrary.cpp
xbmc/interfaces/json-rpc/FileItemHandler.cpp
xbmc/interfaces/json-rpc/FileItemHandler.h
xbmc/interfaces/json-rpc/ServiceDescription.h
xbmc/interfaces/json-rpc/VideoLibrary.cpp
xbmc/interfaces/json-rpc/methods.json
xbmc/interfaces/json-rpc/notifications.json
xbmc/interfaces/json-rpc/types.json
xbmc/interfaces/legacy/File.cpp
xbmc/interfaces/legacy/ListItem.cpp
xbmc/interfaces/legacy/ModuleXbmc.cpp
xbmc/interfaces/legacy/ModuleXbmc.h
xbmc/linux/XFileUtils.cpp
xbmc/music/LastFmManager.cpp
xbmc/music/MusicDatabase.cpp
xbmc/music/MusicDatabase.h
xbmc/music/MusicDbUrl.cpp
xbmc/music/MusicInfoLoader.cpp
xbmc/music/dialogs/GUIDialogMusicInfo.cpp
xbmc/music/dialogs/GUIDialogSongInfo.cpp
xbmc/music/infoscanner/MusicInfoScanner.cpp
xbmc/music/tags/MusicInfoTag.cpp
xbmc/music/tags/TagLoaderTagLib.cpp
xbmc/music/tags/TagLoaderTagLib.h
xbmc/music/windows/GUIWindowMusicBase.cpp
xbmc/music/windows/GUIWindowMusicBase.h
xbmc/music/windows/GUIWindowMusicNav.cpp
xbmc/music/windows/GUIWindowMusicSongs.cpp
xbmc/network/AirTunesServer.cpp
xbmc/network/GUIDialogAccessPoints.cpp
xbmc/network/cddb.cpp
xbmc/network/httprequesthandler/HTTPApiHandler.cpp [deleted file]
xbmc/network/httprequesthandler/HTTPApiHandler.h [deleted file]
xbmc/network/httprequesthandler/Makefile
xbmc/network/upnp/UPnP.cpp
xbmc/network/upnp/UPnPInternal.cpp
xbmc/network/upnp/UPnPInternal.h
xbmc/network/upnp/UPnPRenderer.cpp
xbmc/network/upnp/UPnPRenderer.h
xbmc/network/upnp/UPnPServer.cpp
xbmc/network/upnp/UPnPServer.h
xbmc/peripherals/devices/PeripheralCecAdapter.cpp
xbmc/peripherals/devices/PeripheralCecAdapter.h
xbmc/pictures/GUIWindowPictures.cpp
xbmc/pictures/GUIWindowSlideShow.cpp
xbmc/pictures/GUIWindowSlideShow.h
xbmc/pictures/PictureInfoLoader.cpp
xbmc/pictures/PictureThumbLoader.cpp
xbmc/playlists/SmartPlayList.cpp
xbmc/playlists/SmartPlayList.h
xbmc/pvr/addons/PVRClient.cpp
xbmc/pvr/addons/PVRClient.h
xbmc/pvr/addons/PVRClients.cpp
xbmc/pvr/addons/PVRClients.h
xbmc/pvr/channels/PVRChannelGroup.cpp
xbmc/pvr/channels/PVRChannelGroupsContainer.cpp
xbmc/pvr/channels/PVRChannelGroupsContainer.h
xbmc/pvr/dialogs/GUIDialogPVRChannelManager.cpp
xbmc/pvr/dialogs/GUIDialogPVRGuideInfo.cpp
xbmc/pvr/recordings/PVRRecordings.cpp
xbmc/pvr/timers/PVRTimerInfoTag.cpp
xbmc/pvr/timers/PVRTimerInfoTag.h
xbmc/pvr/windows/GUIWindowPVRChannels.cpp
xbmc/settings/AdvancedSettings.cpp
xbmc/settings/GUIDialogContentSettings.cpp
xbmc/settings/GUIDialogProfileSettings.cpp
xbmc/settings/GUIDialogSettings.cpp
xbmc/settings/GUIDialogSettings.h
xbmc/settings/GUISettings.cpp
xbmc/settings/GUIWindowSettingsCategory.cpp
xbmc/settings/GUIWindowSettingsProfile.cpp
xbmc/settings/Settings.cpp
xbmc/settings/Settings.h
xbmc/system.h
xbmc/test/Makefile
xbmc/test/TestFileItem.cpp [new file with mode: 0644]
xbmc/utils/Archive.cpp
xbmc/utils/Archive.h
xbmc/utils/DatabaseUtils.cpp
xbmc/utils/DatabaseUtils.h
xbmc/utils/FileOperationJob.cpp
xbmc/utils/RecentlyAddedJob.cpp
xbmc/utils/ScraperUrl.cpp
xbmc/utils/ScraperUrl.h
xbmc/utils/StringUtils.cpp
xbmc/utils/TuxBoxUtil.cpp
xbmc/utils/URIUtils.cpp
xbmc/utils/URIUtils.h
xbmc/utils/UrlOptions.cpp
xbmc/utils/UrlOptions.h
xbmc/utils/Variant.cpp
xbmc/utils/Variant.h
xbmc/utils/test/TestStringUtils.cpp
xbmc/utils/test/TestVariant.cpp
xbmc/video/VideoDatabase.cpp
xbmc/video/VideoDatabase.h
xbmc/video/VideoInfoScanner.cpp
xbmc/video/VideoInfoScanner.h
xbmc/video/VideoInfoTag.cpp
xbmc/video/VideoInfoTag.h
xbmc/video/dialogs/GUIDialogAudioSubtitleSettings.cpp
xbmc/video/dialogs/GUIDialogAudioSubtitleSettings.h
xbmc/video/dialogs/GUIDialogVideoBookmarks.cpp
xbmc/video/dialogs/GUIDialogVideoInfo.cpp
xbmc/video/dialogs/GUIDialogVideoInfo.h
xbmc/video/dialogs/GUIDialogVideoScan.cpp [deleted file]
xbmc/video/dialogs/GUIDialogVideoScan.h [deleted file]
xbmc/video/dialogs/GUIDialogVideoSettings.cpp
xbmc/video/dialogs/Makefile
xbmc/video/windows/GUIWindowVideoBase.cpp
xbmc/video/windows/GUIWindowVideoBase.h
xbmc/video/windows/GUIWindowVideoNav.cpp
xbmc/windowing/WindowingFactory.h
xbmc/windowing/egl/EGLNativeType.h [new file with mode: 0644]
xbmc/windowing/egl/EGLNativeTypeAmlogic.cpp [new file with mode: 0644]
xbmc/windowing/egl/EGLNativeTypeAmlogic.h [new file with mode: 0644]
xbmc/windowing/egl/EGLNativeTypeAndroid.cpp [new file with mode: 0644]
xbmc/windowing/egl/EGLNativeTypeAndroid.h [new file with mode: 0644]
xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp [new file with mode: 0644]
xbmc/windowing/egl/EGLNativeTypeRaspberryPI.h [new file with mode: 0644]
xbmc/windowing/egl/EGLQuirks.h [new file with mode: 0644]
xbmc/windowing/egl/EGLWrapper.cpp [new file with mode: 0644]
xbmc/windowing/egl/EGLWrapper.h [new file with mode: 0644]
xbmc/windowing/egl/Makefile
xbmc/windowing/egl/WinEGLPlatform.h [deleted file]
xbmc/windowing/egl/WinEGLPlatformAndroid.cpp [deleted file]
xbmc/windowing/egl/WinEGLPlatformAndroid.h [deleted file]
xbmc/windowing/egl/WinEGLPlatformGeneric.cpp [deleted file]
xbmc/windowing/egl/WinEGLPlatformGeneric.h [deleted file]
xbmc/windowing/egl/WinEGLPlatformRaspberryPI.cpp [deleted file]
xbmc/windowing/egl/WinEGLPlatformRaspberryPI.h [deleted file]
xbmc/windowing/egl/WinSystemEGL.cpp [new file with mode: 0644]
xbmc/windowing/egl/WinSystemEGL.h [new file with mode: 0644]
xbmc/windowing/egl/WinSystemGLES.cpp [deleted file]
xbmc/windowing/egl/WinSystemGLES.h [deleted file]
xbmc/windows/GUIMediaWindow.cpp
xbmc/windows/GUIMediaWindow.h
xbmc/windows/GUIWindowFileManager.cpp
xbmc/windows/GUIWindowLoginScreen.cpp

index 97ae7eb..31826b1 100644 (file)
@@ -48,7 +48,6 @@ DIRECTORY_ARCHIVES=$(DVDPLAYER_ARCHIVES) \
                    xbmc/filesystem/filesystem.a \
                    xbmc/guilib/guilib.a \
                    xbmc/input/input.a \
-                   xbmc/interfaces/http-api/http-api.a \
                    xbmc/interfaces/info/info.a \
                    xbmc/interfaces/interfaces.a \
                    xbmc/interfaces/json-rpc/json-rpc.a \
index efaca0d..62336f4 100644 (file)
@@ -26,6 +26,7 @@
                36A9468815CF214300727135 /* VideoDbUrl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A9468615CF214300727135 /* VideoDbUrl.cpp */; };
                36A9468B15CF215300727135 /* UrlOptions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A9468915CF215300727135 /* UrlOptions.cpp */; };
                36A9468E15CF217400727135 /* MusicDbUrl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A9468C15CF217400727135 /* MusicDbUrl.cpp */; };
+               36A95DB41624898700727135 /* GUIDialogMediaFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A95DB21624898700727135 /* GUIDialogMediaFilter.cpp */; };
                4D5D2E131301753F006ABC13 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D5D2E121301753F006ABC13 /* CFNetwork.framework */; };
                7C0A7ECD13A5DBF900AFC2BD /* AppParamParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C0A7ECB13A5DBF900AFC2BD /* AppParamParser.cpp */; };
                7C0A7FC813A9E75400AFC2BD /* DirtyRegionSolvers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C0A7FC413A9E75400AFC2BD /* DirtyRegionSolvers.cpp */; };
                DF33C2A415509C1B0046CDCB /* XbmcContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF33C2A215509C1B0046CDCB /* XbmcContext.cpp */; };
                DF33C2AE15509C5A0046CDCB /* ilog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF33C2AB15509C5A0046CDCB /* ilog.cpp */; };
                DF34890913FD96390026A711 /* GUIAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF34890713FD96390026A711 /* GUIAction.cpp */; };
-               DF44852F140064F40069344B /* BXAcodec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF44852D140064F40069344B /* BXAcodec.cpp */; };
                DF4485351400651B0069344B /* PipesManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF4485321400651B0069344B /* PipesManager.cpp */; };
                DF4485381400654A0069344B /* AirTunesServer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF4485361400654A0069344B /* AirTunesServer.cpp */; };
                DF527780151BAFD600B5B63B /* WebSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF527777151BAFD600B5B63B /* WebSocket.cpp */; };
                DFC0F8F51613A1960066D598 /* XLCDproc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFC0F8F31613A1960066D598 /* XLCDproc.cpp */; };
                DFC0F91C1613A3A00066D598 /* LCDFactory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFC0F91A1613A3A00066D598 /* LCDFactory.cpp */; };
                DFC5393A1526659D00D5FD5C /* AppIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = DFC539391526659D00D5FD5C /* AppIcon.png */; };
-               DFCA6B0B15224684000BFAAE /* HTTPApiHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFCA6AFE15224684000BFAAE /* HTTPApiHandler.cpp */; };
                DFCA6B0C15224684000BFAAE /* HTTPJsonRpcHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFCA6B0015224684000BFAAE /* HTTPJsonRpcHandler.cpp */; };
                DFCA6B0D15224684000BFAAE /* HTTPVfsHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFCA6B0215224684000BFAAE /* HTTPVfsHandler.cpp */; };
                DFCA6B0E15224684000BFAAE /* HTTPWebinterfaceAddonsHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFCA6B0415224684000BFAAE /* HTTPWebinterfaceAddonsHandler.cpp */; };
                F56C7B4C131EC155000AD0F6 /* GUIDialogVideoInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F56C7785131EC154000AD0F6 /* GUIDialogVideoInfo.cpp */; };
                F56C7B4D131EC155000AD0F6 /* GUIDialogVideoOSD.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F56C7787131EC154000AD0F6 /* GUIDialogVideoOSD.cpp */; };
                F56C7B4E131EC155000AD0F6 /* GUIDialogVideoOverlay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F56C7789131EC154000AD0F6 /* GUIDialogVideoOverlay.cpp */; };
-               F56C7B4F131EC155000AD0F6 /* GUIDialogVideoScan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F56C778B131EC154000AD0F6 /* GUIDialogVideoScan.cpp */; };
                F56C7B50131EC155000AD0F6 /* GUIDialogVideoSettings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F56C778D131EC154000AD0F6 /* GUIDialogVideoSettings.cpp */; };
                F56C7B51131EC155000AD0F6 /* GUIWindowFullScreen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F56C7790131EC154000AD0F6 /* GUIWindowFullScreen.cpp */; };
                F56C7B52131EC155000AD0F6 /* GUIWindowVideoBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F56C7792131EC154000AD0F6 /* GUIWindowVideoBase.cpp */; };
                F589AE8212890BEF00D8079E /* libsquish.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F589AE7D12890BEF00D8079E /* libsquish.a */; };
                F589AE8312890BEF00D8079E /* librtv.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F589AE7E12890BEF00D8079E /* librtv.a */; settings = {ATTRIBUTES = (Required, ); }; };
                F589AE8512890BEF00D8079E /* libxdaap.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F589AE8012890BEF00D8079E /* libxdaap.a */; settings = {ATTRIBUTES = (Required, ); }; };
+               F592D4BF162495B10023BCE7 /* NptPosixTime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F592D4BE162495B00023BCE7 /* NptPosixTime.cpp */; };
+               F592D4C2162496620023BCE7 /* NptHash.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F592D4C0162496620023BCE7 /* NptHash.cpp */; };
                F5A29EC312A7221B003A610C /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F5A29EC212A7221B003A610C /* CoreMedia.framework */; };
                F5A29F2712A72246003A610C /* VideoToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F5A29F2612A72246003A610C /* VideoToolbox.framework */; };
-               F5AE40EA134175160004BD79 /* HttpApi.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5AE40E6134175160004BD79 /* HttpApi.cpp */; };
-               F5AE40EB134175160004BD79 /* XBMChttp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5AE40E8134175160004BD79 /* XBMChttp.cpp */; };
                F5AE41081341751E0004BD79 /* AudioLibrary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5AE40ED1341751E0004BD79 /* AudioLibrary.cpp */; };
                F5AE410B1341751E0004BD79 /* FileItemHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5AE40F31341751E0004BD79 /* FileItemHandler.cpp */; };
                F5AE410C1341751E0004BD79 /* FileOperations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5AE40F51341751E0004BD79 /* FileOperations.cpp */; };
                36A9468A15CF215300727135 /* UrlOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UrlOptions.h; sourceTree = "<group>"; };
                36A9468C15CF217400727135 /* MusicDbUrl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MusicDbUrl.cpp; sourceTree = "<group>"; };
                36A9468D15CF217400727135 /* MusicDbUrl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MusicDbUrl.h; sourceTree = "<group>"; };
+               36A95DB21624898700727135 /* GUIDialogMediaFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIDialogMediaFilter.cpp; sourceTree = "<group>"; };
+               36A95DB31624898700727135 /* GUIDialogMediaFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIDialogMediaFilter.h; sourceTree = "<group>"; };
                4D5D2E121301753F006ABC13 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; };
                7C0A7ECB13A5DBF900AFC2BD /* AppParamParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AppParamParser.cpp; sourceTree = "<group>"; };
                7C0A7ECC13A5DBF900AFC2BD /* AppParamParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppParamParser.h; sourceTree = "<group>"; };
                DF33C2AC15509C5A0046CDCB /* ilog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ilog.h; sourceTree = "<group>"; };
                DF34890713FD96390026A711 /* GUIAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIAction.cpp; sourceTree = "<group>"; };
                DF34890813FD96390026A711 /* GUIAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIAction.h; sourceTree = "<group>"; };
-               DF44852D140064F40069344B /* BXAcodec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BXAcodec.cpp; sourceTree = "<group>"; };
-               DF44852E140064F40069344B /* BXAcodec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BXAcodec.h; sourceTree = "<group>"; };
                DF4485321400651B0069344B /* PipesManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PipesManager.cpp; sourceTree = "<group>"; };
                DF4485331400651B0069344B /* PipesManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PipesManager.h; sourceTree = "<group>"; };
                DF4485361400654A0069344B /* AirTunesServer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AirTunesServer.cpp; sourceTree = "<group>"; };
                DFC0F91A1613A3A00066D598 /* LCDFactory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LCDFactory.cpp; sourceTree = "<group>"; };
                DFC0F91B1613A3A00066D598 /* LCDFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LCDFactory.h; sourceTree = "<group>"; };
                DFC539391526659D00D5FD5C /* AppIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = AppIcon.png; path = media/AppIcon.png; sourceTree = "<group>"; };
-               DFCA6AFE15224684000BFAAE /* HTTPApiHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HTTPApiHandler.cpp; sourceTree = "<group>"; };
-               DFCA6AFF15224684000BFAAE /* HTTPApiHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPApiHandler.h; sourceTree = "<group>"; };
                DFCA6B0015224684000BFAAE /* HTTPJsonRpcHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HTTPJsonRpcHandler.cpp; sourceTree = "<group>"; };
                DFCA6B0115224684000BFAAE /* HTTPJsonRpcHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPJsonRpcHandler.h; sourceTree = "<group>"; };
                DFCA6B0215224684000BFAAE /* HTTPVfsHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HTTPVfsHandler.cpp; sourceTree = "<group>"; };
                F56C7788131EC154000AD0F6 /* GUIDialogVideoOSD.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIDialogVideoOSD.h; sourceTree = "<group>"; };
                F56C7789131EC154000AD0F6 /* GUIDialogVideoOverlay.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIDialogVideoOverlay.cpp; sourceTree = "<group>"; };
                F56C778A131EC154000AD0F6 /* GUIDialogVideoOverlay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIDialogVideoOverlay.h; sourceTree = "<group>"; };
-               F56C778B131EC154000AD0F6 /* GUIDialogVideoScan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIDialogVideoScan.cpp; sourceTree = "<group>"; };
-               F56C778C131EC154000AD0F6 /* GUIDialogVideoScan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIDialogVideoScan.h; sourceTree = "<group>"; };
                F56C778D131EC154000AD0F6 /* GUIDialogVideoSettings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIDialogVideoSettings.cpp; sourceTree = "<group>"; };
                F56C778E131EC154000AD0F6 /* GUIDialogVideoSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIDialogVideoSettings.h; sourceTree = "<group>"; };
                F56C7790131EC154000AD0F6 /* GUIWindowFullScreen.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIWindowFullScreen.cpp; sourceTree = "<group>"; };
                F589AE7D12890BEF00D8079E /* libsquish.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libsquish.a; path = lib/libsquish/libsquish.a; sourceTree = "<group>"; };
                F589AE7E12890BEF00D8079E /* librtv.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = librtv.a; path = lib/libRTV/librtv.a; sourceTree = "<group>"; };
                F589AE8012890BEF00D8079E /* libxdaap.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libxdaap.a; path = lib/libXDAAP/libxdaap.a; sourceTree = "<group>"; };
+               F592D4BE162495B00023BCE7 /* NptPosixTime.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NptPosixTime.cpp; path = lib/libUPnP/Neptune/Source/System/Posix/NptPosixTime.cpp; sourceTree = SOURCE_ROOT; };
+               F592D4C0162496620023BCE7 /* NptHash.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NptHash.cpp; path = lib/libUPnP/Neptune/Source/Core/NptHash.cpp; sourceTree = SOURCE_ROOT; };
+               F592D4C1162496620023BCE7 /* NptHash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NptHash.h; path = lib/libUPnP/Neptune/Source/Core/NptHash.h; sourceTree = SOURCE_ROOT; };
                F5A29EC212A7221B003A610C /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };
                F5A29F2612A72246003A610C /* VideoToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = VideoToolbox.framework; path = System/Library/PrivateFrameworks/VideoToolbox.framework; sourceTree = SDKROOT; };
-               F5AE40E6134175160004BD79 /* HttpApi.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HttpApi.cpp; sourceTree = "<group>"; };
-               F5AE40E7134175160004BD79 /* HttpApi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HttpApi.h; sourceTree = "<group>"; };
-               F5AE40E8134175160004BD79 /* XBMChttp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = XBMChttp.cpp; sourceTree = "<group>"; };
-               F5AE40E9134175160004BD79 /* XBMChttp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XBMChttp.h; sourceTree = "<group>"; };
                F5AE40ED1341751E0004BD79 /* AudioLibrary.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AudioLibrary.cpp; sourceTree = "<group>"; };
                F5AE40EE1341751E0004BD79 /* AudioLibrary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioLibrary.h; sourceTree = "<group>"; };
                F5AE40F31341751E0004BD79 /* FileItemHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileItemHandler.cpp; sourceTree = "<group>"; };
                DFCA6AFD15224684000BFAAE /* httprequesthandler */ = {
                        isa = PBXGroup;
                        children = (
-                               DFCA6AFE15224684000BFAAE /* HTTPApiHandler.cpp */,
-                               DFCA6AFF15224684000BFAAE /* HTTPApiHandler.h */,
                                7C6EB706155F3B160080368A /* HTTPImageHandler.cpp */,
                                7C6EB707155F3B160080368A /* HTTPImageHandler.h */,
                                DFCA6B0015224684000BFAAE /* HTTPJsonRpcHandler.cpp */,
                                F56C7305131EC151000AD0F6 /* ASAPCodec.h */,
                                F56C730C131EC151000AD0F6 /* AudioDecoder.cpp */,
                                F56C730D131EC151000AD0F6 /* AudioDecoder.h */,
-                               DF44852D140064F40069344B /* BXAcodec.cpp */,
-                               DF44852E140064F40069344B /* BXAcodec.h */,
                                F56C730E131EC151000AD0F6 /* CachingCodec.h */,
                                F56C730F131EC151000AD0F6 /* CDDAcodec.cpp */,
                                F56C7310131EC151000AD0F6 /* CDDAcodec.h */,
                                F56C7374131EC151000AD0F6 /* GUIDialogKaiToast.h */,
                                DF830D4915BB2D2300602BE6 /* GUIDialogKeyboardGeneric.cpp */,
                                DF830D4A15BB2D2300602BE6 /* GUIDialogKeyboardGeneric.h */,
+                               36A95DB21624898700727135 /* GUIDialogMediaFilter.cpp */,
+                               36A95DB31624898700727135 /* GUIDialogMediaFilter.h */,
                                F56C7377131EC151000AD0F6 /* GUIDialogMediaSource.cpp */,
                                F56C7378131EC151000AD0F6 /* GUIDialogMediaSource.h */,
                                F56C7379131EC151000AD0F6 /* GUIDialogMuteBug.cpp */,
                F56C7563131EC152000AD0F6 /* interfaces */ = {
                        isa = PBXGroup;
                        children = (
-                               F5AE40E5134175160004BD79 /* http-api */,
                                F5E6209C13E9081400D5F2CD /* info */,
                                F5AE40EC1341751E0004BD79 /* json-rpc */,
                                DF1AD02D15FCE62E00E10810 /* legacy */,
                                F56C7788131EC154000AD0F6 /* GUIDialogVideoOSD.h */,
                                F56C7789131EC154000AD0F6 /* GUIDialogVideoOverlay.cpp */,
                                F56C778A131EC154000AD0F6 /* GUIDialogVideoOverlay.h */,
-                               F56C778B131EC154000AD0F6 /* GUIDialogVideoScan.cpp */,
-                               F56C778C131EC154000AD0F6 /* GUIDialogVideoScan.h */,
                                F56C778D131EC154000AD0F6 /* GUIDialogVideoSettings.cpp */,
                                F56C778E131EC154000AD0F6 /* GUIDialogVideoSettings.h */,
                        );
                                F56C7CFD131EF8D9000AD0F6 /* NptPosixQueue.cpp */,
                                F56C7CFE131EF8D9000AD0F6 /* NptPosixSystem.cpp */,
                                F56C7CFF131EF8D9000AD0F6 /* NptPosixThreads.cpp */,
+                               F592D4BE162495B00023BCE7 /* NptPosixTime.cpp */,
                                F56C7CCC131EF8D8000AD0F6 /* NptQueue.cpp */,
                                F56C7CCD131EF8D8000AD0F6 /* NptQueue.h */,
                                F56C7CCE131EF8D8000AD0F6 /* NptReferences.h */,
                                F56C7D0C131EF8D9000AD0F6 /* Neptune.cpp */,
                                F56C7D0D131EF8D9000AD0F6 /* Neptune.h */,
                                F56C7D13131EF8D9000AD0F6 /* PltAction.cpp */,
+                               F592D4C0162496620023BCE7 /* NptHash.cpp */,
+                               F592D4C1162496620023BCE7 /* NptHash.h */,
                                F56C7D14131EF8D9000AD0F6 /* PltAction.h */,
                                F56C7D15131EF8D9000AD0F6 /* PltArgument.cpp */,
                                F56C7D16131EF8D9000AD0F6 /* PltArgument.h */,
                        name = "Internal Libs";
                        sourceTree = "<group>";
                };
-               F5AE40E5134175160004BD79 /* http-api */ = {
-                       isa = PBXGroup;
-                       children = (
-                               F5AE40E6134175160004BD79 /* HttpApi.cpp */,
-                               F5AE40E7134175160004BD79 /* HttpApi.h */,
-                               F5AE40E8134175160004BD79 /* XBMChttp.cpp */,
-                               F5AE40E9134175160004BD79 /* XBMChttp.h */,
-                       );
-                       path = "http-api";
-                       sourceTree = "<group>";
-               };
                F5AE40EC1341751E0004BD79 /* json-rpc */ = {
                        isa = PBXGroup;
                        children = (
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        shellPath = /bin/bash;
-                       shellScript = "#set -x\n\nfunction check_dyloaded_depends\n{\n  b=$(find \"$EXTERNAL_LIBS\" -name $1 -print)\n  if [ -f \"$b\" ]; then\n    #echo \"Processing $b\"\n    if [ ! -f  \"$TARGET_FRAMEWORKS/$(basename $b)\" ]; then\n      echo \"    Packaging $b\"\n      cp -f \"$b\" \"$TARGET_FRAMEWORKS/\"\n      chmod u+w \"$TARGET_FRAMEWORKS/$(basename $b)\"\n    fi\n    for a in $(otool -L \"$b\"  | grep \"$EXTERNAL_LIBS\" | awk ' { print $1 } ') ; do\n      if [ -f \"$a\" ]; then\n        if [ ! -f  \"$TARGET_FRAMEWORKS/$(basename $a)\" ]; then\n          echo \"    Packaging $a\"\n          cp -f \"$a\" \"$TARGET_FRAMEWORKS/\"\n          chmod u+w \"$TARGET_FRAMEWORKS/$(basename $a)\"\n          install_name_tool -change \"$a\" \"$DYLIB_NAMEPATH/$(basename $a)\" \"$TARGET_FRAMEWORKS/$(basename $b)\"\n        fi\n      fi\n    done \n  fi\n}\n\nfunction check_xbmc_dylib_depends\n{\n  REWIND=\"1\"\n  while [ $REWIND = \"1\" ]\n  do\n    let REWIND=\"0\"\n    for b in $(find \"$1\" -name \"$2\" -print) ; do\n      #echo \"Processing $b\"\n      install_name_tool -id \"$(basename $b)\" \"$b\"\n      for a in $(otool -L \"$b\"  | grep \"$EXTERNAL_LIBS\" | awk ' { print $1 } ') ; do\n        #echo \"    Packaging $a\"\n        if [ ! -f  \"$TARGET_FRAMEWORKS/$(basename $a)\" ]; then\n          echo \"    Packaging $a\"\n          cp -f \"$a\" \"$TARGET_FRAMEWORKS/\"\n          chmod u+w \"$TARGET_FRAMEWORKS/$(basename $a)\"\n          let REWIND=\"1\"\n        fi\n        install_name_tool -change \"$a\" \"$DYLIB_NAMEPATH/$(basename $a)\" \"$b\"\n      done\n    done\n  done\n}\n\nEXTERNAL_LIBS=/Users/Shared/xbmc-depends/\"$SDK_NAME\"_\"$ARCHS\"\n\nTARGET_NAME=$PRODUCT_NAME.$WRAPPER_EXTENSION\nTARGET_CONTENTS=$TARGET_BUILD_DIR/$TARGET_NAME\n\nTARGET_BINARY=$TARGET_CONTENTS/XBMC\nTARGET_FRAMEWORKS=$TARGET_CONTENTS/Frameworks\nDYLIB_NAMEPATH=@executable_path/Appliances/XBMC.frappliance/Frameworks\nXBMC_HOME=$TARGET_CONTENTS/XBMCData/XBMCHome\n\nmkdir -p \"$TARGET_CONTENTS\"\nmkdir -p \"$TARGET_CONTENTS/XBMCData/XBMCHome\"\n# start clean so we don't keep old dylibs\nrm -rf \"$TARGET_CONTENTS/Frameworks\"\nmkdir -p \"$TARGET_CONTENTS/Frameworks\"\n\necho \"Package $TARGET_BUILD_DIR/XBMC\"\n\n# Copy all of XBMC's dylib dependencies and rename their locations to inside the Framework\necho \"Checking $TARGET_BINARY dylib dependencies\"\nfor a in $(otool -L \"$TARGET_BINARY\"  | grep \"$EXTERNAL_LIBS\" | awk ' { print $1 } ') ; do \n\techo \"    Packaging $a\"\n\tcp -f \"$a\" \"$TARGET_FRAMEWORKS/\"\n\tchmod u+w \"$TARGET_FRAMEWORKS/$(basename $a)\"\n\tinstall_name_tool -change \"$a\" \"$DYLIB_NAMEPATH/$(basename $a)\" \"$TARGET_BINARY\"\ndone\n\necho \"Package $EXTERNAL_LIBS/lib/python2.6\"\nmkdir -p \"$TARGET_CONTENTS/Frameworks/lib\"\nPYTHONSYNC=\"rsync -aq --exclude .DS_Store --exclude *.a --exclude *.exe --exclude test --exclude tests\"\n${PYTHONSYNC} \"$EXTERNAL_LIBS/lib/python2.6\" \"$TARGET_FRAMEWORKS/lib/\"\nrm -rf \"$TARGET_FRAMEWORKS/lib/python2.6/config\"\n\necho \"Checking $TARGET_FRAMEWORKS/lib/python2.6 *.so for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$TARGET_FRAMEWORKS\"/lib/python2.6 \"*.so\"\n\necho \"Checking $XBMC_HOME/system *.so for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$XBMC_HOME\"/system \"*.so\"\n\necho \"Checking $XBMC_HOME/addons *.so for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$XBMC_HOME\"/addons \"*.so\"\n\necho \"Checking $XBMC_HOME/addons *.pvr for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$XBMC_HOME\"/addons \"*.pvr\"\n\necho \"Checking $XBMC_HOME/addons *.xbs for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$XBMC_HOME\"/addons \"*.xbs\"\n\necho \"Checking xbmc/DllPaths_generated.h for dylib dependencies\"\nfor a in $(grep .dylib \"$SRCROOT\"/xbmc/DllPaths_generated.h | awk '{print $3}' | sed s/\\\"//g) ; do\n  check_dyloaded_depends $a\ndone\n\necho \"Checking $TARGET_FRAMEWORKS for missing dylib dependencies\"\nREWIND=\"1\"\nwhile [ $REWIND = \"1\" ]\ndo\n\tlet REWIND=\"0\"\n\tfor b in \"$TARGET_FRAMEWORKS/\"*dylib* ; do\n\t\t#echo \"  Processing $b\"\n\t\tfor a in $(otool -L \"$b\"  | grep \"$EXTERNAL_LIBS\" | awk ' { print $1 } ') ; do\n\t\t\t#echo \"Processing $a\"\n\t\t\tif [ ! -f  \"$TARGET_FRAMEWORKS/$(basename $a)\" ]; then\n\t\t\t\techo \"    Packaging $a\"\n\t\t\t\tcp -f \"$a\" \"$TARGET_FRAMEWORKS/\"\n\t\t\t\tchmod u+w \"$TARGET_FRAMEWORKS/$(basename $a)\"\n\t\t\t\tlet REWIND=\"1\"\n\t\t\tfi\n\t\t\tinstall_name_tool -change \"$a\" \"$DYLIB_NAMEPATH/$(basename $a)\" \"$TARGET_FRAMEWORKS/$(basename $b)\"\n\t\tdone \n\tdone\ndone\n";
+                       shellScript = "#set -x\n\nfunction check_dyloaded_depends\n{\n  b=$(find \"$EXTERNAL_LIBS\" -name $1 -print)\n  if [ -f \"$b\" ]; then\n    #echo \"Processing $b\"\n    if [ ! -f  \"$TARGET_FRAMEWORKS/$(basename $b)\" ]; then\n      echo \"    Packaging $b\"\n      cp -f \"$b\" \"$TARGET_FRAMEWORKS/\"\n      chmod u+w \"$TARGET_FRAMEWORKS/$(basename $b)\"\n    fi\n    for a in $(otool -L \"$b\"  | grep \"$EXTERNAL_LIBS\" | awk ' { print $1 } ') ; do\n      if [ -f \"$a\" ]; then\n        if [ ! -f  \"$TARGET_FRAMEWORKS/$(basename $a)\" ]; then\n          echo \"    Packaging $a\"\n          cp -f \"$a\" \"$TARGET_FRAMEWORKS/\"\n          chmod u+w \"$TARGET_FRAMEWORKS/$(basename $a)\"\n          install_name_tool -change \"$a\" \"$DYLIB_NAMEPATH/$(basename $a)\" \"$TARGET_FRAMEWORKS/$(basename $b)\"\n        fi\n      fi\n    done \n  fi\n}\n\nfunction check_xbmc_dylib_depends\n{\n  REWIND=\"1\"\n  while [ $REWIND = \"1\" ]\n  do\n    let REWIND=\"0\"\n    for b in $(find \"$1\" -type f -name \"$2\" -print) ; do\n      #echo \"Processing $b\"\n      install_name_tool -id \"$(basename $b)\" \"$b\"\n      for a in $(otool -L \"$b\"  | grep \"$EXTERNAL_LIBS\" | awk ' { print $1 } ') ; do\n        #echo \"    Packaging $a\"\n        if [ ! -f  \"$TARGET_FRAMEWORKS/$(basename $a)\" ]; then\n          echo \"    Packaging $a\"\n          cp -f \"$a\" \"$TARGET_FRAMEWORKS/\"\n          chmod u+w \"$TARGET_FRAMEWORKS/$(basename $a)\"\n          let REWIND=\"1\"\n        fi\n        install_name_tool -change \"$a\" \"$DYLIB_NAMEPATH/$(basename $a)\" \"$b\"\n      done\n    done\n  done\n}\n\nEXTERNAL_LIBS=/Users/Shared/xbmc-depends/\"$SDK_NAME\"_\"$ARCHS\"\n\nTARGET_NAME=$PRODUCT_NAME.$WRAPPER_EXTENSION\nTARGET_CONTENTS=$TARGET_BUILD_DIR/$TARGET_NAME\n\nTARGET_BINARY=$TARGET_CONTENTS/XBMC\nTARGET_FRAMEWORKS=$TARGET_CONTENTS/Frameworks\nDYLIB_NAMEPATH=@executable_path/Appliances/XBMC.frappliance/Frameworks\nXBMC_HOME=$TARGET_CONTENTS/XBMCData/XBMCHome\n\nmkdir -p \"$TARGET_CONTENTS\"\nmkdir -p \"$TARGET_CONTENTS/XBMCData/XBMCHome\"\n# start clean so we don't keep old dylibs\nrm -rf \"$TARGET_CONTENTS/Frameworks\"\nmkdir -p \"$TARGET_CONTENTS/Frameworks\"\n\necho \"Package $TARGET_BUILD_DIR/XBMC\"\n\n# Copy all of XBMC's dylib dependencies and rename their locations to inside the Framework\necho \"Checking $TARGET_BINARY dylib dependencies\"\nfor a in $(otool -L \"$TARGET_BINARY\"  | grep \"$EXTERNAL_LIBS\" | awk ' { print $1 } ') ; do \n\techo \"    Packaging $a\"\n\tcp -f \"$a\" \"$TARGET_FRAMEWORKS/\"\n\tchmod u+w \"$TARGET_FRAMEWORKS/$(basename $a)\"\n\tinstall_name_tool -change \"$a\" \"$DYLIB_NAMEPATH/$(basename $a)\" \"$TARGET_BINARY\"\ndone\n\nif [ \"$SDK_NAME\" = \"iphoneos6.0\" ] ; then\n\techo \"Fixing $TARGET_BINARY VideoToolbox dylib name\"\n    VTB_SDK6=/System/Library/Frameworks/VideoToolbox.framework/VideoToolbox\n    VTB_SDK5=/System/Library/PrivateFrameworks/VideoToolbox.framework/VideoToolbox\n\tinstall_name_tool -change \"$VTB_SDK6\" \"$VTB_SDK5\" \"$TARGET_BINARY\"\nfi\n\necho \"Package $EXTERNAL_LIBS/lib/python2.6\"\nmkdir -p \"$TARGET_CONTENTS/Frameworks/lib\"\nPYTHONSYNC=\"rsync -aq --exclude .DS_Store --exclude *.a --exclude *.exe --exclude test --exclude tests\"\n${PYTHONSYNC} \"$EXTERNAL_LIBS/lib/python2.6\" \"$TARGET_FRAMEWORKS/lib/\"\nrm -rf \"$TARGET_FRAMEWORKS/lib/python2.6/config\"\n\necho \"Checking $TARGET_FRAMEWORKS/lib/python2.6 *.so for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$TARGET_FRAMEWORKS\"/lib/python2.6 \"*.so\"\n\necho \"Checking $XBMC_HOME/system *.so for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$XBMC_HOME\"/system \"*.so\"\n\necho \"Checking $XBMC_HOME/addons *.so for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$XBMC_HOME\"/addons \"*.so\"\n\necho \"Checking $XBMC_HOME/addons *.pvr for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$XBMC_HOME\"/addons \"*.pvr\"\n\necho \"Checking $XBMC_HOME/addons *.xbs for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$XBMC_HOME\"/addons \"*.xbs\"\n\necho \"Checking xbmc/DllPaths_generated.h for dylib dependencies\"\nfor a in $(grep .dylib \"$SRCROOT\"/xbmc/DllPaths_generated.h | awk '{print $3}' | sed s/\\\"//g) ; do\n  check_dyloaded_depends $a\ndone\n\necho \"Checking $TARGET_FRAMEWORKS for missing dylib dependencies\"\nREWIND=\"1\"\nwhile [ $REWIND = \"1\" ]\ndo\n\tlet REWIND=\"0\"\n\tfor b in \"$TARGET_FRAMEWORKS/\"*dylib* ; do\n\t\t#echo \"  Processing $b\"\n\t\tfor a in $(otool -L \"$b\"  | grep \"$EXTERNAL_LIBS\" | awk ' { print $1 } ') ; do\n\t\t\t#echo \"Processing $a\"\n\t\t\tif [ ! -f  \"$TARGET_FRAMEWORKS/$(basename $a)\" ]; then\n\t\t\t\techo \"    Packaging $a\"\n\t\t\t\tcp -f \"$a\" \"$TARGET_FRAMEWORKS/\"\n\t\t\t\tchmod u+w \"$TARGET_FRAMEWORKS/$(basename $a)\"\n\t\t\t\tlet REWIND=\"1\"\n\t\t\tfi\n\t\t\tinstall_name_tool -change \"$a\" \"$DYLIB_NAMEPATH/$(basename $a)\" \"$TARGET_FRAMEWORKS/$(basename $b)\"\n\t\tdone \n\tdone\ndone\n";
                };
 /* End PBXShellScriptBuildPhase section */
 
                                F56C7B4C131EC155000AD0F6 /* GUIDialogVideoInfo.cpp in Sources */,
                                F56C7B4D131EC155000AD0F6 /* GUIDialogVideoOSD.cpp in Sources */,
                                F56C7B4E131EC155000AD0F6 /* GUIDialogVideoOverlay.cpp in Sources */,
-                               F56C7B4F131EC155000AD0F6 /* GUIDialogVideoScan.cpp in Sources */,
                                F56C7B50131EC155000AD0F6 /* GUIDialogVideoSettings.cpp in Sources */,
                                F56C7B51131EC155000AD0F6 /* GUIWindowFullScreen.cpp in Sources */,
                                F56C7B52131EC155000AD0F6 /* GUIWindowVideoBase.cpp in Sources */,
                                F57A1DBD1329FB0A00498CC7 /* SourcesDirectory.cpp in Sources */,
                                F5B13E0113344F310045076D /* DarwinUtils.mm in Sources */,
                                7C99B7AA134072CD00FC2B16 /* GUIDialogPlayEject.cpp in Sources */,
-                               F5AE40EA134175160004BD79 /* HttpApi.cpp in Sources */,
-                               F5AE40EB134175160004BD79 /* XBMChttp.cpp in Sources */,
                                F5AE41081341751E0004BD79 /* AudioLibrary.cpp in Sources */,
                                F5AE410B1341751E0004BD79 /* FileItemHandler.cpp in Sources */,
                                F5AE410C1341751E0004BD79 /* FileOperations.cpp in Sources */,
                                18968DE814155E1D005BA742 /* ApplicationOperations.cpp in Sources */,
                                DFCFC53D1413F7F70004D0BF /* AFPDirectory.cpp in Sources */,
                                32D6D47C1423A9D8003641AC /* JpegIO.cpp in Sources */,
-                               DF44852F140064F40069344B /* BXAcodec.cpp in Sources */,
                                DF4485351400651B0069344B /* PipesManager.cpp in Sources */,
                                DF4485381400654A0069344B /* AirTunesServer.cpp in Sources */,
                                DF98D9A81434F4B400A6EBE1 /* SkinVariable.cpp in Sources */,
                                DF527789151BAFEE00B5B63B /* HttpResponse.cpp in Sources */,
                                188F761015221809009870CE /* GUIOperations.cpp in Sources */,
                                188F76291522186C009870CE /* Mime.cpp in Sources */,
-                               DFCA6B0B15224684000BFAAE /* HTTPApiHandler.cpp in Sources */,
                                DFCA6B0C15224684000BFAAE /* HTTPJsonRpcHandler.cpp in Sources */,
                                DFCA6B0D15224684000BFAAE /* HTTPVfsHandler.cpp in Sources */,
                                DFCA6B0E15224684000BFAAE /* HTTPWebinterfaceAddonsHandler.cpp in Sources */,
                                7C4458DB161E209100A905F6 /* Screenshot.cpp in Sources */,
                                1D638118161E20AC003603ED /* PeripheralImon.cpp in Sources */,
                                DF24EAC71621E58D00034265 /* DVDDemuxBXA.cpp in Sources */,
+                               36A95DB41624898700727135 /* GUIDialogMediaFilter.cpp in Sources */,
+                               F592D4BF162495B10023BCE7 /* NptPosixTime.cpp in Sources */,
+                               F592D4C2162496620023BCE7 /* NptHash.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                        "\"$(SRCROOT)/lib/libsquish\"",
                                        "\"$(SRCROOT)/lib/SlingboxLib\"",
                                        "\"$(SRCROOT)/xbmc/interfaces/json-rpc\"",
-                                       "\"$(SRCROOT)/xbmc/interfaces/http-api\"",
                                        "\"$(SRCROOT)/lib/ffmpeg/libavcodec\"",
                                        "\"$(SRCROOT)/lib/ffmpeg/libavutil\"",
                                        "\"$(SRCROOT)/lib/ffmpeg/libavformat\"",
                                        "\"$(SRCROOT)/lib/libsquish\"",
                                        "\"$(SRCROOT)/lib/SlingboxLib\"",
                                        "\"$(SRCROOT)/xbmc/interfaces/json-rpc\"",
-                                       "\"$(SRCROOT)/xbmc/interfaces/http-api\"",
                                        "\"$(SRCROOT)/lib/ffmpeg/libavcodec\"",
                                        "\"$(SRCROOT)/lib/ffmpeg/libavutil\"",
                                        "\"$(SRCROOT)/lib/ffmpeg/libavformat\"",
index 4f87068..0bb279d 100644 (file)
@@ -27,6 +27,7 @@
                36A9467815CF20A500727135 /* UrlOptions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A9467615CF20A500727135 /* UrlOptions.cpp */; };
                36A9467B15CF20BD00727135 /* VideoDbUrl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A9467915CF20BD00727135 /* VideoDbUrl.cpp */; };
                36A9467E15CF20E100727135 /* DbUrl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A9467C15CF20E100727135 /* DbUrl.cpp */; };
+               36A95DAD1624896C00727135 /* GUIDialogMediaFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A95DAB1624896C00727135 /* GUIDialogMediaFilter.cpp */; };
                4D5D2E1E1301758F006ABC13 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D5D2E1D1301758F006ABC13 /* CFNetwork.framework */; };
                7C0A7EDE13A5DC2800AFC2BD /* AppParamParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C0A7EDC13A5DC2800AFC2BD /* AppParamParser.cpp */; };
                7C0A7F9D13A9E70800AFC2BD /* GUIWindowDebugInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C0A7F9B13A9E70800AFC2BD /* GUIWindowDebugInfo.cpp */; };
                DF2E329415509B2C000F5772 /* XbmcContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF2E329215509B2C000F5772 /* XbmcContext.cpp */; };
                DF33C29415509BF50046CDCB /* ilog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF33C29115509BF50046CDCB /* ilog.cpp */; };
                DF3488F813FD961A0026A711 /* GUIAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF3488F613FD961A0026A711 /* GUIAction.cpp */; };
-               DF44856C140065C60069344B /* BXAcodec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF44856A140065C60069344B /* BXAcodec.cpp */; };
                DF448572140065E10069344B /* PipesManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF44856F140065E10069344B /* PipesManager.cpp */; };
                DF4485751400662D0069344B /* AirTunesServer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF4485731400662D0069344B /* AirTunesServer.cpp */; };
                DF527757151BAF8200B5B63B /* WebSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF52774E151BAF8200B5B63B /* WebSocket.cpp */; };
                DFC0F8E71613A16F0066D598 /* XLCDproc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFC0F8E51613A16F0066D598 /* XLCDproc.cpp */; };
                DFC0F90F1613A3810066D598 /* LCDFactory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFC0F90D1613A3810066D598 /* LCDFactory.cpp */; };
                DFC3867E158296EC008AE277 /* Exception.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFC3867C158296EC008AE277 /* Exception.cpp */; };
-               DFCA6AEB15224671000BFAAE /* HTTPApiHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFCA6ADE15224671000BFAAE /* HTTPApiHandler.cpp */; };
                DFCA6AEC15224671000BFAAE /* HTTPJsonRpcHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFCA6AE015224671000BFAAE /* HTTPJsonRpcHandler.cpp */; };
                DFCA6AED15224671000BFAAE /* HTTPVfsHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFCA6AE215224671000BFAAE /* HTTPVfsHandler.cpp */; };
                DFCA6AEE15224671000BFAAE /* HTTPWebinterfaceAddonsHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFCA6AE415224671000BFAAE /* HTTPWebinterfaceAddonsHandler.cpp */; };
                F56C8B3B131F42ED000AD0F6 /* GUIDialogVideoInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F56C8774131F42EC000AD0F6 /* GUIDialogVideoInfo.cpp */; };
                F56C8B3C131F42ED000AD0F6 /* GUIDialogVideoOSD.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F56C8776131F42EC000AD0F6 /* GUIDialogVideoOSD.cpp */; };
                F56C8B3D131F42ED000AD0F6 /* GUIDialogVideoOverlay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F56C8778131F42EC000AD0F6 /* GUIDialogVideoOverlay.cpp */; };
-               F56C8B3E131F42ED000AD0F6 /* GUIDialogVideoScan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F56C877A131F42EC000AD0F6 /* GUIDialogVideoScan.cpp */; };
                F56C8B3F131F42ED000AD0F6 /* GUIDialogVideoSettings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F56C877C131F42EC000AD0F6 /* GUIDialogVideoSettings.cpp */; };
                F56C8B40131F42ED000AD0F6 /* GUIWindowFullScreen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F56C877F131F42EC000AD0F6 /* GUIWindowFullScreen.cpp */; };
                F56C8B41131F42ED000AD0F6 /* GUIWindowVideoBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F56C8781131F42EC000AD0F6 /* GUIWindowVideoBase.cpp */; };
                F589AE4B1288E09200D8079E /* libncurses.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F589AE4A1288E09200D8079E /* libncurses.dylib */; };
                F5A29EC312A7221B003A610C /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F5A29EC212A7221B003A610C /* CoreMedia.framework */; };
                F5A29F2712A72246003A610C /* VideoToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F5A29F2612A72246003A610C /* VideoToolbox.framework */; };
-               F5AE413D1341754C0004BD79 /* HttpApi.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5AE41391341754C0004BD79 /* HttpApi.cpp */; };
-               F5AE413E1341754C0004BD79 /* XBMChttp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5AE413B1341754C0004BD79 /* XBMChttp.cpp */; };
                F5AE415B134175520004BD79 /* AudioLibrary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5AE4140134175520004BD79 /* AudioLibrary.cpp */; };
                F5AE415E134175520004BD79 /* FileItemHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5AE4146134175520004BD79 /* FileItemHandler.cpp */; };
                F5AE415F134175520004BD79 /* FileOperations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5AE4148134175520004BD79 /* FileOperations.cpp */; };
                36A9467A15CF20BD00727135 /* VideoDbUrl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VideoDbUrl.h; sourceTree = "<group>"; };
                36A9467C15CF20E100727135 /* DbUrl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DbUrl.cpp; sourceTree = "<group>"; };
                36A9467D15CF20E100727135 /* DbUrl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DbUrl.h; sourceTree = "<group>"; };
+               36A95DAB1624896C00727135 /* GUIDialogMediaFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIDialogMediaFilter.cpp; sourceTree = "<group>"; };
+               36A95DAC1624896C00727135 /* GUIDialogMediaFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIDialogMediaFilter.h; sourceTree = "<group>"; };
                4D5D2E1D1301758F006ABC13 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; };
                7C0A7EDC13A5DC2800AFC2BD /* AppParamParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AppParamParser.cpp; sourceTree = "<group>"; };
                7C0A7EDD13A5DC2800AFC2BD /* AppParamParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppParamParser.h; sourceTree = "<group>"; };
                DF33C29215509BF50046CDCB /* ilog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ilog.h; sourceTree = "<group>"; };
                DF3488F613FD961A0026A711 /* GUIAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIAction.cpp; sourceTree = "<group>"; };
                DF3488F713FD961A0026A711 /* GUIAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIAction.h; sourceTree = "<group>"; };
-               DF44856A140065C60069344B /* BXAcodec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BXAcodec.cpp; sourceTree = "<group>"; };
-               DF44856B140065C60069344B /* BXAcodec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BXAcodec.h; sourceTree = "<group>"; };
                DF44856F140065E10069344B /* PipesManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PipesManager.cpp; sourceTree = "<group>"; };
                DF448570140065E10069344B /* PipesManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PipesManager.h; sourceTree = "<group>"; };
                DF4485731400662D0069344B /* AirTunesServer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AirTunesServer.cpp; sourceTree = "<group>"; };
                DFC0F90E1613A3810066D598 /* LCDFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LCDFactory.h; sourceTree = "<group>"; };
                DFC3867C158296EC008AE277 /* Exception.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Exception.cpp; sourceTree = "<group>"; };
                DFC3867D158296EC008AE277 /* Exception.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Exception.h; sourceTree = "<group>"; };
-               DFCA6ADE15224671000BFAAE /* HTTPApiHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HTTPApiHandler.cpp; sourceTree = "<group>"; };
-               DFCA6ADF15224671000BFAAE /* HTTPApiHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPApiHandler.h; sourceTree = "<group>"; };
                DFCA6AE015224671000BFAAE /* HTTPJsonRpcHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HTTPJsonRpcHandler.cpp; sourceTree = "<group>"; };
                DFCA6AE115224671000BFAAE /* HTTPJsonRpcHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPJsonRpcHandler.h; sourceTree = "<group>"; };
                DFCA6AE215224671000BFAAE /* HTTPVfsHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HTTPVfsHandler.cpp; sourceTree = "<group>"; };
                F56C8777131F42EC000AD0F6 /* GUIDialogVideoOSD.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIDialogVideoOSD.h; sourceTree = "<group>"; };
                F56C8778131F42EC000AD0F6 /* GUIDialogVideoOverlay.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIDialogVideoOverlay.cpp; sourceTree = "<group>"; };
                F56C8779131F42EC000AD0F6 /* GUIDialogVideoOverlay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIDialogVideoOverlay.h; sourceTree = "<group>"; };
-               F56C877A131F42EC000AD0F6 /* GUIDialogVideoScan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIDialogVideoScan.cpp; sourceTree = "<group>"; };
-               F56C877B131F42EC000AD0F6 /* GUIDialogVideoScan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIDialogVideoScan.h; sourceTree = "<group>"; };
                F56C877C131F42EC000AD0F6 /* GUIDialogVideoSettings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIDialogVideoSettings.cpp; sourceTree = "<group>"; };
                F56C877D131F42EC000AD0F6 /* GUIDialogVideoSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIDialogVideoSettings.h; sourceTree = "<group>"; };
                F56C877F131F42EC000AD0F6 /* GUIWindowFullScreen.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIWindowFullScreen.cpp; sourceTree = "<group>"; };
                F589AE4A1288E09200D8079E /* libncurses.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libncurses.dylib; path = usr/lib/libncurses.dylib; sourceTree = SDKROOT; };
                F5A29EC212A7221B003A610C /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };
                F5A29F2612A72246003A610C /* VideoToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = VideoToolbox.framework; path = System/Library/PrivateFrameworks/VideoToolbox.framework; sourceTree = SDKROOT; };
-               F5AE41391341754C0004BD79 /* HttpApi.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HttpApi.cpp; sourceTree = "<group>"; };
-               F5AE413A1341754C0004BD79 /* HttpApi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HttpApi.h; sourceTree = "<group>"; };
-               F5AE413B1341754C0004BD79 /* XBMChttp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = XBMChttp.cpp; sourceTree = "<group>"; };
-               F5AE413C1341754C0004BD79 /* XBMChttp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XBMChttp.h; sourceTree = "<group>"; };
                F5AE4140134175520004BD79 /* AudioLibrary.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AudioLibrary.cpp; sourceTree = "<group>"; };
                F5AE4141134175520004BD79 /* AudioLibrary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioLibrary.h; sourceTree = "<group>"; };
                F5AE4146134175520004BD79 /* FileItemHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileItemHandler.cpp; sourceTree = "<group>"; };
                DFCA6ADD15224671000BFAAE /* httprequesthandler */ = {
                        isa = PBXGroup;
                        children = (
-                               DFCA6ADE15224671000BFAAE /* HTTPApiHandler.cpp */,
-                               DFCA6ADF15224671000BFAAE /* HTTPApiHandler.h */,
                                7C6EB718155F3B330080368A /* HTTPImageHandler.cpp */,
                                7C6EB719155F3B330080368A /* HTTPImageHandler.h */,
                                DFCA6AE015224671000BFAAE /* HTTPJsonRpcHandler.cpp */,
                                F56C80C5131F42E5000AD0F6 /* NptPosixQueue.cpp */,
                                F56C80C6131F42E5000AD0F6 /* NptPosixSystem.cpp */,
                                F56C80C7131F42E5000AD0F6 /* NptPosixThreads.cpp */,
+                               DFF7A93015F7C73B00D316E9 /* NptPosixTime.cpp */,
                                F56C8094131F42E5000AD0F6 /* NptQueue.cpp */,
                                F56C8095131F42E5000AD0F6 /* NptQueue.h */,
                                F56C8096131F42E5000AD0F6 /* NptReferences.h */,
                                DFF7A94215F7C7C500D316E9 /* NptCocoaEnviroment.mm */,
                                DFF7A93415F7C75A00D316E9 /* NptHash.cpp */,
                                DFF7A93515F7C75A00D316E9 /* NptHash.h */,
-                               DFF7A93015F7C73B00D316E9 /* NptPosixTime.cpp */,
                                F56C80DD131F42E6000AD0F6 /* PltAction.cpp */,
                                F56C80DE131F42E6000AD0F6 /* PltAction.h */,
                                F56C80DF131F42E6000AD0F6 /* PltArgument.cpp */,
                                F56C8307131F42E7000AD0F6 /* ASAPCodec.h */,
                                F56C830E131F42E7000AD0F6 /* AudioDecoder.cpp */,
                                F56C830F131F42E7000AD0F6 /* AudioDecoder.h */,
-                               DF44856A140065C60069344B /* BXAcodec.cpp */,
-                               DF44856B140065C60069344B /* BXAcodec.h */,
                                F56C8310131F42E7000AD0F6 /* CachingCodec.h */,
                                F56C8311131F42E7000AD0F6 /* CDDAcodec.cpp */,
                                F56C8312131F42E7000AD0F6 /* CDDAcodec.h */,
                                F56C8357131F42E8000AD0F6 /* GUIDialogKaiToast.h */,
                                DF830C9315BB20FC00602BE6 /* GUIDialogKeyboardGeneric.cpp */,
                                DF830C9415BB20FC00602BE6 /* GUIDialogKeyboardGeneric.h */,
+                               36A95DAB1624896C00727135 /* GUIDialogMediaFilter.cpp */,
+                               36A95DAC1624896C00727135 /* GUIDialogMediaFilter.h */,
                                F56C835A131F42E8000AD0F6 /* GUIDialogMediaSource.cpp */,
                                F56C835B131F42E8000AD0F6 /* GUIDialogMediaSource.h */,
                                F56C835C131F42E8000AD0F6 /* GUIDialogMuteBug.cpp */,
                F56C8546131F42E9000AD0F6 /* interfaces */ = {
                        isa = PBXGroup;
                        children = (
-                               F5AE41381341754C0004BD79 /* http-api */,
                                F5E6209313E907E200D5F2CD /* info */,
                                F5AE413F134175520004BD79 /* json-rpc */,
                                DF1AD10315FCE71000E10810 /* legacy */,
                                F56C8777131F42EC000AD0F6 /* GUIDialogVideoOSD.h */,
                                F56C8778131F42EC000AD0F6 /* GUIDialogVideoOverlay.cpp */,
                                F56C8779131F42EC000AD0F6 /* GUIDialogVideoOverlay.h */,
-                               F56C877A131F42EC000AD0F6 /* GUIDialogVideoScan.cpp */,
-                               F56C877B131F42EC000AD0F6 /* GUIDialogVideoScan.h */,
                                F56C877C131F42EC000AD0F6 /* GUIDialogVideoSettings.cpp */,
                                F56C877D131F42EC000AD0F6 /* GUIDialogVideoSettings.h */,
                        );
                        name = "Internal Libs";
                        sourceTree = "<group>";
                };
-               F5AE41381341754C0004BD79 /* http-api */ = {
-                       isa = PBXGroup;
-                       children = (
-                               F5AE41391341754C0004BD79 /* HttpApi.cpp */,
-                               F5AE413A1341754C0004BD79 /* HttpApi.h */,
-                               F5AE413B1341754C0004BD79 /* XBMChttp.cpp */,
-                               F5AE413C1341754C0004BD79 /* XBMChttp.h */,
-                       );
-                       path = "http-api";
-                       sourceTree = "<group>";
-               };
                F5AE413F134175520004BD79 /* json-rpc */ = {
                        isa = PBXGroup;
                        children = (
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        shellPath = /bin/bash;
-                       shellScript = "#set -x\n\nfunction check_dyloaded_depends\n{\n  b=$(find \"$EXTERNAL_LIBS\" -name $1 -print)\n  if [ -f \"$b\" ]; then\n    #echo \"Processing $b\"\n    if [ ! -f  \"$TARGET_FRAMEWORKS/$(basename $b)\" ]; then\n      echo \"    Packaging $b\"\n      cp -f \"$b\" \"$TARGET_FRAMEWORKS/\"\n      chmod u+w \"$TARGET_FRAMEWORKS/$(basename $b)\"\n    fi\n    for a in $(otool -L \"$b\"  | grep \"$EXTERNAL_LIBS\" | awk ' { print $1 } ') ; do\n      if [ -f \"$a\" ]; then\n        if [ ! -f  \"$TARGET_FRAMEWORKS/$(basename $a)\" ]; then\n          echo \"    Packaging $a\"\n          cp -f \"$a\" \"$TARGET_FRAMEWORKS/\"\n          chmod u+w \"$TARGET_FRAMEWORKS/$(basename $a)\"\n          install_name_tool -change \"$a\" \"$DYLIB_NAMEPATH/$(basename $a)\" \"$TARGET_FRAMEWORKS/$(basename $b)\"\n        fi\n      fi\n    done \n  fi\n}\n\nfunction check_xbmc_dylib_depends\n{\n  REWIND=\"1\"\n  while [ $REWIND = \"1\" ]\n  do\n    let REWIND=\"0\"\n    for b in $(find \"$1\" -name \"$2\" -print) ; do\n      #echo \"Processing $b\"\n      install_name_tool -id \"$(basename $b)\" \"$b\"\n      for a in $(otool -L \"$b\"  | grep \"$EXTERNAL_LIBS\" | awk ' { print $1 } ') ; do\n        #echo \"    Packaging $a\"\n        if [ ! -f  \"$TARGET_FRAMEWORKS/$(basename $a)\" ]; then\n          echo \"    Packaging $a\"\n          cp -f \"$a\" \"$TARGET_FRAMEWORKS/\"\n          chmod u+w \"$TARGET_FRAMEWORKS/$(basename $a)\"\n          let REWIND=\"1\"\n        fi\n        install_name_tool -change \"$a\" \"$DYLIB_NAMEPATH/$(basename $a)\" \"$b\"\n      done\n    done\n  done\n}\n\nEXTERNAL_LIBS=/Users/Shared/xbmc-depends/\"$SDK_NAME\"_\"$ARCHS\"\n\nTARGET_NAME=$PRODUCT_NAME.$WRAPPER_EXTENSION\nTARGET_CONTENTS=$TARGET_BUILD_DIR/$TARGET_NAME\n\nTARGET_BINARY=$TARGET_CONTENTS/XBMC\nTARGET_FRAMEWORKS=$TARGET_CONTENTS/Frameworks\nDYLIB_NAMEPATH=@executable_path/Frameworks\nXBMC_HOME=$TARGET_CONTENTS/XBMCData/XBMCHome\n\nmkdir -p \"$TARGET_CONTENTS\"\nmkdir -p \"$TARGET_CONTENTS/XBMCData/XBMCHome\"\n# start clean so we don't keep old dylibs\nrm -rf \"$TARGET_CONTENTS/Frameworks\"\nmkdir -p \"$TARGET_CONTENTS/Frameworks\"\n\necho \"Package $TARGET_BUILD_DIR/XBMC\"\n\n# Copy all of XBMC's dylib dependencies and rename their locations to inside the Framework\necho \"Checking $TARGET_BINARY dylib dependencies\"\nfor a in $(otool -L \"$TARGET_BINARY\"  | grep \"$EXTERNAL_LIBS\" | awk ' { print $1 } ') ; do \n\techo \"    Packaging $a\"\n\tcp -f \"$a\" \"$TARGET_FRAMEWORKS/\"\n\tchmod u+w \"$TARGET_FRAMEWORKS/$(basename $a)\"\n\tinstall_name_tool -change \"$a\" \"$DYLIB_NAMEPATH/$(basename $a)\" \"$TARGET_BINARY\"\ndone\n\necho \"Package $EXTERNAL_LIBS/lib/python2.6\"\nmkdir -p \"$TARGET_CONTENTS/Frameworks/lib\"\nPYTHONSYNC=\"rsync -aq --exclude .DS_Store --exclude *.a --exclude *.exe --exclude test --exclude tests\"\n${PYTHONSYNC} \"$EXTERNAL_LIBS/lib/python2.6\" \"$TARGET_FRAMEWORKS/lib/\"\nrm -rf \"$TARGET_FRAMEWORKS/lib/python2.6/config\"\n\necho \"Checking $TARGET_FRAMEWORKS/lib/python2.6 *.so for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$TARGET_FRAMEWORKS\"/lib/python2.6 \"*.so\"\n\necho \"Checking $XBMC_HOME/system *.so for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$XBMC_HOME\"/system \"*.so\"\n\necho \"Checking $XBMC_HOME/addons *.so for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$XBMC_HOME\"/addons \"*.so\"\n\necho \"Checking $XBMC_HOME/addons *.pvr for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$XBMC_HOME\"/addons \"*.pvr\"\n\necho \"Checking $XBMC_HOME/addons *.xbs for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$XBMC_HOME\"/addons \"*.xbs\"\n\necho \"Checking xbmc/DllPaths_generated.h for dylib dependencies\"\nfor a in $(grep .dylib \"$SRCROOT\"/xbmc/DllPaths_generated.h | awk '{print $3}' | sed s/\\\"//g) ; do\n  check_dyloaded_depends $a\ndone\n\necho \"Checking $TARGET_FRAMEWORKS for missing dylib dependencies\"\nREWIND=\"1\"\nwhile [ $REWIND = \"1\" ]\ndo\n\tlet REWIND=\"0\"\n\tfor b in \"$TARGET_FRAMEWORKS/\"*dylib* ; do\n\t\t#echo \"  Processing $b\"\n\t\tfor a in $(otool -L \"$b\"  | grep \"$EXTERNAL_LIBS\" | awk ' { print $1 } ') ; do\n\t\t\t#echo \"Processing $a\"\n\t\t\tif [ ! -f  \"$TARGET_FRAMEWORKS/$(basename $a)\" ]; then\n\t\t\t\techo \"    Packaging $a\"\n\t\t\t\tcp -f \"$a\" \"$TARGET_FRAMEWORKS/\"\n\t\t\t\tchmod u+w \"$TARGET_FRAMEWORKS/$(basename $a)\"\n\t\t\t\tlet REWIND=\"1\"\n\t\t\tfi\n\t\t\tinstall_name_tool -change \"$a\" \"$DYLIB_NAMEPATH/$(basename $a)\" \"$TARGET_FRAMEWORKS/$(basename $b)\"\n\t\tdone \n\tdone\ndone\n";
+                       shellScript = "#set -x\n\nfunction check_dyloaded_depends\n{\n  b=$(find \"$EXTERNAL_LIBS\" -name $1 -print)\n  if [ -f \"$b\" ]; then\n    #echo \"Processing $b\"\n    if [ ! -f  \"$TARGET_FRAMEWORKS/$(basename $b)\" ]; then\n      echo \"    Packaging $b\"\n      cp -f \"$b\" \"$TARGET_FRAMEWORKS/\"\n      chmod u+w \"$TARGET_FRAMEWORKS/$(basename $b)\"\n    fi\n    for a in $(otool -L \"$b\"  | grep \"$EXTERNAL_LIBS\" | awk ' { print $1 } ') ; do\n      if [ -f \"$a\" ]; then\n        if [ ! -f  \"$TARGET_FRAMEWORKS/$(basename $a)\" ]; then\n          echo \"    Packaging $a\"\n          cp -f \"$a\" \"$TARGET_FRAMEWORKS/\"\n          chmod u+w \"$TARGET_FRAMEWORKS/$(basename $a)\"\n          install_name_tool -change \"$a\" \"$DYLIB_NAMEPATH/$(basename $a)\" \"$TARGET_FRAMEWORKS/$(basename $b)\"\n        fi\n      fi\n    done \n  fi\n}\n\nfunction check_xbmc_dylib_depends\n{\n  REWIND=\"1\"\n  while [ $REWIND = \"1\" ]\n  do\n    let REWIND=\"0\"\n    for b in $(find \"$1\" -type f -name \"$2\" -print) ; do\n      #echo \"Processing $b\"\n      install_name_tool -id \"$(basename $b)\" \"$b\"\n      for a in $(otool -L \"$b\"  | grep \"$EXTERNAL_LIBS\" | awk ' { print $1 } ') ; do\n        #echo \"    Packaging $a\"\n        if [ ! -f  \"$TARGET_FRAMEWORKS/$(basename $a)\" ]; then\n          echo \"    Packaging $a\"\n          cp -f \"$a\" \"$TARGET_FRAMEWORKS/\"\n          chmod u+w \"$TARGET_FRAMEWORKS/$(basename $a)\"\n          let REWIND=\"1\"\n        fi\n        install_name_tool -change \"$a\" \"$DYLIB_NAMEPATH/$(basename $a)\" \"$b\"\n      done\n    done\n  done\n}\n\nEXTERNAL_LIBS=/Users/Shared/xbmc-depends/\"$SDK_NAME\"_\"$ARCHS\"\n\nTARGET_NAME=$PRODUCT_NAME.$WRAPPER_EXTENSION\nTARGET_CONTENTS=$TARGET_BUILD_DIR/$TARGET_NAME\n\nTARGET_BINARY=$TARGET_CONTENTS/XBMC\nTARGET_FRAMEWORKS=$TARGET_CONTENTS/Frameworks\nDYLIB_NAMEPATH=@executable_path/Frameworks\nXBMC_HOME=$TARGET_CONTENTS/XBMCData/XBMCHome\n\nmkdir -p \"$TARGET_CONTENTS\"\nmkdir -p \"$TARGET_CONTENTS/XBMCData/XBMCHome\"\n# start clean so we don't keep old dylibs\nrm -rf \"$TARGET_CONTENTS/Frameworks\"\nmkdir -p \"$TARGET_CONTENTS/Frameworks\"\n\necho \"Package $TARGET_BUILD_DIR/XBMC\"\n\n# Copy all of XBMC's dylib dependencies and rename their locations to inside the Framework\necho \"Checking $TARGET_BINARY dylib dependencies\"\nfor a in $(otool -L \"$TARGET_BINARY\"  | grep \"$EXTERNAL_LIBS\" | awk ' { print $1 } ') ; do \n\techo \"    Packaging $a\"\n\tcp -f \"$a\" \"$TARGET_FRAMEWORKS/\"\n\tchmod u+w \"$TARGET_FRAMEWORKS/$(basename $a)\"\n\tinstall_name_tool -change \"$a\" \"$DYLIB_NAMEPATH/$(basename $a)\" \"$TARGET_BINARY\"\ndone\n\nif [ \"$SDK_NAME\" = \"iphoneos6.0\" ] ; then\n\techo \"Fixing $TARGET_BINARY VideoToolbox dylib name\"\n    VTB_SDK6=/System/Library/Frameworks/VideoToolbox.framework/VideoToolbox\n    VTB_SDK5=/System/Library/PrivateFrameworks/VideoToolbox.framework/VideoToolbox\n\tinstall_name_tool -change \"$VTB_SDK6\" \"$VTB_SDK5\" \"$TARGET_BINARY\"\nfi\n\necho \"Package $EXTERNAL_LIBS/lib/python2.6\"\nmkdir -p \"$TARGET_CONTENTS/Frameworks/lib\"\nPYTHONSYNC=\"rsync -aq --exclude .DS_Store --exclude *.a --exclude *.exe --exclude test --exclude tests\"\n${PYTHONSYNC} \"$EXTERNAL_LIBS/lib/python2.6\" \"$TARGET_FRAMEWORKS/lib/\"\nrm -rf \"$TARGET_FRAMEWORKS/lib/python2.6/config\"\n\necho \"Checking $TARGET_FRAMEWORKS/lib/python2.6 *.so for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$TARGET_FRAMEWORKS\"/lib/python2.6 \"*.so\"\n\necho \"Checking $XBMC_HOME/system *.so for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$XBMC_HOME\"/system \"*.so\"\n\necho \"Checking $XBMC_HOME/addons *.so for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$XBMC_HOME\"/addons \"*.so\"\n\necho \"Checking $XBMC_HOME/addons *.pvr for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$XBMC_HOME\"/addons \"*.pvr\"\n\necho \"Checking $XBMC_HOME/addons *.xbs for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$XBMC_HOME\"/addons \"*.xbs\"\n\necho \"Checking xbmc/DllPaths_generated.h for dylib dependencies\"\nfor a in $(grep .dylib \"$SRCROOT\"/xbmc/DllPaths_generated.h | awk '{print $3}' | sed s/\\\"//g) ; do\n  check_dyloaded_depends $a\ndone\n\necho \"Checking $TARGET_FRAMEWORKS for missing dylib dependencies\"\nREWIND=\"1\"\nwhile [ $REWIND = \"1\" ]\ndo\n\tlet REWIND=\"0\"\n\tfor b in \"$TARGET_FRAMEWORKS/\"*dylib* ; do\n\t\t#echo \"  Processing $b\"\n\t\tfor a in $(otool -L \"$b\"  | grep \"$EXTERNAL_LIBS\" | awk ' { print $1 } ') ; do\n\t\t\t#echo \"Processing $a\"\n\t\t\tif [ ! -f  \"$TARGET_FRAMEWORKS/$(basename $a)\" ]; then\n\t\t\t\techo \"    Packaging $a\"\n\t\t\t\tcp -f \"$a\" \"$TARGET_FRAMEWORKS/\"\n\t\t\t\tchmod u+w \"$TARGET_FRAMEWORKS/$(basename $a)\"\n\t\t\t\tlet REWIND=\"1\"\n\t\t\tfi\n\t\t\tinstall_name_tool -change \"$a\" \"$DYLIB_NAMEPATH/$(basename $a)\" \"$TARGET_FRAMEWORKS/$(basename $b)\"\n\t\tdone \n\tdone\ndone\n";
                };
 /* End PBXShellScriptBuildPhase section */
 
                                F56C8B3B131F42ED000AD0F6 /* GUIDialogVideoInfo.cpp in Sources */,
                                F56C8B3C131F42ED000AD0F6 /* GUIDialogVideoOSD.cpp in Sources */,
                                F56C8B3D131F42ED000AD0F6 /* GUIDialogVideoOverlay.cpp in Sources */,
-                               F56C8B3E131F42ED000AD0F6 /* GUIDialogVideoScan.cpp in Sources */,
                                F56C8B3F131F42ED000AD0F6 /* GUIDialogVideoSettings.cpp in Sources */,
                                F56C8B40131F42ED000AD0F6 /* GUIWindowFullScreen.cpp in Sources */,
                                F56C8B41131F42ED000AD0F6 /* GUIWindowVideoBase.cpp in Sources */,
                                F57A1DB81329FAF700498CC7 /* SourcesDirectory.cpp in Sources */,
                                F5B13DCF1334490D0045076D /* DarwinUtils.mm in Sources */,
                                7C99B7BE1340730000FC2B16 /* GUIDialogPlayEject.cpp in Sources */,
-                               F5AE413D1341754C0004BD79 /* HttpApi.cpp in Sources */,
-                               F5AE413E1341754C0004BD79 /* XBMChttp.cpp in Sources */,
                                F5AE415B134175520004BD79 /* AudioLibrary.cpp in Sources */,
                                F5AE415E134175520004BD79 /* FileItemHandler.cpp in Sources */,
                                F5AE415F134175520004BD79 /* FileOperations.cpp in Sources */,
                                18968DDE14155E01005BA742 /* ApplicationOperations.cpp in Sources */,
                                DFCFC52A1413F7D60004D0BF /* AFPDirectory.cpp in Sources */,
                                3291892B1423A9B700E878CD /* JpegIO.cpp in Sources */,
-                               DF44856C140065C60069344B /* BXAcodec.cpp in Sources */,
                                DF448572140065E10069344B /* PipesManager.cpp in Sources */,
                                DF4485751400662D0069344B /* AirTunesServer.cpp in Sources */,
                                DF98D9991434F49500A6EBE1 /* SkinVariable.cpp in Sources */,
                                DF527761151BAFA000B5B63B /* HttpResponse.cpp in Sources */,
                                188F761E1522182F009870CE /* GUIOperations.cpp in Sources */,
                                188F76211522184E009870CE /* Mime.cpp in Sources */,
-                               DFCA6AEB15224671000BFAAE /* HTTPApiHandler.cpp in Sources */,
                                DFCA6AEC15224671000BFAAE /* HTTPJsonRpcHandler.cpp in Sources */,
                                DFCA6AED15224671000BFAAE /* HTTPVfsHandler.cpp in Sources */,
                                DFCA6AEE15224671000BFAAE /* HTTPWebinterfaceAddonsHandler.cpp in Sources */,
                                7C4458C8161E206100A905F6 /* Screenshot.cpp in Sources */,
                                1D638120161E20F2003603ED /* PeripheralImon.cpp in Sources */,
                                DF24EADE1621E67200034265 /* DVDDemuxBXA.cpp in Sources */,
+                               36A95DAD1624896C00727135 /* GUIDialogMediaFilter.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                        "\"$(SRCROOT)/lib/cmyth/librefmem\"",
                                        "\"$(SRCROOT)/lib/libsquish\"",
                                        "\"$(SRCROOT)/lib/SlingboxLib\"",
-                                       "\"$(SRCROOT)/xbmc/interfaces/http-api\"",
                                        "\"$(SRCROOT)/xbmc/interfaces/json-rpc\"",
                                        "\"$(SRCROOT)/lib/ffmpeg/libavcodec\"",
                                        "\"$(SRCROOT)/lib/ffmpeg/libavutil\"",
                                        "\"$(SRCROOT)/lib/cmyth/librefmem\"",
                                        "\"$(SRCROOT)/lib/libsquish\"",
                                        "\"$(SRCROOT)/lib/SlingboxLib\"",
-                                       "\"$(SRCROOT)/xbmc/interfaces/http-api\"",
                                        "\"$(SRCROOT)/xbmc/interfaces/json-rpc\"",
                                        "\"$(SRCROOT)/lib/ffmpeg/libavcodec\"",
                                        "\"$(SRCROOT)/lib/ffmpeg/libavutil\"",
index 1f28f55..eac6df7 100644 (file)
                36A9466715CF1FD200727135 /* MusicDbUrl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A9466515CF1FD200727135 /* MusicDbUrl.cpp */; };
                36A9466A15CF1FED00727135 /* UrlOptions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A9466815CF1FED00727135 /* UrlOptions.cpp */; };
                36A9466D15CF201F00727135 /* VideoDbUrl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A9466B15CF201F00727135 /* VideoDbUrl.cpp */; };
+               36A95DA51624894400727135 /* GUIDialogMediaFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A95DA31624894400727135 /* GUIDialogMediaFilter.cpp */; };
                3802709A13D5A653009493DD /* SystemClock.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3802709813D5A653009493DD /* SystemClock.cpp */; };
                384718D81325BA04000486D6 /* XBDateTime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 384718D61325BA04000486D6 /* XBDateTime.cpp */; };
                38F4E57013CCCB3B00664821 /* Implementation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 38F4E56C13CCCB3B00664821 /* Implementation.cpp */; };
                DF34898213FDAAF60026A711 /* HttpParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF34898113FDAAF60026A711 /* HttpParser.cpp */; };
                DF448457140048A60069344B /* AirTunesServer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF448455140048A60069344B /* AirTunesServer.cpp */; };
                DF44845E140048C80069344B /* PipesManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF44845B140048C80069344B /* PipesManager.cpp */; };
-               DF4484EE140054530069344B /* BXAcodec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF4484EC140054530069344B /* BXAcodec.cpp */; };
                DF5276E1151BAEDA00B5B63B /* Base64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF52769A151BAEDA00B5B63B /* Base64.cpp */; };
                DF5276E2151BAEDA00B5B63B /* HttpResponse.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF52769C151BAEDA00B5B63B /* HttpResponse.cpp */; };
                DF527734151BAF4C00B5B63B /* WebSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF52772B151BAF4C00B5B63B /* WebSocket.cpp */; };
                DFBE805115F7D75700D7D102 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DFBE803D15F7D72100D7D102 /* SystemConfiguration.framework */; };
                DFC0F8CB16139DF10066D598 /* XLCDproc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFC0F8C916139DF10066D598 /* XLCDproc.cpp */; };
                DFC0F9021613A35E0066D598 /* LCDFactory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFC0F9001613A35E0066D598 /* LCDFactory.cpp */; };
-               DFCA6AC6152245CD000BFAAE /* HTTPApiHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFCA6AB9152245CD000BFAAE /* HTTPApiHandler.cpp */; };
                DFCA6AC7152245CD000BFAAE /* HTTPJsonRpcHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFCA6ABB152245CD000BFAAE /* HTTPJsonRpcHandler.cpp */; };
                DFCA6AC8152245CD000BFAAE /* HTTPVfsHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFCA6ABD152245CD000BFAAE /* HTTPVfsHandler.cpp */; };
                DFCA6AC9152245CD000BFAAE /* HTTPWebinterfaceAddonsHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFCA6ABF152245CD000BFAAE /* HTTPWebinterfaceAddonsHandler.cpp */; };
                E38E209A0D25F9FD00618676 /* GUIDialogSongInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E38E17DA0D25F9FA00618676 /* GUIDialogSongInfo.cpp */; };
                E38E209B0D25F9FD00618676 /* GUIDialogSubMenu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E38E17DC0D25F9FA00618676 /* GUIDialogSubMenu.cpp */; };
                E38E209D0D25F9FD00618676 /* GUIDialogVideoBookmarks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E38E17E00D25F9FA00618676 /* GUIDialogVideoBookmarks.cpp */; };
-               E38E209E0D25F9FD00618676 /* GUIDialogVideoScan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E38E17E20D25F9FA00618676 /* GUIDialogVideoScan.cpp */; };
                E38E20A00D25F9FD00618676 /* GUIDialogVisualisationPresetList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E38E17E60D25F9FA00618676 /* GUIDialogVisualisationPresetList.cpp */; };
                E38E20A20D25F9FD00618676 /* GUIDialogVolumeBar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E38E17EA0D25F9FA00618676 /* GUIDialogVolumeBar.cpp */; };
                E38E20A30D25F9FD00618676 /* GUIDialogYesNo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E38E17EC0D25F9FA00618676 /* GUIDialogYesNo.cpp */; };
                F5AACA680FB3DE2D00DBB77C /* GUIDialogSelect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5AACA670FB3DE2D00DBB77C /* GUIDialogSelect.cpp */; };
                F5AACA970FB3E2B800DBB77C /* GUIDialogSlider.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5AACA950FB3E2B800DBB77C /* GUIDialogSlider.cpp */; };
                F5AD1EA80F488A1A0065EB5D /* GUIWindowKaraokeLyrics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5AD1EA70F488A1A0065EB5D /* GUIWindowKaraokeLyrics.cpp */; };
-               F5AE407613415D8D0004BD79 /* HttpApi.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5AE406F13415D8C0004BD79 /* HttpApi.cpp */; };
-               F5AE407913415D8D0004BD79 /* XBMChttp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5AE407413415D8C0004BD79 /* XBMChttp.cpp */; };
                F5AE409C13415D9E0004BD79 /* AudioLibrary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5AE408013415D9E0004BD79 /* AudioLibrary.cpp */; };
                F5AE409F13415D9E0004BD79 /* FileItemHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5AE408613415D9E0004BD79 /* FileItemHandler.cpp */; };
                F5AE40A013415D9E0004BD79 /* FileOperations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5AE408813415D9E0004BD79 /* FileOperations.cpp */; };
                36A9466915CF1FED00727135 /* UrlOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UrlOptions.h; sourceTree = "<group>"; };
                36A9466B15CF201F00727135 /* VideoDbUrl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VideoDbUrl.cpp; sourceTree = "<group>"; };
                36A9466C15CF201F00727135 /* VideoDbUrl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VideoDbUrl.h; sourceTree = "<group>"; };
+               36A95DA31624894400727135 /* GUIDialogMediaFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIDialogMediaFilter.cpp; sourceTree = "<group>"; };
+               36A95DA41624894400727135 /* GUIDialogMediaFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIDialogMediaFilter.h; sourceTree = "<group>"; };
                3802709713D5A62D009493DD /* ThreadLocal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadLocal.h; sourceTree = "<group>"; };
                3802709813D5A653009493DD /* SystemClock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SystemClock.cpp; sourceTree = "<group>"; };
                3802709913D5A653009493DD /* SystemClock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SystemClock.h; sourceTree = "<group>"; };
                DF448456140048A60069344B /* AirTunesServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AirTunesServer.h; sourceTree = "<group>"; };
                DF44845B140048C80069344B /* PipesManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PipesManager.cpp; sourceTree = "<group>"; };
                DF44845C140048C80069344B /* PipesManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PipesManager.h; sourceTree = "<group>"; };
-               DF4484EC140054530069344B /* BXAcodec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BXAcodec.cpp; sourceTree = "<group>"; };
-               DF4484ED140054530069344B /* BXAcodec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BXAcodec.h; sourceTree = "<group>"; };
                DF52769A151BAEDA00B5B63B /* Base64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Base64.cpp; sourceTree = "<group>"; };
                DF52769B151BAEDA00B5B63B /* Base64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Base64.h; sourceTree = "<group>"; };
                DF52769C151BAEDA00B5B63B /* HttpResponse.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HttpResponse.cpp; sourceTree = "<group>"; };
                DFC0F8CA16139DF10066D598 /* XLCDproc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XLCDproc.h; sourceTree = "<group>"; };
                DFC0F9001613A35E0066D598 /* LCDFactory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LCDFactory.cpp; sourceTree = "<group>"; };
                DFC0F9011613A35E0066D598 /* LCDFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LCDFactory.h; sourceTree = "<group>"; };
-               DFCA6AB9152245CD000BFAAE /* HTTPApiHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HTTPApiHandler.cpp; sourceTree = "<group>"; };
-               DFCA6ABA152245CD000BFAAE /* HTTPApiHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPApiHandler.h; sourceTree = "<group>"; };
                DFCA6ABB152245CD000BFAAE /* HTTPJsonRpcHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HTTPJsonRpcHandler.cpp; sourceTree = "<group>"; };
                DFCA6ABC152245CD000BFAAE /* HTTPJsonRpcHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPJsonRpcHandler.h; sourceTree = "<group>"; };
                DFCA6ABD152245CD000BFAAE /* HTTPVfsHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HTTPVfsHandler.cpp; sourceTree = "<group>"; };
                E38E17DD0D25F9FA00618676 /* GUIDialogSubMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIDialogSubMenu.h; sourceTree = "<group>"; };
                E38E17E00D25F9FA00618676 /* GUIDialogVideoBookmarks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIDialogVideoBookmarks.cpp; sourceTree = "<group>"; };
                E38E17E10D25F9FA00618676 /* GUIDialogVideoBookmarks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIDialogVideoBookmarks.h; sourceTree = "<group>"; };
-               E38E17E20D25F9FA00618676 /* GUIDialogVideoScan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIDialogVideoScan.cpp; sourceTree = "<group>"; };
-               E38E17E30D25F9FA00618676 /* GUIDialogVideoScan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIDialogVideoScan.h; sourceTree = "<group>"; };
                E38E17E60D25F9FA00618676 /* GUIDialogVisualisationPresetList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIDialogVisualisationPresetList.cpp; sourceTree = "<group>"; };
                E38E17E70D25F9FA00618676 /* GUIDialogVisualisationPresetList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIDialogVisualisationPresetList.h; sourceTree = "<group>"; };
                E38E17EA0D25F9FA00618676 /* GUIDialogVolumeBar.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIDialogVolumeBar.cpp; sourceTree = "<group>"; };
                F5AACA960FB3E2B800DBB77C /* GUIDialogSlider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIDialogSlider.h; sourceTree = "<group>"; };
                F5AD1EA60F488A1A0065EB5D /* GUIWindowKaraokeLyrics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIWindowKaraokeLyrics.h; sourceTree = "<group>"; };
                F5AD1EA70F488A1A0065EB5D /* GUIWindowKaraokeLyrics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIWindowKaraokeLyrics.cpp; sourceTree = "<group>"; };
-               F5AE406F13415D8C0004BD79 /* HttpApi.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HttpApi.cpp; sourceTree = "<group>"; };
-               F5AE407013415D8C0004BD79 /* HttpApi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HttpApi.h; sourceTree = "<group>"; };
-               F5AE407413415D8C0004BD79 /* XBMChttp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = XBMChttp.cpp; sourceTree = "<group>"; };
-               F5AE407513415D8C0004BD79 /* XBMChttp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XBMChttp.h; sourceTree = "<group>"; };
                F5AE408013415D9E0004BD79 /* AudioLibrary.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AudioLibrary.cpp; sourceTree = "<group>"; };
                F5AE408113415D9E0004BD79 /* AudioLibrary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioLibrary.h; sourceTree = "<group>"; };
                F5AE408613415D9E0004BD79 /* FileItemHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileItemHandler.cpp; sourceTree = "<group>"; };
                                E38A06CD0D95AA5500FF8227 /* GUIDialogKaiToast.h */,
                                DF830D0A15BB260C00602BE6 /* GUIDialogKeyboardGeneric.cpp */,
                                DF830D0B15BB260C00602BE6 /* GUIDialogKeyboardGeneric.h */,
+                               36A95DA31624894400727135 /* GUIDialogMediaFilter.cpp */,
+                               36A95DA41624894400727135 /* GUIDialogMediaFilter.h */,
                                E38E17B80D25F9FA00618676 /* GUIDialogMediaSource.cpp */,
                                E38E17B90D25F9FA00618676 /* GUIDialogMediaSource.h */,
                                E38E17BE0D25F9FA00618676 /* GUIDialogMuteBug.cpp */,
                4367217312D6640E002508E6 /* interfaces */ = {
                        isa = PBXGroup;
                        children = (
-                               F5AE406E13415D8C0004BD79 /* http-api */,
                                7C89674213C03B21003631FE /* info */,
                                F5AE407F13415D9E0004BD79 /* json-rpc */,
                                DF1AD17B15FCE77900E10810 /* legacy */,
                                E38E181E0D25F9FA00618676 /* GUIDialogVideoOSD.h */,
                                E38E18430D25F9FA00618676 /* GUIDialogVideoOverlay.cpp */,
                                E38E18440D25F9FA00618676 /* GUIDialogVideoOverlay.h */,
-                               E38E17E20D25F9FA00618676 /* GUIDialogVideoScan.cpp */,
-                               E38E17E30D25F9FA00618676 /* GUIDialogVideoScan.h */,
                                18B7C90B129427A6009E7A26 /* GUIDialogVideoSettings.cpp */,
                                18B7C90C129427A6009E7A26 /* GUIDialogVideoSettings.h */,
                        );
                DFCA6AB8152245CD000BFAAE /* httprequesthandler */ = {
                        isa = PBXGroup;
                        children = (
-                               DFCA6AB9152245CD000BFAAE /* HTTPApiHandler.cpp */,
-                               DFCA6ABA152245CD000BFAAE /* HTTPApiHandler.h */,
                                7C6EB6F8155F32C30080368A /* HTTPImageHandler.cpp */,
                                7C6EB6F9155F32C30080368A /* HTTPImageHandler.h */,
                                DFCA6ABB152245CD000BFAAE /* HTTPJsonRpcHandler.cpp */,
                                88ACB01D0DCF409E0083CFDF /* ASAPCodec.h */,
                                E38E15E30D25F9FA00618676 /* AudioDecoder.cpp */,
                                E38E15E40D25F9FA00618676 /* AudioDecoder.h */,
-                               DF4484EC140054530069344B /* BXAcodec.cpp */,
-                               DF4484ED140054530069344B /* BXAcodec.h */,
                                E38E15E50D25F9FA00618676 /* CachingCodec.h */,
                                E38E15E60D25F9FA00618676 /* CDDAcodec.cpp */,
                                E38E15E70D25F9FA00618676 /* CDDAcodec.h */,
                        name = "internal libs";
                        sourceTree = "<group>";
                };
-               F5AE406E13415D8C0004BD79 /* http-api */ = {
-                       isa = PBXGroup;
-                       children = (
-                               F5AE406F13415D8C0004BD79 /* HttpApi.cpp */,
-                               F5AE407013415D8C0004BD79 /* HttpApi.h */,
-                               F5AE407413415D8C0004BD79 /* XBMChttp.cpp */,
-                               F5AE407513415D8C0004BD79 /* XBMChttp.h */,
-                       );
-                       path = "http-api";
-                       sourceTree = "<group>";
-               };
                F5AE407F13415D9E0004BD79 /* json-rpc */ = {
                        isa = PBXGroup;
                        children = (
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        shellPath = /bin/sh;
-                       shellScript = "#set -x\n\nfunction check_dyloaded_depends\n{\n  b=$(find \"$EXTERNAL_LIBS\" -name $1 -print)\n  if [ -f \"$b\" ]; then\n    #echo \"Processing $b\"\n    if [ ! -f  \"$TARGET_FRAMEWORKS/$(basename $b)\" ]; then\n      echo \"    Packaging $b\"\n      cp -f \"$b\" \"$TARGET_FRAMEWORKS/\"\n      chmod u+w \"$TARGET_FRAMEWORKS/$(basename $b)\"\n    fi\n    for a in $(otool -L \"$b\"  | grep \"$EXTERNAL_LIBS\" | awk ' { print $1 } ') ; do\n      if [ -f \"$a\" ]; then\n        if [ ! -f  \"$TARGET_FRAMEWORKS/$(basename $a)\" ]; then\n          echo \"    Packaging $a\"\n          cp -f \"$a\" \"$TARGET_FRAMEWORKS/\"\n          chmod u+w \"$TARGET_FRAMEWORKS/$(basename $a)\"\n          install_name_tool -change \"$a\" \"$DYLIB_NAMEPATH/$(basename $a)\" \"$TARGET_FRAMEWORKS/$(basename $b)\"\n        fi\n      fi\n    done \n  fi\n}\n\nfunction check_xbmc_dylib_depends\n{\n  REWIND=\"1\"\n  while [ $REWIND = \"1\" ]\n  do\n    let REWIND=\"0\"\n    for b in $(find \"$1\" -name \"$2\" -print) ; do\n      #echo \"Processing $b\"\n      install_name_tool -id \"$(basename $b)\" \"$b\"\n      for a in $(otool -L \"$b\"  | grep \"$EXTERNAL_LIBS\" | awk ' { print $1 } ') ; do\n        #echo \"    Packaging $a\"\n        if [ ! -f  \"$TARGET_FRAMEWORKS/$(basename $a)\" ]; then\n          echo \"    Packaging $a\"\n          cp -f \"$a\" \"$TARGET_FRAMEWORKS/\"\n          chmod u+w \"$TARGET_FRAMEWORKS/$(basename $a)\"\n          let REWIND=\"1\"\n        fi\n        install_name_tool -change \"$a\" \"$DYLIB_NAMEPATH/$(basename $a)\" \"$b\"\n      done\n    done\n  done\n}\n\nEXTERNAL_LIBS=/Users/Shared/xbmc-depends/\"$SDK_NAME\"_\"$ARCHS\"\n\nTARGET_NAME=$PRODUCT_NAME\nTARGET_CONTENTS=$TARGET_BUILD_DIR/$TARGET_NAME/Contents\n\nTARGET_BINARY=$TARGET_CONTENTS/MacOS/XBMC\nTARGET_FRAMEWORKS=$TARGET_CONTENTS/Frameworks\nDYLIB_NAMEPATH=@executable_path/../Frameworks\nXBMC_HOME=$TARGET_CONTENTS/Resources/XBMC\n\nmkdir -p \"$TARGET_CONTENTS/MacOS\"\nmkdir -p \"$TARGET_CONTENTS/Resources\"\n# start clean so we don't keep old dylibs\nrm -rf \"$TARGET_CONTENTS/Frameworks\"\nmkdir -p \"$TARGET_CONTENTS/Frameworks\"\n\necho \"Package $TARGET_BUILD_DIR/XBMC\"\ncp -f \"$TARGET_BUILD_DIR/XBMC\" \"$TARGET_BINARY\"\ncp -f \"$SRCROOT/media/xbmc.icns\" \"$TARGET_CONTENTS/Resources/\"\ncp -f \"$SRCROOT/xbmc/osx/Info.plist\" \"$TARGET_CONTENTS/\"\n\n# Copy all of XBMC's dylib dependencies and rename their locations to inside the Framework\necho \"Checking $TARGET_BINARY dylib dependencies\"\nfor a in $(otool -L \"$TARGET_BINARY\"  | grep \"$EXTERNAL_LIBS\" | awk ' { print $1 } ') ; do \n\techo \"    Packaging $a\"\n\tcp -f \"$a\" \"$TARGET_FRAMEWORKS/\"\n\tchmod u+w \"$TARGET_FRAMEWORKS/$(basename $a)\"\n\tinstall_name_tool -change \"$a\" \"$DYLIB_NAMEPATH/$(basename $a)\" \"$TARGET_BINARY\"\ndone\n\necho \"Package $EXTERNAL_LIBS/lib/python2.6\"\nmkdir -p \"$TARGET_CONTENTS/Frameworks/lib\"\nPYTHONSYNC=\"rsync -aq --exclude .DS_Store --exclude *.a --exclude *.exe --exclude test --exclude tests\"\n${PYTHONSYNC} \"$EXTERNAL_LIBS/lib/python2.6\" \"$TARGET_FRAMEWORKS/lib/\"\nrm -rf \"$TARGET_FRAMEWORKS/lib/python2.6/config\"\n\necho \"Checking $TARGET_FRAMEWORKS/lib/python2.6 *.so for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$TARGET_FRAMEWORKS\"/lib/python2.6 \"*.so\"\n\necho \"Checking $XBMC_HOME/system *.so for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$XBMC_HOME\"/system \"*.so\"\n\necho \"Checking $XBMC_HOME/addons *.so for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$XBMC_HOME\"/addons \"*.so\"\n\necho \"Checking $XBMC_HOME/addons *.pvr for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$XBMC_HOME\"/addons \"*.pvr\"\n\necho \"Checking $XBMC_HOME/addons *.xbs for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$XBMC_HOME\"/addons \"*.xbs\"\n\necho \"Checking xbmc/DllPaths_generated.h for dylib dependencies\"\nfor a in $(grep .dylib \"$SRCROOT\"/xbmc/DllPaths_generated.h | awk '{print $3}' | sed s/\\\"//g) ; do\n  check_dyloaded_depends $a\ndone\n\necho \"Checking $TARGET_FRAMEWORKS for missing dylib dependencies\"\nREWIND=\"1\"\nwhile [ $REWIND = \"1\" ]\ndo\n\tlet REWIND=\"0\"\n\tfor b in \"$TARGET_FRAMEWORKS/\"*dylib* ; do\n\t\t#echo \"  Processing $b\"\n\t\tfor a in $(otool -L \"$b\"  | grep \"$EXTERNAL_LIBS\" | awk ' { print $1 } ') ; do\n\t\t\t#echo \"Processing $a\"\n\t\t\tif [ ! -f  \"$TARGET_FRAMEWORKS/$(basename $a)\" ]; then\n\t\t\t\techo \"    Packaging $a\"\n\t\t\t\tcp -f \"$a\" \"$TARGET_FRAMEWORKS/\"\n\t\t\t\tchmod u+w \"$TARGET_FRAMEWORKS/$(basename $a)\"\n\t\t\t\tlet REWIND=\"1\"\n\t\t\tfi\n\t\t\tinstall_name_tool -change \"$a\" \"$DYLIB_NAMEPATH/$(basename $a)\" \"$TARGET_FRAMEWORKS/$(basename $b)\"\n\t\tdone \n\tdone\ndone\n";
+                       shellScript = "#set -x\n\nfunction check_dyloaded_depends\n{\n  b=$(find \"$EXTERNAL_LIBS\" -name $1 -print)\n  if [ -f \"$b\" ]; then\n    #echo \"Processing $b\"\n    if [ ! -f  \"$TARGET_FRAMEWORKS/$(basename $b)\" ]; then\n      echo \"    Packaging $b\"\n      cp -f \"$b\" \"$TARGET_FRAMEWORKS/\"\n      chmod u+w \"$TARGET_FRAMEWORKS/$(basename $b)\"\n    fi\n    for a in $(otool -L \"$b\"  | grep \"$EXTERNAL_LIBS\" | awk ' { print $1 } ') ; do\n      if [ -f \"$a\" ]; then\n        if [ ! -f  \"$TARGET_FRAMEWORKS/$(basename $a)\" ]; then\n          echo \"    Packaging $a\"\n          cp -f \"$a\" \"$TARGET_FRAMEWORKS/\"\n          chmod u+w \"$TARGET_FRAMEWORKS/$(basename $a)\"\n          install_name_tool -change \"$a\" \"$DYLIB_NAMEPATH/$(basename $a)\" \"$TARGET_FRAMEWORKS/$(basename $b)\"\n        fi\n      fi\n    done \n  fi\n}\n\nfunction check_xbmc_dylib_depends\n{\n  REWIND=\"1\"\n  while [ $REWIND = \"1\" ]\n  do\n    let REWIND=\"0\"\n    for b in $(find \"$1\" -type f -name \"$2\" -print) ; do\n      #echo \"Processing $b\"\n      install_name_tool -id \"$(basename $b)\" \"$b\"\n      for a in $(otool -L \"$b\"  | grep \"$EXTERNAL_LIBS\" | awk ' { print $1 } ') ; do\n        #echo \"    Packaging $a\"\n        if [ ! -f  \"$TARGET_FRAMEWORKS/$(basename $a)\" ]; then\n          echo \"    Packaging $a\"\n          cp -f \"$a\" \"$TARGET_FRAMEWORKS/\"\n          chmod u+w \"$TARGET_FRAMEWORKS/$(basename $a)\"\n          let REWIND=\"1\"\n        fi\n        install_name_tool -change \"$a\" \"$DYLIB_NAMEPATH/$(basename $a)\" \"$b\"\n      done\n    done\n  done\n}\n\nEXTERNAL_LIBS=/Users/Shared/xbmc-depends/\"$SDK_NAME\"_\"$ARCHS\"\n\nTARGET_NAME=$PRODUCT_NAME\nTARGET_CONTENTS=$TARGET_BUILD_DIR/$TARGET_NAME/Contents\n\nTARGET_BINARY=$TARGET_CONTENTS/MacOS/XBMC\nTARGET_FRAMEWORKS=$TARGET_CONTENTS/Frameworks\nDYLIB_NAMEPATH=@executable_path/../Frameworks\nXBMC_HOME=$TARGET_CONTENTS/Resources/XBMC\n\nmkdir -p \"$TARGET_CONTENTS/MacOS\"\nmkdir -p \"$TARGET_CONTENTS/Resources\"\n# start clean so we don't keep old dylibs\nrm -rf \"$TARGET_CONTENTS/Frameworks\"\nmkdir -p \"$TARGET_CONTENTS/Frameworks\"\n\necho \"Package $TARGET_BUILD_DIR/XBMC\"\ncp -f \"$TARGET_BUILD_DIR/XBMC\" \"$TARGET_BINARY\"\ncp -f \"$SRCROOT/media/xbmc.icns\" \"$TARGET_CONTENTS/Resources/\"\ncp -f \"$SRCROOT/xbmc/osx/Info.plist\" \"$TARGET_CONTENTS/\"\n\n# Copy all of XBMC's dylib dependencies and rename their locations to inside the Framework\necho \"Checking $TARGET_BINARY dylib dependencies\"\nfor a in $(otool -L \"$TARGET_BINARY\"  | grep \"$EXTERNAL_LIBS\" | awk ' { print $1 } ') ; do \n\techo \"    Packaging $a\"\n\tcp -f \"$a\" \"$TARGET_FRAMEWORKS/\"\n\tchmod u+w \"$TARGET_FRAMEWORKS/$(basename $a)\"\n\tinstall_name_tool -change \"$a\" \"$DYLIB_NAMEPATH/$(basename $a)\" \"$TARGET_BINARY\"\ndone\n\necho \"Package $EXTERNAL_LIBS/lib/python2.6\"\nmkdir -p \"$TARGET_CONTENTS/Frameworks/lib\"\nPYTHONSYNC=\"rsync -aq --exclude .DS_Store --exclude *.a --exclude *.exe --exclude test --exclude tests\"\n${PYTHONSYNC} \"$EXTERNAL_LIBS/lib/python2.6\" \"$TARGET_FRAMEWORKS/lib/\"\nrm -rf \"$TARGET_FRAMEWORKS/lib/python2.6/config\"\n\necho \"Checking $TARGET_FRAMEWORKS/lib/python2.6 *.so for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$TARGET_FRAMEWORKS\"/lib/python2.6 \"*.so\"\n\necho \"Checking $XBMC_HOME/system *.so for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$XBMC_HOME\"/system \"*.so\"\n\necho \"Checking $XBMC_HOME/addons *.so for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$XBMC_HOME\"/addons \"*.so\"\n\necho \"Checking $XBMC_HOME/addons *.pvr for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$XBMC_HOME\"/addons \"*.pvr\"\n\necho \"Checking $XBMC_HOME/addons *.xbs for dylib dependencies\"\ncheck_xbmc_dylib_depends \"$XBMC_HOME\"/addons \"*.xbs\"\n\necho \"Checking xbmc/DllPaths_generated.h for dylib dependencies\"\nfor a in $(grep .dylib \"$SRCROOT\"/xbmc/DllPaths_generated.h | awk '{print $3}' | sed s/\\\"//g) ; do\n  check_dyloaded_depends $a\ndone\n\necho \"Checking $TARGET_FRAMEWORKS for missing dylib dependencies\"\nREWIND=\"1\"\nwhile [ $REWIND = \"1\" ]\ndo\n\tlet REWIND=\"0\"\n\tfor b in \"$TARGET_FRAMEWORKS/\"*dylib* ; do\n\t\t#echo \"  Processing $b\"\n\t\tfor a in $(otool -L \"$b\"  | grep \"$EXTERNAL_LIBS\" | awk ' { print $1 } ') ; do\n\t\t\t#echo \"Processing $a\"\n\t\t\tif [ ! -f  \"$TARGET_FRAMEWORKS/$(basename $a)\" ]; then\n\t\t\t\techo \"    Packaging $a\"\n\t\t\t\tcp -f \"$a\" \"$TARGET_FRAMEWORKS/\"\n\t\t\t\tchmod u+w \"$TARGET_FRAMEWORKS/$(basename $a)\"\n\t\t\t\tlet REWIND=\"1\"\n\t\t\tfi\n\t\t\tinstall_name_tool -change \"$a\" \"$DYLIB_NAMEPATH/$(basename $a)\" \"$TARGET_FRAMEWORKS/$(basename $b)\"\n\t\tdone \n\tdone\ndone\n";
                };
                81B8FC150E7D927A00354E2E /* update version info */ = {
                        isa = PBXShellScriptBuildPhase;
                                E38E209A0D25F9FD00618676 /* GUIDialogSongInfo.cpp in Sources */,
                                E38E209B0D25F9FD00618676 /* GUIDialogSubMenu.cpp in Sources */,
                                E38E209D0D25F9FD00618676 /* GUIDialogVideoBookmarks.cpp in Sources */,
-                               E38E209E0D25F9FD00618676 /* GUIDialogVideoScan.cpp in Sources */,
                                E38E20A00D25F9FD00618676 /* GUIDialogVisualisationPresetList.cpp in Sources */,
                                E38E20A20D25F9FD00618676 /* GUIDialogVolumeBar.cpp in Sources */,
                                E38E20A30D25F9FD00618676 /* GUIDialogYesNo.cpp in Sources */,
                                F5B13C8D1334056B0045076D /* DarwinUtils.mm in Sources */,
                                7C99B6A4133D342100FC2B16 /* CircularCache.cpp in Sources */,
                                7C99B7951340723F00FC2B16 /* GUIDialogPlayEject.cpp in Sources */,
-                               F5AE407613415D8D0004BD79 /* HttpApi.cpp in Sources */,
-                               F5AE407913415D8D0004BD79 /* XBMChttp.cpp in Sources */,
                                F5AE409C13415D9E0004BD79 /* AudioLibrary.cpp in Sources */,
                                F5AE409F13415D9E0004BD79 /* FileItemHandler.cpp in Sources */,
                                F5AE40A013415D9E0004BD79 /* FileOperations.cpp in Sources */,
                                32C631281423A90F00F18420 /* JpegIO.cpp in Sources */,
                                DF448457140048A60069344B /* AirTunesServer.cpp in Sources */,
                                DF44845E140048C80069344B /* PipesManager.cpp in Sources */,
-                               DF4484EE140054530069344B /* BXAcodec.cpp in Sources */,
                                DF98D98C1434F47D00A6EBE1 /* SkinVariable.cpp in Sources */,
                                F5E10537140AA38100175026 /* PeripheralBusUSB.cpp in Sources */,
                                F5E10538140AA38100175026 /* PeripheralBus.cpp in Sources */,
                                DF527737151BAF4C00B5B63B /* WebSocketV8.cpp in Sources */,
                                188F75FE152217BC009870CE /* Mime.cpp in Sources */,
                                188F7602152217DF009870CE /* GUIOperations.cpp in Sources */,
-                               DFCA6AC6152245CD000BFAAE /* HTTPApiHandler.cpp in Sources */,
                                DFCA6AC7152245CD000BFAAE /* HTTPJsonRpcHandler.cpp in Sources */,
                                DFCA6AC8152245CD000BFAAE /* HTTPVfsHandler.cpp in Sources */,
                                DFCA6AC9152245CD000BFAAE /* HTTPWebinterfaceAddonsHandler.cpp in Sources */,
                                7C4458BD161E203800A905F6 /* Screenshot.cpp in Sources */,
                                1D638128161E211E003603ED /* PeripheralImon.cpp in Sources */,
                                AE89ACA61621DAB800E17DBC /* DVDDemuxBXA.cpp in Sources */,
+                               36A95DA51624894400727135 /* GUIDialogMediaFilter.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                        "$(SRCROOT)/lib/cmyth/librefmem",
                                        "$(SRCROOT)/lib/libsquish",
                                        "$(SRCROOT)/lib/SlingboxLib",
-                                       "$(SRCROOT)/xbmc/interfaces/http-api",
                                        "$(SRCROOT)/xbmc/interfaces/json-rpc",
                                        "\"$(SRCROOT)/lib/ffmpeg/libavcodec\"",
                                        "\"$(SRCROOT)/lib/ffmpeg/libavutil\"",
                                        "$(SRCROOT)/lib/cmyth/librefmem",
                                        "$(SRCROOT)/lib/libsquish",
                                        "$(SRCROOT)/lib/SlingboxLib",
-                                       "$(SRCROOT)/xbmc/interfaces/http-api",
                                        "$(SRCROOT)/xbmc/interfaces/json-rpc",
                                        "\"$(SRCROOT)/lib/ffmpeg/libavcodec\"",
                                        "\"$(SRCROOT)/lib/ffmpeg/libavutil\"",
index 8b8e7d3..0863160 100644 (file)
 class CHelper_libXBMC_pvr
 {
 public:
-  CHelper_libXBMC_pvr()
+  CHelper_libXBMC_pvr(void)
   {
     m_libXBMC_pvr = NULL;
     m_Handle      = NULL;
   }
 
-  ~CHelper_libXBMC_pvr()
+  ~CHelper_libXBMC_pvr(void)
   {
     if (m_libXBMC_pvr)
     {
@@ -54,9 +54,14 @@ public:
     }
   }
 
-  bool RegisterMe(void *Handle)
+  /*!
+   * @brief Resolve all callback methods
+   * @param handle Pointer to the add-on
+   * @return True when all methods were resolved, false otherwise.
+   */
+  bool RegisterMe(void* handle)
   {
-    m_Handle = Handle;
+    m_Handle = handle;
 
     std::string libBasePath;
     libBasePath  = ((cb_array*)m_Handle)->libPath;
@@ -117,6 +122,10 @@ public:
       dlsym(m_libXBMC_pvr, "PVR_trigger_channel_groups_update");
     if (PVR_trigger_channel_groups_update == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
 
+    PVR_trigger_epg_update = (void (*)(void* HANDLE, void* CB, unsigned int iChannelUid))
+      dlsym(m_libXBMC_pvr, "PVR_trigger_epg_update");
+    if (PVR_trigger_epg_update == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
+
     PVR_transfer_channel_group  = (void (*)(void* HANDLE, void* CB, const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP *group))
       dlsym(m_libXBMC_pvr, "PVR_transfer_channel_group");
     if (PVR_transfer_channel_group == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
@@ -139,72 +148,142 @@ public:
     return m_Callbacks != NULL;
   }
 
-  void TransferEpgEntry(const ADDON_HANDLE handle, const EPG_TAG *epgentry)
+  /*!
+   * @brief Transfer an EPG tag from the add-on to XBMC
+   * @param handle The handle parameter that XBMC used when requesting the EPG data
+   * @param entry The entry to transfer to XBMC
+   */
+  void TransferEpgEntry(const ADDON_HANDLE handle, const EPG_TAG* entry)
+  {
+    return PVR_transfer_epg_entry(m_Handle, m_Callbacks, handle, entry);
+  }
+
+  /*!
+   * @brief Transfer a channel entry from the add-on to XBMC
+   * @param handle The handle parameter that XBMC used when requesting the channel list
+   * @param entry The entry to transfer to XBMC
+   */
+  void TransferChannelEntry(const ADDON_HANDLE handle, const PVR_CHANNEL* entry)
+  {
+    return PVR_transfer_channel_entry(m_Handle, m_Callbacks, handle, entry);
+  }
+
+  /*!
+   * @brief Transfer a timer entry from the add-on to XBMC
+   * @param handle The handle parameter that XBMC used when requesting the timers list
+   * @param entry The entry to transfer to XBMC
+   */
+  void TransferTimerEntry(const ADDON_HANDLE handle, const PVR_TIMER* entry)
   {
-    return PVR_transfer_epg_entry(m_Handle, m_Callbacks, handle, epgentry);
+    return PVR_transfer_timer_entry(m_Handle, m_Callbacks, handle, entry);
   }
 
-  void TransferChannelEntry(const ADDON_HANDLE handle, const PVR_CHANNEL *chan)
+  /*!
+   * @brief Transfer a recording entry from the add-on to XBMC
+   * @param handle The handle parameter that XBMC used when requesting the recordings list
+   * @param entry The entry to transfer to XBMC
+   */
+  void TransferRecordingEntry(const ADDON_HANDLE handle, const PVR_RECORDING* entry)
   {
-    return PVR_transfer_channel_entry(m_Handle, m_Callbacks, handle, chan);
+    return PVR_transfer_recording_entry(m_Handle, m_Callbacks, handle, entry);
   }
 
-  void TransferTimerEntry(const ADDON_HANDLE handle, const PVR_TIMER *timer)
+  /*!
+   * @brief Transfer a channel group from the add-on to XBMC. The group will be created if it doesn't exist.
+   * @param handle The handle parameter that XBMC used when requesting the channel groups list
+   * @param entry The entry to transfer to XBMC
+   */
+  void TransferChannelGroup(const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP* entry)
   {
-    return PVR_transfer_timer_entry(m_Handle, m_Callbacks, handle, timer);
+    return PVR_transfer_channel_group(m_Handle, m_Callbacks, handle, entry);
   }
 
-  void TransferRecordingEntry(const ADDON_HANDLE handle, const PVR_RECORDING *recording)
+  /*!
+   * @brief Transfer a channel group member entry from the add-on to XBMC. The channel will be added to the group if the group can be found.
+   * @param handle The handle parameter that XBMC used when requesting the channel group members list
+   * @param entry The entry to transfer to XBMC
+   */
+  void TransferChannelGroupMember(const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP_MEMBER* entry)
   {
-    return PVR_transfer_recording_entry(m_Handle, m_Callbacks, handle, recording);
+    return PVR_transfer_channel_group_member(m_Handle, m_Callbacks, handle, entry);
   }
 
-  void AddMenuHook(PVR_MENUHOOK *hook)
+  /*!
+   * @brief Add or replace a menu hook for the context menu for this add-on
+   * @param hook The hook to add
+   */
+  void AddMenuHook(PVR_MENUHOOK* hook)
   {
     return PVR_add_menu_hook(m_Handle, m_Callbacks, hook);
   }
 
-  void Recording(const char *Name, const char *FileName, bool On)
+  /*!
+   * @brief Display a notification in XBMC that a recording started or stopped on the server
+   * @param strRecordingName The name of the recording to display
+   * @param strFileName The filename of the recording
+   * @param bOn True when recording started, false when it stopped
+   */
+  void Recording(const char* strRecordingName, const char* strFileName, bool bOn)
   {
-    return PVR_recording(m_Handle, m_Callbacks, Name, FileName, On);
+    return PVR_recording(m_Handle, m_Callbacks, strRecordingName, strFileName, bOn);
   }
 
-  void TriggerTimerUpdate()
+  /*!
+   * @brief Request XBMC to update it's list of timers
+   */
+  void TriggerTimerUpdate(void)
   {
     return PVR_trigger_timer_update(m_Handle, m_Callbacks);
   }
 
-  void TriggerRecordingUpdate()
+  /*!
+   * @brief Request XBMC to update it's list of recordings
+   */
+  void TriggerRecordingUpdate(void)
   {
     return PVR_trigger_recording_update(m_Handle, m_Callbacks);
   }
 
-  void TriggerChannelUpdate()
+  /*!
+   * @brief Request XBMC to update it's list of channels
+   */
+  void TriggerChannelUpdate(void)
   {
     return PVR_trigger_channel_update(m_Handle, m_Callbacks);
   }
 
-  void TriggerChannelGroupsUpdate()
-  {
-    return PVR_trigger_channel_groups_update(m_Handle, m_Callbacks);
-  }
-
-  void TransferChannelGroup(const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP *group)
+  /*!
+   * @brief Schedule an EPG update for the given channel channel
+   * @param iChannelUid The unique id of the channel for this add-on
+   */
+  void TriggerEpgUpdate(unsigned int iChannelUid)
   {
-    return PVR_transfer_channel_group(m_Handle, m_Callbacks, handle, group);
+    return PVR_trigger_epg_update(m_Handle, m_Callbacks, iChannelUid);
   }
 
-  void TransferChannelGroupMember(const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP_MEMBER *member)
+  /*!
+   * @brief Request XBMC to update it's list of channel groups
+   */
+  void TriggerChannelGroupsUpdate(void)
   {
-    return PVR_transfer_channel_group_member(m_Handle, m_Callbacks, handle, member);
+    return PVR_trigger_channel_groups_update(m_Handle, m_Callbacks);
   }
 
 #ifdef USE_DEMUX
+  /*!
+   * @brief Free a packet that was allocated with AllocateDemuxPacket
+   * @param pPacket The packet to free
+   */
   void FreeDemuxPacket(DemuxPacket* pPacket)
   {
     return PVR_free_demux_packet(m_Handle, m_Callbacks, pPacket);
   }
 
+  /*!
+   * @brief Allocate a demux packet. Free with FreeDemuxPacket
+   * @param iDataSize The size of the data that will go into the packet
+   * @return The allocated packet
+   */
   DemuxPacket* AllocateDemuxPacket(int iDataSize)
   {
     return PVR_allocate_demux_packet(m_Handle, m_Callbacks, iDataSize);
@@ -212,29 +291,30 @@ public:
 #endif
 
 protected:
-  void* (*PVR_register_me)(void *HANDLE);
-  void (*PVR_unregister_me)(void* HANDLE, void* CB);
-  void (*PVR_transfer_epg_entry)(void* HANDLE, void* CB, const ADDON_HANDLE handle, const EPG_TAG *epgentry);
-  void (*PVR_transfer_channel_entry)(void* HANDLE, void* CB, const ADDON_HANDLE handle, const PVR_CHANNEL *chan);
-  void (*PVR_transfer_timer_entry)(void* HANDLE, void* CB, const ADDON_HANDLE handle, const PVR_TIMER *timer);
-  void (*PVR_transfer_recording_entry)(void* HANDLE, void* CB, const ADDON_HANDLE handle, const PVR_RECORDING *recording);
-  void (*PVR_add_menu_hook)(void* HANDLE, void* CB, PVR_MENUHOOK *hook);
-  void (*PVR_recording)(void* HANDLE, void* CB, const char *Name, const char *FileName, bool On);
-  void (*PVR_trigger_channel_update)(void* HANDLE, void* CB);
-  void (*PVR_trigger_channel_groups_update)(void* HANDLE, void* CB);
-  void (*PVR_trigger_timer_update)(void* HANDLE, void* CB);
-  void (*PVR_trigger_recording_update)(void* HANDLE, void* CB);
-  void (*PVR_transfer_channel_group)(void* HANDLE, void* CB, const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP *group);
-  void (*PVR_transfer_channel_group_member)(void* HANDLE, void* CB, const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP_MEMBER *member);
+  void* (*PVR_register_me)(void*);
+  void (*PVR_unregister_me)(void*, void*);
+  void (*PVR_transfer_epg_entry)(void*, void*, const ADDON_HANDLE, const EPG_TAG*);
+  void (*PVR_transfer_channel_entry)(void*, void*, const ADDON_HANDLE, const PVR_CHANNEL*);
+  void (*PVR_transfer_timer_entry)(void*, void*, const ADDON_HANDLE, const PVR_TIMER*);
+  void (*PVR_transfer_recording_entry)(void*, void*, const ADDON_HANDLE, const PVR_RECORDING*);
+  void (*PVR_add_menu_hook)(void*, void*, PVR_MENUHOOK*);
+  void (*PVR_recording)(void*, void*, const char*, const char*, bool);
+  void (*PVR_trigger_channel_update)(void*, void*);
+  void (*PVR_trigger_channel_groups_update)(void*, void*);
+  void (*PVR_trigger_timer_update)(void*, void*);
+  void (*PVR_trigger_recording_update)(void* , void*);
+  void (*PVR_trigger_epg_update)(void*, void*, unsigned int);
+  void (*PVR_transfer_channel_group)(void*, void*, const ADDON_HANDLE, const PVR_CHANNEL_GROUP*);
+  void (*PVR_transfer_channel_group_member)(void*, void*, const ADDON_HANDLE, const PVR_CHANNEL_GROUP_MEMBER*);
 #ifdef USE_DEMUX
-  void (*PVR_free_demux_packet)(void* HANDLE, void* CB, DemuxPacket* pPacket);
-  DemuxPacket* (*PVR_allocate_demux_packet)(void* HANDLE, void* CB, int iDataSize);
+  void (*PVR_free_demux_packet)(void*, void*, DemuxPacket*);
+  DemuxPacket* (*PVR_allocate_demux_packet)(void*, void*, int);
 #endif
 
 private:
-  void *m_libXBMC_pvr;
-  void *m_Handle;
-  void *m_Callbacks;
+  voidm_libXBMC_pvr;
+  voidm_Handle;
+  voidm_Callbacks;
   struct cb_array
   {
     const char* libPath;
index cff6982..b59bf43 100644 (file)
@@ -72,7 +72,7 @@
                                                <posy>0</posy>
                                                <width>675</width>
                                                <height>380</height>
-                                               <texture background="true">$INFO[ListItem.Property(Fanart_Image)]</texture>
+                                               <texture background="true">$INFO[ListItem.Art(fanart)]</texture>
                                                <bordertexture border="5">button-nofocus.png</bordertexture>
                                                <bordersize>4</bordersize>
                                                <aspectratio>keep</aspectratio>
diff --git a/addons/skin.confluence/720p/DialogMediaFilter.xml b/addons/skin.confluence/720p/DialogMediaFilter.xml
new file mode 100644 (file)
index 0000000..accb0c8
--- /dev/null
@@ -0,0 +1,184 @@
+<window id="151">
+       <defaultcontrol always="true">5</defaultcontrol>
+       <coordinates>
+               <system>1</system>
+               <posx>240</posx>
+               <posy>100</posy>
+       </coordinates>
+       <include>dialogeffect</include>
+       <controls>
+               <control type="image">
+                       <description>background image</description>
+                       <posx>0</posx>
+                       <posy>0</posy>
+                       <width>800</width>
+                       <height>500</height>
+                       <texture border="40">DialogBack.png</texture>
+               </control>
+               <control type="image">
+                       <description>Dialog Header image</description>
+                       <posx>40</posx>
+                       <posy>16</posy>
+                       <width>720</width>
+                       <height>40</height>
+                       <texture>dialogheader.png</texture>
+               </control>
+               <control type="label" id="2">
+                       <description>header label</description>
+                       <posx>40</posx>
+                       <posy>20</posy>
+                       <width>720</width>
+                       <height>30</height>
+                       <font>font13_title</font>
+                       <label>587</label>
+                       <align>center</align>
+                       <aligny>center</aligny>
+                       <textcolor>selected</textcolor>
+                       <shadowcolor>black</shadowcolor>
+               </control>
+               <control type="button">
+                       <description>Close Window button</description>
+                       <posx>710</posx>
+                       <posy>15</posy>
+                       <width>64</width>
+                       <height>32</height>
+                       <label>-</label>
+                       <font>-</font>
+                       <onclick>PreviousMenu</onclick>
+                       <texturefocus>DialogCloseButton-focus.png</texturefocus>
+                       <texturenofocus>DialogCloseButton.png</texturenofocus>
+                       <onleft>10</onleft>
+                       <onright>10</onright>
+                       <onup>10</onup>
+                       <ondown>10</ondown>
+                       <visible>system.getbool(input.enablemouse)</visible>
+               </control>
+
+               <control type="grouplist" id="5">
+                       <description>control area</description>
+                       <posx>30</posx>
+                       <posy>70</posy>
+                       <width>720</width>
+                       <height>350</height>
+                       <itemgap>4</itemgap>
+                       <pagecontrol>6</pagecontrol>
+                       <onup>9001</onup>
+                       <ondown>9001</ondown>
+                       <onleft>9001</onleft>
+                       <onright>6</onright>
+               </control>
+               <control type="scrollbar" id="6">
+                       <posx>755</posx>
+                       <posy>70</posy>
+                       <width>25</width>
+                       <height>350</height>
+                       <texturesliderbackground border="0,14,0,14">ScrollBarV.png</texturesliderbackground>
+                       <texturesliderbar border="2,16,2,16">ScrollBarV_bar.png</texturesliderbar>
+                       <texturesliderbarfocus border="2,16,2,16">ScrollBarV_bar_focus.png</texturesliderbarfocus>
+                       <textureslidernib>ScrollBarNib.png</textureslidernib>
+                       <textureslidernibfocus>ScrollBarNib.png</textureslidernibfocus>
+                       <onleft>5</onleft>
+                       <onright>9001</onright>
+                       <showonepage>false</showonepage>
+                       <orientation>vertical</orientation>
+               </control>
+
+               <control type="button" id="7">
+                       <description>Default Button</description>
+                       <posx>0</posx>
+                       <posy>0</posy>
+                       <height>40</height>
+                       <font>font13</font>
+                       <textcolor>grey2</textcolor>
+                       <focusedcolor>white</focusedcolor>
+                       <texturenofocus border="5">button-nofocus.png</texturenofocus>
+                       <texturefocus border="5">button-focus2.png</texturefocus>
+               </control>
+               <control type="radiobutton" id="8">
+                       <description>Default RadioButton</description>
+                       <posx>0</posx>
+                       <posy>0</posy>
+                       <height>40</height>
+                       <font>font13</font>
+                       <textcolor>grey2</textcolor>
+                       <focusedcolor>white</focusedcolor>
+                       <texturenofocus border="5">button-nofocus.png</texturenofocus>
+                       <texturefocus border="5">button-focus2.png</texturefocus>
+               </control>
+               <control type="spincontrolex" id="9">
+                       <description>Default SpinControlex</description>
+                       <posx>0</posx>
+                       <posy>0</posy>
+                       <height>40</height>
+                       <font>font13</font>
+                       <textcolor>grey2</textcolor>
+                       <focusedcolor>white</focusedcolor>
+                       <texturenofocus border="5">button-nofocus.png</texturenofocus>
+                       <texturefocus border="5">button-focus2.png</texturefocus>
+                       <aligny>center</aligny>
+                       <reverse>yes</reverse>
+               </control>
+               <control type="sliderex" id="10">
+                       <description>Default Slider</description>
+                       <posx>0</posx>
+                       <posy>0</posy>
+                       <height>40</height>
+                       <font>font13</font>
+                       <textcolor>grey2</textcolor>
+                       <focusedcolor>white</focusedcolor>
+                       <texturenofocus border="5">button-nofocus.png</texturenofocus>
+                       <texturefocus border="5">button-focus2.png</texturefocus>
+                       <aligny>center</aligny>
+               </control>
+               <control type="edit" id="12">
+                       <description>Default Edit</description>
+                       <posx>0</posx>
+                       <posy>0</posy>
+                       <height>40</height>
+                       <font>font13</font>
+                       <textcolor>grey2</textcolor>
+                       <focusedcolor>white</focusedcolor>
+                       <texturenofocus border="5">button-nofocus.png</texturenofocus>
+                       <texturefocus border="5">button-focus2.png</texturefocus>
+               </control>
+
+               <control type="group" id="9001">
+                       <posx>190</posx>
+                       <posy>435</posy>
+                       <control type="button" id="28">
+                               <description>Ok Button</description>
+                               <posx>0</posx>
+                               <posy>0</posy>
+                               <width>200</width>
+                               <height>40</height>
+                               <align>center</align>
+                               <aligny>center</aligny>
+                               <texturenofocus border="5">button-nofocus.png</texturenofocus>
+                               <texturefocus border="5">button-focus.png</texturefocus>
+                               <label>186</label>
+                               <font>font12_title</font>
+                               <onup>5</onup>
+                               <onleft>27</onleft>
+                               <onright>27</onright>
+                               <ondown>5</ondown>
+                       </control>
+                       <control type="button" id="27">
+                               <description>Clear Button</description>
+                               <posx>210</posx>
+                               <posy>0</posy>
+                               <width>200</width>
+                               <height>40</height>
+                               <align>center</align>
+                               <aligny>center</aligny>
+                               <texturenofocus border="5">button-nofocus.png</texturenofocus>
+                               <texturefocus border="5">button-focus.png</texturefocus>
+                               <label>192</label>
+                               <font>font12_title</font>
+                               <onup>5</onup>
+                               <onleft>28</onleft>
+                               <onright>28</onright>
+                               <ondown>5</ondown>
+                       </control>
+               </control>
+       </controls>
+</window>
index f762531..41a6b0b 100644 (file)
@@ -73,7 +73,7 @@
                                                <posy>0</posy>
                                                <width>675</width>
                                                <height>380</height>
-                                               <texture background="true">$INFO[ListItem.Property(Fanart_Image)]</texture>
+                                               <texture background="true">$INFO[ListItem.Art(fanart)]</texture>
                                                <bordertexture border="5">button-nofocus.png</bordertexture>
                                                <bordersize>4</bordersize>
                                                <aspectratio>keep</aspectratio>
                                        </control>
                                </control>
                                <control type="group">
-                                       <visible>[Container.Content(TVShows) + !Skin.HasSetting(TVShowsUsePosters)] + !Control.HasFocus(12)</visible>
+                                       <visible>Container.Content(TVShows) + !Control.HasFocus(12)</visible>
                                        <posy>90</posy>
                                        <posx>210</posx>
                                        <include>VisibleFadeEffect</include>
                                        <control type="image">
-                                               <posx>177</posx>
-                                               <posy>10</posy>
-                                               <width>675</width>
-                                               <height>124</height>
+                                               <posx>0</posx>
+                                               <posy>0</posy>
+                                               <width>270</width>
+                                               <height>380</height>
                                                <aspectratio>stretch</aspectratio>
                                                <bordertexture border="5">button-nofocus.png</bordertexture>
                                                <bordersize>4</bordersize>
                                                <texture background="true">$INFO[ListItem.Icon]</texture>
+                                               <visible>IsEmpty(ListItem.Art(poster))</visible>
                                        </control>
                                        <control type="image">
-                                               <posx>177</posx>
-                                               <posy>10</posy>
-                                               <width>400</width>
-                                               <height>100</height>
-                                               <aspectratio>stretch</aspectratio>
-                                               <texture>GlassOverlay.png</texture>
-                                               <colordiffuse>AAFFFFFF</colordiffuse>
-                                       </control>
-                                       <control type="list" id="49">
-                                               <posx>95</posx>
-                                               <posy>160</posy>
-                                               <width>840</width>
-                                               <height>180</height>
-                                               <onleft>49</onleft>
-                                               <onright>49</onright>
-                                               <onup>9000</onup>
-                                               <ondown>61</ondown>
-                                               <pagecontrol>-</pagecontrol>
-                                               <scrolltime>200</scrolltime>
-                                               <itemlayout height="30">
-                                                       <control type="label">
-                                                               <posx>165</posx>
-                                                               <posy>0</posy>
-                                                               <width>160</width>
-                                                               <height>30</height>
-                                                               <font>font13</font>
-                                                               <align>right</align>
-                                                               <aligny>center</aligny>
-                                                               <textcolor>blue</textcolor>
-                                                               <selectedcolor>selected</selectedcolor>
-                                                               <info>ListItem.Label</info>
-                                                       </control>
-                                                       <control type="label">
-                                                               <posx>175</posx>
-                                                               <posy>0</posy>
-                                                               <width>665</width>
-                                                               <height>30</height>
-                                                               <font>font13</font>
-                                                               <align>left</align>
-                                                               <aligny>center</aligny>
-                                                               <textcolor>white</textcolor>
-                                                               <selectedcolor>white</selectedcolor>
-                                                               <info>ListItem.Label2</info>
-                                                       </control>
-                                               </itemlayout>
-                                               <focusedlayout height="30">
-                                                       <control type="image">
-                                                               <posx>0</posx>
-                                                               <posy>0</posy>
-                                                               <width>840</width>
-                                                               <height>30</height>
-                                                               <visible>Control.HasFocus(49)</visible>
-                                                               <texture>MenuItemFO.png</texture>
-                                                               <include>VisibleFadeEffect</include>
-                                                       </control>
-                                                       <control type="label">
-                                                               <posx>165</posx>
-                                                               <posy>0</posy>
-                                                               <width>160</width>
-                                                               <height>30</height>
-                                                               <font>font13</font>
-                                                               <align>right</align>
-                                                               <aligny>center</aligny>
-                                                               <textcolor>blue</textcolor>
-                                                               <selectedcolor>selected</selectedcolor>
-                                                               <info>ListItem.Label</info>
-                                                       </control>
-                                                       <control type="label">
-                                                               <posx>175</posx>
-                                                               <posy>0</posy>
-                                                               <width>665</width>
-                                                               <height>30</height>
-                                                               <font>font13</font>
-                                                               <align>left</align>
-                                                               <aligny>center</aligny>
-                                                               <textcolor>white</textcolor>
-                                                               <selectedcolor>white</selectedcolor>
-                                                               <info>ListItem.Label2</info>
-                                                       </control>
-                                               </focusedlayout>
-                                               <content>
-                                                       <item>
-                                                               <label>$LOCALIZE[20360]:</label>
-                                                               <label2>$INFO[listitem.episode] [COLOR=grey] ($INFO[ListItem.Property(WatchedEpisodes),, $LOCALIZE[16102]] - $INFO[ListItem.Property(UnWatchedEpisodes), , $LOCALIZE[16101]])[/COLOR]</label2>
-                                                               <onclick>-</onclick>
-                                                               <visible>!IsEmpty(ListItem.Episode)</visible>
-                                                       </item>
-                                                       <item>
-                                                               <label>$LOCALIZE[31322]:</label>
-                                                               <label2>$INFO[ListItem.Premiered]</label2>
-                                                               <onclick>-</onclick>
-                                                               <visible>!IsEmpty(ListItem.Premiered)</visible>
-                                                       </item>
-                                                       <item>
-                                                               <label>$LOCALIZE[515]:</label>
-                                                               <label2>$INFO[ListItem.Genre]</label2>
-                                                               <onclick>-</onclick>
-                                                               <visible>!IsEmpty(ListItem.Genre)</visible>
-                                                       </item>
-                                                       <item>
-                                                               <label>$LOCALIZE[562]:</label>
-                                                               <label2>$INFO[ListItem.Year]</label2>
-                                                               <onclick>-</onclick>
-                                                               <visible>!IsEmpty(ListItem.Year)</visible>
-                                                       </item>
-                                                       <item>
-                                                               <label>$LOCALIZE[563]:</label>
-                                                               <label2>$INFO[ListItem.Rating]</label2>
-                                                               <onclick>-</onclick>
-                                                               <visible>!IsEmpty(ListItem.Rating)</visible>
-                                                       </item>
-                                                       <item>
-                                                               <label>$LOCALIZE[15311]</label>
-                                                               <label2>$INFO[ListItem.FilenameAndPath]</label2>
-                                                               <onclick>-</onclick>
-                                                               <visible>!IsEmpty(ListItem.FilenameAndPath)</visible>
-                                                       </item>
-                                               </content>
-                                       </control>
-                                       <control type="image">
-                                               <posx>0</posx>
-                                               <posy>370</posy>
-                                               <width>1030</width>
-                                               <height>4</height>
-                                               <aspectratio>stretch</aspectratio>
-                                               <texture>separator.png</texture>
-                                       </control>
-                               </control>
-                               <control type="group">
-                                       <visible>[Container.Content(TVShows) + Skin.HasSetting(TVShowsUsePosters)] + !Control.HasFocus(12)</visible>
-                                       <posy>90</posy>
-                                       <posx>210</posx>
-                                       <include>VisibleFadeEffect</include>
-                                       <control type="image">
                                                <posx>0</posx>
                                                <posy>0</posy>
                                                <width>270</width>
                                                <aspectratio>stretch</aspectratio>
                                                <bordertexture border="5">button-nofocus.png</bordertexture>
                                                <bordersize>4</bordersize>
-                                               <texture background="true">$INFO[ListItem.Icon]</texture>
+                                               <texture background="true">$INFO[ListItem.Art(poster)]</texture>
+                                               <visible>!IsEmpty(ListItem.Art(poster))</visible>
                                        </control>
                                        <control type="image">
                                                <posx>4</posx>
                                        <control type="button" id="10">
                                                <description>Get Thumb</description>
                                                <include>ButtonInfoDialogsCommonValues</include>
-                                               <label>13405</label>
-                                       </control>
-                                       <control type="button" id="12">
-                                               <description>Get Fanart</description>
-                                               <include>ButtonInfoDialogsCommonValues</include>
-                                               <label>20413</label>
+                                               <label>13511</label>
                                        </control>
                                        <control type="button" id="11">
                                                <description>Play Trailer</description>
diff --git a/addons/skin.confluence/720p/DialogVideoScan.xml b/addons/skin.confluence/720p/DialogVideoScan.xml
deleted file mode 100644 (file)
index d66f297..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-<window id="133">
-       <defaultcontrol></defaultcontrol>
-               <animation effect="slide" start="0,-70" end="0,0" time="100">WindowOpen</animation>
-               <animation effect="slide" start="0,0" end="0,-70" delay="400" time="100">WindowClose</animation>
-       <controls>
-               <control type="group">
-                       <posx>720</posx>
-                       <posy>0</posy>
-                       <animation effect="slide" end="0,-80" time="200" condition="Window.IsVisible(FullscreenVideo) | Window.IsVisible(Visualisation)">conditional</animation>
-                       <control type="image">
-                               <posx>0</posx>
-                               <posy>-10</posy>
-                               <width>400</width>
-                               <height>70</height>
-                               <texture flipy="true" border="20,20,20,2">InfoMessagePanel.png</texture>
-                       </control>
-                       <control type="label" id="401">
-                               <description>Caption Label</description>
-                               <posx>15</posx>
-                               <posy>4</posy>
-                               <width>370</width>
-                               <height>18</height>
-                               <font>font10_title</font>
-                               <textcolor>selected</textcolor>
-                               <align>left</align>
-                               <aligny>center</aligny>
-                       </control>
-                       <control type="label" id="405">
-                               <description>Current Directory Label</description>
-                               <posx>15</posx>
-                               <posy>20</posy>
-                               <width>370</width>
-                               <height>20</height>
-                               <font>font10</font>
-                               <align>left</align>
-                               <aligny>center</aligny>
-                       </control>
-                       <control type="progress" id="404">
-                               <description>progress control</description>
-                               <posx>15</posx>
-                               <posy>42</posy>
-                               <width>370</width>
-                               <height>8</height>
-                       </control>
-               </control>
-       </controls>
-</window>
\ No newline at end of file
index fb62336..1c21ae4 100644 (file)
@@ -40,7 +40,7 @@
                                <width>130</width>
                                <height>295</height>
                                <aspectratio aligny="bottom">keep</aspectratio>
-                               <texture>$INFO[MusicPlayer.Cover]</texture>
+                               <texture fallback="DefaultAlbumCover.png">$INFO[Player.Art(thumb)]</texture>
                                <bordertexture border="8">ThumbBorder.png</bordertexture>
                                <bordersize>5</bordersize>
                        </control>
                                        <width>150</width>
                                        <height>300</height>
                                        <aspectratio aligny="bottom">keep</aspectratio>
-                                       <texture>$INFO[VideoPlayer.Cover]</texture>
+                                       <texture fallback="DefaultVideoCover.png">$INFO[Player.Art(thumb)]</texture>
                                        <bordertexture border="8">ThumbBorder.png</bordertexture>
                                        <bordersize>5</bordersize>
                                </control>
                                        <width>120</width>
                                        <height>300</height>
                                        <aspectratio aligny="bottom">keep</aspectratio>
-                                       <texture>$INFO[VideoPlayer.Cover]</texture>
+                                       <texture fallback="DefaultVideoCover.png">$INFO[Player.Art(thumb)]</texture>
                                        <bordertexture border="8">ThumbBorder.png</bordertexture>
                                        <bordersize>5</bordersize>
                                </control>
                                        <width>120</width>
                                        <height>300</height>
                                        <aspectratio aligny="bottom">keep</aspectratio>
-                                       <texture>$INFO[VideoPlayer.Cover]</texture>
+                                       <texture fallback="DefaultVideoCover.png">$INFO[Player.Art(thumb)]</texture>
                                        <bordertexture border="8">ThumbBorder.png</bordertexture>
                                        <bordersize>5</bordersize>
                                </control>
                                        <width>180</width>
                                        <height>120</height>
                                        <aspectratio>scale</aspectratio>
-                                       <texture>$INFO[VideoPlayer.Cover]</texture>
+                                       <texture fallback="DefaultVideoCover.png">$INFO[Player.Art(thumb)]</texture>
                                        <bordertexture border="8">ThumbBorder.png</bordertexture>
                                        <bordersize>5</bordersize>
                                </control>
                                                <texturefocus>OSDStopFO.png</texturefocus>
                                                <texturenofocus>OSDStopNF.png</texturenofocus>
                                                <onleft>602</onleft>
-                                               <onright>606</onright>
+                                               <onright>604</onright>
                                                <onup>9003</onup>
                                                <ondown>9000</ondown>
                                                <onclick>down</onclick>
                                                <onclick>XBMC.PlayerControl(Stop)</onclick>
                                        </control>
+                                       <control type="togglebutton" id="604">
+                                               <posx>100</posx>
+                                               <posy>2</posy>
+                                               <width>30</width>
+                                               <height>30</height>
+                                               <label>-</label>
+                                               <texturefocus>OSDPauseFO.png</texturefocus>
+                                               <texturenofocus>OSDPauseNF.png</texturenofocus>
+                                               <usealttexture>Player.Paused | Player.Forwarding | Player.Rewinding</usealttexture>
+                                               <alttexturefocus>OSDPlayFO.png</alttexturefocus>
+                                               <alttexturenofocus>OSDPlayNF.png</alttexturenofocus>
+                                               <onleft>603</onleft>
+                                               <onright>606</onright>
+                                               <onup>9003</onup>
+                                               <ondown>9000</ondown>
+                                               <onclick>XBMC.PlayerControl(Play)</onclick>
+                                               <enable>Player.PauseEnabled</enable>
+                                               <animation effect="fade" start="100" end="30" time="100" condition="!Player.PauseEnabled">Conditional</animation>
+                                       </control>
                                        <control type="button" id="606">
-                                               <posx>130</posx>
+                                               <posx>160</posx>
                                                <posy>2</posy>
                                                <width>30</width>
                                                <height>30</height>
                                                <label>-</label>
                                                <texturefocus>OSDRecordOffFO.png</texturefocus>
                                                <texturenofocus>OSDRecordOffNF.png</texturenofocus>
-                                               <onleft>603</onleft>
+                                               <onleft>604</onleft>
                                                <onright>607</onright>
                                                <onup>9003</onup>
                                                <ondown>9000</ondown>
index b6f78e1..0f9cb2f 100644 (file)
@@ -28,7 +28,7 @@
                        <width>1280</width>
                        <height>720</height>
                        <aspectratio>scale</aspectratio>
-                       <texture background="true">$INFO[ListItem.Property(Fanart_Image)]</texture>
+                       <texture background="true">$INFO[ListItem.Art(fanart)]</texture>
                        <include>backgroundfade</include>
                        <fadetime>FanartCrossfadeTime</fadetime>
                        <visible>!Skin.HasSetting(HideBackGroundFanart) + !IsEmpty(ListItem.Property(Fanart_Image))</visible>
@@ -66,6 +66,7 @@
                        <height>120</height>
                        <texture flipy="true">HomeNowPlayingBack.png</texture>
                        <visible>[Player.HasVideo + !Skin.HasSetting(ShowBackgroundVideo)] | [Player.HasAudio + ![Skin.HasSetting(ShowBackgroundVis) | SubString(Window(videolibrary).Property(TvTunesIsAlive),True)]] | [!Skin.HasSetting(HideBackGroundFanart) + !IsEmpty(ListItem.Property(Fanart_Image))]</visible>
+                       <include>VisibleFadeEffect</include>
                </control>
        </include>
        <include name="ContentPanelBackgrounds">
index 68d5cbf..50d68d4 100644 (file)
@@ -16,9 +16,9 @@
                        <posy>0</posy>
                        <width>1280</width>
                        <height>720</height>
-                       <texture background="true">$INFO[MusicPlayer.Property(Fanart_Image)]</texture>
+                       <texture background="true">$INFO[Player.Art(fanart)]</texture>
                        <colordiffuse>AAFFFFFF</colordiffuse>
-                       <visible>!IsEmpty(MusicPlayer.Property(Fanart_Image)) + !Skin.HasSetting(HideVisualizationFanart)</visible>
+                       <visible>!IsEmpty(Player.Art(fanart)) + !Skin.HasSetting(HideVisualizationFanart)</visible>
                        <fadetime>600</fadetime>
                </control>
                <!-- media infos -->
@@ -87,7 +87,7 @@
                                <posy>250r</posy>
                                <width>300</width>
                                <height>230</height>
-                               <info>MusicPlayer.Cover</info>
+                               <texture fallback="DefaultAlbumCover.png">$INFO[Player.Art(thumb)]</texture>
                                <aspectratio aligny="bottom">keep</aspectratio>
                                <bordertexture border="8">ThumbShadow.png</bordertexture>
                                <bordersize>8</bordersize>
index b906bbe..aaf084f 100644 (file)
                                        <include>ButtonCommonValues</include>
                                </control>
                                <control type="edit" id="19">
+                                       <visible>Container.CanFilter + !Container.CanFilterAdvanced</visible>
                                        <description>Filter</description>
                                        <textwidth>230</textwidth>
                                        <include>ButtonCommonValues</include>
                                        <label>587</label>
                                </control>
+                               <control type="radiobutton" id="20">
+                                       <visible>Container.CanFilterAdvanced</visible>
+                                       <description>Filter</description>
+                                       <include>ButtonCommonValues</include>
+                                       <label>587</label>
+                                       <selected>Container.Filtered</selected>
+                                       <onclick>right</onclick>
+                                       <onclick>Filter</onclick>
+                               </control>
                                <control type="radiobutton" id="100">
                                        <description>Show Info Toggle</description>
                                        <textwidth>170</textwidth>
index b5c4495..19d1088 100644 (file)
                                        <enable>Library.HasContent(Music)</enable>
                                </control>
                                <control type="edit" id="19">
+                                       <visible>Container.CanFilter + !Container.CanFilterAdvanced</visible>
                                        <description>Filter</description>
                                        <textwidth>230</textwidth>
                                        <include>ButtonCommonValues</include>
                                        <label>587</label>
                                </control>
+                               <control type="radiobutton" id="20">
+                                       <visible>Container.CanFilterAdvanced</visible>
+                                       <description>Filter</description>
+                                       <include>ButtonCommonValues</include>
+                                       <label>587</label>
+                                       <selected>Container.Filtered</selected>
+                                       <onclick>right</onclick>
+                                       <onclick>Filter</onclick>
+                               </control>
                                <include>CommonNowPlaying_Controls</include>
                        </control>
                </control>
index 7301d5e..f57291c 100644 (file)
                                        <usealttexture>Container.SortDirection(Ascending)</usealttexture>
                                </control>
                                <control type="edit" id="19">
+                                       <visible>Container.CanFilter + !Container.CanFilterAdvanced</visible>
                                        <description>Filter</description>
                                        <textwidth>230</textwidth>
                                        <include>ButtonCommonValues</include>
                                        <label>587</label>
                                </control>
+                               <control type="radiobutton" id="20">
+                                       <visible>Container.CanFilterAdvanced</visible>
+                                       <description>Filter</description>
+                                       <include>ButtonCommonValues</include>
+                                       <label>587</label>
+                                       <onclick>right</onclick>
+                                       <onclick>Filter</onclick>
+                               </control>
                                <control type="label" id="201">
                                        <width>250</width>
                                        <height>35</height>
index e1b8f69..c95312a 100644 (file)
                                        <usealttexture>Container.SortDirection(Ascending)</usealttexture>
                                </control>
                                <control type="edit" id="19">
+                                       <visible>Container.CanFilter + !Container.CanFilterAdvanced</visible>
                                        <description>Filter</description>
                                        <textwidth>230</textwidth>
                                        <include>ButtonCommonValues</include>
                                        <label>587</label>
                                </control>
+                               <control type="radiobutton" id="20">
+                                       <visible>Container.CanFilterAdvanced</visible>
+                                       <description>Filter</description>
+                                       <include>ButtonCommonValues</include>
+                                       <label>587</label>
+                                       <onclick>right</onclick>
+                                       <onclick>Filter</onclick>
+                               </control>
                                <include>CommonNowPlaying_Controls</include>
                        </control>
                </control>
index 9c76c66..7b44602 100644 (file)
                                        <usealttexture>Container.SortDirection(Ascending)</usealttexture>
                                </control>
                                <control type="edit" id="19">
+                                       <visible>Container.CanFilter + !Container.CanFilterAdvanced</visible>
                                        <description>Filter</description>
                                        <textwidth>230</textwidth>
                                        <include>ButtonCommonValues</include>
                                        <label>587</label>
                                </control>
+                               <control type="radiobutton" id="20">
+                                       <visible>Container.CanFilterAdvanced</visible>
+                                       <description>Filter</description>
+                                       <include>ButtonCommonValues</include>
+                                       <label>587</label>
+                                       <selected>Container.Filtered</selected>
+                                       <onclick>right</onclick>
+                                       <onclick>Filter</onclick>
+                               </control>
                                <control type="radiobutton" id="99">
                                        <description>Show Info Toggle</description>
                                        <textwidth>170</textwidth>
index e6a6241..05a5da8 100644 (file)
                                <ondown>200</ondown>
                                <onclick>XBMC.PlayerControl(Rewind)</onclick>
                                <visible>VideoPlayer.Content(LiveTV)</visible>
-                               <enable>false</enable>
+                               <enable>Player.SeekEnabled</enable>
                                <animation effect="fade" start="100" end="50" time="100" condition="true">Conditional</animation>
                        </control>
                        <control type="button" id="702">
                                <onclick>XBMC.PlayerControl(Play)</onclick>
                                <visible>VideoPlayer.Content(LiveTV)</visible>
                                <enable>false</enable>
+                               <enable>Player.PauseEnabled</enable>
                                <animation effect="fade" start="100" end="50" time="100" condition="true">Conditional</animation>
                        </control>
                        <control type="button" id="704">
                                <ondown>200</ondown>
                                <onclick>XBMC.PlayerControl(Forward)</onclick>
                                <visible>VideoPlayer.Content(LiveTV)</visible>
-                               <enable>false</enable>
+                               <enable>Player.SeekEnabled</enable>
                                <animation effect="fade" start="100" end="50" time="100" condition="true">Conditional</animation>
                        </control>
                        <control type="button" id="700">
index a208efe..b32ec14 100644 (file)
@@ -67,7 +67,7 @@
                                <posy>260r</posy>
                                <width>300</width>
                                <height>230</height>
-                               <info>VideoPlayer.Cover</info>
+                               <texture fallback="DefaultVideoCover.png">$INFO[Player.Art(thumb)]</texture>
                                <aspectratio aligny="bottom">keep</aspectratio>
                                <bordertexture border="8">ThumbShadow.png</bordertexture>
                                <bordersize>8</bordersize>
@@ -79,7 +79,7 @@
                                <posy>350r</posy>
                                <width>300</width>
                                <height>330</height>
-                               <info>VideoPlayer.Cover</info>
+                               <texture fallback="DefaultVideoCover.png">$INFO[Player.Art(thumb)]</texture>
                                <aspectratio aligny="bottom">keep</aspectratio>
                                <bordertexture border="8">ThumbShadow.png</bordertexture>
                                <bordersize>8</bordersize>
index 5c722de..cc39eee 100644 (file)
                <control type="group" id="100">
                        <posx>325</posx>
                        <posy>60r</posy>
-                       <defaultcontrol always="true">602</defaultcontrol>
+                       <defaultcontrol always="true">202</defaultcontrol>
                        <animation effect="fade" time="200">VisibleChange</animation>
                        <visible>![Window.IsVisible(SliderDialog) | Window.IsVisible(OSDVideoSettings) | Window.IsVisible(OSDAudioSettings) | Window.IsVisible(VideoBookmarks)]</visible>
                        <visible>!VideoPlayer.Content(LiveTV)</visible>
-                       <control type="button" id="600">
+                       <control type="button" id="200">
                                <posx>0</posx>
                                <posy>0</posy>
                                <width>55</width>
                                <font>-</font>
                                <texturefocus>OSDPrevTrackFO.png</texturefocus>
                                <texturenofocus>OSDPrevTrackNF.png</texturenofocus>
-                               <onleft>705</onleft>
-                               <onright>601</onright>
+                               <onleft>254</onleft>
+                               <onright>201</onright>
                                <onup>1000</onup>
                                <ondown>1000</ondown>
                                <onclick>PlayerControl(Previous)</onclick>
                        </control>
-                       <control type="button" id="601">
+                       <control type="button" id="201">
                                <posx>55</posx>
                                <posy>0</posy>
                                <width>55</width>
                                <font>-</font>
                                <texturefocus>OSDRewindFO.png</texturefocus>
                                <texturenofocus>OSDRewindNF.png</texturenofocus>
-                               <onleft>600</onleft>
-                               <onright>602</onright>
+                               <onleft>200</onleft>
+                               <onright>202</onright>
                                <onup>1000</onup>
                                <ondown>1000</ondown>
                                <onclick>PlayerControl(Rewind)</onclick>
                        </control>
-                       <control type="togglebutton" id="602">
+                       <control type="togglebutton" id="202">
                                <posx>110</posx>
                                <posy>0</posy>
                                <width>55</width>
                                <usealttexture>Player.Paused | Player.Forwarding | Player.Rewinding</usealttexture>
                                <alttexturefocus>OSDPlayFO.png</alttexturefocus>
                                <alttexturenofocus>OSDPlayNF.png</alttexturenofocus>
-                               <onleft>601</onleft>
-                               <onright>603</onright>
+                               <onleft>201</onleft>
+                               <onright>203</onright>
                                <onup>1000</onup>
                                <ondown>1000</ondown>
                                <onclick>PlayerControl(Play)</onclick>
                        </control>
-                       <control type="button" id="603">
+                       <control type="button" id="203">
                                <posx>165</posx>
                                <posy>0</posy>
                                <width>55</width>
                                <font>-</font>
                                <texturefocus>OSDStopFO.png</texturefocus>
                                <texturenofocus>OSDStopNF.png</texturenofocus>
-                               <onleft>602</onleft>
-                               <onright>604</onright>
+                               <onleft>202</onleft>
+                               <onright>204</onright>
                                <onup>1000</onup>
                                <ondown>1000</ondown>
                                <onclick>PlayerControl(Stop)</onclick>
                        </control>
-                       <control type="button" id="604">
+                       <control type="button" id="204">
                                <posx>220</posx>
                                <posy>0</posy>
                                <width>55</width>
                                <font>-</font>
                                <texturefocus>OSDForwardFO.png</texturefocus>
                                <texturenofocus>OSDForwardNF.png</texturenofocus>
-                               <onleft>603</onleft>
-                               <onright>605</onright>
+                               <onleft>203</onleft>
+                               <onright>205</onright>
                                <onup>1000</onup>
                                <ondown>1000</ondown>
                                <onclick>PlayerControl(Forward)</onclick>
                        </control>
-                       <control type="button" id="605">
+                       <control type="button" id="205">
                                <posx>275</posx>
                                <posy>0</posy>
                                <width>55</width>
                                <font>-</font>
                                <texturefocus>OSDNextTrackFO.png</texturefocus>
                                <texturenofocus>OSDNextTrackNF.png</texturenofocus>
-                               <onleft>604</onleft>
-                               <onright>701</onright>
+                               <onleft>204</onleft>
+                               <onright>250</onright>
                                <onup>1000</onup>
                                <ondown>1000</ondown>
                                <onclick>PlayerControl(Next)</onclick>
                <control type="group" id="100">
                        <posx>325</posx>
                        <posy>60r</posy>
-                       <defaultcontrol always="true">601</defaultcontrol>
+                       <defaultcontrol always="true">301</defaultcontrol>
                        <animation effect="fade" time="200">VisibleChange</animation>
                        <visible>![Window.IsVisible(SliderDialog) | Window.IsVisible(OSDVideoSettings) | Window.IsVisible(OSDAudioSettings) | Window.IsVisible(VideoBookmarks) | Window.IsVisible(PVROSDChannels) | Window.IsVisible(PVROSDGuide)]</visible>
                        <visible>VideoPlayer.Content(LiveTV)</visible>
-                       <control type="button" id="600">
+                       <control type="button" id="300">
                                <posx>0</posx>
                                <posy>0</posy>
                                <width>55</width>
                                <font>-</font>
                                <texturefocus>OSDChannelUPFO.png</texturefocus>
                                <texturenofocus>OSDChannelUPNF.png</texturenofocus>
-                               <onleft>704</onleft>
-                               <onright>601</onright>
+                               <onleft>353</onleft>
+                               <onright>301</onright>
                                <onup>1000</onup>
                                <ondown>1000</ondown>
                                <onclick>PlayerControl(Previous)</onclick>
                        </control>
-                       <control type="button" id="601">
+                       <control type="button" id="301">
                                <posx>55</posx>
                                <posy>0</posy>
                                <width>55</width>
                                <font>-</font>
                                <texturefocus>OSDChannelDownFO.png</texturefocus>
                                <texturenofocus>OSDChannelDownNF.png</texturenofocus>
-                               <onleft>600</onleft>
-                               <onright>602</onright>
+                               <onleft>300</onleft>
+                               <onright>302</onright>
                                <onup>1000</onup>
                                <ondown>1000</ondown>
                                <onclick>PlayerControl(Next)</onclick>
                        </control>
-                       <control type="togglebutton" id="602">
+                       <control type="button" id="302">
                                <posx>110</posx>
                                <posy>0</posy>
                                <width>55</width>
                                <height>55</height>
+                               <label>31354</label>
+                               <font>-</font>
+                               <texturefocus>OSDRewindFO.png</texturefocus>
+                               <texturenofocus>OSDRewindNF.png</texturenofocus>
+                               <onleft>301</onleft>
+                               <onright>303</onright>
+                               <onup>1000</onup>
+                               <ondown>1000</ondown>
+                               <onclick>PlayerControl(Rewind)</onclick>
+                               <enable>Player.SeekEnabled</enable>
+                               <animation effect="fade" start="100" end="50" time="100" condition="!Player.SeekEnabled">Conditional</animation>
+                       </control>
+                       <control type="togglebutton" id="303">
+                               <posx>165</posx>
+                               <posy>0</posy>
+                               <width>55</width>
+                               <height>55</height>
                                <label>31351</label>
                                <altlabel>208</altlabel>
                                <font>-</font>
                                <usealttexture>Player.Paused | Player.Forwarding | Player.Rewinding</usealttexture>
                                <alttexturefocus>OSDPlayFO.png</alttexturefocus>
                                <alttexturenofocus>OSDPlayNF.png</alttexturenofocus>
-                               <onleft>601</onleft>
-                               <onright>603</onright>
+                               <onleft>302</onleft>
+                               <onright>304</onright>
                                <onup>1000</onup>
                                <ondown>1000</ondown>
                                <onclick>PlayerControl(Play)</onclick>
-                               <visible>False</visible>
+                               <enable>Player.PauseEnabled</enable>
+                               <animation effect="fade" start="100" end="50" time="100" condition="!Player.PauseEnabled">Conditional</animation>
                        </control>
-                       <control type="button" id="603">
-                               <posx>165</posx>
+                       <control type="button" id="304">
+                               <posx>220</posx>
                                <posy>0</posy>
                                <width>55</width>
                                <height>55</height>
                                <font>-</font>
                                <texturefocus>OSDStopFO.png</texturefocus>
                                <texturenofocus>OSDStopNF.png</texturenofocus>
-                               <onleft>602</onleft>
-                               <onright>604</onright>
+                               <onleft>303</onleft>
+                               <onright>305</onright>
                                <onup>1000</onup>
                                <ondown>1000</ondown>
                                <onclick>PlayerControl(Stop)</onclick>
                        </control>
-                       <control type="button" id="604">
-                               <posx>220</posx>
+                       <control type="button" id="305">
+                               <posx>275</posx>
+                               <posy>0</posy>
+                               <width>55</width>
+                               <height>55</height>
+                               <label>31353</label>
+                               <font>-</font>
+                               <texturefocus>OSDForwardFO.png</texturefocus>
+                               <texturenofocus>OSDForwardNF.png</texturenofocus>
+                               <onleft>304</onleft>
+                               <onright>306</onright>
+                               <onup>1000</onup>
+                               <ondown>1000</ondown>
+                               <onclick>PlayerControl(Forward)</onclick>
+                               <enable>Player.SeekEnabled</enable>
+                               <animation effect="fade" start="100" end="50" time="100" condition="!Player.SeekEnabled">Conditional</animation>
+                       </control>
+                       <control type="button" id="306">
+                               <posx>330</posx>
                                <posy>0</posy>
                                <width>55</width>
                                <height>55</height>
                                <font>-</font>
                                <texturefocus>OSDChannelListFO.png</texturefocus>
                                <texturenofocus>OSDChannelListNF.png</texturenofocus>
-                               <onleft>603</onleft>
-                               <onright>605</onright>
+                               <onleft>305</onleft>
+                               <onright>307</onright>
                                <onup>1000</onup>
                                <ondown>1000</ondown>
                                <onclick>ActivateWindow(PVROSDChannels)</onclick>
                                <onclick>Dialog.Close(VideoOSD)</onclick>
                        </control>
-                       <control type="button" id="605">
-                               <posx>275</posx>
+                       <control type="button" id="307">
+                               <posx>385</posx>
                                <posy>0</posy>
                                <width>55</width>
                                <height>55</height>
                                <font>-</font>
                                <texturefocus>OSDepgFO.png</texturefocus>
                                <texturenofocus>OSDepgNF.png</texturenofocus>
-                               <onleft>604</onleft>
-                               <onright>701</onright>
+                               <onleft>306</onleft>
+                               <onright>350</onright>
                                <onup>1000</onup>
                                <ondown>1000</ondown>
                                <onclick>ActivateWindow(PVROSDGuide)</onclick>
                                <onclick>Dialog.Close(VideoOSD)</onclick>
                        </control>
-                       <control type="label" id="606">
-                               <posx>330</posx>
+                       <control type="label" id="608">
+                               <posx>440</posx>
                                <posy>0</posy>
-                               <width>385</width>
+                               <width>275</width>
                                <height>55</height>
                                <label>$INFO[VideoPlayer.NextTitle,$LOCALIZE[209]: ]</label>
                                <align>center</align>
                        <animation effect="fade" time="200">VisibleChange</animation>
                        <visible>![Window.IsVisible(SliderDialog) | Window.IsVisible(OSDVideoSettings) | Window.IsVisible(OSDAudioSettings) | Window.IsVisible(VideoBookmarks)]</visible>
                        <visible>!VideoPlayer.Content(LiveTV)</visible>
-                       <control type="togglebutton" id="701">
+                       <control type="togglebutton" id="250">
                                <posx>0</posx>
                                <posy>0</posy>
                                <width>55</width>
                                <texturenofocus>OSDSubtitlesNF.png</texturenofocus>
                                <alttexturefocus>OSDSubtitlesFO.png</alttexturefocus>
                                <alttexturenofocus>OSDSubtitlesNF.png</alttexturenofocus>
-                               <onleft>605</onleft>
-                               <onright>702</onright>
+                               <onleft>205</onleft>
+                               <onright>251</onright>
                                <onup>1000</onup>
                                <ondown>1000</ondown>
                                <onclick>Close</onclick>
                                <altclick>XBMC.RunScript($INFO[Skin.String(SubtitleScript_Path)])</altclick>
                                <usealttexture>IsEmpty(Skin.String(SubtitleScript_Path))</usealttexture>
                        </control>
-                       <control type="button" id="702">
+                       <control type="button" id="251">
                                <posx>55</posx>
                                <posy>0</posy>
                                <width>55</width>
                                <font>-</font>
                                <texturefocus>OSDVideoFO.png</texturefocus>
                                <texturenofocus>OSDVideoNF.png</texturenofocus>
-                               <onleft>701</onleft>
-                               <onright>703</onright>
+                               <onleft>250</onleft>
+                               <onright>252</onright>
                                <onup>1000</onup>
                                <ondown>1000</ondown>
                                <onclick>ActivateWindow(OSDVideoSettings)</onclick>
                        </control>
-                       <control type="button" id="703">
+                       <control type="button" id="252">
                                <posx>110</posx>
                                <posy>0</posy>
                                <width>55</width>
                                <font>-</font>
                                <texturefocus>OSDAudioFO.png</texturefocus>
                                <texturenofocus>OSDAudioNF.png</texturenofocus>
-                               <onleft>702</onleft>
-                               <onright>704</onright>
+                               <onleft>251</onleft>
+                               <onright>253</onright>
                                <onup>1000</onup>
                                <ondown>1000</ondown>
                                <onclick>ActivateWindow(OSDAudioSettings)</onclick>
                        </control>
-                       <control type="button" id="704">
+                       <control type="button" id="253">
                                <posx>165</posx>
                                <posy>0</posy>
                                <width>55</width>
                                <font>-</font>
                                <texturefocus>OSDBookmarksFO.png</texturefocus>
                                <texturenofocus>OSDBookmarksNF.png</texturenofocus>
-                               <onleft>703</onleft>
-                               <onright>705</onright>
+                               <onleft>252</onleft>
+                               <onright>254</onright>
                                <onup>1000</onup>
                                <ondown>1000</ondown>
                                <onclick>ActivateWindow(VideoBookmarks)</onclick>
                        </control>
-                       <control type="button" id="705">
+                       <control type="button" id="254">
                                <posx>220</posx>
                                <posy>0</posy>
                                <width>55</width>
                                <font>-</font>
                                <texturefocus>OSDDvdFO.png</texturefocus>
                                <texturenofocus>OSDDvdNF.png</texturenofocus>
-                               <onleft>704</onleft>
-                               <onright>600</onright>
+                               <onleft>253</onleft>
+                               <onright>200</onright>
                                <onup>1000</onup>
                                <ondown>1000</ondown>
                                <onclick>PlayerControl(ShowVideoMenu)</onclick>
                        <animation effect="fade" time="200">VisibleChange</animation>
                        <visible>![Window.IsVisible(SliderDialog) | Window.IsVisible(OSDVideoSettings) | Window.IsVisible(OSDAudioSettings) | Window.IsVisible(VideoBookmarks) | Window.IsVisible(PVROSDChannels) | Window.IsVisible(PVROSDGuide)]</visible>
                        <visible>VideoPlayer.Content(LiveTV)</visible>
-                       <control type="button" id="701">
+                       <control type="button" id="350">
                                <posx>0</posx>
                                <posy>0</posy>
                                <width>55</width>
                                <font>-</font>
                                <texturefocus>OSDTeleTextFO.png</texturefocus>
                                <texturenofocus>OSDTeleTextNF.png</texturenofocus>
-                               <onleft>605</onleft>
-                               <onright>702</onright>
+                               <onleft>307</onleft>
+                               <onright>351</onright>
                                <onup>1000</onup>
                                <ondown>1000</ondown>
                                <onclick>ActivateWindow(Teletext)</onclick>
                        </control>
-                       <control type="button" id="702">
+                       <control type="button" id="351">
                                <posx>55</posx>
                                <posy>0</posy>
                                <width>55</width>
                                <font>-</font>
                                <texturefocus>OSDVideoFO.png</texturefocus>
                                <texturenofocus>OSDVideoNF.png</texturenofocus>
-                               <onleft>701</onleft>
-                               <onright>703</onright>
+                               <onleft>350</onleft>
+                               <onright>352</onright>
                                <onup>1000</onup>
                                <ondown>1000</ondown>
                                <onclick>ActivateWindow(OSDVideoSettings)</onclick>
                        </control>
-                       <control type="button" id="703">
+                       <control type="button" id="352">
                                <posx>110</posx>
                                <posy>0</posy>
                                <width>55</width>
                                <font>-</font>
                                <texturefocus>OSDAudioFO.png</texturefocus>
                                <texturenofocus>OSDAudioNF.png</texturenofocus>
-                               <onleft>702</onleft>
-                               <onright>704</onright>
+                               <onleft>351</onleft>
+                               <onright>353</onright>
                                <onup>1000</onup>
                                <ondown>1000</ondown>
                                <onclick>ActivateWindow(OSDAudioSettings)</onclick>
                        </control>
-                       <control type="togglebutton" id="704">
+                       <control type="togglebutton" id="353">
                                <posx>165</posx>
                                <posy>0</posy>
                                <width>55</width>
                                <usealttexture>Player.Recording</usealttexture>
                                <alttexturefocus>OSDRecordOnFO.png</alttexturefocus>
                                <alttexturenofocus>OSDRecordOnNF.png</alttexturenofocus>
-                               <onleft>703</onleft>
-                               <onright>600</onright>
+                               <onleft>352</onleft>
+                               <onright>300</onright>
                                <onup>1000</onup>
                                <ondown>1000</ondown>
                                <onclick>PlayerControl(Record)</onclick>
index 4fe2278..6728fa6 100644 (file)
@@ -15,7 +15,6 @@
                                <viewtype label="535">list</viewtype>
                                <pagecontrol>60</pagecontrol>
                                <scrolltime>200</scrolltime>
-                               <visible>![Window.IsVisible(VideoLibrary) + Container.Content(TVShows) + !Skin.HasSetting(TVShowsUsePosters)]</visible>
                                <itemlayout height="40" width="580">
                                        <control type="image">
                                                <posx>0</posx>
                                <pagecontrol>60</pagecontrol>
                                <scrolltime>200</scrolltime>
                                <preloaditems>2</preloaditems>
-                               <itemlayout condition="!Container.Content(Movies) + !Container.Content(Seasons) + [!Container.Content(TVShows) + !Skin.HasSetting(TVShowsUsePosters)]" height="186" width="216">
+                               <itemlayout condition="!Container.Content(Movies) + !Container.Content(Seasons) + !Container.Content(TVShows)" height="186" width="216">
                                        <control type="image">
                                                <posx>1</posx>
                                                <posy>0</posy>
                                                <texture>$INFO[ListItem.Overlay]</texture>
                                        </control>
                                </itemlayout>
-                               <focusedlayout condition="!Container.Content(Movies) + !Container.Content(Seasons) + [!Container.Content(TVShows) + !Skin.HasSetting(TVShowsUsePosters)]" height="186" width="216">
+                               <focusedlayout condition="!Container.Content(Movies) + !Container.Content(Seasons) + !Container.Content(TVShows)" height="186" width="216">
                                        <control type="image">
                                                <posx>1</posx>
                                                <posy>0</posy>
                                                <texture>$INFO[ListItem.Overlay]</texture>
                                        </control>
                                </focusedlayout>
-                               <itemlayout condition="Container.Content(Movies) | Container.Content(Seasons) | [Container.Content(TVShows) + Skin.HasSetting(TVShowsUsePosters)]" height="279" width="216">
+                               <itemlayout condition="Container.Content(Movies) | Container.Content(Seasons) | Container.Content(TVShows)" height="279" width="216">
                                        <control type="image">
                                                <posx>1</posx>
                                                <posy>0</posy>
                                                <texture>$INFO[ListItem.Overlay]</texture>
                                        </control>
                                </itemlayout>
-                               <focusedlayout condition="Container.Content(Movies) | Container.Content(Seasons) | [Container.Content(TVShows) + Skin.HasSetting(TVShowsUsePosters)]" height="276" width="216">
+                               <focusedlayout condition="Container.Content(Movies) | Container.Content(Seasons) | Container.Content(TVShows)" height="276" width="216">
                                        <control type="image">
                                                <posx>1</posx>
                                                <posy>0</posy>
                        <visible>Control.IsVisible(505)</visible>
                        <include>VisibleFadeEffect</include>
                        <control type="panel" id="505">
-                               <visible>!Container.Content(LiveTV) + !Container.Content(Movies) + !Container.Content(Episodes) + !Container.Content(Seasons) + !Container.Content(MusicVideos) + !Container.Content(Addons) + !Skin.HasSetting(TVShowsUsePosters)</visible>
+                               <visible>!Container.Content(LiveTV) + !Container.Content(Movies) + !Container.Content(Episodes) + !Container.Content(Seasons) + !Container.Content(MusicVideos) + !Container.Content(Addons)</visible>
                                <posx>95</posx>
                                <posy>80</posy>
                                <width>1080</width>
                                                <bordertexture border="5">button-nofocus.png</bordertexture>
                                                <bordersize>5</bordersize>
                                                <texture background="true">$INFO[Listitem.Icon]</texture>
+                                               <visible>IsEmpty(ListItem.Art(banner))</visible>
+                                       </control>
+                                       <control type="image">
+                                               <posx>1</posx>
+                                               <posy>0</posy>
+                                               <width>538</width>
+                                               <height>105</height>
+                                               <bordertexture border="5">button-nofocus.png</bordertexture>
+                                               <bordersize>5</bordersize>
+                                               <texture background="true">$INFO[Listitem.Art(banner)]</texture>
+                                               <visible>!IsEmpty(ListItem.Art(banner))</visible>
                                        </control>
                                        <control type="image">
                                                <posx>500</posx>
                                                <bordertexture border="5">folder-focus.png</bordertexture>
                                                <bordersize>5</bordersize>
                                                <texture background="true">$INFO[Listitem.Icon]</texture>
+                                               <visible>IsEmpty(ListItem.Art(banner))</visible>
+                                       </control>
+                                       <control type="image">
+                                               <posx>1</posx>
+                                               <posy>0</posy>
+                                               <width>538</width>
+                                               <height>105</height>
+                                               <bordertexture border="5">folder-focus.png</bordertexture>
+                                               <bordersize>5</bordersize>
+                                               <texture background="true">$INFO[Listitem.Art(banner)]</texture>
+                                               <visible>!IsEmpty(ListItem.Art(banner))</visible>
                                        </control>
                                        <control type="image">
                                                <posx>500</posx>
index c95c526..de6562f 100644 (file)
                                                <control type="textbox">
                                                        <description>Plot Value for TVShow</description>
                                                        <posx>50</posx>
-                                                       <posy>40</posy>
+                                                       <posy>35</posy>
                                                        <width>1000</width>
                                                        <height>60</height>
                                                        <font>font12</font>
index 803514b..d122022 100644 (file)
@@ -11,7 +11,7 @@
                        <usecontrolcoords>true</usecontrolcoords>
                        <include>VisibleFadeEffect</include>
                        <control type="fixedlist" id="501">
-                               <visible>Container.Content(Movies) | Container.Content(Seasons) | [Container.Content(TVShows) + Skin.HasSetting(TVShowsUsePosters)]</visible>
+                               <visible>Container.Content(Movies) | Container.Content(Seasons) | Container.Content(TVShows)</visible>
                                <visible>!Container.Content(LiveTV)</visible>
                                <posx>-183</posx>
                                <posy>0</posy>
                                                <bordertexture border="5">button-nofocus.png</bordertexture>
                                                <bordersize>4</bordersize>
                                                <texture background="true">$INFO[ListItem.Icon]</texture>
+                                               <visible>IsEmpty(ListItem.Art(poster))</visible>
+                                       </control>
+                                       <control type="image">
+                                               <posx>2</posx>
+                                               <posy>40</posy>
+                                               <width>214</width>
+                                               <height>310</height>
+                                               <aspectratio>stretch</aspectratio>
+                                               <bordertexture border="5">button-nofocus.png</bordertexture>
+                                               <bordersize>4</bordersize>
+                                               <texture background="true">$INFO[ListItem.Art(poster)]</texture>
+                                               <visible>!IsEmpty(ListItem.Art(poster))</visible>
                                        </control>
                                </itemlayout>
                                <focusedlayout height="310" width="218">
                                                <texture background="true">$INFO[ListItem.Icon]</texture>
                                                <animation reversible="false" effect="zoom" start="-2,36,222,318" end="-28,0,284,390" time="200">focus</animation>
                                                <animation reversible="false" effect="zoom" end="-2,36,222,318" start="-28,0,284,390" time="200">unfocus</animation>
+                                               <visible>!IsEmpty(ListItem.Art(poster))</visible>
+                                       </control>
+                                       <control type="image">
+                                               <posx>-2</posx>
+                                               <posy>36</posy>
+                                               <width>222</width>
+                                               <height>318</height>
+                                               <aspectratio>stretch</aspectratio>
+                                               <bordertexture border="8">ThumbBorder.png</bordertexture>
+                                               <bordersize>8</bordersize>
+                                               <texture background="true">$INFO[ListItem.Art(poster)]</texture>
+                                               <animation reversible="false" effect="zoom" start="-2,36,222,318" end="-28,0,284,390" time="200">focus</animation>
+                                               <animation reversible="false" effect="zoom" end="-2,36,222,318" start="-28,0,284,390" time="200">unfocus</animation>
+                                               <visible>IsEmpty(ListItem.Art(poster))</visible>
                                        </control>
                                        <control type="image">
                                                <posx>6</posx>
                        <posx>0</posx>
                        <posy>460</posy>
                        <control type="fixedlist" id="508">
-                               <visible>Container.Content(Movies) | [Container.Content(TVShows) + Skin.HasSetting(TVShowsUsePosters)]</visible>
+                               <visible>Container.Content(Movies) | Container.Content(TVShows)</visible>
                                <hitrect x="0" y="-10" w="1280" h="190" />
                                <posx>-20</posx>
                                <posy>0</posy>
                                                <bordersize>4</bordersize>
                                                <fadetime>200</fadetime>
                                                <texture background="true">$INFO[ListItem.Icon]</texture>
+                                               <visible>IsEmpty(ListItem.Art(poster))</visible>
+                                       </control>
+                                       <control type="image">
+                                               <posx>2</posx>
+                                               <posy>20</posy>
+                                               <width>120</width>
+                                               <height>160</height>
+                                               <aspectratio>stretch</aspectratio>
+                                               <bordertexture border="5">button-nofocus.png</bordertexture>
+                                               <bordersize>4</bordersize>
+                                               <fadetime>200</fadetime>
+                                               <texture background="true">$INFO[ListItem.art(poster)]</texture>
+                                               <visible>!IsEmpty(ListItem.Art(poster))</visible>
                                        </control>
                                        <control type="image">
                                                <posx>6</posx>
                                                <texture background="true">$INFO[ListItem.Icon]</texture>
                                                <animation reversible="false" effect="zoom" start="-2,16,128,168" end="-12,-10,148,198" time="200">focus</animation>
                                                <animation reversible="false" effect="zoom" end="-2,16,128,168" start="-12,-10,148,198" time="200">unfocus</animation>
+                                               <visible>IsEmpty(ListItem.Art(poster))</visible>
+                                       </control>
+                                       <control type="image">
+                                               <posx>-2</posx>
+                                               <posy>16</posy>
+                                               <width>128</width>
+                                               <height>168</height>
+                                               <aspectratio>stretch</aspectratio>
+                                               <bordertexture border="8">ThumbBorder.png</bordertexture>
+                                               <bordersize>8</bordersize>
+                                               <fadetime>200</fadetime>
+                                               <texture background="true">$INFO[ListItem.Art(poster)]</texture>
+                                               <animation reversible="false" effect="zoom" start="-2,16,128,168" end="-12,-10,148,198" time="200">focus</animation>
+                                               <animation reversible="false" effect="zoom" end="-2,16,128,168" start="-12,-10,148,198" time="200">unfocus</animation>
+                                               <visible>!IsEmpty(ListItem.Art(poster))</visible>
                                        </control>
                                        <control type="image">
                                                <posx>90</posx>
                        <control type="group">
                                <posx>710</posx>
                                <posy>245</posy>
-                               <visible>Container.Content(TVShows) + !Skin.HasSetting(TVShowsUsePosters)</visible>
+                               <visible>Container.Content(TVShows)</visible>
                                <control type="image">
                                        <posx>0</posx>
                                        <posy>0</posy>
                                        <texture background="true">$INFO[ListItem.Icon]</texture>
                                        <bordertexture border="8">ThumbShadow.png</bordertexture>
                                        <bordersize>8</bordersize>
+                                       <visible>IsEmpty(ListItem.Art(banner))</visible>
+                               </control>
+                               <control type="image">
+                                       <posx>0</posx>
+                                       <posy>0</posy>
+                                       <width>530</width>
+                                       <height>110</height>
+                                       <aspectratio>keep</aspectratio>
+                                       <fadetime>IconCrossfadeTime</fadetime>
+                                       <texture background="true">$INFO[ListItem.Art(banner)]</texture>
+                                       <bordertexture border="8">ThumbShadow.png</bordertexture>
+                                       <bordersize>8</bordersize>
+                                       <visible>!IsEmpty(ListItem.Art(banner))</visible>
                                </control>
                                <control type="label">
                                        <description>Episodes txt</description>
                        <control type="group">
                                <posx>710</posx>
                                <posy>245</posy>
-                               <visible>Container.Content(Seasons) | [Container.Content(TVShows) + Skin.HasSetting(TVShowsUsePosters)]</visible>
+                               <visible>Container.Content(Seasons)</visible>
                                <control type="image">
                                        <posx>0</posx>
                                        <posy>0</posy>
                                        <autoscroll time="2000" delay="3000" repeat="5000">Skin.HasSetting(AutoScroll)</autoscroll>
                                        <visible>Container.Content(Seasons)</visible>
                                </control>
-                               <control type="textbox">
-                                       <description>Description Value for TVShows</description>
-                                       <posx>270</posx>
-                                       <posy>0</posy>
-                                       <width>250</width>
-                                       <height>355</height>
-                                       <font>font12</font>
-                                       <align>justify</align>
-                                       <textcolor>white</textcolor>
-                                       <label>$INFO[ListItem.Plot]</label>
-                                       <autoscroll time="2000" delay="3000" repeat="5000">Skin.HasSetting(AutoScroll)</autoscroll>
-                                       <visible>Container.Content(TVShows) + Skin.HasSetting(TVShowsUsePosters)</visible>
-                               </control>
                                <control type="label">
                                        <description>Watched Count</description>
                                        <posx>10</posx>
                                        <height>286</height>
                                        <aspectratio>scale</aspectratio>
                                        <fadetime>IconCrossfadeTime</fadetime>
-                                       <texture background="true" fallback="Fanart_Fallback_Small.jpg" >$INFO[ListItem.Property(fanart_image)]</texture>
+                                       <texture background="true" fallback="Fanart_Fallback_Small.jpg" >$INFO[ListItem.Art(fanart)]</texture>
                                        <visible>Container.Content(Movies)</visible>
                                        <bordertexture background="true" border="8">ThumbShadow.png</bordertexture>
                                        <bordersize>8</bordersize>
                                        <height>325</height>
                                        <aspectratio>scale</aspectratio>
                                        <fadetime>IconCrossfadeTime</fadetime>
-                                       <texture background="true" fallback="Fanart_Fallback_Small.jpg" >$INFO[ListItem.Property(fanart_image)]</texture>
+                                       <texture background="true" fallback="Fanart_Fallback_Small.jpg" >$INFO[ListItem.Art(fanart)]</texture>
                                        <visible>Container.Content(TVShows)</visible>
                                        <bordertexture background="true" border="8">ThumbShadow.png</bordertexture>
                                        <bordersize>8</bordersize>
                                        <height>420</height>
                                        <aspectratio scalediffuse="false">scale</aspectratio>
                                        <fadetime>IconCrossfadeTime</fadetime>
-                                       <texture diffuse="Fanart_Diffuse.png" background="true" fallback="Fanart_Fallback_Small.jpg" >$INFO[ListItem.Property(fanart_image)]</texture>
+                                       <texture diffuse="Fanart_Diffuse.png" background="true" fallback="Fanart_Fallback_Small.jpg" >$INFO[ListItem.Art(fanart)]</texture>
                                </control>
                                <control type="label">
                                        <posx>10</posx>
                                        <height>420</height>
                                        <aspectratio scalediffuse="false">scale</aspectratio>
                                        <fadetime>IconCrossfadeTime</fadetime>
-                                       <texture diffuse="Fanart_Diffuse.png" background="true" fallback="Fanart_Fallback_Small.jpg" >$INFO[ListItem.Property(fanart_image)]</texture>
+                                       <texture diffuse="Fanart_Diffuse.png" background="true" fallback="Fanart_Fallback_Small.jpg" >$INFO[ListItem.Art(fanart)]</texture>
                                </control>
                                <control type="label">
                                        <posx>10</posx>
                                        <posy>395</posy>
-                                       <width>730</width>
+                                       <width>540</width>
                                        <height>30</height>
                                        <font>font24_title</font>
                                        <textcolor>white</textcolor>
                                        <description>Description Value for Video</description>
                                        <posx>10</posx>
                                        <posy>425</posy>
-                                       <width>730</width>
+                                       <width>540</width>
                                        <height>145</height>
                                        <font>font12</font>
                                        <align>justify</align>
                                        <label>$INFO[ListItem.Plot]</label>
                                        <autoscroll time="2000" delay="3000" repeat="5000">Skin.HasSetting(AutoScroll)</autoscroll>
                                </control>
+                               <control type="image">
+                                       <posx>560</posx>
+                                       <posy>140</posy>
+                                       <width>180</width>
+                                       <height>440</height>
+                                       <aspectratio align="left" aligny="bottom">keep</aspectratio>
+                                       <fadetime>IconCrossfadeTime</fadetime>
+                                       <texture background="true">$INFO[ListItem.Art(poster)]</texture>
+                                       <bordertexture border="8">ThumbShadow.png</bordertexture>
+                                       <bordersize>8</bordersize>
+                               </control>
                        </control>
                        <control type="group">
                                <posx>470</posx>
                                        <height>420</height>
                                        <aspectratio scalediffuse="false">scale</aspectratio>
                                        <fadetime>IconCrossfadeTime</fadetime>
-                                       <texture diffuse="Fanart_Diffuse.png" background="true" fallback="Fanart_Fallback_Small.jpg" >$INFO[ListItem.Property(fanart_image)]</texture>
+                                       <texture diffuse="Fanart_Diffuse.png" background="true" fallback="Fanart_Fallback_Small.jpg" >$INFO[ListItem.Art(fanart)]</texture>
                                </control>
                                <control type="label">
                                        <posx>10</posx>
                                        <height>420</height>
                                        <aspectratio scalediffuse="false">scale</aspectratio>
                                        <fadetime>IconCrossfadeTime</fadetime>
-                                       <texture diffuse="Fanart_Diffuse.png" background="true" fallback="Fanart_Fallback_Small.jpg" >$INFO[ListItem.Property(fanart_image)]</texture>
+                                       <texture diffuse="Fanart_Diffuse.png" background="true" fallback="Fanart_Fallback_Small.jpg" >$INFO[ListItem.Art(fanart)]</texture>
                                </control>
                                <control type="label">
                                        <posx>10</posx>
index f29e127..5422cc1 100644 (file)
                                                <align>left</align>
                                                <aligny>center</aligny>
                                        </control>
-                                       <control type="radiobutton" id="105">
-                                               <width>750</width>
-                                               <height>40</height>
-                                               <font>font13</font>
-                                               <label>31123</label>
-                                               <textcolor>grey2</textcolor>
-                                               <focusedcolor>white</focusedcolor>
-                                               <texturefocus>MenuItemFO.png</texturefocus>
-                                               <texturenofocus>MenuItemNF.png</texturenofocus>
-                                               <onclick>Skin.ToggleSetting(TVShowsUsePosters)</onclick>
-                                               <selected>Skin.HasSetting(TVShowsUsePosters)</selected>
-                                       </control>
                                        <control type="radiobutton" id="115">
                                                <width>750</width>
                                                <height>40</height>
index 6fa3b0c..34205c7 100644 (file)
@@ -29,7 +29,7 @@
                        <texture>black-back.png</texture>
                        <animation effect="fade" time="400">Visible</animation>
                        <animation effect="fade" time="200">Hidden</animation>
-                       <visible>Window.IsActive(MovieInformation) | Window.IsActive(MusicInformation) | Window.IsActive(SongInformation) | Window.IsActive(FileBrowser) | Window.IsActive(TextViewer) | Window.IsActive(AddonSettings) | Window.IsActive(ContentSettings) | Window.IsActive(SelectDialog) | Window.IsActive(FileStackingDialog) | Window.IsActive(MediaSource) | Window.IsActive(PictureInfo) | Window.IsActive(PlayerControls) | Window.IsActive(VirtualKeyboard) | Window.IsActive(NumericInput) | Window.IsActive(ProfileSettings) | Window.IsActive(LockSettings) | Window.IsActive(SmartPlaylistEditor) | Window.IsActive(SmartPlaylistRule) | Window.IsActive(script-RSS_Editor-rssEditor.xml) | Window.IsActive(script-RSS_Editor-setEditor.xml) | Window.IsActive(AddonInformation) | Window.IsActive(Peripherals) | Window.IsActive(PeripheralSettings) | Window.IsActive(script-XBMC_Lyrics-main.xml) | Window.IsActive(PVRChannelManager)</visible>
+                       <visible>Window.IsActive(MovieInformation) | Window.IsActive(MusicInformation) | Window.IsActive(SongInformation) | Window.IsActive(FileBrowser) | Window.IsActive(TextViewer) | Window.IsActive(AddonSettings) | Window.IsActive(ContentSettings) | Window.IsActive(SelectDialog) | Window.IsActive(FileStackingDialog) | Window.IsActive(MediaSource) | Window.IsActive(PictureInfo) | Window.IsActive(PlayerControls) | Window.IsActive(VirtualKeyboard) | Window.IsActive(NumericInput) | Window.IsActive(ProfileSettings) | Window.IsActive(LockSettings) | Window.IsActive(SmartPlaylistEditor) | Window.IsActive(SmartPlaylistRule) | Window.IsActive(script-RSS_Editor-rssEditor.xml) | Window.IsActive(script-RSS_Editor-setEditor.xml) | Window.IsActive(AddonInformation) | Window.IsActive(Peripherals) | Window.IsActive(PeripheralSettings) | Window.IsActive(script-XBMC_Lyrics-main.xml) | Window.IsActive(PVRChannelManager) | Window.IsActive(MediaFilter)</visible>
                </control>
        </include>
        <include name="WindowTitleCommons">
                                <scroll>false</scroll>
                                <align>right</align>
                                <aligny>center</aligny>
-                               <label>$INFO[Window.Property(filter),$LOCALIZE[587] ([COLOR=blue],[/COLOR]) - ]$INFO[Container.NumItems,([COLOR=blue],[/COLOR]) $LOCALIZE[31025]]$INFO[Container.CurrentPage, - $LOCALIZE[31024] ([COLOR=blue]]$INFO[Container.NumPages,/,[/COLOR])]</label>
+                               <label>$INFO[Container.NumItems,([COLOR=blue],[/COLOR]) $LOCALIZE[31025]]$INFO[Container.CurrentPage, - $LOCALIZE[31024] ([COLOR=blue]]$INFO[Container.NumPages,/,[/COLOR])]</label>
                                <include>Window_OpenClose_Animation</include>
                        </control>
                        <control type="label">
                                <onclick>down</onclick>
                                <onclick>XBMC.PlayerControl(Stop)</onclick>
                        </control>
-                       <control type="button" id="604">
+                       <control type="togglebutton" id="604">
+                               <posx>140</posx>
+                               <posy>2</posy>
+                               <width>39</width>
+                               <height>39</height>
+                               <label>-</label>
+                               <texturefocus>OSDPauseFO.png</texturefocus>
+                               <texturenofocus>OSDPauseNF.png</texturenofocus>
+                               <usealttexture>Player.Paused | Player.Forwarding | Player.Rewinding</usealttexture>
+                               <alttexturefocus>OSDPlayFO.png</alttexturefocus>
+                               <alttexturenofocus>OSDPlayNF.png</alttexturenofocus>
+                               <onleft>603</onleft>
+                               <onright>605</onright>
+                               <onup>610</onup>
+                               <ondown>606</ondown>
+                               <onback>50</onback>
+                               <onclick>XBMC.PlayerControl(Play)</onclick>
+                               <enable>Player.PauseEnabled</enable>
+                               <animation effect="fade" start="100" end="30" time="100" condition="!Player.PauseEnabled">Conditional</animation>
+                       </control>
+                       <control type="button" id="605">
                                <posx>180</posx>
                                <posy>2</posy>
                                <width>39</width>
                                <label>-</label>
                                <texturefocus>OSDRecordOffFO.png</texturefocus>
                                <texturenofocus>OSDRecordOffNF.png</texturenofocus>
-                               <onleft>603</onleft>
+                               <onleft>604</onleft>
                                <onright>50</onright>
                                <onup>610</onup>
                                <ondown>611</ondown>
index fae0ecc..e89eb6a 100644 (file)
@@ -248,10 +248,6 @@ msgctxt "#31122"
 msgid "Weather Page"
 msgstr ""
 
-msgctxt "#31123"
-msgid "Use \"Posters\" instead of \"Banners\" for TV Shows"
-msgstr ""
-
 msgctxt "#31124"
 msgid "Show Background \"Now Playing\" Video"
 msgstr ""
diff --git a/addons/skin.confluence/media/DefaultInProgressShows.png b/addons/skin.confluence/media/DefaultInProgressShows.png
new file mode 100644 (file)
index 0000000..b784784
Binary files /dev/null and b/addons/skin.confluence/media/DefaultInProgressShows.png differ
index 8412676..570ef40 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <addon
   id="webinterface.default"
-  version="2.0.6"
+  version="2.1.0"
   name="Default"
   provider-name="Team XBMC">
   <requires>
index c289b16..6b9e1d1 100644 (file)
Binary files a/addons/webinterface.default/icon.png and b/addons/webinterface.default/icon.png differ
index ef73da9..bbfd653 100644 (file)
Binary files a/addons/webinterface.default/images/DefaultAlbumCover.png and b/addons/webinterface.default/images/DefaultAlbumCover.png differ
index ce13c2a..1aa81a1 100644 (file)
Binary files a/addons/webinterface.default/images/DefaultVideo.png and b/addons/webinterface.default/images/DefaultVideo.png differ
index 767727a..628fbf6 100644 (file)
Binary files a/addons/webinterface.default/images/close-button.png and b/addons/webinterface.default/images/close-button.png differ
index f915659..8e10d59 100755 (executable)
Binary files a/addons/webinterface.default/images/remote.jpg and b/addons/webinterface.default/images/remote.jpg differ
index 7d2307c..9b3a7be 100755 (executable)
@@ -21,8 +21,6 @@
           <li id="movieLibrary">Movies</li>
           <li id="tvshowLibrary">TV Shows</li>
           <li id="musicLibrary">Music</li>
-          <!-- <li id="pictureLibrary">Pictures</li> TODO: needs pagination -->
-          <!-- <li id="settingsPanel">Settings</li> -->
         </ul>
       </div>
       <img src="images/ajax-loader.gif" alt="Loading please wait" id="spinner" style="display: none">
@@ -69,6 +67,6 @@
         <div id="nowPlayingPlaylist" style="display: none;"></div>
       </div>
     </div>
-    <script type="text/javascript" src="js/xbmc.launcher.js?v=2.0.6"></script>
+    <script type="text/javascript" src="js/xbmc.launcher.js?v=2.1.0"></script>
   </body>
 </html>
index 576833c..0d8faf6 100755 (executable)
@@ -30,7 +30,6 @@ MediaLibrary.prototype = {
     this.bindControls();
     this.getPlaylists();
   },
-
   bindControls: function() {
     $('#musicLibrary').click(jQuery.proxy(this.musicLibraryOpen, this));
     $('#movieLibrary').click(jQuery.proxy(this.movieLibraryOpen, this));
@@ -48,42 +47,26 @@ MediaLibrary.prototype = {
     $('#pictureLibrary').removeClass('selected');
     this.hideOverlay();
   },
-  replaceAll: function(haystack, find, replace) {
-    var parts = haystack.split(find);
-    var result = "";
-    var first = true;
-    for (index in parts)
-    {
-      if (!first)
-        result += replace;
-      else
-        first = false;
-
-      result += parts[index];
-    }
-
-    return result;
+  replaceAll: function(haystack, needle, thread) {
+    return (haystack || '').split(needle || '').join(thread || '');
   },
-
   getPlaylists: function() {
-    jQuery.ajax({
-      type: 'POST',
-      contentType: 'application/json',
-      url: xbmc.core.JSON_RPC + '?GetPlaylists',
-      data: '{"jsonrpc": "2.0", "method": "Playlist.GetPlaylists", "id": 1}',
-      timeout: 3000,
-      success: jQuery.proxy(function(data) {
+    xbmc.rpc.request({
+      'context': this,
+      'method': 'Playlist.GetPlaylists',
+      'timeout': 3000,
+      'success': function(data) {
         if (data && data.result && data.result.length > 0) {
           $.each($(data.result), jQuery.proxy(function(i, item) {
             this.playlists[item.type] = item.playlistid;
           }, this));
         }
-      }, this),
-      error: jQuery.proxy(function(data, error) {
+      },
+      'error': function(data, error) {
         xbmc.core.displayCommunicationError();
         setTimeout(jQuery.proxy(this.updateState, this), 2000);
-      }, this),
-      dataType: 'json'});
+      }
+    });
   },
   remoteControlOpen: function(event) {
     this.resetPage();
@@ -94,7 +77,7 @@ MediaLibrary.prototype = {
       $('#spinner').show();
       libraryContainer = $('<div>');
       libraryContainer.attr('id', 'remoteContainer')
-              .addClass('contentContainer');
+        .addClass('contentContainer');
       $('#content').append(libraryContainer);
       var keys=[
           {name:'up',width:'40px',height:'30px',top:'28px',left:'58px'}
@@ -126,12 +109,9 @@ MediaLibrary.prototype = {
           .css('width',keys[akey]['width'])
           .css('top',keys[akey]['top'])
           .css('left',keys[akey]['left'])
-          //.css('border','1px solid black')
           .bind('click',{key: keys[akey]['name']},jQuery.proxy(this.pressRemoteKey,this));
           libraryContainer.append(aremotekey);
       }
-
-
     } else {
       libraryContainer.show();
       libraryContainer.trigger('scroll');
@@ -139,280 +119,163 @@ MediaLibrary.prototype = {
 
     $('#spinner').hide();
   },
-
   pressRemoteKey: function(event) {
-    var keyPressed=event.data.key;
+    var player = -1,
+      keyPressed = event.data.key;
     $('#spinner').show();
-    var player = -1;
-    // TODO: Get active player
-    if($('#videoDescription').is(':visible'))
-      player = this.playlists["video"];
-    else if($('#audioDescription').is(':visible'))
-      player = this.playlists["audio"];
 
-    //common part
     switch(keyPressed) {
+      case 'up':
+        return xbmc.rpc.request({
+          'method': 'Input.Up'
+        });
+      case 'down':
+        return xbmc.rpc.request({
+          'method': 'Input.Down'
+        });
+      case 'left':
+        return xbmc.rpc.request({
+          'method': 'Input.Left'
+        });
+      case 'right':
+        return xbmc.rpc.request({
+          'method': 'Input.Right'
+        });
+      case 'ok':
+        return xbmc.rpc.request({
+          'method': 'Input.Select'
+        });
       case 'cleanlib_a':
-        jQuery.ajax({
-          type: 'POST',
-          contentType: 'application/json',
-          url: xbmc.core.JSON_RPC + '?SendRemoteKey',
-          data: '{"jsonrpc": "2.0", "method": "AudioLibrary.Clean", "id": 1}',
-          success: jQuery.proxy(function(data) {
-            $('#spinner').hide();
-          }, this),
-          dataType: 'json'});
-        return;
+        return xbmc.rpc.request({
+          'method': 'AudioLibrary.Clean'
+        });
       case 'updatelib_a':
-        jQuery.ajax({
-          type: 'POST',
-          contentType: 'application/json',
-          url: xbmc.core.JSON_RPC + '?SendRemoteKey',
-          data: '{"jsonrpc": "2.0", "method": "AudioLibrary.Scan", "id": 1}',
-          success: jQuery.proxy(function(data) {
-            $('#spinner').hide();
-          }, this),
-          dataType: 'json'});
-        return;
+        return xbmc.rpc.request({
+          'method': 'AudioLibrary.Scan'
+        });
       case 'cleanlib_v':
-        jQuery.ajax({
-          type: 'POST',
-          contentType: 'application/json',
-          url: xbmc.core.JSON_RPC + '?SendRemoteKey',
-          data: '{"jsonrpc": "2.0", "method": "VideoLibrary.Clean", "id": 1}',
-          success: jQuery.proxy(function(data) {
-            $('#spinner').hide();
-          }, this),
-          dataType: 'json'});
-        return;
+        return xbmc.rpc.request({
+          'method': 'VideoLibrary.Clean'
+        });
       case 'updatelib_v':
-        jQuery.ajax({
-          type: 'POST',
-          contentType: 'application/json',
-          url: xbmc.core.JSON_RPC + '?SendRemoteKey',
-          data: '{"jsonrpc": "2.0", "method": "VideoLibrary.Scan", "id": 1}',
-          success: jQuery.proxy(function(data) {
-            $('#spinner').hide();
-          }, this),
-          dataType: 'json'});
-        return;
+        return xbmc.rpc.request({
+          'method': 'VideoLibrary.Scan'
+        });
       case 'back':
-        jQuery.ajax({
-          type: 'POST',
-          contentType: 'application/json',
-          url: xbmc.core.JSON_RPC + '?SendRemoteKey',
-          data: '{"jsonrpc": "2.0", "method": "Input.Back", "id": 1}',
-          success: jQuery.proxy(function(data) {
-            $('#spinner').hide();
-          }, this),
-          dataType: 'json'});
-        return;
+        return xbmc.rpc.request({
+          'method': 'Input.Back'
+        });
       case 'home':
-        jQuery.ajax({
-          type: 'POST',
-          contentType: 'application/json',
-          url: xbmc.core.JSON_RPC + '?SendRemoteKey',
-          data: '{"jsonrpc": "2.0", "method": "Input.Home", "id": 1}',
-          success: jQuery.proxy(function(data) {
-            $('#spinner').hide();
-          }, this),
-          dataType: 'json'});
-        return;
+        return xbmc.rpc.request({
+          'method': 'Input.Home'
+        });
       case 'mute':
-        jQuery.ajax({
-          type: 'POST',
-          contentType: 'application/json',
-          url: xbmc.core.JSON_RPC + '?SendRemoteKey',
-          data: '{"jsonrpc": "2.0", "method": "Application.SetMute", "params": { "mute": "toggle" }, "id": 1}',
-          success: jQuery.proxy(function(data) {
-            $('#spinner').hide();
-          }, this),
-          dataType: 'json'});
-        return;
+        return xbmc.rpc.request({
+          'method': 'Application.SetMute',
+          'params': {
+            'mute': 'toggle'
+          }
+        });
       case 'power':
-        jQuery.ajax({
-          type: 'POST',
-          contentType: 'application/json',
-          url: xbmc.core.JSON_RPC + '?SendRemoteKey',
-          data: '{"jsonrpc": "2.0", "method": "System.Shutdown", "id": 1}',
-          success: jQuery.proxy(function(data) {
-            $('#spinner').hide();
-          }, this),
-          dataType: 'json'});
-        return;
+        return xbmc.rpc.request({
+          'method': 'System.Shutdown'
+        });
       case 'volumeup':
-        jQuery.ajax({
-          type: 'POST',
-          contentType: 'application/json',
-          url: xbmc.core.JSON_RPC + '?SendRemoteKey',
-          data: '{"jsonrpc": "2.0", "method": "Application.GetProperties", "params": { "properties": [ "volume" ] }, "id": 1}',
-          success: jQuery.proxy(function(data) {
+        return xbmc.rpc.request({
+          'method': 'Application.GetProperties',
+          'params': {
+            'properties': [
+              'volume'
+            ]
+          },
+          'success': function(data) {
             var volume = data.result.volume + 1;
-            jQuery.ajax({
-              type: 'POST',
-              contentType: 'application/json',
-              url: xbmc.core.JSON_RPC + '?SendRemoteKey',
-              data: '{"jsonrpc": "2.0", "method": "Application.SetVolume", "params": { "volume": '+volume+' }, "id": 1}',
-              success: jQuery.proxy(function(data) {
-                $('#spinner').hide();
-              }, this),
-              dataType: 'json'});
-          }, this),
-          dataType: 'json'});
-        return;
+            xbmc.rpc.request({
+              'method': 'Application.SetVolume',
+              'params': {
+                'volume': volume
+              }
+            });
+          }
+        });
       case 'volumedown':
-        jQuery.ajax({
-          type: 'POST',
-          contentType: 'application/json',
-          url: xbmc.core.JSON_RPC + '?SendRemoteKey',
-          data: '{"jsonrpc": "2.0", "method": "Application.GetProperties", "params": { "properties": [ "volume" ] }, "id": 1}',
-          success: jQuery.proxy(function(data) {
+        return xbmc.rpc.request({
+          'method': 'Application.GetProperties',
+          'params': {
+            'properties': [
+              'volume'
+            ]
+          },
+          'success': function(data) {
             var volume = data.result.volume - 1;
-            jQuery.ajax({
-              type: 'POST',
-              contentType: 'application/json',
-              url: xbmc.core.JSON_RPC + '?SendRemoteKey',
-              data: '{"jsonrpc": "2.0", "method": "Application.SetVolume", "params": { "volume": '+volume+' }, "id": 1}',
-              success: jQuery.proxy(function(data) {
-                $('#spinner').hide();
-              }, this),
-              dataType: 'json'});
-          }, this),
-          dataType: 'json'});
-        return;
+            xbmc.rpc.request({
+              'method': 'Application.SetVolume',
+              'params': {
+                'volume': volume
+              }
+            });
+          }
+        });
     }
 
-    switch(keyPressed) {
-      case 'up':
-        jQuery.ajax({
-          type: 'POST',
-          contentType: 'application/json',
-          url: xbmc.core.JSON_RPC + '?SendRemoteKey',
-          data: '{"jsonrpc": "2.0", "method": "Input.Up", "id": 1}',
-          success: jQuery.proxy(function(data) {
-            $('#spinner').hide();
-          }, this),
-          dataType: 'json'});
-        return;
-      case 'down':
-        jQuery.ajax({
-          type: 'POST',
-          contentType: 'application/json',
-          url: xbmc.core.JSON_RPC + '?SendRemoteKey',
-          data: '{"jsonrpc": "2.0", "method": "Input.Down", "id": 1}',
-          success: jQuery.proxy(function(data) {
-            $('#spinner').hide();
-          }, this),
-          dataType: 'json'});
-        return;
-      case 'left':
-        jQuery.ajax({
-          type: 'POST',
-          contentType: 'application/json',
-          url: xbmc.core.JSON_RPC + '?SendRemoteKey',
-          data: '{"jsonrpc": "2.0", "method": "Input.Left", "id": 1}',
-          success: jQuery.proxy(function(data) {
-            $('#spinner').hide();
-          }, this),
-          dataType: 'json'});
-        return;
-      case 'right':
-        jQuery.ajax({
-          type: 'POST',
-          contentType: 'application/json',
-          url: xbmc.core.JSON_RPC + '?SendRemoteKey',
-          data: '{"jsonrpc": "2.0", "method": "Input.Right", "id": 1}',
-          success: jQuery.proxy(function(data) {
-            $('#spinner').hide();
-          }, this),
-          dataType: 'json'});
-        return;
-      case 'ok':
-        jQuery.ajax({
-          type: 'POST',
-          contentType: 'application/json',
-          url: xbmc.core.JSON_RPC + '?SendRemoteKey',
-          data: '{"jsonrpc": "2.0", "method": "Input.Select", "id": 1}',
-          success: jQuery.proxy(function(data) {
-            $('#spinner').hide();
-          }, this),
-          dataType: 'json'});
-        return;
-    }
+    // TODO: Get active player
+    if($('#videoDescription').is(':visible'))
+      player = this.playlists["video"];
+    else if($('#audioDescription').is(':visible'))
+      player = this.playlists["audio"];
 
     if (player >= 0)
     {
       switch(keyPressed) {
         case 'playpause':
-          jQuery.ajax({
-            type: 'POST',
-            contentType: 'application/json',
-            url: xbmc.core.JSON_RPC + '?SendRemoteKey',
-            data: '{"jsonrpc": "2.0", "method": "Player.PlayPause", "params": { "playerid": ' + player + ' }, "id": 1}',
-            success: jQuery.proxy(function(data) {
-              $('#spinner').hide();
-            }, this),
-            dataType: 'json'});
-          return;
+          return xbmc.rpc.request({
+            'method': 'Player.PlayPause',
+            'params': {
+              'playerid': player
+            }
+          });
         case 'stop':
-          jQuery.ajax({
-            type: 'POST',
-            contentType: 'application/json',
-            url: xbmc.core.JSON_RPC + '?SendRemoteKey',
-            data: '{"jsonrpc": "2.0", "method": "Player.Stop", "params": { "playerid": ' + player + ' }, "id": 1}',
-            success: jQuery.proxy(function(data) {
-              $('#spinner').hide();
-            }, this),
-            dataType: 'json'});
-          return;
+          return xbmc.rpc.request({
+            'method': 'Player.Stop',
+            'params': {
+              'playerid': player
+            }
+          });
         case 'next':
-          jQuery.ajax({
-            type: 'POST',
-            contentType: 'application/json',
-            url: xbmc.core.JSON_RPC + '?SendRemoteKey',
-            data: '{"jsonrpc": "2.0", "method": "Player.GoTo", "params": { "playerid": ' + player + ', "to": "next" }, "id": 1}',
-            success: jQuery.proxy(function(data) {
-              $('#spinner').hide();
-            }, this),
-            dataType: 'json'});
-          return;
+          return xbmc.rpc.request({
+            'method': 'Player.GoTo',
+            'params': {
+              'playerid': player,
+              'to': 'next'
+            }
+          });
         case 'previous':
-          jQuery.ajax({
-            type: 'POST',
-            contentType: 'application/json',
-            url: xbmc.core.JSON_RPC + '?SendRemoteKey',
-            data: '{"jsonrpc": "2.0", "method": "Player.GoTo", "params": { "playerid": ' + player + ', "to": "previous" }, "id": 1}',
-            success: jQuery.proxy(function(data) {
-              $('#spinner').hide();
-            }, this),
-            dataType: 'json'});
-          return;
+          return xbmc.rpc.request({
+            'method': 'Player.GoTo',
+            'params': {
+              'playerid': player,
+              'to': 'previous'
+            }
+          });
         case 'forward':
-          jQuery.ajax({
-            type: 'POST',
-            contentType: 'application/json',
-            url: xbmc.core.JSON_RPC + '?SendRemoteKey',
-            data: '{"jsonrpc": "2.0", "method": "Player.SetSpeed", "params": { "playerid": ' + player + ', "speed": "increment" }, "id": 1}',
-            success: jQuery.proxy(function(data) {
-              $('#spinner').hide();
-            }, this),
-            dataType: 'json'});
-          return;
+          return xbmc.rpc.request({
+            'method': 'Player.SetSpeed',
+            'params': {
+              'playerid': player,
+              'speed': 'increment'
+            }
+          });
         case 'rewind':
-          jQuery.ajax({
-            type: 'POST',
-            contentType: 'application/json',
-            url: xbmc.core.JSON_RPC + '?SendRemoteKey',
-            data: '{"jsonrpc": "2.0", "method": "Player.SetSpeed", "params": { "playerid": ' + player + ', "speed": "decrement" }, "id": 1}',
-            success: jQuery.proxy(function(data) {
-              $('#spinner').hide();
-            }, this),
-            dataType: 'json'});
-          return;
+          return xbmc.rpc.request({
+            'method': 'Player.SetSpeed',
+            'params': {
+              'playerid': player,
+              'speed': 'decrement'
+            }
+          });
       }
     }
   },
-
   musicLibraryOpen: function(event) {
     this.resetPage();
     $('#musicLibrary').addClass('selected');
@@ -422,14 +285,34 @@ MediaLibrary.prototype = {
       $('#spinner').show();
       libraryContainer = $('<div>');
       libraryContainer.attr('id', 'libraryContainer')
-                      .addClass('contentContainer');
+        .addClass('contentContainer');
       $('#content').append(libraryContainer);
-      jQuery.ajax({
-        type: 'POST',
-        contentType: 'application/json',
-        url: xbmc.core.JSON_RPC + '?GetAlbums',
-        data: '{"jsonrpc": "2.0", "method": "AudioLibrary.GetAlbums", "params": { "limits": { "start": 0 }, "properties": ["description", "theme", "mood", "style", "type", "albumlabel", "artist", "genre", "rating", "title", "year", "thumbnail"], "sort": { "method": "artist" } }, "id": 1}',
-        success: jQuery.proxy(function(data) {
+      xbmc.rpc.request({
+        'context': this,
+        'method': 'AudioLibrary.GetAlbums',
+        'params': {
+          'limits': {
+            'start': 0
+          },
+          'properties': [
+            'description',
+            'theme',
+            'mood',
+            'style',
+            'type',
+            'albumlabel',
+            'artist',
+            'genre',
+            'rating',
+            'title',
+            'year',
+            'thumbnail'
+          ],
+          'sort': {
+            'method': 'artist'
+          }
+        },
+        'success': function(data) {
           if (data && data.result && data.result.albums) {
             this.albumList = data.result.albums;
             $.each($(this.albumList), jQuery.proxy(function(i, item) {
@@ -445,8 +328,8 @@ MediaLibrary.prototype = {
           } else {
             libraryContainer.html('');
           }
-        }, this),
-        dataType: 'json'});
+        }
+      });
     } else {
       libraryContainer.show();
       libraryContainer.trigger('scroll');
@@ -493,7 +376,6 @@ MediaLibrary.prototype = {
   },
   showAlbumSelectorBlock: function(album) {
     if (album) {
-      //Find album in stored array
       var prevAlbum = null,
         nextAlbum = null;
       $.each($(this.albumList), jQuery.proxy(function(i, item) {
@@ -509,7 +391,7 @@ MediaLibrary.prototype = {
       if (!albumSelectorBlock || albumSelectorBlock.length == 0) {
         albumSelectorBlock = $('<div>');
         albumSelectorBlock.attr('id', 'albumSelector')
-                  .html('<table><tr><td class="allAlbums">All Albums</td><td class="activeAlbumTitle"></td><td class="prevAlbum">&nbsp;</td><td class="nextAlbum">&nbsp;</td></tr></table>');
+          .html('<table><tr><td class="allAlbums">All Albums</td><td class="activeAlbumTitle"></td><td class="prevAlbum">&nbsp;</td><td class="nextAlbum">&nbsp;</td></tr></table>');
         $('#content').prepend(albumSelectorBlock);
         $('#albumSelector .allAlbums').bind('click', jQuery.proxy(this.hideAlbumDetails, this));
       }
@@ -535,17 +417,30 @@ MediaLibrary.prototype = {
     $('#topScrollFade').hide();
     if (!albumDetailsContainer || albumDetailsContainer.length == 0) {
       $('#spinner').show();
-      jQuery.ajax({
-        type: 'POST',
-        contentType: 'application/json',
-        url: xbmc.core.JSON_RPC + '?GetSongs',
-        data: '{"jsonrpc": "2.0", "method": "AudioLibrary.GetSongs", "params": { "properties": ["title", "artist", "genre", "track", "duration", "year", "rating", "playcount"], "filter": { "albumid" : ' + event.data.album.albumid + ' } }, "id": 1}',
-        success: jQuery.proxy(function(data) {
+      xbmc.rpc.request({
+        'context': this,
+        'method': 'AudioLibrary.GetSongs',
+        'params': {
+          'properties': [
+            'title',
+            'artist',
+            'genre',
+            'track',
+            'duration',
+            'year',
+            'rating',
+            'playcount'
+          ],
+          'filter': {
+            'albumid' : event.data.album.albumid
+          }
+        },
+        'success': function(data) {
           albumDetailsContainer = $('<div>');
           albumDetailsContainer.attr('id', 'albumDetails' + event.data.album.albumid)
-                     .addClass('contentContainer')
-                     .addClass('albumContainer')
-                     .html('<table class="albumView"><thead><tr class="headerRow"><th>Artwork</th><th>&nbsp;</th><th>Name</th><th class="time">Time</th><th>Artist</th><th>Genre</th></tr></thead><tbody class="resultSet"></tbody></table>');
+            .addClass('contentContainer')
+            .addClass('albumContainer')
+            .html('<table class="albumView"><thead><tr class="headerRow"><th>Artwork</th><th>&nbsp;</th><th>Name</th><th class="time">Time</th><th>Artist</th><th>Genre</th></tr></thead><tbody class="resultSet"></tbody></table>');
           $('.contentContainer').hide();
           $('#content').append(albumDetailsContainer);
           var albumThumbnail = event.data.album.thumbnail;
@@ -604,14 +499,13 @@ MediaLibrary.prototype = {
             .append($('<div>').addClass('footerPadding'));
           $('#spinner').hide();
           myScroll = new iScroll('albumDetails' + event.data.album.albumid);
-        }, this),
-        dataType: 'json'});
+        }
+      });
     } else {
       $('.contentContainer').hide();
       $('#albumDetails' + event.data.album.albumid).show();
     }
   },
-
   togglePosterView: function(event){
     var view=event.data.mode;
     var wthumblist,hthumblist,hthumbdetails;
@@ -633,7 +527,7 @@ MediaLibrary.prototype = {
         hthumbdetails='213px';
         $("#toggleLandscape").addClass('activeMode');
         break;
-      default: //set banner view as default
+      default:
         xbmc.core.setCookie('TVView','banner');
         wthumblist='379px';
         hthumblist='70px';
@@ -644,49 +538,45 @@ MediaLibrary.prototype = {
     $(".floatableTVShowCover, .floatableTVShowCover div.imgWrapper, .floatableTVShowCover img, .floatableTVShowCover div.imgWrapper div.inner").css('width',wthumblist).css('height',hthumblist);
     $(".floatableTVShowCoverSeason div.imgWrapper, .floatableTVShowCoverSeason div.imgWrapper div.inner,.floatableTVShowCoverSeason img, .floatableTVShowCoverSeason").css('height',hthumbdetails);
   },
-
   displayTVShowDetails: function(event) {
     var tvshowDetailsContainer = $('#tvShowDetails' + event.data.tvshow.tvshowid);
     $('#topScrollFade').hide();
     toggle=this.toggle.detach();
     if (!tvshowDetailsContainer || tvshowDetailsContainer.length == 0) {
       $('#spinner').show();
-      jQuery.ajax({
-        type: 'POST',
-        contentType: 'application/json',
-        url: xbmc.core.JSON_RPC + '?GetTVShowSeasons',
-        data: '{"jsonrpc": "2.0", "method": "VideoLibrary.GetSeasons", "params": { "properties": [ "season", "showtitle", "playcount", "episode", "thumbnail","fanart" ], "tvshowid" : ' + event.data.tvshow.tvshowid + ' }, "id": 1}',
-        success: jQuery.proxy(function(data) {
+      xbmc.rpc.request({
+        'context': this,
+        'method': 'VideoLibrary.GetSeasons',
+        'params': {
+          'properties': [
+            'season',
+            'showtitle',
+            'playcount',
+            'episode',
+            'thumbnail',
+            'fanart'
+          ],
+          'tvshowid' : event.data.tvshow.tvshowid
+        },
+        'success': function(data) {
           tvshowDetailsContainer = $('<div>');
           tvshowDetailsContainer.attr('id', 'tvShowDetails' + event.data.tvshow.tvshowid)
-                                .css('display', 'none')
-                                .addClass('contentContainer')
-                                .addClass('tvshowContainer');
+            .css('display', 'none')
+            .addClass('contentContainer')
+            .addClass('tvshowContainer');
           var showThumb = this.generateThumb('tvshowseason', event.data.tvshow.thumbnail, event.data.tvshow.title);
           if (data && data.result && data.result.seasons && data.result.seasons.length > 0) {
             var showDetails = $('<div>').addClass('showDetails');
             showDetails.append(toggle);
             showDetails.append($('<p>').html(data.result.seasons[0].showtitle).addClass('showTitle'));
             var seasonSelectionSelect = $('<select>').addClass('seasonPicker');
-            //var episodeCount = 0;
             this.tvActiveShowContainer = tvshowDetailsContainer;
-            //var fanart;
-            $.each($(data.result.seasons), jQuery.proxy(function(i, item) {
-  //              if(fanart==null && item.fanart!=null){
-  //                fanart=item.fanart;
-  //              }
-  //              //episodeCount += item.episode;
+            $.each($(data.result.seasons), function(i, item) {
               var season = $('<option>').attr('value',i);
               season.text(item.label);
               seasonSelectionSelect.append(season);
-
-            }, this));
-  //            if(fanart!=null)
-  //            {
-  //              $('.contentContainer').css('background','url("'+this.getThumbnailPath(fanart)+'")').css('background-size','cover');
-  //            }
+            });
             seasonSelectionSelect.bind('change', {tvshow: event.data.tvshow.tvshowid, seasons: data.result.seasons, element: seasonSelectionSelect}, jQuery.proxy(this.displaySeasonListings, this));
-            //showDetails.append($('<p>').html('<span class="heading">Episodes:</span> ' + episodeCount));
             showDetails.append(seasonSelectionSelect);
             tvshowDetailsContainer.append(showDetails);
             tvshowDetailsContainer.append(showThumb);
@@ -706,8 +596,8 @@ MediaLibrary.prototype = {
             tvshowDetailsContainer.fadeIn();
           }
           $('#spinner').hide();
-        }, this),
-        dataType: 'json'});
+        }
+      });
     } else {
       $('.contentContainer').hide();
       $('#tvShowDetails' + event.data.tvshow.tvshowid).show();
@@ -715,21 +605,26 @@ MediaLibrary.prototype = {
     }
   },
   displaySeasonListings: function(event) {
-    //retrieve selected season
     var selectedVal=event.data.element.val();
     var seasons=event.data.seasons;
     $('#topScrollFade').hide();
-    //Hide old listings
     var oldListings = $('.episodeListingsContainer', this.tvActiveShowContainer).fadeOut();
-    //Update ActiveSeason
     this.tvActiveSeason = selectedVal;
-    //Populate new listings
-    jQuery.ajax({
-      type: 'POST',
-      contentType: 'application/json',
-      url: xbmc.core.JSON_RPC + '?GetTVSeasonEpisodes',
-      data: '{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes", "params": { "properties": [ "title", "thumbnail","episode","plot","season"], "season" : ' + seasons[selectedVal].season + ', "tvshowid" : ' + event.data.tvshow + ' }, "id": 1}',
-      success: jQuery.proxy(function(data) {
+    xbmc.rpc.request({
+      'context': this,
+      'method': 'VideoLibrary.GetEpisodes',
+      'params': {
+        'properties': [
+          'title',
+          'thumbnail',
+          'episode',
+          'plot',
+          'season'
+        ],
+        'season': seasons[selectedVal].season,
+        'tvshowid': event.data.tvshow
+      },
+      'success': function(data) {
         var episodeListingsContainer = $('<div>').addClass('episodeListingsContainer');
         var episodeTable= $('<table>').addClass('seasonView').html('<thead><tr class="headerRow"><th class="thumbHeader">N&deg;</th><th>Title</th><th class="thumbHeader">Thumb</th><th class="thumbHeader">Details</th></tr></thead><tbody class="resultSet"></tbody>');
         $.each($(data.result.episodes), jQuery.proxy(function(i, item) {
@@ -745,10 +640,9 @@ MediaLibrary.prototype = {
         }, this));
         episodeListingsContainer.append(episodeTable);
         $(this.tvActiveShowContainer).append(episodeListingsContainer);
-      }, this),
-      dataType: 'json'});
+      }
+    });
   },
-
   displayEpisodeDetails: function(event) {
     var episodeDetails = $('<div>').attr('id', 'episode-' + event.data.episode.episodeid).addClass('episodePopoverContainer');
     episodeDetails.append($('<img>').attr('src', 'images/close-button.png').addClass('closeButton').bind('click', jQuery.proxy(this.hideOverlay, this)));
@@ -773,9 +667,6 @@ MediaLibrary.prototype = {
     if (event.data.episode.genre) {
       episodeDetails.append($('<p>').addClass('genre').html('<strong>Genre:</strong> ' + event.data.episode.genre));
     }
-    if (event.data.episode.rating) {
-      //Todo
-    }
     if (event.data.episode.director) {
       episodeDetails.append($('<p>').addClass('director').html('<strong>Directed By:</strong> ' + event.data.episode.director));
     }
@@ -784,17 +675,19 @@ MediaLibrary.prototype = {
     $('#overlay').show();
     this.updatePlayButtonLocation();
   },
-
   playTVShow: function(event) {
-    jQuery.ajax({
-      type: 'POST',
-      contentType: 'application/json',
-      url: xbmc.core.JSON_RPC + '?AddTvShowToPlaylist',
-      data: '{"jsonrpc": "2.0", "method": "Player.Open", "params": { "item": { "episodeid": ' + event.data.episode.episodeid + ' } }, "id": 1}',
-      success: jQuery.proxy(function(data) {
+    xbmc.rpc.request({
+      'context': this,
+      'method': 'Player.Open',
+      'params': {
+        'item': {
+          'episodeid': event.data.episode.episodeid
+        }
+      },
+      'success': function(data) {
         this.hideOverlay();
-      }, this),
-      dataType: 'json'});
+      }
+    });
   },
   hideOverlay: function(event) {
     if (this.activeCover) {
@@ -825,15 +718,18 @@ MediaLibrary.prototype = {
     }
   },
   playMovie: function(event) {
-    jQuery.ajax({
-      type: 'POST',
-      contentType: 'application/json',
-      url: xbmc.core.JSON_RPC + '?PlayMovie',
-      data: '{"jsonrpc": "2.0", "method": "Player.Open", "params": { "item": { "movieid": ' + event.data.movie.movieid + ' } }, "id": 1}',
-      success: jQuery.proxy(function(data) {
+    xbmc.rpc.request({
+      'context': this,
+      'method': 'Player.Open',
+      'params': {
+        'item': {
+          'movieid': event.data.movie.movieid
+        }
+      },
+      'success': function(data) {
         this.hideOverlay();
-      }, this),
-      dataType: 'json'});
+      }
+    });
   },
   displayMovieDetails: function(event) {
     var movieDetails = $('<div>').attr('id', 'movie-' + event.data.movie.movieid).addClass('moviePopoverContainer');
@@ -853,9 +749,6 @@ MediaLibrary.prototype = {
     if (event.data.movie.genre) {
       movieDetails.append($('<p>').addClass('genre').html('<strong>Genre:</strong> ' + event.data.movie.genre));
     }
-    if (event.data.movie.rating) {
-      //Todo
-    }
     if (event.data.movie.director) {
       movieDetails.append($('<p>').addClass('director').html('<strong>Directed By:</strong> ' + event.data.movie.director));
     }
@@ -865,32 +758,37 @@ MediaLibrary.prototype = {
     this.updatePlayButtonLocation();
   },
   playTrack: function(event) {
-    jQuery.ajax({
-      type: 'POST',
-      contentType: 'application/json',
-      url: xbmc.core.JSON_RPC + '?ClearPlaylist',
-      data: '{"jsonrpc": "2.0", "method": "Playlist.Clear", "params": { "playlistid": ' + this.playlists["audio"] + ' }, "id": 1}',
-      success: jQuery.proxy(function(data) {
-        //check that clear worked.
-        jQuery.ajax({
-          type: 'POST',
-          contentType: 'application/json',
-          url: xbmc.core.JSON_RPC + '?AddAlbumToPlaylist',
-          data: '{"jsonrpc": "2.0", "method": "Playlist.Add", "params": { "playlistid": ' + this.playlists["audio"] + ', "item": { "albumid": ' + event.data.album.albumid + ' } }, "id": 1}',
-          success: jQuery.proxy(function(data) {
-            //play specific song in playlist
-            jQuery.ajax({
-              type: 'POST',
-              contentType: 'application/json',
-              url: xbmc.core.JSON_RPC + '?PlaylistItemPlay',
-              data: '{"jsonrpc": "2.0", "method": "Player.Open", "params": { "item": { "playlistid": ' + this.playlists["audio"] + ', "position": '+ event.data.itmnbr + ' } }, "id": 1}',
-              success: jQuery.proxy(function(data) {
-              }, this),
-              dataType: 'json'});
-          }, this),
-          dataType: 'json'});
-      }, this),
-      dataType: 'json'});
+    xbmc.rpc.request({
+      'context': this,
+      'method': 'Playlist.Clear',
+      'params': {
+        'playlistid': this.playlists["audio"]
+      },
+      'success': function(data) {
+        xbmc.rpc.request({
+          'context': this,
+          'method': 'Playlist.Add',
+          'params': {
+            'playlistid': this.playlists["audio"],
+            'item': {
+              'albumid': event.data.album.albumid
+            }
+          },
+          'success': function(data) {
+            xbmc.rpc.request({
+              'method': 'Player.Open',
+              'params': {
+                'item': {
+                  'playlistid': this.playlists["audio"],
+                  'position': event.data.itmnbr
+                }
+              },
+              'success': function() {}
+            });
+          }
+        });
+      }
+    });
   },
   movieLibraryOpen: function() {
     this.resetPage();
@@ -899,12 +797,36 @@ MediaLibrary.prototype = {
     var libraryContainer = $('#movieLibraryContainer');
     if (!libraryContainer || libraryContainer.length == 0) {
       $('#spinner').show();
-      jQuery.ajax({
-        type: 'POST',
-        contentType: 'application/json',
-        url: xbmc.core.JSON_RPC + '?GetMovies',
-        data: '{"jsonrpc": "2.0", "method": "VideoLibrary.GetMovies", "params": { "limits": { "start": 0 }, "properties": [ "genre", "director", "trailer", "tagline", "plot", "plotoutline", "title", "originaltitle", "lastplayed", "runtime", "year", "playcount", "rating", "thumbnail", "file" ], "sort": { "method": "sorttitle", "ignorearticle": true } }, "id": 1}',
-        success: jQuery.proxy(function(data) {
+      xbmc.rpc.request({
+        'context': this,
+        'method': 'VideoLibrary.GetMovies',
+        'params': {
+          'limits': {
+            'start': 0
+          },
+          'properties': [
+            'genre',
+            'director',
+            'trailer',
+            'tagline',
+            'plot',
+            'plotoutline',
+            'title',
+            'originaltitle',
+            'lastplayed',
+            'runtime',
+            'year',
+            'playcount',
+            'rating',
+            'thumbnail',
+            'file'
+          ],
+          'sort': {
+            'method': 'sorttitle',
+            'ignorearticle': true
+          }
+        },
+        'success': function(data) {
           if (data && data.result && data.result.movies) {
               libraryContainer = $('<div>');
               libraryContainer.attr('id', 'movieLibraryContainer')
@@ -913,7 +835,6 @@ MediaLibrary.prototype = {
           } else {
             libraryContainer.html('');
           }
-          //data.result.movies.sort(jQuery.proxy(this.movieTitleSorter, this));
           $.each($(data.result.movies), jQuery.proxy(function(i, item) {
             var floatableMovieCover = this.generateThumb('movie', item.thumbnail, item.title);
             floatableMovieCover.bind('click', { movie: item }, jQuery.proxy(this.displayMovieDetails, this));
@@ -923,10 +844,9 @@ MediaLibrary.prototype = {
           $('#spinner').hide();
           libraryContainer.bind('scroll', { activeLibrary: libraryContainer }, jQuery.proxy(this.updateScrollEffects, this));
           libraryContainer.trigger('scroll');
-          //$('#libraryContainer img').lazyload();
           myScroll = new iScroll('movieLibraryContainer');
-        }, this),
-        dataType: 'json'});
+        }
+      });
     } else {
       libraryContainer.show();
       libraryContainer.trigger('scroll');
@@ -942,31 +862,45 @@ MediaLibrary.prototype = {
       toggle=$('<p>').addClass('toggle');
       togglePoster= $('<span>Poster</span>');
       togglePoster.attr('id', 'togglePoster')
-            .css('cursor','pointer')
-            .bind('click',{mode: 'poster'},jQuery.proxy(this.togglePosterView,this));
+        .css('cursor','pointer')
+        .bind('click',{mode: 'poster'},jQuery.proxy(this.togglePosterView,this));
       toggleBanner= $('<span>Banner</span>');
       toggleBanner.attr('id', 'toggleBanner')
-            .css('cursor','pointer')
-            .addClass('activeMode')
-            .bind('click',{mode: 'banner'},jQuery.proxy(this.togglePosterView,this));
+        .css('cursor','pointer')
+        .addClass('activeMode')
+        .bind('click',{mode: 'banner'},jQuery.proxy(this.togglePosterView,this));
       toggleLandscape= $('<span>Landscape</span>');
       toggleLandscape.attr('id', 'toggleLandscape')
-            .css('cursor','pointer')
-            .bind('click',{mode: 'landscape'},jQuery.proxy(this.togglePosterView,this));
+        .css('cursor','pointer')
+        .bind('click',{mode: 'landscape'},jQuery.proxy(this.togglePosterView,this));
       toggle.append(toggleBanner).append(' | ').append(togglePoster).append(' | ').append(toggleLandscape);
       this.toggle=toggle;
-      jQuery.ajax({
-        type: 'POST',
-        contentType: 'application/json',
-        url: xbmc.core.JSON_RPC + '?GetTVShows',
-        data: '{"jsonrpc": "2.0", "method": "VideoLibrary.GetTVShows", "params": { "properties": ["genre", "plot", "title", "lastplayed", "episode", "year", "playcount", "rating", "thumbnail", "studio", "mpaa", "premiered"] }, "id": 1}',
-        success: jQuery.proxy(function(data) {
+      xbmc.rpc.request({
+        'context': this,
+        'method': 'VideoLibrary.GetTVShows',
+        'params': {
+          'properties': [
+            'genre',
+            'plot',
+            'title',
+            'lastplayed',
+            'episode',
+            'year',
+            'playcount',
+            'rating',
+            'thumbnail',
+            'studio',
+            'mpaa',
+            'premiered'
+          ]
+        },
+        'success': function(data) {
           if (data && data.result && data.result.tvshows) {
-              libraryContainer = $('<div>');
-              libraryContainer.append(toggle);
-              libraryContainer.attr('id', 'tvshowLibraryContainer')
-                      .addClass('contentContainer');
-              $('#content').append(libraryContainer);
+            libraryContainer = $('<div>');
+            libraryContainer.append(toggle);
+            libraryContainer.attr('id', 'tvshowLibraryContainer')
+              .addClass('contentContainer');
+            $('#content').append(libraryContainer);
           } else {
             libraryContainer.html('');
           }
@@ -991,13 +925,12 @@ MediaLibrary.prototype = {
                 break;
             }
           }
-        }, this),
-        dataType: 'json'});
+        }
+      });
     } else {
       libraryContainer.prepend($(".toggle").detach()).show();
       libraryContainer.trigger('scroll');
     }
-
   },
   updateScrollEffects: function(event) {
     if (event.data.activeLibrary && $(event.data.activeLibrary).scrollTop() > 0) {
@@ -1007,14 +940,17 @@ MediaLibrary.prototype = {
     }
   },
   startSlideshow: function(event) {
-    jQuery.ajax({
-      type: 'POST',
-      contentType: 'application/json',
-      url: xbmc.core.JSON_RPC + '?StartSlideshow',
-      data: '{"jsonrpc": "2.0", "method": "Player.Open", "params": { "item": { "recursive" : "true", "random": "true", "path" : "' + this.replaceAll(event.data.directory.file, "\\", "\\\\") + '" } }, "id": 1}',
-      success: jQuery.proxy(function(data) {
-      }, this),
-      dataType: 'json'});
+    xbmc.rpc.request({
+      'method': 'Player.Open',
+      'params': {
+        'item': {
+          'recursive': 'true',
+          'random': 'true',
+          'path' : this.replaceAll(event.data.directory.file, "\\", "\\\\")
+        }
+      },
+      'success': function() {}
+    });
   },
   showDirectory: function(event) {
     var directory = event.data.directory.file;
@@ -1025,16 +961,18 @@ MediaLibrary.prototype = {
     var libraryContainer = $('#pictureLibraryDirContainer' + directory);
     if (!libraryContainer || libraryContainer.length == 0) {
       $('#spinner').show();
-      jQuery.ajax({
-        type: 'POST',
-        contentType: 'application/json',
-        url: xbmc.core.JSON_RPC + '?GetDirectory',
-        data: '{"jsonrpc": "2.0", "method": "Files.GetDirectory", "params": { "media" : "pictures", "directory": "' + jsonDirectory + '" }, "id": 1}',
-        success: jQuery.proxy(function(data) {
+      xbmc.rpc.request({
+        'context': this,
+        'method': 'Files.GetDirectory',
+        'params': {
+          'media' : 'pictures',
+          'directory': jsonDirectory
+        },
+        'success': function(data) {
           if (data && data.result && ( data.result.directories || data.result.files )) {
             libraryContainer = $('<div>');
             libraryContainer.attr('id', 'pictureLibraryDirContainer' + directory)
-                    .addClass('contentContainer');
+              .addClass('contentContainer');
             $('#content').append(libraryContainer);
             var breadcrumb = $('<div>');
             var seperator = '/';
@@ -1043,7 +981,6 @@ MediaLibrary.prototype = {
             jQuery.each(directoryArray, function(i,v) {
               if(v != '') {
                 item += v + seperator;
-                //tmp.bind('click', { directory: item }, jQuery.proxy(this.showDirectory, this));
                 breadcrumb.append($('<div>').text(' > ' + v).css('float','left').addClass('breadcrumb'));
               }
             });
@@ -1060,10 +997,6 @@ MediaLibrary.prototype = {
                 {
                   var floatableShare = this.generateThumb('directory', item.thumbnail, item.label);
                   floatableShare.bind('click', { directory: item }, jQuery.proxy(this.showDirectory, this));
-                  //var slideshow = $('<div">');
-                  //slideshow.html('<div>Slideshow</div>');
-                  //slideshow.bind('click', { directory: item }, jQuery.proxy(this.startSlideshow, this));
-                  //floatableShare.append(slideshow);
                   libraryContainer.append(floatableShare);
                 }
               }, this));
@@ -1076,8 +1009,8 @@ MediaLibrary.prototype = {
           libraryContainer.bind('scroll', { activeLibrary: libraryContainer }, jQuery.proxy(this.updateScrollEffects, this));
           libraryContainer.trigger('scroll');
           myScroll = new iScroll('#pictureLibraryDirContainer' + directory);
-        }, this),
-        dataType: 'json'});
+        }
+      });
     } else {
       libraryContainer.show();
       libraryContainer.trigger('scroll');
@@ -1090,16 +1023,17 @@ MediaLibrary.prototype = {
     var libraryContainer = $('#pictureLibraryContainer');
     if (!libraryContainer || libraryContainer.length == 0) {
       $('#spinner').show();
-      jQuery.ajax({
-        type: 'POST',
-        contentType: 'application/json',
-        url: xbmc.core.JSON_RPC + '?GetSources',
-        data: '{"jsonrpc": "2.0", "method": "Files.GetSources", "params": { "media" : "pictures" }, "id": 1}',
-        success: jQuery.proxy(function(data) {
+      xbmc.rpc.request({
+        'context': this,
+        'method': 'Files.GetSources',
+        'params': {
+          'media' : 'pictures'
+        },
+        'success': function(data) {
           if (data && data.result && data.result.shares) {
             libraryContainer = $('<div>');
             libraryContainer.attr('id', 'pictureLibraryContainer')
-                            .addClass('contentContainer');
+              .addClass('contentContainer');
             $('#content').append(libraryContainer);
           } else {
             libraryContainer.html('');
@@ -1114,11 +1048,11 @@ MediaLibrary.prototype = {
           libraryContainer.bind('scroll', { activeLibrary: libraryContainer }, jQuery.proxy(this.updateScrollEffects, this));
           libraryContainer.trigger('scroll');
           myScroll = new iScroll('#pictureLibraryContainer');
-        }, this),
-        dataType: 'json'});
+        }
+      });
     } else {
       libraryContainer.show();
       libraryContainer.trigger('scroll');
     }
   }
-}
\ No newline at end of file
+}
index 0a6dfdc..4ee8f54 100755 (executable)
@@ -41,13 +41,11 @@ NowPlayingManager.prototype = {
     $(window).bind('click', jQuery.proxy(this.hidePlaylist, this));
   },
   updateState: function() {
-    jQuery.ajax({
-      type: 'POST',
-      contentType: 'application/json',
-      url: xbmc.core.JSON_RPC + '?UpdateState',
-      data: '{"jsonrpc": "2.0", "method": "Player.GetActivePlayers", "id": 1}',
-      timeout: 3000,
-      success: jQuery.proxy(function(data) {
+    xbmc.rpc.request({
+      'context': this,
+      'method': 'Player.GetActivePlayers',
+      'timeout': 3000,
+      'success': function(data) {
         if (data && data.result && data.result.length > 0) {
           if (data.result[0].playerid != this.activePlayerId) {
             this.activePlayerId = data.result[0].playerid;
@@ -71,11 +69,10 @@ NowPlayingManager.prototype = {
             }
 
             this.stopRefreshTime();
-
             this.updatePlayer();
           }
         }
-        else if (data.result.length <= 0)
+        else if (!data || !data.result || data.result.length <= 0)
         {
           this.stopVideoPlaylistUpdate();
           this.stopAudioPlaylistUpdate();
@@ -83,28 +80,36 @@ NowPlayingManager.prototype = {
           this.activePlayerId = -1;
         }
 
-        if (this.activePlayerId >= 0)
+        if (this.activePlayerId >= 0) {
           this.showFooter();
-        else {
+        else {
           this.stopRefreshTime();
           this.hideFooter();
         }
 
         setTimeout(jQuery.proxy(this.updateState, this), 1000);
-      }, this),
-      error: jQuery.proxy(function(data, error) {
+      },
+      'error': function(data, error) {
         xbmc.core.displayCommunicationError();
         setTimeout(jQuery.proxy(this.updateState, this), 2000);
-      }, this),
-      dataType: 'json'});
+      }
+    });
   },
   updatePlayer: function() {
-    jQuery.ajax({
-      type: 'POST',
-      contentType: 'application/json',
-      url: xbmc.core.JSON_RPC + '?UpdatePlayer',
-      data: '{"jsonrpc": "2.0", "method": "Player.GetProperties", "params": { "playerid": ' + this.activePlayerId + ', "properties": [ "playlistid", "speed", "position", "totaltime", "time" ] }, "id": 1}',
-      success: jQuery.proxy(function(data) {
+    xbmc.rpc.request({
+      'context': this,
+      'method': 'Player.GetProperties',
+      'params': {
+        'playerid': this.activePlayerId,
+        'properties': [
+          'playlistid',
+          'speed',
+          'position',
+          'totaltime',
+          'time'
+        ]
+      },
+      'success': function(data) {
         if (data && data.result)
         {
           this.playlistid = data.result.playlistid;
@@ -127,8 +132,8 @@ NowPlayingManager.prototype = {
           this.activeItemTimer = 1;
           setTimeout(jQuery.proxy(this.updateActiveItemDurationLoop, this), 1000);
         }
-      }, this),
-      dataType: 'json'});
+      }
+    });
   },
   bindPlaybackControls: function() {
     $('#pbNext').bind('click', jQuery.proxy(this.nextTrack, this));
@@ -157,42 +162,37 @@ NowPlayingManager.prototype = {
   },
   nextTrack: function() {
     if (this.activePlayer) {
-      jQuery.ajax({
-        type: 'POST',
-        contentType: 'application/json',
-        url: xbmc.core.JSON_RPC + '?SkipNext',
-        data: '{"jsonrpc": "2.0", "method": "Player.GoTo", "params": { "playerid": ' + this.activePlayerId + ', "to": "next" }, "id": 1}',
-        success: jQuery.proxy(function(data) {
-          if (data && data.result == 'OK') {
-            //this.updateAudioPlaylist(true);
-          }
-        }, this),
-        dataType: 'json'});
+      xbmc.rpc.request({
+        'method': 'Player.GoTo',
+        'params': {
+          'playerid': this.activePlayerId,
+          'to': 'next'
+        },
+        'success': function() {}
+      });
     }
   },
   prevTrack: function() {
     if (this.activePlayer) {
-      jQuery.ajax({
-        type: 'POST',
-        contentType: 'application/json',
-        url: xbmc.core.JSON_RPC + '?SkipPrevious',
-        data: '{"jsonrpc": "2.0", "method": "Player.GoTo", "params": { "playerid": ' + this.activePlayerId + ', "to": "previous" }, "id": 1}',
-        success: jQuery.proxy(function(data) {
-          if (data && data.result == 'OK') {
-            //this.updateAudioPlaylist(true);
-          }
-        }, this),
-        dataType: 'json'});
+      xbmc.rpc.request({
+        'method': 'Player.GoTo',
+        'params': {
+          'playerid': this.activePlayerId,
+          'to': 'previous'
+        },
+        'success': function() {}
+      });
     }
   },
   stopTrack: function() {
     if (this.activePlayer) {
-      jQuery.ajax({
-        type: 'POST',
-        contentType: 'application/json',
-        url: xbmc.core.JSON_RPC + '?Stop',
-        data: '{"jsonrpc": "2.0", "method": "Player.Stop", "params": { "playerid": ' + this.activePlayerId + ' }, "id": 1}',
-        success: jQuery.proxy(function(data) {
+      xbmc.rpc.request({
+        'context': this,
+        'method': 'Player.Stop',
+        'params': {
+          'playerid': this.activePlayerId
+        },
+        'success': function(data) {
           if (data && data.result == 'OK') {
             this.playing = false;
             this.paused = false;
@@ -200,19 +200,20 @@ NowPlayingManager.prototype = {
             this.trackDurationTime = 0;
             this.showPlayButton();
           }
-        }, this),
-        dataType: 'json'});
+        }
+      });
     }
   },
   playPauseTrack: function() {
     if (this.activePlayer) {
       var method = ((this.playing || this.paused) ? 'Player.PlayPause' : 'Playlist.Play');
-      jQuery.ajax({
-        type: 'POST',
-        contentType: 'application/json',
-        url: xbmc.core.JSON_RPC + '?PlayPause',
-        data: '{"jsonrpc": "2.0", "method": "' + method + '", "params": { "playerid": ' + this.activePlayerId + ' }, "id": 1}',
-        success: jQuery.proxy(function(data) {
+      xbmc.rpc.request({
+        'context': this,
+        'method': method, 
+        'params': {
+          'playerid': this.activePlayerId
+        },
+        'success': function(data) {
           if (data && data.result) {
             this.playing = data.result.speed != 0;
             this.paused = data.result.speed == 0;
@@ -222,8 +223,8 @@ NowPlayingManager.prototype = {
               this.showPlayButton();
             }
           }
-        }, this),
-        dataType: 'json'});
+        }
+      });
     }
   },
   showPauseButton: function() {
@@ -249,15 +250,14 @@ NowPlayingManager.prototype = {
   playPlaylistItem: function(sender) {
     var sequenceId = $(sender.currentTarget).attr('seq');
     if (!this.activePlaylistItem || (this.activePlaylistItem !== undefined && sequenceId != this.activePlaylistItem.seq)) {
-      jQuery.ajax({
-      type: 'POST',
-      contentType: 'application/json',
-      url: xbmc.core.JSON_RPC + '?PlaylistItemPlay',
-      data: '{"jsonrpc": "2.0", "method": "Player.GoTo", "params": { "playerid": ' + this.activePlayerId + ', "to": ' + sequenceId + '}, "id": 1}',
-      success: jQuery.proxy(function(data) {
-      
-      }, this),
-      dataType: 'json'});
+      xbmc.rpc.request({
+        'method': 'Player.GoTo',
+        'params': {
+          'playerid': this.activePlayerId,
+          'to': sequenceId
+        },
+        'success': function() {}
+      });
     }
     this.hidePlaylist();
   },
@@ -279,14 +279,21 @@ NowPlayingManager.prototype = {
     return false;
   },
   updateAudioPlaylist: function() {
-    jQuery.ajax({
-      type: 'POST',
-      contentType: 'application/json',
-      url: xbmc.core.JSON_RPC + '?updateAudioPlaylist',
-      data: '{"jsonrpc": "2.0", "method": "Playlist.GetItems", "params": { "playlistid": ' + this.playlistid + ', "properties": [ "title", "album", "artist", "duration", "thumbnail" ] }, "id": 1}',
-      success: jQuery.proxy(function(data) {
+    xbmc.rpc.request({
+      'context': this,
+      'method': 'Playlist.GetItems',
+      'params': {
+        'playlistid': this.playlistid,
+        'properties':[
+          'title',
+          'album',
+          'artist',
+          'duration',
+          'thumbnail'
+        ]
+      },
+      'success': function(data) {
         if (data && data.result && data.result.items && data.result.items.length > 0 && data.result.limits.total > 0) {
-          //Compare new playlist to active playlist, only redraw if a change is noticed
           if (!this.activePlaylistItem || this.playlistChanged(data.result.items) || (this.activePlaylistItem && (this.activePlaylistItem.seq != this.currentItem))) {
             var ul = $('<ul>');
             var activeItem;
@@ -337,14 +344,13 @@ NowPlayingManager.prototype = {
         if (this.autoRefreshAudioPlaylist) {
           setTimeout(jQuery.proxy(this.updateAudioPlaylist, this), 1000);
         }
-      }, this),
-      error: jQuery.proxy(function(data) {
+      },
+      'error': function(data) {
         xbmc.core.displayCommunicationError();
         if (this.autoRefreshAudioPlaylist) {
           setTimeout(jQuery.proxy(this.updateAudioPlaylist, this), 2000); /* Slow down request period */
         }
-      }, this),
-      dataType: 'json'
+      }
     });
   },
   stopAudioPlaylistUpdate: function() {
@@ -487,14 +493,23 @@ NowPlayingManager.prototype = {
     return true;
   },
   updateVideoPlaylist: function() {
-    jQuery.ajax({
-      type: 'POST',
-      contentType: 'application/json',
-      url: xbmc.core.JSON_RPC + '?updateVideoPlaylist',
-      data: '{"jsonrpc": "2.0", "method": "Playlist.GetItems", "params": { "playlistid": ' + this.playlistid + ', "properties": ["title", "season", "episode", "plot", "runtime", "showtitle","thumbnail"] }, "id": 1}',
-      success: jQuery.proxy(function(data) {
+    xbmc.rpc.request({
+      'context': this,
+      'method': 'Playlist.GetItems',
+      'params': {
+        'playlistid': this.playlistid,
+        'properties':[
+          'title',
+          'season',
+          'episode',
+          'plot',
+          'runtime',
+          'showtitle',
+          'thumbnail'
+        ]
+      },
+      'success': function(data) {
         if (data && data.result && data.result.items && data.result.items.length > 0 && data.result.limits.total > 0) {
-          //Compare new playlist to active playlist, only redraw if a change is noticed.
           if (this.playlistChanged(data.result.items)) {
             var ul = $('<ul>');
             var activeItem;
@@ -542,12 +557,22 @@ NowPlayingManager.prototype = {
             $('#nowPlayingPanel').show();
           }
         } else {
-          jQuery.ajax({
-            type: 'POST',
-            contentType: 'application/json',
-            url: xbmc.core.JSON_RPC + '?updateVideoPlayer',
-            data: '{"jsonrpc": "2.0", "method": "Player.GetItem", "params": { "playerid": ' + this.playlistid + ', "properties": ["title", "season", "episode", "plot", "runtime", "showtitle","thumbnail"] }, "id": 1}',
-            success: jQuery.proxy(function(data) {
+          xbmc.rpc.request({
+            'context': this,
+            'method': 'Player.GetItem',
+            'params': {
+              'playerid': this.activePlayerId,
+              'properties': [
+                'title',
+                'season',
+                'episode',
+                'plot',
+                'runtime',
+                'showtitle',
+                'thumbnail'
+              ]
+            },
+            'success': function(data) {
               if (data && data.result && data.result.item) {
                 this.activePlaylistItem = data.result.item;
                 if (!this.updateActiveItemDurationRunOnce) {
@@ -568,27 +593,25 @@ NowPlayingManager.prototype = {
                 $('#videoDescription').hide();
                 $('#nowPlayingPanel').hide();
               }
-            }, this),
-            error: jQuery.proxy(function(data) {
+            },
+            'error': function(data) {
               xbmc.core.displayCommunicationError();
               if (this.autoRefreshVideoPlaylist) {
                 setTimeout(jQuery.proxy(this.updateVideoPlaylist, this), 2000); /* Slow down request period */
               }
-            }, this),
-            dataType: 'json'
+            }
           });
         }
         if (this.autoRefreshVideoPlaylist) {
           setTimeout(jQuery.proxy(this.updateVideoPlaylist, this), 1000);
         }
-      }, this),
-      error: jQuery.proxy(function(data) {
+      },
+      'error': function(data) {
         xbmc.core.displayCommunicationError();
         if (this.autoRefreshVideoPlaylist) {
           setTimeout(jQuery.proxy(this.updateVideoPlaylist, this), 2000); /* Slow down request period */
         }
-      }, this),
-      dataType: 'json'
+      }
     });
   }
 }
diff --git a/addons/webinterface.default/js/iscroll.js b/addons/webinterface.default/js/iscroll.js
deleted file mode 100644 (file)
index 693e0e7..0000000
+++ /dev/null
@@ -1,709 +0,0 @@
-/**
- * 
- * Find more about the scrolling function at
- * http://cubiq.org/iscroll
- *
- * Copyright (c) 2010 Matteo Spinelli, http://cubiq.org/
- * Released under MIT license
- * http://cubiq.org/dropbox/mit-license.txt
- * 
- * Version 3.6 - Last updated: 2010.08.24
- * 
- */
-
-(function(){
-function iScroll (el, options) {
-       var that = this, i;
-       that.element = typeof el == 'object' ? el : document.getElementById(el);
-       that.wrapper = that.element.parentNode;
-
-       that.element.style.webkitTransitionProperty = '-webkit-transform';
-       that.element.style.webkitTransitionTimingFunction = 'cubic-bezier(0,0,0.25,1)';
-       that.element.style.webkitTransitionDuration = '0';
-       that.element.style.webkitTransform = translateOpen + '0,0' + translateClose;
-
-       // Default options
-       that.options = {
-               bounce: has3d,
-               momentum: has3d,
-               checkDOMChanges: true,
-               topOnDOMChanges: false,
-               hScrollbar: has3d,
-               vScrollbar: has3d,
-               fadeScrollbar: isIphone || isIpad || !isTouch,
-               shrinkScrollbar: isIphone || isIpad || !isTouch,
-               desktopCompatibility: false,
-               overflow: 'hidden',
-               snap: false
-       };
-       
-       // User defined options
-       if (typeof options == 'object') {
-               for (i in options) {
-                       that.options[i] = options[i];
-               }
-       }
-
-       if (that.options.desktopCompatibility) {
-               that.options.overflow = 'hidden';
-       }
-       
-       that.wrapper.style.overflow = that.options.overflow;
-       
-       that.refresh();
-
-       window.addEventListener('onorientationchange' in window ? 'orientationchange' : 'resize', that, false);
-
-       if (isTouch || that.options.desktopCompatibility) {
-               that.element.addEventListener(START_EVENT, that, false);
-               that.element.addEventListener(MOVE_EVENT, that, false);
-               that.element.addEventListener(END_EVENT, that, false);
-       }
-       
-       if (that.options.checkDOMChanges) {
-               that.element.addEventListener('DOMSubtreeModified', that, false);
-       }
-}
-
-iScroll.prototype = {
-       x: 0,
-       y: 0,
-       enabled: true,
-
-       handleEvent: function (e) {
-               var that = this;
-
-               switch (e.type) {
-                       case START_EVENT:
-                               that.touchStart(e);
-                               break;
-                       case MOVE_EVENT:
-                               that.touchMove(e);
-                               break;
-                       case END_EVENT:
-                               that.touchEnd(e);
-                               break;
-                       case 'webkitTransitionEnd':
-                               that.transitionEnd();
-                               break;
-                       case 'orientationchange':
-                       case 'resize':
-                               that.refresh();
-                               break;
-                       case 'DOMSubtreeModified':
-                               that.onDOMModified(e);
-                               break;
-               }
-       },
-       
-       onDOMModified: function (e) {
-               var that = this;
-
-               // (Hopefully) execute onDOMModified only once
-               if (e.target.parentNode != that.element) {
-                       return;
-               }
-
-               setTimeout(function () { that.refresh(); }, 0);
-
-               if (that.options.topOnDOMChanges && (that.x!=0 || that.y!=0)) {
-                       that.scrollTo(0,0,'0');
-               }
-       },
-
-       refresh: function () {
-               var that = this,
-                       resetX = this.x, resetY = this.y,
-                       snap;
-               
-               that.scrollWidth = that.wrapper.clientWidth;
-               that.scrollHeight = that.wrapper.clientHeight;
-               that.scrollerWidth = that.element.offsetWidth;
-               that.scrollerHeight = that.element.offsetHeight;
-               that.maxScrollX = that.scrollWidth - that.scrollerWidth;
-               that.maxScrollY = that.scrollHeight - that.scrollerHeight;
-               that.directionX = 0;
-               that.directionY = 0;
-
-               if (that.scrollX) {
-                       if (that.maxScrollX >= 0) {
-                               resetX = 0;
-                       } else if (that.x < that.maxScrollX) {
-                               resetX = that.maxScrollX;
-                       }
-               }
-               if (that.scrollY) {
-                       if (that.maxScrollY >= 0) {
-                               resetY = 0;
-                       } else if (that.y < that.maxScrollY) {
-                               resetY = that.maxScrollY;
-                       }
-               }
-               // Snap
-               if (that.options.snap) {
-                       that.maxPageX = -Math.floor(that.maxScrollX/that.scrollWidth);
-                       that.maxPageY = -Math.floor(that.maxScrollY/that.scrollHeight);
-
-                       snap = that.snap(resetX, resetY);
-                       resetX = snap.x;
-                       resetY = snap.y;
-               }
-
-               if (resetX!=that.x || resetY!=that.y) {
-                       that.setTransitionTime('0');
-                       that.setPosition(resetX, resetY, true);
-               }
-               
-               that.scrollX = that.scrollerWidth > that.scrollWidth;
-               that.scrollY = !that.scrollX || that.scrollerHeight > that.scrollHeight;
-
-               // Update horizontal scrollbar
-               if (that.options.hScrollbar && that.scrollX) {
-                       that.scrollBarX = that.scrollBarX || new scrollbar('horizontal', that.wrapper, that.options.fadeScrollbar, that.options.shrinkScrollbar);
-                       that.scrollBarX.init(that.scrollWidth, that.scrollerWidth);
-               } else if (that.scrollBarX) {
-                       that.scrollBarX = that.scrollBarX.remove();
-               }
-
-               // Update vertical scrollbar
-               if (that.options.vScrollbar && that.scrollY && that.scrollerHeight > that.scrollHeight) {
-                       that.scrollBarY = that.scrollBarY || new scrollbar('vertical', that.wrapper, that.options.fadeScrollbar, that.options.shrinkScrollbar);
-                       that.scrollBarY.init(that.scrollHeight, that.scrollerHeight);
-               } else if (that.scrollBarY) {
-                       that.scrollBarY = that.scrollBarY.remove();
-               }
-       },
-
-       setPosition: function (x, y, hideScrollBars) {
-               var that = this;
-               
-               that.x = x;
-               that.y = y;
-
-               that.element.style.webkitTransform = translateOpen + that.x + 'px,' + that.y + 'px' + translateClose;
-
-               // Move the scrollbars
-               if (!hideScrollBars) {
-                       if (that.scrollBarX) {
-                               that.scrollBarX.setPosition(that.x);
-                       }
-                       if (that.scrollBarY) {
-                               that.scrollBarY.setPosition(that.y);
-                       }
-               }
-       },
-       
-       setTransitionTime: function(time) {
-               var that = this;
-               
-               time = time || '0';
-               that.element.style.webkitTransitionDuration = time;
-               
-               if (that.scrollBarX) {
-                       that.scrollBarX.bar.style.webkitTransitionDuration = time;
-                       that.scrollBarX.wrapper.style.webkitTransitionDuration = has3d && that.options.fadeScrollbar ? '300ms' : '0';
-               }
-               if (that.scrollBarY) {
-                       that.scrollBarY.bar.style.webkitTransitionDuration = time;
-                       that.scrollBarY.wrapper.style.webkitTransitionDuration = has3d && that.options.fadeScrollbar ? '300ms' : '0';
-               }
-       },
-               
-       touchStart: function(e) {
-               var that = this,
-                       matrix;
-
-               e.preventDefault();
-               e.stopPropagation();
-               
-               if (!that.enabled) {
-                       return;
-               }
-
-               that.scrolling = true;          // This is probably not needed, but may be useful if iScroll is used in conjuction with other frameworks
-
-               that.moved = false;
-               that.dist = 0;
-
-               that.setTransitionTime('0');
-
-               // Check if the scroller is really where it should be
-               if (that.options.momentum || that.options.snap) {
-                       matrix = new WebKitCSSMatrix(window.getComputedStyle(that.element).webkitTransform);
-                       if (matrix.e != that.x || matrix.f != that.y) {
-                               document.removeEventListener('webkitTransitionEnd', that, false);
-                               that.setPosition(matrix.e, matrix.f);
-                               that.moved = true;
-                       }
-               }
-
-               that.touchStartX = isTouch ? e.changedTouches[0].pageX : e.pageX;
-               that.scrollStartX = that.x;
-
-               that.touchStartY = isTouch ? e.changedTouches[0].pageY : e.pageY;
-               that.scrollStartY = that.y;
-
-               that.scrollStartTime = e.timeStamp;
-
-               that.directionX = 0;
-               that.directionY = 0;
-       },
-       
-       touchMove: function(e) {
-               var that = this,
-                       pageX = isTouch ? e.changedTouches[0].pageX : e.pageX,
-                       pageY = isTouch ? e.changedTouches[0].pageY : e.pageY,
-                       leftDelta = that.scrollX ? pageX - that.touchStartX : 0,
-                       topDelta = that.scrollY ? pageY - that.touchStartY : 0,
-                       newX = that.x + leftDelta,
-                       newY = that.y + topDelta;
-
-               if (!that.scrolling) {
-                       return;
-               }
-
-               //e.preventDefault();
-               e.stopPropagation();    // Stopping propagation just saves some cpu cycles (I presume)
-
-               that.touchStartX = pageX;
-               that.touchStartY = pageY;
-
-               // Slow down if outside of the boundaries
-               if (newX >= 0 || newX < that.maxScrollX) {
-                       newX = that.options.bounce ? Math.round(that.x + leftDelta / 3) : (newX >= 0 || that.maxScrollX>=0) ? 0 : that.maxScrollX;
-               }
-               if (newY >= 0 || newY < that.maxScrollY) { 
-                       newY = that.options.bounce ? Math.round(that.y + topDelta / 3) : (newY >= 0 || that.maxScrollY>=0) ? 0 : that.maxScrollY;
-               }
-
-               if (that.dist > 5) {                    // 5 pixels threshold is needed on Android, but also on iPhone looks more natural
-                       that.setPosition(newX, newY);
-                       that.moved = true;
-                       that.directionX = leftDelta > 0 ? -1 : 1;
-                       that.directionY = topDelta > 0 ? -1 : 1;
-               } else {
-                       that.dist+= Math.abs(leftDelta) + Math.abs(topDelta);
-               }
-       },
-       
-       touchEnd: function(e) {
-               var that = this,
-                       time = e.timeStamp - that.scrollStartTime,
-                       point = isTouch ? e.changedTouches[0] : e,
-                       target, ev,
-                       momentumX, momentumY,
-                       newDuration = 0,
-                       newPositionX = that.x, newPositionY = that.y,
-                       snap;
-
-               if (!that.scrolling) {
-                       return;
-               }
-               that.scrolling = false;
-
-               if (!that.moved) {
-                       that.resetPosition();
-
-                       if (isTouch) {
-                               // Find the last touched element
-                               target = point.target;
-                               while (target.nodeType != 1) {
-                                       target = target.parentNode;
-                               }
-
-                               // Create the fake event
-                               target.style.pointerEvents = 'auto';
-                               ev = document.createEvent('MouseEvents');
-                               ev.initMouseEvent('click', true, true, e.view, 1,
-                                       point.screenX, point.screenY, point.clientX, point.clientY,
-                                       e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
-                                       0, null);
-                               ev._fake = true;
-                               target.dispatchEvent(ev);
-                       }
-
-                       return;
-               }
-
-               if (!that.options.snap && time > 250) {                 // Prevent slingshot effect
-                       that.resetPosition();
-                       return;
-               }
-
-               if (that.options.momentum) {
-                       momentumX = that.scrollX === true
-                               ? that.momentum(that.x - that.scrollStartX,
-                                                               time,
-                                                               that.options.bounce ? -that.x + that.scrollWidth/5 : -that.x,
-                                                               that.options.bounce ? that.x + that.scrollerWidth - that.scrollWidth + that.scrollWidth/5 : that.x + that.scrollerWidth - that.scrollWidth)
-                               : { dist: 0, time: 0 };
-
-                       momentumY = that.scrollY === true
-                               ? that.momentum(that.y - that.scrollStartY,
-                                                               time,
-                                                               that.options.bounce ? -that.y + that.scrollHeight/5 : -that.y,
-                                                               that.options.bounce ? (that.maxScrollY < 0 ? that.y + that.scrollerHeight - that.scrollHeight : 0) + that.scrollHeight/5 : that.y + that.scrollerHeight - that.scrollHeight)
-                               : { dist: 0, time: 0 };
-
-                       newDuration = Math.max(Math.max(momentumX.time, momentumY.time), 1);            // The minimum animation length must be 1ms
-                       newPositionX = that.x + momentumX.dist;
-                       newPositionY = that.y + momentumY.dist;
-               }
-
-               if (that.options.snap) {
-                       snap = that.snap(newPositionX, newPositionY);
-                       newPositionX = snap.x;
-                       newPositionY = snap.y;
-                       newDuration = Math.max(snap.time, newDuration);
-               }
-
-               that.scrollTo(newPositionX, newPositionY, newDuration + 'ms');
-       },
-
-       transitionEnd: function () {
-               var that = this;
-               document.removeEventListener('webkitTransitionEnd', that, false);
-               that.resetPosition();
-       },
-
-       resetPosition: function () {
-               var that = this,
-                       resetX = that.x,
-                       resetY = that.y;
-
-               if (that.x >= 0) {
-                       resetX = 0;
-               } else if (that.x < that.maxScrollX) {
-                       resetX = that.maxScrollX;
-               }
-
-               if (that.y >= 0 || that.maxScrollY > 0) {
-                       resetY = 0;
-               } else if (that.y < that.maxScrollY) {
-                       resetY = that.maxScrollY;
-               }
-               
-               if (resetX != that.x || resetY != that.y) {
-                       that.scrollTo(resetX, resetY);
-               } else {
-                       if (that.moved) {
-                               that.onScrollEnd();             // Execute custom code on scroll end
-                               that.moved = false;
-                       }
-
-                       // Hide the scrollbars
-                       if (that.scrollBarX) {
-                               that.scrollBarX.hide();
-                       }
-                       if (that.scrollBarY) {
-                               that.scrollBarY.hide();
-                       }
-               }
-       },
-       
-       snap: function (x, y) {
-               var that = this, time;
-
-               if (that.directionX > 0) {
-                       x = Math.floor(x/that.scrollWidth);
-               } else if (that.directionX < 0) {
-                       x = Math.ceil(x/that.scrollWidth);
-               } else {
-                       x = Math.round(x/that.scrollWidth);
-               }
-               that.pageX = -x;
-               x = x * that.scrollWidth;
-               if (x > 0) {
-                       x = that.pageX = 0;
-               } else if (x < that.maxScrollX) {
-                       that.pageX = that.maxPageX;
-                       x = that.maxScrollX;
-               }
-
-               if (that.directionY > 0) {
-                       y = Math.floor(y/that.scrollHeight);
-               } else if (that.directionY < 0) {
-                       y = Math.ceil(y/that.scrollHeight);
-               } else {
-                       y = Math.round(y/that.scrollHeight);
-               }
-               that.pageY = -y;
-               y = y * that.scrollHeight;
-               if (y > 0) {
-                       y = that.pageY = 0;
-               } else if (y < that.maxScrollY) {
-                       that.pageY = that.maxPageY;
-                       y = that.maxScrollY;
-               }
-
-               // Snap with constant speed (proportional duration)
-               time = Math.round(Math.max(
-                               Math.abs(that.x - x) / that.scrollWidth * 500,
-                               Math.abs(that.y - y) / that.scrollHeight * 500
-                       ));
-                       
-               return { x: x, y: y, time: time };
-       },
-
-       scrollTo: function (destX, destY, runtime) {
-               var that = this;
-
-               if (that.x == destX && that.y == destY) {
-                       that.resetPosition();
-                       return;
-               }
-
-               that.moved = true;
-               that.setTransitionTime(runtime || '350ms');
-               that.setPosition(destX, destY);
-
-               if (runtime==='0' || runtime=='0s' || runtime=='0ms') {
-                       that.resetPosition();
-               } else {
-                       document.addEventListener('webkitTransitionEnd', that, false);  // At the end of the transition check if we are still inside of the boundaries
-               }
-       },
-       
-       scrollToPage: function (pageX, pageY, runtime) {
-               var that = this, snap;
-
-               if (!that.options.snap) {
-                       that.pageX = -Math.round(that.x / that.scrollWidth);
-                       that.pageY = -Math.round(that.y / that.scrollHeight);
-               }
-
-               if (pageX == 'next') {
-                       pageX = ++that.pageX;
-               } else if (pageX == 'prev') {
-                       pageX = --that.pageX;
-               }
-
-               if (pageY == 'next') {
-                       pageY = ++that.pageY;
-               } else if (pageY == 'prev') {
-                       pageY = --that.pageY;
-               }
-
-               pageX = -pageX*that.scrollWidth;
-               pageY = -pageY*that.scrollHeight;
-
-               snap = that.snap(pageX, pageY);
-               pageX = snap.x;
-               pageY = snap.y;
-
-               that.scrollTo(pageX, pageY, runtime || '500ms');
-       },
-
-       scrollToElement: function (el, runtime) {
-               el = typeof el == 'object' ? el : this.element.querySelector(el);
-
-               if (!el) {
-                       return;
-               }
-
-               var that = this,
-                       x = that.scrollX ? -el.offsetLeft : 0,
-                       y = that.scrollY ? -el.offsetTop : 0;
-
-               if (x >= 0) {
-                       x = 0;
-               } else if (x < that.maxScrollX) {
-                       x = that.maxScrollX;
-               }
-
-               if (y >= 0) {
-                       y = 0;
-               } else if (y < that.maxScrollY) {
-                       y = that.maxScrollY;
-               }
-
-               that.scrollTo(x, y, runtime);
-       },
-
-       momentum: function (dist, time, maxDistUpper, maxDistLower) {
-               var friction = 2.5,
-                       deceleration = 1.2,
-                       speed = Math.abs(dist) / time * 1000,
-                       newDist = speed * speed / friction / 1000,
-                       newTime = 0;
-
-               // Proportinally reduce speed if we are outside of the boundaries 
-               if (dist > 0 && newDist > maxDistUpper) {
-                       speed = speed * maxDistUpper / newDist / friction;
-                       newDist = maxDistUpper;
-               } else if (dist < 0 && newDist > maxDistLower) {
-                       speed = speed * maxDistLower / newDist / friction;
-                       newDist = maxDistLower;
-               }
-               
-               newDist = newDist * (dist < 0 ? -1 : 1);
-               newTime = speed / deceleration;
-
-               return { dist: Math.round(newDist), time: Math.round(newTime) };
-       },
-       
-       onScrollEnd: function () {},
-       
-       destroy: function (full) {
-               var that = this;
-
-               window.removeEventListener('onorientationchange' in window ? 'orientationchange' : 'resize', that, false);              
-               that.element.removeEventListener(START_EVENT, that, false);
-               that.element.removeEventListener(MOVE_EVENT, that, false);
-               that.element.removeEventListener(END_EVENT, that, false);
-               document.removeEventListener('webkitTransitionEnd', that, false);
-
-               if (that.options.checkDOMChanges) {
-                       that.element.removeEventListener('DOMSubtreeModified', that, false);
-               }
-
-               if (that.scrollBarX) {
-                       that.scrollBarX = that.scrollBarX.remove();
-               }
-
-               if (that.scrollBarY) {
-                       that.scrollBarY = that.scrollBarY.remove();
-               }
-               
-               if (full) {
-                       that.wrapper.parentNode.removeChild(that.wrapper);
-               }
-               
-               return null;
-       }
-};
-
-function scrollbar (dir, wrapper, fade, shrink) {
-       var that = this, style;
-       
-       that.dir = dir;
-       that.fade = fade;
-       that.shrink = shrink;
-       that.uid = ++uid;
-
-       // Create main scrollbar
-       that.bar = document.createElement('div');
-
-       style = 'position:absolute;top:0;left:0;-webkit-transition-timing-function:cubic-bezier(0,0,0.25,1);pointer-events:none;-webkit-transition-duration:0;-webkit-transition-delay:0;-webkit-transition-property:-webkit-transform;z-index:10;background:rgba(0,0,0,0.5);' +
-               '-webkit-transform:' + translateOpen + '0,0' + translateClose + ';' +
-               (dir == 'horizontal' ? '-webkit-border-radius:3px 2px;min-width:6px;min-height:5px' : '-webkit-border-radius:2px 3px;min-width:5px;min-height:6px');
-
-       that.bar.setAttribute('style', style);
-
-       // Create scrollbar wrapper
-       that.wrapper = document.createElement('div');
-       style = '-webkit-mask:-webkit-canvas(scrollbar' + that.uid + that.dir + ');position:absolute;z-index:10;pointer-events:none;overflow:hidden;opacity:0;-webkit-transition-duration:' + (fade ? '300ms' : '0') + ';-webkit-transition-delay:0;-webkit-transition-property:opacity;' +
-               (that.dir == 'horizontal' ? 'bottom:2px;left:2px;right:7px;height:5px' : 'top:2px;right:2px;bottom:7px;width:5px;');
-       that.wrapper.setAttribute('style', style);
-
-       // Add scrollbar to the DOM
-       that.wrapper.appendChild(that.bar);
-       wrapper.appendChild(that.wrapper);
-}
-
-scrollbar.prototype = {
-       init: function (scroll, size) {
-               var that = this,
-                       ctx;
-
-               // Create scrollbar mask
-               if (that.dir == 'horizontal') {
-                       if (that.maxSize != that.wrapper.offsetWidth) {
-                               that.maxSize = that.wrapper.offsetWidth;
-                               ctx = document.getCSSCanvasContext("2d", "scrollbar" + that.uid + that.dir, that.maxSize, 5);
-                               ctx.fillStyle = "rgb(0,0,0)";
-                               ctx.beginPath();
-                               ctx.arc(2.5, 2.5, 2.5, Math.PI/2, -Math.PI/2, false);
-                               ctx.lineTo(that.maxSize-2.5, 0);
-                               ctx.arc(that.maxSize-2.5, 2.5, 2.5, -Math.PI/2, Math.PI/2, false);
-                               ctx.closePath();
-                               ctx.fill();
-                       }
-               } else {
-                       if (that.maxSize != that.wrapper.offsetHeight) {
-                               that.maxSize = that.wrapper.offsetHeight;
-                               ctx = document.getCSSCanvasContext("2d", "scrollbar" + that.uid + that.dir, 5, that.maxSize);
-                               ctx.fillStyle = "rgb(0,0,0)";
-                               ctx.beginPath();
-                               ctx.arc(2.5, 2.5, 2.5, Math.PI, 0, false);
-                               ctx.lineTo(5, that.maxSize-2.5);
-                               ctx.arc(2.5, that.maxSize-2.5, 2.5, 0, Math.PI, false);
-                               ctx.closePath();
-                               ctx.fill();
-                       }
-               }
-
-               that.size = Math.max(Math.round(that.maxSize * that.maxSize / size), 6);
-               that.maxScroll = that.maxSize - that.size;
-               that.toWrapperProp = that.maxScroll / (scroll - size);
-               that.bar.style[that.dir == 'horizontal' ? 'width' : 'height'] = that.size + 'px';
-       },
-       
-       setPosition: function (pos) {
-               var that = this;
-               
-               if (that.wrapper.style.opacity != '1') {
-                       that.show();
-               }
-
-               pos = Math.round(that.toWrapperProp * pos);
-
-               if (pos < 0) {
-                       pos = that.shrink ? pos + pos*3 : 0;
-                       if (that.size + pos < 7) {
-                               pos = -that.size + 6;
-                       }
-               } else if (pos > that.maxScroll) {
-                       pos = that.shrink ? pos + (pos-that.maxScroll)*3 : that.maxScroll;
-                       if (that.size + that.maxScroll - pos < 7) {
-                               pos = that.size + that.maxScroll - 6;
-                       }
-               }
-
-               pos = that.dir == 'horizontal'
-                       ? translateOpen + pos + 'px,0' + translateClose
-                       : translateOpen + '0,' + pos + 'px' + translateClose;
-
-               that.bar.style.webkitTransform = pos;
-       },
-
-       show: function () {
-               if (has3d) {
-                       this.wrapper.style.webkitTransitionDelay = '0';
-               }
-               this.wrapper.style.opacity = '1';
-       },
-
-       hide: function () {
-               if (has3d) {
-                       this.wrapper.style.webkitTransitionDelay = '350ms';
-               }
-               this.wrapper.style.opacity = '0';
-       },
-       
-       remove: function () {
-               this.wrapper.parentNode.removeChild(this.wrapper);
-               return null;
-       }
-};
-
-// Is translate3d compatible?
-var has3d = ('WebKitCSSMatrix' in window && 'm11' in new WebKitCSSMatrix()),
-       // Device sniffing
-       isIphone = (/iphone/gi).test(navigator.appVersion),
-       isIpad = (/ipad/gi).test(navigator.appVersion),
-       isAndroid = (/android/gi).test(navigator.appVersion),
-       isTouch = isIphone || isIpad || isAndroid,
-       // Event sniffing
-       START_EVENT = isTouch ? 'touchstart' : 'mousedown',
-       MOVE_EVENT = isTouch ? 'touchmove' : 'mousemove',
-       END_EVENT = isTouch ? 'touchend' : 'mouseup',
-       // Translate3d helper
-       translateOpen = 'translate' + (has3d ? '3d(' : '('),
-       translateClose = has3d ? ',0)' : ')',
-       // Unique ID
-       uid = 0;
-
-// Expose iScroll to the world
-window.iScroll = iScroll;
-})();
\ No newline at end of file
diff --git a/addons/webinterface.default/js/jquery-1.5.2.js b/addons/webinterface.default/js/jquery-1.5.2.js
deleted file mode 100644 (file)
index af9b7da..0000000
+++ /dev/null
@@ -1,8374 +0,0 @@
-/*!
- * jQuery JavaScript Library v1.5.2
- * http://jquery.com/
- *
- * Copyright 2011, John Resig
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * Includes Sizzle.js
- * http://sizzlejs.com/
- * Copyright 2011, The Dojo Foundation
- * Released under the MIT, BSD, and GPL Licenses.
- *
- * Date: Thu Mar 31 15:28:23 2011 -0400
- */
-(function( window, undefined ) {
-
-// Use the correct document accordingly with window argument (sandbox)
-var document = window.document;
-var jQuery = (function() {
-
-// Define a local copy of jQuery
-var jQuery = function( selector, context ) {
-               // The jQuery object is actually just the init constructor 'enhanced'
-               return new jQuery.fn.init( selector, context, rootjQuery );
-       },
-
-       // Map over jQuery in case of overwrite
-       _jQuery = window.jQuery,
-
-       // Map over the $ in case of overwrite
-       _$ = window.$,
-
-       // A central reference to the root jQuery(document)
-       rootjQuery,
-
-       // A simple way to check for HTML strings or ID strings
-       // (both of which we optimize for)
-       quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,
-
-       // Check if a string has a non-whitespace character in it
-       rnotwhite = /\S/,
-
-       // Used for trimming whitespace
-       trimLeft = /^\s+/,
-       trimRight = /\s+$/,
-
-       // Check for digits
-       rdigit = /\d/,
-
-       // Match a standalone tag
-       rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,
-
-       // JSON RegExp
-       rvalidchars = /^[\],:{}\s]*$/,
-       rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
-       rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
-       rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
-
-       // Useragent RegExp
-       rwebkit = /(webkit)[ \/]([\w.]+)/,
-       ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/,
-       rmsie = /(msie) ([\w.]+)/,
-       rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/,
-
-       // Keep a UserAgent string for use with jQuery.browser
-       userAgent = navigator.userAgent,
-
-       // For matching the engine and version of the browser
-       browserMatch,
-
-       // The deferred used on DOM ready
-       readyList,
-
-       // The ready event handler
-       DOMContentLoaded,
-
-       // Save a reference to some core methods
-       toString = Object.prototype.toString,
-       hasOwn = Object.prototype.hasOwnProperty,
-       push = Array.prototype.push,
-       slice = Array.prototype.slice,
-       trim = String.prototype.trim,
-       indexOf = Array.prototype.indexOf,
-
-       // [[Class]] -> type pairs
-       class2type = {};
-
-jQuery.fn = jQuery.prototype = {
-       constructor: jQuery,
-       init: function( selector, context, rootjQuery ) {
-               var match, elem, ret, doc;
-
-               // Handle $(""), $(null), or $(undefined)
-               if ( !selector ) {
-                       return this;
-               }
-
-               // Handle $(DOMElement)
-               if ( selector.nodeType ) {
-                       this.context = this[0] = selector;
-                       this.length = 1;
-                       return this;
-               }
-
-               // The body element only exists once, optimize finding it
-               if ( selector === "body" && !context && document.body ) {
-                       this.context = document;
-                       this[0] = document.body;
-                       this.selector = "body";
-                       this.length = 1;
-                       return this;
-               }
-
-               // Handle HTML strings
-               if ( typeof selector === "string" ) {
-                       // Are we dealing with HTML string or an ID?
-                       match = quickExpr.exec( selector );
-
-                       // Verify a match, and that no context was specified for #id
-                       if ( match && (match[1] || !context) ) {
-
-                               // HANDLE: $(html) -> $(array)
-                               if ( match[1] ) {
-                                       context = context instanceof jQuery ? context[0] : context;
-                                       doc = (context ? context.ownerDocument || context : document);
-
-                                       // If a single string is passed in and it's a single tag
-                                       // just do a createElement and skip the rest
-                                       ret = rsingleTag.exec( selector );
-
-                                       if ( ret ) {
-                                               if ( jQuery.isPlainObject( context ) ) {
-                                                       selector = [ document.createElement( ret[1] ) ];
-                                                       jQuery.fn.attr.call( selector, context, true );
-
-                                               } else {
-                                                       selector = [ doc.createElement( ret[1] ) ];
-                                               }
-
-                                       } else {
-                                               ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
-                                               selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes;
-                                       }
-
-                                       return jQuery.merge( this, selector );
-
-                               // HANDLE: $("#id")
-                               } else {
-                                       elem = document.getElementById( match[2] );
-
-                                       // Check parentNode to catch when Blackberry 4.6 returns
-                                       // nodes that are no longer in the document #6963
-                                       if ( elem && elem.parentNode ) {
-                                               // Handle the case where IE and Opera return items
-                                               // by name instead of ID
-                                               if ( elem.id !== match[2] ) {
-                                                       return rootjQuery.find( selector );
-                                               }
-
-                                               // Otherwise, we inject the element directly into the jQuery object
-                                               this.length = 1;
-                                               this[0] = elem;
-                                       }
-
-                                       this.context = document;
-                                       this.selector = selector;
-                                       return this;
-                               }
-
-                       // HANDLE: $(expr, $(...))
-                       } else if ( !context || context.jquery ) {
-                               return (context || rootjQuery).find( selector );
-
-                       // HANDLE: $(expr, context)
-                       // (which is just equivalent to: $(context).find(expr)
-                       } else {
-                               return this.constructor( context ).find( selector );
-                       }
-
-               // HANDLE: $(function)
-               // Shortcut for document ready
-               } else if ( jQuery.isFunction( selector ) ) {
-                       return rootjQuery.ready( selector );
-               }
-
-               if (selector.selector !== undefined) {
-                       this.selector = selector.selector;
-                       this.context = selector.context;
-               }
-
-               return jQuery.makeArray( selector, this );
-       },
-
-       // Start with an empty selector
-       selector: "",
-
-       // The current version of jQuery being used
-       jquery: "1.5.2",
-
-       // The default length of a jQuery object is 0
-       length: 0,
-
-       // The number of elements contained in the matched element set
-       size: function() {
-               return this.length;
-       },
-
-       toArray: function() {
-               return slice.call( this, 0 );
-       },
-
-       // Get the Nth element in the matched element set OR
-       // Get the whole matched element set as a clean array
-       get: function( num ) {
-               return num == null ?
-
-                       // Return a 'clean' array
-                       this.toArray() :
-
-                       // Return just the object
-                       ( num < 0 ? this[ this.length + num ] : this[ num ] );
-       },
-
-       // Take an array of elements and push it onto the stack
-       // (returning the new matched element set)
-       pushStack: function( elems, name, selector ) {
-               // Build a new jQuery matched element set
-               var ret = this.constructor();
-
-               if ( jQuery.isArray( elems ) ) {
-                       push.apply( ret, elems );
-
-               } else {
-                       jQuery.merge( ret, elems );
-               }
-
-               // Add the old object onto the stack (as a reference)
-               ret.prevObject = this;
-
-               ret.context = this.context;
-
-               if ( name === "find" ) {
-                       ret.selector = this.selector + (this.selector ? " " : "") + selector;
-               } else if ( name ) {
-                       ret.selector = this.selector + "." + name + "(" + selector + ")";
-               }
-
-               // Return the newly-formed element set
-               return ret;
-       },
-
-       // Execute a callback for every element in the matched set.
-       // (You can seed the arguments with an array of args, but this is
-       // only used internally.)
-       each: function( callback, args ) {
-               return jQuery.each( this, callback, args );
-       },
-
-       ready: function( fn ) {
-               // Attach the listeners
-               jQuery.bindReady();
-
-               // Add the callback
-               readyList.done( fn );
-
-               return this;
-       },
-
-       eq: function( i ) {
-               return i === -1 ?
-                       this.slice( i ) :
-                       this.slice( i, +i + 1 );
-       },
-
-       first: function() {
-               return this.eq( 0 );
-       },
-
-       last: function() {
-               return this.eq( -1 );
-       },
-
-       slice: function() {
-               return this.pushStack( slice.apply( this, arguments ),
-                       "slice", slice.call(arguments).join(",") );
-       },
-
-       map: function( callback ) {
-               return this.pushStack( jQuery.map(this, function( elem, i ) {
-                       return callback.call( elem, i, elem );
-               }));
-       },
-
-       end: function() {
-               return this.prevObject || this.constructor(null);
-       },
-
-       // For internal use only.
-       // Behaves like an Array's method, not like a jQuery method.
-       push: push,
-       sort: [].sort,
-       splice: [].splice
-};
-
-// Give the init function the jQuery prototype for later instantiation
-jQuery.fn.init.prototype = jQuery.fn;
-
-jQuery.extend = jQuery.fn.extend = function() {
-       var options, name, src, copy, copyIsArray, clone,
-               target = arguments[0] || {},
-               i = 1,
-               length = arguments.length,
-               deep = false;
-
-       // Handle a deep copy situation
-       if ( typeof target === "boolean" ) {
-               deep = target;
-               target = arguments[1] || {};
-               // skip the boolean and the target
-               i = 2;
-       }
-
-       // Handle case when target is a string or something (possible in deep copy)
-       if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
-               target = {};
-       }
-
-       // extend jQuery itself if only one argument is passed
-       if ( length === i ) {
-               target = this;
-               --i;
-       }
-
-       for ( ; i < length; i++ ) {
-               // Only deal with non-null/undefined values
-               if ( (options = arguments[ i ]) != null ) {
-                       // Extend the base object
-                       for ( name in options ) {
-                               src = target[ name ];
-                               copy = options[ name ];
-
-                               // Prevent never-ending loop
-                               if ( target === copy ) {
-                                       continue;
-                               }
-
-                               // Recurse if we're merging plain objects or arrays
-                               if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
-                                       if ( copyIsArray ) {
-                                               copyIsArray = false;
-                                               clone = src && jQuery.isArray(src) ? src : [];
-
-                                       } else {
-                                               clone = src && jQuery.isPlainObject(src) ? src : {};
-                                       }
-
-                                       // Never move original objects, clone them
-                                       target[ name ] = jQuery.extend( deep, clone, copy );
-
-                               // Don't bring in undefined values
-                               } else if ( copy !== undefined ) {
-                                       target[ name ] = copy;
-                               }
-                       }
-               }
-       }
-
-       // Return the modified object
-       return target;
-};
-
-jQuery.extend({
-       noConflict: function( deep ) {
-               window.$ = _$;
-
-               if ( deep ) {
-                       window.jQuery = _jQuery;
-               }
-
-               return jQuery;
-       },
-
-       // Is the DOM ready to be used? Set to true once it occurs.
-       isReady: false,
-
-       // A counter to track how many items to wait for before
-       // the ready event fires. See #6781
-       readyWait: 1,
-
-       // Handle when the DOM is ready
-       ready: function( wait ) {
-               // A third-party is pushing the ready event forwards
-               if ( wait === true ) {
-                       jQuery.readyWait--;
-               }
-
-               // Make sure that the DOM is not already loaded
-               if ( !jQuery.readyWait || (wait !== true && !jQuery.isReady) ) {
-                       // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
-                       if ( !document.body ) {
-                               return setTimeout( jQuery.ready, 1 );
-                       }
-
-                       // Remember that the DOM is ready
-                       jQuery.isReady = true;
-
-                       // If a normal DOM Ready event fired, decrement, and wait if need be
-                       if ( wait !== true && --jQuery.readyWait > 0 ) {
-                               return;
-                       }
-
-                       // If there are functions bound, to execute
-                       readyList.resolveWith( document, [ jQuery ] );
-
-                       // Trigger any bound ready events
-                       if ( jQuery.fn.trigger ) {
-                               jQuery( document ).trigger( "ready" ).unbind( "ready" );
-                       }
-               }
-       },
-
-       bindReady: function() {
-               if ( readyList ) {
-                       return;
-               }
-
-               readyList = jQuery._Deferred();
-
-               // Catch cases where $(document).ready() is called after the
-               // browser event has already occurred.
-               if ( document.readyState === "complete" ) {
-                       // Handle it asynchronously to allow scripts the opportunity to delay ready
-                       return setTimeout( jQuery.ready, 1 );
-               }
-
-               // Mozilla, Opera and webkit nightlies currently support this event
-               if ( document.addEventListener ) {
-                       // Use the handy event callback
-                       document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
-
-                       // A fallback to window.onload, that will always work
-                       window.addEventListener( "load", jQuery.ready, false );
-
-               // If IE event model is used
-               } else if ( document.attachEvent ) {
-                       // ensure firing before onload,
-                       // maybe late but safe also for iframes
-                       document.attachEvent("onreadystatechange", DOMContentLoaded);
-
-                       // A fallback to window.onload, that will always work
-                       window.attachEvent( "onload", jQuery.ready );
-
-                       // If IE and not a frame
-                       // continually check to see if the document is ready
-                       var toplevel = false;
-
-                       try {
-                               toplevel = window.frameElement == null;
-                       } catch(e) {}
-
-                       if ( document.documentElement.doScroll && toplevel ) {
-                               doScrollCheck();
-                       }
-               }
-       },
-
-       // See test/unit/core.js for details concerning isFunction.
-       // Since version 1.3, DOM methods and functions like alert
-       // aren't supported. They return false on IE (#2968).
-       isFunction: function( obj ) {
-               return jQuery.type(obj) === "function";
-       },
-
-       isArray: Array.isArray || function( obj ) {
-               return jQuery.type(obj) === "array";
-       },
-
-       // A crude way of determining if an object is a window
-       isWindow: function( obj ) {
-               return obj && typeof obj === "object" && "setInterval" in obj;
-       },
-
-       isNaN: function( obj ) {
-               return obj == null || !rdigit.test( obj ) || isNaN( obj );
-       },
-
-       type: function( obj ) {
-               return obj == null ?
-                       String( obj ) :
-                       class2type[ toString.call(obj) ] || "object";
-       },
-
-       isPlainObject: function( obj ) {
-               // Must be an Object.
-               // Because of IE, we also have to check the presence of the constructor property.
-               // Make sure that DOM nodes and window objects don't pass through, as well
-               if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
-                       return false;
-               }
-
-               // Not own constructor property must be Object
-               if ( obj.constructor &&
-                       !hasOwn.call(obj, "constructor") &&
-                       !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
-                       return false;
-               }
-
-               // Own properties are enumerated firstly, so to speed up,
-               // if last one is own, then all properties are own.
-
-               var key;
-               for ( key in obj ) {}
-
-               return key === undefined || hasOwn.call( obj, key );
-       },
-
-       isEmptyObject: function( obj ) {
-               for ( var name in obj ) {
-                       return false;
-               }
-               return true;
-       },
-
-       error: function( msg ) {
-               throw msg;
-       },
-
-       parseJSON: function( data ) {
-               if ( typeof data !== "string" || !data ) {
-                       return null;
-               }
-
-               // Make sure leading/trailing whitespace is removed (IE can't handle it)
-               data = jQuery.trim( data );
-
-               // Make sure the incoming data is actual JSON
-               // Logic borrowed from http://json.org/json2.js
-               if ( rvalidchars.test(data.replace(rvalidescape, "@")
-                       .replace(rvalidtokens, "]")
-                       .replace(rvalidbraces, "")) ) {
-
-                       // Try to use the native JSON parser first
-                       return window.JSON && window.JSON.parse ?
-                               window.JSON.parse( data ) :
-                               (new Function("return " + data))();
-
-               } else {
-                       jQuery.error( "Invalid JSON: " + data );
-               }
-       },
-
-       // Cross-browser xml parsing
-       // (xml & tmp used internally)
-       parseXML: function( data , xml , tmp ) {
-
-               if ( window.DOMParser ) { // Standard
-                       tmp = new DOMParser();
-                       xml = tmp.parseFromString( data , "text/xml" );
-               } else { // IE
-                       xml = new ActiveXObject( "Microsoft.XMLDOM" );
-                       xml.async = "false";
-                       xml.loadXML( data );
-               }
-
-               tmp = xml.documentElement;
-
-               if ( ! tmp || ! tmp.nodeName || tmp.nodeName === "parsererror" ) {
-                       jQuery.error( "Invalid XML: " + data );
-               }
-
-               return xml;
-       },
-
-       noop: function() {},
-
-       // Evalulates a script in a global context
-       globalEval: function( data ) {
-               if ( data && rnotwhite.test(data) ) {
-                       // Inspired by code by Andrea Giammarchi
-                       // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
-                       var head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement,
-                               script = document.createElement( "script" );
-
-                       if ( jQuery.support.scriptEval() ) {
-                               script.appendChild( document.createTextNode( data ) );
-                       } else {
-                               script.text = data;
-                       }
-
-                       // Use insertBefore instead of appendChild to circumvent an IE6 bug.
-                       // This arises when a base node is used (#2709).
-                       head.insertBefore( script, head.firstChild );
-                       head.removeChild( script );
-               }
-       },
-
-       nodeName: function( elem, name ) {
-               return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
-       },
-
-       // args is for internal usage only
-       each: function( object, callback, args ) {
-               var name, i = 0,
-                       length = object.length,
-                       isObj = length === undefined || jQuery.isFunction(object);
-
-               if ( args ) {
-                       if ( isObj ) {
-                               for ( name in object ) {
-                                       if ( callback.apply( object[ name ], args ) === false ) {
-                                               break;
-                                       }
-                               }
-                       } else {
-                               for ( ; i < length; ) {
-                                       if ( callback.apply( object[ i++ ], args ) === false ) {
-                                               break;
-                                       }
-                               }
-                       }
-
-               // A special, fast, case for the most common use of each
-               } else {
-                       if ( isObj ) {
-                               for ( name in object ) {
-                                       if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
-                                               break;
-                                       }
-                               }
-                       } else {
-                               for ( var value = object[0];
-                                       i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {}
-                       }
-               }
-
-               return object;
-       },
-
-       // Use native String.trim function wherever possible
-       trim: trim ?
-               function( text ) {
-                       return text == null ?
-                               "" :
-                               trim.call( text );
-               } :
-
-               // Otherwise use our own trimming functionality
-               function( text ) {
-                       return text == null ?
-                               "" :
-                               text.toString().replace( trimLeft, "" ).replace( trimRight, "" );
-               },
-
-       // results is for internal usage only
-       makeArray: function( array, results ) {
-               var ret = results || [];
-
-               if ( array != null ) {
-                       // The window, strings (and functions) also have 'length'
-                       // The extra typeof function check is to prevent crashes
-                       // in Safari 2 (See: #3039)
-                       // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
-                       var type = jQuery.type(array);
-
-                       if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) {
-                               push.call( ret, array );
-                       } else {
-                               jQuery.merge( ret, array );
-                       }
-               }
-
-               return ret;
-       },
-
-       inArray: function( elem, array ) {
-               if ( array.indexOf ) {
-                       return array.indexOf( elem );
-               }
-
-               for ( var i = 0, length = array.length; i < length; i++ ) {
-                       if ( array[ i ] === elem ) {
-                               return i;
-                       }
-               }
-
-               return -1;
-       },
-
-       merge: function( first, second ) {
-               var i = first.length,
-                       j = 0;
-
-               if ( typeof second.length === "number" ) {
-                       for ( var l = second.length; j < l; j++ ) {
-                               first[ i++ ] = second[ j ];
-                       }
-
-               } else {
-                       while ( second[j] !== undefined ) {
-                               first[ i++ ] = second[ j++ ];
-                       }
-               }
-
-               first.length = i;
-
-               return first;
-       },
-
-       grep: function( elems, callback, inv ) {
-               var ret = [], retVal;
-               inv = !!inv;
-
-               // Go through the array, only saving the items
-               // that pass the validator function
-               for ( var i = 0, length = elems.length; i < length; i++ ) {
-                       retVal = !!callback( elems[ i ], i );
-                       if ( inv !== retVal ) {
-                               ret.push( elems[ i ] );
-                       }
-               }
-
-               return ret;
-       },
-
-       // arg is for internal usage only
-       map: function( elems, callback, arg ) {
-               var ret = [], value;
-
-               // Go through the array, translating each of the items to their
-               // new value (or values).
-               for ( var i = 0, length = elems.length; i < length; i++ ) {
-                       value = callback( elems[ i ], i, arg );
-
-                       if ( value != null ) {
-                               ret[ ret.length ] = value;
-                       }
-               }
-
-               // Flatten any nested arrays
-               return ret.concat.apply( [], ret );
-       },
-
-       // A global GUID counter for objects
-       guid: 1,
-
-       proxy: function( fn, proxy, thisObject ) {
-               if ( arguments.length === 2 ) {
-                       if ( typeof proxy === "string" ) {
-                               thisObject = fn;
-                               fn = thisObject[ proxy ];
-                               proxy = undefined;
-
-                       } else if ( proxy && !jQuery.isFunction( proxy ) ) {
-                               thisObject = proxy;
-                               proxy = undefined;
-                       }
-               }
-
-               if ( !proxy && fn ) {
-                       proxy = function() {
-                               return fn.apply( thisObject || this, arguments );
-                       };
-               }
-
-               // Set the guid of unique handler to the same of original handler, so it can be removed
-               if ( fn ) {
-                       proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
-               }
-
-               // So proxy can be declared as an argument
-               return proxy;
-       },
-
-       // Mutifunctional method to get and set values to a collection
-       // The value/s can be optionally by executed if its a function
-       access: function( elems, key, value, exec, fn, pass ) {
-               var length = elems.length;
-
-               // Setting many attributes
-               if ( typeof key === "object" ) {
-                       for ( var k in key ) {
-                               jQuery.access( elems, k, key[k], exec, fn, value );
-                       }
-                       return elems;
-               }
-
-               // Setting one attribute
-               if ( value !== undefined ) {
-                       // Optionally, function values get executed if exec is true
-                       exec = !pass && exec && jQuery.isFunction(value);
-
-                       for ( var i = 0; i < length; i++ ) {
-                               fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
-                       }
-
-                       return elems;
-               }
-
-               // Getting an attribute
-               return length ? fn( elems[0], key ) : undefined;
-       },
-
-       now: function() {
-               return (new Date()).getTime();
-       },
-
-       // Use of jQuery.browser is frowned upon.
-       // More details: http://docs.jquery.com/Utilities/jQuery.browser
-       uaMatch: function( ua ) {
-               ua = ua.toLowerCase();
-
-               var match = rwebkit.exec( ua ) ||
-                       ropera.exec( ua ) ||
-                       rmsie.exec( ua ) ||
-                       ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
-                       [];
-
-               return { browser: match[1] || "", version: match[2] || "0" };
-       },
-
-       sub: function() {
-               function jQuerySubclass( selector, context ) {
-                       return new jQuerySubclass.fn.init( selector, context );
-               }
-               jQuery.extend( true, jQuerySubclass, this );
-               jQuerySubclass.superclass = this;
-               jQuerySubclass.fn = jQuerySubclass.prototype = this();
-               jQuerySubclass.fn.constructor = jQuerySubclass;
-               jQuerySubclass.subclass = this.subclass;
-               jQuerySubclass.fn.init = function init( selector, context ) {
-                       if ( context && context instanceof jQuery && !(context instanceof jQuerySubclass) ) {
-                               context = jQuerySubclass(context);
-                       }
-
-                       return jQuery.fn.init.call( this, selector, context, rootjQuerySubclass );
-               };
-               jQuerySubclass.fn.init.prototype = jQuerySubclass.fn;
-               var rootjQuerySubclass = jQuerySubclass(document);
-               return jQuerySubclass;
-       },
-
-       browser: {}
-});
-
-// Populate the class2type map
-jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
-       class2type[ "[object " + name + "]" ] = name.toLowerCase();
-});
-
-browserMatch = jQuery.uaMatch( userAgent );
-if ( browserMatch.browser ) {
-       jQuery.browser[ browserMatch.browser ] = true;
-       jQuery.browser.version = browserMatch.version;
-}
-
-// Deprecated, use jQuery.browser.webkit instead
-if ( jQuery.browser.webkit ) {
-       jQuery.browser.safari = true;
-}
-
-if ( indexOf ) {
-       jQuery.inArray = function( elem, array ) {
-               return indexOf.call( array, elem );
-       };
-}
-
-// IE doesn't match non-breaking spaces with \s
-if ( rnotwhite.test( "\xA0" ) ) {
-       trimLeft = /^[\s\xA0]+/;
-       trimRight = /[\s\xA0]+$/;
-}
-
-// All jQuery objects should point back to these
-rootjQuery = jQuery(document);
-
-// Cleanup functions for the document ready method
-if ( document.addEventListener ) {
-       DOMContentLoaded = function() {
-               document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
-               jQuery.ready();
-       };
-
-} else if ( document.attachEvent ) {
-       DOMContentLoaded = function() {
-               // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
-               if ( document.readyState === "complete" ) {
-                       document.detachEvent( "onreadystatechange", DOMContentLoaded );
-                       jQuery.ready();
-               }
-       };
-}
-
-// The DOM ready check for Internet Explorer
-function doScrollCheck() {
-       if ( jQuery.isReady ) {
-               return;
-       }
-
-       try {
-               // If IE is used, use the trick by Diego Perini
-               // http://javascript.nwbox.com/IEContentLoaded/
-               document.documentElement.doScroll("left");
-       } catch(e) {
-               setTimeout( doScrollCheck, 1 );
-               return;
-       }
-
-       // and execute any waiting functions
-       jQuery.ready();
-}
-
-// Expose jQuery to the global object
-return jQuery;
-
-})();
-
-
-var // Promise methods
-       promiseMethods = "then done fail isResolved isRejected promise".split( " " ),
-       // Static reference to slice
-       sliceDeferred = [].slice;
-
-jQuery.extend({
-       // Create a simple deferred (one callbacks list)
-       _Deferred: function() {
-               var // callbacks list
-                       callbacks = [],
-                       // stored [ context , args ]
-                       fired,
-                       // to avoid firing when already doing so
-                       firing,
-                       // flag to know if the deferred has been cancelled
-                       cancelled,
-                       // the deferred itself
-                       deferred  = {
-
-                               // done( f1, f2, ...)
-                               done: function() {
-                                       if ( !cancelled ) {
-                                               var args = arguments,
-                                                       i,
-                                                       length,
-                                                       elem,
-                                                       type,
-                                                       _fired;
-                                               if ( fired ) {
-                                                       _fired = fired;
-                                                       fired = 0;
-                                               }
-                                               for ( i = 0, length = args.length; i < length; i++ ) {
-                                                       elem = args[ i ];
-                                                       type = jQuery.type( elem );
-                                                       if ( type === "array" ) {
-                                                               deferred.done.apply( deferred, elem );
-                                                       } else if ( type === "function" ) {
-                                                               callbacks.push( elem );
-                                                       }
-                                               }
-                                               if ( _fired ) {
-                                                       deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
-                                               }
-                                       }
-                                       return this;
-                               },
-
-                               // resolve with given context and args
-                               resolveWith: function( context, args ) {
-                                       if ( !cancelled && !fired && !firing ) {
-                                               // make sure args are available (#8421)
-                                               args = args || [];
-                                               firing = 1;
-                                               try {
-                                                       while( callbacks[ 0 ] ) {
-                                                               callbacks.shift().apply( context, args );
-                                                       }
-                                               }
-                                               finally {
-                                                       fired = [ context, args ];
-                                                       firing = 0;
-                                               }
-                                       }
-                                       return this;
-                               },
-
-                               // resolve with this as context and given arguments
-                               resolve: function() {
-                                       deferred.resolveWith( this, arguments );
-                                       return this;
-                               },
-
-                               // Has this deferred been resolved?
-                               isResolved: function() {
-                                       return !!( firing || fired );
-                               },
-
-                               // Cancel
-                               cancel: function() {
-                                       cancelled = 1;
-                                       callbacks = [];
-                                       return this;
-                               }
-                       };
-
-               return deferred;
-       },
-
-       // Full fledged deferred (two callbacks list)
-       Deferred: function( func ) {
-               var deferred = jQuery._Deferred(),
-                       failDeferred = jQuery._Deferred(),
-                       promise;
-               // Add errorDeferred methods, then and promise
-               jQuery.extend( deferred, {
-                       then: function( doneCallbacks, failCallbacks ) {
-                               deferred.done( doneCallbacks ).fail( failCallbacks );
-                               return this;
-                       },
-                       fail: failDeferred.done,
-                       rejectWith: failDeferred.resolveWith,
-                       reject: failDeferred.resolve,
-                       isRejected: failDeferred.isResolved,
-                       // Get a promise for this deferred
-                       // If obj is provided, the promise aspect is added to the object
-                       promise: function( obj ) {
-                               if ( obj == null ) {
-                                       if ( promise ) {
-                                               return promise;
-                                       }
-                                       promise = obj = {};
-                               }
-                               var i = promiseMethods.length;
-                               while( i-- ) {
-                                       obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ];
-                               }
-                               return obj;
-                       }
-               } );
-               // Make sure only one callback list will be used
-               deferred.done( failDeferred.cancel ).fail( deferred.cancel );
-               // Unexpose cancel
-               delete deferred.cancel;
-               // Call given func if any
-               if ( func ) {
-                       func.call( deferred, deferred );
-               }
-               return deferred;
-       },
-
-       // Deferred helper
-       when: function( firstParam ) {
-               var args = arguments,
-                       i = 0,
-                       length = args.length,
-                       count = length,
-                       deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?
-                               firstParam :
-                               jQuery.Deferred();
-               function resolveFunc( i ) {
-                       return function( value ) {
-                               args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
-                               if ( !( --count ) ) {
-                                       // Strange bug in FF4:
-                                       // Values changed onto the arguments object sometimes end up as undefined values
-                                       // outside the $.when method. Cloning the object into a fresh array solves the issue
-                                       deferred.resolveWith( deferred, sliceDeferred.call( args, 0 ) );
-                               }
-                       };
-               }
-               if ( length > 1 ) {
-                       for( ; i < length; i++ ) {
-                               if ( args[ i ] && jQuery.isFunction( args[ i ].promise ) ) {
-                                       args[ i ].promise().then( resolveFunc(i), deferred.reject );
-                               } else {
-                                       --count;
-                               }
-                       }
-                       if ( !count ) {
-                               deferred.resolveWith( deferred, args );
-                       }
-               } else if ( deferred !== firstParam ) {
-                       deferred.resolveWith( deferred, length ? [ firstParam ] : [] );
-               }
-               return deferred.promise();
-       }
-});
-
-
-
-
-(function() {
-
-       jQuery.support = {};
-
-       var div = document.createElement("div");
-
-       div.style.display = "none";
-       div.innerHTML = "   <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
-
-       var all = div.getElementsByTagName("*"),
-               a = div.getElementsByTagName("a")[0],
-               select = document.createElement("select"),
-               opt = select.appendChild( document.createElement("option") ),
-               input = div.getElementsByTagName("input")[0];
-
-       // Can't get basic test support
-       if ( !all || !all.length || !a ) {
-               return;
-       }
-
-       jQuery.support = {
-               // IE strips leading whitespace when .innerHTML is used
-               leadingWhitespace: div.firstChild.nodeType === 3,
-
-               // Make sure that tbody elements aren't automatically inserted
-               // IE will insert them into empty tables
-               tbody: !div.getElementsByTagName("tbody").length,
-
-               // Make sure that link elements get serialized correctly by innerHTML
-               // This requires a wrapper element in IE
-               htmlSerialize: !!div.getElementsByTagName("link").length,
-
-               // Get the style information from getAttribute
-               // (IE uses .cssText insted)
-               style: /red/.test( a.getAttribute("style") ),
-
-               // Make sure that URLs aren't manipulated
-               // (IE normalizes it by default)
-               hrefNormalized: a.getAttribute("href") === "/a",
-
-               // Make sure that element opacity exists
-               // (IE uses filter instead)
-               // Use a regex to work around a WebKit issue. See #5145
-               opacity: /^0.55$/.test( a.style.opacity ),
-
-               // Verify style float existence
-               // (IE uses styleFloat instead of cssFloat)
-               cssFloat: !!a.style.cssFloat,
-
-               // Make sure that if no value is specified for a checkbox
-               // that it defaults to "on".
-               // (WebKit defaults to "" instead)
-               checkOn: input.value === "on",
-
-               // Make sure that a selected-by-default option has a working selected property.
-               // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
-               optSelected: opt.selected,
-
-               // Will be defined later
-               deleteExpando: true,
-               optDisabled: false,
-               checkClone: false,
-               noCloneEvent: true,
-               noCloneChecked: true,
-               boxModel: null,
-               inlineBlockNeedsLayout: false,
-               shrinkWrapBlocks: false,
-               reliableHiddenOffsets: true,
-               reliableMarginRight: true
-       };
-
-       input.checked = true;
-       jQuery.support.noCloneChecked = input.cloneNode( true ).checked;
-
-       // Make sure that the options inside disabled selects aren't marked as disabled
-       // (WebKit marks them as diabled)
-       select.disabled = true;
-       jQuery.support.optDisabled = !opt.disabled;
-
-       var _scriptEval = null;
-       jQuery.support.scriptEval = function() {
-               if ( _scriptEval === null ) {
-                       var root = document.documentElement,
-                               script = document.createElement("script"),
-                               id = "script" + jQuery.now();
-
-                       // Make sure that the execution of code works by injecting a script
-                       // tag with appendChild/createTextNode
-                       // (IE doesn't support this, fails, and uses .text instead)
-                       try {
-                               script.appendChild( document.createTextNode( "window." + id + "=1;" ) );
-                       } catch(e) {}
-
-                       root.insertBefore( script, root.firstChild );
-
-                       if ( window[ id ] ) {
-                               _scriptEval = true;
-                               delete window[ id ];
-                       } else {
-                               _scriptEval = false;
-                       }
-
-                       root.removeChild( script );
-               }
-
-               return _scriptEval;
-       };
-
-       // Test to see if it's possible to delete an expando from an element
-       // Fails in Internet Explorer
-       try {
-               delete div.test;
-
-       } catch(e) {
-               jQuery.support.deleteExpando = false;
-       }
-
-       if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
-               div.attachEvent("onclick", function click() {
-                       // Cloning a node shouldn't copy over any
-                       // bound event handlers (IE does this)
-                       jQuery.support.noCloneEvent = false;
-                       div.detachEvent("onclick", click);
-               });
-               div.cloneNode(true).fireEvent("onclick");
-       }
-
-       div = document.createElement("div");
-       div.innerHTML = "<input type='radio' name='radiotest' checked='checked'/>";
-
-       var fragment = document.createDocumentFragment();
-       fragment.appendChild( div.firstChild );
-
-       // WebKit doesn't clone checked state correctly in fragments
-       jQuery.support.checkClone = fragment.cloneNode(true).cloneNode(true).lastChild.checked;
-
-       // Figure out if the W3C box model works as expected
-       // document.body must exist before we can do this
-       jQuery(function() {
-               var div = document.createElement("div"),
-                       body = document.getElementsByTagName("body")[0];
-
-               // Frameset documents with no body should not run this code
-               if ( !body ) {
-                       return;
-               }
-
-               div.style.width = div.style.paddingLeft = "1px";
-               body.appendChild( div );
-               jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2;
-
-               if ( "zoom" in div.style ) {
-                       // Check if natively block-level elements act like inline-block
-                       // elements when setting their display to 'inline' and giving
-                       // them layout
-                       // (IE < 8 does this)
-                       div.style.display = "inline";
-                       div.style.zoom = 1;
-                       jQuery.support.inlineBlockNeedsLayout = div.offsetWidth === 2;
-
-                       // Check if elements with layout shrink-wrap their children
-                       // (IE 6 does this)
-                       div.style.display = "";
-                       div.innerHTML = "<div style='width:4px;'></div>";
-                       jQuery.support.shrinkWrapBlocks = div.offsetWidth !== 2;
-               }
-
-               div.innerHTML = "<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>";
-               var tds = div.getElementsByTagName("td");
-
-               // Check if table cells still have offsetWidth/Height when they are set
-               // to display:none and there are still other visible table cells in a
-               // table row; if so, offsetWidth/Height are not reliable for use when
-               // determining if an element has been hidden directly using
-               // display:none (it is still safe to use offsets if a parent element is
-               // hidden; don safety goggles and see bug #4512 for more information).
-               // (only IE 8 fails this test)
-               jQuery.support.reliableHiddenOffsets = tds[0].offsetHeight === 0;
-
-               tds[0].style.display = "";
-               tds[1].style.display = "none";
-
-               // Check if empty table cells still have offsetWidth/Height
-               // (IE < 8 fail this test)
-               jQuery.support.reliableHiddenOffsets = jQuery.support.reliableHiddenOffsets && tds[0].offsetHeight === 0;
-               div.innerHTML = "";
-
-               // Check if div with explicit width and no margin-right incorrectly
-               // gets computed margin-right based on width of container. For more
-               // info see bug #3333
-               // Fails in WebKit before Feb 2011 nightlies
-               // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
-               if ( document.defaultView && document.defaultView.getComputedStyle ) {
-                       div.style.width = "1px";
-                       div.style.marginRight = "0";
-                       jQuery.support.reliableMarginRight = ( parseInt(document.defaultView.getComputedStyle(div, null).marginRight, 10) || 0 ) === 0;
-               }
-
-               body.removeChild( div ).style.display = "none";
-               div = tds = null;
-       });
-
-       // Technique from Juriy Zaytsev
-       // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
-       var eventSupported = function( eventName ) {
-               var el = document.createElement("div");
-               eventName = "on" + eventName;
-
-               // We only care about the case where non-standard event systems
-               // are used, namely in IE. Short-circuiting here helps us to
-               // avoid an eval call (in setAttribute) which can cause CSP
-               // to go haywire. See: https://developer.mozilla.org/en/Security/CSP
-               if ( !el.attachEvent ) {
-                       return true;
-               }
-
-               var isSupported = (eventName in el);
-               if ( !isSupported ) {
-                       el.setAttribute(eventName, "return;");
-                       isSupported = typeof el[eventName] === "function";
-               }
-               return isSupported;
-       };
-
-       jQuery.support.submitBubbles = eventSupported("submit");
-       jQuery.support.changeBubbles = eventSupported("change");
-
-       // release memory in IE
-       div = all = a = null;
-})();
-
-
-
-var rbrace = /^(?:\{.*\}|\[.*\])$/;
-
-jQuery.extend({
-       cache: {},
-
-       // Please use with caution
-       uuid: 0,
-
-       // Unique for each copy of jQuery on the page
-       // Non-digits removed to match rinlinejQuery
-       expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
-
-       // The following elements throw uncatchable exceptions if you
-       // attempt to add expando properties to them.
-       noData: {
-               "embed": true,
-               // Ban all objects except for Flash (which handle expandos)
-               "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
-               "applet": true
-       },
-
-       hasData: function( elem ) {
-               elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
-
-               return !!elem && !isEmptyDataObject( elem );
-       },
-
-       data: function( elem, name, data, pvt /* Internal Use Only */ ) {
-               if ( !jQuery.acceptData( elem ) ) {
-                       return;
-               }
-
-               var internalKey = jQuery.expando, getByName = typeof name === "string", thisCache,
-
-                       // We have to handle DOM nodes and JS objects differently because IE6-7
-                       // can't GC object references properly across the DOM-JS boundary
-                       isNode = elem.nodeType,
-
-                       // Only DOM nodes need the global jQuery cache; JS object data is
-                       // attached directly to the object so GC can occur automatically
-                       cache = isNode ? jQuery.cache : elem,
-
-                       // Only defining an ID for JS objects if its cache already exists allows
-                       // the code to shortcut on the same path as a DOM node with no cache
-                       id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando;
-
-               // Avoid doing any more work than we need to when trying to get data on an
-               // object that has no data at all
-               if ( (!id || (pvt && id && !cache[ id ][ internalKey ])) && getByName && data === undefined ) {
-                       return;
-               }
-
-               if ( !id ) {
-                       // Only DOM nodes need a new unique ID for each element since their data
-                       // ends up in the global cache
-                       if ( isNode ) {
-                               elem[ jQuery.expando ] = id = ++jQuery.uuid;
-                       } else {
-                               id = jQuery.expando;
-                       }
-               }
-
-               if ( !cache[ id ] ) {
-                       cache[ id ] = {};
-
-                       // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery
-                       // metadata on plain JS objects when the object is serialized using
-                       // JSON.stringify
-                       if ( !isNode ) {
-                               cache[ id ].toJSON = jQuery.noop;
-                       }
-               }
-
-               // An object can be passed to jQuery.data instead of a key/value pair; this gets
-               // shallow copied over onto the existing cache
-               if ( typeof name === "object" || typeof name === "function" ) {
-                       if ( pvt ) {
-                               cache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name);
-                       } else {
-                               cache[ id ] = jQuery.extend(cache[ id ], name);
-                       }
-               }
-
-               thisCache = cache[ id ];
-
-               // Internal jQuery data is stored in a separate object inside the object's data
-               // cache in order to avoid key collisions between internal data and user-defined
-               // data
-               if ( pvt ) {
-                       if ( !thisCache[ internalKey ] ) {
-                               thisCache[ internalKey ] = {};
-                       }
-
-                       thisCache = thisCache[ internalKey ];
-               }
-
-               if ( data !== undefined ) {
-                       thisCache[ name ] = data;
-               }
-
-               // TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should
-               // not attempt to inspect the internal events object using jQuery.data, as this
-               // internal data object is undocumented and subject to change.
-               if ( name === "events" && !thisCache[name] ) {
-                       return thisCache[ internalKey ] && thisCache[ internalKey ].events;
-               }
-
-               return getByName ? thisCache[ name ] : thisCache;
-       },
-
-       removeData: function( elem, name, pvt /* Internal Use Only */ ) {
-               if ( !jQuery.acceptData( elem ) ) {
-                       return;
-               }
-
-               var internalKey = jQuery.expando, isNode = elem.nodeType,
-
-                       // See jQuery.data for more information
-                       cache = isNode ? jQuery.cache : elem,
-
-                       // See jQuery.data for more information
-                       id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
-
-               // If there is already no cache entry for this object, there is no
-               // purpose in continuing
-               if ( !cache[ id ] ) {
-                       return;
-               }
-
-               if ( name ) {
-                       var thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ];
-
-                       if ( thisCache ) {
-                               delete thisCache[ name ];
-
-                               // If there is no data left in the cache, we want to continue
-                               // and let the cache object itself get destroyed
-                               if ( !isEmptyDataObject(thisCache) ) {
-                                       return;
-                               }
-                       }
-               }
-
-               // See jQuery.data for more information
-               if ( pvt ) {
-                       delete cache[ id ][ internalKey ];
-
-                       // Don't destroy the parent cache unless the internal data object
-                       // had been the only thing left in it
-                       if ( !isEmptyDataObject(cache[ id ]) ) {
-                               return;
-                       }
-               }
-
-               var internalCache = cache[ id ][ internalKey ];
-
-               // Browsers that fail expando deletion also refuse to delete expandos on
-               // the window, but it will allow it on all other JS objects; other browsers
-               // don't care
-               if ( jQuery.support.deleteExpando || cache != window ) {
-                       delete cache[ id ];
-               } else {
-                       cache[ id ] = null;
-               }
-
-               // We destroyed the entire user cache at once because it's faster than
-               // iterating through each key, but we need to continue to persist internal
-               // data if it existed
-               if ( internalCache ) {
-                       cache[ id ] = {};
-                       // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery
-                       // metadata on plain JS objects when the object is serialized using
-                       // JSON.stringify
-                       if ( !isNode ) {
-                               cache[ id ].toJSON = jQuery.noop;
-                       }
-
-                       cache[ id ][ internalKey ] = internalCache;
-
-               // Otherwise, we need to eliminate the expando on the node to avoid
-               // false lookups in the cache for entries that no longer exist
-               } else if ( isNode ) {
-                       // IE does not allow us to delete expando properties from nodes,
-                       // nor does it have a removeAttribute function on Document nodes;
-                       // we must handle all of these cases
-                       if ( jQuery.support.deleteExpando ) {
-                               delete elem[ jQuery.expando ];
-                       } else if ( elem.removeAttribute ) {
-                               elem.removeAttribute( jQuery.expando );
-                       } else {
-                               elem[ jQuery.expando ] = null;
-                       }
-               }
-       },
-
-       // For internal use only.
-       _data: function( elem, name, data ) {
-               return jQuery.data( elem, name, data, true );
-       },
-
-       // A method for determining if a DOM node can handle the data expando
-       acceptData: function( elem ) {
-               if ( elem.nodeName ) {
-                       var match = jQuery.noData[ elem.nodeName.toLowerCase() ];
-
-                       if ( match ) {
-                               return !(match === true || elem.getAttribute("classid") !== match);
-                       }
-               }
-
-               return true;
-       }
-});
-
-jQuery.fn.extend({
-       data: function( key, value ) {
-               var data = null;
-
-               if ( typeof key === "undefined" ) {
-                       if ( this.length ) {
-                               data = jQuery.data( this[0] );
-
-                               if ( this[0].nodeType === 1 ) {
-                                       var attr = this[0].attributes, name;
-                                       for ( var i = 0, l = attr.length; i < l; i++ ) {
-                                               name = attr[i].name;
-
-                                               if ( name.indexOf( "data-" ) === 0 ) {
-                                                       name = name.substr( 5 );
-                                                       dataAttr( this[0], name, data[ name ] );
-                                               }
-                                       }
-                               }
-                       }
-
-                       return data;
-
-               } else if ( typeof key === "object" ) {
-                       return this.each(function() {
-                               jQuery.data( this, key );
-                       });
-               }
-
-               var parts = key.split(".");
-               parts[1] = parts[1] ? "." + parts[1] : "";
-
-               if ( value === undefined ) {
-                       data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
-
-                       // Try to fetch any internally stored data first
-                       if ( data === undefined && this.length ) {
-                               data = jQuery.data( this[0], key );
-                               data = dataAttr( this[0], key, data );
-                       }
-
-                       return data === undefined && parts[1] ?
-                               this.data( parts[0] ) :
-                               data;
-
-               } else {
-                       return this.each(function() {
-                               var $this = jQuery( this ),
-                                       args = [ parts[0], value ];
-
-                               $this.triggerHandler( "setData" + parts[1] + "!", args );
-                               jQuery.data( this, key, value );
-                               $this.triggerHandler( "changeData" + parts[1] + "!", args );
-                       });
-               }
-       },
-
-       removeData: function( key ) {
-               return this.each(function() {
-                       jQuery.removeData( this, key );
-               });
-       }
-});
-
-function dataAttr( elem, key, data ) {
-       // If nothing was found internally, try to fetch any
-       // data from the HTML5 data-* attribute
-       if ( data === undefined && elem.nodeType === 1 ) {
-               data = elem.getAttribute( "data-" + key );
-
-               if ( typeof data === "string" ) {
-                       try {
-                               data = data === "true" ? true :
-                               data === "false" ? false :
-                               data === "null" ? null :
-                               !jQuery.isNaN( data ) ? parseFloat( data ) :
-                                       rbrace.test( data ) ? jQuery.parseJSON( data ) :
-                                       data;
-                       } catch( e ) {}
-
-                       // Make sure we set the data so it isn't changed later
-                       jQuery.data( elem, key, data );
-
-               } else {
-                       data = undefined;
-               }
-       }
-
-       return data;
-}
-
-// TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON
-// property to be considered empty objects; this property always exists in
-// order to make sure JSON.stringify does not expose internal metadata
-function isEmptyDataObject( obj ) {
-       for ( var name in obj ) {
-               if ( name !== "toJSON" ) {
-                       return false;
-               }
-       }
-
-       return true;
-}
-
-
-
-
-jQuery.extend({
-       queue: function( elem, type, data ) {
-               if ( !elem ) {
-                       return;
-               }
-
-               type = (type || "fx") + "queue";
-               var q = jQuery._data( elem, type );
-
-               // Speed up dequeue by getting out quickly if this is just a lookup
-               if ( !data ) {
-                       return q || [];
-               }
-
-               if ( !q || jQuery.isArray(data) ) {
-                       q = jQuery._data( elem, type, jQuery.makeArray(data) );
-
-               } else {
-                       q.push( data );
-               }
-
-               return q;
-       },
-
-       dequeue: function( elem, type ) {
-               type = type || "fx";
-
-               var queue = jQuery.queue( elem, type ),
-                       fn = queue.shift();
-
-               // If the fx queue is dequeued, always remove the progress sentinel
-               if ( fn === "inprogress" ) {
-                       fn = queue.shift();
-               }
-
-               if ( fn ) {
-                       // Add a progress sentinel to prevent the fx queue from being
-                       // automatically dequeued
-                       if ( type === "fx" ) {
-                               queue.unshift("inprogress");
-                       }
-
-                       fn.call(elem, function() {
-                               jQuery.dequeue(elem, type);
-                       });
-               }
-
-               if ( !queue.length ) {
-                       jQuery.removeData( elem, type + "queue", true );
-               }
-       }
-});
-
-jQuery.fn.extend({
-       queue: function( type, data ) {
-               if ( typeof type !== "string" ) {
-                       data = type;
-                       type = "fx";
-               }
-
-               if ( data === undefined ) {
-                       return jQuery.queue( this[0], type );
-               }
-               return this.each(function( i ) {
-                       var queue = jQuery.queue( this, type, data );
-
-                       if ( type === "fx" && queue[0] !== "inprogress" ) {
-                               jQuery.dequeue( this, type );
-                       }
-               });
-       },
-       dequeue: function( type ) {
-               return this.each(function() {
-                       jQuery.dequeue( this, type );
-               });
-       },
-
-       // Based off of the plugin by Clint Helfers, with permission.
-       // http://blindsignals.com/index.php/2009/07/jquery-delay/
-       delay: function( time, type ) {
-               time = jQuery.fx ? jQuery.fx.speeds[time] || time : time;
-               type = type || "fx";
-
-               return this.queue( type, function() {
-                       var elem = this;
-                       setTimeout(function() {
-                               jQuery.dequeue( elem, type );
-                       }, time );
-               });
-       },
-
-       clearQueue: function( type ) {
-               return this.queue( type || "fx", [] );
-       }
-});
-
-
-
-
-var rclass = /[\n\t\r]/g,
-       rspaces = /\s+/,
-       rreturn = /\r/g,
-       rspecialurl = /^(?:href|src|style)$/,
-       rtype = /^(?:button|input)$/i,
-       rfocusable = /^(?:button|input|object|select|textarea)$/i,
-       rclickable = /^a(?:rea)?$/i,
-       rradiocheck = /^(?:radio|checkbox)$/i;
-
-jQuery.props = {
-       "for": "htmlFor",
-       "class": "className",
-       readonly: "readOnly",
-       maxlength: "maxLength",
-       cellspacing: "cellSpacing",
-       rowspan: "rowSpan",
-       colspan: "colSpan",
-       tabindex: "tabIndex",
-       usemap: "useMap",
-       frameborder: "frameBorder"
-};
-
-jQuery.fn.extend({
-       attr: function( name, value ) {
-               return jQuery.access( this, name, value, true, jQuery.attr );
-       },
-
-       removeAttr: function( name, fn ) {
-               return this.each(function(){
-                       jQuery.attr( this, name, "" );
-                       if ( this.nodeType === 1 ) {
-                               this.removeAttribute( name );
-                       }
-               });
-       },
-
-       addClass: function( value ) {
-               if ( jQuery.isFunction(value) ) {
-                       return this.each(function(i) {
-                               var self = jQuery(this);
-                               self.addClass( value.call(this, i, self.attr("class")) );
-                       });
-               }
-
-               if ( value && typeof value === "string" ) {
-                       var classNames = (value || "").split( rspaces );
-
-                       for ( var i = 0, l = this.length; i < l; i++ ) {
-                               var elem = this[i];
-
-                               if ( elem.nodeType === 1 ) {
-                                       if ( !elem.className ) {
-                                               elem.className = value;
-
-                                       } else {
-                                               var className = " " + elem.className + " ",
-                                                       setClass = elem.className;
-
-                                               for ( var c = 0, cl = classNames.length; c < cl; c++ ) {
-                                                       if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) {
-                                                               setClass += " " + classNames[c];
-                                                       }
-                                               }
-                                               elem.className = jQuery.trim( setClass );
-                                       }
-                               }
-                       }
-               }
-
-               return this;
-       },
-
-       removeClass: function( value ) {
-               if ( jQuery.isFunction(value) ) {
-                       return this.each(function(i) {
-                               var self = jQuery(this);
-                               self.removeClass( value.call(this, i, self.attr("class")) );
-                       });
-               }
-
-               if ( (value && typeof value === "string") || value === undefined ) {
-                       var classNames = (value || "").split( rspaces );
-
-                       for ( var i = 0, l = this.length; i < l; i++ ) {
-                               var elem = this[i];
-
-                               if ( elem.nodeType === 1 && elem.className ) {
-                                       if ( value ) {
-                                               var className = (" " + elem.className + " ").replace(rclass, " ");
-                                               for ( var c = 0, cl = classNames.length; c < cl; c++ ) {
-                                                       className = className.replace(" " + classNames[c] + " ", " ");
-                                               }
-                                               elem.className = jQuery.trim( className );
-
-                                       } else {
-                                               elem.className = "";
-                                       }
-                               }
-                       }
-               }
-
-               return this;
-       },
-
-       toggleClass: function( value, stateVal ) {
-               var type = typeof value,
-                       isBool = typeof stateVal === "boolean";
-
-               if ( jQuery.isFunction( value ) ) {
-                       return this.each(function(i) {
-                               var self = jQuery(this);
-                               self.toggleClass( value.call(this, i, self.attr("class"), stateVal), stateVal );
-                       });
-               }
-
-               return this.each(function() {
-                       if ( type === "string" ) {
-                               // toggle individual class names
-                               var className,
-                                       i = 0,
-                                       self = jQuery( this ),
-                                       state = stateVal,
-                                       classNames = value.split( rspaces );
-
-                               while ( (className = classNames[ i++ ]) ) {
-                                       // check each className given, space seperated list
-                                       state = isBool ? state : !self.hasClass( className );
-                                       self[ state ? "addClass" : "removeClass" ]( className );
-                               }
-
-                       } else if ( type === "undefined" || type === "boolean" ) {
-                               if ( this.className ) {
-                                       // store className if set
-                                       jQuery._data( this, "__className__", this.className );
-                               }
-
-                               // toggle whole className
-                               this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
-                       }
-               });
-       },
-
-       hasClass: function( selector ) {
-               var className = " " + selector + " ";
-               for ( var i = 0, l = this.length; i < l; i++ ) {
-                       if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
-                               return true;
-                       }
-               }
-
-               return false;
-       },
-
-       val: function( value ) {
-               if ( !arguments.length ) {
-                       var elem = this[0];
-
-                       if ( elem ) {
-                               if ( jQuery.nodeName( elem, "option" ) ) {
-                                       // attributes.value is undefined in Blackberry 4.7 but
-                                       // uses .value. See #6932
-                                       var val = elem.attributes.value;
-                                       return !val || val.specified ? elem.value : elem.text;
-                               }
-
-                               // We need to handle select boxes special
-                               if ( jQuery.nodeName( elem, "select" ) ) {
-                                       var index = elem.selectedIndex,
-                                               values = [],
-                                               options = elem.options,
-                                               one = elem.type === "select-one";
-
-                                       // Nothing was selected
-                                       if ( index < 0 ) {
-                                               return null;
-                                       }
-
-                                       // Loop through all the selected options
-                                       for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
-                                               var option = options[ i ];
-
-                                               // Don't return options that are disabled or in a disabled optgroup
-                                               if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) &&
-                                                               (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) {
-
-                                                       // Get the specific value for the option
-                                                       value = jQuery(option).val();
-
-                                                       // We don't need an array for one selects
-                                                       if ( one ) {
-                                                               return value;
-                                                       }
-
-                                                       // Multi-Selects return an array
-                                                       values.push( value );
-                                               }
-                                       }
-
-                                       // Fixes Bug #2551 -- select.val() broken in IE after form.reset()
-                                       if ( one && !values.length && options.length ) {
-                                               return jQuery( options[ index ] ).val();
-                                       }
-
-                                       return values;
-                               }
-
-                               // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
-                               if ( rradiocheck.test( elem.type ) && !jQuery.support.checkOn ) {
-                                       return elem.getAttribute("value") === null ? "on" : elem.value;
-                               }
-
-                               // Everything else, we just grab the value
-                               return (elem.value || "").replace(rreturn, "");
-
-                       }
-
-                       return undefined;
-               }
-
-               var isFunction = jQuery.isFunction(value);
-
-               return this.each(function(i) {
-                       var self = jQuery(this), val = value;
-
-                       if ( this.nodeType !== 1 ) {
-                               return;
-                       }
-
-                       if ( isFunction ) {
-                               val = value.call(this, i, self.val());
-                       }
-
-                       // Treat null/undefined as ""; convert numbers to string
-                       if ( val == null ) {
-                               val = "";
-                       } else if ( typeof val === "number" ) {
-                               val += "";
-                       } else if ( jQuery.isArray(val) ) {
-                               val = jQuery.map(val, function (value) {
-                                       return value == null ? "" : value + "";
-                               });
-                       }
-
-                       if ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) {
-                               this.checked = jQuery.inArray( self.val(), val ) >= 0;
-
-                       } else if ( jQuery.nodeName( this, "select" ) ) {
-                               var values = jQuery.makeArray(val);
-
-                               jQuery( "option", this ).each(function() {
-                                       this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
-                               });
-
-                               if ( !values.length ) {
-                                       this.selectedIndex = -1;
-                               }
-
-                       } else {
-                               this.value = val;
-                       }
-               });
-       }
-});
-
-jQuery.extend({
-       attrFn: {
-               val: true,
-               css: true,
-               html: true,
-               text: true,
-               data: true,
-               width: true,
-               height: true,
-               offset: true
-       },
-
-       attr: function( elem, name, value, pass ) {
-               // don't get/set attributes on text, comment and attribute nodes
-               if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || elem.nodeType === 2 ) {
-                       return undefined;
-               }
-
-               if ( pass && name in jQuery.attrFn ) {
-                       return jQuery(elem)[name](value);
-               }
-
-               var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ),
-                       // Whether we are setting (or getting)
-                       set = value !== undefined;
-
-               // Try to normalize/fix the name
-               name = notxml && jQuery.props[ name ] || name;
-
-               // Only do all the following if this is a node (faster for style)
-               if ( elem.nodeType === 1 ) {
-                       // These attributes require special treatment
-                       var special = rspecialurl.test( name );
-
-                       // Safari mis-reports the default selected property of an option
-                       // Accessing the parent's selectedIndex property fixes it
-                       if ( name === "selected" && !jQuery.support.optSelected ) {
-                               var parent = elem.parentNode;
-                               if ( parent ) {
-                                       parent.selectedIndex;
-
-                                       // Make sure that it also works with optgroups, see #5701
-                                       if ( parent.parentNode ) {
-                                               parent.parentNode.selectedIndex;
-                                       }
-                               }
-                       }
-
-                       // If applicable, access the attribute via the DOM 0 way
-                       // 'in' checks fail in Blackberry 4.7 #6931
-                       if ( (name in elem || elem[ name ] !== undefined) && notxml && !special ) {
-                               if ( set ) {
-                                       // We can't allow the type property to be changed (since it causes problems in IE)
-                                       if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) {
-                                               jQuery.error( "type property can't be changed" );
-                                       }
-
-                                       if ( value === null ) {
-                                               if ( elem.nodeType === 1 ) {
-                                                       elem.removeAttribute( name );
-                                               }
-
-                                       } else {
-                                               elem[ name ] = value;
-                                       }
-                               }
-
-                               // browsers index elements by id/name on forms, give priority to attributes.
-                               if ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) {
-                                       return elem.getAttributeNode( name ).nodeValue;
-                               }
-
-                               // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
-                               // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
-                               if ( name === "tabIndex" ) {
-                                       var attributeNode = elem.getAttributeNode( "tabIndex" );
-
-                                       return attributeNode && attributeNode.specified ?
-                                               attributeNode.value :
-                                               rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
-                                                       0 :
-                                                       undefined;
-                               }
-
-                               return elem[ name ];
-                       }
-
-                       if ( !jQuery.support.style && notxml && name === "style" ) {
-                               if ( set ) {
-                                       elem.style.cssText = "" + value;
-                               }
-
-                               return elem.style.cssText;
-                       }
-
-                       if ( set ) {
-                               // convert the value to a string (all browsers do this but IE) see #1070
-                               elem.setAttribute( name, "" + value );
-                       }
-
-                       // Ensure that missing attributes return undefined
-                       // Blackberry 4.7 returns "" from getAttribute #6938
-                       if ( !elem.attributes[ name ] && (elem.hasAttribute && !elem.hasAttribute( name )) ) {
-                               return undefined;
-                       }
-
-                       var attr = !jQuery.support.hrefNormalized && notxml && special ?
-                                       // Some attributes require a special call on IE
-                                       elem.getAttribute( name, 2 ) :
-                                       elem.getAttribute( name );
-
-                       // Non-existent attributes return null, we normalize to undefined
-                       return attr === null ? undefined : attr;
-               }
-               // Handle everything which isn't a DOM element node
-               if ( set ) {
-                       elem[ name ] = value;
-               }
-               return elem[ name ];
-       }
-});
-
-
-
-
-var rnamespaces = /\.(.*)$/,
-       rformElems = /^(?:textarea|input|select)$/i,
-       rperiod = /\./g,
-       rspace = / /g,
-       rescape = /[^\w\s.|`]/g,
-       fcleanup = function( nm ) {
-               return nm.replace(rescape, "\\$&");
-       };
-
-/*
- * A number of helper functions used for managing events.
- * Many of the ideas behind this code originated from
- * Dean Edwards' addEvent library.
- */
-jQuery.event = {
-
-       // Bind an event to an element
-       // Original by Dean Edwards
-       add: function( elem, types, handler, data ) {
-               if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
-                       return;
-               }
-
-               // TODO :: Use a try/catch until it's safe to pull this out (likely 1.6)
-               // Minor release fix for bug #8018
-               try {
-                       // For whatever reason, IE has trouble passing the window object
-                       // around, causing it to be cloned in the process
-                       if ( jQuery.isWindow( elem ) && ( elem !== window && !elem.frameElement ) ) {
-                               elem = window;
-                       }
-               }
-               catch ( e ) {}
-
-               if ( handler === false ) {
-                       handler = returnFalse;
-               } else if ( !handler ) {
-                       // Fixes bug #7229. Fix recommended by jdalton
-                       return;
-               }
-
-               var handleObjIn, handleObj;
-
-               if ( handler.handler ) {
-                       handleObjIn = handler;
-                       handler = handleObjIn.handler;
-               }
-
-               // Make sure that the function being executed has a unique ID
-               if ( !handler.guid ) {
-                       handler.guid = jQuery.guid++;
-               }
-
-               // Init the element's event structure
-               var elemData = jQuery._data( elem );
-
-               // If no elemData is found then we must be trying to bind to one of the
-               // banned noData elements
-               if ( !elemData ) {
-                       return;
-               }
-
-               var events = elemData.events,
-                       eventHandle = elemData.handle;
-
-               if ( !events ) {
-                       elemData.events = events = {};
-               }
-
-               if ( !eventHandle ) {
-                       elemData.handle = eventHandle = function( e ) {
-                               // Handle the second event of a trigger and when
-                               // an event is called after a page has unloaded
-                               return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ?
-                                       jQuery.event.handle.apply( eventHandle.elem, arguments ) :
-                                       undefined;
-                       };
-               }
-
-               // Add elem as a property of the handle function
-               // This is to prevent a memory leak with non-native events in IE.
-               eventHandle.elem = elem;
-
-               // Handle multiple events separated by a space
-               // jQuery(...).bind("mouseover mouseout", fn);
-               types = types.split(" ");
-
-               var type, i = 0, namespaces;
-
-               while ( (type = types[ i++ ]) ) {
-                       handleObj = handleObjIn ?
-                               jQuery.extend({}, handleObjIn) :
-                               { handler: handler, data: data };
-
-                       // Namespaced event handlers
-                       if ( type.indexOf(".") > -1 ) {
-                               namespaces = type.split(".");
-                               type = namespaces.shift();
-                               handleObj.namespace = namespaces.slice(0).sort().join(".");
-
-                       } else {
-                               namespaces = [];
-                               handleObj.namespace = "";
-                       }
-
-                       handleObj.type = type;
-                       if ( !handleObj.guid ) {
-                               handleObj.guid = handler.guid;
-                       }
-
-                       // Get the current list of functions bound to this event
-                       var handlers = events[ type ],
-                               special = jQuery.event.special[ type ] || {};
-
-                       // Init the event handler queue
-                       if ( !handlers ) {
-                               handlers = events[ type ] = [];
-
-                               // Check for a special event handler
-                               // Only use addEventListener/attachEvent if the special
-                               // events handler returns false
-                               if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
-                                       // Bind the global event handler to the element
-                                       if ( elem.addEventListener ) {
-                                               elem.addEventListener( type, eventHandle, false );
-
-                                       } else if ( elem.attachEvent ) {
-                                               elem.attachEvent( "on" + type, eventHandle );
-                                       }
-                               }
-                       }
-
-                       if ( special.add ) {
-                               special.add.call( elem, handleObj );
-
-                               if ( !handleObj.handler.guid ) {
-                                       handleObj.handler.guid = handler.guid;
-                               }
-                       }
-
-                       // Add the function to the element's handler list
-                       handlers.push( handleObj );
-
-                       // Keep track of which events have been used, for global triggering
-                       jQuery.event.global[ type ] = true;
-               }
-
-               // Nullify elem to prevent memory leaks in IE
-               elem = null;
-       },
-
-       global: {},
-
-       // Detach an event or set of events from an element
-       remove: function( elem, types, handler, pos ) {
-               // don't do events on text and comment nodes
-               if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
-                       return;
-               }
-
-               if ( handler === false ) {
-                       handler = returnFalse;
-               }
-
-               var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
-                       elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
-                       events = elemData && elemData.events;
-
-               if ( !elemData || !events ) {
-                       return;
-               }
-
-               // types is actually an event object here
-               if ( types && types.type ) {
-                       handler = types.handler;
-                       types = types.type;
-               }
-
-               // Unbind all events for the element
-               if ( !types || typeof types === "string" && types.charAt(0) === "." ) {
-                       types = types || "";
-
-                       for ( type in events ) {
-                               jQuery.event.remove( elem, type + types );
-                       }
-
-                       return;
-               }
-
-               // Handle multiple events separated by a space
-               // jQuery(...).unbind("mouseover mouseout", fn);
-               types = types.split(" ");
-
-               while ( (type = types[ i++ ]) ) {
-                       origType = type;
-                       handleObj = null;
-                       all = type.indexOf(".") < 0;
-                       namespaces = [];
-
-                       if ( !all ) {
-                               // Namespaced event handlers
-                               namespaces = type.split(".");
-                               type = namespaces.shift();
-
-                               namespace = new RegExp("(^|\\.)" +
-                                       jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)");
-                       }
-
-                       eventType = events[ type ];
-
-                       if ( !eventType ) {
-                               continue;
-                       }
-
-                       if ( !handler ) {
-                               for ( j = 0; j < eventType.length; j++ ) {
-                                       handleObj = eventType[ j ];
-
-                                       if ( all || namespace.test( handleObj.namespace ) ) {
-                                               jQuery.event.remove( elem, origType, handleObj.handler, j );
-                                               eventType.splice( j--, 1 );
-                                       }
-                               }
-
-                               continue;
-                       }
-
-                       special = jQuery.event.special[ type ] || {};
-
-                       for ( j = pos || 0; j < eventType.length; j++ ) {
-                               handleObj = eventType[ j ];
-
-                               if ( handler.guid === handleObj.guid ) {
-                                       // remove the given handler for the given type
-                                       if ( all || namespace.test( handleObj.namespace ) ) {
-                                               if ( pos == null ) {
-                                                       eventType.splice( j--, 1 );
-                                               }
-
-                                               if ( special.remove ) {
-                                                       special.remove.call( elem, handleObj );
-                                               }
-                                       }
-
-                                       if ( pos != null ) {
-                                               break;
-                                       }
-                               }
-                       }
-
-                       // remove generic event handler if no more handlers exist
-                       if ( eventType.length === 0 || pos != null && eventType.length === 1 ) {
-                               if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
-                                       jQuery.removeEvent( elem, type, elemData.handle );
-                               }
-
-                               ret = null;
-                               delete events[ type ];
-                       }
-               }
-
-               // Remove the expando if it's no longer used
-               if ( jQuery.isEmptyObject( events ) ) {
-                       var handle = elemData.handle;
-                       if ( handle ) {
-                               handle.elem = null;
-                       }
-
-                       delete elemData.events;
-                       delete elemData.handle;
-
-                       if ( jQuery.isEmptyObject( elemData ) ) {
-                               jQuery.removeData( elem, undefined, true );
-                       }
-               }
-       },
-
-       // bubbling is internal
-       trigger: function( event, data, elem /*, bubbling */ ) {
-               // Event object or event type
-               var type = event.type || event,
-                       bubbling = arguments[3];
-
-               if ( !bubbling ) {
-                       event = typeof event === "object" ?
-                               // jQuery.Event object
-                               event[ jQuery.expando ] ? event :
-                               // Object literal
-                               jQuery.extend( jQuery.Event(type), event ) :
-                               // Just the event type (string)
-                               jQuery.Event(type);
-
-                       if ( type.indexOf("!") >= 0 ) {
-                               event.type = type = type.slice(0, -1);
-                               event.exclusive = true;
-                       }
-
-                       // Handle a global trigger
-                       if ( !elem ) {
-                               // Don't bubble custom events when global (to avoid too much overhead)
-                               event.stopPropagation();
-
-                               // Only trigger if we've ever bound an event for it
-                               if ( jQuery.event.global[ type ] ) {
-                                       // XXX This code smells terrible. event.js should not be directly
-                                       // inspecting the data cache
-                                       jQuery.each( jQuery.cache, function() {
-                                               // internalKey variable is just used to make it easier to find
-                                               // and potentially change this stuff later; currently it just
-                                               // points to jQuery.expando
-                                               var internalKey = jQuery.expando,
-                                                       internalCache = this[ internalKey ];
-                                               if ( internalCache && internalCache.events && internalCache.events[ type ] ) {
-                                                       jQuery.event.trigger( event, data, internalCache.handle.elem );
-                                               }
-                                       });
-                               }
-                       }
-
-                       // Handle triggering a single element
-
-                       // don't do events on text and comment nodes
-                       if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
-                               return undefined;
-                       }
-
-                       // Clean up in case it is reused
-                       event.result = undefined;
-                       event.target = elem;
-
-                       // Clone the incoming data, if any
-                       data = jQuery.makeArray( data );
-                       data.unshift( event );
-               }
-
-               event.currentTarget = elem;
-
-               // Trigger the event, it is assumed that "handle" is a function
-               var handle = jQuery._data( elem, "handle" );
-
-               if ( handle ) {
-                       handle.apply( elem, data );
-               }
-
-               var parent = elem.parentNode || elem.ownerDocument;
-
-               // Trigger an inline bound script
-               try {
-                       if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {
-                               if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) {
-                                       event.result = false;
-                                       event.preventDefault();
-                               }
-                       }
-
-               // prevent IE from throwing an error for some elements with some event types, see #3533
-               } catch (inlineError) {}
-
-               if ( !event.isPropagationStopped() && parent ) {
-                       jQuery.event.trigger( event, data, parent, true );
-
-               } else if ( !event.isDefaultPrevented() ) {
-                       var old,
-                               target = event.target,
-                               targetType = type.replace( rnamespaces, "" ),
-                               isClick = jQuery.nodeName( target, "a" ) && targetType === "click",
-                               special = jQuery.event.special[ targetType ] || {};
-
-                       if ( (!special._default || special._default.call( elem, event ) === false) &&
-                               !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {
-
-                               try {
-                                       if ( target[ targetType ] ) {
-                                               // Make sure that we don't accidentally re-trigger the onFOO events
-                                               old = target[ "on" + targetType ];
-
-                                               if ( old ) {
-                                                       target[ "on" + targetType ] = null;
-                                               }
-
-                                               jQuery.event.triggered = event.type;
-                                               target[ targetType ]();
-                                       }
-
-                               // prevent IE from throwing an error for some elements with some event types, see #3533
-                               } catch (triggerError) {}
-
-                               if ( old ) {
-                                       target[ "on" + targetType ] = old;
-                               }
-
-                               jQuery.event.triggered = undefined;
-                       }
-               }
-       },
-
-       handle: function( event ) {
-               var all, handlers, namespaces, namespace_re, events,
-                       namespace_sort = [],
-                       args = jQuery.makeArray( arguments );
-
-               event = args[0] = jQuery.event.fix( event || window.event );
-               event.currentTarget = this;
-
-               // Namespaced event handlers
-               all = event.type.indexOf(".") < 0 && !event.exclusive;
-
-               if ( !all ) {
-                       namespaces = event.type.split(".");
-                       event.type = namespaces.shift();
-                       namespace_sort = namespaces.slice(0).sort();
-                       namespace_re = new RegExp("(^|\\.)" + namespace_sort.join("\\.(?:.*\\.)?") + "(\\.|$)");
-               }
-
-               event.namespace = event.namespace || namespace_sort.join(".");
-
-               events = jQuery._data(this, "events");
-
-               handlers = (events || {})[ event.type ];
-
-               if ( events && handlers ) {
-                       // Clone the handlers to prevent manipulation
-                       handlers = handlers.slice(0);
-
-                       for ( var j = 0, l = handlers.length; j < l; j++ ) {
-                               var handleObj = handlers[ j ];
-
-                               // Filter the functions by class
-                               if ( all || namespace_re.test( handleObj.namespace ) ) {
-                                       // Pass in a reference to the handler function itself
-                                       // So that we can later remove it
-                                       event.handler = handleObj.handler;
-                                       event.data = handleObj.data;
-                                       event.handleObj = handleObj;
-
-                                       var ret = handleObj.handler.apply( this, args );
-
-                                       if ( ret !== undefined ) {
-                                               event.result = ret;
-                                               if ( ret === false ) {
-                                                       event.preventDefault();
-                                                       event.stopPropagation();
-                                               }
-                                       }
-
-                                       if ( event.isImmediatePropagationStopped() ) {
-                                               break;
-                                       }
-                               }
-                       }
-               }
-
-               return event.result;
-       },
-
-       props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
-
-       fix: function( event ) {
-               if ( event[ jQuery.expando ] ) {
-                       return event;
-               }
-
-               // store a copy of the original event object
-               // and "clone" to set read-only properties
-               var originalEvent = event;
-               event = jQuery.Event( originalEvent );
-
-               for ( var i = this.props.length, prop; i; ) {
-                       prop = this.props[ --i ];
-                       event[ prop ] = originalEvent[ prop ];
-               }
-
-               // Fix target property, if necessary
-               if ( !event.target ) {
-                       // Fixes #1925 where srcElement might not be defined either
-                       event.target = event.srcElement || document;
-               }
-
-               // check if target is a textnode (safari)
-               if ( event.target.nodeType === 3 ) {
-                       event.target = event.target.parentNode;
-               }
-
-               // Add relatedTarget, if necessary
-               if ( !event.relatedTarget && event.fromElement ) {
-                       event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
-               }
-
-               // Calculate pageX/Y if missing and clientX/Y available
-               if ( event.pageX == null && event.clientX != null ) {
-                       var doc = document.documentElement,
-                               body = document.body;
-
-                       event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
-                       event.pageY = event.clientY + (doc && doc.scrollTop  || body && body.scrollTop  || 0) - (doc && doc.clientTop  || body && body.clientTop  || 0);
-               }
-
-               // Add which for key events
-               if ( event.which == null && (event.charCode != null || event.keyCode != null) ) {
-                       event.which = event.charCode != null ? event.charCode : event.keyCode;
-               }
-
-               // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
-               if ( !event.metaKey && event.ctrlKey ) {
-                       event.metaKey = event.ctrlKey;
-               }
-
-               // Add which for click: 1 === left; 2 === middle; 3 === right
-               // Note: button is not normalized, so don't use it
-               if ( !event.which && event.button !== undefined ) {
-                       event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
-               }
-
-               return event;
-       },
-
-       // Deprecated, use jQuery.guid instead
-       guid: 1E8,
-
-       // Deprecated, use jQuery.proxy instead
-       proxy: jQuery.proxy,
-
-       special: {
-               ready: {
-                       // Make sure the ready event is setup
-                       setup: jQuery.bindReady,
-                       teardown: jQuery.noop
-               },
-
-               live: {
-                       add: function( handleObj ) {
-                               jQuery.event.add( this,
-                                       liveConvert( handleObj.origType, handleObj.selector ),
-                                       jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );
-                       },
-
-                       remove: function( handleObj ) {
-                               jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );
-                       }
-               },
-
-               beforeunload: {
-                       setup: function( data, namespaces, eventHandle ) {
-                               // We only want to do this special case on windows
-                               if ( jQuery.isWindow( this ) ) {
-                                       this.onbeforeunload = eventHandle;
-                               }
-                       },
-
-                       teardown: function( namespaces, eventHandle ) {
-                               if ( this.onbeforeunload === eventHandle ) {
-                                       this.onbeforeunload = null;
-                               }
-                       }
-               }
-       }
-};
-
-jQuery.removeEvent = document.removeEventListener ?
-       function( elem, type, handle ) {
-               if ( elem.removeEventListener ) {
-                       elem.removeEventListener( type, handle, false );
-               }
-       } :
-       function( elem, type, handle ) {
-               if ( elem.detachEvent ) {
-                       elem.detachEvent( "on" + type, handle );
-               }
-       };
-
-jQuery.Event = function( src ) {
-       // Allow instantiation without the 'new' keyword
-       if ( !this.preventDefault ) {
-               return new jQuery.Event( src );
-       }
-
-       // Event object
-       if ( src && src.type ) {
-               this.originalEvent = src;
-               this.type = src.type;
-
-               // Events bubbling up the document may have been marked as prevented
-               // by a handler lower down the tree; reflect the correct value.
-               this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false ||
-                       src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse;
-
-       // Event type
-       } else {
-               this.type = src;
-       }
-
-       // timeStamp is buggy for some events on Firefox(#3843)
-       // So we won't rely on the native value
-       this.timeStamp = jQuery.now();
-
-       // Mark it as fixed
-       this[ jQuery.expando ] = true;
-};
-
-function returnFalse() {
-       return false;
-}
-function returnTrue() {
-       return true;
-}
-
-// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
-// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
-jQuery.Event.prototype = {
-       preventDefault: function() {
-               this.isDefaultPrevented = returnTrue;
-
-               var e = this.originalEvent;
-               if ( !e ) {
-                       return;
-               }
-
-               // if preventDefault exists run it on the original event
-               if ( e.preventDefault ) {
-                       e.preventDefault();
-
-               // otherwise set the returnValue property of the original event to false (IE)
-               } else {
-                       e.returnValue = false;
-               }
-       },
-       stopPropagation: function() {
-               this.isPropagationStopped = returnTrue;
-
-               var e = this.originalEvent;
-               if ( !e ) {
-                       return;
-               }
-               // if stopPropagation exists run it on the original event
-               if ( e.stopPropagation ) {
-                       e.stopPropagation();
-               }
-               // otherwise set the cancelBubble property of the original event to true (IE)
-               e.cancelBubble = true;
-       },
-       stopImmediatePropagation: function() {
-               this.isImmediatePropagationStopped = returnTrue;
-               this.stopPropagation();
-       },
-       isDefaultPrevented: returnFalse,
-       isPropagationStopped: returnFalse,
-       isImmediatePropagationStopped: returnFalse
-};
-
-// Checks if an event happened on an element within another element
-// Used in jQuery.event.special.mouseenter and mouseleave handlers
-var withinElement = function( event ) {
-       // Check if mouse(over|out) are still within the same parent element
-       var parent = event.relatedTarget;
-
-       // Firefox sometimes assigns relatedTarget a XUL element
-       // which we cannot access the parentNode property of
-       try {
-
-               // Chrome does something similar, the parentNode property
-               // can be accessed but is null.
-               if ( parent && parent !== document && !parent.parentNode ) {
-                       return;
-               }
-               // Traverse up the tree
-               while ( parent && parent !== this ) {
-                       parent = parent.parentNode;
-               }
-
-               if ( parent !== this ) {
-                       // set the correct event type
-                       event.type = event.data;
-
-                       // handle event if we actually just moused on to a non sub-element
-                       jQuery.event.handle.apply( this, arguments );
-               }
-
-       // assuming we've left the element since we most likely mousedover a xul element
-       } catch(e) { }
-},
-
-// In case of event delegation, we only need to rename the event.type,
-// liveHandler will take care of the rest.
-delegate = function( event ) {
-       event.type = event.data;
-       jQuery.event.handle.apply( this, arguments );
-};
-
-// Create mouseenter and mouseleave events
-jQuery.each({
-       mouseenter: "mouseover",
-       mouseleave: "mouseout"
-}, function( orig, fix ) {
-       jQuery.event.special[ orig ] = {
-               setup: function( data ) {
-                       jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
-               },
-               teardown: function( data ) {
-                       jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
-               }
-       };
-});
-
-// submit delegation
-if ( !jQuery.support.submitBubbles ) {
-
-       jQuery.event.special.submit = {
-               setup: function( data, namespaces ) {
-                       if ( this.nodeName && this.nodeName.toLowerCase() !== "form" ) {
-                               jQuery.event.add(this, "click.specialSubmit", function( e ) {
-                                       var elem = e.target,
-                                               type = elem.type;
-
-                                       if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
-                                               trigger( "submit", this, arguments );
-                                       }
-                               });
-
-                               jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
-                                       var elem = e.target,
-                                               type = elem.type;
-
-                                       if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
-                                               trigger( "submit", this, arguments );
-                                       }
-                               });
-
-                       } else {
-                               return false;
-                       }
-               },
-
-               teardown: function( namespaces ) {
-                       jQuery.event.remove( this, ".specialSubmit" );
-               }
-       };
-
-}
-
-// change delegation, happens here so we have bind.
-if ( !jQuery.support.changeBubbles ) {
-
-       var changeFilters,
-
-       getVal = function( elem ) {
-               var type = elem.type, val = elem.value;
-
-               if ( type === "radio" || type === "checkbox" ) {
-                       val = elem.checked;
-
-               } else if ( type === "select-multiple" ) {
-                       val = elem.selectedIndex > -1 ?
-                               jQuery.map( elem.options, function( elem ) {
-                                       return elem.selected;
-                               }).join("-") :
-                               "";
-
-               } else if ( elem.nodeName.toLowerCase() === "select" ) {
-                       val = elem.selectedIndex;
-               }
-
-               return val;
-       },
-
-       testChange = function testChange( e ) {
-               var elem = e.target, data, val;
-
-               if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) {
-                       return;
-               }
-
-               data = jQuery._data( elem, "_change_data" );
-               val = getVal(elem);
-
-               // the current data will be also retrieved by beforeactivate
-               if ( e.type !== "focusout" || elem.type !== "radio" ) {
-                       jQuery._data( elem, "_change_data", val );
-               }
-
-               if ( data === undefined || val === data ) {
-                       return;
-               }
-
-               if ( data != null || val ) {
-                       e.type = "change";
-                       e.liveFired = undefined;
-                       jQuery.event.trigger( e, arguments[1], elem );
-               }
-       };
-
-       jQuery.event.special.change = {
-               filters: {
-                       focusout: testChange,
-
-                       beforedeactivate: testChange,
-
-                       click: function( e ) {
-                               var elem = e.target, type = elem.type;
-
-                               if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
-                                       testChange.call( this, e );
-                               }
-                       },
-
-                       // Change has to be called before submit
-                       // Keydown will be called before keypress, which is used in submit-event delegation
-                       keydown: function( e ) {
-                               var elem = e.target, type = elem.type;
-
-                               if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
-                                       (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
-                                       type === "select-multiple" ) {
-                                       testChange.call( this, e );
-                               }
-                       },
-
-                       // Beforeactivate happens also before the previous element is blurred
-                       // with this event you can't trigger a change event, but you can store
-                       // information
-                       beforeactivate: function( e ) {
-                               var elem = e.target;
-                               jQuery._data( elem, "_change_data", getVal(elem) );
-                       }
-               },
-
-               setup: function( data, namespaces ) {
-                       if ( this.type === "file" ) {
-                               return false;
-                       }
-
-                       for ( var type in changeFilters ) {
-                               jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
-                       }
-
-                       return rformElems.test( this.nodeName );
-               },
-
-               teardown: function( namespaces ) {
-                       jQuery.event.remove( this, ".specialChange" );
-
-                       return rformElems.test( this.nodeName );
-               }
-       };
-
-       changeFilters = jQuery.event.special.change.filters;
-
-       // Handle when the input is .focus()'d
-       changeFilters.focus = changeFilters.beforeactivate;
-}
-
-function trigger( type, elem, args ) {
-       // Piggyback on a donor event to simulate a different one.
-       // Fake originalEvent to avoid donor's stopPropagation, but if the
-       // simulated event prevents default then we do the same on the donor.
-       // Don't pass args or remember liveFired; they apply to the donor event.
-       var event = jQuery.extend( {}, args[ 0 ] );
-       event.type = type;
-       event.originalEvent = {};
-       event.liveFired = undefined;
-       jQuery.event.handle.call( elem, event );
-       if ( event.isDefaultPrevented() ) {
-               args[ 0 ].preventDefault();
-       }
-}
-
-// Create "bubbling" focus and blur events
-if ( document.addEventListener ) {
-       jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
-       
-               // Attach a single capturing handler while someone wants focusin/focusout
-               var attaches = 0;
-               
-               jQuery.event.special[ fix ] = {
-                       setup: function() {
-                               if ( attaches++ === 0 ) {
-                                       document.addEventListener( orig, handler, true );
-                               }
-                       },
-                       teardown: function() {
-                               if ( --attaches === 0 ) {
-                                       document.removeEventListener( orig, handler, true );
-                               }
-                       }
-               };
-
-               function handler( donor ) {
-                       // Donor event is always a native one; fix it and switch its type.
-                       // Let focusin/out handler cancel the donor focus/blur event.
-                       var e = jQuery.event.fix( donor );
-                       e.type = fix;
-                       e.originalEvent = {};
-                       jQuery.event.trigger( e, null, e.target );
-                       if ( e.isDefaultPrevented() ) {
-                               donor.preventDefault();
-                       }
-               }
-       });
-}
-
-jQuery.each(["bind", "one"], function( i, name ) {
-       jQuery.fn[ name ] = function( type, data, fn ) {
-               // Handle object literals
-               if ( typeof type === "object" ) {
-                       for ( var key in type ) {
-                               this[ name ](key, data, type[key], fn);
-                       }
-                       return this;
-               }
-
-               if ( jQuery.isFunction( data ) || data === false ) {
-                       fn = data;
-                       data = undefined;
-               }
-
-               var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
-                       jQuery( this ).unbind( event, handler );
-                       return fn.apply( this, arguments );
-               }) : fn;
-
-               if ( type === "unload" && name !== "one" ) {
-                       this.one( type, data, fn );
-
-               } else {
-                       for ( var i = 0, l = this.length; i < l; i++ ) {
-                               jQuery.event.add( this[i], type, handler, data );
-                       }
-               }
-
-               return this;
-       };
-});
-
-jQuery.fn.extend({
-       unbind: function( type, fn ) {
-               // Handle object literals
-               if ( typeof type === "object" && !type.preventDefault ) {
-                       for ( var key in type ) {
-                               this.unbind(key, type[key]);
-                       }
-
-               } else {
-                       for ( var i = 0, l = this.length; i < l; i++ ) {
-                               jQuery.event.remove( this[i], type, fn );
-                       }
-               }
-
-               return this;
-       },
-
-       delegate: function( selector, types, data, fn ) {
-               return this.live( types, data, fn, selector );
-       },
-
-       undelegate: function( selector, types, fn ) {
-               if ( arguments.length === 0 ) {
-                               return this.unbind( "live" );
-
-               } else {
-                       return this.die( types, null, fn, selector );
-               }
-       },
-
-       trigger: function( type, data ) {
-               return this.each(function() {
-                       jQuery.event.trigger( type, data, this );
-               });
-       },
-
-       triggerHandler: function( type, data ) {
-               if ( this[0] ) {
-                       var event = jQuery.Event( type );
-                       event.preventDefault();
-                       event.stopPropagation();
-                       jQuery.event.trigger( event, data, this[0] );
-                       return event.result;
-               }
-       },
-
-       toggle: function( fn ) {
-               // Save reference to arguments for access in closure
-               var args = arguments,
-                       i = 1;
-
-               // link all the functions, so any of them can unbind this click handler
-               while ( i < args.length ) {
-                       jQuery.proxy( fn, args[ i++ ] );
-               }
-
-               return this.click( jQuery.proxy( fn, function( event ) {
-                       // Figure out which function to execute
-                       var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
-                       jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
-
-                       // Make sure that clicks stop
-                       event.preventDefault();
-
-                       // and execute the function
-                       return args[ lastToggle ].apply( this, arguments ) || false;
-               }));
-       },
-
-       hover: function( fnOver, fnOut ) {
-               return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
-       }
-});
-
-var liveMap = {
-       focus: "focusin",
-       blur: "focusout",
-       mouseenter: "mouseover",
-       mouseleave: "mouseout"
-};
-
-jQuery.each(["live", "die"], function( i, name ) {
-       jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
-               var type, i = 0, match, namespaces, preType,
-                       selector = origSelector || this.selector,
-                       context = origSelector ? this : jQuery( this.context );
-
-               if ( typeof types === "object" && !types.preventDefault ) {
-                       for ( var key in types ) {
-                               context[ name ]( key, data, types[key], selector );
-                       }
-
-                       return this;
-               }
-
-               if ( jQuery.isFunction( data ) ) {
-                       fn = data;
-                       data = undefined;
-               }
-
-               types = (types || "").split(" ");
-
-               while ( (type = types[ i++ ]) != null ) {
-                       match = rnamespaces.exec( type );
-                       namespaces = "";
-
-                       if ( match )  {
-                               namespaces = match[0];
-                               type = type.replace( rnamespaces, "" );
-                       }
-
-                       if ( type === "hover" ) {
-                               types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
-                               continue;
-                       }
-
-                       preType = type;
-
-                       if ( type === "focus" || type === "blur" ) {
-                               types.push( liveMap[ type ] + namespaces );
-                               type = type + namespaces;
-
-                       } else {
-                               type = (liveMap[ type ] || type) + namespaces;
-                       }
-
-                       if ( name === "live" ) {
-                               // bind live handler
-                               for ( var j = 0, l = context.length; j < l; j++ ) {
-                                       jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
-                                               { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
-                               }
-
-                       } else {
-                               // unbind live handler
-                               context.unbind( "live." + liveConvert( type, selector ), fn );
-                       }
-               }
-
-               return this;
-       };
-});
-
-function liveHandler( event ) {
-       var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
-               elems = [],
-               selectors = [],
-               events = jQuery._data( this, "events" );
-
-       // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911)
-       if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) {
-               return;
-       }
-
-       if ( event.namespace ) {
-               namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)");
-       }
-
-       event.liveFired = this;
-
-       var live = events.live.slice(0);
-
-       for ( j = 0; j < live.length; j++ ) {
-               handleObj = live[j];
-
-               if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
-                       selectors.push( handleObj.selector );
-
-               } else {
-                       live.splice( j--, 1 );
-               }
-       }
-
-       match = jQuery( event.target ).closest( selectors, event.currentTarget );
-
-       for ( i = 0, l = match.length; i < l; i++ ) {
-               close = match[i];
-
-               for ( j = 0; j < live.length; j++ ) {
-                       handleObj = live[j];
-
-                       if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) {
-                               elem = close.elem;
-                               related = null;
-
-                               // Those two events require additional checking
-                               if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
-                                       event.type = handleObj.preType;
-                                       related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
-                               }
-
-                               if ( !related || related !== elem ) {
-                                       elems.push({ elem: elem, handleObj: handleObj, level: close.level });
-                               }
-                       }
-               }
-       }
-
-       for ( i = 0, l = elems.length; i < l; i++ ) {
-               match = elems[i];
-
-               if ( maxLevel && match.level > maxLevel ) {
-                       break;
-               }
-
-               event.currentTarget = match.elem;
-               event.data = match.handleObj.data;
-               event.handleObj = match.handleObj;
-
-               ret = match.handleObj.origHandler.apply( match.elem, arguments );
-
-               if ( ret === false || event.isPropagationStopped() ) {
-                       maxLevel = match.level;
-
-                       if ( ret === false ) {
-                               stop = false;
-                       }
-                       if ( event.isImmediatePropagationStopped() ) {
-                               break;
-                       }
-               }
-       }
-
-       return stop;
-}
-
-function liveConvert( type, selector ) {
-       return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspace, "&");
-}
-
-jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
-       "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
-       "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
-
-       // Handle event binding
-       jQuery.fn[ name ] = function( data, fn ) {
-               if ( fn == null ) {
-                       fn = data;
-                       data = null;
-               }
-
-               return arguments.length > 0 ?
-                       this.bind( name, data, fn ) :
-                       this.trigger( name );
-       };
-
-       if ( jQuery.attrFn ) {
-               jQuery.attrFn[ name ] = true;
-       }
-});
-
-
-/*!
- * Sizzle CSS Selector Engine
- *  Copyright 2011, The Dojo Foundation
- *  Released under the MIT, BSD, and GPL Licenses.
- *  More information: http://sizzlejs.com/
- */
-(function(){
-
-var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
-       done = 0,
-       toString = Object.prototype.toString,
-       hasDuplicate = false,
-       baseHasDuplicate = true,
-       rBackslash = /\\/g,
-       rNonWord = /\W/;
-
-// Here we check if the JavaScript engine is using some sort of
-// optimization where it does not always call our comparision
-// function. If that is the case, discard the hasDuplicate value.
-//   Thus far that includes Google Chrome.
-[0, 0].sort(function() {
-       baseHasDuplicate = false;
-       return 0;
-});
-
-var Sizzle = function( selector, context, results, seed ) {
-       results = results || [];
-       context = context || document;
-
-       var origContext = context;
-
-       if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
-               return [];
-       }
-       
-       if ( !selector || typeof selector !== "string" ) {
-               return results;
-       }
-
-       var m, set, checkSet, extra, ret, cur, pop, i,
-               prune = true,
-               contextXML = Sizzle.isXML( context ),
-               parts = [],
-               soFar = selector;
-       
-       // Reset the position of the chunker regexp (start from head)
-       do {
-               chunker.exec( "" );
-               m = chunker.exec( soFar );
-
-               if ( m ) {
-                       soFar = m[3];
-               
-                       parts.push( m[1] );
-               
-                       if ( m[2] ) {
-                               extra = m[3];
-                               break;
-                       }
-               }
-       } while ( m );
-
-       if ( parts.length > 1 && origPOS.exec( selector ) ) {
-
-               if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
-                       set = posProcess( parts[0] + parts[1], context );
-
-               } else {
-                       set = Expr.relative[ parts[0] ] ?
-                               [ context ] :
-                               Sizzle( parts.shift(), context );
-
-                       while ( parts.length ) {
-                               selector = parts.shift();
-
-                               if ( Expr.relative[ selector ] ) {
-                                       selector += parts.shift();
-                               }
-                               
-                               set = posProcess( selector, set );
-                       }
-               }
-
-       } else {
-               // Take a shortcut and set the context if the root selector is an ID
-               // (but not if it'll be faster if the inner selector is an ID)
-               if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
-                               Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
-
-                       ret = Sizzle.find( parts.shift(), context, contextXML );
-                       context = ret.expr ?
-                               Sizzle.filter( ret.expr, ret.set )[0] :
-                               ret.set[0];
-               }
-
-               if ( context ) {
-                       ret = seed ?
-                               { expr: parts.pop(), set: makeArray(seed) } :
-                               Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
-
-                       set = ret.expr ?
-                               Sizzle.filter( ret.expr, ret.set ) :
-                               ret.set;
-
-                       if ( parts.length > 0 ) {
-                               checkSet = makeArray( set );
-
-                       } else {
-                               prune = false;
-                       }
-
-                       while ( parts.length ) {
-                               cur = parts.pop();
-                               pop = cur;
-
-                               if ( !Expr.relative[ cur ] ) {
-                                       cur = "";
-                               } else {
-                                       pop = parts.pop();
-                               }
-
-                               if ( pop == null ) {
-                                       pop = context;
-                               }
-
-                               Expr.relative[ cur ]( checkSet, pop, contextXML );
-                       }
-
-               } else {
-                       checkSet = parts = [];
-               }
-       }
-
-       if ( !checkSet ) {
-               checkSet = set;
-       }
-
-       if ( !checkSet ) {
-               Sizzle.error( cur || selector );
-       }
-
-       if ( toString.call(checkSet) === "[object Array]" ) {
-               if ( !prune ) {
-                       results.push.apply( results, checkSet );
-
-               } else if ( context && context.nodeType === 1 ) {
-                       for ( i = 0; checkSet[i] != null; i++ ) {
-                               if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {
-                                       results.push( set[i] );
-                               }
-                       }
-
-               } else {
-                       for ( i = 0; checkSet[i] != null; i++ ) {
-                               if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
-                                       results.push( set[i] );
-                               }
-                       }
-               }
-
-       } else {
-               makeArray( checkSet, results );
-       }
-
-       if ( extra ) {
-               Sizzle( extra, origContext, results, seed );
-               Sizzle.uniqueSort( results );
-       }
-
-       return results;
-};
-
-Sizzle.uniqueSort = function( results ) {
-       if ( sortOrder ) {
-               hasDuplicate = baseHasDuplicate;
-               results.sort( sortOrder );
-
-               if ( hasDuplicate ) {
-                       for ( var i = 1; i < results.length; i++ ) {
-                               if ( results[i] === results[ i - 1 ] ) {
-                                       results.splice( i--, 1 );
-                               }
-                       }
-               }
-       }
-
-       return results;
-};
-
-Sizzle.matches = function( expr, set ) {
-       return Sizzle( expr, null, null, set );
-};
-
-Sizzle.matchesSelector = function( node, expr ) {
-       return Sizzle( expr, null, null, [node] ).length > 0;
-};
-
-Sizzle.find = function( expr, context, isXML ) {
-       var set;
-
-       if ( !expr ) {
-               return [];
-       }
-
-       for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
-               var match,
-                       type = Expr.order[i];
-               
-               if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
-                       var left = match[1];
-                       match.splice( 1, 1 );
-
-                       if ( left.substr( left.length - 1 ) !== "\\" ) {
-                               match[1] = (match[1] || "").replace( rBackslash, "" );
-                               set = Expr.find[ type ]( match, context, isXML );
-
-                               if ( set != null ) {
-                                       expr = expr.replace( Expr.match[ type ], "" );
-                                       break;
-                               }
-                       }
-               }
-       }
-
-       if ( !set ) {
-               set = typeof context.getElementsByTagName !== "undefined" ?
-                       context.getElementsByTagName( "*" ) :
-                       [];
-       }
-
-       return { set: set, expr: expr };
-};
-
-Sizzle.filter = function( expr, set, inplace, not ) {
-       var match, anyFound,
-               old = expr,
-               result = [],
-               curLoop = set,
-               isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );
-
-       while ( expr && set.length ) {
-               for ( var type in Expr.filter ) {
-                       if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
-                               var found, item,
-                                       filter = Expr.filter[ type ],
-                                       left = match[1];
-
-                               anyFound = false;
-
-                               match.splice(1,1);
-
-                               if ( left.substr( left.length - 1 ) === "\\" ) {
-                                       continue;
-                               }
-
-                               if ( curLoop === result ) {
-                                       result = [];
-                               }
-
-                               if ( Expr.preFilter[ type ] ) {
-                                       match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
-
-                                       if ( !match ) {
-                                               anyFound = found = true;
-
-                                       } else if ( match === true ) {
-                                               continue;
-                                       }
-                               }
-
-                               if ( match ) {
-                                       for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
-                                               if ( item ) {
-                                                       found = filter( item, match, i, curLoop );
-                                                       var pass = not ^ !!found;
-
-                                                       if ( inplace && found != null ) {
-                                                               if ( pass ) {
-                                                                       anyFound = true;
-
-                                                               } else {
-                                                                       curLoop[i] = false;
-                                                               }
-
-                                                       } else if ( pass ) {
-                                                               result.push( item );
-                                                               anyFound = true;
-                                                       }
-                                               }
-                                       }
-                               }
-
-                               if ( found !== undefined ) {
-                                       if ( !inplace ) {
-                                               curLoop = result;
-                                       }
-
-                                       expr = expr.replace( Expr.match[ type ], "" );
-
-                                       if ( !anyFound ) {
-                                               return [];
-                                       }
-
-                                       break;
-                               }
-                       }
-               }
-
-               // Improper expression
-               if ( expr === old ) {
-                       if ( anyFound == null ) {
-                               Sizzle.error( expr );
-
-                       } else {
-                               break;
-                       }
-               }
-
-               old = expr;
-       }
-
-       return curLoop;
-};
-
-Sizzle.error = function( msg ) {
-       throw "Syntax error, unrecognized expression: " + msg;
-};
-
-var Expr = Sizzle.selectors = {
-       order: [ "ID", "NAME", "TAG" ],
-
-       match: {
-               ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
-               CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
-               NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
-               ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,
-               TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
-               CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,
-               POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
-               PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
-       },
-
-       leftMatch: {},
-
-       attrMap: {
-               "class": "className",
-               "for": "htmlFor"
-       },
-
-       attrHandle: {
-               href: function( elem ) {
-                       return elem.getAttribute( "href" );
-               },
-               type: function( elem ) {
-                       return elem.getAttribute( "type" );
-               }
-       },
-
-       relative: {
-               "+": function(checkSet, part){
-                       var isPartStr = typeof part === "string",
-                               isTag = isPartStr && !rNonWord.test( part ),
-                               isPartStrNotTag = isPartStr && !isTag;
-
-                       if ( isTag ) {
-                               part = part.toLowerCase();
-                       }
-
-                       for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
-                               if ( (elem = checkSet[i]) ) {
-                                       while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
-
-                                       checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
-                                               elem || false :
-                                               elem === part;
-                               }
-                       }
-
-                       if ( isPartStrNotTag ) {
-                               Sizzle.filter( part, checkSet, true );
-                       }
-               },
-
-               ">": function( checkSet, part ) {
-                       var elem,
-                               isPartStr = typeof part === "string",
-                               i = 0,
-                               l = checkSet.length;
-
-                       if ( isPartStr && !rNonWord.test( part ) ) {
-                               part = part.toLowerCase();
-
-                               for ( ; i < l; i++ ) {
-                                       elem = checkSet[i];
-
-                                       if ( elem ) {
-                                               var parent = elem.parentNode;
-                                               checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
-                                       }
-                               }
-
-                       } else {
-                               for ( ; i < l; i++ ) {
-                                       elem = checkSet[i];
-
-                                       if ( elem ) {
-                                               checkSet[i] = isPartStr ?
-                                                       elem.parentNode :
-                                                       elem.parentNode === part;
-                                       }
-                               }
-
-                               if ( isPartStr ) {
-                                       Sizzle.filter( part, checkSet, true );
-                               }
-                       }
-               },
-
-               "": function(checkSet, part, isXML){
-                       var nodeCheck,
-                               doneName = done++,
-                               checkFn = dirCheck;
-
-                       if ( typeof part === "string" && !rNonWord.test( part ) ) {
-                               part = part.toLowerCase();
-                               nodeCheck = part;
-                               checkFn = dirNodeCheck;
-                       }
-
-                       checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML );
-               },
-
-               "~": function( checkSet, part, isXML ) {
-                       var nodeCheck,
-                               doneName = done++,
-                               checkFn = dirCheck;
-
-                       if ( typeof part === "string" && !rNonWord.test( part ) ) {
-                               part = part.toLowerCase();
-                               nodeCheck = part;
-                               checkFn = dirNodeCheck;
-                       }
-
-                       checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML );
-               }
-       },
-
-       find: {
-               ID: function( match, context, isXML ) {
-                       if ( typeof context.getElementById !== "undefined" && !isXML ) {
-                               var m = context.getElementById(match[1]);
-                               // Check parentNode to catch when Blackberry 4.6 returns
-                               // nodes that are no longer in the document #6963
-                               return m && m.parentNode ? [m] : [];
-                       }
-               },
-
-               NAME: function( match, context ) {
-                       if ( typeof context.getElementsByName !== "undefined" ) {
-                               var ret = [],
-                                       results = context.getElementsByName( match[1] );
-
-                               for ( var i = 0, l = results.length; i < l; i++ ) {
-                                       if ( results[i].getAttribute("name") === match[1] ) {
-                                               ret.push( results[i] );
-                                       }
-                               }
-
-                               return ret.length === 0 ? null : ret;
-                       }
-               },
-
-               TAG: function( match, context ) {
-                       if ( typeof context.getElementsByTagName !== "undefined" ) {
-                               return context.getElementsByTagName( match[1] );
-                       }
-               }
-       },
-       preFilter: {
-               CLASS: function( match, curLoop, inplace, result, not, isXML ) {
-                       match = " " + match[1].replace( rBackslash, "" ) + " ";
-
-                       if ( isXML ) {
-                               return match;
-                       }
-
-                       for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
-                               if ( elem ) {
-                                       if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) {
-                                               if ( !inplace ) {
-                                                       result.push( elem );
-                                               }
-
-                                       } else if ( inplace ) {
-                                               curLoop[i] = false;
-                                       }
-                               }
-                       }
-
-                       return false;
-               },
-
-               ID: function( match ) {
-                       return match[1].replace( rBackslash, "" );
-               },
-
-               TAG: function( match, curLoop ) {
-                       return match[1].replace( rBackslash, "" ).toLowerCase();
-               },
-
-               CHILD: function( match ) {
-                       if ( match[1] === "nth" ) {
-                               if ( !match[2] ) {
-                                       Sizzle.error( match[0] );
-                               }
-
-                               match[2] = match[2].replace(/^\+|\s*/g, '');
-
-                               // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
-                               var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec(
-                                       match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
-                                       !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
-
-                               // calculate the numbers (first)n+(last) including if they are negative
-                               match[2] = (test[1] + (test[2] || 1)) - 0;
-                               match[3] = test[3] - 0;
-                       }
-                       else if ( match[2] ) {
-                               Sizzle.error( match[0] );
-                       }
-
-                       // TODO: Move to normal caching system
-                       match[0] = done++;
-
-                       return match;
-               },
-
-               ATTR: function( match, curLoop, inplace, result, not, isXML ) {
-                       var name = match[1] = match[1].replace( rBackslash, "" );
-                       
-                       if ( !isXML && Expr.attrMap[name] ) {
-                               match[1] = Expr.attrMap[name];
-                       }
-
-                       // Handle if an un-quoted value was used
-                       match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" );
-
-                       if ( match[2] === "~=" ) {
-                               match[4] = " " + match[4] + " ";
-                       }
-
-                       return match;
-               },
-
-               PSEUDO: function( match, curLoop, inplace, result, not ) {
-                       if ( match[1] === "not" ) {
-                               // If we're dealing with a complex expression, or a simple one
-                               if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
-                                       match[3] = Sizzle(match[3], null, null, curLoop);
-
-                               } else {
-                                       var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
-
-                                       if ( !inplace ) {
-                                               result.push.apply( result, ret );
-                                       }
-
-                                       return false;
-                               }
-
-                       } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
-                               return true;
-                       }
-                       
-                       return match;
-               },
-
-               POS: function( match ) {
-                       match.unshift( true );
-
-                       return match;
-               }
-       },
-       
-       filters: {
-               enabled: function( elem ) {
-                       return elem.disabled === false && elem.type !== "hidden";
-               },
-
-               disabled: function( elem ) {
-                       return elem.disabled === true;
-               },
-
-               checked: function( elem ) {
-                       return elem.checked === true;
-               },
-               
-               selected: function( elem ) {
-                       // Accessing this property makes selected-by-default
-                       // options in Safari work properly
-                       if ( elem.parentNode ) {
-                               elem.parentNode.selectedIndex;
-                       }
-                       
-                       return elem.selected === true;
-               },
-
-               parent: function( elem ) {
-                       return !!elem.firstChild;
-               },
-
-               empty: function( elem ) {
-                       return !elem.firstChild;
-               },
-
-               has: function( elem, i, match ) {
-                       return !!Sizzle( match[3], elem ).length;
-               },
-
-               header: function( elem ) {
-                       return (/h\d/i).test( elem.nodeName );
-               },
-
-               text: function( elem ) {
-                       var attr = elem.getAttribute( "type" ), type = elem.type;
-                       // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) 
-                       // use getAttribute instead to test this case
-                       return "text" === type && ( attr === type || attr === null );
-               },
-
-               radio: function( elem ) {
-                       return "radio" === elem.type;
-               },
-
-               checkbox: function( elem ) {
-                       return "checkbox" === elem.type;
-               },
-
-               file: function( elem ) {
-                       return "file" === elem.type;
-               },
-               password: function( elem ) {
-                       return "password" === elem.type;
-               },
-
-               submit: function( elem ) {
-                       return "submit" === elem.type;
-               },
-
-               image: function( elem ) {
-                       return "image" === elem.type;
-               },
-
-               reset: function( elem ) {
-                       return "reset" === elem.type;
-               },
-
-               button: function( elem ) {
-                       return "button" === elem.type || elem.nodeName.toLowerCase() === "button";
-               },
-
-               input: function( elem ) {
-                       return (/input|select|textarea|button/i).test( elem.nodeName );
-               }
-       },
-       setFilters: {
-               first: function( elem, i ) {
-                       return i === 0;
-               },
-
-               last: function( elem, i, match, array ) {
-                       return i === array.length - 1;
-               },
-
-               even: function( elem, i ) {
-                       return i % 2 === 0;
-               },
-
-               odd: function( elem, i ) {
-                       return i % 2 === 1;
-               },
-
-               lt: function( elem, i, match ) {
-                       return i < match[3] - 0;
-               },
-
-               gt: function( elem, i, match ) {
-                       return i > match[3] - 0;
-               },
-
-               nth: function( elem, i, match ) {
-                       return match[3] - 0 === i;
-               },
-
-               eq: function( elem, i, match ) {
-                       return match[3] - 0 === i;
-               }
-       },
-       filter: {
-               PSEUDO: function( elem, match, i, array ) {
-                       var name = match[1],
-                               filter = Expr.filters[ name ];
-
-                       if ( filter ) {
-                               return filter( elem, i, match, array );
-
-                       } else if ( name === "contains" ) {
-                               return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0;
-
-                       } else if ( name === "not" ) {
-                               var not = match[3];
-
-                               for ( var j = 0, l = not.length; j < l; j++ ) {
-                                       if ( not[j] === elem ) {
-                                               return false;
-                                       }
-                               }
-
-                               return true;
-
-                       } else {
-                               Sizzle.error( name );
-                       }
-               },
-
-               CHILD: function( elem, match ) {
-                       var type = match[1],
-                               node = elem;
-
-                       switch ( type ) {
-                               case "only":
-                               case "first":
-                                       while ( (node = node.previousSibling) )  {
-                                               if ( node.nodeType === 1 ) { 
-                                                       return false; 
-                                               }
-                                       }
-
-                                       if ( type === "first" ) { 
-                                               return true; 
-                                       }
-
-                                       node = elem;
-
-                               case "last":
-                                       while ( (node = node.nextSibling) )      {
-                                               if ( node.nodeType === 1 ) { 
-                                                       return false; 
-                                               }
-                                       }
-
-                                       return true;
-
-                               case "nth":
-                                       var first = match[2],
-                                               last = match[3];
-
-                                       if ( first === 1 && last === 0 ) {
-                                               return true;
-                                       }
-                                       
-                                       var doneName = match[0],
-                                               parent = elem.parentNode;
-       
-                                       if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
-                                               var count = 0;
-                                               
-                                               for ( node = parent.firstChild; node; node = node.nextSibling ) {
-                                                       if ( node.nodeType === 1 ) {
-                                                               node.nodeIndex = ++count;
-                                                       }
-                                               } 
-
-                                               parent.sizcache = doneName;
-                                       }
-                                       
-                                       var diff = elem.nodeIndex - last;
-
-                                       if ( first === 0 ) {
-                                               return diff === 0;
-
-                                       } else {
-                                               return ( diff % first === 0 && diff / first >= 0 );
-                                       }
-                       }
-               },
-
-               ID: function( elem, match ) {
-                       return elem.nodeType === 1 && elem.getAttribute("id") === match;
-               },
-
-               TAG: function( elem, match ) {
-                       return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match;
-               },
-               
-               CLASS: function( elem, match ) {
-                       return (" " + (elem.className || elem.getAttribute("class")) + " ")
-                               .indexOf( match ) > -1;
-               },
-
-               ATTR: function( elem, match ) {
-                       var name = match[1],
-                               result = Expr.attrHandle[ name ] ?
-                                       Expr.attrHandle[ name ]( elem ) :
-                                       elem[ name ] != null ?
-                                               elem[ name ] :
-                                               elem.getAttribute( name ),
-                               value = result + "",
-                               type = match[2],
-                               check = match[4];
-
-                       return result == null ?
-                               type === "!=" :
-                               type === "=" ?
-                               value === check :
-                               type === "*=" ?
-                               value.indexOf(check) >= 0 :
-                               type === "~=" ?
-                               (" " + value + " ").indexOf(check) >= 0 :
-                               !check ?
-                               value && result !== false :
-                               type === "!=" ?
-                               value !== check :
-                               type === "^=" ?
-                               value.indexOf(check) === 0 :
-                               type === "$=" ?
-                               value.substr(value.length - check.length) === check :
-                               type === "|=" ?
-                               value === check || value.substr(0, check.length + 1) === check + "-" :
-                               false;
-               },
-
-               POS: function( elem, match, i, array ) {
-                       var name = match[2],
-                               filter = Expr.setFilters[ name ];
-
-                       if ( filter ) {
-                               return filter( elem, i, match, array );
-                       }
-               }
-       }
-};
-
-var origPOS = Expr.match.POS,
-       fescape = function(all, num){
-               return "\\" + (num - 0 + 1);
-       };
-
-for ( var type in Expr.match ) {
-       Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) );
-       Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) );
-}
-
-var makeArray = function( array, results ) {
-       array = Array.prototype.slice.call( array, 0 );
-
-       if ( results ) {
-               results.push.apply( results, array );
-               return results;
-       }
-       
-       return array;
-};
-
-// Perform a simple check to determine if the browser is capable of
-// converting a NodeList to an array using builtin methods.
-// Also verifies that the returned array holds DOM nodes
-// (which is not the case in the Blackberry browser)
-try {
-       Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;
-
-// Provide a fallback method if it does not work
-} catch( e ) {
-       makeArray = function( array, results ) {
-               var i = 0,
-                       ret = results || [];
-
-               if ( toString.call(array) === "[object Array]" ) {
-                       Array.prototype.push.apply( ret, array );
-
-               } else {
-                       if ( typeof array.length === "number" ) {
-                               for ( var l = array.length; i < l; i++ ) {
-                                       ret.push( array[i] );
-                               }
-
-                       } else {
-                               for ( ; array[i]; i++ ) {
-                                       ret.push( array[i] );
-                               }
-                       }
-               }
-
-               return ret;
-       };
-}
-
-var sortOrder, siblingCheck;
-
-if ( document.documentElement.compareDocumentPosition ) {
-       sortOrder = function( a, b ) {
-               if ( a === b ) {
-                       hasDuplicate = true;
-                       return 0;
-               }
-
-               if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
-                       return a.compareDocumentPosition ? -1 : 1;
-               }
-
-               return a.compareDocumentPosition(b) & 4 ? -1 : 1;
-       };
-
-} else {
-       sortOrder = function( a, b ) {
-               var al, bl,
-                       ap = [],
-                       bp = [],
-                       aup = a.parentNode,
-                       bup = b.parentNode,
-                       cur = aup;
-
-               // The nodes are identical, we can exit early
-               if ( a === b ) {
-                       hasDuplicate = true;
-                       return 0;
-
-               // If the nodes are siblings (or identical) we can do a quick check
-               } else if ( aup === bup ) {
-                       return siblingCheck( a, b );
-
-               // If no parents were found then the nodes are disconnected
-               } else if ( !aup ) {
-                       return -1;
-
-               } else if ( !bup ) {
-                       return 1;
-               }
-
-               // Otherwise they're somewhere else in the tree so we need
-               // to build up a full list of the parentNodes for comparison
-               while ( cur ) {
-                       ap.unshift( cur );
-                       cur = cur.parentNode;
-               }
-
-               cur = bup;
-
-               while ( cur ) {
-                       bp.unshift( cur );
-                       cur = cur.parentNode;
-               }
-
-               al = ap.length;
-               bl = bp.length;
-
-               // Start walking down the tree looking for a discrepancy
-               for ( var i = 0; i < al && i < bl; i++ ) {
-                       if ( ap[i] !== bp[i] ) {
-                               return siblingCheck( ap[i], bp[i] );
-                       }
-               }
-
-               // We ended someplace up the tree so do a sibling check
-               return i === al ?
-                       siblingCheck( a, bp[i], -1 ) :
-                       siblingCheck( ap[i], b, 1 );
-       };
-
-       siblingCheck = function( a, b, ret ) {
-               if ( a === b ) {
-                       return ret;
-               }
-
-               var cur = a.nextSibling;
-
-               while ( cur ) {
-                       if ( cur === b ) {
-                               return -1;
-                       }
-
-                       cur = cur.nextSibling;
-               }
-
-               return 1;
-       };
-}
-
-// Utility function for retreiving the text value of an array of DOM nodes
-Sizzle.getText = function( elems ) {
-       var ret = "", elem;
-
-       for ( var i = 0; elems[i]; i++ ) {
-               elem = elems[i];
-
-               // Get the text from text nodes and CDATA nodes
-               if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
-                       ret += elem.nodeValue;
-
-               // Traverse everything else, except comment nodes
-               } else if ( elem.nodeType !== 8 ) {
-                       ret += Sizzle.getText( elem.childNodes );
-               }
-       }
-
-       return ret;
-};
-
-// Check to see if the browser returns elements by name when
-// querying by getElementById (and provide a workaround)
-(function(){
-       // We're going to inject a fake input element with a specified name
-       var form = document.createElement("div"),
-               id = "script" + (new Date()).getTime(),
-               root = document.documentElement;
-
-       form.innerHTML = "<a name='" + id + "'/>";
-
-       // Inject it into the root element, check its status, and remove it quickly
-       root.insertBefore( form, root.firstChild );
-
-       // The workaround has to do additional checks after a getElementById
-       // Which slows things down for other browsers (hence the branching)
-       if ( document.getElementById( id ) ) {
-               Expr.find.ID = function( match, context, isXML ) {
-                       if ( typeof context.getElementById !== "undefined" && !isXML ) {
-                               var m = context.getElementById(match[1]);
-
-                               return m ?
-                                       m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ?
-                                               [m] :
-                                               undefined :
-                                       [];
-                       }
-               };
-
-               Expr.filter.ID = function( elem, match ) {
-                       var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
-
-                       return elem.nodeType === 1 && node && node.nodeValue === match;
-               };
-       }
-
-       root.removeChild( form );
-
-       // release memory in IE
-       root = form = null;
-})();
-
-(function(){
-       // Check to see if the browser returns only elements
-       // when doing getElementsByTagName("*")
-
-       // Create a fake element
-       var div = document.createElement("div");
-       div.appendChild( document.createComment("") );
-
-       // Make sure no comments are found
-       if ( div.getElementsByTagName("*").length > 0 ) {
-               Expr.find.TAG = function( match, context ) {
-                       var results = context.getElementsByTagName( match[1] );
-
-                       // Filter out possible comments
-                       if ( match[1] === "*" ) {
-                               var tmp = [];
-
-                               for ( var i = 0; results[i]; i++ ) {
-                                       if ( results[i].nodeType === 1 ) {
-                                               tmp.push( results[i] );
-                                       }
-                               }
-
-                               results = tmp;
-                       }
-
-                       return results;
-               };
-       }
-
-       // Check to see if an attribute returns normalized href attributes
-       div.innerHTML = "<a href='#'></a>";
-
-       if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
-                       div.firstChild.getAttribute("href") !== "#" ) {
-
-               Expr.attrHandle.href = function( elem ) {
-                       return elem.getAttribute( "href", 2 );
-               };
-       }
-
-       // release memory in IE
-       div = null;
-})();
-
-if ( document.querySelectorAll ) {
-       (function(){
-               var oldSizzle = Sizzle,
-                       div = document.createElement("div"),
-                       id = "__sizzle__";
-
-               div.innerHTML = "<p class='TEST'></p>";
-
-               // Safari can't handle uppercase or unicode characters when
-               // in quirks mode.
-               if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
-                       return;
-               }
-       
-               Sizzle = function( query, context, extra, seed ) {
-                       context = context || document;
-
-                       // Only use querySelectorAll on non-XML documents
-                       // (ID selectors don't work in non-HTML documents)
-                       if ( !seed && !Sizzle.isXML(context) ) {
-                               // See if we find a selector to speed up
-                               var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query );
-                               
-                               if ( match && (context.nodeType === 1 || context.nodeType === 9) ) {
-                                       // Speed-up: Sizzle("TAG")
-                                       if ( match[1] ) {
-                                               return makeArray( context.getElementsByTagName( query ), extra );
-                                       
-                                       // Speed-up: Sizzle(".CLASS")
-                                       } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) {
-                                               return makeArray( context.getElementsByClassName( match[2] ), extra );
-                                       }
-                               }
-                               
-                               if ( context.nodeType === 9 ) {
-                                       // Speed-up: Sizzle("body")
-                                       // The body element only exists once, optimize finding it
-                                       if ( query === "body" && context.body ) {
-                                               return makeArray( [ context.body ], extra );
-                                               
-                                       // Speed-up: Sizzle("#ID")
-                                       } else if ( match && match[3] ) {
-                                               var elem = context.getElementById( match[3] );
-
-                                               // Check parentNode to catch when Blackberry 4.6 returns
-                                               // nodes that are no longer in the document #6963
-                                               if ( elem && elem.parentNode ) {
-                                                       // Handle the case where IE and Opera return items
-                                                       // by name instead of ID
-                                                       if ( elem.id === match[3] ) {
-                                                               return makeArray( [ elem ], extra );
-                                                       }
-                                                       
-                                               } else {
-                                                       return makeArray( [], extra );
-                                               }
-                                       }
-                                       
-                                       try {
-                                               return makeArray( context.querySelectorAll(query), extra );
-                                       } catch(qsaError) {}
-
-                               // qSA works strangely on Element-rooted queries
-                               // We can work around this by specifying an extra ID on the root
-                               // and working up from there (Thanks to Andrew Dupont for the technique)
-                               // IE 8 doesn't work on object elements
-                               } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
-                                       var oldContext = context,
-                                               old = context.getAttribute( "id" ),
-                                               nid = old || id,
-                                               hasParent = context.parentNode,
-                                               relativeHierarchySelector = /^\s*[+~]/.test( query );
-
-                                       if ( !old ) {
-                                               context.setAttribute( "id", nid );
-                                       } else {
-                                               nid = nid.replace( /'/g, "\\$&" );
-                                       }
-                                       if ( relativeHierarchySelector && hasParent ) {
-                                               context = context.parentNode;
-                                       }
-
-                                       try {
-                                               if ( !relativeHierarchySelector || hasParent ) {
-                                                       return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra );
-                                               }
-
-                                       } catch(pseudoError) {
-                                       } finally {
-                                               if ( !old ) {
-                                                       oldContext.removeAttribute( "id" );
-                                               }
-                                       }
-                               }
-                       }
-               
-                       return oldSizzle(query, context, extra, seed);
-               };
-
-               for ( var prop in oldSizzle ) {
-                       Sizzle[ prop ] = oldSizzle[ prop ];
-               }
-
-               // release memory in IE
-               div = null;
-       })();
-}
-
-(function(){
-       var html = document.documentElement,
-               matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector;
-
-       if ( matches ) {
-               // Check to see if it's possible to do matchesSelector
-               // on a disconnected node (IE 9 fails this)
-               var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ),
-                       pseudoWorks = false;
-
-               try {
-                       // This should fail with an exception
-                       // Gecko does not error, returns false instead
-                       matches.call( document.documentElement, "[test!='']:sizzle" );
-       
-               } catch( pseudoError ) {
-                       pseudoWorks = true;
-               }
-
-               Sizzle.matchesSelector = function( node, expr ) {
-                       // Make sure that attribute selectors are quoted
-                       expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");
-
-                       if ( !Sizzle.isXML( node ) ) {
-                               try { 
-                                       if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {
-                                               var ret = matches.call( node, expr );
-
-                                               // IE 9's matchesSelector returns false on disconnected nodes
-                                               if ( ret || !disconnectedMatch ||
-                                                               // As well, disconnected nodes are said to be in a document
-                                                               // fragment in IE 9, so check for that
-                                                               node.document && node.document.nodeType !== 11 ) {
-                                                       return ret;
-                                               }
-                                       }
-                               } catch(e) {}
-                       }
-
-                       return Sizzle(expr, null, null, [node]).length > 0;
-               };
-       }
-})();
-
-(function(){
-       var div = document.createElement("div");
-
-       div.innerHTML = "<div class='test e'></div><div class='test'></div>";
-
-       // Opera can't find a second classname (in 9.6)
-       // Also, make sure that getElementsByClassName actually exists
-       if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
-               return;
-       }
-
-       // Safari caches class attributes, doesn't catch changes (in 3.2)
-       div.lastChild.className = "e";
-
-       if ( div.getElementsByClassName("e").length === 1 ) {
-               return;
-       }
-       
-       Expr.order.splice(1, 0, "CLASS");
-       Expr.find.CLASS = function( match, context, isXML ) {
-               if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
-                       return context.getElementsByClassName(match[1]);
-               }
-       };
-
-       // release memory in IE
-       div = null;
-})();
-
-function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
-       for ( var i = 0, l = checkSet.length; i < l; i++ ) {
-               var elem = checkSet[i];
-
-               if ( elem ) {
-                       var match = false;
-
-                       elem = elem[dir];
-
-                       while ( elem ) {
-                               if ( elem.sizcache === doneName ) {
-                                       match = checkSet[elem.sizset];
-                                       break;
-                               }
-
-                               if ( elem.nodeType === 1 && !isXML ){
-                                       elem.sizcache = doneName;
-                                       elem.sizset = i;
-                               }
-
-                               if ( elem.nodeName.toLowerCase() === cur ) {
-                                       match = elem;
-                                       break;
-                               }
-
-                               elem = elem[dir];
-                       }
-
-                       checkSet[i] = match;
-               }
-       }
-}
-
-function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
-       for ( var i = 0, l = checkSet.length; i < l; i++ ) {
-               var elem = checkSet[i];
-
-               if ( elem ) {
-                       var match = false;
-                       
-                       elem = elem[dir];
-
-                       while ( elem ) {
-                               if ( elem.sizcache === doneName ) {
-                                       match = checkSet[elem.sizset];
-                                       break;
-                               }
-
-                               if ( elem.nodeType === 1 ) {
-                                       if ( !isXML ) {
-                                               elem.sizcache = doneName;
-                                               elem.sizset = i;
-                                       }
-
-                                       if ( typeof cur !== "string" ) {
-                                               if ( elem === cur ) {
-                                                       match = true;
-                                                       break;
-                                               }
-
-                                       } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
-                                               match = elem;
-                                               break;
-                                       }
-                               }
-
-                               elem = elem[dir];
-                       }
-
-                       checkSet[i] = match;
-               }
-       }
-}
-
-if ( document.documentElement.contains ) {
-       Sizzle.contains = function( a, b ) {
-               return a !== b && (a.contains ? a.contains(b) : true);
-       };
-
-} else if ( document.documentElement.compareDocumentPosition ) {
-       Sizzle.contains = function( a, b ) {
-               return !!(a.compareDocumentPosition(b) & 16);
-       };
-
-} else {
-       Sizzle.contains = function() {
-               return false;
-       };
-}
-
-Sizzle.isXML = function( elem ) {
-       // documentElement is verified for cases where it doesn't yet exist
-       // (such as loading iframes in IE - #4833) 
-       var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
-
-       return documentElement ? documentElement.nodeName !== "HTML" : false;
-};
-
-var posProcess = function( selector, context ) {
-       var match,
-               tmpSet = [],
-               later = "",
-               root = context.nodeType ? [context] : context;
-
-       // Position selectors must be done after the filter
-       // And so must :not(positional) so we move all PSEUDOs to the end
-       while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
-               later += match[0];
-               selector = selector.replace( Expr.match.PSEUDO, "" );
-       }
-
-       selector = Expr.relative[selector] ? selector + "*" : selector;
-
-       for ( var i = 0, l = root.length; i < l; i++ ) {
-               Sizzle( selector, root[i], tmpSet );
-       }
-
-       return Sizzle.filter( later, tmpSet );
-};
-
-// EXPOSE
-jQuery.find = Sizzle;
-jQuery.expr = Sizzle.selectors;
-jQuery.expr[":"] = jQuery.expr.filters;
-jQuery.unique = Sizzle.uniqueSort;
-jQuery.text = Sizzle.getText;
-jQuery.isXMLDoc = Sizzle.isXML;
-jQuery.contains = Sizzle.contains;
-
-
-})();
-
-
-var runtil = /Until$/,
-       rparentsprev = /^(?:parents|prevUntil|prevAll)/,
-       // Note: This RegExp should be improved, or likely pulled from Sizzle
-       rmultiselector = /,/,
-       isSimple = /^.[^:#\[\.,]*$/,
-       slice = Array.prototype.slice,
-       POS = jQuery.expr.match.POS,
-       // methods guaranteed to produce a unique set when starting from a unique set
-       guaranteedUnique = {
-               children: true,
-               contents: true,
-               next: true,
-               prev: true
-       };
-
-jQuery.fn.extend({
-       find: function( selector ) {
-               var ret = this.pushStack( "", "find", selector ),
-                       length = 0;
-
-               for ( var i = 0, l = this.length; i < l; i++ ) {
-                       length = ret.length;
-                       jQuery.find( selector, this[i], ret );
-
-                       if ( i > 0 ) {
-                               // Make sure that the results are unique
-                               for ( var n = length; n < ret.length; n++ ) {
-                                       for ( var r = 0; r < length; r++ ) {
-                                               if ( ret[r] === ret[n] ) {
-                                                       ret.splice(n--, 1);
-                                                       break;
-                                               }
-                                       }
-                               }
-                       }
-               }
-
-               return ret;
-       },
-
-       has: function( target ) {
-               var targets = jQuery( target );
-               return this.filter(function() {
-                       for ( var i = 0, l = targets.length; i < l; i++ ) {
-                               if ( jQuery.contains( this, targets[i] ) ) {
-                                       return true;
-                               }
-                       }
-               });
-       },
-
-       not: function( selector ) {
-               return this.pushStack( winnow(this, selector, false), "not", selector);
-       },
-
-       filter: function( selector ) {
-               return this.pushStack( winnow(this, selector, true), "filter", selector );
-       },
-
-       is: function( selector ) {
-               return !!selector && jQuery.filter( selector, this ).length > 0;
-       },
-
-       closest: function( selectors, context ) {
-               var ret = [], i, l, cur = this[0];
-
-               if ( jQuery.isArray( selectors ) ) {
-                       var match, selector,
-                               matches = {},
-                               level = 1;
-
-                       if ( cur && selectors.length ) {
-                               for ( i = 0, l = selectors.length; i < l; i++ ) {
-                                       selector = selectors[i];
-
-                                       if ( !matches[selector] ) {
-                                               matches[selector] = jQuery.expr.match.POS.test( selector ) ?
-                                                       jQuery( selector, context || this.context ) :
-                                                       selector;
-                                       }
-                               }
-
-                               while ( cur && cur.ownerDocument && cur !== context ) {
-                                       for ( selector in matches ) {
-                                               match = matches[selector];
-
-                                               if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) {
-                                                       ret.push({ selector: selector, elem: cur, level: level });
-                                               }
-                                       }
-
-                                       cur = cur.parentNode;
-                                       level++;
-                               }
-                       }
-
-                       return ret;
-               }
-
-               var pos = POS.test( selectors ) ?
-                       jQuery( selectors, context || this.context ) : null;
-
-               for ( i = 0, l = this.length; i < l; i++ ) {
-                       cur = this[i];
-
-                       while ( cur ) {
-                               if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
-                                       ret.push( cur );
-                                       break;
-
-                               } else {
-                                       cur = cur.parentNode;
-                                       if ( !cur || !cur.ownerDocument || cur === context ) {
-                                               break;
-                                       }
-                               }
-                       }
-               }
-
-               ret = ret.length > 1 ? jQuery.unique(ret) : ret;
-
-               return this.pushStack( ret, "closest", selectors );
-       },
-
-       // Determine the position of an element within
-       // the matched set of elements
-       index: function( elem ) {
-               if ( !elem || typeof elem === "string" ) {
-                       return jQuery.inArray( this[0],
-                               // If it receives a string, the selector is used
-                               // If it receives nothing, the siblings are used
-                               elem ? jQuery( elem ) : this.parent().children() );
-               }
-               // Locate the position of the desired element
-               return jQuery.inArray(
-                       // If it receives a jQuery object, the first element is used
-                       elem.jquery ? elem[0] : elem, this );
-       },
-
-       add: function( selector, context ) {
-               var set = typeof selector === "string" ?
-                               jQuery( selector, context ) :
-                               jQuery.makeArray( selector ),
-                       all = jQuery.merge( this.get(), set );
-
-               return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
-                       all :
-                       jQuery.unique( all ) );
-       },
-
-       andSelf: function() {
-               return this.add( this.prevObject );
-       }
-});
-
-// A painfully simple check to see if an element is disconnected
-// from a document (should be improved, where feasible).
-function isDisconnected( node ) {
-       return !node || !node.parentNode || node.parentNode.nodeType === 11;
-}
-
-jQuery.each({
-       parent: function( elem ) {
-               var parent = elem.parentNode;
-               return parent && parent.nodeType !== 11 ? parent : null;
-       },
-       parents: function( elem ) {
-               return jQuery.dir( elem, "parentNode" );
-       },
-       parentsUntil: function( elem, i, until ) {
-               return jQuery.dir( elem, "parentNode", until );
-       },
-       next: function( elem ) {
-               return jQuery.nth( elem, 2, "nextSibling" );
-       },
-       prev: function( elem ) {
-               return jQuery.nth( elem, 2, "previousSibling" );
-       },
-       nextAll: function( elem ) {
-               return jQuery.dir( elem, "nextSibling" );
-       },
-       prevAll: function( elem ) {
-               return jQuery.dir( elem, "previousSibling" );
-       },
-       nextUntil: function( elem, i, until ) {
-               return jQuery.dir( elem, "nextSibling", until );
-       },
-       prevUntil: function( elem, i, until ) {
-               return jQuery.dir( elem, "previousSibling", until );
-       },
-       siblings: function( elem ) {
-               return jQuery.sibling( elem.parentNode.firstChild, elem );
-       },
-       children: function( elem ) {
-               return jQuery.sibling( elem.firstChild );
-       },
-       contents: function( elem ) {
-               return jQuery.nodeName( elem, "iframe" ) ?
-                       elem.contentDocument || elem.contentWindow.document :
-                       jQuery.makeArray( elem.childNodes );
-       }
-}, function( name, fn ) {
-       jQuery.fn[ name ] = function( until, selector ) {
-               var ret = jQuery.map( this, fn, until ),
-                       // The variable 'args' was introduced in
-                       // https://github.com/jquery/jquery/commit/52a0238
-                       // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed.
-                       // http://code.google.com/p/v8/issues/detail?id=1050
-                       args = slice.call(arguments);
-
-               if ( !runtil.test( name ) ) {
-                       selector = until;
-               }
-
-               if ( selector && typeof selector === "string" ) {
-                       ret = jQuery.filter( selector, ret );
-               }
-
-               ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
-
-               if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
-                       ret = ret.reverse();
-               }
-
-               return this.pushStack( ret, name, args.join(",") );
-       };
-});
-
-jQuery.extend({
-       filter: function( expr, elems, not ) {
-               if ( not ) {
-                       expr = ":not(" + expr + ")";
-               }
-
-               return elems.length === 1 ?
-                       jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
-                       jQuery.find.matches(expr, elems);
-       },
-
-       dir: function( elem, dir, until ) {
-               var matched = [],
-                       cur = elem[ dir ];
-
-               while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
-                       if ( cur.nodeType === 1 ) {
-                               matched.push( cur );
-                       }
-                       cur = cur[dir];
-               }
-               return matched;
-       },
-
-       nth: function( cur, result, dir, elem ) {
-               result = result || 1;
-               var num = 0;
-
-               for ( ; cur; cur = cur[dir] ) {
-                       if ( cur.nodeType === 1 && ++num === result ) {
-                               break;
-                       }
-               }
-
-               return cur;
-       },
-
-       sibling: function( n, elem ) {
-               var r = [];
-
-               for ( ; n; n = n.nextSibling ) {
-                       if ( n.nodeType === 1 && n !== elem ) {
-                               r.push( n );
-                       }
-               }
-
-               return r;
-       }
-});
-
-// Implement the identical functionality for filter and not
-function winnow( elements, qualifier, keep ) {
-       if ( jQuery.isFunction( qualifier ) ) {
-               return jQuery.grep(elements, function( elem, i ) {
-                       var retVal = !!qualifier.call( elem, i, elem );
-                       return retVal === keep;
-               });
-
-       } else if ( qualifier.nodeType ) {
-               return jQuery.grep(elements, function( elem, i ) {
-                       return (elem === qualifier) === keep;
-               });
-
-       } else if ( typeof qualifier === "string" ) {
-               var filtered = jQuery.grep(elements, function( elem ) {
-                       return elem.nodeType === 1;
-               });
-
-               if ( isSimple.test( qualifier ) ) {
-                       return jQuery.filter(qualifier, filtered, !keep);
-               } else {
-                       qualifier = jQuery.filter( qualifier, filtered );
-               }
-       }
-
-       return jQuery.grep(elements, function( elem, i ) {
-               return (jQuery.inArray( elem, qualifier ) >= 0) === keep;
-       });
-}
-
-
-
-
-var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
-       rleadingWhitespace = /^\s+/,
-       rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
-       rtagName = /<([\w:]+)/,
-       rtbody = /<tbody/i,
-       rhtml = /<|&#?\w+;/,
-       rnocache = /<(?:script|object|embed|option|style)/i,
-       // checked="checked" or checked
-       rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
-       wrapMap = {
-               option: [ 1, "<select multiple='multiple'>", "</select>" ],
-               legend: [ 1, "<fieldset>", "</fieldset>" ],
-               thead: [ 1, "<table>", "</table>" ],
-               tr: [ 2, "<table><tbody>", "</tbody></table>" ],
-               td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
-               col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
-               area: [ 1, "<map>", "</map>" ],
-               _default: [ 0, "", "" ]
-       };
-
-wrapMap.optgroup = wrapMap.option;
-wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
-wrapMap.th = wrapMap.td;
-
-// IE can't serialize <link> and <script> tags normally
-if ( !jQuery.support.htmlSerialize ) {
-       wrapMap._default = [ 1, "div<div>", "</div>" ];
-}
-
-jQuery.fn.extend({
-       text: function( text ) {
-               if ( jQuery.isFunction(text) ) {
-                       return this.each(function(i) {
-                               var self = jQuery( this );
-
-                               self.text( text.call(this, i, self.text()) );
-                       });
-               }
-
-               if ( typeof text !== "object" && text !== undefined ) {
-                       return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
-               }
-
-               return jQuery.text( this );
-       },
-
-       wrapAll: function( html ) {
-               if ( jQuery.isFunction( html ) ) {
-                       return this.each(function(i) {
-                               jQuery(this).wrapAll( html.call(this, i) );
-                       });
-               }
-
-               if ( this[0] ) {
-                       // The elements to wrap the target around
-                       var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
-
-                       if ( this[0].parentNode ) {
-                               wrap.insertBefore( this[0] );
-                       }
-
-                       wrap.map(function() {
-                               var elem = this;
-
-                               while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
-                                       elem = elem.firstChild;
-                               }
-
-                               return elem;
-                       }).append(this);
-               }
-
-               return this;
-       },
-
-       wrapInner: function( html ) {
-               if ( jQuery.isFunction( html ) ) {
-                       return this.each(function(i) {
-                               jQuery(this).wrapInner( html.call(this, i) );
-                       });
-               }
-
-               return this.each(function() {
-                       var self = jQuery( this ),
-                               contents = self.contents();
-
-                       if ( contents.length ) {
-                               contents.wrapAll( html );
-
-                       } else {
-                               self.append( html );
-                       }
-               });
-       },
-
-       wrap: function( html ) {
-               return this.each(function() {
-                       jQuery( this ).wrapAll( html );
-               });
-       },
-
-       unwrap: function() {
-               return this.parent().each(function() {
-                       if ( !jQuery.nodeName( this, "body" ) ) {
-                               jQuery( this ).replaceWith( this.childNodes );
-                       }
-               }).end();
-       },
-
-       append: function() {
-               return this.domManip(arguments, true, function( elem ) {
-                       if ( this.nodeType === 1 ) {
-                               this.appendChild( elem );
-                       }
-               });
-       },
-
-       prepend: function() {
-               return this.domManip(arguments, true, function( elem ) {
-                       if ( this.nodeType === 1 ) {
-                               this.insertBefore( elem, this.firstChild );
-                       }
-               });
-       },
-
-       before: function() {
-               if ( this[0] && this[0].parentNode ) {
-                       return this.domManip(arguments, false, function( elem ) {
-                               this.parentNode.insertBefore( elem, this );
-                       });
-               } else if ( arguments.length ) {
-                       var set = jQuery(arguments[0]);
-                       set.push.apply( set, this.toArray() );
-                       return this.pushStack( set, "before", arguments );
-               }
-       },
-
-       after: function() {
-               if ( this[0] && this[0].parentNode ) {
-                       return this.domManip(arguments, false, function( elem ) {
-                               this.parentNode.insertBefore( elem, this.nextSibling );
-                       });
-               } else if ( arguments.length ) {
-                       var set = this.pushStack( this, "after", arguments );
-                       set.push.apply( set, jQuery(arguments[0]).toArray() );
-                       return set;
-               }
-       },
-
-       // keepData is for internal use only--do not document
-       remove: function( selector, keepData ) {
-               for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
-                       if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
-                               if ( !keepData && elem.nodeType === 1 ) {
-                                       jQuery.cleanData( elem.getElementsByTagName("*") );
-                                       jQuery.cleanData( [ elem ] );
-                               }
-
-                               if ( elem.parentNode ) {
-                                       elem.parentNode.removeChild( elem );
-                               }
-                       }
-               }
-
-               return this;
-       },
-
-       empty: function() {
-               for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
-                       // Remove element nodes and prevent memory leaks
-                       if ( elem.nodeType === 1 ) {
-                               jQuery.cleanData( elem.getElementsByTagName("*") );
-                       }
-
-                       // Remove any remaining nodes
-                       while ( elem.firstChild ) {
-                               elem.removeChild( elem.firstChild );
-                       }
-               }
-
-               return this;
-       },
-
-       clone: function( dataAndEvents, deepDataAndEvents ) {
-               dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
-               deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
-
-               return this.map( function () {
-                       return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
-               });
-       },
-
-       html: function( value ) {
-               if ( value === undefined ) {
-                       return this[0] && this[0].nodeType === 1 ?
-                               this[0].innerHTML.replace(rinlinejQuery, "") :
-                               null;
-
-               // See if we can take a shortcut and just use innerHTML
-               } else if ( typeof value === "string" && !rnocache.test( value ) &&
-                       (jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
-                       !wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {
-
-                       value = value.replace(rxhtmlTag, "<$1></$2>");
-
-                       try {
-                               for ( var i = 0, l = this.length; i < l; i++ ) {
-                                       // Remove element nodes and prevent memory leaks
-                                       if ( this[i].nodeType === 1 ) {
-                                               jQuery.cleanData( this[i].getElementsByTagName("*") );
-                                               this[i].innerHTML = value;
-                                       }
-                               }
-
-                       // If using innerHTML throws an exception, use the fallback method
-                       } catch(e) {
-                               this.empty().append( value );
-                       }
-
-               } else if ( jQuery.isFunction( value ) ) {
-                       this.each(function(i){
-                               var self = jQuery( this );
-
-                               self.html( value.call(this, i, self.html()) );
-                       });
-
-               } else {
-                       this.empty().append( value );
-               }
-
-               return this;
-       },
-
-       replaceWith: function( value ) {
-               if ( this[0] && this[0].parentNode ) {
-                       // Make sure that the elements are removed from the DOM before they are inserted
-                       // this can help fix replacing a parent with child elements
-                       if ( jQuery.isFunction( value ) ) {
-                               return this.each(function(i) {
-                                       var self = jQuery(this), old = self.html();
-                                       self.replaceWith( value.call( this, i, old ) );
-                               });
-                       }
-
-                       if ( typeof value !== "string" ) {
-                               value = jQuery( value ).detach();
-                       }
-
-                       return this.each(function() {
-                               var next = this.nextSibling,
-                                       parent = this.parentNode;
-
-                               jQuery( this ).remove();
-
-                               if ( next ) {
-                                       jQuery(next).before( value );
-                               } else {
-                                       jQuery(parent).append( value );
-                               }
-                       });
-               } else {
-                       return this.length ?
-                               this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
-                               this;
-               }
-       },
-
-       detach: function( selector ) {
-               return this.remove( selector, true );
-       },
-
-       domManip: function( args, table, callback ) {
-               var results, first, fragment, parent,
-                       value = args[0],
-                       scripts = [];
-
-               // We can't cloneNode fragments that contain checked, in WebKit
-               if ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test( value ) ) {
-                       return this.each(function() {
-                               jQuery(this).domManip( args, table, callback, true );
-                       });
-               }
-
-               if ( jQuery.isFunction(value) ) {
-                       return this.each(function(i) {
-                               var self = jQuery(this);
-                               args[0] = value.call(this, i, table ? self.html() : undefined);
-                               self.domManip( args, table, callback );
-                       });
-               }
-
-               if ( this[0] ) {
-                       parent = value && value.parentNode;
-
-                       // If we're in a fragment, just use that instead of building a new one
-                       if ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) {
-                               results = { fragment: parent };
-
-                       } else {
-                               results = jQuery.buildFragment( args, this, scripts );
-                       }
-
-                       fragment = results.fragment;
-
-                       if ( fragment.childNodes.length === 1 ) {
-                               first = fragment = fragment.firstChild;
-                       } else {
-                               first = fragment.firstChild;
-                       }
-
-                       if ( first ) {
-                               table = table && jQuery.nodeName( first, "tr" );
-
-                               for ( var i = 0, l = this.length, lastIndex = l - 1; i < l; i++ ) {
-                                       callback.call(
-                                               table ?
-                                                       root(this[i], first) :
-                                                       this[i],
-                                               // Make sure that we do not leak memory by inadvertently discarding
-                                               // the original fragment (which might have attached data) instead of
-                                               // using it; in addition, use the original fragment object for the last
-                                               // item instead of first because it can end up being emptied incorrectly
-                                               // in certain situations (Bug #8070).
-                                               // Fragments from the fragment cache must always be cloned and never used
-                                               // in place.
-                                               results.cacheable || (l > 1 && i < lastIndex) ?
-                                                       jQuery.clone( fragment, true, true ) :
-                                                       fragment
-                                       );
-                               }
-                       }
-
-                       if ( scripts.length ) {
-                               jQuery.each( scripts, evalScript );
-                       }
-               }
-
-               return this;
-       }
-});
-
-function root( elem, cur ) {
-       return jQuery.nodeName(elem, "table") ?
-               (elem.getElementsByTagName("tbody")[0] ||
-               elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
-               elem;
-}
-
-function cloneCopyEvent( src, dest ) {
-
-       if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
-               return;
-       }
-
-       var internalKey = jQuery.expando,
-               oldData = jQuery.data( src ),
-               curData = jQuery.data( dest, oldData );
-
-       // Switch to use the internal data object, if it exists, for the next
-       // stage of data copying
-       if ( (oldData = oldData[ internalKey ]) ) {
-               var events = oldData.events;
-                               curData = curData[ internalKey ] = jQuery.extend({}, oldData);
-
-               if ( events ) {
-                       delete curData.handle;
-                       curData.events = {};
-
-                       for ( var type in events ) {
-                               for ( var i = 0, l = events[ type ].length; i < l; i++ ) {
-                                       jQuery.event.add( dest, type + ( events[ type ][ i ].namespace ? "." : "" ) + events[ type ][ i ].namespace, events[ type ][ i ], events[ type ][ i ].data );
-                               }
-                       }
-               }
-       }
-}
-
-function cloneFixAttributes(src, dest) {
-       // We do not need to do anything for non-Elements
-       if ( dest.nodeType !== 1 ) {
-               return;
-       }
-
-       var nodeName = dest.nodeName.toLowerCase();
-
-       // clearAttributes removes the attributes, which we don't want,
-       // but also removes the attachEvent events, which we *do* want
-       dest.clearAttributes();
-
-       // mergeAttributes, in contrast, only merges back on the
-       // original attributes, not the events
-       dest.mergeAttributes(src);
-
-       // IE6-8 fail to clone children inside object elements that use
-       // the proprietary classid attribute value (rather than the type
-       // attribute) to identify the type of content to display
-       if ( nodeName === "object" ) {
-               dest.outerHTML = src.outerHTML;
-
-       } else if ( nodeName === "input" && (src.type === "checkbox" || src.type === "radio") ) {
-               // IE6-8 fails to persist the checked state of a cloned checkbox
-               // or radio button. Worse, IE6-7 fail to give the cloned element
-               // a checked appearance if the defaultChecked value isn't also set
-               if ( src.checked ) {
-                       dest.defaultChecked = dest.checked = src.checked;
-               }
-
-               // IE6-7 get confused and end up setting the value of a cloned
-               // checkbox/radio button to an empty string instead of "on"
-               if ( dest.value !== src.value ) {
-                       dest.value = src.value;
-               }
-
-       // IE6-8 fails to return the selected option to the default selected
-       // state when cloning options
-       } else if ( nodeName === "option" ) {
-               dest.selected = src.defaultSelected;
-
-       // IE6-8 fails to set the defaultValue to the correct value when
-       // cloning other types of input fields
-       } else if ( nodeName === "input" || nodeName === "textarea" ) {
-               dest.defaultValue = src.defaultValue;
-       }
-
-       // Event data gets referenced instead of copied if the expando
-       // gets copied too
-       dest.removeAttribute( jQuery.expando );
-}
-
-jQuery.buildFragment = function( args, nodes, scripts ) {
-       var fragment, cacheable, cacheresults,
-               doc = (nodes && nodes[0] ? nodes[0].ownerDocument || nodes[0] : document);
-
-       // Only cache "small" (1/2 KB) HTML strings that are associated with the main document
-       // Cloning options loses the selected state, so don't cache them
-       // IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
-       // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
-       if ( args.length === 1 && typeof args[0] === "string" && args[0].length < 512 && doc === document &&
-               args[0].charAt(0) === "<" && !rnocache.test( args[0] ) && (jQuery.support.checkClone || !rchecked.test( args[0] )) ) {
-
-               cacheable = true;
-               cacheresults = jQuery.fragments[ args[0] ];
-               if ( cacheresults ) {
-                       if ( cacheresults !== 1 ) {
-                               fragment = cacheresults;
-                       }
-               }
-       }
-
-       if ( !fragment ) {
-               fragment = doc.createDocumentFragment();
-               jQuery.clean( args, doc, fragment, scripts );
-       }
-
-       if ( cacheable ) {
-               jQuery.fragments[ args[0] ] = cacheresults ? fragment : 1;
-       }
-
-       return { fragment: fragment, cacheable: cacheable };
-};
-
-jQuery.fragments = {};
-
-jQuery.each({
-       appendTo: "append",
-       prependTo: "prepend",
-       insertBefore: "before",
-       insertAfter: "after",
-       replaceAll: "replaceWith"
-}, function( name, original ) {
-       jQuery.fn[ name ] = function( selector ) {
-               var ret = [],
-                       insert = jQuery( selector ),
-                       parent = this.length === 1 && this[0].parentNode;
-
-               if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {
-                       insert[ original ]( this[0] );
-                       return this;
-
-               } else {
-                       for ( var i = 0, l = insert.length; i < l; i++ ) {
-                               var elems = (i > 0 ? this.clone(true) : this).get();
-                               jQuery( insert[i] )[ original ]( elems );
-                               ret = ret.concat( elems );
-                       }
-
-                       return this.pushStack( ret, name, insert.selector );
-               }
-       };
-});
-
-function getAll( elem ) {
-       if ( "getElementsByTagName" in elem ) {
-               return elem.getElementsByTagName( "*" );
-       
-       } else if ( "querySelectorAll" in elem ) {
-               return elem.querySelectorAll( "*" );
-
-       } else {
-               return [];
-       }
-}
-
-jQuery.extend({
-       clone: function( elem, dataAndEvents, deepDataAndEvents ) {
-               var clone = elem.cloneNode(true),
-                               srcElements,
-                               destElements,
-                               i;
-
-               if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
-                               (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
-                       // IE copies events bound via attachEvent when using cloneNode.
-                       // Calling detachEvent on the clone will also remove the events
-                       // from the original. In order to get around this, we use some
-                       // proprietary methods to clear the events. Thanks to MooTools
-                       // guys for this hotness.
-
-                       cloneFixAttributes( elem, clone );
-
-                       // Using Sizzle here is crazy slow, so we use getElementsByTagName
-                       // instead
-                       srcElements = getAll( elem );
-                       destElements = getAll( clone );
-
-                       // Weird iteration because IE will replace the length property
-                       // with an element if you are cloning the body and one of the
-                       // elements on the page has a name or id of "length"
-                       for ( i = 0; srcElements[i]; ++i ) {
-                               cloneFixAttributes( srcElements[i], destElements[i] );
-                       }
-               }
-
-               // Copy the events from the original to the clone
-               if ( dataAndEvents ) {
-                       cloneCopyEvent( elem, clone );
-
-                       if ( deepDataAndEvents ) {
-                               srcElements = getAll( elem );
-                               destElements = getAll( clone );
-
-                               for ( i = 0; srcElements[i]; ++i ) {
-                                       cloneCopyEvent( srcElements[i], destElements[i] );
-                               }
-                       }
-               }
-
-               // Return the cloned set
-               return clone;
-},
-       clean: function( elems, context, fragment, scripts ) {
-               context = context || document;
-
-               // !context.createElement fails in IE with an error but returns typeof 'object'
-               if ( typeof context.createElement === "undefined" ) {
-                       context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
-               }
-
-               var ret = [];
-
-               for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
-                       if ( typeof elem === "number" ) {
-                               elem += "";
-                       }
-
-                       if ( !elem ) {
-                               continue;
-                       }
-
-                       // Convert html string into DOM nodes
-                       if ( typeof elem === "string" && !rhtml.test( elem ) ) {
-                               elem = context.createTextNode( elem );
-
-                       } else if ( typeof elem === "string" ) {
-                               // Fix "XHTML"-style tags in all browsers
-                               elem = elem.replace(rxhtmlTag, "<$1></$2>");
-
-                               // Trim whitespace, otherwise indexOf won't work as expected
-                               var tag = (rtagName.exec( elem ) || ["", ""])[1].toLowerCase(),
-                                       wrap = wrapMap[ tag ] || wrapMap._default,
-                                       depth = wrap[0],
-                                       div = context.createElement("div");
-
-                               // Go to html and back, then peel off extra wrappers
-                               div.innerHTML = wrap[1] + elem + wrap[2];
-
-                               // Move to the right depth
-                               while ( depth-- ) {
-                                       div = div.lastChild;
-                               }
-
-                               // Remove IE's autoinserted <tbody> from table fragments
-                               if ( !jQuery.support.tbody ) {
-
-                                       // String was a <table>, *may* have spurious <tbody>
-                                       var hasBody = rtbody.test(elem),
-                                               tbody = tag === "table" && !hasBody ?
-                                                       div.firstChild && div.firstChild.childNodes :
-
-                                                       // String was a bare <thead> or <tfoot>
-                                                       wrap[1] === "<table>" && !hasBody ?
-                                                               div.childNodes :
-                                                               [];
-
-                                       for ( var j = tbody.length - 1; j >= 0 ; --j ) {
-                                               if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
-                                                       tbody[ j ].parentNode.removeChild( tbody[ j ] );
-                                               }
-                                       }
-
-                               }
-
-                               // IE completely kills leading whitespace when innerHTML is used
-                               if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
-                                       div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
-                               }
-
-                               elem = div.childNodes;
-                       }
-
-                       if ( elem.nodeType ) {
-                               ret.push( elem );
-                       } else {
-                               ret = jQuery.merge( ret, elem );
-                       }
-               }
-
-               if ( fragment ) {
-                       for ( i = 0; ret[i]; i++ ) {
-                               if ( scripts && jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
-                                       scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );
-
-                               } else {
-                                       if ( ret[i].nodeType === 1 ) {
-                                               ret.splice.apply( ret, [i + 1, 0].concat(jQuery.makeArray(ret[i].getElementsByTagName("script"))) );
-                                       }
-                                       fragment.appendChild( ret[i] );
-                               }
-                       }
-               }
-
-               return ret;
-       },
-
-       cleanData: function( elems ) {
-               var data, id, cache = jQuery.cache, internalKey = jQuery.expando, special = jQuery.event.special,
-                       deleteExpando = jQuery.support.deleteExpando;
-
-               for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
-                       if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
-                               continue;
-                       }
-
-                       id = elem[ jQuery.expando ];
-
-                       if ( id ) {
-                               data = cache[ id ] && cache[ id ][ internalKey ];
-
-                               if ( data && data.events ) {
-                                       for ( var type in data.events ) {
-                                               if ( special[ type ] ) {
-                                                       jQuery.event.remove( elem, type );
-
-                                               // This is a shortcut to avoid jQuery.event.remove's overhead
-                                               } else {
-                                                       jQuery.removeEvent( elem, type, data.handle );
-                                               }
-                                       }
-
-                                       // Null the DOM reference to avoid IE6/7/8 leak (#7054)
-                                       if ( data.handle ) {
-                                               data.handle.elem = null;
-                                       }
-                               }
-
-                               if ( deleteExpando ) {
-                                       delete elem[ jQuery.expando ];
-
-                               } else if ( elem.removeAttribute ) {
-                                       elem.removeAttribute( jQuery.expando );
-                               }
-
-                               delete cache[ id ];
-                       }
-               }
-       }
-});
-
-function evalScript( i, elem ) {
-       if ( elem.src ) {
-               jQuery.ajax({
-                       url: elem.src,
-                       async: false,
-                       dataType: "script"
-               });
-       } else {
-               jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );
-       }
-
-       if ( elem.parentNode ) {
-               elem.parentNode.removeChild( elem );
-       }
-}
-
-
-
-
-var ralpha = /alpha\([^)]*\)/i,
-       ropacity = /opacity=([^)]*)/,
-       rdashAlpha = /-([a-z])/ig,
-       // fixed for IE9, see #8346
-       rupper = /([A-Z]|^ms)/g,
-       rnumpx = /^-?\d+(?:px)?$/i,
-       rnum = /^-?\d/,
-
-       cssShow = { position: "absolute", visibility: "hidden", display: "block" },
-       cssWidth = [ "Left", "Right" ],
-       cssHeight = [ "Top", "Bottom" ],
-       curCSS,
-
-       getComputedStyle,
-       currentStyle,
-
-       fcamelCase = function( all, letter ) {
-               return letter.toUpperCase();
-       };
-
-jQuery.fn.css = function( name, value ) {
-       // Setting 'undefined' is a no-op
-       if ( arguments.length === 2 && value === undefined ) {
-               return this;
-       }
-
-       return jQuery.access( this, name, value, true, function( elem, name, value ) {
-               return value !== undefined ?
-                       jQuery.style( elem, name, value ) :
-                       jQuery.css( elem, name );
-       });
-};
-
-jQuery.extend({
-       // Add in style property hooks for overriding the default
-       // behavior of getting and setting a style property
-       cssHooks: {
-               opacity: {
-                       get: function( elem, computed ) {
-                               if ( computed ) {
-                                       // We should always get a number back from opacity
-                                       var ret = curCSS( elem, "opacity", "opacity" );
-                                       return ret === "" ? "1" : ret;
-
-                               } else {
-                                       return elem.style.opacity;
-                               }
-                       }
-               }
-       },
-
-       // Exclude the following css properties to add px
-       cssNumber: {
-               "zIndex": true,
-               "fontWeight": true,
-               "opacity": true,
-               "zoom": true,
-               "lineHeight": true
-       },
-
-       // Add in properties whose names you wish to fix before
-       // setting or getting the value
-       cssProps: {
-               // normalize float css property
-               "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
-       },
-
-       // Get and set the style property on a DOM Node
-       style: function( elem, name, value, extra ) {
-               // Don't set styles on text and comment nodes
-               if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
-                       return;
-               }
-
-               // Make sure that we're working with the right name
-               var ret, origName = jQuery.camelCase( name ),
-                       style = elem.style, hooks = jQuery.cssHooks[ origName ];
-
-               name = jQuery.cssProps[ origName ] || origName;
-
-               // Check if we're setting a value
-               if ( value !== undefined ) {
-                       // Make sure that NaN and null values aren't set. See: #7116
-                       if ( typeof value === "number" && isNaN( value ) || value == null ) {
-                               return;
-                       }
-
-                       // If a number was passed in, add 'px' to the (except for certain CSS properties)
-                       if ( typeof value === "number" && !jQuery.cssNumber[ origName ] ) {
-                               value += "px";
-                       }
-
-                       // If a hook was provided, use that value, otherwise just set the specified value
-                       if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value )) !== undefined ) {
-                               // Wrapped to prevent IE from throwing errors when 'invalid' values are provided
-                               // Fixes bug #5509
-                               try {
-                                       style[ name ] = value;
-                               } catch(e) {}
-                       }
-
-               } else {
-                       // If a hook was provided get the non-computed value from there
-                       if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
-                               return ret;
-                       }
-
-                       // Otherwise just get the value from the style object
-                       return style[ name ];
-               }
-       },
-
-       css: function( elem, name, extra ) {
-               // Make sure that we're working with the right name
-               var ret, origName = jQuery.camelCase( name ),
-                       hooks = jQuery.cssHooks[ origName ];
-
-               name = jQuery.cssProps[ origName ] || origName;
-
-               // If a hook was provided get the computed value from there
-               if ( hooks && "get" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) {
-                       return ret;
-
-               // Otherwise, if a way to get the computed value exists, use that
-               } else if ( curCSS ) {
-                       return curCSS( elem, name, origName );
-               }
-       },
-
-       // A method for quickly swapping in/out CSS properties to get correct calculations
-       swap: function( elem, options, callback ) {
-               var old = {};
-
-               // Remember the old values, and insert the new ones
-               for ( var name in options ) {
-                       old[ name ] = elem.style[ name ];
-                       elem.style[ name ] = options[ name ];
-               }
-
-               callback.call( elem );
-
-               // Revert the old values
-               for ( name in options ) {
-                       elem.style[ name ] = old[ name ];
-               }
-       },
-
-       camelCase: function( string ) {
-               return string.replace( rdashAlpha, fcamelCase );
-       }
-});
-
-// DEPRECATED, Use jQuery.css() instead
-jQuery.curCSS = jQuery.css;
-
-jQuery.each(["height", "width"], function( i, name ) {
-       jQuery.cssHooks[ name ] = {
-               get: function( elem, computed, extra ) {
-                       var val;
-
-                       if ( computed ) {
-                               if ( elem.offsetWidth !== 0 ) {
-                                       val = getWH( elem, name, extra );
-
-                               } else {
-                                       jQuery.swap( elem, cssShow, function() {
-                                               val = getWH( elem, name, extra );
-                                       });
-                               }
-
-                               if ( val <= 0 ) {
-                                       val = curCSS( elem, name, name );
-
-                                       if ( val === "0px" && currentStyle ) {
-                                               val = currentStyle( elem, name, name );
-                                       }
-
-                                       if ( val != null ) {
-                                               // Should return "auto" instead of 0, use 0 for
-                                               // temporary backwards-compat
-                                               return val === "" || val === "auto" ? "0px" : val;
-                                       }
-                               }
-
-                               if ( val < 0 || val == null ) {
-                                       val = elem.style[ name ];
-
-                                       // Should return "auto" instead of 0, use 0 for
-                                       // temporary backwards-compat
-                                       return val === "" || val === "auto" ? "0px" : val;
-                               }
-
-                               return typeof val === "string" ? val : val + "px";
-                       }
-               },
-
-               set: function( elem, value ) {
-                       if ( rnumpx.test( value ) ) {
-                               // ignore negative width and height values #1599
-                               value = parseFloat(value);
-
-                               if ( value >= 0 ) {
-                                       return value + "px";
-                               }
-
-                       } else {
-                               return value;
-                       }
-               }
-       };
-});
-
-if ( !jQuery.support.opacity ) {
-       jQuery.cssHooks.opacity = {
-               get: function( elem, computed ) {
-                       // IE uses filters for opacity
-                       return ropacity.test((computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "") ?
-                               (parseFloat(RegExp.$1) / 100) + "" :
-                               computed ? "1" : "";
-               },
-
-               set: function( elem, value ) {
-                       var style = elem.style;
-
-                       // IE has trouble with opacity if it does not have layout
-                       // Force it by setting the zoom level
-                       style.zoom = 1;
-
-                       // Set the alpha filter to set the opacity
-                       var opacity = jQuery.isNaN(value) ?
-                               "" :
-                               "alpha(opacity=" + value * 100 + ")",
-                               filter = style.filter || "";
-
-                       style.filter = ralpha.test(filter) ?
-                               filter.replace(ralpha, opacity) :
-                               style.filter + ' ' + opacity;
-               }
-       };
-}
-
-jQuery(function() {
-       // This hook cannot be added until DOM ready because the support test
-       // for it is not run until after DOM ready
-       if ( !jQuery.support.reliableMarginRight ) {
-               jQuery.cssHooks.marginRight = {
-                       get: function( elem, computed ) {
-                               // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
-                               // Work around by temporarily setting element display to inline-block
-                               var ret;
-                               jQuery.swap( elem, { "display": "inline-block" }, function() {
-                                       if ( computed ) {
-                                               ret = curCSS( elem, "margin-right", "marginRight" );
-                                       } else {
-                                               ret = elem.style.marginRight;
-                                       }
-                               });
-                               return ret;
-                       }
-               };
-       }
-});
-
-if ( document.defaultView && document.defaultView.getComputedStyle ) {
-       getComputedStyle = function( elem, newName, name ) {
-               var ret, defaultView, computedStyle;
-
-               name = name.replace( rupper, "-$1" ).toLowerCase();
-
-               if ( !(defaultView = elem.ownerDocument.defaultView) ) {
-                       return undefined;
-               }
-
-               if ( (computedStyle = defaultView.getComputedStyle( elem, null )) ) {
-                       ret = computedStyle.getPropertyValue( name );
-                       if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
-                               ret = jQuery.style( elem, name );
-                       }
-               }
-
-               return ret;
-       };
-}
-
-if ( document.documentElement.currentStyle ) {
-       currentStyle = function( elem, name ) {
-               var left,
-                       ret = elem.currentStyle && elem.currentStyle[ name ],
-                       rsLeft = elem.runtimeStyle && elem.runtimeStyle[ name ],
-                       style = elem.style;
-
-               // From the awesome hack by Dean Edwards
-               // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
-
-               // If we're not dealing with a regular pixel number
-               // but a number that has a weird ending, we need to convert it to pixels
-               if ( !rnumpx.test( ret ) && rnum.test( ret ) ) {
-                       // Remember the original values
-                       left = style.left;
-
-                       // Put in the new values to get a computed value out
-                       if ( rsLeft ) {
-                               elem.runtimeStyle.left = elem.currentStyle.left;
-                       }
-                       style.left = name === "fontSize" ? "1em" : (ret || 0);
-                       ret = style.pixelLeft + "px";
-
-                       // Revert the changed values
-                       style.left = left;
-                       if ( rsLeft ) {
-                               elem.runtimeStyle.left = rsLeft;
-                       }
-               }
-
-               return ret === "" ? "auto" : ret;
-       };
-}
-
-curCSS = getComputedStyle || currentStyle;
-
-function getWH( elem, name, extra ) {
-       var which = name === "width" ? cssWidth : cssHeight,
-               val = name === "width" ? elem.offsetWidth : elem.offsetHeight;
-
-       if ( extra === "border" ) {
-               return val;
-       }
-
-       jQuery.each( which, function() {
-               if ( !extra ) {
-                       val -= parseFloat(jQuery.css( elem, "padding" + this )) || 0;
-               }
-
-               if ( extra === "margin" ) {
-                       val += parseFloat(jQuery.css( elem, "margin" + this )) || 0;
-
-               } else {
-                       val -= parseFloat(jQuery.css( elem, "border" + this + "Width" )) || 0;
-               }
-       });
-
-       return val;
-}
-
-if ( jQuery.expr && jQuery.expr.filters ) {
-       jQuery.expr.filters.hidden = function( elem ) {
-               var width = elem.offsetWidth,
-                       height = elem.offsetHeight;
-
-               return (width === 0 && height === 0) || (!jQuery.support.reliableHiddenOffsets && (elem.style.display || jQuery.css( elem, "display" )) === "none");
-       };
-
-       jQuery.expr.filters.visible = function( elem ) {
-               return !jQuery.expr.filters.hidden( elem );
-       };
-}
-
-
-
-
-var r20 = /%20/g,
-       rbracket = /\[\]$/,
-       rCRLF = /\r?\n/g,
-       rhash = /#.*$/,
-       rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
-       rinput = /^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
-       // #7653, #8125, #8152: local protocol detection
-       rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|widget):$/,
-       rnoContent = /^(?:GET|HEAD)$/,
-       rprotocol = /^\/\//,
-       rquery = /\?/,
-       rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
-       rselectTextarea = /^(?:select|textarea)/i,
-       rspacesAjax = /\s+/,
-       rts = /([?&])_=[^&]*/,
-       rucHeaders = /(^|\-)([a-z])/g,
-       rucHeadersFunc = function( _, $1, $2 ) {
-               return $1 + $2.toUpperCase();
-       },
-       rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,
-
-       // Keep a copy of the old load method
-       _load = jQuery.fn.load,
-
-       /* Prefilters
-        * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
-        * 2) These are called:
-        *    - BEFORE asking for a transport
-        *    - AFTER param serialization (s.data is a string if s.processData is true)
-        * 3) key is the dataType
-        * 4) the catchall symbol "*" can be used
-        * 5) execution will start with transport dataType and THEN continue down to "*" if needed
-        */
-       prefilters = {},
-
-       /* Transports bindings
-        * 1) key is the dataType
-        * 2) the catchall symbol "*" can be used
-        * 3) selection will start with transport dataType and THEN go to "*" if needed
-        */
-       transports = {},
-
-       // Document location
-       ajaxLocation,
-
-       // Document location segments
-       ajaxLocParts;
-
-// #8138, IE may throw an exception when accessing
-// a field from document.location if document.domain has been set
-try {
-       ajaxLocation = document.location.href;
-} catch( e ) {
-       // Use the href attribute of an A element
-       // since IE will modify it given document.location
-       ajaxLocation = document.createElement( "a" );
-       ajaxLocation.href = "";
-       ajaxLocation = ajaxLocation.href;
-}
-
-// Segment location into parts
-ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
-
-// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
-function addToPrefiltersOrTransports( structure ) {
-
-       // dataTypeExpression is optional and defaults to "*"
-       return function( dataTypeExpression, func ) {
-
-               if ( typeof dataTypeExpression !== "string" ) {
-                       func = dataTypeExpression;
-                       dataTypeExpression = "*";
-               }
-
-               if ( jQuery.isFunction( func ) ) {
-                       var dataTypes = dataTypeExpression.toLowerCase().split( rspacesAjax ),
-                               i = 0,
-                               length = dataTypes.length,
-                               dataType,
-                               list,
-                               placeBefore;
-
-                       // For each dataType in the dataTypeExpression
-                       for(; i < length; i++ ) {
-                               dataType = dataTypes[ i ];
-                               // We control if we're asked to add before
-                               // any existing element
-                               placeBefore = /^\+/.test( dataType );
-                               if ( placeBefore ) {
-                                       dataType = dataType.substr( 1 ) || "*";
-                               }
-                               list = structure[ dataType ] = structure[ dataType ] || [];
-                               // then we add to the structure accordingly
-                               list[ placeBefore ? "unshift" : "push" ]( func );
-                       }
-               }
-       };
-}
-
-//Base inspection function for prefilters and transports
-function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,
-               dataType /* internal */, inspected /* internal */ ) {
-
-       dataType = dataType || options.dataTypes[ 0 ];
-       inspected = inspected || {};
-
-       inspected[ dataType ] = true;
-
-       var list = structure[ dataType ],
-               i = 0,
-               length = list ? list.length : 0,
-               executeOnly = ( structure === prefilters ),
-               selection;
-
-       for(; i < length && ( executeOnly || !selection ); i++ ) {
-               selection = list[ i ]( options, originalOptions, jqXHR );
-               // If we got redirected to another dataType
-               // we try there if executing only and not done already
-               if ( typeof selection === "string" ) {
-                       if ( !executeOnly || inspected[ selection ] ) {
-                               selection = undefined;
-                       } else {
-                               options.dataTypes.unshift( selection );
-                               selection = inspectPrefiltersOrTransports(
-                                               structure, options, originalOptions, jqXHR, selection, inspected );
-                       }
-               }
-       }
-       // If we're only executing or nothing was selected
-       // we try the catchall dataType if not done already
-       if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) {
-               selection = inspectPrefiltersOrTransports(
-                               structure, options, originalOptions, jqXHR, "*", inspected );
-       }
-       // unnecessary when only executing (prefilters)
-       // but it'll be ignored by the caller in that case
-       return selection;
-}
-
-jQuery.fn.extend({
-       load: function( url, params, callback ) {
-               if ( typeof url !== "string" && _load ) {
-                       return _load.apply( this, arguments );
-
-               // Don't do a request if no elements are being requested
-               } else if ( !this.length ) {
-                       return this;
-               }
-
-               var off = url.indexOf( " " );
-               if ( off >= 0 ) {
-                       var selector = url.slice( off, url.length );
-                       url = url.slice( 0, off );
-               }
-
-               // Default to a GET request
-               var type = "GET";
-
-               // If the second parameter was provided
-               if ( params ) {
-                       // If it's a function
-                       if ( jQuery.isFunction( params ) ) {
-                               // We assume that it's the callback
-                               callback = params;
-                               params = undefined;
-
-                       // Otherwise, build a param string
-                       } else if ( typeof params === "object" ) {
-                               params = jQuery.param( params, jQuery.ajaxSettings.traditional );
-                               type = "POST";
-                       }
-               }
-
-               var self = this;
-
-               // Request the remote document
-               jQuery.ajax({
-                       url: url,
-                       type: type,
-                       dataType: "html",
-                       data: params,
-                       // Complete callback (responseText is used internally)
-                       complete: function( jqXHR, status, responseText ) {
-                               // Store the response as specified by the jqXHR object
-                               responseText = jqXHR.responseText;
-                               // If successful, inject the HTML into all the matched elements
-                               if ( jqXHR.isResolved() ) {
-                                       // #4825: Get the actual response in case
-                                       // a dataFilter is present in ajaxSettings
-                                       jqXHR.done(function( r ) {
-                                               responseText = r;
-                                       });
-                                       // See if a selector was specified
-                                       self.html( selector ?
-                                               // Create a dummy div to hold the results
-                                               jQuery("<div>")
-                                                       // inject the contents of the document in, removing the scripts
-                                                       // to avoid any 'Permission Denied' errors in IE
-                                                       .append(responseText.replace(rscript, ""))
-
-                                                       // Locate the specified elements
-                                                       .find(selector) :
-
-                                               // If not, just inject the full result
-                                               responseText );
-                               }
-
-                               if ( callback ) {
-                                       self.each( callback, [ responseText, status, jqXHR ] );
-                               }
-                       }
-               });
-
-               return this;
-       },
-
-       serialize: function() {
-               return jQuery.param( this.serializeArray() );
-       },
-
-       serializeArray: function() {
-               return this.map(function(){
-                       return this.elements ? jQuery.makeArray( this.elements ) : this;
-               })
-               .filter(function(){
-                       return this.name && !this.disabled &&
-                               ( this.checked || rselectTextarea.test( this.nodeName ) ||
-                                       rinput.test( this.type ) );
-               })
-               .map(function( i, elem ){
-                       var val = jQuery( this ).val();
-
-                       return val == null ?
-                               null :
-                               jQuery.isArray( val ) ?
-                                       jQuery.map( val, function( val, i ){
-                                               return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
-                                       }) :
-                                       { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
-               }).get();
-       }
-});
-
-// Attach a bunch of functions for handling common AJAX events
-jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){
-       jQuery.fn[ o ] = function( f ){
-               return this.bind( o, f );
-       };
-} );
-
-jQuery.each( [ "get", "post" ], function( i, method ) {
-       jQuery[ method ] = function( url, data, callback, type ) {
-               // shift arguments if data argument was omitted
-               if ( jQuery.isFunction( data ) ) {
-                       type = type || callback;
-                       callback = data;
-                       data = undefined;
-               }
-
-               return jQuery.ajax({
-                       type: method,
-                       url: url,
-                       data: data,
-                       success: callback,
-                       dataType: type
-               });
-       };
-} );
-
-jQuery.extend({
-
-       getScript: function( url, callback ) {
-               return jQuery.get( url, undefined, callback, "script" );
-       },
-
-       getJSON: function( url, data, callback ) {
-               return jQuery.get( url, data, callback, "json" );
-       },
-
-       // Creates a full fledged settings object into target
-       // with both ajaxSettings and settings fields.
-       // If target is omitted, writes into ajaxSettings.
-       ajaxSetup: function ( target, settings ) {
-               if ( !settings ) {
-                       // Only one parameter, we extend ajaxSettings
-                       settings = target;
-                       target = jQuery.extend( true, jQuery.ajaxSettings, settings );
-               } else {
-                       // target was provided, we extend into it
-                       jQuery.extend( true, target, jQuery.ajaxSettings, settings );
-               }
-               // Flatten fields we don't want deep extended
-               for( var field in { context: 1, url: 1 } ) {
-                       if ( field in settings ) {
-                               target[ field ] = settings[ field ];
-                       } else if( field in jQuery.ajaxSettings ) {
-                               target[ field ] = jQuery.ajaxSettings[ field ];
-                       }
-               }
-               return target;
-       },
-
-       ajaxSettings: {
-               url: ajaxLocation,
-               isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
-               global: true,
-               type: "GET",
-               contentType: "application/x-www-form-urlencoded",
-               processData: true,
-               async: true,
-               /*
-               timeout: 0,
-               data: null,
-               dataType: null,
-               username: null,
-               password: null,
-               cache: null,
-               traditional: false,
-               headers: {},
-               */
-
-               accepts: {
-                       xml: "application/xml, text/xml",
-                       html: "text/html",
-                       text: "text/plain",
-                       json: "application/json, text/javascript",
-                       "*": "*/*"
-               },
-
-               contents: {
-                       xml: /xml/,
-                       html: /html/,
-                       json: /json/
-               },
-
-               responseFields: {
-                       xml: "responseXML",
-                       text: "responseText"
-               },
-
-               // List of data converters
-               // 1) key format is "source_type destination_type" (a single space in-between)
-               // 2) the catchall symbol "*" can be used for source_type
-               converters: {
-
-                       // Convert anything to text
-                       "* text": window.String,
-
-                       // Text to html (true = no transformation)
-                       "text html": true,
-
-                       // Evaluate text as a json expression
-                       "text json": jQuery.parseJSON,
-
-                       // Parse text as xml
-                       "text xml": jQuery.parseXML
-               }
-       },
-
-       ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
-       ajaxTransport: addToPrefiltersOrTransports( transports ),
-
-       // Main method
-       ajax: function( url, options ) {
-
-               // If url is an object, simulate pre-1.5 signature
-               if ( typeof url === "object" ) {
-                       options = url;
-                       url = undefined;
-               }
-
-               // Force options to be an object
-               options = options || {};
-
-               var // Create the final options object
-                       s = jQuery.ajaxSetup( {}, options ),
-                       // Callbacks context
-                       callbackContext = s.context || s,
-                       // Context for global events
-                       // It's the callbackContext if one was provided in the options
-                       // and if it's a DOM node or a jQuery collection
-                       globalEventContext = callbackContext !== s &&
-                               ( callbackContext.nodeType || callbackContext instanceof jQuery ) ?
-                                               jQuery( callbackContext ) : jQuery.event,
-                       // Deferreds
-                       deferred = jQuery.Deferred(),
-                       completeDeferred = jQuery._Deferred(),
-                       // Status-dependent callbacks
-                       statusCode = s.statusCode || {},
-                       // ifModified key
-                       ifModifiedKey,
-                       // Headers (they are sent all at once)
-                       requestHeaders = {},
-                       // Response headers
-                       responseHeadersString,
-                       responseHeaders,
-                       // transport
-                       transport,
-                       // timeout handle
-                       timeoutTimer,
-                       // Cross-domain detection vars
-                       parts,
-                       // The jqXHR state
-                       state = 0,
-                       // To know if global events are to be dispatched
-                       fireGlobals,
-                       // Loop variable
-                       i,
-                       // Fake xhr
-                       jqXHR = {
-
-                               readyState: 0,
-
-                               // Caches the header
-                               setRequestHeader: function( name, value ) {
-                                       if ( !state ) {
-                                               requestHeaders[ name.toLowerCase().replace( rucHeaders, rucHeadersFunc ) ] = value;
-                                       }
-                                       return this;
-                               },
-
-                               // Raw string
-                               getAllResponseHeaders: function() {
-                                       return state === 2 ? responseHeadersString : null;
-                               },
-
-                               // Builds headers hashtable if needed
-                               getResponseHeader: function( key ) {
-                                       var match;
-                                       if ( state === 2 ) {
-                                               if ( !responseHeaders ) {
-                                                       responseHeaders = {};
-                                                       while( ( match = rheaders.exec( responseHeadersString ) ) ) {
-                                                               responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
-                                                       }
-                                               }
-                                               match = responseHeaders[ key.toLowerCase() ];
-                                       }
-                                       return match === undefined ? null : match;
-                               },
-
-                               // Overrides response content-type header
-                               overrideMimeType: function( type ) {
-                                       if ( !state ) {
-                                               s.mimeType = type;
-                                       }
-                                       return this;
-                               },
-
-                               // Cancel the request
-                               abort: function( statusText ) {
-                                       statusText = statusText || "abort";
-                                       if ( transport ) {
-                                               transport.abort( statusText );
-                                       }
-                                       done( 0, statusText );
-                                       return this;
-                               }
-                       };
-
-               // Callback for when everything is done
-               // It is defined here because jslint complains if it is declared
-               // at the end of the function (which would be more logical and readable)
-               function done( status, statusText, responses, headers ) {
-
-                       // Called once
-                       if ( state === 2 ) {
-                               return;
-                       }
-
-                       // State is "done" now
-                       state = 2;
-
-                       // Clear timeout if it exists
-                       if ( timeoutTimer ) {
-                               clearTimeout( timeoutTimer );
-                       }
-
-                       // Dereference transport for early garbage collection
-                       // (no matter how long the jqXHR object will be used)
-                       transport = undefined;
-
-                       // Cache response headers
-                       responseHeadersString = headers || "";
-
-                       // Set readyState
-                       jqXHR.readyState = status ? 4 : 0;
-
-                       var isSuccess,
-                               success,
-                               error,
-                               response = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined,
-                               lastModified,
-                               etag;
-
-                       // If successful, handle type chaining
-                       if ( status >= 200 && status < 300 || status === 304 ) {
-
-                               // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
-                               if ( s.ifModified ) {
-
-                                       if ( ( lastModified = jqXHR.getResponseHeader( "Last-Modified" ) ) ) {
-                                               jQuery.lastModified[ ifModifiedKey ] = lastModified;
-                                       }
-                                       if ( ( etag = jqXHR.getResponseHeader( "Etag" ) ) ) {
-                                               jQuery.etag[ ifModifiedKey ] = etag;
-                                       }
-                               }
-
-                               // If not modified
-                               if ( status === 304 ) {
-
-                                       statusText = "notmodified";
-                                       isSuccess = true;
-
-                               // If we have data
-                               } else {
-
-                                       try {
-                                               success = ajaxConvert( s, response );
-                                               statusText = "success";
-                                               isSuccess = true;
-                                       } catch(e) {
-                                               // We have a parsererror
-                                               statusText = "parsererror";
-                                               error = e;
-                                       }
-                               }
-                       } else {
-                               // We extract error from statusText
-                               // then normalize statusText and status for non-aborts
-                               error = statusText;
-                               if( !statusText || status ) {
-                                       statusText = "error";
-                                       if ( status < 0 ) {
-                                               status = 0;
-                                       }
-                               }
-                       }
-
-                       // Set data for the fake xhr object
-                       jqXHR.status = status;
-                       jqXHR.statusText = statusText;
-
-                       // Success/Error
-                       if ( isSuccess ) {
-                               deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
-                       } else {
-                               deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
-                       }
-
-                       // Status-dependent callbacks
-                       jqXHR.statusCode( statusCode );
-                       statusCode = undefined;
-
-                       if ( fireGlobals ) {
-                               globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ),
-                                               [ jqXHR, s, isSuccess ? success : error ] );
-                       }
-
-                       // Complete
-                       completeDeferred.resolveWith( callbackContext, [ jqXHR, statusText ] );
-
-                       if ( fireGlobals ) {
-                               globalEventContext.trigger( "ajaxComplete", [ jqXHR, s] );
-                               // Handle the global AJAX counter
-                               if ( !( --jQuery.active ) ) {
-                                       jQuery.event.trigger( "ajaxStop" );
-                               }
-                       }
-               }
-
-               // Attach deferreds
-               deferred.promise( jqXHR );
-               jqXHR.success = jqXHR.done;
-               jqXHR.error = jqXHR.fail;
-               jqXHR.complete = completeDeferred.done;
-
-               // Status-dependent callbacks
-               jqXHR.statusCode = function( map ) {
-                       if ( map ) {
-                               var tmp;
-                               if ( state < 2 ) {
-                                       for( tmp in map ) {
-                                               statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];
-                                       }
-                               } else {
-                                       tmp = map[ jqXHR.status ];
-                                       jqXHR.then( tmp, tmp );
-                               }
-                       }
-                       return this;
-               };
-
-               // Remove hash character (#7531: and string promotion)
-               // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
-               // We also use the url parameter if available
-               s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
-
-               // Extract dataTypes list
-               s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( rspacesAjax );
-
-               // Determine if a cross-domain request is in order
-               if ( s.crossDomain == null ) {
-                       parts = rurl.exec( s.url.toLowerCase() );
-                       s.crossDomain = !!( parts &&
-                               ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] ||
-                                       ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
-                                               ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
-                       );
-               }
-
-               // Convert data if not already a string
-               if ( s.data && s.processData && typeof s.data !== "string" ) {
-                       s.data = jQuery.param( s.data, s.traditional );
-               }
-
-               // Apply prefilters
-               inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
-
-               // If request was aborted inside a prefiler, stop there
-               if ( state === 2 ) {
-                       return false;
-               }
-
-               // We can fire global events as of now if asked to
-               fireGlobals = s.global;
-
-               // Uppercase the type
-               s.type = s.type.toUpperCase();
-
-               // Determine if request has content
-               s.hasContent = !rnoContent.test( s.type );
-
-               // Watch for a new set of requests
-               if ( fireGlobals && jQuery.active++ === 0 ) {
-                       jQuery.event.trigger( "ajaxStart" );
-               }
-
-               // More options handling for requests with no content
-               if ( !s.hasContent ) {
-
-                       // If data is available, append data to url
-                       if ( s.data ) {
-                               s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
-                       }
-
-                       // Get ifModifiedKey before adding the anti-cache parameter
-                       ifModifiedKey = s.url;
-
-                       // Add anti-cache in url if needed
-                       if ( s.cache === false ) {
-
-                               var ts = jQuery.now(),
-                                       // try replacing _= if it is there
-                                       ret = s.url.replace( rts, "$1_=" + ts );
-
-                               // if nothing was replaced, add timestamp to the end
-                               s.url = ret + ( (ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" );
-                       }
-               }
-
-               // Set the correct header, if data is being sent
-               if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
-                       requestHeaders[ "Content-Type" ] = s.contentType;
-               }
-
-               // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
-               if ( s.ifModified ) {
-                       ifModifiedKey = ifModifiedKey || s.url;
-                       if ( jQuery.lastModified[ ifModifiedKey ] ) {
-                               requestHeaders[ "If-Modified-Since" ] = jQuery.lastModified[ ifModifiedKey ];
-                       }
-                       if ( jQuery.etag[ ifModifiedKey ] ) {
-                               requestHeaders[ "If-None-Match" ] = jQuery.etag[ ifModifiedKey ];
-                       }
-               }
-
-               // Set the Accepts header for the server, depending on the dataType
-               requestHeaders.Accept = s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
-                       s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", */*; q=0.01" : "" ) :
-                       s.accepts[ "*" ];
-
-               // Check for headers option
-               for ( i in s.headers ) {
-                       jqXHR.setRequestHeader( i, s.headers[ i ] );
-               }
-
-               // Allow custom headers/mimetypes and early abort
-               if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
-                               // Abort if not done already
-                               jqXHR.abort();
-                               return false;
-
-               }
-
-               // Install callbacks on deferreds
-               for ( i in { success: 1, error: 1, complete: 1 } ) {
-                       jqXHR[ i ]( s[ i ] );
-               }
-
-               // Get transport
-               transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
-
-               // If no transport, we auto-abort
-               if ( !transport ) {
-                       done( -1, "No Transport" );
-               } else {
-                       jqXHR.readyState = 1;
-                       // Send global event
-                       if ( fireGlobals ) {
-                               globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
-                       }
-                       // Timeout
-                       if ( s.async && s.timeout > 0 ) {
-                               timeoutTimer = setTimeout( function(){
-                                       jqXHR.abort( "timeout" );
-                               }, s.timeout );
-                       }
-
-                       try {
-                               state = 1;
-                               transport.send( requestHeaders, done );
-                       } catch (e) {
-                               // Propagate exception as error if not done
-                               if ( status < 2 ) {
-                                       done( -1, e );
-                               // Simply rethrow otherwise
-                               } else {
-                                       jQuery.error( e );
-                               }
-                       }
-               }
-
-               return jqXHR;
-       },
-
-       // Serialize an array of form elements or a set of
-       // key/values into a query string
-       param: function( a, traditional ) {
-               var s = [],
-                       add = function( key, value ) {
-                               // If value is a function, invoke it and return its value
-                               value = jQuery.isFunction( value ) ? value() : value;
-                               s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
-                       };
-
-               // Set traditional to true for jQuery <= 1.3.2 behavior.
-               if ( traditional === undefined ) {
-                       traditional = jQuery.ajaxSettings.traditional;
-               }
-
-               // If an array was passed in, assume that it is an array of form elements.
-               if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
-                       // Serialize the form elements
-                       jQuery.each( a, function() {
-                               add( this.name, this.value );
-                       } );
-
-               } else {
-                       // If traditional, encode the "old" way (the way 1.3.2 or older
-                       // did it), otherwise encode params recursively.
-                       for ( var prefix in a ) {
-                               buildParams( prefix, a[ prefix ], traditional, add );
-                       }
-               }
-
-               // Return the resulting serialization
-               return s.join( "&" ).replace( r20, "+" );
-       }
-});
-
-function buildParams( prefix, obj, traditional, add ) {
-       if ( jQuery.isArray( obj ) && obj.length ) {
-               // Serialize array item.
-               jQuery.each( obj, function( i, v ) {
-                       if ( traditional || rbracket.test( prefix ) ) {
-                               // Treat each array item as a scalar.
-                               add( prefix, v );
-
-                       } else {
-                               // If array item is non-scalar (array or object), encode its
-                               // numeric index to resolve deserialization ambiguity issues.
-                               // Note that rack (as of 1.0.0) can't currently deserialize
-                               // nested arrays properly, and attempting to do so may cause
-                               // a server error. Possible fixes are to modify rack's
-                               // deserialization algorithm or to provide an option or flag
-                               // to force array serialization to be shallow.
-                               buildParams( prefix + "[" + ( typeof v === "object" || jQuery.isArray(v) ? i : "" ) + "]", v, traditional, add );
-                       }
-               });
-
-       } else if ( !traditional && obj != null && typeof obj === "object" ) {
-               // If we see an array here, it is empty and should be treated as an empty
-               // object
-               if ( jQuery.isArray( obj ) || jQuery.isEmptyObject( obj ) ) {
-                       add( prefix, "" );
-
-               // Serialize object item.
-               } else {
-                       for ( var name in obj ) {
-                               buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
-                       }
-               }
-
-       } else {
-               // Serialize scalar item.
-               add( prefix, obj );
-       }
-}
-
-// This is still on the jQuery object... for now
-// Want to move this to jQuery.ajax some day
-jQuery.extend({
-
-       // Counter for holding the number of active queries
-       active: 0,
-
-       // Last-Modified header cache for next request
-       lastModified: {},
-       etag: {}
-
-});
-
-/* Handles responses to an ajax request:
- * - sets all responseXXX fields accordingly
- * - finds the right dataType (mediates between content-type and expected dataType)
- * - returns the corresponding response
- */
-function ajaxHandleResponses( s, jqXHR, responses ) {
-
-       var contents = s.contents,
-               dataTypes = s.dataTypes,
-               responseFields = s.responseFields,
-               ct,
-               type,
-               finalDataType,
-               firstDataType;
-
-       // Fill responseXXX fields
-       for( type in responseFields ) {
-               if ( type in responses ) {
-                       jqXHR[ responseFields[type] ] = responses[ type ];
-               }
-       }
-
-       // Remove auto dataType and get content-type in the process
-       while( dataTypes[ 0 ] === "*" ) {
-               dataTypes.shift();
-               if ( ct === undefined ) {
-                       ct = s.mimeType || jqXHR.getResponseHeader( "content-type" );
-               }
-       }
-
-       // Check if we're dealing with a known content-type
-       if ( ct ) {
-               for ( type in contents ) {
-                       if ( contents[ type ] && contents[ type ].test( ct ) ) {
-                               dataTypes.unshift( type );
-                               break;
-                       }
-               }
-       }
-
-       // Check to see if we have a response for the expected dataType
-       if ( dataTypes[ 0 ] in responses ) {
-               finalDataType = dataTypes[ 0 ];
-       } else {
-               // Try convertible dataTypes
-               for ( type in responses ) {
-                       if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
-                               finalDataType = type;
-                               break;
-                       }
-                       if ( !firstDataType ) {
-                               firstDataType = type;
-                       }
-               }
-               // Or just use first one
-               finalDataType = finalDataType || firstDataType;
-       }
-
-       // If we found a dataType
-       // We add the dataType to the list if needed
-       // and return the corresponding response
-       if ( finalDataType ) {
-               if ( finalDataType !== dataTypes[ 0 ] ) {
-                       dataTypes.unshift( finalDataType );
-               }
-               return responses[ finalDataType ];
-       }
-}
-
-// Chain conversions given the request and the original response
-function ajaxConvert( s, response ) {
-
-       // Apply the dataFilter if provided
-       if ( s.dataFilter ) {
-               response = s.dataFilter( response, s.dataType );
-       }
-
-       var dataTypes = s.dataTypes,
-               converters = {},
-               i,
-               key,
-               length = dataTypes.length,
-               tmp,
-               // Current and previous dataTypes
-               current = dataTypes[ 0 ],
-               prev,
-               // Conversion expression
-               conversion,
-               // Conversion function
-               conv,
-               // Conversion functions (transitive conversion)
-               conv1,
-               conv2;
-
-       // For each dataType in the chain
-       for( i = 1; i < length; i++ ) {
-
-               // Create converters map
-               // with lowercased keys
-               if ( i === 1 ) {
-                       for( key in s.converters ) {
-                               if( typeof key === "string" ) {
-                                       converters[ key.toLowerCase() ] = s.converters[ key ];
-                               }
-                       }
-               }
-
-               // Get the dataTypes
-               prev = current;
-               current = dataTypes[ i ];
-
-               // If current is auto dataType, update it to prev
-               if( current === "*" ) {
-                       current = prev;
-               // If no auto and dataTypes are actually different
-               } else if ( prev !== "*" && prev !== current ) {
-
-                       // Get the converter
-                       conversion = prev + " " + current;
-                       conv = converters[ conversion ] || converters[ "* " + current ];
-
-                       // If there is no direct converter, search transitively
-                       if ( !conv ) {
-                               conv2 = undefined;
-                               for( conv1 in converters ) {
-                                       tmp = conv1.split( " " );
-                                       if ( tmp[ 0 ] === prev || tmp[ 0 ] === "*" ) {
-                                               conv2 = converters[ tmp[1] + " " + current ];
-                                               if ( conv2 ) {
-                                                       conv1 = converters[ conv1 ];
-                                                       if ( conv1 === true ) {
-                                                               conv = conv2;
-                                                       } else if ( conv2 === true ) {
-                                                               conv = conv1;
-                                                       }
-                                                       break;
-                                               }
-                                       }
-                               }
-                       }
-                       // If we found no converter, dispatch an error
-                       if ( !( conv || conv2 ) ) {
-                               jQuery.error( "No conversion from " + conversion.replace(" "," to ") );
-                       }
-                       // If found converter is not an equivalence
-                       if ( conv !== true ) {
-                               // Convert with 1 or 2 converters accordingly
-                               response = conv ? conv( response ) : conv2( conv1(response) );
-                       }
-               }
-       }
-       return response;
-}
-
-
-
-
-var jsc = jQuery.now(),
-       jsre = /(\=)\?(&|$)|\?\?/i;
-
-// Default jsonp settings
-jQuery.ajaxSetup({
-       jsonp: "callback",
-       jsonpCallback: function() {
-               return jQuery.expando + "_" + ( jsc++ );
-       }
-});
-
-// Detect, normalize options and install callbacks for jsonp requests
-jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
-
-       var dataIsString = ( typeof s.data === "string" );
-
-       if ( s.dataTypes[ 0 ] === "jsonp" ||
-               originalSettings.jsonpCallback ||
-               originalSettings.jsonp != null ||
-               s.jsonp !== false && ( jsre.test( s.url ) ||
-                               dataIsString && jsre.test( s.data ) ) ) {
-
-               var responseContainer,
-                       jsonpCallback = s.jsonpCallback =
-                               jQuery.isFunction( s.jsonpCallback ) ? s.jsonpCallback() : s.jsonpCallback,
-                       previous = window[ jsonpCallback ],
-                       url = s.url,
-                       data = s.data,
-                       replace = "$1" + jsonpCallback + "$2",
-                       cleanUp = function() {
-                               // Set callback back to previous value
-                               window[ jsonpCallback ] = previous;
-                               // Call if it was a function and we have a response
-                               if ( responseContainer && jQuery.isFunction( previous ) ) {
-                                       window[ jsonpCallback ]( responseContainer[ 0 ] );
-                               }
-                       };
-
-               if ( s.jsonp !== false ) {
-                       url = url.replace( jsre, replace );
-                       if ( s.url === url ) {
-                               if ( dataIsString ) {
-                                       data = data.replace( jsre, replace );
-                               }
-                               if ( s.data === data ) {
-                                       // Add callback manually
-                                       url += (/\?/.test( url ) ? "&" : "?") + s.jsonp + "=" + jsonpCallback;
-                               }
-                       }
-               }
-
-               s.url = url;
-               s.data = data;
-
-               // Install callback
-               window[ jsonpCallback ] = function( response ) {
-                       responseContainer = [ response ];
-               };
-
-               // Install cleanUp function
-               jqXHR.then( cleanUp, cleanUp );
-
-               // Use data converter to retrieve json after script execution
-               s.converters["script json"] = function() {
-                       if ( !responseContainer ) {
-                               jQuery.error( jsonpCallback + " was not called" );
-                       }
-                       return responseContainer[ 0 ];
-               };
-
-               // force json dataType
-               s.dataTypes[ 0 ] = "json";
-
-               // Delegate to script
-               return "script";
-       }
-} );
-
-
-
-
-// Install script dataType
-jQuery.ajaxSetup({
-       accepts: {
-               script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
-       },
-       contents: {
-               script: /javascript|ecmascript/
-       },
-       converters: {
-               "text script": function( text ) {
-                       jQuery.globalEval( text );
-                       return text;
-               }
-       }
-});
-
-// Handle cache's special case and global
-jQuery.ajaxPrefilter( "script", function( s ) {
-       if ( s.cache === undefined ) {
-               s.cache = false;
-       }
-       if ( s.crossDomain ) {
-               s.type = "GET";
-               s.global = false;
-       }
-} );
-
-// Bind script tag hack transport
-jQuery.ajaxTransport( "script", function(s) {
-
-       // This transport only deals with cross domain requests
-       if ( s.crossDomain ) {
-
-               var script,
-                       head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement;
-
-               return {
-
-                       send: function( _, callback ) {
-
-                               script = document.createElement( "script" );
-
-                               script.async = "async";
-
-                               if ( s.scriptCharset ) {
-                                       script.charset = s.scriptCharset;
-                               }
-
-                               script.src = s.url;
-
-                               // Attach handlers for all browsers
-                               script.onload = script.onreadystatechange = function( _, isAbort ) {
-
-                                       if ( !script.readyState || /loaded|complete/.test( script.readyState ) ) {
-
-                                               // Handle memory leak in IE
-                                               script.onload = script.onreadystatechange = null;
-
-                                               // Remove the script
-                                               if ( head && script.parentNode ) {
-                                                       head.removeChild( script );
-                                               }
-
-                                               // Dereference the script
-                                               script = undefined;
-
-                                               // Callback if not abort
-                                               if ( !isAbort ) {
-                                                       callback( 200, "success" );
-                                               }
-                                       }
-                               };
-                               // Use insertBefore instead of appendChild  to circumvent an IE6 bug.
-                               // This arises when a base node is used (#2709 and #4378).
-                               head.insertBefore( script, head.firstChild );
-                       },
-
-                       abort: function() {
-                               if ( script ) {
-                                       script.onload( 0, 1 );
-                               }
-                       }
-               };
-       }
-} );
-
-
-
-
-var // #5280: next active xhr id and list of active xhrs' callbacks
-       xhrId = jQuery.now(),
-       xhrCallbacks,
-
-       // XHR used to determine supports properties
-       testXHR;
-
-// #5280: Internet Explorer will keep connections alive if we don't abort on unload
-function xhrOnUnloadAbort() {
-       jQuery( window ).unload(function() {
-               // Abort all pending requests
-               for ( var key in xhrCallbacks ) {
-                       xhrCallbacks[ key ]( 0, 1 );
-               }
-       });
-}
-
-// Functions to create xhrs
-function createStandardXHR() {
-       try {
-               return new window.XMLHttpRequest();
-       } catch( e ) {}
-}
-
-function createActiveXHR() {
-       try {
-               return new window.ActiveXObject( "Microsoft.XMLHTTP" );
-       } catch( e ) {}
-}
-
-// Create the request object
-// (This is still attached to ajaxSettings for backward compatibility)
-jQuery.ajaxSettings.xhr = window.ActiveXObject ?
-       /* Microsoft failed to properly
-        * implement the XMLHttpRequest in IE7 (can't request local files),
-        * so we use the ActiveXObject when it is available
-        * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
-        * we need a fallback.
-        */
-       function() {
-               return !this.isLocal && createStandardXHR() || createActiveXHR();
-       } :
-       // For all other browsers, use the standard XMLHttpRequest object
-       createStandardXHR;
-
-// Test if we can create an xhr object
-testXHR = jQuery.ajaxSettings.xhr();
-jQuery.support.ajax = !!testXHR;
-
-// Does this browser support crossDomain XHR requests
-jQuery.support.cors = testXHR && ( "withCredentials" in testXHR );
-
-// No need for the temporary xhr anymore
-testXHR = undefined;
-
-// Create transport if the browser can provide an xhr
-if ( jQuery.support.ajax ) {
-
-       jQuery.ajaxTransport(function( s ) {
-               // Cross domain only allowed if supported through XMLHttpRequest
-               if ( !s.crossDomain || jQuery.support.cors ) {
-
-                       var callback;
-
-                       return {
-                               send: function( headers, complete ) {
-
-                                       // Get a new xhr
-                                       var xhr = s.xhr(),
-                                               handle,
-                                               i;
-
-                                       // Open the socket
-                                       // Passing null username, generates a login popup on Opera (#2865)
-                                       if ( s.username ) {
-                                               xhr.open( s.type, s.url, s.async, s.username, s.password );
-                                       } else {
-                                               xhr.open( s.type, s.url, s.async );
-                                       }
-
-                                       // Apply custom fields if provided
-                                       if ( s.xhrFields ) {
-                                               for ( i in s.xhrFields ) {
-                                                       xhr[ i ] = s.xhrFields[ i ];
-                                               }
-                                       }
-
-                                       // Override mime type if needed
-                                       if ( s.mimeType && xhr.overrideMimeType ) {
-                                               xhr.overrideMimeType( s.mimeType );
-                                       }
-
-                                       // X-Requested-With header
-                                       // For cross-domain requests, seeing as conditions for a preflight are
-                                       // akin to a jigsaw puzzle, we simply never set it to be sure.
-                                       // (it can always be set on a per-request basis or even using ajaxSetup)
-                                       // For same-domain requests, won't change header if already provided.
-                                       if ( !s.crossDomain && !headers["X-Requested-With"] ) {
-                                               headers[ "X-Requested-With" ] = "XMLHttpRequest";
-                                       }
-
-                                       // Need an extra try/catch for cross domain requests in Firefox 3
-                                       try {
-                                               for ( i in headers ) {
-                                                       xhr.setRequestHeader( i, headers[ i ] );
-                                               }
-                                       } catch( _ ) {}
-
-                                       // Do send the request
-                                       // This may raise an exception which is actually
-                                       // handled in jQuery.ajax (so no try/catch here)
-                                       xhr.send( ( s.hasContent && s.data ) || null );
-
-                                       // Listener
-                                       callback = function( _, isAbort ) {
-
-                                               var status,
-                                                       statusText,
-                                                       responseHeaders,
-                                                       responses,
-                                                       xml;
-
-                                               // Firefox throws exceptions when accessing properties
-                                               // of an xhr when a network error occured
-                                               // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
-                                               try {
-
-                                                       // Was never called and is aborted or complete
-                                                       if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
-
-                                                               // Only called once
-                                                               callback = undefined;
-
-                                                               // Do not keep as active anymore
-                                                               if ( handle ) {
-                                                                       xhr.onreadystatechange = jQuery.noop;
-                                                                       delete xhrCallbacks[ handle ];
-                                                               }
-
-                                                               // If it's an abort
-                                                               if ( isAbort ) {
-                                                                       // Abort it manually if needed
-                                                                       if ( xhr.readyState !== 4 ) {
-                                                                               xhr.abort();
-                                                                       }
-                                                               } else {
-                                                                       status = xhr.status;
-                                                                       responseHeaders = xhr.getAllResponseHeaders();
-                                                                       responses = {};
-                                                                       xml = xhr.responseXML;
-
-                                                                       // Construct response list
-                                                                       if ( xml && xml.documentElement /* #4958 */ ) {
-                                                                               responses.xml = xml;
-                                                                       }
-                                                                       responses.text = xhr.responseText;
-
-                                                                       // Firefox throws an exception when accessing
-                                                                       // statusText for faulty cross-domain requests
-                                                                       try {
-                                                                               statusText = xhr.statusText;
-                                                                       } catch( e ) {
-                                                                               // We normalize with Webkit giving an empty statusText
-                                                                               statusText = "";
-                                                                       }
-
-                                                                       // Filter status for non standard behaviors
-
-                                                                       // If the request is local and we have data: assume a success
-                                                                       // (success with no data won't get notified, that's the best we
-                                                                       // can do given current implementations)
-                                                                       if ( !status && s.isLocal && !s.crossDomain ) {
-                                                                               status = responses.text ? 200 : 404;
-                                                                       // IE - #1450: sometimes returns 1223 when it should be 204
-                                                                       } else if ( status === 1223 ) {
-                                                                               status = 204;
-                                                                       }
-                                                               }
-                                                       }
-                                               } catch( firefoxAccessException ) {
-                                                       if ( !isAbort ) {
-                                                               complete( -1, firefoxAccessException );
-                                                       }
-                                               }
-
-                                               // Call complete if needed
-                                               if ( responses ) {
-                                                       complete( status, statusText, responses, responseHeaders );
-                                               }
-                                       };
-
-                                       // if we're in sync mode or it's in cache
-                                       // and has been retrieved directly (IE6 & IE7)
-                                       // we need to manually fire the callback
-                                       if ( !s.async || xhr.readyState === 4 ) {
-                                               callback();
-                                       } else {
-                                               // Create the active xhrs callbacks list if needed
-                                               // and attach the unload handler
-                                               if ( !xhrCallbacks ) {
-                                                       xhrCallbacks = {};
-                                                       xhrOnUnloadAbort();
-                                               }
-                                               // Add to list of active xhrs callbacks
-                                               handle = xhrId++;
-                                               xhr.onreadystatechange = xhrCallbacks[ handle ] = callback;
-                                       }
-                               },
-
-                               abort: function() {
-                                       if ( callback ) {
-                                               callback(0,1);
-                                       }
-                               }
-                       };
-               }
-       });
-}
-
-
-
-
-var elemdisplay = {},
-       rfxtypes = /^(?:toggle|show|hide)$/,
-       rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,
-       timerId,
-       fxAttrs = [
-               // height animations
-               [ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
-               // width animations
-               [ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
-               // opacity animations
-               [ "opacity" ]
-       ];
-
-jQuery.fn.extend({
-       show: function( speed, easing, callback ) {
-               var elem, display;
-
-               if ( speed || speed === 0 ) {
-                       return this.animate( genFx("show", 3), speed, easing, callback);
-
-               } else {
-                       for ( var i = 0, j = this.length; i < j; i++ ) {
-                               elem = this[i];
-                               display = elem.style.display;
-
-                               // Reset the inline display of this element to learn if it is
-                               // being hidden by cascaded rules or not
-                               if ( !jQuery._data(elem, "olddisplay") && display === "none" ) {
-                                       display = elem.style.display = "";
-                               }
-
-                               // Set elements which have been overridden with display: none
-                               // in a stylesheet to whatever the default browser style is
-                               // for such an element
-                               if ( display === "" && jQuery.css( elem, "display" ) === "none" ) {
-                                       jQuery._data(elem, "olddisplay", defaultDisplay(elem.nodeName));
-                               }
-                       }
-
-                       // Set the display of most of the elements in a second loop
-                       // to avoid the constant reflow
-                       for ( i = 0; i < j; i++ ) {
-                               elem = this[i];
-                               display = elem.style.display;
-
-                               if ( display === "" || display === "none" ) {
-                                       elem.style.display = jQuery._data(elem, "olddisplay") || "";
-                               }
-                       }
-
-                       return this;
-               }
-       },
-
-       hide: function( speed, easing, callback ) {
-               if ( speed || speed === 0 ) {
-                       return this.animate( genFx("hide", 3), speed, easing, callback);
-
-               } else {
-                       for ( var i = 0, j = this.length; i < j; i++ ) {
-                               var display = jQuery.css( this[i], "display" );
-
-                               if ( display !== "none" && !jQuery._data( this[i], "olddisplay" ) ) {
-                                       jQuery._data( this[i], "olddisplay", display );
-                               }
-                       }
-
-                       // Set the display of the elements in a second loop
-                       // to avoid the constant reflow
-                       for ( i = 0; i < j; i++ ) {
-                               this[i].style.display = "none";
-                       }
-
-                       return this;
-               }
-       },
-
-       // Save the old toggle function
-       _toggle: jQuery.fn.toggle,
-
-       toggle: function( fn, fn2, callback ) {
-               var bool = typeof fn === "boolean";
-
-               if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {
-                       this._toggle.apply( this, arguments );
-
-               } else if ( fn == null || bool ) {
-                       this.each(function() {
-                               var state = bool ? fn : jQuery(this).is(":hidden");
-                               jQuery(this)[ state ? "show" : "hide" ]();
-                       });
-
-               } else {
-                       this.animate(genFx("toggle", 3), fn, fn2, callback);
-               }
-
-               return this;
-       },
-
-       fadeTo: function( speed, to, easing, callback ) {
-               return this.filter(":hidden").css("opacity", 0).show().end()
-                                       .animate({opacity: to}, speed, easing, callback);
-       },
-
-       animate: function( prop, speed, easing, callback ) {
-               var optall = jQuery.speed(speed, easing, callback);
-
-               if ( jQuery.isEmptyObject( prop ) ) {
-                       return this.each( optall.complete );
-               }
-
-               return this[ optall.queue === false ? "each" : "queue" ](function() {
-                       // XXX 'this' does not always have a nodeName when running the
-                       // test suite
-
-                       var opt = jQuery.extend({}, optall), p,
-                               isElement = this.nodeType === 1,
-                               hidden = isElement && jQuery(this).is(":hidden"),
-                               self = this;
-
-                       for ( p in prop ) {
-                               var name = jQuery.camelCase( p );
-
-                               if ( p !== name ) {
-                                       prop[ name ] = prop[ p ];
-                                       delete prop[ p ];
-                                       p = name;
-                               }
-
-                               if ( prop[p] === "hide" && hidden || prop[p] === "show" && !hidden ) {
-                                       return opt.complete.call(this);
-                               }
-
-                               if ( isElement && ( p === "height" || p === "width" ) ) {
-                                       // Make sure that nothing sneaks out
-                                       // Record all 3 overflow attributes because IE does not
-                                       // change the overflow attribute when overflowX and
-                                       // overflowY are set to the same value
-                                       opt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ];
-
-                                       // Set display property to inline-block for height/width
-                                       // animations on inline elements that are having width/height
-                                       // animated
-                                       if ( jQuery.css( this, "display" ) === "inline" &&
-                                                       jQuery.css( this, "float" ) === "none" ) {
-                                               if ( !jQuery.support.inlineBlockNeedsLayout ) {
-                                                       this.style.display = "inline-block";
-
-                                               } else {
-                                                       var display = defaultDisplay(this.nodeName);
-
-                                                       // inline-level elements accept inline-block;
-                                                       // block-level elements need to be inline with layout
-                                                       if ( display === "inline" ) {
-                                                               this.style.display = "inline-block";
-
-                                                       } else {
-                                                               this.style.display = "inline";
-                                                               this.style.zoom = 1;
-                                                       }
-                                               }
-                                       }
-                               }
-
-                               if ( jQuery.isArray( prop[p] ) ) {
-                                       // Create (if needed) and add to specialEasing
-                                       (opt.specialEasing = opt.specialEasing || {})[p] = prop[p][1];
-                                       prop[p] = prop[p][0];
-                               }
-                       }
-
-                       if ( opt.overflow != null ) {
-                               this.style.overflow = "hidden";
-                       }
-
-                       opt.curAnim = jQuery.extend({}, prop);
-
-                       jQuery.each( prop, function( name, val ) {
-                               var e = new jQuery.fx( self, opt, name );
-
-                               if ( rfxtypes.test(val) ) {
-                                       e[ val === "toggle" ? hidden ? "show" : "hide" : val ]( prop );
-
-                               } else {
-                                       var parts = rfxnum.exec(val),
-                                               start = e.cur();
-
-                                       if ( parts ) {
-                                               var end = parseFloat( parts[2] ),
-                                                       unit = parts[3] || ( jQuery.cssNumber[ name ] ? "" : "px" );
-
-                                               // We need to compute starting value
-                                               if ( unit !== "px" ) {
-                                                       jQuery.style( self, name, (end || 1) + unit);
-                                                       start = ((end || 1) / e.cur()) * start;
-                                                       jQuery.style( self, name, start + unit);
-                                               }
-
-                                               // If a +=/-= token was provided, we're doing a relative animation
-                                               if ( parts[1] ) {
-                                                       end = ((parts[1] === "-=" ? -1 : 1) * end) + start;
-                                               }
-
-                                               e.custom( start, end, unit );
-
-                                       } else {
-                                               e.custom( start, val, "" );
-                                       }
-                               }
-                       });
-
-                       // For JS strict compliance
-                       return true;
-               });
-       },
-
-       stop: function( clearQueue, gotoEnd ) {
-               var timers = jQuery.timers;
-
-               if ( clearQueue ) {
-                       this.queue([]);
-               }
-
-               this.each(function() {
-                       // go in reverse order so anything added to the queue during the loop is ignored
-                       for ( var i = timers.length - 1; i >= 0; i-- ) {
-                               if ( timers[i].elem === this ) {
-                                       if (gotoEnd) {
-                                               // force the next step to be the last
-                                               timers[i](true);
-                                       }
-
-                                       timers.splice(i, 1);
-                               }
-                       }
-               });
-
-               // start the next in the queue if the last step wasn't forced
-               if ( !gotoEnd ) {
-                       this.dequeue();
-               }
-
-               return this;
-       }
-
-});
-
-function genFx( type, num ) {
-       var obj = {};
-
-       jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function() {
-               obj[ this ] = type;
-       });
-
-       return obj;
-}
-
-// Generate shortcuts for custom animations
-jQuery.each({
-       slideDown: genFx("show", 1),
-       slideUp: genFx("hide", 1),
-       slideToggle: genFx("toggle", 1),
-       fadeIn: { opacity: "show" },
-       fadeOut: { opacity: "hide" },
-       fadeToggle: { opacity: "toggle" }
-}, function( name, props ) {
-       jQuery.fn[ name ] = function( speed, easing, callback ) {
-               return this.animate( props, speed, easing, callback );
-       };
-});
-
-jQuery.extend({
-       speed: function( speed, easing, fn ) {
-               var opt = speed && typeof speed === "object" ? jQuery.extend({}, speed) : {
-                       complete: fn || !fn && easing ||
-                               jQuery.isFunction( speed ) && speed,
-                       duration: speed,
-                       easing: fn && easing || easing && !jQuery.isFunction(easing) && easing
-               };
-
-               opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
-                       opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[opt.duration] : jQuery.fx.speeds._default;
-
-               // Queueing
-               opt.old = opt.complete;
-               opt.complete = function() {
-                       if ( opt.queue !== false ) {
-                               jQuery(this).dequeue();
-                       }
-                       if ( jQuery.isFunction( opt.old ) ) {
-                               opt.old.call( this );
-                       }
-               };
-
-               return opt;
-       },
-
-       easing: {
-               linear: function( p, n, firstNum, diff ) {
-                       return firstNum + diff * p;
-               },
-               swing: function( p, n, firstNum, diff ) {
-                       return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;
-               }
-       },
-
-       timers: [],
-
-       fx: function( elem, options, prop ) {
-               this.options = options;
-               this.elem = elem;
-               this.prop = prop;
-
-               if ( !options.orig ) {
-                       options.orig = {};
-               }
-       }
-
-});
-
-jQuery.fx.prototype = {
-       // Simple function for setting a style value
-       update: function() {
-               if ( this.options.step ) {
-                       this.options.step.call( this.elem, this.now, this );
-               }
-
-               (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );
-       },
-
-       // Get the current size
-       cur: function() {
-               if ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) ) {
-                       return this.elem[ this.prop ];
-               }
-
-               var parsed,
-                       r = jQuery.css( this.elem, this.prop );
-               // Empty strings, null, undefined and "auto" are converted to 0,
-               // complex values such as "rotate(1rad)" are returned as is,
-               // simple values such as "10px" are parsed to Float.
-               return isNaN( parsed = parseFloat( r ) ) ? !r || r === "auto" ? 0 : r : parsed;
-       },
-
-       // Start an animation from one number to another
-       custom: function( from, to, unit ) {
-               var self = this,
-                       fx = jQuery.fx;
-
-               this.startTime = jQuery.now();
-               this.start = from;
-               this.end = to;
-               this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" );
-               this.now = this.start;
-               this.pos = this.state = 0;
-
-               function t( gotoEnd ) {
-                       return self.step(gotoEnd);
-               }
-
-               t.elem = this.elem;
-
-               if ( t() && jQuery.timers.push(t) && !timerId ) {
-                       timerId = setInterval(fx.tick, fx.interval);
-               }
-       },
-
-       // Simple 'show' function
-       show: function() {
-               // Remember where we started, so that we can go back to it later
-               this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
-               this.options.show = true;
-
-               // Begin the animation
-               // Make sure that we start at a small width/height to avoid any
-               // flash of content
-               this.custom(this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur());
-
-               // Start by showing the element
-               jQuery( this.elem ).show();
-       },
-
-       // Simple 'hide' function
-       hide: function() {
-               // Remember where we started, so that we can go back to it later
-               this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
-               this.options.hide = true;
-
-               // Begin the animation
-               this.custom(this.cur(), 0);
-       },
-
-       // Each step of an animation
-       step: function( gotoEnd ) {
-               var t = jQuery.now(), done = true;
-
-               if ( gotoEnd || t >= this.options.duration + this.startTime ) {
-                       this.now = this.end;
-                       this.pos = this.state = 1;
-                       this.update();
-
-                       this.options.curAnim[ this.prop ] = true;
-
-                       for ( var i in this.options.curAnim ) {
-                               if ( this.options.curAnim[i] !== true ) {
-                                       done = false;
-                               }
-                       }
-
-                       if ( done ) {
-                               // Reset the overflow
-                               if ( this.options.overflow != null && !jQuery.support.shrinkWrapBlocks ) {
-                                       var elem = this.elem,
-                                               options = this.options;
-
-                                       jQuery.each( [ "", "X", "Y" ], function (index, value) {
-                                               elem.style[ "overflow" + value ] = options.overflow[index];
-                                       } );
-                               }
-
-                               // Hide the element if the "hide" operation was done
-                               if ( this.options.hide ) {
-                                       jQuery(this.elem).hide();
-                               }
-
-                               // Reset the properties, if the item has been hidden or shown
-                               if ( this.options.hide || this.options.show ) {
-                                       for ( var p in this.options.curAnim ) {
-                                               jQuery.style( this.elem, p, this.options.orig[p] );
-                                       }
-                               }
-
-                               // Execute the complete function
-                               this.options.complete.call( this.elem );
-                       }
-
-                       return false;
-
-               } else {
-                       var n = t - this.startTime;
-                       this.state = n / this.options.duration;
-
-                       // Perform the easing function, defaults to swing
-                       var specialEasing = this.options.specialEasing && this.options.specialEasing[this.prop];
-                       var defaultEasing = this.options.easing || (jQuery.easing.swing ? "swing" : "linear");
-                       this.pos = jQuery.easing[specialEasing || defaultEasing](this.state, n, 0, 1, this.options.duration);
-                       this.now = this.start + ((this.end - this.start) * this.pos);
-
-                       // Perform the next step of the animation
-                       this.update();
-               }
-
-               return true;
-       }
-};
-
-jQuery.extend( jQuery.fx, {
-       tick: function() {
-               var timers = jQuery.timers;
-
-               for ( var i = 0; i < timers.length; i++ ) {
-                       if ( !timers[i]() ) {
-                               timers.splice(i--, 1);
-                       }
-               }
-
-               if ( !timers.length ) {
-                       jQuery.fx.stop();
-               }
-       },
-
-       interval: 13,
-
-       stop: function() {
-               clearInterval( timerId );
-               timerId = null;
-       },
-
-       speeds: {
-               slow: 600,
-               fast: 200,
-               // Default speed
-               _default: 400
-       },
-
-       step: {
-               opacity: function( fx ) {
-                       jQuery.style( fx.elem, "opacity", fx.now );
-               },
-
-               _default: function( fx ) {
-                       if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {
-                               fx.elem.style[ fx.prop ] = (fx.prop === "width" || fx.prop === "height" ? Math.max(0, fx.now) : fx.now) + fx.unit;
-                       } else {
-                               fx.elem[ fx.prop ] = fx.now;
-                       }
-               }
-       }
-});
-
-if ( jQuery.expr && jQuery.expr.filters ) {
-       jQuery.expr.filters.animated = function( elem ) {
-               return jQuery.grep(jQuery.timers, function( fn ) {
-                       return elem === fn.elem;
-               }).length;
-       };
-}
-
-function defaultDisplay( nodeName ) {
-       if ( !elemdisplay[ nodeName ] ) {
-               var elem = jQuery("<" + nodeName + ">").appendTo("body"),
-                       display = elem.css("display");
-
-               elem.remove();
-
-               if ( display === "none" || display === "" ) {
-                       display = "block";
-               }
-
-               elemdisplay[ nodeName ] = display;
-       }
-
-       return elemdisplay[ nodeName ];
-}
-
-
-
-
-var rtable = /^t(?:able|d|h)$/i,
-       rroot = /^(?:body|html)$/i;
-
-if ( "getBoundingClientRect" in document.documentElement ) {
-       jQuery.fn.offset = function( options ) {
-               var elem = this[0], box;
-
-               if ( options ) {
-                       return this.each(function( i ) {
-                               jQuery.offset.setOffset( this, options, i );
-                       });
-               }
-
-               if ( !elem || !elem.ownerDocument ) {
-                       return null;
-               }
-
-               if ( elem === elem.ownerDocument.body ) {
-                       return jQuery.offset.bodyOffset( elem );
-               }
-
-               try {
-                       box = elem.getBoundingClientRect();
-               } catch(e) {}
-
-               var doc = elem.ownerDocument,
-                       docElem = doc.documentElement;
-
-               // Make sure we're not dealing with a disconnected DOM node
-               if ( !box || !jQuery.contains( docElem, elem ) ) {
-                       return box ? { top: box.top, left: box.left } : { top: 0, left: 0 };
-               }
-
-               var body = doc.body,
-                       win = getWindow(doc),
-                       clientTop  = docElem.clientTop  || body.clientTop  || 0,
-                       clientLeft = docElem.clientLeft || body.clientLeft || 0,
-                       scrollTop  = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop  || body.scrollTop,
-                       scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft,
-                       top  = box.top  + scrollTop  - clientTop,
-                       left = box.left + scrollLeft - clientLeft;
-
-               return { top: top, left: left };
-       };
-
-} else {
-       jQuery.fn.offset = function( options ) {
-               var elem = this[0];
-
-               if ( options ) {
-                       return this.each(function( i ) {
-                               jQuery.offset.setOffset( this, options, i );
-                       });
-               }
-
-               if ( !elem || !elem.ownerDocument ) {
-                       return null;
-               }
-
-               if ( elem === elem.ownerDocument.body ) {
-                       return jQuery.offset.bodyOffset( elem );
-               }
-
-               jQuery.offset.initialize();
-
-               var computedStyle,
-                       offsetParent = elem.offsetParent,
-                       prevOffsetParent = elem,
-                       doc = elem.ownerDocument,
-                       docElem = doc.documentElement,
-                       body = doc.body,
-                       defaultView = doc.defaultView,
-                       prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
-                       top = elem.offsetTop,
-                       left = elem.offsetLeft;
-
-               while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
-                       if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
-                               break;
-                       }
-
-                       computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;
-                       top  -= elem.scrollTop;
-                       left -= elem.scrollLeft;
-
-                       if ( elem === offsetParent ) {
-                               top  += elem.offsetTop;
-                               left += elem.offsetLeft;
-
-                               if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {
-                                       top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
-                                       left += parseFloat( computedStyle.borderLeftWidth ) || 0;
-                               }
-
-                               prevOffsetParent = offsetParent;
-                               offsetParent = elem.offsetParent;
-                       }
-
-                       if ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
-                               top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
-                               left += parseFloat( computedStyle.borderLeftWidth ) || 0;
-                       }
-
-                       prevComputedStyle = computedStyle;
-               }
-
-               if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {
-                       top  += body.offsetTop;
-                       left += body.offsetLeft;
-               }
-
-               if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
-                       top  += Math.max( docElem.scrollTop, body.scrollTop );
-                       left += Math.max( docElem.scrollLeft, body.scrollLeft );
-               }
-
-               return { top: top, left: left };
-       };
-}
-
-jQuery.offset = {
-       initialize: function() {
-               var body = document.body, container = document.createElement("div"), innerDiv, checkDiv, table, td, bodyMarginTop = parseFloat( jQuery.css(body, "marginTop") ) || 0,
-                       html = "<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
-
-               jQuery.extend( container.style, { position: "absolute", top: 0, left: 0, margin: 0, border: 0, width: "1px", height: "1px", visibility: "hidden" } );
-
-               container.innerHTML = html;
-               body.insertBefore( container, body.firstChild );
-               innerDiv = container.firstChild;
-               checkDiv = innerDiv.firstChild;
-               td = innerDiv.nextSibling.firstChild.firstChild;
-
-               this.doesNotAddBorder = (checkDiv.offsetTop !== 5);
-               this.doesAddBorderForTableAndCells = (td.offsetTop === 5);
-
-               checkDiv.style.position = "fixed";
-               checkDiv.style.top = "20px";
-
-               // safari subtracts parent border width here which is 5px
-               this.supportsFixedPosition = (checkDiv.offsetTop === 20 || checkDiv.offsetTop === 15);
-               checkDiv.style.position = checkDiv.style.top = "";
-
-               innerDiv.style.overflow = "hidden";
-               innerDiv.style.position = "relative";
-
-               this.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5);
-
-               this.doesNotIncludeMarginInBodyOffset = (body.offsetTop !== bodyMarginTop);
-
-               body.removeChild( container );
-               jQuery.offset.initialize = jQuery.noop;
-       },
-
-       bodyOffset: function( body ) {
-               var top = body.offsetTop,
-                       left = body.offsetLeft;
-
-               jQuery.offset.initialize();
-
-               if ( jQuery.offset.doesNotIncludeMarginInBodyOffset ) {
-                       top  += parseFloat( jQuery.css(body, "marginTop") ) || 0;
-                       left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
-               }
-
-               return { top: top, left: left };
-       },
-
-       setOffset: function( elem, options, i ) {
-               var position = jQuery.css( elem, "position" );
-
-               // set position first, in-case top/left are set even on static elem
-               if ( position === "static" ) {
-                       elem.style.position = "relative";
-               }
-
-               var curElem = jQuery( elem ),
-                       curOffset = curElem.offset(),
-                       curCSSTop = jQuery.css( elem, "top" ),
-                       curCSSLeft = jQuery.css( elem, "left" ),
-                       calculatePosition = (position === "absolute" || position === "fixed") && jQuery.inArray('auto', [curCSSTop, curCSSLeft]) > -1,
-                       props = {}, curPosition = {}, curTop, curLeft;
-
-               // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
-               if ( calculatePosition ) {
-                       curPosition = curElem.position();
-               }
-
-               curTop  = calculatePosition ? curPosition.top  : parseInt( curCSSTop,  10 ) || 0;
-               curLeft = calculatePosition ? curPosition.left : parseInt( curCSSLeft, 10 ) || 0;
-
-               if ( jQuery.isFunction( options ) ) {
-                       options = options.call( elem, i, curOffset );
-               }
-
-               if (options.top != null) {
-                       props.top = (options.top - curOffset.top) + curTop;
-               }
-               if (options.left != null) {
-                       props.left = (options.left - curOffset.left) + curLeft;
-               }
-
-               if ( "using" in options ) {
-                       options.using.call( elem, props );
-               } else {
-                       curElem.css( props );
-               }
-       }
-};
-
-
-jQuery.fn.extend({
-       position: function() {
-               if ( !this[0] ) {
-                       return null;
-               }
-
-               var elem = this[0],
-
-               // Get *real* offsetParent
-               offsetParent = this.offsetParent(),
-
-               // Get correct offsets
-               offset       = this.offset(),
-               parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
-
-               // Subtract element margins
-               // note: when an element has margin: auto the offsetLeft and marginLeft
-               // are the same in Safari causing offset.left to incorrectly be 0
-               offset.top  -= parseFloat( jQuery.css(elem, "marginTop") ) || 0;
-               offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0;
-
-               // Add offsetParent borders
-               parentOffset.top  += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0;
-               parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0;
-
-               // Subtract the two offsets
-               return {
-                       top:  offset.top  - parentOffset.top,
-                       left: offset.left - parentOffset.left
-               };
-       },
-
-       offsetParent: function() {
-               return this.map(function() {
-                       var offsetParent = this.offsetParent || document.body;
-                       while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
-                               offsetParent = offsetParent.offsetParent;
-                       }
-                       return offsetParent;
-               });
-       }
-});
-
-
-// Create scrollLeft and scrollTop methods
-jQuery.each( ["Left", "Top"], function( i, name ) {
-       var method = "scroll" + name;
-
-       jQuery.fn[ method ] = function(val) {
-               var elem = this[0], win;
-
-               if ( !elem ) {
-                       return null;
-               }
-
-               if ( val !== undefined ) {
-                       // Set the scroll offset
-                       return this.each(function() {
-                               win = getWindow( this );
-
-                               if ( win ) {
-                                       win.scrollTo(
-                                               !i ? val : jQuery(win).scrollLeft(),
-                                               i ? val : jQuery(win).scrollTop()
-                                       );
-
-                               } else {
-                                       this[ method ] = val;
-                               }
-                       });
-               } else {
-                       win = getWindow( elem );
-
-                       // Return the scroll offset
-                       return win ? ("pageXOffset" in win) ? win[ i ? "pageYOffset" : "pageXOffset" ] :
-                               jQuery.support.boxModel && win.document.documentElement[ method ] ||
-                                       win.document.body[ method ] :
-                               elem[ method ];
-               }
-       };
-});
-
-function getWindow( elem ) {
-       return jQuery.isWindow( elem ) ?
-               elem :
-               elem.nodeType === 9 ?
-                       elem.defaultView || elem.parentWindow :
-                       false;
-}
-
-
-
-
-// Create innerHeight, innerWidth, outerHeight and outerWidth methods
-jQuery.each([ "Height", "Width" ], function( i, name ) {
-
-       var type = name.toLowerCase();
-
-       // innerHeight and innerWidth
-       jQuery.fn["inner" + name] = function() {
-               return this[0] ?
-                       parseFloat( jQuery.css( this[0], type, "padding" ) ) :
-                       null;
-       };
-
-       // outerHeight and outerWidth
-       jQuery.fn["outer" + name] = function( margin ) {
-               return this[0] ?
-                       parseFloat( jQuery.css( this[0], type, margin ? "margin" : "border" ) ) :
-                       null;
-       };
-
-       jQuery.fn[ type ] = function( size ) {
-               // Get window width or height
-               var elem = this[0];
-               if ( !elem ) {
-                       return size == null ? null : this;
-               }
-
-               if ( jQuery.isFunction( size ) ) {
-                       return this.each(function( i ) {
-                               var self = jQuery( this );
-                               self[ type ]( size.call( this, i, self[ type ]() ) );
-                       });
-               }
-
-               if ( jQuery.isWindow( elem ) ) {
-                       // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
-                       // 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat
-                       var docElemProp = elem.document.documentElement[ "client" + name ];
-                       return elem.document.compatMode === "CSS1Compat" && docElemProp ||
-                               elem.document.body[ "client" + name ] || docElemProp;
-
-               // Get document width or height
-               } else if ( elem.nodeType === 9 ) {
-                       // Either scroll[Width/Height] or offset[Width/Height], whichever is greater
-                       return Math.max(
-                               elem.documentElement["client" + name],
-                               elem.body["scroll" + name], elem.documentElement["scroll" + name],
-                               elem.body["offset" + name], elem.documentElement["offset" + name]
-                       );
-
-               // Get or set width or height on the element
-               } else if ( size === undefined ) {
-                       var orig = jQuery.css( elem, type ),
-                               ret = parseFloat( orig );
-
-                       return jQuery.isNaN( ret ) ? orig : ret;
-
-               // Set the width or height on the element (default to pixels if value is unitless)
-               } else {
-                       return this.css( type, typeof size === "string" ? size : size + "px" );
-               }
-       };
-
-});
-
-
-window.jQuery = window.$ = jQuery;
-})(window);
\ No newline at end of file
diff --git a/addons/webinterface.default/js/jquery-1.5.2.min.js b/addons/webinterface.default/js/jquery-1.5.2.min.js
deleted file mode 100644 (file)
index d5636d7..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*!
- * jQuery JavaScript Library v1.5.2
- * http://jquery.com/
- *
- * Copyright 2011, John Resig
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * Includes Sizzle.js
- * http://sizzlejs.com/
- * Copyright 2011, The Dojo Foundation
- * Released under the MIT, BSD, and GPL Licenses.
- *
- * Date: Thu Mar 31 15:28:23 2011 -0400
- */
-(function(a,b){function ci(a){return d.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cf(a){if(!b_[a]){var b=d("<"+a+">").appendTo("body"),c=b.css("display");b.remove();if(c==="none"||c==="")c="block";b_[a]=c}return b_[a]}function ce(a,b){var c={};d.each(cd.concat.apply([],cd.slice(0,b)),function(){c[this]=a});return c}function b$(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function bZ(){try{return new a.XMLHttpRequest}catch(b){}}function bY(){d(a).unload(function(){for(var a in bW)bW[a](0,1)})}function bS(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var e=a.dataTypes,f={},g,h,i=e.length,j,k=e[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h==="string"&&(f[h.toLowerCase()]=a.converters[h]);l=k,k=e[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=f[m]||f["* "+k];if(!n){p=b;for(o in f){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=f[j[1]+" "+k];if(p){o=f[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&d.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function bR(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function bQ(a,b,c,e){if(d.isArray(b)&&b.length)d.each(b,function(b,f){c||bs.test(a)?e(a,f):bQ(a+"["+(typeof f==="object"||d.isArray(f)?b:"")+"]",f,c,e)});else if(c||b==null||typeof b!=="object")e(a,b);else if(d.isArray(b)||d.isEmptyObject(b))e(a,"");else for(var f in b)bQ(a+"["+f+"]",b[f],c,e)}function bP(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bJ,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l==="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=bP(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=bP(a,c,d,e,"*",g));return l}function bO(a){return function(b,c){typeof b!=="string"&&(c=b,b="*");if(d.isFunction(c)){var e=b.toLowerCase().split(bD),f=0,g=e.length,h,i,j;for(;f<g;f++)h=e[f],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function bq(a,b,c){var e=b==="width"?bk:bl,f=b==="width"?a.offsetWidth:a.offsetHeight;if(c==="border")return f;d.each(e,function(){c||(f-=parseFloat(d.css(a,"padding"+this))||0),c==="margin"?f+=parseFloat(d.css(a,"margin"+this))||0:f-=parseFloat(d.css(a,"border"+this+"Width"))||0});return f}function bc(a,b){b.src?d.ajax({url:b.src,async:!1,dataType:"script"}):d.globalEval(b.text||b.textContent||b.innerHTML||""),b.parentNode&&b.parentNode.removeChild(b)}function bb(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function ba(a,b){if(b.nodeType===1){var c=b.nodeName.toLowerCase();b.clearAttributes(),b.mergeAttributes(a);if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(d.expando)}}function _(a,b){if(b.nodeType===1&&d.hasData(a)){var c=d.expando,e=d.data(a),f=d.data(b,e);if(e=e[c]){var g=e.events;f=f[c]=d.extend({},e);if(g){delete f.handle,f.events={};for(var h in g)for(var i=0,j=g[h].length;i<j;i++)d.event.add(b,h+(g[h][i].namespace?".":"")+g[h][i].namespace,g[h][i],g[h][i].data)}}}}function $(a,b){return d.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function Q(a,b,c){if(d.isFunction(b))return d.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return d.grep(a,function(a,d){return a===b===c});if(typeof b==="string"){var e=d.grep(a,function(a){return a.nodeType===1});if(L.test(b))return d.filter(b,e,!c);b=d.filter(b,e)}return d.grep(a,function(a,e){return d.inArray(a,b)>=0===c})}function P(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function H(a,b){return(a&&a!=="*"?a+".":"")+b.replace(t,"`").replace(u,"&")}function G(a){var b,c,e,f,g,h,i,j,k,l,m,n,o,p=[],q=[],s=d._data(this,"events");if(a.liveFired!==this&&s&&s.live&&!a.target.disabled&&(!a.button||a.type!=="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var t=s.live.slice(0);for(i=0;i<t.length;i++)g=t[i],g.origType.replace(r,"")===a.type?q.push(g.selector):t.splice(i--,1);f=d(a.target).closest(q,a.currentTarget);for(j=0,k=f.length;j<k;j++){m=f[j];for(i=0;i<t.length;i++){g=t[i];if(m.selector===g.selector&&(!n||n.test(g.namespace))&&!m.elem.disabled){h=m.elem,e=null;if(g.preType==="mouseenter"||g.preType==="mouseleave")a.type=g.preType,e=d(a.relatedTarget).closest(g.selector)[0];(!e||e!==h)&&p.push({elem:h,handleObj:g,level:m.level})}}}for(j=0,k=p.length;j<k;j++){f=p[j];if(c&&f.level>c)break;a.currentTarget=f.elem,a.data=f.handleObj.data,a.handleObj=f.handleObj,o=f.handleObj.origHandler.apply(f.elem,arguments);if(o===!1||a.isPropagationStopped()){c=f.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function E(a,c,e){var f=d.extend({},e[0]);f.type=a,f.originalEvent={},f.liveFired=b,d.event.handle.call(c,f),f.isDefaultPrevented()&&e[0].preventDefault()}function y(){return!0}function x(){return!1}function i(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function h(a,c,e){if(e===b&&a.nodeType===1){e=a.getAttribute("data-"+c);if(typeof e==="string"){try{e=e==="true"?!0:e==="false"?!1:e==="null"?null:d.isNaN(e)?g.test(e)?d.parseJSON(e):e:parseFloat(e)}catch(f){}d.data(a,c,e)}else e=b}return e}var c=a.document,d=function(){function G(){if(!d.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(G,1);return}d.ready()}}var d=function(a,b){return new d.fn.init(a,b,g)},e=a.jQuery,f=a.$,g,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,i=/\S/,j=/^\s+/,k=/\s+$/,l=/\d/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=navigator.userAgent,w,x,y,z=Object.prototype.toString,A=Object.prototype.hasOwnProperty,B=Array.prototype.push,C=Array.prototype.slice,D=String.prototype.trim,E=Array.prototype.indexOf,F={};d.fn=d.prototype={constructor:d,init:function(a,e,f){var g,i,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!e&&c.body){this.context=c,this[0]=c.body,this.selector="body",this.length=1;return this}if(typeof a==="string"){g=h.exec(a);if(!g||!g[1]&&e)return!e||e.jquery?(e||f).find(a):this.constructor(e).find(a);if(g[1]){e=e instanceof d?e[0]:e,k=e?e.ownerDocument||e:c,j=m.exec(a),j?d.isPlainObject(e)?(a=[c.createElement(j[1])],d.fn.attr.call(a,e,!0)):a=[k.createElement(j[1])]:(j=d.buildFragment([g[1]],[k]),a=(j.cacheable?d.clone(j.fragment):j.fragment).childNodes);return d.merge(this,a)}i=c.getElementById(g[2]);if(i&&i.parentNode){if(i.id!==g[2])return f.find(a);this.length=1,this[0]=i}this.context=c,this.selector=a;return this}if(d.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return d.makeArray(a,this)},selector:"",jquery:"1.5.2",length:0,size:function(){return this.length},toArray:function(){return C.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var e=this.constructor();d.isArray(a)?B.apply(e,a):d.merge(e,a),e.prevObject=this,e.context=this.context,b==="find"?e.selector=this.selector+(this.selector?" ":"")+c:b&&(e.selector=this.selector+"."+b+"("+c+")");return e},each:function(a,b){return d.each(this,a,b)},ready:function(a){d.bindReady(),x.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(C.apply(this,arguments),"slice",C.call(arguments).join(","))},map:function(a){return this.pushStack(d.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:B,sort:[].sort,splice:[].splice},d.fn.init.prototype=d.fn,d.extend=d.fn.extend=function(){var a,c,e,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i==="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!=="object"&&!d.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){e=i[c],f=a[c];if(i===f)continue;l&&f&&(d.isPlainObject(f)||(g=d.isArray(f)))?(g?(g=!1,h=e&&d.isArray(e)?e:[]):h=e&&d.isPlainObject(e)?e:{},i[c]=d.extend(l,h,f)):f!==b&&(i[c]=f)}return i},d.extend({noConflict:function(b){a.$=f,b&&(a.jQuery=e);return d},isReady:!1,readyWait:1,ready:function(a){a===!0&&d.readyWait--;if(!d.readyWait||a!==!0&&!d.isReady){if(!c.body)return setTimeout(d.ready,1);d.isReady=!0;if(a!==!0&&--d.readyWait>0)return;x.resolveWith(c,[d]),d.fn.trigger&&d(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!x){x=d._Deferred();if(c.readyState==="complete")return setTimeout(d.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",y,!1),a.addEventListener("load",d.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",y),a.attachEvent("onload",d.ready);var b=!1;try{b=a.frameElement==null}catch(e){}c.documentElement.doScroll&&b&&G()}}},isFunction:function(a){return d.type(a)==="function"},isArray:Array.isArray||function(a){return d.type(a)==="array"},isWindow:function(a){return a&&typeof a==="object"&&"setInterval"in a},isNaN:function(a){return a==null||!l.test(a)||isNaN(a)},type:function(a){return a==null?String(a):F[z.call(a)]||"object"},isPlainObject:function(a){if(!a||d.type(a)!=="object"||a.nodeType||d.isWindow(a))return!1;if(a.constructor&&!A.call(a,"constructor")&&!A.call(a.constructor.prototype,"isPrototypeOf"))return!1;var c;for(c in a){}return c===b||A.call(a,c)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!=="string"||!b)return null;b=d.trim(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return a.JSON&&a.JSON.parse?a.JSON.parse(b):(new Function("return "+b))();d.error("Invalid JSON: "+b)},parseXML:function(b,c,e){a.DOMParser?(e=new DOMParser,c=e.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b)),e=c.documentElement,(!e||!e.nodeName||e.nodeName==="parsererror")&&d.error("Invalid XML: "+b);return c},noop:function(){},globalEval:function(a){if(a&&i.test(a)){var b=c.head||c.getElementsByTagName("head")[0]||c.documentElement,e=c.createElement("script");d.support.scriptEval()?e.appendChild(c.createTextNode(a)):e.text=a,b.insertBefore(e,b.firstChild),b.removeChild(e)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,e){var f,g=0,h=a.length,i=h===b||d.isFunction(a);if(e){if(i){for(f in a)if(c.apply(a[f],e)===!1)break}else for(;g<h;)if(c.apply(a[g++],e)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(var j=a[0];g<h&&c.call(j,g,j)!==!1;j=a[++g]){}return a},trim:D?function(a){return a==null?"":D.call(a)}:function(a){return a==null?"":(a+"").replace(j,"").replace(k,"")},makeArray:function(a,b){var c=b||[];if(a!=null){var e=d.type(a);a.length==null||e==="string"||e==="function"||e==="regexp"||d.isWindow(a)?B.call(c,a):d.merge(c,a)}return c},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var c=0,d=b.length;c<d;c++)if(b[c]===a)return c;return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length==="number")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,b,c){var d=[],e;for(var f=0,g=a.length;f<g;f++)e=b(a[f],f,c),e!=null&&(d[d.length]=e);return d.concat.apply([],d)},guid:1,proxy:function(a,c,e){arguments.length===2&&(typeof c==="string"?(e=a,a=e[c],c=b):c&&!d.isFunction(c)&&(e=c,c=b)),!c&&a&&(c=function(){return a.apply(e||this,arguments)}),a&&(c.guid=a.guid=a.guid||c.guid||d.guid++);return c},access:function(a,c,e,f,g,h){var i=a.length;if(typeof c==="object"){for(var j in c)d.access(a,j,c[j],f,g,e);return a}if(e!==b){f=!h&&f&&d.isFunction(e);for(var k=0;k<i;k++)g(a[k],c,f?e.call(a[k],k,g(a[k],c)):e,h);return a}return i?g(a[0],c):b},now:function(){return(new Date).getTime()},uaMatch:function(a){a=a.toLowerCase();var b=r.exec(a)||s.exec(a)||t.exec(a)||a.indexOf("compatible")<0&&u.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}d.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.subclass=this.subclass,a.fn.init=function b(b,c){c&&c instanceof d&&!(c instanceof a)&&(c=a(c));return d.fn.init.call(this,b,c,e)},a.fn.init.prototype=a.fn;var e=a(c);return a},browser:{}}),d.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){F["[object "+b+"]"]=b.toLowerCase()}),w=d.uaMatch(v),w.browser&&(d.browser[w.browser]=!0,d.browser.version=w.version),d.browser.webkit&&(d.browser.safari=!0),E&&(d.inArray=function(a,b){return E.call(b,a)}),i.test(" ")&&(j=/^[\s\xA0]+/,k=/[\s\xA0]+$/),g=d(c),c.addEventListener?y=function(){c.removeEventListener("DOMContentLoaded",y,!1),d.ready()}:c.attachEvent&&(y=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",y),d.ready())});return d}(),e="then done fail isResolved isRejected promise".split(" "),f=[].slice;d.extend({_Deferred:function(){var a=[],b,c,e,f={done:function(){if(!e){var c=arguments,g,h,i,j,k;b&&(k=b,b=0);for(g=0,h=c.length;g<h;g++)i=c[g],j=d.type(i),j==="array"?f.done.apply(f,i):j==="function"&&a.push(i);k&&f.resolveWith(k[0],k[1])}return this},resolveWith:function(d,f){if(!e&&!b&&!c){f=f||[],c=1;try{while(a[0])a.shift().apply(d,f)}finally{b=[d,f],c=0}}return this},resolve:function(){f.resolveWith(this,arguments);return this},isResolved:function(){return c||b},cancel:function(){e=1,a=[];return this}};return f},Deferred:function(a){var b=d._Deferred(),c=d._Deferred(),f;d.extend(b,{then:function(a,c){b.done(a).fail(c);return this},fail:c.done,rejectWith:c.resolveWith,reject:c.resolve,isRejected:c.isResolved,promise:function(a){if(a==null){if(f)return f;f=a={}}var c=e.length;while(c--)a[e[c]]=b[e[c]];return a}}),b.done(c.cancel).fail(b.cancel),delete b.cancel,a&&a.call(b,b);return b},when:function(a){function i(a){return function(c){b[a]=arguments.length>1?f.call(arguments,0):c,--g||h.resolveWith(h,f.call(b,0))}}var b=arguments,c=0,e=b.length,g=e,h=e<=1&&a&&d.isFunction(a.promise)?a:d.Deferred();if(e>1){for(;c<e;c++)b[c]&&d.isFunction(b[c].promise)?b[c].promise().then(i(c),h.reject):--g;g||h.resolveWith(h,b)}else h!==a&&h.resolveWith(h,e?[a]:[]);return h.promise()}}),function(){d.support={};var b=c.createElement("div");b.style.display="none",b.innerHTML="   <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";var e=b.getElementsByTagName("*"),f=b.getElementsByTagName("a")[0],g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=b.getElementsByTagName("input")[0];if(e&&e.length&&f){d.support={leadingWhitespace:b.firstChild.nodeType===3,tbody:!b.getElementsByTagName("tbody").length,htmlSerialize:!!b.getElementsByTagName("link").length,style:/red/.test(f.getAttribute("style")),hrefNormalized:f.getAttribute("href")==="/a",opacity:/^0.55$/.test(f.style.opacity),cssFloat:!!f.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,deleteExpando:!0,optDisabled:!1,checkClone:!1,noCloneEvent:!0,noCloneChecked:!0,boxModel:null,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableHiddenOffsets:!0,reliableMarginRight:!0},i.checked=!0,d.support.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,d.support.optDisabled=!h.disabled;var j=null;d.support.scriptEval=function(){if(j===null){var b=c.documentElement,e=c.createElement("script"),f="script"+d.now();try{e.appendChild(c.createTextNode("window."+f+"=1;"))}catch(g){}b.insertBefore(e,b.firstChild),a[f]?(j=!0,delete a[f]):j=!1,b.removeChild(e)}return j};try{delete b.test}catch(k){d.support.deleteExpando=!1}!b.addEventListener&&b.attachEvent&&b.fireEvent&&(b.attachEvent("onclick",function l(){d.support.noCloneEvent=!1,b.detachEvent("onclick",l)}),b.cloneNode(!0).fireEvent("onclick")),b=c.createElement("div"),b.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";var m=c.createDocumentFragment();m.appendChild(b.firstChild),d.support.checkClone=m.cloneNode(!0).cloneNode(!0).lastChild.checked,d(function(){var a=c.createElement("div"),b=c.getElementsByTagName("body")[0];if(b){a.style.width=a.style.paddingLeft="1px",b.appendChild(a),d.boxModel=d.support.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,d.support.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="<div style='width:4px;'></div>",d.support.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>";var e=a.getElementsByTagName("td");d.support.reliableHiddenOffsets=e[0].offsetHeight===0,e[0].style.display="",e[1].style.display="none",d.support.reliableHiddenOffsets=d.support.reliableHiddenOffsets&&e[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(a.style.width="1px",a.style.marginRight="0",d.support.reliableMarginRight=(parseInt(c.defaultView.getComputedStyle(a,null).marginRight,10)||0)===0),b.removeChild(a).style.display="none",a=e=null}});var n=function(a){var b=c.createElement("div");a="on"+a;if(!b.attachEvent)return!0;var d=a in b;d||(b.setAttribute(a,"return;"),d=typeof b[a]==="function");return d};d.support.submitBubbles=n("submit"),d.support.changeBubbles=n("change"),b=e=f=null}}();var g=/^(?:\{.*\}|\[.*\])$/;d.extend({cache:{},uuid:0,expando:"jQuery"+(d.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?d.cache[a[d.expando]]:a[d.expando];return!!a&&!i(a)},data:function(a,c,e,f){if(d.acceptData(a)){var g=d.expando,h=typeof c==="string",i,j=a.nodeType,k=j?d.cache:a,l=j?a[d.expando]:a[d.expando]&&d.expando;if((!l||f&&l&&!k[l][g])&&h&&e===b)return;l||(j?a[d.expando]=l=++d.uuid:l=d.expando),k[l]||(k[l]={},j||(k[l].toJSON=d.noop));if(typeof c==="object"||typeof c==="function")f?k[l][g]=d.extend(k[l][g],c):k[l]=d.extend(k[l],c);i=k[l],f&&(i[g]||(i[g]={}),i=i[g]),e!==b&&(i[c]=e);if(c==="events"&&!i[c])return i[g]&&i[g].events;return h?i[c]:i}},removeData:function(b,c,e){if(d.acceptData(b)){var f=d.expando,g=b.nodeType,h=g?d.cache:b,j=g?b[d.expando]:d.expando;if(!h[j])return;if(c){var k=e?h[j][f]:h[j];if(k){delete k[c];if(!i(k))return}}if(e){delete h[j][f];if(!i(h[j]))return}var l=h[j][f];d.support.deleteExpando||h!=a?delete h[j]:h[j]=null,l?(h[j]={},g||(h[j].toJSON=d.noop),h[j][f]=l):g&&(d.support.deleteExpando?delete b[d.expando]:b.removeAttribute?b.removeAttribute(d.expando):b[d.expando]=null)}},_data:function(a,b,c){return d.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=d.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),d.fn.extend({data:function(a,c){var e=null;if(typeof a==="undefined"){if(this.length){e=d.data(this[0]);if(this[0].nodeType===1){var f=this[0].attributes,g;for(var i=0,j=f.length;i<j;i++)g=f[i].name,g.indexOf("data-")===0&&(g=g.substr(5),h(this[0],g,e[g]))}}return e}if(typeof a==="object")return this.each(function(){d.data(this,a)});var k=a.split(".");k[1]=k[1]?"."+k[1]:"";if(c===b){e=this.triggerHandler("getData"+k[1]+"!",[k[0]]),e===b&&this.length&&(e=d.data(this[0],a),e=h(this[0],a,e));return e===b&&k[1]?this.data(k[0]):e}return this.each(function(){var b=d(this),e=[k[0],c];b.triggerHandler("setData"+k[1]+"!",e),d.data(this,a,c),b.triggerHandler("changeData"+k[1]+"!",e)})},removeData:function(a){return this.each(function(){d.removeData(this,a)})}}),d.extend({queue:function(a,b,c){if(a){b=(b||"fx")+"queue";var e=d._data(a,b);if(!c)return e||[];!e||d.isArray(c)?e=d._data(a,b,d.makeArray(c)):e.push(c);return e}},dequeue:function(a,b){b=b||"fx";var c=d.queue(a,b),e=c.shift();e==="inprogress"&&(e=c.shift()),e&&(b==="fx"&&c.unshift("inprogress"),e.call(a,function(){d.dequeue(a,b)})),c.length||d.removeData(a,b+"queue",!0)}}),d.fn.extend({queue:function(a,c){typeof a!=="string"&&(c=a,a="fx");if(c===b)return d.queue(this[0],a);return this.each(function(b){var e=d.queue(this,a,c);a==="fx"&&e[0]!=="inprogress"&&d.dequeue(this,a)})},dequeue:function(a){return this.each(function(){d.dequeue(this,a)})},delay:function(a,b){a=d.fx?d.fx.speeds[a]||a:a,b=b||"fx";return this.queue(b,function(){var c=this;setTimeout(function(){d.dequeue(c,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var j=/[\n\t\r]/g,k=/\s+/,l=/\r/g,m=/^(?:href|src|style)$/,n=/^(?:button|input)$/i,o=/^(?:button|input|object|select|textarea)$/i,p=/^a(?:rea)?$/i,q=/^(?:radio|checkbox)$/i;d.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"},d.fn.extend({attr:function(a,b){return d.access(this,a,b,!0,d.attr)},removeAttr:function(a,b){return this.each(function(){d.attr(this,a,""),this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(d.isFunction(a))return this.each(function(b){var c=d(this);c.addClass(a.call(this,b,c.attr("class")))});if(a&&typeof a==="string"){var b=(a||"").split(k);for(var c=0,e=this.length;c<e;c++){var f=this[c];if(f.nodeType===1)if(f.className){var g=" "+f.className+" ",h=f.className;for(var i=0,j=b.length;i<j;i++)g.indexOf(" "+b[i]+" ")<0&&(h+=" "+b[i]);f.className=d.trim(h)}else f.className=a}}return this},removeClass:function(a){if(d.isFunction(a))return this.each(function(b){var c=d(this);c.removeClass(a.call(this,b,c.attr("class")))});if(a&&typeof a==="string"||a===b){var c=(a||"").split(k);for(var e=0,f=this.length;e<f;e++){var g=this[e];if(g.nodeType===1&&g.className)if(a){var h=(" "+g.className+" ").replace(j," ");for(var i=0,l=c.length;i<l;i++)h=h.replace(" "+c[i]+" "," ");g.className=d.trim(h)}else g.className=""}}return this},toggleClass:function(a,b){var c=typeof a,e=typeof b==="boolean";if(d.isFunction(a))return this.each(function(c){var e=d(this);e.toggleClass(a.call(this,c,e.attr("class"),b),b)});return this.each(function(){if(c==="string"){var f,g=0,h=d(this),i=b,j=a.split(k);while(f=j[g++])i=e?i:!h.hasClass(f),h[i?"addClass":"removeClass"](f)}else if(c==="undefined"||c==="boolean")this.className&&d._data(this,"__className__",this.className),this.className=this.className||a===!1?"":d._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ";for(var c=0,d=this.length;c<d;c++)if((" "+this[c].className+" ").replace(j," ").indexOf(b)>-1)return!0;return!1},val:function(a){if(!arguments.length){var c=this[0];if(c){if(d.nodeName(c,"option")){var e=c.attributes.value;return!e||e.specified?c.value:c.text}if(d.nodeName(c,"select")){var f=c.selectedIndex,g=[],h=c.options,i=c.type==="select-one";if(f<0)return null;for(var j=i?f:0,k=i?f+1:h.length;j<k;j++){var m=h[j];if(m.selected&&(d.support.optDisabled?!m.disabled:m.getAttribute("disabled")===null)&&(!m.parentNode.disabled||!d.nodeName(m.parentNode,"optgroup"))){a=d(m).val();if(i)return a;g.push(a)}}if(i&&!g.length&&h.length)return d(h[f]).val();return g}if(q.test(c.type)&&!d.support.checkOn)return c.getAttribute("value")===null?"on":c.value;return(c.value||"").replace(l,"")}return b}var n=d.isFunction(a);return this.each(function(b){var c=d(this),e=a;if(this.nodeType===1){n&&(e=a.call(this,b,c.val())),e==null?e="":typeof e==="number"?e+="":d.isArray(e)&&(e=d.map(e,function(a){return a==null?"":a+""}));if(d.isArray(e)&&q.test(this.type))this.checked=d.inArray(c.val(),e)>=0;else if(d.nodeName(this,"select")){var f=d.makeArray(e);d("option",this).each(function(){this.selected=d.inArray(d(this).val(),f)>=0}),f.length||(this.selectedIndex=-1)}else this.value=e}})}}),d.extend({attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,e,f){if(!a||a.nodeType===3||a.nodeType===8||a.nodeType===2)return b;if(f&&c in d.attrFn)return d(a)[c](e);var g=a.nodeType!==1||!d.isXMLDoc(a),h=e!==b;c=g&&d.props[c]||c;if(a.nodeType===1){var i=m.test(c);if(c==="selected"&&!d.support.optSelected){var j=a.parentNode;j&&(j.selectedIndex,j.parentNode&&j.parentNode.selectedIndex)}if((c in a||a[c]!==b)&&g&&!i){h&&(c==="type"&&n.test(a.nodeName)&&a.parentNode&&d.error("type property can't be changed"),e===null?a.nodeType===1&&a.removeAttribute(c):a[c]=e);if(d.nodeName(a,"form")&&a.getAttributeNode(c))return a.getAttributeNode(c).nodeValue;if(c==="tabIndex"){var k=a.getAttributeNode("tabIndex");return k&&k.specified?k.value:o.test(a.nodeName)||p.test(a.nodeName)&&a.href?0:b}return a[c]}if(!d.support.style&&g&&c==="style"){h&&(a.style.cssText=""+e);return a.style.cssText}h&&a.setAttribute(c,""+e);if(!a.attributes[c]&&(a.hasAttribute&&!a.hasAttribute(c)))return b;var l=!d.support.hrefNormalized&&g&&i?a.getAttribute(c,2):a.getAttribute(c);return l===null?b:l}h&&(a[c]=e);return a[c]}});var r=/\.(.*)$/,s=/^(?:textarea|input|select)$/i,t=/\./g,u=/ /g,v=/[^\w\s.|`]/g,w=function(a){return a.replace(v,"\\$&")};d.event={add:function(c,e,f,g){if(c.nodeType!==3&&c.nodeType!==8){try{d.isWindow(c)&&(c!==a&&!c.frameElement)&&(c=a)}catch(h){}if(f===!1)f=x;else if(!f)return;var i,j;f.handler&&(i=f,f=i.handler),f.guid||(f.guid=d.guid++);var k=d._data(c);if(!k)return;var l=k.events,m=k.handle;l||(k.events=l={}),m||(k.handle=m=function(a){return typeof d!=="undefined"&&d.event.triggered!==a.type?d.event.handle.apply(m.elem,arguments):b}),m.elem=c,e=e.split(" ");var n,o=0,p;while(n=e[o++]){j=i?d.extend({},i):{handler:f,data:g},n.indexOf(".")>-1?(p=n.split("."),n=p.shift(),j.namespace=p.slice(0).sort().join(".")):(p=[],j.namespace=""),j.type=n,j.guid||(j.guid=f.guid);var q=l[n],r=d.event.special[n]||{};if(!q){q=l[n]=[];if(!r.setup||r.setup.call(c,g,p,m)===!1)c.addEventListener?c.addEventListener(n,m,!1):c.attachEvent&&c.attachEvent("on"+n,m)}r.add&&(r.add.call(c,j),j.handler.guid||(j.handler.guid=f.guid)),q.push(j),d.event.global[n]=!0}c=null}},global:{},remove:function(a,c,e,f){if(a.nodeType!==3&&a.nodeType!==8){e===!1&&(e=x);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=d.hasData(a)&&d._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(e=c.handler,c=c.type);if(!c||typeof c==="string"&&c.charAt(0)==="."){c=c||"";for(h in t)d.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+d.map(m.slice(0).sort(),w).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!e){for(j=0;j<p.length;j++){q=p[j];if(l||n.test(q.namespace))d.event.remove(a,r,q.handler,j),p.splice(j--,1)}continue}o=d.event.special[h]||{};for(j=f||0;j<p.length;j++){q=p[j];if(e.guid===q.guid){if(l||n.test(q.namespace))f==null&&p.splice(j--,1),o.remove&&o.remove.call(a,q);if(f!=null)break}}if(p.length===0||f!=null&&p.length===1)(!o.teardown||o.teardown.call(a,m)===!1)&&d.removeEvent(a,h,s.handle),g=null,delete t[h]}if(d.isEmptyObject(t)){var u=s.handle;u&&(u.elem=null),delete s.events,delete s.handle,d.isEmptyObject(s)&&d.removeData(a,b,!0)}}},trigger:function(a,c,e){var f=a.type||a,g=arguments[3];if(!g){a=typeof a==="object"?a[d.expando]?a:d.extend(d.Event(f),a):d.Event(f),f.indexOf("!")>=0&&(a.type=f=f.slice(0,-1),a.exclusive=!0),e||(a.stopPropagation(),d.event.global[f]&&d.each(d.cache,function(){var b=d.expando,e=this[b];e&&e.events&&e.events[f]&&d.event.trigger(a,c,e.handle.elem)}));if(!e||e.nodeType===3||e.nodeType===8)return b;a.result=b,a.target=e,c=d.makeArray(c),c.unshift(a)}a.currentTarget=e;var h=d._data(e,"handle");h&&h.apply(e,c);var i=e.parentNode||e.ownerDocument;try{e&&e.nodeName&&d.noData[e.nodeName.toLowerCase()]||e["on"+f]&&e["on"+f].apply(e,c)===!1&&(a.result=!1,a.preventDefault())}catch(j){}if(!a.isPropagationStopped()&&i)d.event.trigger(a,c,i,!0);else if(!a.isDefaultPrevented()){var k,l=a.target,m=f.replace(r,""),n=d.nodeName(l,"a")&&m==="click",o=d.event.special[m]||{};if((!o._default||o._default.call(e,a)===!1)&&!n&&!(l&&l.nodeName&&d.noData[l.nodeName.toLowerCase()])){try{l[m]&&(k=l["on"+m],k&&(l["on"+m]=null),d.event.triggered=a.type,l[m]())}catch(p){}k&&(l["on"+m]=k),d.event.triggered=b}}},handle:function(c){var e,f,g,h,i,j=[],k=d.makeArray(arguments);c=k[0]=d.event.fix(c||a.event),c.currentTarget=this,e=c.type.indexOf(".")<0&&!c.exclusive,e||(g=c.type.split("."),c.type=g.shift(),j=g.slice(0).sort(),h=new RegExp("(^|\\.)"+j.join("\\.(?:.*\\.)?")+"(\\.|$)")),c.namespace=c.namespace||j.join("."),i=d._data(this,"events"),f=(i||{})[c.type];if(i&&f){f=f.slice(0);for(var l=0,m=f.length;l<m;l++){var n=f[l];if(e||h.test(n.namespace)){c.handler=n.handler,c.data=n.data,c.handleObj=n;var o=n.handler.apply(this,k);o!==b&&(c.result=o,o===!1&&(c.preventDefault(),c.stopPropagation()));if(c.isImmediatePropagationStopped())break}}}return c.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(a){if(a[d.expando])return a;var e=a;a=d.Event(e);for(var f=this.props.length,g;f;)g=this.props[--f],a[g]=e[g];a.target||(a.target=a.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),!a.relatedTarget&&a.fromElement&&(a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement);if(a.pageX==null&&a.clientX!=null){var h=c.documentElement,i=c.body;a.pageX=a.clientX+(h&&h.scrollLeft||i&&i.scrollLeft||0)-(h&&h.clientLeft||i&&i.clientLeft||0),a.pageY=a.clientY+(h&&h.scrollTop||i&&i.scrollTop||0)-(h&&h.clientTop||i&&i.clientTop||0)}a.which==null&&(a.charCode!=null||a.keyCode!=null)&&(a.which=a.charCode!=null?a.charCode:a.keyCode),!a.metaKey&&a.ctrlKey&&(a.metaKey=a.ctrlKey),!a.which&&a.button!==b&&(a.which=a.button&1?1:a.button&2?3:a.button&4?2:0);return a},guid:1e8,proxy:d.proxy,special:{ready:{setup:d.bindReady,teardown:d.noop},live:{add:function(a){d.event.add(this,H(a.origType,a.selector),d.extend({},a,{handler:G,guid:a.handler.guid}))},remove:function(a){d.event.remove(this,H(a.origType,a.selector),a)}},beforeunload:{setup:function(a,b,c){d.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}}},d.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent("on"+b,c)},d.Event=function(a){if(!this.preventDefault)return new d.Event(a);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?y:x):this.type=a,this.timeStamp=d.now(),this[d.expando]=!0},d.Event.prototype={preventDefault:function(){this.isDefaultPrevented=y;var a=this.originalEvent;a&&(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=y;var a=this.originalEvent;a&&(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=y,this.stopPropagation()},isDefaultPrevented:x,isPropagationStopped:x,isImmediatePropagationStopped:x};var z=function(a){var b=a.relatedTarget;try{if(b&&b!==c&&!b.parentNode)return;while(b&&b!==this)b=b.parentNode;b!==this&&(a.type=a.data,d.event.handle.apply(this,arguments))}catch(e){}},A=function(a){a.type=a.data,d.event.handle.apply(this,arguments)};d.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){d.event.special[a]={setup:function(c){d.event.add(this,b,c&&c.selector?A:z,a)},teardown:function(a){d.event.remove(this,b,a&&a.selector?A:z)}}}),d.support.submitBubbles||(d.event.special.submit={setup:function(a,b){if(this.nodeName&&this.nodeName.toLowerCase()!=="form")d.event.add(this,"click.specialSubmit",function(a){var b=a.target,c=b.type;(c==="submit"||c==="image")&&d(b).closest("form").length&&E("submit",this,arguments)}),d.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,c=b.type;(c==="text"||c==="password")&&d(b).closest("form").length&&a.keyCode===13&&E("submit",this,arguments)});else return!1},teardown:function(a){d.event.remove(this,".specialSubmit")}});if(!d.support.changeBubbles){var B,C=function(a){var b=a.type,c=a.value;b==="radio"||b==="checkbox"?c=a.checked:b==="select-multiple"?c=a.selectedIndex>-1?d.map(a.options,function(a){return a.selected}).join("-"):"":a.nodeName.toLowerCase()==="select"&&(c=a.selectedIndex);return c},D=function D(a){var c=a.target,e,f;if(s.test(c.nodeName)&&!c.readOnly){e=d._data(c,"_change_data"),f=C(c),(a.type!=="focusout"||c.type!=="radio")&&d._data(c,"_change_data",f);if(e===b||f===e)return;if(e!=null||f)a.type="change",a.liveFired=b,d.event.trigger(a,arguments[1],c)}};d.event.special.change={filters:{focusout:D,beforedeactivate:D,click:function(a){var b=a.target,c=b.type;(c==="radio"||c==="checkbox"||b.nodeName.toLowerCase()==="select")&&D.call(this,a)},keydown:function(a){var b=a.target,c=b.type;(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&D.call(this,a)},beforeactivate:function(a){var b=a.target;d._data(b,"_change_data",C(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in B)d.event.add(this,c+".specialChange",B[c]);return s.test(this.nodeName)},teardown:function(a){d.event.remove(this,".specialChange");return s.test(this.nodeName)}},B=d.event.special.change.filters,B.focus=B.beforeactivate}c.addEventListener&&d.each({focus:"focusin",blur:"focusout"},function(a,b){function f(a){var c=d.event.fix(a);c.type=b,c.originalEvent={},d.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var e=0;d.event.special[b]={setup:function(){e++===0&&c.addEventListener(a,f,!0)},teardown:function(){--e===0&&c.removeEventListener(a,f,!0)}}}),d.each(["bind","one"],function(a,c){d.fn[c]=function(a,e,f){if(typeof a==="object"){for(var g in a)this[c](g,e,a[g],f);return this}if(d.isFunction(e)||e===!1)f=e,e=b;var h=c==="one"?d.proxy(f,function(a){d(this).unbind(a,h);return f.apply(this,arguments)}):f;if(a==="unload"&&c!=="one")this.one(a,e,f);else for(var i=0,j=this.length;i<j;i++)d.event.add(this[i],a,h,e);return this}}),d.fn.extend({unbind:function(a,b){if(typeof a!=="object"||a.preventDefault)for(var e=0,f=this.length;e<f;e++)d.event.remove(this[e],a,b);else for(var c in a)this.unbind(c,a[c]);return this},delegate:function(a,b,c,d){return this.live(b,c,d,a)},undelegate:function(a,b,c){return arguments.length===0?this.unbind("live"):this.die(b,null,c,a)},trigger:function(a,b){return this.each(function(){d.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){var c=d.Event(a);c.preventDefault(),c.stopPropagation(),d.event.trigger(c,b,this[0]);return c.result}},toggle:function(a){var b=arguments,c=1;while(c<b.length)d.proxy(a,b[c++]);return this.click(d.proxy(a,function(e){var f=(d._data(this,"lastToggle"+a.guid)||0)%c;d._data(this,"lastToggle"+a.guid,f+1),e.preventDefault();return b[f].apply(this,arguments)||!1}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var F={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};d.each(["live","die"],function(a,c){d.fn[c]=function(a,e,f,g){var h,i=0,j,k,l,m=g||this.selector,n=g?this:d(this.context);if(typeof a==="object"&&!a.preventDefault){for(var o in a)n[c](o,e,a[o],m);return this}d.isFunction(e)&&(f=e,e=b),a=(a||"").split(" ");while((h=a[i++])!=null){j=r.exec(h),k="",j&&(k=j[0],h=h.replace(r,""));if(h==="hover"){a.push("mouseenter"+k,"mouseleave"+k);continue}l=h,h==="focus"||h==="blur"?(a.push(F[h]+k),h=h+k):h=(F[h]||h)+k;if(c==="live")for(var p=0,q=n.length;p<q;p++)d.event.add(n[p],"live."+H(h,m),{data:e,selector:m,handler:f,origType:h,origHandler:f,preType:l});else n.unbind("live."+H(h,m),f)}return this}}),d.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),function(a,b){d.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.bind(b,a,c):this.trigger(b)},d.attrFn&&(d.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g<h;g++){var i=d[g];if(i){var j=!1;i=i[a];while(i){if(i.sizcache===c){j=d[i.sizset];break}if(i.nodeType===1){f||(i.sizcache=c,i.sizset=g);if(typeof b!=="string"){if(i===b){j=!0;break}}else if(k.filter(b,[i]).length>0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g<h;g++){var i=d[g];if(i){var j=!1;i=i[a];while(i){if(i.sizcache===c){j=d[i.sizset];break}i.nodeType===1&&!f&&(i.sizcache=c,i.sizset=g);if(i.nodeName.toLowerCase()===b){j=i;break}i=i[a]}d[g]=j}}}var a=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,f=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,e,g){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!=="string")return e;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(f.call(n)==="[object Array]")if(u)if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&e.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&e.push(j[t]);else e.push.apply(e,n);else p(n,e);o&&(k(o,h,e,g),k.uniqueSort(e));return e};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},k.matches=function(a,b){return k(a,null,null,b)},k.matchesSelector=function(a,b){return k(b,null,null,[a]).length>0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e<f;e++){var g,h=l.order[e];if(g=l.leftMatch[h].exec(a)){var j=g[1];g.splice(1,1);if(j.substr(j.length-1)!=="\\"){g[1]=(g[1]||"").replace(i,""),d=l.find[h](g,b,c);if(d!=null){a=a.replace(l.match[h],"");break}}}}d||(d=typeof b.getElementsByTagName!=="undefined"?b.getElementsByTagName("*"):[]);return{set:d,expr:a}},k.filter=function(a,c,d,e){var f,g,h=a,i=[],j=c,m=c&&c[0]&&k.isXML(c[0]);while(a&&c.length){for(var n in l.filter)if((f=l.leftMatch[n].exec(a))!=null&&f[2]){var o,p,q=l.filter[n],r=f[1];g=!1,f.splice(1,1);if(r.substr(r.length-1)==="\\")continue;j===i&&(i=[]);if(l.preFilter[n]){f=l.preFilter[n](f,j,d,i,e,m);if(f){if(f===!0)continue}else g=o=!0}if(f)for(var s=0;(p=j[s])!=null;s++)if(p){o=q(p,f,s,j);var t=e^!!o;d&&o!=null?t?g=!0:j[s]=!1:t&&(i.push(p),g=!0)}if(o!==b){d||(j=i),a=a.replace(l.match[n],"");if(!g)return[];break}}if(a===h)if(g==null)k.error(a);else break;h=a}return j},k.error=function(a){throw"Syntax error, unrecognized expression: "+a};var l=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(a){return a.getAttribute("href")},type:function(a){return a.getAttribute("type")}},relative:{"+":function(a,b){var c=typeof b==="string",d=c&&!j.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1){}a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&k.filter(b,a,!0)},">":function(a,b){var c,d=typeof b==="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&k.filter(b,a,!0)}},"":function(a,b,c){var d,f=e++,g=u;typeof b==="string"&&!j.test(b)&&(b=b.toLowerCase(),d=b,g=t),g("parentNode",b,f,a,d,c)},"~":function(a,b,c){var d,f=e++,g=u;typeof b==="string"&&!j.test(b)&&(b=b.toLowerCase(),d=b,g=t),g("previousSibling",b,f,a,d,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!=="undefined"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!=="undefined"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute("name")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!=="undefined")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=" "+a[1].replace(i,"")+" ";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(" "+h.className+" ").replace(/[\t\n\r]/g," ").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return"text"===c&&(b===c||b===null)},radio:function(a){return"radio"===a.type},checkbox:function(a){return"checkbox"===a.type},file:function(a){return"file"===a.type},password:function(a){return"password"===a.type},submit:function(a){return"submit"===a.type},image:function(a){return"image"===a.type},reset:function(a){return"reset"===a.type},button:function(a){return"button"===a.type||a.nodeName.toLowerCase()==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}k.error(e)},CHILD:function(a,b){var c=b[1],d=a;switch(c){case"only":case"first":while(d=d.previousSibling)if(d.nodeType===1)return!1;if(c==="first")return!0;d=a;case"last":while(d=d.nextSibling)if(d.nodeType===1)return!1;return!0;case"nth":var e=b[2],f=b[3];if(e===1&&f===0)return!0;var g=b[0],h=a.parentNode;if(h&&(h.sizcache!==g||!a.nodeIndex)){var i=0;for(d=h.firstChild;d;d=d.nextSibling)d.nodeType===1&&(d.nodeIndex=++i);h.sizcache=g}var j=a.nodeIndex-f;return e===0?j===0:j%e===0&&j/e>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(f.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length==="number")for(var e=a.length;c<e;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var r,s;c.documentElement.compareDocumentPosition?r=function(a,b){if(a===b){g=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(r=function(a,b){var c,d,e=[],f=[],h=a.parentNode,i=b.parentNode,j=h;if(a===b){g=!0;return 0}if(h===i)return s(a,b);if(!h)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return s(e[k],f[k]);return k===c?s(a,f[k],-1):s(e[k],b,1)},s=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),k.getText=function(a){var b="",c;for(var d=0;a[d];d++)c=a[d],c.nodeType===3||c.nodeType===4?b+=c.nodeValue:c.nodeType!==8&&(b+=k.getText(c.childNodes));return b},function(){var a=c.createElement("div"),d="script"+(new Date).getTime(),e=c.documentElement;a.innerHTML="<a name='"+d+"'/>",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!=="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!=="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!=="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!=="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="<p class='TEST'></p>";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="<div class='test e'></div><div class='test'></div>";if(a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!=="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g<h;g++)k(a,f[g],d);return k.filter(e,d)};d.find=k,d.expr=k.selectors,d.expr[":"]=d.expr.filters,d.unique=k.uniqueSort,d.text=k.getText,d.isXMLDoc=k.isXML,d.contains=k.contains}();var I=/Until$/,J=/^(?:parents|prevUntil|prevAll)/,K=/,/,L=/^.[^:#\[\.,]*$/,M=Array.prototype.slice,N=d.expr.match.POS,O={children:!0,contents:!0,next:!0,prev:!0};d.fn.extend({find:function(a){var b=this.pushStack("","find",a),c=0;for(var e=0,f=this.length;e<f;e++){c=b.length,d.find(a,this[e],b);if(e>0)for(var g=c;g<b.length;g++)for(var h=0;h<c;h++)if(b[h]===b[g]){b.splice(g--,1);break}}return b},has:function(a){var b=d(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(d.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(Q(this,a,!1),"not",a)},filter:function(a){return this.pushStack(Q(this,a,!0),"filter",a)},is:function(a){return!!a&&d.filter(a,this).length>0},closest:function(a,b){var c=[],e,f,g=this[0];if(d.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(e=0,f=a.length;e<f;e++)i=a[e],j[i]||(j[i]=d.expr.match.POS.test(i)?d(i,b||this.context):i);while(g&&g.ownerDocument&&g!==b){for(i in j)h=j[i],(h.jquery?h.index(g)>-1:d(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=N.test(a)?d(a,b||this.context):null;for(e=0,f=this.length;e<f;e++){g=this[e];while(g){if(l?l.index(g)>-1:d.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b)break}}c=c.length>1?d.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a||typeof a==="string")return d.inArray(this[0],a?d(a):this.parent().children());return d.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a==="string"?d(a,b):d.makeArray(a),e=d.merge(this.get(),c);return this.pushStack(P(c[0])||P(e[0])?e:d.unique(e))},andSelf:function(){return this.add(this.prevObject)}}),d.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return d.dir(a,"parentNode")},parentsUntil:function(a,b,c){return d.dir(a,"parentNode",c)},next:function(a){return d.nth(a,2,"nextSibling")},prev:function(a){return d.nth(a,2,"previousSibling")},nextAll:function(a){return d.dir(a,"nextSibling")},prevAll:function(a){return d.dir(a,"previousSibling")},nextUntil:function(a,b,c){return d.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return d.dir(a,"previousSibling",c)},siblings:function(a){return d.sibling(a.parentNode.firstChild,a)},children:function(a){return d.sibling(a.firstChild)},contents:function(a){return d.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:d.makeArray(a.childNodes)}},function(a,b){d.fn[a]=function(c,e){var f=d.map(this,b,c),g=M.call(arguments);I.test(a)||(e=c),e&&typeof e==="string"&&(f=d.filter(e,f)),f=this.length>1&&!O[a]?d.unique(f):f,(this.length>1||K.test(e))&&J.test(a)&&(f=f.reverse());return this.pushStack(f,a,g.join(","))}}),d.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?d.find.matchesSelector(b[0],a)?[b[0]]:[]:d.find.matches(a,b)},dir:function(a,c,e){var f=[],g=a[c];while(g&&g.nodeType!==9&&(e===b||g.nodeType!==1||!d(g).is(e)))g.nodeType===1&&f.push(g),g=g[c];return f},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var R=/ jQuery\d+="(?:\d+|null)"/g,S=/^\s+/,T=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,U=/<([\w:]+)/,V=/<tbody/i,W=/<|&#?\w+;/,X=/<(?:script|object|embed|option|style)/i,Y=/checked\s*(?:[^=]|=\s*.checked.)/i,Z={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};Z.optgroup=Z.option,Z.tbody=Z.tfoot=Z.colgroup=Z.caption=Z.thead,Z.th=Z.td,d.support.htmlSerialize||(Z._default=[1,"div<div>","</div>"]),d.fn.extend({text:function(a){if(d.isFunction(a))return this.each(function(b){var c=d(this);c.text(a.call(this,b,c.text()))});if(typeof a!=="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return d.text(this)},wrapAll:function(a){if(d.isFunction(a))return this.each(function(b){d(this).wrapAll(a.call(this,b))});if(this[0]){var b=d(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(d.isFunction(a))return this.each(function(b){d(this).wrapInner(a.call(this,b))});return this.each(function(){var b=d(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){d(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){d.nodeName(this,"body")||d(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=d(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,d(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,e;(e=this[c])!=null;c++)if(!a||d.filter(a,[e]).length)!b&&e.nodeType===1&&(d.cleanData(e.getElementsByTagName("*")),d.cleanData([e])),e.parentNode&&e.parentNode.removeChild(e);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&d.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return d.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(R,""):null;if(typeof a!=="string"||X.test(a)||!d.support.leadingWhitespace&&S.test(a)||Z[(U.exec(a)||["",""])[1].toLowerCase()])d.isFunction(a)?this.each(function(b){var c=d(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);else{a=a.replace(T,"<$1></$2>");try{for(var c=0,e=this.length;c<e;c++)this[c].nodeType===1&&(d.cleanData(this[c].getElementsByTagName("*")),this[c].innerHTML=a)}catch(f){this.empty().append(a)}}return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(d.isFunction(a))return this.each(function(b){var c=d(this),e=c.html();c.replaceWith(a.call(this,b,e))});typeof a!=="string"&&(a=d(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;d(this).remove(),b?d(b).before(a):d(c).append(a)})}return this.length?this.pushStack(d(d.isFunction(a)?a():a),"replaceWith",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,e){var f,g,h,i,j=a[0],k=[];if(!d.support.checkClone&&arguments.length===3&&typeof j==="string"&&Y.test(j))return this.each(function(){d(this).domManip(a,c,e,!0)});if(d.isFunction(j))return this.each(function(f){var g=d(this);a[0]=j.call(this,f,c?g.html():b),g.domManip(a,c,e)});if(this[0]){i=j&&j.parentNode,d.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?f={fragment:i}:f=d.buildFragment(a,this,k),h=f.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&d.nodeName(g,"tr");for(var l=0,m=this.length,n=m-1;l<m;l++)e.call(c?$(this[l],g):this[l],f.cacheable||m>1&&l<n?d.clone(h,!0,!0):h)}k.length&&d.each(k,bc)}return this}}),d.buildFragment=function(a,b,e){var f,g,h,i=b&&b[0]?b[0].ownerDocument||b[0]:c;a.length===1&&typeof a[0]==="string"&&a[0].length<512&&i===c&&a[0].charAt(0)==="<"&&!X.test(a[0])&&(d.support.checkClone||!Y.test(a[0]))&&(g=!0,h=d.fragments[a[0]],h&&(h!==1&&(f=h))),f||(f=i.createDocumentFragment(),d.clean(a,i,f,e)),g&&(d.fragments[a[0]]=h?f:1);return{fragment:f,cacheable:g}},d.fragments={},d.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){d.fn[a]=function(c){var e=[],f=d(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&f.length===1){f[b](this[0]);return this}for(var h=0,i=f.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();d(f[h])[b](j),e=e.concat(j)}return this.pushStack(e,a,f.selector)}}),d.extend({clone:function(a,b,c){var e=a.cloneNode(!0),f,g,h;if((!d.support.noCloneEvent||!d.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!d.isXMLDoc(a)){ba(a,e),f=bb(a),g=bb(e);for(h=0;f[h];++h)ba(f[h],g[h])}if(b){_(a,e);if(c){f=bb(a),g=bb(e);for(h=0;f[h];++h)_(f[h],g[h])}}return e},clean:function(a,b,e,f){b=b||c,typeof b.createElement==="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var g=[];for(var h=0,i;(i=a[h])!=null;h++){typeof i==="number"&&(i+="");if(!i)continue;if(typeof i!=="string"||W.test(i)){if(typeof i==="string"){i=i.replace(T,"<$1></$2>");var j=(U.exec(i)||["",""])[1].toLowerCase(),k=Z[j]||Z._default,l=k[0],m=b.createElement("div");m.innerHTML=k[1]+i+k[2];while(l--)m=m.lastChild;if(!d.support.tbody){var n=V.test(i),o=j==="table"&&!n?m.firstChild&&m.firstChild.childNodes:k[1]==="<table>"&&!n?m.childNodes:[];for(var p=o.length-1;p>=0;--p)d.nodeName(o[p],"tbody")&&!o[p].childNodes.length&&o[p].parentNode.removeChild(o[p])}!d.support.leadingWhitespace&&S.test(i)&&m.insertBefore(b.createTextNode(S.exec(i)[0]),m.firstChild),i=m.childNodes}}else i=b.createTextNode(i);i.nodeType?g.push(i):g=d.merge(g,i)}if(e)for(h=0;g[h];h++)!f||!d.nodeName(g[h],"script")||g[h].type&&g[h].type.toLowerCase()!=="text/javascript"?(g[h].nodeType===1&&g.splice.apply(g,[h+1,0].concat(d.makeArray(g[h].getElementsByTagName("script")))),e.appendChild(g[h])):f.push(g[h].parentNode?g[h].parentNode.removeChild(g[h]):g[h]);return g},cleanData:function(a){var b,c,e=d.cache,f=d.expando,g=d.event.special,h=d.support.deleteExpando;for(var i=0,j;(j=a[i])!=null;i++){if(j.nodeName&&d.noData[j.nodeName.toLowerCase()])continue;c=j[d.expando];if(c){b=e[c]&&e[c][f];if(b&&b.events){for(var k in b.events)g[k]?d.event.remove(j,k):d.removeEvent(j,k,b.handle);b.handle&&(b.handle.elem=null)}h?delete j[d.expando]:j.removeAttribute&&j.removeAttribute(d.expando),delete e[c]}}}});var bd=/alpha\([^)]*\)/i,be=/opacity=([^)]*)/,bf=/-([a-z])/ig,bg=/([A-Z]|^ms)/g,bh=/^-?\d+(?:px)?$/i,bi=/^-?\d/,bj={position:"absolute",visibility:"hidden",display:"block"},bk=["Left","Right"],bl=["Top","Bottom"],bm,bn,bo,bp=function(a,b){return b.toUpperCase()};d.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return d.access(this,a,c,!0,function(a,c,e){return e!==b?d.style(a,c,e):d.css(a,c)})},d.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bm(a,"opacity","opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{zIndex:!0,fontWeight:!0,opacity:!0,zoom:!0,lineHeight:!0},cssProps:{"float":d.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,e,f){if(a&&a.nodeType!==3&&a.nodeType!==8&&a.style){var g,h=d.camelCase(c),i=a.style,j=d.cssHooks[h];c=d.cssProps[h]||h;if(e===b){if(j&&"get"in j&&(g=j.get(a,!1,f))!==b)return g;return i[c]}if(typeof e==="number"&&isNaN(e)||e==null)return;typeof e==="number"&&!d.cssNumber[h]&&(e+="px");if(!j||!("set"in j)||(e=j.set(a,e))!==b)try{i[c]=e}catch(k){}}},css:function(a,c,e){var f,g=d.camelCase(c),h=d.cssHooks[g];c=d.cssProps[g]||g;if(h&&"get"in h&&(f=h.get(a,!0,e))!==b)return f;if(bm)return bm(a,c,g)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]},camelCase:function(a){return a.replace(bf,bp)}}),d.curCSS=d.css,d.each(["height","width"],function(a,b){d.cssHooks[b]={get:function(a,c,e){var f;if(c){a.offsetWidth!==0?f=bq(a,b,e):d.swap(a,bj,function(){f=bq(a,b,e)});if(f<=0){f=bm(a,b,b),f==="0px"&&bo&&(f=bo(a,b,b));if(f!=null)return f===""||f==="auto"?"0px":f}if(f<0||f==null){f=a.style[b];return f===""||f==="auto"?"0px":f}return typeof f==="string"?f:f+"px"}},set:function(a,b){if(!bh.test(b))return b;b=parseFloat(b);if(b>=0)return b+"px"}}}),d.support.opacity||(d.cssHooks.opacity={get:function(a,b){return be.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style;c.zoom=1;var e=d.isNaN(b)?"":"alpha(opacity="+b*100+")",f=c.filter||"";c.filter=bd.test(f)?f.replace(bd,e):c.filter+" "+e}}),d(function(){d.support.reliableMarginRight||(d.cssHooks.marginRight={get:function(a,b){var c;d.swap(a,{display:"inline-block"},function(){b?c=bm(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bn=function(a,c,e){var f,g,h;e=e.replace(bg,"-$1").toLowerCase();if(!(g=a.ownerDocument.defaultView))return b;if(h=g.getComputedStyle(a,null))f=h.getPropertyValue(e),f===""&&!d.contains(a.ownerDocument.documentElement,a)&&(f=d.style(a,e));return f}),c.documentElement.currentStyle&&(bo=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bh.test(d)&&bi.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bm=bn||bo,d.expr&&d.expr.filters&&(d.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!d.support.reliableHiddenOffsets&&(a.style.display||d.css(a,"display"))==="none"},d.expr.filters.visible=function(a){return!d.expr.filters.hidden(a)});var br=/%20/g,bs=/\[\]$/,bt=/\r?\n/g,bu=/#.*$/,bv=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bw=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bx=/^(?:about|app|app\-storage|.+\-extension|file|widget):$/,by=/^(?:GET|HEAD)$/,bz=/^\/\//,bA=/\?/,bB=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bC=/^(?:select|textarea)/i,bD=/\s+/,bE=/([?&])_=[^&]*/,bF=/(^|\-)([a-z])/g,bG=function(a,b,c){return b+c.toUpperCase()},bH=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bI=d.fn.load,bJ={},bK={},bL,bM;try{bL=c.location.href}catch(bN){bL=c.createElement("a"),bL.href="",bL=bL.href}bM=bH.exec(bL.toLowerCase())||[],d.fn.extend({load:function(a,c,e){if(typeof a!=="string"&&bI)return bI.apply(this,arguments);if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var g=a.slice(f,a.length);a=a.slice(0,f)}var h="GET";c&&(d.isFunction(c)?(e=c,c=b):typeof c==="object"&&(c=d.param(c,d.ajaxSettings.traditional),h="POST"));var i=this;d.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?d("<div>").append(c.replace(bB,"")).find(g):c)),e&&i.each(e,[c,b,a])}});return this},serialize:function(){return d.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?d.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bC.test(this.nodeName)||bw.test(this.type))}).map(function(a,b){var c=d(this).val();return c==null?null:d.isArray(c)?d.map(c,function(a,c){return{name:b.name,value:a.replace(bt,"\r\n")}}):{name:b.name,value:c.replace(bt,"\r\n")}}).get()}}),d.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){d.fn[b]=function(a){return this.bind(b,a)}}),d.each(["get","post"],function(a,c){d[c]=function(a,e,f,g){d.isFunction(e)&&(g=g||f,f=e,e=b);return d.ajax({type:c,url:a,data:e,success:f,dataType:g})}}),d.extend({getScript:function(a,c){return d.get(a,b,c,"script")},getJSON:function(a,b,c){return d.get(a,b,c,"json")},ajaxSetup:function(a,b){b?d.extend(!0,a,d.ajaxSettings,b):(b=a,a=d.extend(!0,d.ajaxSettings,b));for(var c in {context:1,url:1})c in b?a[c]=b[c]:c in d.ajaxSettings&&(a[c]=d.ajaxSettings[c]);return a},ajaxSettings:{url:bL,isLocal:bx.test(bM[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":"*/*"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":d.parseJSON,"text xml":d.parseXML}},ajaxPrefilter:bO(bJ),ajaxTransport:bO(bK),ajax:function(a,c){function v(a,c,l,n){if(r!==2){r=2,p&&clearTimeout(p),o=b,m=n||"",u.readyState=a?4:0;var q,t,v,w=l?bR(e,u,l):b,x,y;if(a>=200&&a<300||a===304){if(e.ifModified){if(x=u.getResponseHeader("Last-Modified"))d.lastModified[k]=x;if(y=u.getResponseHeader("Etag"))d.etag[k]=y}if(a===304)c="notmodified",q=!0;else try{t=bS(e,w),c="success",q=!0}catch(z){c="parsererror",v=z}}else{v=c;if(!c||a)c="error",a<0&&(a=0)}u.status=a,u.statusText=c,q?h.resolveWith(f,[t,c,u]):h.rejectWith(f,[u,c,v]),u.statusCode(j),j=b,s&&g.trigger("ajax"+(q?"Success":"Error"),[u,e,q?t:v]),i.resolveWith(f,[u,c]),s&&(g.trigger("ajaxComplete",[u,e]),--d.active||d.event.trigger("ajaxStop"))}}typeof a==="object"&&(c=a,a=b),c=c||{};var e=d.ajaxSetup({},c),f=e.context||e,g=f!==e&&(f.nodeType||f instanceof d)?d(f):d.event,h=d.Deferred(),i=d._Deferred(),j=e.statusCode||{},k,l={},m,n,o,p,q,r=0,s,t,u={readyState:0,setRequestHeader:function(a,b){r||(l[a.toLowerCase().replace(bF,bG)]=b);return this},getAllResponseHeaders:function(){return r===2?m:null},getResponseHeader:function(a){var c;if(r===2){if(!n){n={};while(c=bv.exec(m))n[c[1].toLowerCase()]=c[2]}c=n[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){r||(e.mimeType=a);return this},abort:function(a){a=a||"abort",o&&o.abort(a),v(0,a);return this}};h.promise(u),u.success=u.done,u.error=u.fail,u.complete=i.done,u.statusCode=function(a){if(a){var b;if(r<2)for(b in a)j[b]=[j[b],a[b]];else b=a[u.status],u.then(b,b)}return this},e.url=((a||e.url)+"").replace(bu,"").replace(bz,bM[1]+"//"),e.dataTypes=d.trim(e.dataType||"*").toLowerCase().split(bD),e.crossDomain==null&&(q=bH.exec(e.url.toLowerCase()),e.crossDomain=q&&(q[1]!=bM[1]||q[2]!=bM[2]||(q[3]||(q[1]==="http:"?80:443))!=(bM[3]||(bM[1]==="http:"?80:443)))),e.data&&e.processData&&typeof e.data!=="string"&&(e.data=d.param(e.data,e.traditional)),bP(bJ,e,c,u);if(r===2)return!1;s=e.global,e.type=e.type.toUpperCase(),e.hasContent=!by.test(e.type),s&&d.active++===0&&d.event.trigger("ajaxStart");if(!e.hasContent){e.data&&(e.url+=(bA.test(e.url)?"&":"?")+e.data),k=e.url;if(e.cache===!1){var w=d.now(),x=e.url.replace(bE,"$1_="+w);e.url=x+(x===e.url?(bA.test(e.url)?"&":"?")+"_="+w:"")}}if(e.data&&e.hasContent&&e.contentType!==!1||c.contentType)l["Content-Type"]=e.contentType;e.ifModified&&(k=k||e.url,d.lastModified[k]&&(l["If-Modified-Since"]=d.lastModified[k]),d.etag[k]&&(l["If-None-Match"]=d.etag[k])),l.Accept=e.dataTypes[0]&&e.accepts[e.dataTypes[0]]?e.accepts[e.dataTypes[0]]+(e.dataTypes[0]!=="*"?", */*; q=0.01":""):e.accepts["*"];for(t in e.headers)u.setRequestHeader(t,e.headers[t]);if(e.beforeSend&&(e.beforeSend.call(f,u,e)===!1||r===2)){u.abort();return!1}for(t in {success:1,error:1,complete:1})u[t](e[t]);o=bP(bK,e,c,u);if(o){u.readyState=1,s&&g.trigger("ajaxSend",[u,e]),e.async&&e.timeout>0&&(p=setTimeout(function(){u.abort("timeout")},e.timeout));try{r=1,o.send(l,v)}catch(y){status<2?v(-1,y):d.error(y)}}else v(-1,"No Transport");return u},param:function(a,c){var e=[],f=function(a,b){b=d.isFunction(b)?b():b,e[e.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=d.ajaxSettings.traditional);if(d.isArray(a)||a.jquery&&!d.isPlainObject(a))d.each(a,function(){f(this.name,this.value)});else for(var g in a)bQ(g,a[g],c,f);return e.join("&").replace(br,"+")}}),d.extend({active:0,lastModified:{},etag:{}});var bT=d.now(),bU=/(\=)\?(&|$)|\?\?/i;d.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return d.expando+"_"+bT++}}),d.ajaxPrefilter("json jsonp",function(b,c,e){var f=typeof b.data==="string";if(b.dataTypes[0]==="jsonp"||c.jsonpCallback||c.jsonp!=null||b.jsonp!==!1&&(bU.test(b.url)||f&&bU.test(b.data))){var g,h=b.jsonpCallback=d.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2",m=function(){a[h]=i,g&&d.isFunction(i)&&a[h](g[0])};b.jsonp!==!1&&(j=j.replace(bU,l),b.url===j&&(f&&(k=k.replace(bU,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},e.then(m,m),b.converters["script json"]=function(){g||d.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),d.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){d.globalEval(a);return a}}}),d.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),d.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var bV=d.now(),bW,bX;d.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&bZ()||b$()}:bZ,bX=d.ajaxSettings.xhr(),d.support.ajax=!!bX,d.support.cors=bX&&"withCredentials"in bX,bX=b,d.support.ajax&&d.ajaxTransport(function(a){if(!a.crossDomain||d.support.cors){var c;return{send:function(e,f){var g=a.xhr(),h,i;a.username?g.open(a.type,a.url,a.async,a.username,a.password):g.open(a.type,a.url,a.async);if(a.xhrFields)for(i in a.xhrFields)g[i]=a.xhrFields[i];a.mimeType&&g.overrideMimeType&&g.overrideMimeType(a.mimeType),!a.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(i in e)g.setRequestHeader(i,e[i])}catch(j){}g.send(a.hasContent&&a.data||null),c=function(e,i){var j,k,l,m,n;try{if(c&&(i||g.readyState===4)){c=b,h&&(g.onreadystatechange=d.noop,delete bW[h]);if(i)g.readyState!==4&&g.abort();else{j=g.status,l=g.getAllResponseHeaders(),m={},n=g.responseXML,n&&n.documentElement&&(m.xml=n),m.text=g.responseText;try{k=g.statusText}catch(o){k=""}j||!a.isLocal||a.crossDomain?j===1223&&(j=204):j=m.text?200:404}}}catch(p){i||f(-1,p)}m&&f(j,k,m,l)},a.async&&g.readyState!==4?(bW||(bW={},bY()),h=bV++,g.onreadystatechange=bW[h]=c):c()},abort:function(){c&&c(0,1)}}}});var b_={},ca=/^(?:toggle|show|hide)$/,cb=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cc,cd=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];d.fn.extend({show:function(a,b,c){var e,f;if(a||a===0)return this.animate(ce("show",3),a,b,c);for(var g=0,h=this.length;g<h;g++)e=this[g],f=e.style.display,!d._data(e,"olddisplay")&&f==="none"&&(f=e.style.display=""),f===""&&d.css(e,"display")==="none"&&d._data(e,"olddisplay",cf(e.nodeName));for(g=0;g<h;g++){e=this[g],f=e.style.display;if(f===""||f==="none")e.style.display=d._data(e,"olddisplay")||""}return this},hide:function(a,b,c){if(a||a===0)return this.animate(ce("hide",3),a,b,c);for(var e=0,f=this.length;e<f;e++){var g=d.css(this[e],"display");g!=="none"&&!d._data(this[e],"olddisplay")&&d._data(this[e],"olddisplay",g)}for(e=0;e<f;e++)this[e].style.display="none";return this},_toggle:d.fn.toggle,toggle:function(a,b,c){var e=typeof a==="boolean";d.isFunction(a)&&d.isFunction(b)?this._toggle.apply(this,arguments):a==null||e?this.each(function(){var b=e?a:d(this).is(":hidden");d(this)[b?"show":"hide"]()}):this.animate(ce("toggle",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,e){var f=d.speed(b,c,e);if(d.isEmptyObject(a))return this.each(f.complete);return this[f.queue===!1?"each":"queue"](function(){var b=d.extend({},f),c,e=this.nodeType===1,g=e&&d(this).is(":hidden"),h=this;for(c in a){var i=d.camelCase(c);c!==i&&(a[i]=a[c],delete a[c],c=i);if(a[c]==="hide"&&g||a[c]==="show"&&!g)return b.complete.call(this);if(e&&(c==="height"||c==="width")){b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY];if(d.css(this,"display")==="inline"&&d.css(this,"float")==="none")if(d.support.inlineBlockNeedsLayout){var j=cf(this.nodeName);j==="inline"?this.style.display="inline-block":(this.style.display="inline",this.style.zoom=1)}else this.style.display="inline-block"}d.isArray(a[c])&&((b.specialEasing=b.specialEasing||{})[c]=a[c][1],a[c]=a[c][0])}b.overflow!=null&&(this.style.overflow="hidden"),b.curAnim=d.extend({},a),d.each(a,function(c,e){var f=new d.fx(h,b,c);if(ca.test(e))f[e==="toggle"?g?"show":"hide":e](a);else{var i=cb.exec(e),j=f.cur();if(i){var k=parseFloat(i[2]),l=i[3]||(d.cssNumber[c]?"":"px");l!=="px"&&(d.style(h,c,(k||1)+l),j=(k||1)/f.cur()*j,d.style(h,c,j+l)),i[1]&&(k=(i[1]==="-="?-1:1)*k+j),f.custom(j,k,l)}else f.custom(j,e,"")}});return!0})},stop:function(a,b){var c=d.timers;a&&this.queue([]),this.each(function(){for(var a=c.length-1;a>=0;a--)c[a].elem===this&&(b&&c[a](!0),c.splice(a,1))}),b||this.dequeue();return this}}),d.each({slideDown:ce("show",1),slideUp:ce("hide",1),slideToggle:ce("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){d.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),d.extend({speed:function(a,b,c){var e=a&&typeof a==="object"?d.extend({},a):{complete:c||!c&&b||d.isFunction(a)&&a,duration:a,easing:c&&b||b&&!d.isFunction(b)&&b};e.duration=d.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in d.fx.speeds?d.fx.speeds[e.duration]:d.fx.speeds._default,e.old=e.complete,e.complete=function(){e.queue!==!1&&d(this).dequeue(),d.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig||(b.orig={})}}),d.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(d.fx.step[this.prop]||d.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=d.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,b,c){function g(a){return e.step(a)}var e=this,f=d.fx;this.startTime=d.now(),this.start=a,this.end=b,this.unit=c||this.unit||(d.cssNumber[this.prop]?"":"px"),this.now=this.start,this.pos=this.state=0,g.elem=this.elem,g()&&d.timers.push(g)&&!cc&&(cc=setInterval(f.tick,f.interval))},show:function(){this.options.orig[this.prop]=d.style(this.elem,this.prop),this.options.show=!0,this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),d(this.elem).show()},hide:function(){this.options.orig[this.prop]=d.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b=d.now(),c=!0;if(a||b>=this.options.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),this.options.curAnim[this.prop]=!0;for(var e in this.options.curAnim)this.options.curAnim[e]!==!0&&(c=!1);if(c){if(this.options.overflow!=null&&!d.support.shrinkWrapBlocks){var f=this.elem,g=this.options;d.each(["","X","Y"],function(a,b){f.style["overflow"+b]=g.overflow[a]})}this.options.hide&&d(this.elem).hide();if(this.options.hide||this.options.show)for(var h in this.options.curAnim)d.style(this.elem,h,this.options.orig[h]);this.options.complete.call(this.elem)}return!1}var i=b-this.startTime;this.state=i/this.options.duration;var j=this.options.specialEasing&&this.options.specialEasing[this.prop],k=this.options.easing||(d.easing.swing?"swing":"linear");this.pos=d.easing[j||k](this.state,i,0,1,this.options.duration),this.now=this.start+(this.end-this.start)*this.pos,this.update();return!0}},d.extend(d.fx,{tick:function(){var a=d.timers;for(var b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||d.fx.stop()},interval:13,stop:function(){clearInterval(cc),cc=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){d.style(a.elem,"opacity",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit:a.elem[a.prop]=a.now}}}),d.expr&&d.expr.filters&&(d.expr.filters.animated=function(a){return d.grep(d.timers,function(b){return a===b.elem}).length});var cg=/^t(?:able|d|h)$/i,ch=/^(?:body|html)$/i;"getBoundingClientRect"in c.documentElement?d.fn.offset=function(a){var b=this[0],c;if(a)return this.each(function(b){d.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return d.offset.bodyOffset(b);try{c=b.getBoundingClientRect()}catch(e){}var f=b.ownerDocument,g=f.documentElement;if(!c||!d.contains(g,b))return c?{top:c.top,left:c.left}:{top:0,left:0};var h=f.body,i=ci(f),j=g.clientTop||h.clientTop||0,k=g.clientLeft||h.clientLeft||0,l=i.pageYOffset||d.support.boxModel&&g.scrollTop||h.scrollTop,m=i.pageXOffset||d.support.boxModel&&g.scrollLeft||h.scrollLeft,n=c.top+l-j,o=c.left+m-k;return{top:n,left:o}}:d.fn.offset=function(a){var b=this[0];if(a)return this.each(function(b){d.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return d.offset.bodyOffset(b);d.offset.initialize();var c,e=b.offsetParent,f=b,g=b.ownerDocument,h=g.documentElement,i=g.body,j=g.defaultView,k=j?j.getComputedStyle(b,null):b.currentStyle,l=b.offsetTop,m=b.offsetLeft;while((b=b.parentNode)&&b!==i&&b!==h){if(d.offset.supportsFixedPosition&&k.position==="fixed")break;c=j?j.getComputedStyle(b,null):b.currentStyle,l-=b.scrollTop,m-=b.scrollLeft,b===e&&(l+=b.offsetTop,m+=b.offsetLeft,d.offset.doesNotAddBorder&&(!d.offset.doesAddBorderForTableAndCells||!cg.test(b.nodeName))&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),f=e,e=b.offsetParent),d.offset.subtractsBorderForOverflowNotVisible&&c.overflow!=="visible"&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),k=c}if(k.position==="relative"||k.position==="static")l+=i.offsetTop,m+=i.offsetLeft;d.offset.supportsFixedPosition&&k.position==="fixed"&&(l+=Math.max(h.scrollTop,i.scrollTop),m+=Math.max(h.scrollLeft,i.scrollLeft));return{top:l,left:m}},d.offset={initialize:function(){var a=c.body,b=c.createElement("div"),e,f,g,h,i=parseFloat(d.css(a,"marginTop"))||0,j="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";d.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),e=b.firstChild,f=e.firstChild,h=e.nextSibling.firstChild.firstChild,this.doesNotAddBorder=f.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,f.style.position="fixed",f.style.top="20px",this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15,f.style.position=f.style.top="",e.style.overflow="hidden",e.style.position="relative",this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),d.offset.initialize=d.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;d.offset.initialize(),d.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(d.css(a,"marginTop"))||0,c+=parseFloat(d.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var e=d.css(a,"position");e==="static"&&(a.style.position="relative");var f=d(a),g=f.offset(),h=d.css(a,"top"),i=d.css(a,"left"),j=(e==="absolute"||e==="fixed")&&d.inArray("auto",[h,i])>-1,k={},l={},m,n;j&&(l=f.position()),m=j?l.top:parseInt(h,10)||0,n=j?l.left:parseInt(i,10)||0,d.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):f.css(k)}},d.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),e=ch.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(d.css(a,"marginTop"))||0,c.left-=parseFloat(d.css(a,"marginLeft"))||0,e.top+=parseFloat(d.css(b[0],"borderTopWidth"))||0,e.left+=parseFloat(d.css(b[0],"borderLeftWidth"))||0;return{top:c.top-e.top,left:c.left-e.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&(!ch.test(a.nodeName)&&d.css(a,"position")==="static"))a=a.offsetParent;return a})}}),d.each(["Left","Top"],function(a,c){var e="scroll"+c;d.fn[e]=function(c){var f=this[0],g;if(!f)return null;if(c!==b)return this.each(function(){g=ci(this),g?g.scrollTo(a?d(g).scrollLeft():c,a?c:d(g).scrollTop()):this[e]=c});g=ci(f);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:d.support.boxModel&&g.document.documentElement[e]||g.document.body[e]:f[e]}}),d.each(["Height","Width"],function(a,c){var e=c.toLowerCase();d.fn["inner"+c]=function(){return this[0]?parseFloat(d.css(this[0],e,"padding")):null},d.fn["outer"+c]=function(a){return this[0]?parseFloat(d.css(this[0],e,a?"margin":"border")):null},d.fn[e]=function(a){var f=this[0];if(!f)return a==null?null:this;if(d.isFunction(a))return this.each(function(b){var c=d(this);c[e](a.call(this,b,c[e]()))});if(d.isWindow(f)){var g=f.document.documentElement["client"+c];return f.document.compatMode==="CSS1Compat"&&g||f.document.body["client"+c]||g}if(f.nodeType===9)return Math.max(f.documentElement["client"+c],f.body["scroll"+c],f.documentElement["scroll"+c],f.body["offset"+c],f.documentElement["offset"+c]);if(a===b){var h=d.css(f,e),i=parseFloat(h);return d.isNaN(i)?h:i}return this.css(e,typeof a==="string"?a:a+"px")}}),a.jQuery=a.$=d})(window);
\ No newline at end of file
diff --git a/addons/webinterface.default/js/jquery-1.8.2.min.js b/addons/webinterface.default/js/jquery-1.8.2.min.js
new file mode 100644 (file)
index 0000000..c943d65
--- /dev/null
@@ -0,0 +1,2 @@
+/*! jQuery v1.8.2 jquery.com | jquery.org/license */
+(function(a,b){function G(a){var b=F[a]={};return p.each(a.split(s),function(a,c){b[c]=!0}),b}function J(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(I,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:+d+""===d?+d:H.test(d)?p.parseJSON(d):d}catch(f){}p.data(a,c,d)}else d=b}return d}function K(a){var b;for(b in a){if(b==="data"&&p.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function ba(){return!1}function bb(){return!0}function bh(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function bi(a,b){do a=a[b];while(a&&a.nodeType!==1);return a}function bj(a,b,c){b=b||0;if(p.isFunction(b))return p.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return p.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=p.grep(a,function(a){return a.nodeType===1});if(be.test(b))return p.filter(b,d,!c);b=p.filter(b,d)}return p.grep(a,function(a,d){return p.inArray(a,b)>=0===c})}function bk(a){var b=bl.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function bC(a,b){return a.getElementsByTagName(b)[0]||a.appendChild(a.ownerDocument.createElement(b))}function bD(a,b){if(b.nodeType!==1||!p.hasData(a))return;var c,d,e,f=p._data(a),g=p._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;d<e;d++)p.event.add(b,c,h[c][d])}g.data&&(g.data=p.extend({},g.data))}function bE(a,b){var c;if(b.nodeType!==1)return;b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase(),c==="object"?(b.parentNode&&(b.outerHTML=a.outerHTML),p.support.html5Clone&&a.innerHTML&&!p.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):c==="input"&&bv.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):c==="option"?b.selected=a.defaultSelected:c==="input"||c==="textarea"?b.defaultValue=a.defaultValue:c==="script"&&b.text!==a.text&&(b.text=a.text),b.removeAttribute(p.expando)}function bF(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bG(a){bv.test(a.type)&&(a.defaultChecked=a.checked)}function bY(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=bW.length;while(e--){b=bW[e]+c;if(b in a)return b}return d}function bZ(a,b){return a=b||a,p.css(a,"display")==="none"||!p.contains(a.ownerDocument,a)}function b$(a,b){var c,d,e=[],f=0,g=a.length;for(;f<g;f++){c=a[f];if(!c.style)continue;e[f]=p._data(c,"olddisplay"),b?(!e[f]&&c.style.display==="none"&&(c.style.display=""),c.style.display===""&&bZ(c)&&(e[f]=p._data(c,"olddisplay",cc(c.nodeName)))):(d=bH(c,"display"),!e[f]&&d!=="none"&&p._data(c,"olddisplay",d))}for(f=0;f<g;f++){c=a[f];if(!c.style)continue;if(!b||c.style.display==="none"||c.style.display==="")c.style.display=b?e[f]||"":"none"}return a}function b_(a,b,c){var d=bP.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function ca(a,b,c,d){var e=c===(d?"border":"content")?4:b==="width"?1:0,f=0;for(;e<4;e+=2)c==="margin"&&(f+=p.css(a,c+bV[e],!0)),d?(c==="content"&&(f-=parseFloat(bH(a,"padding"+bV[e]))||0),c!=="margin"&&(f-=parseFloat(bH(a,"border"+bV[e]+"Width"))||0)):(f+=parseFloat(bH(a,"padding"+bV[e]))||0,c!=="padding"&&(f+=parseFloat(bH(a,"border"+bV[e]+"Width"))||0));return f}function cb(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=!0,f=p.support.boxSizing&&p.css(a,"boxSizing")==="border-box";if(d<=0||d==null){d=bH(a,b);if(d<0||d==null)d=a.style[b];if(bQ.test(d))return d;e=f&&(p.support.boxSizingReliable||d===a.style[b]),d=parseFloat(d)||0}return d+ca(a,b,c||(f?"border":"content"),e)+"px"}function cc(a){if(bS[a])return bS[a];var b=p("<"+a+">").appendTo(e.body),c=b.css("display");b.remove();if(c==="none"||c===""){bI=e.body.appendChild(bI||p.extend(e.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!bJ||!bI.createElement)bJ=(bI.contentWindow||bI.contentDocument).document,bJ.write("<!doctype html><html><body>"),bJ.close();b=bJ.body.appendChild(bJ.createElement(a)),c=bH(b,"display"),e.body.removeChild(bI)}return bS[a]=c,c}function ci(a,b,c,d){var e;if(p.isArray(b))p.each(b,function(b,e){c||ce.test(a)?d(a,e):ci(a+"["+(typeof e=="object"?b:"")+"]",e,c,d)});else if(!c&&p.type(b)==="object")for(e in b)ci(a+"["+e+"]",b[e],c,d);else d(a,b)}function cz(a){return function(b,c){typeof b!="string"&&(c=b,b="*");var d,e,f,g=b.toLowerCase().split(s),h=0,i=g.length;if(p.isFunction(c))for(;h<i;h++)d=g[h],f=/^\+/.test(d),f&&(d=d.substr(1)||"*"),e=a[d]=a[d]||[],e[f?"unshift":"push"](c)}}function cA(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h,i=a[f],j=0,k=i?i.length:0,l=a===cv;for(;j<k&&(l||!h);j++)h=i[j](c,d,e),typeof h=="string"&&(!l||g[h]?h=b:(c.dataTypes.unshift(h),h=cA(a,c,d,e,h,g)));return(l||!h)&&!g["*"]&&(h=cA(a,c,d,e,"*",g)),h}function cB(a,c){var d,e,f=p.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((f[d]?a:e||(e={}))[d]=c[d]);e&&p.extend(!0,a,e)}function cC(a,c,d){var e,f,g,h,i=a.contents,j=a.dataTypes,k=a.responseFields;for(f in k)f in d&&(c[k[f]]=d[f]);while(j[0]==="*")j.shift(),e===b&&(e=a.mimeType||c.getResponseHeader("content-type"));if(e)for(f in i)if(i[f]&&i[f].test(e)){j.unshift(f);break}if(j[0]in d)g=j[0];else{for(f in d){if(!j[0]||a.converters[f+" "+j[0]]){g=f;break}h||(h=f)}g=g||h}if(g)return g!==j[0]&&j.unshift(g),d[g]}function cD(a,b){var c,d,e,f,g=a.dataTypes.slice(),h=g[0],i={},j=0;a.dataFilter&&(b=a.dataFilter(b,a.dataType));if(g[1])for(c in a.converters)i[c.toLowerCase()]=a.converters[c];for(;e=g[++j];)if(e!=="*"){if(h!=="*"&&h!==e){c=i[h+" "+e]||i["* "+e];if(!c)for(d in i){f=d.split(" ");if(f[1]===e){c=i[h+" "+f[0]]||i["* "+f[0]];if(c){c===!0?c=i[d]:i[d]!==!0&&(e=f[0],g.splice(j--,0,e));break}}}if(c!==!0)if(c&&a["throws"])b=c(b);else try{b=c(b)}catch(k){return{state:"parsererror",error:c?k:"No conversion from "+h+" to "+e}}}h=e}return{state:"success",data:b}}function cL(){try{return new a.XMLHttpRequest}catch(b){}}function cM(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function cU(){return setTimeout(function(){cN=b},0),cN=p.now()}function cV(a,b){p.each(b,function(b,c){var d=(cT[b]||[]).concat(cT["*"]),e=0,f=d.length;for(;e<f;e++)if(d[e].call(a,b,c))return})}function cW(a,b,c){var d,e=0,f=0,g=cS.length,h=p.Deferred().always(function(){delete i.elem}),i=function(){var b=cN||cU(),c=Math.max(0,j.startTime+j.duration-b),d=1-(c/j.duration||0),e=0,f=j.tweens.length;for(;e<f;e++)j.tweens[e].run(d);return h.notifyWith(a,[j,d,c]),d<1&&f?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:p.extend({},b),opts:p.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:cN||cU(),duration:c.duration,tweens:[],createTween:function(b,c,d){var e=p.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(e),e},stop:function(b){var c=0,d=b?j.tweens.length:0;for(;c<d;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;cX(k,j.opts.specialEasing);for(;e<g;e++){d=cS[e].call(j,a,k,j.opts);if(d)return d}return cV(j,k),p.isFunction(j.opts.start)&&j.opts.start.call(a,j),p.fx.timer(p.extend(i,{anim:j,queue:j.opts.queue,elem:a})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}function cX(a,b){var c,d,e,f,g;for(c in a){d=p.camelCase(c),e=b[d],f=a[c],p.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=p.cssHooks[d];if(g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}}function cY(a,b,c){var d,e,f,g,h,i,j,k,l=this,m=a.style,n={},o=[],q=a.nodeType&&bZ(a);c.queue||(j=p._queueHooks(a,"fx"),j.unqueued==null&&(j.unqueued=0,k=j.empty.fire,j.empty.fire=function(){j.unqueued||k()}),j.unqueued++,l.always(function(){l.always(function(){j.unqueued--,p.queue(a,"fx").length||j.empty.fire()})})),a.nodeType===1&&("height"in b||"width"in b)&&(c.overflow=[m.overflow,m.overflowX,m.overflowY],p.css(a,"display")==="inline"&&p.css(a,"float")==="none"&&(!p.support.inlineBlockNeedsLayout||cc(a.nodeName)==="inline"?m.display="inline-block":m.zoom=1)),c.overflow&&(m.overflow="hidden",p.support.shrinkWrapBlocks||l.done(function(){m.overflow=c.overflow[0],m.overflowX=c.overflow[1],m.overflowY=c.overflow[2]}));for(d in b){f=b[d];if(cP.exec(f)){delete b[d];if(f===(q?"hide":"show"))continue;o.push(d)}}g=o.length;if(g){h=p._data(a,"fxshow")||p._data(a,"fxshow",{}),q?p(a).show():l.done(function(){p(a).hide()}),l.done(function(){var b;p.removeData(a,"fxshow",!0);for(b in n)p.style(a,b,n[b])});for(d=0;d<g;d++)e=o[d],i=l.createTween(e,q?h[e]:0),n[e]=h[e]||p.style(a,e),e in h||(h[e]=i.start,q&&(i.end=i.start,i.start=e==="width"||e==="height"?1:0))}}function cZ(a,b,c,d,e){return new cZ.prototype.init(a,b,c,d,e)}function c$(a,b){var c,d={height:a},e=0;b=b?1:0;for(;e<4;e+=2-b)c=bV[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function da(a){return p.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}var c,d,e=a.document,f=a.location,g=a.navigator,h=a.jQuery,i=a.$,j=Array.prototype.push,k=Array.prototype.slice,l=Array.prototype.indexOf,m=Object.prototype.toString,n=Object.prototype.hasOwnProperty,o=String.prototype.trim,p=function(a,b){return new p.fn.init(a,b,c)},q=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,r=/\S/,s=/\s+/,t=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,u=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,y=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,z=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,A=/^-ms-/,B=/-([\da-z])/gi,C=function(a,b){return(b+"").toUpperCase()},D=function(){e.addEventListener?(e.removeEventListener("DOMContentLoaded",D,!1),p.ready()):e.readyState==="complete"&&(e.detachEvent("onreadystatechange",D),p.ready())},E={};p.fn=p.prototype={constructor:p,init:function(a,c,d){var f,g,h,i;if(!a)return this;if(a.nodeType)return this.context=this[0]=a,this.length=1,this;if(typeof a=="string"){a.charAt(0)==="<"&&a.charAt(a.length-1)===">"&&a.length>=3?f=[null,a,null]:f=u.exec(a);if(f&&(f[1]||!c)){if(f[1])return c=c instanceof p?c[0]:c,i=c&&c.nodeType?c.ownerDocument||c:e,a=p.parseHTML(f[1],i,!0),v.test(f[1])&&p.isPlainObject(c)&&this.attr.call(a,c,!0),p.merge(this,a);g=e.getElementById(f[2]);if(g&&g.parentNode){if(g.id!==f[2])return d.find(a);this.length=1,this[0]=g}return this.context=e,this.selector=a,this}return!c||c.jquery?(c||d).find(a):this.constructor(c).find(a)}return p.isFunction(a)?d.ready(a):(a.selector!==b&&(this.selector=a.selector,this.context=a.context),p.makeArray(a,this))},selector:"",jquery:"1.8.2",length:0,size:function(){return this.length},toArray:function(){return k.call(this)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=p.merge(this.constructor(),a);return d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")"),d},each:function(a,b){return p.each(this,a,b)},ready:function(a){return p.ready.promise().done(a),this},eq:function(a){return a=+a,a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(k.apply(this,arguments),"slice",k.call(arguments).join(","))},map:function(a){return this.pushStack(p.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:j,sort:[].sort,splice:[].splice},p.fn.init.prototype=p.fn,p.extend=p.fn.extend=function(){var a,c,d,e,f,g,h=arguments[0]||{},i=1,j=arguments.length,k=!1;typeof h=="boolean"&&(k=h,h=arguments[1]||{},i=2),typeof h!="object"&&!p.isFunction(h)&&(h={}),j===i&&(h=this,--i);for(;i<j;i++)if((a=arguments[i])!=null)for(c in a){d=h[c],e=a[c];if(h===e)continue;k&&e&&(p.isPlainObject(e)||(f=p.isArray(e)))?(f?(f=!1,g=d&&p.isArray(d)?d:[]):g=d&&p.isPlainObject(d)?d:{},h[c]=p.extend(k,g,e)):e!==b&&(h[c]=e)}return h},p.extend({noConflict:function(b){return a.$===p&&(a.$=i),b&&a.jQuery===p&&(a.jQuery=h),p},isReady:!1,readyWait:1,holdReady:function(a){a?p.readyWait++:p.ready(!0)},ready:function(a){if(a===!0?--p.readyWait:p.isReady)return;if(!e.body)return setTimeout(p.ready,1);p.isReady=!0;if(a!==!0&&--p.readyWait>0)return;d.resolveWith(e,[p]),p.fn.trigger&&p(e).trigger("ready").off("ready")},isFunction:function(a){return p.type(a)==="function"},isArray:Array.isArray||function(a){return p.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):E[m.call(a)]||"object"},isPlainObject:function(a){if(!a||p.type(a)!=="object"||a.nodeType||p.isWindow(a))return!1;try{if(a.constructor&&!n.call(a,"constructor")&&!n.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||n.call(a,d)},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},error:function(a){throw new Error(a)},parseHTML:function(a,b,c){var d;return!a||typeof a!="string"?null:(typeof b=="boolean"&&(c=b,b=0),b=b||e,(d=v.exec(a))?[b.createElement(d[1])]:(d=p.buildFragment([a],b,c?null:[]),p.merge([],(d.cacheable?p.clone(d.fragment):d.fragment).childNodes)))},parseJSON:function(b){if(!b||typeof b!="string")return null;b=p.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(w.test(b.replace(y,"@").replace(z,"]").replace(x,"")))return(new Function("return "+b))();p.error("Invalid JSON: "+b)},parseXML:function(c){var d,e;if(!c||typeof c!="string")return null;try{a.DOMParser?(e=new DOMParser,d=e.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(f){d=b}return(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&p.error("Invalid XML: "+c),d},noop:function(){},globalEval:function(b){b&&r.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(A,"ms-").replace(B,C)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,c,d){var e,f=0,g=a.length,h=g===b||p.isFunction(a);if(d){if(h){for(e in a)if(c.apply(a[e],d)===!1)break}else for(;f<g;)if(c.apply(a[f++],d)===!1)break}else if(h){for(e in a)if(c.call(a[e],e,a[e])===!1)break}else for(;f<g;)if(c.call(a[f],f,a[f++])===!1)break;return a},trim:o&&!o.call(" ")?function(a){return a==null?"":o.call(a)}:function(a){return a==null?"":(a+"").replace(t,"")},makeArray:function(a,b){var c,d=b||[];return a!=null&&(c=p.type(a),a.length==null||c==="string"||c==="function"||c==="regexp"||p.isWindow(a)?j.call(d,a):p.merge(d,a)),d},inArray:function(a,b,c){var d;if(b){if(l)return l.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=c.length,e=a.length,f=0;if(typeof d=="number")for(;f<d;f++)a[e++]=c[f];else while(c[f]!==b)a[e++]=c[f++];return a.length=e,a},grep:function(a,b,c){var d,e=[],f=0,g=a.length;c=!!c;for(;f<g;f++)d=!!b(a[f],f),c!==d&&e.push(a[f]);return e},map:function(a,c,d){var e,f,g=[],h=0,i=a.length,j=a instanceof p||i!==b&&typeof i=="number"&&(i>0&&a[0]&&a[i-1]||i===0||p.isArray(a));if(j)for(;h<i;h++)e=c(a[h],h,d),e!=null&&(g[g.length]=e);else for(f in a)e=c(a[f],f,d),e!=null&&(g[g.length]=e);return g.concat.apply([],g)},guid:1,proxy:function(a,c){var d,e,f;return typeof c=="string"&&(d=a[c],c=a,a=d),p.isFunction(a)?(e=k.call(arguments,2),f=function(){return a.apply(c,e.concat(k.call(arguments)))},f.guid=a.guid=a.guid||p.guid++,f):b},access:function(a,c,d,e,f,g,h){var i,j=d==null,k=0,l=a.length;if(d&&typeof d=="object"){for(k in d)p.access(a,c,k,d[k],1,g,e);f=1}else if(e!==b){i=h===b&&p.isFunction(e),j&&(i?(i=c,c=function(a,b,c){return i.call(p(a),c)}):(c.call(a,e),c=null));if(c)for(;k<l;k++)c(a[k],d,i?e.call(a[k],k,c(a[k],d)):e,h);f=1}return f?a:j?c.call(a):l?c(a[0],d):g},now:function(){return(new Date).getTime()}}),p.ready.promise=function(b){if(!d){d=p.Deferred();if(e.readyState==="complete")setTimeout(p.ready,1);else if(e.addEventListener)e.addEventListener("DOMContentLoaded",D,!1),a.addEventListener("load",p.ready,!1);else{e.attachEvent("onreadystatechange",D),a.attachEvent("onload",p.ready);var c=!1;try{c=a.frameElement==null&&e.documentElement}catch(f){}c&&c.doScroll&&function g(){if(!p.isReady){try{c.doScroll("left")}catch(a){return setTimeout(g,50)}p.ready()}}()}}return d.promise(b)},p.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){E["[object "+b+"]"]=b.toLowerCase()}),c=p(e);var F={};p.Callbacks=function(a){a=typeof a=="string"?F[a]||G(a):p.extend({},a);var c,d,e,f,g,h,i=[],j=!a.once&&[],k=function(b){c=a.memory&&b,d=!0,h=f||0,f=0,g=i.length,e=!0;for(;i&&h<g;h++)if(i[h].apply(b[0],b[1])===!1&&a.stopOnFalse){c=!1;break}e=!1,i&&(j?j.length&&k(j.shift()):c?i=[]:l.disable())},l={add:function(){if(i){var b=i.length;(function d(b){p.each(b,function(b,c){var e=p.type(c);e==="function"&&(!a.unique||!l.has(c))?i.push(c):c&&c.length&&e!=="string"&&d(c)})})(arguments),e?g=i.length:c&&(f=b,k(c))}return this},remove:function(){return i&&p.each(arguments,function(a,b){var c;while((c=p.inArray(b,i,c))>-1)i.splice(c,1),e&&(c<=g&&g--,c<=h&&h--)}),this},has:function(a){return p.inArray(a,i)>-1},empty:function(){return i=[],this},disable:function(){return i=j=c=b,this},disabled:function(){return!i},lock:function(){return j=b,c||l.disable(),this},locked:function(){return!j},fireWith:function(a,b){return b=b||[],b=[a,b.slice?b.slice():b],i&&(!d||j)&&(e?j.push(b):k(b)),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!d}};return l},p.extend({Deferred:function(a){var b=[["resolve","done",p.Callbacks("once memory"),"resolved"],["reject","fail",p.Callbacks("once memory"),"rejected"],["notify","progress",p.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return p.Deferred(function(c){p.each(b,function(b,d){var f=d[0],g=a[b];e[d[1]](p.isFunction(g)?function(){var a=g.apply(this,arguments);a&&p.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f+"With"](this===e?c:this,[a])}:c[f])}),a=null}).promise()},promise:function(a){return a!=null?p.extend(a,d):d}},e={};return d.pipe=d.then,p.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[a^1][2].disable,b[2][2].lock),e[f[0]]=g.fire,e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=k.call(arguments),d=c.length,e=d!==1||a&&p.isFunction(a.promise)?d:0,f=e===1?a:p.Deferred(),g=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?k.call(arguments):d,c===h?f.notifyWith(b,c):--e||f.resolveWith(b,c)}},h,i,j;if(d>1){h=new Array(d),i=new Array(d),j=new Array(d);for(;b<d;b++)c[b]&&p.isFunction(c[b].promise)?c[b].promise().done(g(b,j,c)).fail(f.reject).progress(g(b,i,h)):--e}return e||f.resolveWith(j,c),f.promise()}}),p.support=function(){var b,c,d,f,g,h,i,j,k,l,m,n=e.createElement("div");n.setAttribute("className","t"),n.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",c=n.getElementsByTagName("*"),d=n.getElementsByTagName("a")[0],d.style.cssText="top:1px;float:left;opacity:.5";if(!c||!c.length)return{};f=e.createElement("select"),g=f.appendChild(e.createElement("option")),h=n.getElementsByTagName("input")[0],b={leadingWhitespace:n.firstChild.nodeType===3,tbody:!n.getElementsByTagName("tbody").length,htmlSerialize:!!n.getElementsByTagName("link").length,style:/top/.test(d.getAttribute("style")),hrefNormalized:d.getAttribute("href")==="/a",opacity:/^0.5/.test(d.style.opacity),cssFloat:!!d.style.cssFloat,checkOn:h.value==="on",optSelected:g.selected,getSetAttribute:n.className!=="t",enctype:!!e.createElement("form").enctype,html5Clone:e.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",boxModel:e.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},h.checked=!0,b.noCloneChecked=h.cloneNode(!0).checked,f.disabled=!0,b.optDisabled=!g.disabled;try{delete n.test}catch(o){b.deleteExpando=!1}!n.addEventListener&&n.attachEvent&&n.fireEvent&&(n.attachEvent("onclick",m=function(){b.noCloneEvent=!1}),n.cloneNode(!0).fireEvent("onclick"),n.detachEvent("onclick",m)),h=e.createElement("input"),h.value="t",h.setAttribute("type","radio"),b.radioValue=h.value==="t",h.setAttribute("checked","checked"),h.setAttribute("name","t"),n.appendChild(h),i=e.createDocumentFragment(),i.appendChild(n.lastChild),b.checkClone=i.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=h.checked,i.removeChild(h),i.appendChild(n);if(n.attachEvent)for(k in{submit:!0,change:!0,focusin:!0})j="on"+k,l=j in n,l||(n.setAttribute(j,"return;"),l=typeof n[j]=="function"),b[k+"Bubbles"]=l;return p(function(){var c,d,f,g,h="padding:0;margin:0;border:0;display:block;overflow:hidden;",i=e.getElementsByTagName("body")[0];if(!i)return;c=e.createElement("div"),c.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",i.insertBefore(c,i.firstChild),d=e.createElement("div"),c.appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",f=d.getElementsByTagName("td"),f[0].style.cssText="padding:0;margin:0;border:0;display:none",l=f[0].offsetHeight===0,f[0].style.display="",f[1].style.display="none",b.reliableHiddenOffsets=l&&f[0].offsetHeight===0,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",b.boxSizing=d.offsetWidth===4,b.doesNotIncludeMarginInBodyOffset=i.offsetTop!==1,a.getComputedStyle&&(b.pixelPosition=(a.getComputedStyle(d,null)||{}).top!=="1%",b.boxSizingReliable=(a.getComputedStyle(d,null)||{width:"4px"}).width==="4px",g=e.createElement("div"),g.style.cssText=d.style.cssText=h,g.style.marginRight=g.style.width="0",d.style.width="1px",d.appendChild(g),b.reliableMarginRight=!parseFloat((a.getComputedStyle(g,null)||{}).marginRight)),typeof d.style.zoom!="undefined"&&(d.innerHTML="",d.style.cssText=h+"width:1px;padding:1px;display:inline;zoom:1",b.inlineBlockNeedsLayout=d.offsetWidth===3,d.style.display="block",d.style.overflow="visible",d.innerHTML="<div></div>",d.firstChild.style.width="5px",b.shrinkWrapBlocks=d.offsetWidth!==3,c.style.zoom=1),i.removeChild(c),c=d=f=g=null}),i.removeChild(n),c=d=f=g=h=i=n=null,b}();var H=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,I=/([A-Z])/g;p.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(p.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){return a=a.nodeType?p.cache[a[p.expando]]:a[p.expando],!!a&&!K(a)},data:function(a,c,d,e){if(!p.acceptData(a))return;var f,g,h=p.expando,i=typeof c=="string",j=a.nodeType,k=j?p.cache:a,l=j?a[h]:a[h]&&h;if((!l||!k[l]||!e&&!k[l].data)&&i&&d===b)return;l||(j?a[h]=l=p.deletedIds.pop()||p.guid++:l=h),k[l]||(k[l]={},j||(k[l].toJSON=p.noop));if(typeof c=="object"||typeof c=="function")e?k[l]=p.extend(k[l],c):k[l].data=p.extend(k[l].data,c);return f=k[l],e||(f.data||(f.data={}),f=f.data),d!==b&&(f[p.camelCase(c)]=d),i?(g=f[c],g==null&&(g=f[p.camelCase(c)])):g=f,g},removeData:function(a,b,c){if(!p.acceptData(a))return;var d,e,f,g=a.nodeType,h=g?p.cache:a,i=g?a[p.expando]:p.expando;if(!h[i])return;if(b){d=c?h[i]:h[i].data;if(d){p.isArray(b)||(b in d?b=[b]:(b=p.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,f=b.length;e<f;e++)delete d[b[e]];if(!(c?K:p.isEmptyObject)(d))return}}if(!c){delete h[i].data;if(!K(h[i]))return}g?p.cleanData([a],!0):p.support.deleteExpando||h!=h.window?delete h[i]:h[i]=null},_data:function(a,b,c){return p.data(a,b,c,!0)},acceptData:function(a){var b=a.nodeName&&p.noData[a.nodeName.toLowerCase()];return!b||b!==!0&&a.getAttribute("classid")===b}}),p.fn.extend({data:function(a,c){var d,e,f,g,h,i=this[0],j=0,k=null;if(a===b){if(this.length){k=p.data(i);if(i.nodeType===1&&!p._data(i,"parsedAttrs")){f=i.attributes;for(h=f.length;j<h;j++)g=f[j].name,g.indexOf("data-")||(g=p.camelCase(g.substring(5)),J(i,g,k[g]));p._data(i,"parsedAttrs",!0)}}return k}return typeof a=="object"?this.each(function(){p.data(this,a)}):(d=a.split(".",2),d[1]=d[1]?"."+d[1]:"",e=d[1]+"!",p.access(this,function(c){if(c===b)return k=this.triggerHandler("getData"+e,[d[0]]),k===b&&i&&(k=p.data(i,a),k=J(i,a,k)),k===b&&d[1]?this.data(d[0]):k;d[1]=c,this.each(function(){var b=p(this);b.triggerHandler("setData"+e,d),p.data(this,a,c),b.triggerHandler("changeData"+e,d)})},null,c,arguments.length>1,null,!1))},removeData:function(a){return this.each(function(){p.removeData(this,a)})}}),p.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=p._data(a,b),c&&(!d||p.isArray(c)?d=p._data(a,b,p.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=p.queue(a,b),d=c.length,e=c.shift(),f=p._queueHooks(a,b),g=function(){p.dequeue(a,b)};e==="inprogress"&&(e=c.shift(),d--),e&&(b==="fx"&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return p._data(a,c)||p._data(a,c,{empty:p.Callbacks("once memory").add(function(){p.removeData(a,b+"queue",!0),p.removeData(a,c,!0)})})}}),p.fn.extend({queue:function(a,c){var d=2;return typeof a!="string"&&(c=a,a="fx",d--),arguments.length<d?p.queue(this[0],a):c===b?this:this.each(function(){var b=p.queue(this,a,c);p._queueHooks(this,a),a==="fx"&&b[0]!=="inprogress"&&p.dequeue(this,a)})},dequeue:function(a){return this.each(function(){p.dequeue(this,a)})},delay:function(a,b){return a=p.fx?p.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){var d,e=1,f=p.Deferred(),g=this,h=this.length,i=function(){--e||f.resolveWith(g,[g])};typeof a!="string"&&(c=a,a=b),a=a||"fx";while(h--)d=p._data(g[h],a+"queueHooks"),d&&d.empty&&(e++,d.empty.add(i));return i(),f.promise(c)}});var L,M,N,O=/[\t\r\n]/g,P=/\r/g,Q=/^(?:button|input)$/i,R=/^(?:button|input|object|select|textarea)$/i,S=/^a(?:rea|)$/i,T=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,U=p.support.getSetAttribute;p.fn.extend({attr:function(a,b){return p.access(this,p.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){p.removeAttr(this,a)})},prop:function(a,b){return p.access(this,p.prop,a,b,arguments.length>1)},removeProp:function(a){return a=p.propFix[a]||a,this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,f,g,h;if(p.isFunction(a))return this.each(function(b){p(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(s);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{f=" "+e.className+" ";for(g=0,h=b.length;g<h;g++)f.indexOf(" "+b[g]+" ")<0&&(f+=b[g]+" ");e.className=p.trim(f)}}}return this},removeClass:function(a){var c,d,e,f,g,h,i;if(p.isFunction(a))return this.each(function(b){p(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(s);for(h=0,i=this.length;h<i;h++){e=this[h];if(e.nodeType===1&&e.className){d=(" "+e.className+" ").replace(O," ");for(f=0,g=c.length;f<g;f++)while(d.indexOf(" "+c[f]+" ")>=0)d=d.replace(" "+c[f]+" "," ");e.className=a?p.trim(d):""}}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";return p.isFunction(a)?this.each(function(c){p(this).toggleClass(a.call(this,c,this.className,b),b)}):this.each(function(){if(c==="string"){var e,f=0,g=p(this),h=b,i=a.split(s);while(e=i[f++])h=d?h:!g.hasClass(e),g[h?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&p._data(this,"__className__",this.className),this.className=this.className||a===!1?"":p._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(O," ").indexOf(b)>=0)return!0;return!1},val:function(a){var c,d,e,f=this[0];if(!arguments.length){if(f)return c=p.valHooks[f.type]||p.valHooks[f.nodeName.toLowerCase()],c&&"get"in c&&(d=c.get(f,"value"))!==b?d:(d=f.value,typeof d=="string"?d.replace(P,""):d==null?"":d);return}return e=p.isFunction(a),this.each(function(d){var f,g=p(this);if(this.nodeType!==1)return;e?f=a.call(this,d,g.val()):f=a,f==null?f="":typeof f=="number"?f+="":p.isArray(f)&&(f=p.map(f,function(a){return a==null?"":a+""})),c=p.valHooks[this.type]||p.valHooks[this.nodeName.toLowerCase()];if(!c||!("set"in c)||c.set(this,f,"value")===b)this.value=f})}}),p.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,f=a.selectedIndex,g=[],h=a.options,i=a.type==="select-one";if(f<0)return null;c=i?f:0,d=i?f+1:h.length;for(;c<d;c++){e=h[c];if(e.selected&&(p.support.optDisabled?!e.disabled:e.getAttribute("disabled")===null)&&(!e.parentNode.disabled||!p.nodeName(e.parentNode,"optgroup"))){b=p(e).val();if(i)return b;g.push(b)}}return i&&!g.length&&h.length?p(h[f]).val():g},set:function(a,b){var c=p.makeArray(b);return p(a).find("option").each(function(){this.selected=p.inArray(p(this).val(),c)>=0}),c.length||(a.selectedIndex=-1),c}}},attrFn:{},attr:function(a,c,d,e){var f,g,h,i=a.nodeType;if(!a||i===3||i===8||i===2)return;if(e&&p.isFunction(p.fn[c]))return p(a)[c](d);if(typeof a.getAttribute=="undefined")return p.prop(a,c,d);h=i!==1||!p.isXMLDoc(a),h&&(c=c.toLowerCase(),g=p.attrHooks[c]||(T.test(c)?M:L));if(d!==b){if(d===null){p.removeAttr(a,c);return}return g&&"set"in g&&h&&(f=g.set(a,d,c))!==b?f:(a.setAttribute(c,d+""),d)}return g&&"get"in g&&h&&(f=g.get(a,c))!==null?f:(f=a.getAttribute(c),f===null?b:f)},removeAttr:function(a,b){var c,d,e,f,g=0;if(b&&a.nodeType===1){d=b.split(s);for(;g<d.length;g++)e=d[g],e&&(c=p.propFix[e]||e,f=T.test(e),f||p.attr(a,e,""),a.removeAttribute(U?e:c),f&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(Q.test(a.nodeName)&&a.parentNode)p.error("type property can't be changed");else if(!p.support.radioValue&&b==="radio"&&p.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}},value:{get:function(a,b){return L&&p.nodeName(a,"button")?L.get(a,b):b in a?a.value:null},set:function(a,b,c){if(L&&p.nodeName(a,"button"))return L.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e,f,g,h=a.nodeType;if(!a||h===3||h===8||h===2)return;return g=h!==1||!p.isXMLDoc(a),g&&(c=p.propFix[c]||c,f=p.propHooks[c]),d!==b?f&&"set"in f&&(e=f.set(a,d,c))!==b?e:a[c]=d:f&&"get"in f&&(e=f.get(a,c))!==null?e:a[c]},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):R.test(a.nodeName)||S.test(a.nodeName)&&a.href?0:b}}}}),M={get:function(a,c){var d,e=p.prop(a,c);return e===!0||typeof e!="boolean"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;return b===!1?p.removeAttr(a,c):(d=p.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase())),c}},U||(N={name:!0,id:!0,coords:!0},L=p.valHooks.button={get:function(a,c){var d;return d=a.getAttributeNode(c),d&&(N[c]?d.value!=="":d.specified)?d.value:b},set:function(a,b,c){var d=a.getAttributeNode(c);return d||(d=e.createAttribute(c),a.setAttributeNode(d)),d.value=b+""}},p.each(["width","height"],function(a,b){p.attrHooks[b]=p.extend(p.attrHooks[b],{set:function(a,c){if(c==="")return a.setAttribute(b,"auto"),c}})}),p.attrHooks.contenteditable={get:L.get,set:function(a,b,c){b===""&&(b="false"),L.set(a,b,c)}}),p.support.hrefNormalized||p.each(["href","src","width","height"],function(a,c){p.attrHooks[c]=p.extend(p.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),p.support.style||(p.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=b+""}}),p.support.optSelected||(p.propHooks.selected=p.extend(p.propHooks.selected,{get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}})),p.support.enctype||(p.propFix.enctype="encoding"),p.support.checkOn||p.each(["radio","checkbox"],function(){p.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),p.each(["radio","checkbox"],function(){p.valHooks[this]=p.extend(p.valHooks[this],{set:function(a,b){if(p.isArray(b))return a.checked=p.inArray(p(a).val(),b)>=0}})});var V=/^(?:textarea|input|select)$/i,W=/^([^\.]*|)(?:\.(.+)|)$/,X=/(?:^|\s)hover(\.\S+|)\b/,Y=/^key/,Z=/^(?:mouse|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=function(a){return p.event.special.hover?a:a.replace(X,"mouseenter$1 mouseleave$1")};p.event={add:function(a,c,d,e,f){var g,h,i,j,k,l,m,n,o,q,r;if(a.nodeType===3||a.nodeType===8||!c||!d||!(g=p._data(a)))return;d.handler&&(o=d,d=o.handler,f=o.selector),d.guid||(d.guid=p.guid++),i=g.events,i||(g.events=i={}),h=g.handle,h||(g.handle=h=function(a){return typeof p!="undefined"&&(!a||p.event.triggered!==a.type)?p.event.dispatch.apply(h.elem,arguments):b},h.elem=a),c=p.trim(_(c)).split(" ");for(j=0;j<c.length;j++){k=W.exec(c[j])||[],l=k[1],m=(k[2]||"").split(".").sort(),r=p.event.special[l]||{},l=(f?r.delegateType:r.bindType)||l,r=p.event.special[l]||{},n=p.extend({type:l,origType:k[1],data:e,handler:d,guid:d.guid,selector:f,needsContext:f&&p.expr.match.needsContext.test(f),namespace:m.join(".")},o),q=i[l];if(!q){q=i[l]=[],q.delegateCount=0;if(!r.setup||r.setup.call(a,e,m,h)===!1)a.addEventListener?a.addEventListener(l,h,!1):a.attachEvent&&a.attachEvent("on"+l,h)}r.add&&(r.add.call(a,n),n.handler.guid||(n.handler.guid=d.guid)),f?q.splice(q.delegateCount++,0,n):q.push(n),p.event.global[l]=!0}a=null},global:{},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,q,r=p.hasData(a)&&p._data(a);if(!r||!(m=r.events))return;b=p.trim(_(b||"")).split(" ");for(f=0;f<b.length;f++){g=W.exec(b[f])||[],h=i=g[1],j=g[2];if(!h){for(h in m)p.event.remove(a,h+b[f],c,d,!0);continue}n=p.event.special[h]||{},h=(d?n.delegateType:n.bindType)||h,o=m[h]||[],k=o.length,j=j?new RegExp("(^|\\.)"+j.split(".").sort().join("\\.(?:.*\\.|)")+"(\\.|$)"):null;for(l=0;l<o.length;l++)q=o[l],(e||i===q.origType)&&(!c||c.guid===q.guid)&&(!j||j.test(q.namespace))&&(!d||d===q.selector||d==="**"&&q.selector)&&(o.splice(l--,1),q.selector&&o.delegateCount--,n.remove&&n.remove.call(a,q));o.length===0&&k!==o.length&&((!n.teardown||n.teardown.call(a,j,r.handle)===!1)&&p.removeEvent(a,h,r.handle),delete m[h])}p.isEmptyObject(m)&&(delete r.handle,p.removeData(a,"events",!0))},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,f,g){if(!f||f.nodeType!==3&&f.nodeType!==8){var h,i,j,k,l,m,n,o,q,r,s=c.type||c,t=[];if($.test(s+p.event.triggered))return;s.indexOf("!")>=0&&(s=s.slice(0,-1),i=!0),s.indexOf(".")>=0&&(t=s.split("."),s=t.shift(),t.sort());if((!f||p.event.customEvent[s])&&!p.event.global[s])return;c=typeof c=="object"?c[p.expando]?c:new p.Event(s,c):new p.Event(s),c.type=s,c.isTrigger=!0,c.exclusive=i,c.namespace=t.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+t.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,m=s.indexOf(":")<0?"on"+s:"";if(!f){h=p.cache;for(j in h)h[j].events&&h[j].events[s]&&p.event.trigger(c,d,h[j].handle.elem,!0);return}c.result=b,c.target||(c.target=f),d=d!=null?p.makeArray(d):[],d.unshift(c),n=p.event.special[s]||{};if(n.trigger&&n.trigger.apply(f,d)===!1)return;q=[[f,n.bindType||s]];if(!g&&!n.noBubble&&!p.isWindow(f)){r=n.delegateType||s,k=$.test(r+s)?f:f.parentNode;for(l=f;k;k=k.parentNode)q.push([k,r]),l=k;l===(f.ownerDocument||e)&&q.push([l.defaultView||l.parentWindow||a,r])}for(j=0;j<q.length&&!c.isPropagationStopped();j++)k=q[j][0],c.type=q[j][1],o=(p._data(k,"events")||{})[c.type]&&p._data(k,"handle"),o&&o.apply(k,d),o=m&&k[m],o&&p.acceptData(k)&&o.apply&&o.apply(k,d)===!1&&c.preventDefault();return c.type=s,!g&&!c.isDefaultPrevented()&&(!n._default||n._default.apply(f.ownerDocument,d)===!1)&&(s!=="click"||!p.nodeName(f,"a"))&&p.acceptData(f)&&m&&f[s]&&(s!=="focus"&&s!=="blur"||c.target.offsetWidth!==0)&&!p.isWindow(f)&&(l=f[m],l&&(f[m]=null),p.event.triggered=s,f[s](),p.event.triggered=b,l&&(f[m]=l)),c.result}return},dispatch:function(c){c=p.event.fix(c||a.event);var d,e,f,g,h,i,j,l,m,n,o=(p._data(this,"events")||{})[c.type]||[],q=o.delegateCount,r=k.call(arguments),s=!c.exclusive&&!c.namespace,t=p.event.special[c.type]||{},u=[];r[0]=c,c.delegateTarget=this;if(t.preDispatch&&t.preDispatch.call(this,c)===!1)return;if(q&&(!c.button||c.type!=="click"))for(f=c.target;f!=this;f=f.parentNode||this)if(f.disabled!==!0||c.type!=="click"){h={},j=[];for(d=0;d<q;d++)l=o[d],m=l.selector,h[m]===b&&(h[m]=l.needsContext?p(m,this).index(f)>=0:p.find(m,this,null,[f]).length),h[m]&&j.push(l);j.length&&u.push({elem:f,matches:j})}o.length>q&&u.push({elem:this,matches:o.slice(q)});for(d=0;d<u.length&&!c.isPropagationStopped();d++){i=u[d],c.currentTarget=i.elem;for(e=0;e<i.matches.length&&!c.isImmediatePropagationStopped();e++){l=i.matches[e];if(s||!c.namespace&&!l.namespace||c.namespace_re&&c.namespace_re.test(l.namespace))c.data=l.data,c.handleObj=l,g=((p.event.special[l.origType]||{}).handle||l.handler).apply(i.elem,r),g!==b&&(c.result=g,g===!1&&(c.preventDefault(),c.stopPropagation()))}}return t.postDispatch&&t.postDispatch.call(this,c),c.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,c){var d,f,g,h=c.button,i=c.fromElement;return a.pageX==null&&c.clientX!=null&&(d=a.target.ownerDocument||e,f=d.documentElement,g=d.body,a.pageX=c.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=c.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?c.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0),a}},fix:function(a){if(a[p.expando])return a;var b,c,d=a,f=p.event.fixHooks[a.type]||{},g=f.props?this.props.concat(f.props):this.props;a=p.Event(d);for(b=g.length;b;)c=g[--b],a[c]=d[c];return a.target||(a.target=d.srcElement||e),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,f.filter?f.filter(a,d):a},special:{load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(a,b,c){p.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=p.extend(new p.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?p.event.trigger(e,null,b):p.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},p.event.handle=p.event.dispatch,p.removeEvent=e.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){var d="on"+b;a.detachEvent&&(typeof a[d]=="undefined"&&(a[d]=null),a.detachEvent(d,c))},p.Event=function(a,b){if(this instanceof p.Event)a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?bb:ba):this.type=a,b&&p.extend(this,b),this.timeStamp=a&&a.timeStamp||p.now(),this[p.expando]=!0;else return new p.Event(a,b)},p.Event.prototype={preventDefault:function(){this.isDefaultPrevented=bb;var a=this.originalEvent;if(!a)return;a.preventDefault?a.preventDefault():a.returnValue=!1},stopPropagation:function(){this.isPropagationStopped=bb;var a=this.originalEvent;if(!a)return;a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=bb,this.stopPropagation()},isDefaultPrevented:ba,isPropagationStopped:ba,isImmediatePropagationStopped:ba},p.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){p.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj,g=f.selector;if(!e||e!==d&&!p.contains(d,e))a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b;return c}}}),p.support.submitBubbles||(p.event.special.submit={setup:function(){if(p.nodeName(this,"form"))return!1;p.event.add(this,"click._submit keypress._submit",function(a){var c=a.target,d=p.nodeName(c,"input")||p.nodeName(c,"button")?c.form:b;d&&!p._data(d,"_submit_attached")&&(p.event.add(d,"submit._submit",function(a){a._submit_bubble=!0}),p._data(d,"_submit_attached",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&p.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){if(p.nodeName(this,"form"))return!1;p.event.remove(this,"._submit")}}),p.support.changeBubbles||(p.event.special.change={setup:function(){if(V.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")p.event.add(this,"propertychange._change",function(a){a.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),p.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),p.event.simulate("change",this,a,!0)});return!1}p.event.add(this,"beforeactivate._change",function(a){var b=a.target;V.test(b.nodeName)&&!p._data(b,"_change_attached")&&(p.event.add(b,"change._change",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&p.event.simulate("change",this.parentNode,a,!0)}),p._data(b,"_change_attached",!0))})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!=="radio"&&b.type!=="checkbox")return a.handleObj.handler.apply(this,arguments)},teardown:function(){return p.event.remove(this,"._change"),!V.test(this.nodeName)}}),p.support.focusinBubbles||p.each({focus:"focusin",blur:"focusout"},function(a,b){var c=0,d=function(a){p.event.simulate(b,a.target,p.event.fix(a),!0)};p.event.special[b]={setup:function(){c++===0&&e.addEventListener(a,d,!0)},teardown:function(){--c===0&&e.removeEventListener(a,d,!0)}}}),p.fn.extend({on:function(a,c,d,e,f){var g,h;if(typeof a=="object"){typeof c!="string"&&(d=d||c,c=b);for(h in a)this.on(h,c,d,a[h],f);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c=="string"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=ba;else if(!e)return this;return f===1&&(g=e,e=function(a){return p().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=p.guid++)),this.each(function(){p.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,c,d){var e,f;if(a&&a.preventDefault&&a.handleObj)return e=a.handleObj,p(a.delegateTarget).off(e.namespace?e.origType+"."+e.namespace:e.origType,e.selector,e.handler),this;if(typeof a=="object"){for(f in a)this.off(f,c,a[f]);return this}if(c===!1||typeof c=="function")d=c,c=b;return d===!1&&(d=ba),this.each(function(){p.event.remove(this,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){return p(this.context).on(a,this.selector,b,c),this},die:function(a,b){return p(this.context).off(a,this.selector||"**",b),this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length===1?this.off(a,"**"):this.off(b,a||"**",c)},trigger:function(a,b){return this.each(function(){p.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return p.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||p.guid++,d=0,e=function(c){var e=(p._data(this,"lastToggle"+a.guid)||0)%d;return p._data(this,"lastToggle"+a.guid,e+1),c.preventDefault(),b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),p.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){p.fn[b]=function(a,c){return c==null&&(c=a,a=null),arguments.length>0?this.on(b,null,a,c):this.trigger(b)},Y.test(b)&&(p.event.fixHooks[b]=p.event.keyHooks),Z.test(b)&&(p.event.fixHooks[b]=p.event.mouseHooks)}),function(a,b){function bc(a,b,c,d){c=c||[],b=b||r;var e,f,i,j,k=b.nodeType;if(!a||typeof a!="string")return c;if(k!==1&&k!==9)return[];i=g(b);if(!i&&!d)if(e=P.exec(a))if(j=e[1]){if(k===9){f=b.getElementById(j);if(!f||!f.parentNode)return c;if(f.id===j)return c.push(f),c}else if(b.ownerDocument&&(f=b.ownerDocument.getElementById(j))&&h(b,f)&&f.id===j)return c.push(f),c}else{if(e[2])return w.apply(c,x.call(b.getElementsByTagName(a),0)),c;if((j=e[3])&&_&&b.getElementsByClassName)return w.apply(c,x.call(b.getElementsByClassName(j),0)),c}return bp(a.replace(L,"$1"),b,c,d,i)}function bd(a){return function(b){var c=b.nodeName.toLowerCase();return c==="input"&&b.type===a}}function be(a){return function(b){var c=b.nodeName.toLowerCase();return(c==="input"||c==="button")&&b.type===a}}function bf(a){return z(function(b){return b=+b,z(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function bg(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}function bh(a,b){var c,d,f,g,h,i,j,k=C[o][a];if(k)return b?0:k.slice(0);h=a,i=[],j=e.preFilter;while(h){if(!c||(d=M.exec(h)))d&&(h=h.slice(d[0].length)),i.push(f=[]);c=!1;if(d=N.exec(h))f.push(c=new q(d.shift())),h=h.slice(c.length),c.type=d[0].replace(L," ");for(g in e.filter)(d=W[g].exec(h))&&(!j[g]||(d=j[g](d,r,!0)))&&(f.push(c=new q(d.shift())),h=h.slice(c.length),c.type=g,c.matches=d);if(!c)break}return b?h.length:h?bc.error(a):C(a,i).slice(0)}function bi(a,b,d){var e=b.dir,f=d&&b.dir==="parentNode",g=u++;return b.first?function(b,c,d){while(b=b[e])if(f||b.nodeType===1)return a(b,c,d)}:function(b,d,h){if(!h){var i,j=t+" "+g+" ",k=j+c;while(b=b[e])if(f||b.nodeType===1){if((i=b[o])===k)return b.sizset;if(typeof i=="string"&&i.indexOf(j)===0){if(b.sizset)return b}else{b[o]=k;if(a(b,d,h))return b.sizset=!0,b;b.sizset=!1}}}else while(b=b[e])if(f||b.nodeType===1)if(a(b,d,h))return b}}function bj(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function bk(a,b,c,d,e){var f,g=[],h=0,i=a.length,j=b!=null;for(;h<i;h++)if(f=a[h])if(!c||c(f,d,e))g.push(f),j&&b.push(h);return g}function bl(a,b,c,d,e,f){return d&&!d[o]&&(d=bl(d)),e&&!e[o]&&(e=bl(e,f)),z(function(f,g,h,i){if(f&&e)return;var j,k,l,m=[],n=[],o=g.length,p=f||bo(b||"*",h.nodeType?[h]:h,[],f),q=a&&(f||!b)?bk(p,m,a,h,i):p,r=c?e||(f?a:o||d)?[]:g:q;c&&c(q,r,h,i);if(d){l=bk(r,n),d(l,[],h,i),j=l.length;while(j--)if(k=l[j])r[n[j]]=!(q[n[j]]=k)}if(f){j=a&&r.length;while(j--)if(k=r[j])f[m[j]]=!(g[m[j]]=k)}else r=bk(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):w.apply(g,r)})}function bm(a){var b,c,d,f=a.length,g=e.relative[a[0].type],h=g||e.relative[" "],i=g?1:0,j=bi(function(a){return a===b},h,!0),k=bi(function(a){return y.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==l)||((b=c).nodeType?j(a,c,d):k(a,c,d))}];for(;i<f;i++)if(c=e.relative[a[i].type])m=[bi(bj(m),c)];else{c=e.filter[a[i].type].apply(null,a[i].matches);if(c[o]){d=++i;for(;d<f;d++)if(e.relative[a[d].type])break;return bl(i>1&&bj(m),i>1&&a.slice(0,i-1).join("").replace(L,"$1"),c,i<d&&bm(a.slice(i,d)),d<f&&bm(a=a.slice(d)),d<f&&a.join(""))}m.push(c)}return bj(m)}function bn(a,b){var d=b.length>0,f=a.length>0,g=function(h,i,j,k,m){var n,o,p,q=[],s=0,u="0",x=h&&[],y=m!=null,z=l,A=h||f&&e.find.TAG("*",m&&i.parentNode||i),B=t+=z==null?1:Math.E;y&&(l=i!==r&&i,c=g.el);for(;(n=A[u])!=null;u++){if(f&&n){for(o=0;p=a[o];o++)if(p(n,i,j)){k.push(n);break}y&&(t=B,c=++g.el)}d&&((n=!p&&n)&&s--,h&&x.push(n))}s+=u;if(d&&u!==s){for(o=0;p=b[o];o++)p(x,q,i,j);if(h){if(s>0)while(u--)!x[u]&&!q[u]&&(q[u]=v.call(k));q=bk(q)}w.apply(k,q),y&&!h&&q.length>0&&s+b.length>1&&bc.uniqueSort(k)}return y&&(t=B,l=z),x};return g.el=0,d?z(g):g}function bo(a,b,c,d){var e=0,f=b.length;for(;e<f;e++)bc(a,b[e],c,d);return c}function bp(a,b,c,d,f){var g,h,j,k,l,m=bh(a),n=m.length;if(!d&&m.length===1){h=m[0]=m[0].slice(0);if(h.length>2&&(j=h[0]).type==="ID"&&b.nodeType===9&&!f&&e.relative[h[1].type]){b=e.find.ID(j.matches[0].replace(V,""),b,f)[0];if(!b)return c;a=a.slice(h.shift().length)}for(g=W.POS.test(a)?-1:h.length-1;g>=0;g--){j=h[g];if(e.relative[k=j.type])break;if(l=e.find[k])if(d=l(j.matches[0].replace(V,""),R.test(h[0].type)&&b.parentNode||b,f)){h.splice(g,1),a=d.length&&h.join("");if(!a)return w.apply(c,x.call(d,0)),c;break}}}return i(a,m)(d,b,f,c,R.test(a)),c}function bq(){}var c,d,e,f,g,h,i,j,k,l,m=!0,n="undefined",o=("sizcache"+Math.random()).replace(".",""),q=String,r=a.document,s=r.documentElement,t=0,u=0,v=[].pop,w=[].push,x=[].slice,y=[].indexOf||function(a){var b=0,c=this.length;for(;b<c;b++)if(this[b]===a)return b;return-1},z=function(a,b){return a[o]=b==null||b,a},A=function(){var a={},b=[];return z(function(c,d){return b.push(c)>e.cacheLength&&delete a[b.shift()],a[c]=d},a)},B=A(),C=A(),D=A(),E="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",G=F.replace("w","w#"),H="([*^$|!~]?=)",I="\\["+E+"*("+F+")"+E+"*(?:"+H+E+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+G+")|)|)"+E+"*\\]",J=":("+F+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+I+")|[^:]|\\\\.)*|.*))\\)|)",K=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+E+"*((?:-\\d)?\\d*)"+E+"*\\)|)(?=[^-]|$)",L=new RegExp("^"+E+"+|((?:^|[^\\\\])(?:\\\\.)*)"+E+"+$","g"),M=new RegExp("^"+E+"*,"+E+"*"),N=new RegExp("^"+E+"*([\\x20\\t\\r\\n\\f>+~])"+E+"*"),O=new RegExp(J),P=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,Q=/^:not/,R=/[\x20\t\r\n\f]*[+~]/,S=/:not\($/,T=/h\d/i,U=/input|select|textarea|button/i,V=/\\(?!\\)/g,W={ID:new RegExp("^#("+F+")"),CLASS:new RegExp("^\\.("+F+")"),NAME:new RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:new RegExp("^("+F.replace("w","w*")+")"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+J),POS:new RegExp(K,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+E+"*(even|odd|(([+-]|)(\\d*)n|)"+E+"*(?:([+-]|)"+E+"*(\\d+)|))"+E+"*\\)|)","i"),needsContext:new RegExp("^"+E+"*[>+~]|"+K,"i")},X=function(a){var b=r.createElement("div");try{return a(b)}catch(c){return!1}finally{b=null}},Y=X(function(a){return a.appendChild(r.createComment("")),!a.getElementsByTagName("*").length}),Z=X(function(a){return a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!==n&&a.firstChild.getAttribute("href")==="#"}),$=X(function(a){a.innerHTML="<select></select>";var b=typeof a.lastChild.getAttribute("multiple");return b!=="boolean"&&b!=="string"}),_=X(function(a){return a.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",!a.getElementsByClassName||!a.getElementsByClassName("e").length?!1:(a.lastChild.className="e",a.getElementsByClassName("e").length===2)}),ba=X(function(a){a.id=o+0,a.innerHTML="<a name='"+o+"'></a><div name='"+o+"'></div>",s.insertBefore(a,s.firstChild);var b=r.getElementsByName&&r.getElementsByName(o).length===2+r.getElementsByName(o+0).length;return d=!r.getElementById(o),s.removeChild(a),b});try{x.call(s.childNodes,0)[0].nodeType}catch(bb){x=function(a){var b,c=[];for(;b=this[a];a++)c.push(b);return c}}bc.matches=function(a,b){return bc(a,null,null,b)},bc.matchesSelector=function(a,b){return bc(b,null,null,[a]).length>0},f=bc.getText=function(a){var b,c="",d=0,e=a.nodeType;if(e){if(e===1||e===9||e===11){if(typeof a.textContent=="string")return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=f(a)}else if(e===3||e===4)return a.nodeValue}else for(;b=a[d];d++)c+=f(b);return c},g=bc.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?b.nodeName!=="HTML":!1},h=bc.contains=s.contains?function(a,b){var c=a.nodeType===9?a.documentElement:a,d=b&&b.parentNode;return a===d||!!(d&&d.nodeType===1&&c.contains&&c.contains(d))}:s.compareDocumentPosition?function(a,b){return b&&!!(a.compareDocumentPosition(b)&16)}:function(a,b){while(b=b.parentNode)if(b===a)return!0;return!1},bc.attr=function(a,b){var c,d=g(a);return d||(b=b.toLowerCase()),(c=e.attrHandle[b])?c(a):d||$?a.getAttribute(b):(c=a.getAttributeNode(b),c?typeof a[b]=="boolean"?a[b]?b:null:c.specified?c.value:null:null)},e=bc.selectors={cacheLength:50,createPseudo:z,match:W,attrHandle:Z?{}:{href:function(a){return a.getAttribute("href",2)},type:function(a){return a.getAttribute("type")}},find:{ID:d?function(a,b,c){if(typeof b.getElementById!==n&&!c){var d=b.getElementById(a);return d&&d.parentNode?[d]:[]}}:function(a,c,d){if(typeof c.getElementById!==n&&!d){var e=c.getElementById(a);return e?e.id===a||typeof e.getAttributeNode!==n&&e.getAttributeNode("id").value===a?[e]:b:[]}},TAG:Y?function(a,b){if(typeof b.getElementsByTagName!==n)return b.getElementsByTagName(a)}:function(a,b){var c=b.getElementsByTagName(a);if(a==="*"){var d,e=[],f=0;for(;d=c[f];f++)d.nodeType===1&&e.push(d);return e}return c},NAME:ba&&function(a,b){if(typeof b.getElementsByName!==n)return b.getElementsByName(name)},CLASS:_&&function(a,b,c){if(typeof b.getElementsByClassName!==n&&!c)return b.getElementsByClassName(a)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(V,""),a[3]=(a[4]||a[5]||"").replace(V,""),a[2]==="~="&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),a[1]==="nth"?(a[2]||bc.error(a[0]),a[3]=+(a[3]?a[4]+(a[5]||1):2*(a[2]==="even"||a[2]==="odd")),a[4]=+(a[6]+a[7]||a[2]==="odd")):a[2]&&bc.error(a[0]),a},PSEUDO:function(a){var b,c;if(W.CHILD.test(a[0]))return null;if(a[3])a[2]=a[3];else if(b=a[4])O.test(b)&&(c=bh(b,!0))&&(c=b.indexOf(")",b.length-c)-b.length)&&(b=b.slice(0,c),a[0]=a[0].slice(0,c)),a[2]=b;return a.slice(0,3)}},filter:{ID:d?function(a){return a=a.replace(V,""),function(b){return b.getAttribute("id")===a}}:function(a){return a=a.replace(V,""),function(b){var c=typeof b.getAttributeNode!==n&&b.getAttributeNode("id");return c&&c.value===a}},TAG:function(a){return a==="*"?function(){return!0}:(a=a.replace(V,"").toLowerCase(),function(b){return b.nodeName&&b.nodeName.toLowerCase()===a})},CLASS:function(a){var b=B[o][a];return b||(b=B(a,new RegExp("(^|"+E+")"+a+"("+E+"|$)"))),function(a){return b.test(a.className||typeof a.getAttribute!==n&&a.getAttribute("class")||"")}},ATTR:function(a,b,c){return function(d,e){var f=bc.attr(d,a);return f==null?b==="!=":b?(f+="",b==="="?f===c:b==="!="?f!==c:b==="^="?c&&f.indexOf(c)===0:b==="*="?c&&f.indexOf(c)>-1:b==="$="?c&&f.substr(f.length-c.length)===c:b==="~="?(" "+f+" ").indexOf(c)>-1:b==="|="?f===c||f.substr(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d){return a==="nth"?function(a){var b,e,f=a.parentNode;if(c===1&&d===0)return!0;if(f){e=0;for(b=f.firstChild;b;b=b.nextSibling)if(b.nodeType===1){e++;if(a===b)break}}return e-=d,e===c||e%c===0&&e/c>=0}:function(b){var c=b;switch(a){case"only":case"first":while(c=c.previousSibling)if(c.nodeType===1)return!1;if(a==="first")return!0;c=b;case"last":while(c=c.nextSibling)if(c.nodeType===1)return!1;return!0}}},PSEUDO:function(a,b){var c,d=e.pseudos[a]||e.setFilters[a.toLowerCase()]||bc.error("unsupported pseudo: "+a);return d[o]?d(b):d.length>1?(c=[a,a,"",b],e.setFilters.hasOwnProperty(a.toLowerCase())?z(function(a,c){var e,f=d(a,b),g=f.length;while(g--)e=y.call(a,f[g]),a[e]=!(c[e]=f[g])}):function(a){return d(a,0,c)}):d}},pseudos:{not:z(function(a){var b=[],c=[],d=i(a.replace(L,"$1"));return d[o]?z(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)if(f=g[h])a[h]=!(b[h]=f)}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:z(function(a){return function(b){return bc(a,b).length>0}}),contains:z(function(a){return function(b){return(b.textContent||b.innerText||f(b)).indexOf(a)>-1}}),enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&!!a.checked||b==="option"&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},parent:function(a){return!e.pseudos.empty(a)},empty:function(a){var b;a=a.firstChild;while(a){if(a.nodeName>"@"||(b=a.nodeType)===3||b===4)return!1;a=a.nextSibling}return!0},header:function(a){return T.test(a.nodeName)},text:function(a){var b,c;return a.nodeName.toLowerCase()==="input"&&(b=a.type)==="text"&&((c=a.getAttribute("type"))==null||c.toLowerCase()===b)},radio:bd("radio"),checkbox:bd("checkbox"),file:bd("file"),password:bd("password"),image:bd("image"),submit:be("submit"),reset:be("reset"),button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&a.type==="button"||b==="button"},input:function(a){return U.test(a.nodeName)},focus:function(a){var b=a.ownerDocument;return a===b.activeElement&&(!b.hasFocus||b.hasFocus())&&(!!a.type||!!a.href)},active:function(a){return a===a.ownerDocument.activeElement},first:bf(function(a,b,c){return[0]}),last:bf(function(a,b,c){return[b-1]}),eq:bf(function(a,b,c){return[c<0?c+b:c]}),even:bf(function(a,b,c){for(var d=0;d<b;d+=2)a.push(d);return a}),odd:bf(function(a,b,c){for(var d=1;d<b;d+=2)a.push(d);return a}),lt:bf(function(a,b,c){for(var d=c<0?c+b:c;--d>=0;)a.push(d);return a}),gt:bf(function(a,b,c){for(var d=c<0?c+b:c;++d<b;)a.push(d);return a})}},j=s.compareDocumentPosition?function(a,b){return a===b?(k=!0,0):(!a.compareDocumentPosition||!b.compareDocumentPosition?a.compareDocumentPosition:a.compareDocumentPosition(b)&4)?-1:1}:function(a,b){if(a===b)return k=!0,0;if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,h=b.parentNode,i=g;if(g===h)return bg(a,b);if(!g)return-1;if(!h)return 1;while(i)e.unshift(i),i=i.parentNode;i=h;while(i)f.unshift(i),i=i.parentNode;c=e.length,d=f.length;for(var j=0;j<c&&j<d;j++)if(e[j]!==f[j])return bg(e[j],f[j]);return j===c?bg(a,f[j],-1):bg(e[j],b,1)},[0,0].sort(j),m=!k,bc.uniqueSort=function(a){var b,c=1;k=m,a.sort(j);if(k)for(;b=a[c];c++)b===a[c-1]&&a.splice(c--,1);return a},bc.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},i=bc.compile=function(a,b){var c,d=[],e=[],f=D[o][a];if(!f){b||(b=bh(a)),c=b.length;while(c--)f=bm(b[c]),f[o]?d.push(f):e.push(f);f=D(a,bn(e,d))}return f},r.querySelectorAll&&function(){var a,b=bp,c=/'|\\/g,d=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,e=[":focus"],f=[":active",":focus"],h=s.matchesSelector||s.mozMatchesSelector||s.webkitMatchesSelector||s.oMatchesSelector||s.msMatchesSelector;X(function(a){a.innerHTML="<select><option selected=''></option></select>",a.querySelectorAll("[selected]").length||e.push("\\["+E+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),a.querySelectorAll(":checked").length||e.push(":checked")}),X(function(a){a.innerHTML="<p test=''></p>",a.querySelectorAll("[test^='']").length&&e.push("[*^$]="+E+"*(?:\"\"|'')"),a.innerHTML="<input type='hidden'/>",a.querySelectorAll(":enabled").length||e.push(":enabled",":disabled")}),e=new RegExp(e.join("|")),bp=function(a,d,f,g,h){if(!g&&!h&&(!e||!e.test(a))){var i,j,k=!0,l=o,m=d,n=d.nodeType===9&&a;if(d.nodeType===1&&d.nodeName.toLowerCase()!=="object"){i=bh(a),(k=d.getAttribute("id"))?l=k.replace(c,"\\$&"):d.setAttribute("id",l),l="[id='"+l+"'] ",j=i.length;while(j--)i[j]=l+i[j].join("");m=R.test(a)&&d.parentNode||d,n=i.join(",")}if(n)try{return w.apply(f,x.call(m.querySelectorAll(n),0)),f}catch(p){}finally{k||d.removeAttribute("id")}}return b(a,d,f,g,h)},h&&(X(function(b){a=h.call(b,"div");try{h.call(b,"[test!='']:sizzle"),f.push("!=",J)}catch(c){}}),f=new RegExp(f.join("|")),bc.matchesSelector=function(b,c){c=c.replace(d,"='$1']");if(!g(b)&&!f.test(c)&&(!e||!e.test(c)))try{var i=h.call(b,c);if(i||a||b.document&&b.document.nodeType!==11)return i}catch(j){}return bc(c,null,null,[b]).length>0})}(),e.pseudos.nth=e.pseudos.eq,e.filters=bq.prototype=e.pseudos,e.setFilters=new bq,bc.attr=p.attr,p.find=bc,p.expr=bc.selectors,p.expr[":"]=p.expr.pseudos,p.unique=bc.uniqueSort,p.text=bc.getText,p.isXMLDoc=bc.isXML,p.contains=bc.contains}(a);var bc=/Until$/,bd=/^(?:parents|prev(?:Until|All))/,be=/^.[^:#\[\.,]*$/,bf=p.expr.match.needsContext,bg={children:!0,contents:!0,next:!0,prev:!0};p.fn.extend({find:function(a){var b,c,d,e,f,g,h=this;if(typeof a!="string")return p(a).filter(function(){for(b=0,c=h.length;b<c;b++)if(p.contains(h[b],this))return!0});g=this.pushStack("","find",a);for(b=0,c=this.length;b<c;b++){d=g.length,p.find(a,this[b],g);if(b>0)for(e=d;e<g.length;e++)for(f=0;f<d;f++)if(g[f]===g[e]){g.splice(e--,1);break}}return g},has:function(a){var b,c=p(a,this),d=c.length;return this.filter(function(){for(b=0;b<d;b++)if(p.contains(this,c[b]))return!0})},not:function(a){return this.pushStack(bj(this,a,!1),"not",a)},filter:function(a){return this.pushStack(bj(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?bf.test(a)?p(a,this.context).index(this[0])>=0:p.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c,d=0,e=this.length,f=[],g=bf.test(a)||typeof a!="string"?p(a,b||this.context):0;for(;d<e;d++){c=this[d];while(c&&c.ownerDocument&&c!==b&&c.nodeType!==11){if(g?g.index(c)>-1:p.find.matchesSelector(c,a)){f.push(c);break}c=c.parentNode}}return f=f.length>1?p.unique(f):f,this.pushStack(f,"closest",a)},index:function(a){return a?typeof a=="string"?p.inArray(this[0],p(a)):p.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(a,b){var c=typeof a=="string"?p(a,b):p.makeArray(a&&a.nodeType?[a]:a),d=p.merge(this.get(),c);return this.pushStack(bh(c[0])||bh(d[0])?d:p.unique(d))},addBack:function(a){return this.add(a==null?this.prevObject:this.prevObject.filter(a))}}),p.fn.andSelf=p.fn.addBack,p.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return p.dir(a,"parentNode")},parentsUntil:function(a,b,c){return p.dir(a,"parentNode",c)},next:function(a){return bi(a,"nextSibling")},prev:function(a){return bi(a,"previousSibling")},nextAll:function(a){return p.dir(a,"nextSibling")},prevAll:function(a){return p.dir(a,"previousSibling")},nextUntil:function(a,b,c){return p.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return p.dir(a,"previousSibling",c)},siblings:function(a){return p.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return p.sibling(a.firstChild)},contents:function(a){return p.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:p.merge([],a.childNodes)}},function(a,b){p.fn[a]=function(c,d){var e=p.map(this,b,c);return bc.test(a)||(d=c),d&&typeof d=="string"&&(e=p.filter(d,e)),e=this.length>1&&!bg[a]?p.unique(e):e,this.length>1&&bd.test(a)&&(e=e.reverse()),this.pushStack(e,a,k.call(arguments).join(","))}}),p.extend({filter:function(a,b,c){return c&&(a=":not("+a+")"),b.length===1?p.find.matchesSelector(b[0],a)?[b[0]]:[]:p.find.matches(a,b)},dir:function(a,c,d){var e=[],f=a[c];while(f&&f.nodeType!==9&&(d===b||f.nodeType!==1||!p(f).is(d)))f.nodeType===1&&e.push(f),f=f[c];return e},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var bl="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",bm=/ jQuery\d+="(?:null|\d+)"/g,bn=/^\s+/,bo=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bp=/<([\w:]+)/,bq=/<tbody/i,br=/<|&#?\w+;/,bs=/<(?:script|style|link)/i,bt=/<(?:script|object|embed|option|style)/i,bu=new RegExp("<(?:"+bl+")[\\s/>]","i"),bv=/^(?:checkbox|radio)$/,bw=/checked\s*(?:[^=]|=\s*.checked.)/i,bx=/\/(java|ecma)script/i,by=/^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,bz={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},bA=bk(e),bB=bA.appendChild(e.createElement("div"));bz.optgroup=bz.option,bz.tbody=bz.tfoot=bz.colgroup=bz.caption=bz.thead,bz.th=bz.td,p.support.htmlSerialize||(bz._default=[1,"X<div>","</div>"]),p.fn.extend({text:function(a){return p.access(this,function(a){return a===b?p.text(this):this.empty().append((this[0]&&this[0].ownerDocument||e).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(p.isFunction(a))return this.each(function(b){p(this).wrapAll(a.call(this,b))});if(this[0]){var b=p(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return p.isFunction(a)?this.each(function(b){p(this).wrapInner(a.call(this,b))}):this.each(function(){var b=p(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=p.isFunction(a);return this.each(function(c){p(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){p.nodeName(this,"body")||p(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(a,this.firstChild)})},before:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(a,this),"before",this.selector)}},after:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(this,a),"after",this.selector)}},remove:function(a,b){var c,d=0;for(;(c=this[d])!=null;d++)if(!a||p.filter(a,[c]).length)!b&&c.nodeType===1&&(p.cleanData(c.getElementsByTagName("*")),p.cleanData([c])),c.parentNode&&c.parentNode.removeChild(c);return this},empty:function(){var a,b=0;for(;(a=this[b])!=null;b++){a.nodeType===1&&p.cleanData(a.getElementsByTagName("*"));while(a.firstChild)a.removeChild(a.firstChild)}return this},clone:function(a,b){return a=a==null?!1:a,b=b==null?a:b,this.map(function(){return p.clone(this,a,b)})},html:function(a){return p.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nodeType===1?c.innerHTML.replace(bm,""):b;if(typeof a=="string"&&!bs.test(a)&&(p.support.htmlSerialize||!bu.test(a))&&(p.support.leadingWhitespace||!bn.test(a))&&!bz[(bp.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(bo,"<$1></$2>");try{for(;d<e;d++)c=this[d]||{},c.nodeType===1&&(p.cleanData(c.getElementsByTagName("*")),c.innerHTML=a);c=0}catch(f){}}c&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(a){return bh(this[0])?this.length?this.pushStack(p(p.isFunction(a)?a():a),"replaceWith",a):this:p.isFunction(a)?this.each(function(b){var c=p(this),d=c.html();c.replaceWith(a.call(this,b,d))}):(typeof a!="string"&&(a=p(a).detach()),this.each(function(){var b=this.nextSibling,c=this.parentNode;p(this).remove(),b?p(b).before(a):p(c).append(a)}))},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){a=[].concat.apply([],a);var e,f,g,h,i=0,j=a[0],k=[],l=this.length;if(!p.support.checkClone&&l>1&&typeof j=="string"&&bw.test(j))return this.each(function(){p(this).domManip(a,c,d)});if(p.isFunction(j))return this.each(function(e){var f=p(this);a[0]=j.call(this,e,c?f.html():b),f.domManip(a,c,d)});if(this[0]){e=p.buildFragment(a,this,k),g=e.fragment,f=g.firstChild,g.childNodes.length===1&&(g=f);if(f){c=c&&p.nodeName(f,"tr");for(h=e.cacheable||l-1;i<l;i++)d.call(c&&p.nodeName(this[i],"table")?bC(this[i],"tbody"):this[i],i===h?g:p.clone(g,!0,!0))}g=f=null,k.length&&p.each(k,function(a,b){b.src?p.ajax?p.ajax({url:b.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):p.error("no ajax"):p.globalEval((b.text||b.textContent||b.innerHTML||"").replace(by,"")),b.parentNode&&b.parentNode.removeChild(b)})}return this}}),p.buildFragment=function(a,c,d){var f,g,h,i=a[0];return c=c||e,c=!c.nodeType&&c[0]||c,c=c.ownerDocument||c,a.length===1&&typeof i=="string"&&i.length<512&&c===e&&i.charAt(0)==="<"&&!bt.test(i)&&(p.support.checkClone||!bw.test(i))&&(p.support.html5Clone||!bu.test(i))&&(g=!0,f=p.fragments[i],h=f!==b),f||(f=c.createDocumentFragment(),p.clean(a,c,f,d),g&&(p.fragments[i]=h&&f)),{fragment:f,cacheable:g}},p.fragments={},p.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){p.fn[a]=function(c){var d,e=0,f=[],g=p(c),h=g.length,i=this.length===1&&this[0].parentNode;if((i==null||i&&i.nodeType===11&&i.childNodes.length===1)&&h===1)return g[b](this[0]),this;for(;e<h;e++)d=(e>0?this.clone(!0):this).get(),p(g[e])[b](d),f=f.concat(d);return this.pushStack(f,a,g.selector)}}),p.extend({clone:function(a,b,c){var d,e,f,g;p.support.html5Clone||p.isXMLDoc(a)||!bu.test("<"+a.nodeName+">")?g=a.cloneNode(!0):(bB.innerHTML=a.outerHTML,bB.removeChild(g=bB.firstChild));if((!p.support.noCloneEvent||!p.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!p.isXMLDoc(a)){bE(a,g),d=bF(a),e=bF(g);for(f=0;d[f];++f)e[f]&&bE(d[f],e[f])}if(b){bD(a,g);if(c){d=bF(a),e=bF(g);for(f=0;d[f];++f)bD(d[f],e[f])}}return d=e=null,g},clean:function(a,b,c,d){var f,g,h,i,j,k,l,m,n,o,q,r,s=b===e&&bA,t=[];if(!b||typeof b.createDocumentFragment=="undefined")b=e;for(f=0;(h=a[f])!=null;f++){typeof h=="number"&&(h+="");if(!h)continue;if(typeof h=="string")if(!br.test(h))h=b.createTextNode(h);else{s=s||bk(b),l=b.createElement("div"),s.appendChild(l),h=h.replace(bo,"<$1></$2>"),i=(bp.exec(h)||["",""])[1].toLowerCase(),j=bz[i]||bz._default,k=j[0],l.innerHTML=j[1]+h+j[2];while(k--)l=l.lastChild;if(!p.support.tbody){m=bq.test(h),n=i==="table"&&!m?l.firstChild&&l.firstChild.childNodes:j[1]==="<table>"&&!m?l.childNodes:[];for(g=n.length-1;g>=0;--g)p.nodeName(n[g],"tbody")&&!n[g].childNodes.length&&n[g].parentNode.removeChild(n[g])}!p.support.leadingWhitespace&&bn.test(h)&&l.insertBefore(b.createTextNode(bn.exec(h)[0]),l.firstChild),h=l.childNodes,l.parentNode.removeChild(l)}h.nodeType?t.push(h):p.merge(t,h)}l&&(h=l=s=null);if(!p.support.appendChecked)for(f=0;(h=t[f])!=null;f++)p.nodeName(h,"input")?bG(h):typeof h.getElementsByTagName!="undefined"&&p.grep(h.getElementsByTagName("input"),bG);if(c){q=function(a){if(!a.type||bx.test(a.type))return d?d.push(a.parentNode?a.parentNode.removeChild(a):a):c.appendChild(a)};for(f=0;(h=t[f])!=null;f++)if(!p.nodeName(h,"script")||!q(h))c.appendChild(h),typeof h.getElementsByTagName!="undefined"&&(r=p.grep(p.merge([],h.getElementsByTagName("script")),q),t.splice.apply(t,[f+1,0].concat(r)),f+=r.length)}return t},cleanData:function(a,b){var c,d,e,f,g=0,h=p.expando,i=p.cache,j=p.support.deleteExpando,k=p.event.special;for(;(e=a[g])!=null;g++)if(b||p.acceptData(e)){d=e[h],c=d&&i[d];if(c){if(c.events)for(f in c.events)k[f]?p.event.remove(e,f):p.removeEvent(e,f,c.handle);i[d]&&(delete i[d],j?delete e[h]:e.removeAttribute?e.removeAttribute(h):e[h]=null,p.deletedIds.push(d))}}}}),function(){var a,b;p.uaMatch=function(a){a=a.toLowerCase();var b=/(chrome)[ \/]([\w.]+)/.exec(a)||/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||a.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},a=p.uaMatch(g.userAgent),b={},a.browser&&(b[a.browser]=!0,b.version=a.version),b.chrome?b.webkit=!0:b.webkit&&(b.safari=!0),p.browser=b,p.sub=function(){function a(b,c){return new a.fn.init(b,c)}p.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function c(c,d){return d&&d instanceof p&&!(d instanceof a)&&(d=a(d)),p.fn.init.call(this,c,d,b)},a.fn.init.prototype=a.fn;var b=a(e);return a}}();var bH,bI,bJ,bK=/alpha\([^)]*\)/i,bL=/opacity=([^)]*)/,bM=/^(top|right|bottom|left)$/,bN=/^(none|table(?!-c[ea]).+)/,bO=/^margin/,bP=new RegExp("^("+q+")(.*)$","i"),bQ=new RegExp("^("+q+")(?!px)[a-z%]+$","i"),bR=new RegExp("^([-+])=("+q+")","i"),bS={},bT={position:"absolute",visibility:"hidden",display:"block"},bU={letterSpacing:0,fontWeight:400},bV=["Top","Right","Bottom","Left"],bW=["Webkit","O","Moz","ms"],bX=p.fn.toggle;p.fn.extend({css:function(a,c){return p.access(this,function(a,c,d){return d!==b?p.style(a,c,d):p.css(a,c)},a,c,arguments.length>1)},show:function(){return b$(this,!0)},hide:function(){return b$(this)},toggle:function(a,b){var c=typeof a=="boolean";return p.isFunction(a)&&p.isFunction(b)?bX.apply(this,arguments):this.each(function(){(c?a:bZ(this))?p(this).show():p(this).hide()})}}),p.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bH(a,"opacity");return c===""?"1":c}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":p.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!a||a.nodeType===3||a.nodeType===8||!a.style)return;var f,g,h,i=p.camelCase(c),j=a.style;c=p.cssProps[i]||(p.cssProps[i]=bY(j,i)),h=p.cssHooks[c]||p.cssHooks[i];if(d===b)return h&&"get"in h&&(f=h.get(a,!1,e))!==b?f:j[c];g=typeof d,g==="string"&&(f=bR.exec(d))&&(d=(f[1]+1)*f[2]+parseFloat(p.css(a,c)),g="number");if(d==null||g==="number"&&isNaN(d))return;g==="number"&&!p.cssNumber[i]&&(d+="px");if(!h||!("set"in h)||(d=h.set(a,d,e))!==b)try{j[c]=d}catch(k){}},css:function(a,c,d,e){var f,g,h,i=p.camelCase(c);return c=p.cssProps[i]||(p.cssProps[i]=bY(a.style,i)),h=p.cssHooks[c]||p.cssHooks[i],h&&"get"in h&&(f=h.get(a,!0,e)),f===b&&(f=bH(a,c)),f==="normal"&&c in bU&&(f=bU[c]),d||e!==b?(g=parseFloat(f),d||p.isNumeric(g)?g||0:f):f},swap:function(a,b,c){var d,e,f={};for(e in b)f[e]=a.style[e],a.style[e]=b[e];d=c.call(a);for(e in b)a.style[e]=f[e];return d}}),a.getComputedStyle?bH=function(b,c){var d,e,f,g,h=a.getComputedStyle(b,null),i=b.style;return h&&(d=h[c],d===""&&!p.contains(b.ownerDocument,b)&&(d=p.style(b,c)),bQ.test(d)&&bO.test(c)&&(e=i.width,f=i.minWidth,g=i.maxWidth,i.minWidth=i.maxWidth=i.width=d,d=h.width,i.width=e,i.minWidth=f,i.maxWidth=g)),d}:e.documentElement.currentStyle&&(bH=function(a,b){var c,d,e=a.currentStyle&&a.currentStyle[b],f=a.style;return e==null&&f&&f[b]&&(e=f[b]),bQ.test(e)&&!bM.test(b)&&(c=f.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":e,e=f.pixelLeft+"px",f.left=c,d&&(a.runtimeStyle.left=d)),e===""?"auto":e}),p.each(["height","width"],function(a,b){p.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth===0&&bN.test(bH(a,"display"))?p.swap(a,bT,function(){return cb(a,b,d)}):cb(a,b,d)},set:function(a,c,d){return b_(a,c,d?ca(a,b,d,p.support.boxSizing&&p.css(a,"boxSizing")==="border-box"):0)}}}),p.support.opacity||(p.cssHooks.opacity={get:function(a,b){return bL.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=p.isNumeric(b)?"alpha(opacity="+b*100+")":"",f=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&p.trim(f.replace(bK,""))===""&&c.removeAttribute){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bK.test(f)?f.replace(bK,e):f+" "+e}}),p(function(){p.support.reliableMarginRight||(p.cssHooks.marginRight={get:function(a,b){return p.swap(a,{display:"inline-block"},function(){if(b)return bH(a,"marginRight")})}}),!p.support.pixelPosition&&p.fn.position&&p.each(["top","left"],function(a,b){p.cssHooks[b]={get:function(a,c){if(c){var d=bH(a,b);return bQ.test(d)?p(a).position()[b]+"px":d}}}})}),p.expr&&p.expr.filters&&(p.expr.filters.hidden=function(a){return a.offsetWidth===0&&a.offsetHeight===0||!p.support.reliableHiddenOffsets&&(a.style&&a.style.display||bH(a,"display"))==="none"},p.expr.filters.visible=function(a){return!p.expr.filters.hidden(a)}),p.each({margin:"",padding:"",border:"Width"},function(a,b){p.cssHooks[a+b]={expand:function(c){var d,e=typeof c=="string"?c.split(" "):[c],f={};for(d=0;d<4;d++)f[a+bV[d]+b]=e[d]||e[d-2]||e[0];return f}},bO.test(a)||(p.cssHooks[a+b].set=b_)});var cd=/%20/g,ce=/\[\]$/,cf=/\r?\n/g,cg=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,ch=/^(?:select|textarea)/i;p.fn.extend({serialize:function(){return p.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?p.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ch.test(this.nodeName)||cg.test(this.type))}).map(function(a,b){var c=p(this).val();return c==null?null:p.isArray(c)?p.map(c,function(a,c){return{name:b.name,value:a.replace(cf,"\r\n")}}):{name:b.name,value:c.replace(cf,"\r\n")}}).get()}}),p.param=function(a,c){var d,e=[],f=function(a,b){b=p.isFunction(b)?b():b==null?"":b,e[e.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=p.ajaxSettings&&p.ajaxSettings.traditional);if(p.isArray(a)||a.jquery&&!p.isPlainObject(a))p.each(a,function(){f(this.name,this.value)});else for(d in a)ci(d,a[d],c,f);return e.join("&").replace(cd,"+")};var cj,ck,cl=/#.*$/,cm=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,cn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,co=/^(?:GET|HEAD)$/,cp=/^\/\//,cq=/\?/,cr=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,cs=/([?&])_=[^&]*/,ct=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,cu=p.fn.load,cv={},cw={},cx=["*/"]+["*"];try{ck=f.href}catch(cy){ck=e.createElement("a"),ck.href="",ck=ck.href}cj=ct.exec(ck.toLowerCase())||[],p.fn.load=function(a,c,d){if(typeof a!="string"&&cu)return cu.apply(this,arguments);if(!this.length)return this;var e,f,g,h=this,i=a.indexOf(" ");return i>=0&&(e=a.slice(i,a.length),a=a.slice(0,i)),p.isFunction(c)?(d=c,c=b):c&&typeof c=="object"&&(f="POST"),p.ajax({url:a,type:f,dataType:"html",data:c,complete:function(a,b){d&&h.each(d,g||[a.responseText,b,a])}}).done(function(a){g=arguments,h.html(e?p("<div>").append(a.replace(cr,"")).find(e):a)}),this},p.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){p.fn[b]=function(a){return this.on(b,a)}}),p.each(["get","post"],function(a,c){p[c]=function(a,d,e,f){return p.isFunction(d)&&(f=f||e,e=d,d=b),p.ajax({type:c,url:a,data:d,success:e,dataType:f})}}),p.extend({getScript:function(a,c){return p.get(a,b,c,"script")},getJSON:function(a,b,c){return p.get(a,b,c,"json")},ajaxSetup:function(a,b){return b?cB(a,p.ajaxSettings):(b=a,a=p.ajaxSettings),cB(a,b),a},ajaxSettings:{url:ck,isLocal:cn.test(cj[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":cx},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":p.parseJSON,"text xml":p.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:cz(cv),ajaxTransport:cz(cw),ajax:function(a,c){function y(a,c,f,i){var k,s,t,u,w,y=c;if(v===2)return;v=2,h&&clearTimeout(h),g=b,e=i||"",x.readyState=a>0?4:0,f&&(u=cC(l,x,f));if(a>=200&&a<300||a===304)l.ifModified&&(w=x.getResponseHeader("Last-Modified"),w&&(p.lastModified[d]=w),w=x.getResponseHeader("Etag"),w&&(p.etag[d]=w)),a===304?(y="notmodified",k=!0):(k=cD(l,u),y=k.state,s=k.data,t=k.error,k=!t);else{t=y;if(!y||a)y="error",a<0&&(a=0)}x.status=a,x.statusText=(c||y)+"",k?o.resolveWith(m,[s,y,x]):o.rejectWith(m,[x,y,t]),x.statusCode(r),r=b,j&&n.trigger("ajax"+(k?"Success":"Error"),[x,l,k?s:t]),q.fireWith(m,[x,y]),j&&(n.trigger("ajaxComplete",[x,l]),--p.active||p.event.trigger("ajaxStop"))}typeof a=="object"&&(c=a,a=b),c=c||{};var d,e,f,g,h,i,j,k,l=p.ajaxSetup({},c),m=l.context||l,n=m!==l&&(m.nodeType||m instanceof p)?p(m):p.event,o=p.Deferred(),q=p.Callbacks("once memory"),r=l.statusCode||{},t={},u={},v=0,w="canceled",x={readyState:0,setRequestHeader:function(a,b){if(!v){var c=a.toLowerCase();a=u[c]=u[c]||a,t[a]=b}return this},getAllResponseHeaders:function(){return v===2?e:null},getResponseHeader:function(a){var c;if(v===2){if(!f){f={};while(c=cm.exec(e))f[c[1].toLowerCase()]=c[2]}c=f[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){return v||(l.mimeType=a),this},abort:function(a){return a=a||w,g&&g.abort(a),y(0,a),this}};o.promise(x),x.success=x.done,x.error=x.fail,x.complete=q.add,x.statusCode=function(a){if(a){var b;if(v<2)for(b in a)r[b]=[r[b],a[b]];else b=a[x.status],x.always(b)}return this},l.url=((a||l.url)+"").replace(cl,"").replace(cp,cj[1]+"//"),l.dataTypes=p.trim(l.dataType||"*").toLowerCase().split(s),l.crossDomain==null&&(i=ct.exec(l.url.toLowerCase())||!1,l.crossDomain=i&&i.join(":")+(i[3]?"":i[1]==="http:"?80:443)!==cj.join(":")+(cj[3]?"":cj[1]==="http:"?80:443)),l.data&&l.processData&&typeof l.data!="string"&&(l.data=p.param(l.data,l.traditional)),cA(cv,l,c,x);if(v===2)return x;j=l.global,l.type=l.type.toUpperCase(),l.hasContent=!co.test(l.type),j&&p.active++===0&&p.event.trigger("ajaxStart");if(!l.hasContent){l.data&&(l.url+=(cq.test(l.url)?"&":"?")+l.data,delete l.data),d=l.url;if(l.cache===!1){var z=p.now(),A=l.url.replace(cs,"$1_="+z);l.url=A+(A===l.url?(cq.test(l.url)?"&":"?")+"_="+z:"")}}(l.data&&l.hasContent&&l.contentType!==!1||c.contentType)&&x.setRequestHeader("Content-Type",l.contentType),l.ifModified&&(d=d||l.url,p.lastModified[d]&&x.setRequestHeader("If-Modified-Since",p.lastModified[d]),p.etag[d]&&x.setRequestHeader("If-None-Match",p.etag[d])),x.setRequestHeader("Accept",l.dataTypes[0]&&l.accepts[l.dataTypes[0]]?l.accepts[l.dataTypes[0]]+(l.dataTypes[0]!=="*"?", "+cx+"; q=0.01":""):l.accepts["*"]);for(k in l.headers)x.setRequestHeader(k,l.headers[k]);if(!l.beforeSend||l.beforeSend.call(m,x,l)!==!1&&v!==2){w="abort";for(k in{success:1,error:1,complete:1})x[k](l[k]);g=cA(cw,l,c,x);if(!g)y(-1,"No Transport");else{x.readyState=1,j&&n.trigger("ajaxSend",[x,l]),l.async&&l.timeout>0&&(h=setTimeout(function(){x.abort("timeout")},l.timeout));try{v=1,g.send(t,y)}catch(B){if(v<2)y(-1,B);else throw B}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var cE=[],cF=/\?/,cG=/(=)\?(?=&|$)|\?\?/,cH=p.now();p.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=cE.pop()||p.expando+"_"+cH++;return this[a]=!0,a}}),p.ajaxPrefilter("json jsonp",function(c,d,e){var f,g,h,i=c.data,j=c.url,k=c.jsonp!==!1,l=k&&cG.test(j),m=k&&!l&&typeof i=="string"&&!(c.contentType||"").indexOf("application/x-www-form-urlencoded")&&cG.test(i);if(c.dataTypes[0]==="jsonp"||l||m)return f=c.jsonpCallback=p.isFunction(c.jsonpCallback)?c.jsonpCallback():c.jsonpCallback,g=a[f],l?c.url=j.replace(cG,"$1"+f):m?c.data=i.replace(cG,"$1"+f):k&&(c.url+=(cF.test(j)?"&":"?")+c.jsonp+"="+f),c.converters["script json"]=function(){return h||p.error(f+" was not called"),h[0]},c.dataTypes[0]="json",a[f]=function(){h=arguments},e.always(function(){a[f]=g,c[f]&&(c.jsonpCallback=d.jsonpCallback,cE.push(f)),h&&p.isFunction(g)&&g(h[0]),h=g=b}),"script"}),p.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){return p.globalEval(a),a}}}),p.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),p.ajaxTransport("script",function(a){if(a.crossDomain){var c,d=e.head||e.getElementsByTagName("head")[0]||e.documentElement;return{send:function(f,g){c=e.createElement("script"),c.async="async",a.scriptCharset&&(c.charset=a.scriptCharset),c.src=a.url,c.onload=c.onreadystatechange=function(a,e){if(e||!c.readyState||/loaded|complete/.test(c.readyState))c.onload=c.onreadystatechange=null,d&&c.parentNode&&d.removeChild(c),c=b,e||g(200,"success")},d.insertBefore(c,d.firstChild)},abort:function(){c&&c.onload(0,1)}}}});var cI,cJ=a.ActiveXObject?function(){for(var a in cI)cI[a](0,1)}:!1,cK=0;p.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&cL()||cM()}:cL,function(a){p.extend(p.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(p.ajaxSettings.xhr()),p.support.ajax&&p.ajaxTransport(function(c){if(!c.crossDomain||p.support.cors){var d;return{send:function(e,f){var g,h,i=c.xhr();c.username?i.open(c.type,c.url,c.async,c.username,c.password):i.open(c.type,c.url,c.async);if(c.xhrFields)for(h in c.xhrFields)i[h]=c.xhrFields[h];c.mimeType&&i.overrideMimeType&&i.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(h in e)i.setRequestHeader(h,e[h])}catch(j){}i.send(c.hasContent&&c.data||null),d=function(a,e){var h,j,k,l,m;try{if(d&&(e||i.readyState===4)){d=b,g&&(i.onreadystatechange=p.noop,cJ&&delete cI[g]);if(e)i.readyState!==4&&i.abort();else{h=i.status,k=i.getAllResponseHeaders(),l={},m=i.responseXML,m&&m.documentElement&&(l.xml=m);try{l.text=i.responseText}catch(a){}try{j=i.statusText}catch(n){j=""}!h&&c.isLocal&&!c.crossDomain?h=l.text?200:404:h===1223&&(h=204)}}}catch(o){e||f(-1,o)}l&&f(h,j,l,k)},c.async?i.readyState===4?setTimeout(d,0):(g=++cK,cJ&&(cI||(cI={},p(a).unload(cJ)),cI[g]=d),i.onreadystatechange=d):d()},abort:function(){d&&d(0,1)}}}});var cN,cO,cP=/^(?:toggle|show|hide)$/,cQ=new RegExp("^(?:([-+])=|)("+q+")([a-z%]*)$","i"),cR=/queueHooks$/,cS=[cY],cT={"*":[function(a,b){var c,d,e=this.createTween(a,b),f=cQ.exec(b),g=e.cur(),h=+g||0,i=1,j=20;if(f){c=+f[2],d=f[3]||(p.cssNumber[a]?"":"px");if(d!=="px"&&h){h=p.css(e.elem,a,!0)||c||1;do i=i||".5",h=h/i,p.style(e.elem,a,h+d);while(i!==(i=e.cur()/g)&&i!==1&&--j)}e.unit=d,e.start=h,e.end=f[1]?h+(f[1]+1)*c:c}return e}]};p.Animation=p.extend(cW,{tweener:function(a,b){p.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");var c,d=0,e=a.length;for(;d<e;d++)c=a[d],cT[c]=cT[c]||[],cT[c].unshift(b)},prefilter:function(a,b){b?cS.unshift(a):cS.push(a)}}),p.Tween=cZ,cZ.prototype={constructor:cZ,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(p.cssNumber[c]?"":"px")},cur:function(){var a=cZ.propHooks[this.prop];return a&&a.get?a.get(this):cZ.propHooks._default.get(this)},run:function(a){var b,c=cZ.propHooks[this.prop];return this.options.duration?this.pos=b=p.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):cZ.propHooks._default.set(this),this}},cZ.prototype.init.prototype=cZ.prototype,cZ.propHooks={_default:{get:function(a){var b;return a.elem[a.prop]==null||!!a.elem.style&&a.elem.style[a.prop]!=null?(b=p.css(a.elem,a.prop,!1,""),!b||b==="auto"?0:b):a.elem[a.prop]},set:function(a){p.fx.step[a.prop]?p.fx.step[a.prop](a):a.elem.style&&(a.elem.style[p.cssProps[a.prop]]!=null||p.cssHooks[a.prop])?p.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},cZ.propHooks.scrollTop=cZ.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},p.each(["toggle","show","hide"],function(a,b){var c=p.fn[b];p.fn[b]=function(d,e,f){return d==null||typeof d=="boolean"||!a&&p.isFunction(d)&&p.isFunction(e)?c.apply(this,arguments):this.animate(c$(b,!0),d,e,f)}}),p.fn.extend({fadeTo:function(a,b,c,d){return this.filter(bZ).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=p.isEmptyObject(a),f=p.speed(b,c,d),g=function(){var b=cW(this,p.extend({},a),f);e&&b.stop(!0)};return e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,c,d){var e=function(a){var b=a.stop;delete a.stop,b(d)};return typeof a!="string"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,c=a!=null&&a+"queueHooks",f=p.timers,g=p._data(this);if(c)g[c]&&g[c].stop&&e(g[c]);else for(c in g)g[c]&&g[c].stop&&cR.test(c)&&e(g[c]);for(c=f.length;c--;)f[c].elem===this&&(a==null||f[c].queue===a)&&(f[c].anim.stop(d),b=!1,f.splice(c,1));(b||!d)&&p.dequeue(this,a)})}}),p.each({slideDown:c$("show"),slideUp:c$("hide"),slideToggle:c$("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){p.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),p.speed=function(a,b,c){var d=a&&typeof a=="object"?p.extend({},a):{complete:c||!c&&b||p.isFunction(a)&&a,duration:a,easing:c&&b||b&&!p.isFunction(b)&&b};d.duration=p.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in p.fx.speeds?p.fx.speeds[d.duration]:p.fx.speeds._default;if(d.queue==null||d.queue===!0)d.queue="fx";return d.old=d.complete,d.complete=function(){p.isFunction(d.old)&&d.old.call(this),d.queue&&p.dequeue(this,d.queue)},d},p.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},p.timers=[],p.fx=cZ.prototype.init,p.fx.tick=function(){var a,b=p.timers,c=0;for(;c<b.length;c++)a=b[c],!a()&&b[c]===a&&b.splice(c--,1);b.length||p.fx.stop()},p.fx.timer=function(a){a()&&p.timers.push(a)&&!cO&&(cO=setInterval(p.fx.tick,p.fx.interval))},p.fx.interval=13,p.fx.stop=function(){clearInterval(cO),cO=null},p.fx.speeds={slow:600,fast:200,_default:400},p.fx.step={},p.expr&&p.expr.filters&&(p.expr.filters.animated=function(a){return p.grep(p.timers,function(b){return a===b.elem}).length});var c_=/^(?:body|html)$/i;p.fn.offset=function(a){if(arguments.length)return a===b?this:this.each(function(b){p.offset.setOffset(this,a,b)});var c,d,e,f,g,h,i,j={top:0,left:0},k=this[0],l=k&&k.ownerDocument;if(!l)return;return(d=l.body)===k?p.offset.bodyOffset(k):(c=l.documentElement,p.contains(c,k)?(typeof k.getBoundingClientRect!="undefined"&&(j=k.getBoundingClientRect()),e=da(l),f=c.clientTop||d.clientTop||0,g=c.clientLeft||d.clientLeft||0,h=e.pageYOffset||c.scrollTop,i=e.pageXOffset||c.scrollLeft,{top:j.top+h-f,left:j.left+i-g}):j)},p.offset={bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;return p.support.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(p.css(a,"marginTop"))||0,c+=parseFloat(p.css(a,"marginLeft"))||0),{top:b,left:c}},setOffset:function(a,b,c){var d=p.css(a,"position");d==="static"&&(a.style.position="relative");var e=p(a),f=e.offset(),g=p.css(a,"top"),h=p.css(a,"left"),i=(d==="absolute"||d==="fixed")&&p.inArray("auto",[g,h])>-1,j={},k={},l,m;i?(k=e.position(),l=k.top,m=k.left):(l=parseFloat(g)||0,m=parseFloat(h)||0),p.isFunction(b)&&(b=b.call(a,c,f)),b.top!=null&&(j.top=b.top-f.top+l),b.left!=null&&(j.left=b.left-f.left+m),"using"in b?b.using.call(a,j):e.css(j)}},p.fn.extend({position:function(){if(!this[0])return;var a=this[0],b=this.offsetParent(),c=this.offset(),d=c_.test(b[0].nodeName)?{top:0,left:0}:b.offset();return c.top-=parseFloat(p.css(a,"marginTop"))||0,c.left-=parseFloat(p.css(a,"marginLeft"))||0,d.top+=parseFloat(p.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(p.css(b[0],"borderLeftWidth"))||0,{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||e.body;while(a&&!c_.test(a.nodeName)&&p.css(a,"position")==="static")a=a.offsetParent;return a||e.body})}}),p.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,c){var d=/Y/.test(c);p.fn[a]=function(e){return p.access(this,function(a,e,f){var g=da(a);if(f===b)return g?c in g?g[c]:g.document.documentElement[e]:a[e];g?g.scrollTo(d?p(g).scrollLeft():f,d?f:p(g).scrollTop()):a[e]=f},a,e,arguments.length,null)}}),p.each({Height:"height",Width:"width"},function(a,c){p.each({padding:"inner"+a,content:c,"":"outer"+a},function(d,e){p.fn[e]=function(e,f){var g=arguments.length&&(d||typeof e!="boolean"),h=d||(e===!0||f===!0?"margin":"border");return p.access(this,function(c,d,e){var f;return p.isWindow(c)?c.document.documentElement["client"+a]:c.nodeType===9?(f=c.documentElement,Math.max(c.body["scroll"+a],f["scroll"+a],c.body["offset"+a],f["offset"+a],f["client"+a])):e===b?p.css(c,d,e,h):p.style(c,d,e,h)},c,g?e:b,g,null)}})}),a.jQuery=a.$=p,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return p})})(window);
diff --git a/addons/webinterface.default/js/jquery.lazyload.js b/addons/webinterface.default/js/jquery.lazyload.js
deleted file mode 100644 (file)
index 9e350c9..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Lazy Load - jQuery plugin for lazy loading images
- *
- * Copyright (c) 2007-2009 Mika Tuupola
- *
- * Licensed under the MIT license:
- *   http://www.opensource.org/licenses/mit-license.php
- *
- * Project home:
- *   http://www.appelsiini.net/projects/lazyload
- *
- * Version:  1.5.0
- *
- */
-
-(function($) {
-
-    $.fn.lazyload = function(options) {
-        var settings = {
-            threshold    : 0,
-            failurelimit : 0,
-            event        : "scroll",
-            effect       : "show",
-            container    : window
-        };
-                
-        if(options) {
-            $.extend(settings, options);
-        }
-
-        /* Fire one scroll event per scroll. Not one scroll event per image. */
-        var elements = this;
-        if ("scroll" == settings.event) {
-            $(settings.container).bind("scroll", function(event) {
-                
-                var counter = 0;
-                elements.each(function() {
-                    if ($.abovethetop(this, settings) ||
-                        $.leftofbegin(this, settings)) {
-                            /* Nothing. */
-                    } else if (!$.belowthefold(this, settings) &&
-                        !$.rightoffold(this, settings)) {
-                            $(this).trigger("appear");
-                    } else {
-                        if (counter++ > settings.failurelimit) {
-                            return false;
-                        }
-                    }
-                });
-                /* Remove image from array so it is not looped next time. */
-                var temp = $.grep(elements, function(element) {
-                    return !element.loaded;
-                });
-                elements = $(temp);
-            });
-        }
-        
-        this.each(function() {
-            var self = this;
-            
-            /* Save original only if it is not defined in HTML. */
-            if (undefined == $(self).attr("original")) {
-                $(self).attr("original", $(self).attr("src"));     
-            }
-
-            if ("scroll" != settings.event || 
-                    undefined == $(self).attr("src") || 
-                    settings.placeholder == $(self).attr("src") || 
-                    ($.abovethetop(self, settings) ||
-                     $.leftofbegin(self, settings) || 
-                     $.belowthefold(self, settings) || 
-                     $.rightoffold(self, settings) )) {
-                        
-                if (settings.placeholder) {
-                    $(self).attr("src", settings.placeholder);      
-                } else {
-                    $(self).removeAttr("src");
-                }
-                self.loaded = false;
-            } else {
-                self.loaded = true;
-            }
-            
-            /* When appear is triggered load original image. */
-            $(self).one("appear", function() {
-                if (!this.loaded) {
-                    $("<img />")
-                        .bind("load", function() {
-                            $(self)
-                                .hide()
-                                .attr("src", $(self).attr("original"))
-                                [settings.effect](settings.effectspeed);
-                            self.loaded = true;
-                        })
-                        .attr("src", $(self).attr("original"));
-                };
-            });
-
-            /* When wanted event is triggered load original image */
-            /* by triggering appear.                              */
-            if ("scroll" != settings.event) {
-                $(self).bind(settings.event, function(event) {
-                    if (!self.loaded) {
-                        $(self).trigger("appear");
-                    }
-                });
-            }
-        });
-        
-        /* Force initial check if images should appear. */
-        $(settings.container).trigger(settings.event);
-        
-        return this;
-
-    };
-
-    /* Convenience methods in jQuery namespace.           */
-    /* Use as  $.belowthefold(element, {threshold : 100, container : window}) */
-
-    $.belowthefold = function(element, settings) {
-        if (settings.container === undefined || settings.container === window) {
-            var fold = $(window).height() + $(window).scrollTop();
-        } else {
-            var fold = $(settings.container).offset().top + $(settings.container).height();
-        }
-        return fold <= $(element).offset().top - settings.threshold;
-    };
-    
-    $.rightoffold = function(element, settings) {
-        if (settings.container === undefined || settings.container === window) {
-            var fold = $(window).width() + $(window).scrollLeft();
-        } else {
-            var fold = $(settings.container).offset().left + $(settings.container).width();
-        }
-        return fold <= $(element).offset().left - settings.threshold;
-    };
-        
-    $.abovethetop = function(element, settings) {
-        if (settings.container === undefined || settings.container === window) {
-            var fold = $(window).scrollTop();
-        } else {
-            var fold = $(settings.container).offset().top;
-        }
-        return fold >= $(element).offset().top + settings.threshold  + $(element).height();
-    };
-    
-    $.leftofbegin = function(element, settings) {
-        if (settings.container === undefined || settings.container === window) {
-            var fold = $(window).scrollLeft();
-        } else {
-            var fold = $(settings.container).offset().left;
-        }
-        return fold >= $(element).offset().left + settings.threshold + $(element).width();
-    };
-    /* Custom selectors for your convenience.   */
-    /* Use as $("img:below-the-fold").something() */
-
-    $.extend($.expr[':'], {
-        "below-the-fold" : "$.belowthefold(a, {threshold : 0, container: window})",
-        "above-the-fold" : "!$.belowthefold(a, {threshold : 0, container: window})",
-        "right-of-fold"  : "$.rightoffold(a, {threshold : 0, container: window})",
-        "left-of-fold"   : "!$.rightoffold(a, {threshold : 0, container: window})"
-    });
-    
-})(jQuery);
\ No newline at end of file
diff --git a/addons/webinterface.default/js/json2.js b/addons/webinterface.default/js/json2.js
new file mode 100644 (file)
index 0000000..c7745df
--- /dev/null
@@ -0,0 +1,486 @@
+/*
+    json2.js
+    2012-10-08
+
+    Public Domain.
+
+    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+
+    See http://www.JSON.org/js.html
+
+
+    This code should be minified before deployment.
+    See http://javascript.crockford.com/jsmin.html
+
+    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
+    NOT CONTROL.
+
+
+    This file creates a global JSON object containing two methods: stringify
+    and parse.
+
+        JSON.stringify(value, replacer, space)
+            value       any JavaScript value, usually an object or array.
+
+            replacer    an optional parameter that determines how object
+                        values are stringified for objects. It can be a
+                        function or an array of strings.
+
+            space       an optional parameter that specifies the indentation
+                        of nested structures. If it is omitted, the text will
+                        be packed without extra whitespace. If it is a number,
+                        it will specify the number of spaces to indent at each
+                        level. If it is a string (such as '\t' or '&nbsp;'),
+                        it contains the characters used to indent at each level.
+
+            This method produces a JSON text from a JavaScript value.
+
+            When an object value is found, if the object contains a toJSON
+            method, its toJSON method will be called and the result will be
+            stringified. A toJSON method does not serialize: it returns the
+            value represented by the name/value pair that should be serialized,
+            or undefined if nothing should be serialized. The toJSON method
+            will be passed the key associated with the value, and this will be
+            bound to the value
+
+            For example, this would serialize Dates as ISO strings.
+
+                Date.prototype.toJSON = function (key) {
+                    function f(n) {
+                        // Format integers to have at least two digits.
+                        return n < 10 ? '0' + n : n;
+                    }
+
+                    return this.getUTCFullYear()   + '-' +
+                         f(this.getUTCMonth() + 1) + '-' +
+                         f(this.getUTCDate())      + 'T' +
+                         f(this.getUTCHours())     + ':' +
+                         f(this.getUTCMinutes())   + ':' +
+                         f(this.getUTCSeconds())   + 'Z';
+                };
+
+            You can provide an optional replacer method. It will be passed the
+            key and value of each member, with this bound to the containing
+            object. The value that is returned from your method will be
+            serialized. If your method returns undefined, then the member will
+            be excluded from the serialization.
+
+            If the replacer parameter is an array of strings, then it will be
+            used to select the members to be serialized. It filters the results
+            such that only members with keys listed in the replacer array are
+            stringified.
+
+            Values that do not have JSON representations, such as undefined or
+            functions, will not be serialized. Such values in objects will be
+            dropped; in arrays they will be replaced with null. You can use
+            a replacer function to replace those with JSON values.
+            JSON.stringify(undefined) returns undefined.
+
+            The optional space parameter produces a stringification of the
+            value that is filled with line breaks and indentation to make it
+            easier to read.
+
+            If the space parameter is a non-empty string, then that string will
+            be used for indentation. If the space parameter is a number, then
+            the indentation will be that many spaces.
+
+            Example:
+
+            text = JSON.stringify(['e', {pluribus: 'unum'}]);
+            // text is '["e",{"pluribus":"unum"}]'
+
+
+            text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
+            // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
+
+            text = JSON.stringify([new Date()], function (key, value) {
+                return this[key] instanceof Date ?
+                    'Date(' + this[key] + ')' : value;
+            });
+            // text is '["Date(---current time---)"]'
+
+
+        JSON.parse(text, reviver)
+            This method parses a JSON text to produce an object or array.
+            It can throw a SyntaxError exception.
+
+            The optional reviver parameter is a function that can filter and
+            transform the results. It receives each of the keys and values,
+            and its return value is used instead of the original value.
+            If it returns what it received, then the structure is not modified.
+            If it returns undefined then the member is deleted.
+
+            Example:
+
+            // Parse the text. Values that look like ISO date strings will
+            // be converted to Date objects.
+
+            myData = JSON.parse(text, function (key, value) {
+                var a;
+                if (typeof value === 'string') {
+                    a =
+/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
+                    if (a) {
+                        return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+                            +a[5], +a[6]));
+                    }
+                }
+                return value;
+            });
+
+            myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
+                var d;
+                if (typeof value === 'string' &&
+                        value.slice(0, 5) === 'Date(' &&
+                        value.slice(-1) === ')') {
+                    d = new Date(value.slice(5, -1));
+                    if (d) {
+                        return d;
+                    }
+                }
+                return value;
+            });
+
+
+    This is a reference implementation. You are free to copy, modify, or
+    redistribute.
+*/
+
+/*jslint evil: true, regexp: true */
+
+/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
+    call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
+    getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
+    lastIndex, length, parse, prototype, push, replace, slice, stringify,
+    test, toJSON, toString, valueOf
+*/
+
+
+// Create a JSON object only if one does not already exist. We create the
+// methods in a closure to avoid creating global variables.
+
+if (typeof JSON !== 'object') {
+    JSON = {};
+}
+
+(function () {
+    'use strict';
+
+    function f(n) {
+        // Format integers to have at least two digits.
+        return n < 10 ? '0' + n : n;
+    }
+
+    if (typeof Date.prototype.toJSON !== 'function') {
+
+        Date.prototype.toJSON = function (key) {
+
+            return isFinite(this.valueOf())
+                ? this.getUTCFullYear()     + '-' +
+                    f(this.getUTCMonth() + 1) + '-' +
+                    f(this.getUTCDate())      + 'T' +
+                    f(this.getUTCHours())     + ':' +
+                    f(this.getUTCMinutes())   + ':' +
+                    f(this.getUTCSeconds())   + 'Z'
+                : null;
+        };
+
+        String.prototype.toJSON      =
+            Number.prototype.toJSON  =
+            Boolean.prototype.toJSON = function (key) {
+                return this.valueOf();
+            };
+    }
+
+    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+        gap,
+        indent,
+        meta = {    // table of character substitutions
+            '\b': '\\b',
+            '\t': '\\t',
+            '\n': '\\n',
+            '\f': '\\f',
+            '\r': '\\r',
+            '"' : '\\"',
+            '\\': '\\\\'
+        },
+        rep;
+
+
+    function quote(string) {
+
+// If the string contains no control characters, no quote characters, and no
+// backslash characters, then we can safely slap some quotes around it.
+// Otherwise we must also replace the offending characters with safe escape
+// sequences.
+
+        escapable.lastIndex = 0;
+        return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
+            var c = meta[a];
+            return typeof c === 'string'
+                ? c
+                : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+        }) + '"' : '"' + string + '"';
+    }
+
+
+    function str(key, holder) {
+
+// Produce a string from holder[key].
+
+        var i,          // The loop counter.
+            k,          // The member key.
+            v,          // The member value.
+            length,
+            mind = gap,
+            partial,
+            value = holder[key];
+
+// If the value has a toJSON method, call it to obtain a replacement value.
+
+        if (value && typeof value === 'object' &&
+                typeof value.toJSON === 'function') {
+            value = value.toJSON(key);
+        }
+
+// If we were called with a replacer function, then call the replacer to
+// obtain a replacement value.
+
+        if (typeof rep === 'function') {
+            value = rep.call(holder, key, value);
+        }
+
+// What happens next depends on the value's type.
+
+        switch (typeof value) {
+        case 'string':
+            return quote(value);
+
+        case 'number':
+
+// JSON numbers must be finite. Encode non-finite numbers as null.
+
+            return isFinite(value) ? String(value) : 'null';
+
+        case 'boolean':
+        case 'null':
+
+// If the value is a boolean or null, convert it to a string. Note:
+// typeof null does not produce 'null'. The case is included here in
+// the remote chance that this gets fixed someday.
+
+            return String(value);
+
+// If the type is 'object', we might be dealing with an object or an array or
+// null.
+
+        case 'object':
+
+// Due to a specification blunder in ECMAScript, typeof null is 'object',
+// so watch out for that case.
+
+            if (!value) {
+                return 'null';
+            }
+
+// Make an array to hold the partial results of stringifying this object value.
+
+            gap += indent;
+            partial = [];
+
+// Is the value an array?
+
+            if (Object.prototype.toString.apply(value) === '[object Array]') {
+
+// The value is an array. Stringify every element. Use null as a placeholder
+// for non-JSON values.
+
+                length = value.length;
+                for (i = 0; i < length; i += 1) {
+                    partial[i] = str(i, value) || 'null';
+                }
+
+// Join all of the elements together, separated with commas, and wrap them in
+// brackets.
+
+                v = partial.length === 0
+                    ? '[]'
+                    : gap
+                    ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
+                    : '[' + partial.join(',') + ']';
+                gap = mind;
+                return v;
+            }
+
+// If the replacer is an array, use it to select the members to be stringified.
+
+            if (rep && typeof rep === 'object') {
+                length = rep.length;
+                for (i = 0; i < length; i += 1) {
+                    if (typeof rep[i] === 'string') {
+                        k = rep[i];
+                        v = str(k, value);
+                        if (v) {
+                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
+                        }
+                    }
+                }
+            } else {
+
+// Otherwise, iterate through all of the keys in the object.
+
+                for (k in value) {
+                    if (Object.prototype.hasOwnProperty.call(value, k)) {
+                        v = str(k, value);
+                        if (v) {
+                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
+                        }
+                    }
+                }
+            }
+
+// Join all of the member texts together, separated with commas,
+// and wrap them in braces.
+
+            v = partial.length === 0
+                ? '{}'
+                : gap
+                ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
+                : '{' + partial.join(',') + '}';
+            gap = mind;
+            return v;
+        }
+    }
+
+// If the JSON object does not yet have a stringify method, give it one.
+
+    if (typeof JSON.stringify !== 'function') {
+        JSON.stringify = function (value, replacer, space) {
+
+// The stringify method takes a value and an optional replacer, and an optional
+// space parameter, and returns a JSON text. The replacer can be a function
+// that can replace values, or an array of strings that will select the keys.
+// A default replacer method can be provided. Use of the space parameter can
+// produce text that is more easily readable.
+
+            var i;
+            gap = '';
+            indent = '';
+
+// If the space parameter is a number, make an indent string containing that
+// many spaces.
+
+            if (typeof space === 'number') {
+                for (i = 0; i < space; i += 1) {
+                    indent += ' ';
+                }
+
+// If the space parameter is a string, it will be used as the indent string.
+
+            } else if (typeof space === 'string') {
+                indent = space;
+            }
+
+// If there is a replacer, it must be a function or an array.
+// Otherwise, throw an error.
+
+            rep = replacer;
+            if (replacer && typeof replacer !== 'function' &&
+                    (typeof replacer !== 'object' ||
+                    typeof replacer.length !== 'number')) {
+                throw new Error('JSON.stringify');
+            }
+
+// Make a fake root object containing our value under the key of ''.
+// Return the result of stringifying the value.
+
+            return str('', {'': value});
+        };
+    }
+
+
+// If the JSON object does not yet have a parse method, give it one.
+
+    if (typeof JSON.parse !== 'function') {
+        JSON.parse = function (text, reviver) {
+
+// The parse method takes a text and an optional reviver function, and returns
+// a JavaScript value if the text is a valid JSON text.
+
+            var j;
+
+            function walk(holder, key) {
+
+// The walk method is used to recursively walk the resulting structure so
+// that modifications can be made.
+
+                var k, v, value = holder[key];
+                if (value && typeof value === 'object') {
+                    for (k in value) {
+                        if (Object.prototype.hasOwnProperty.call(value, k)) {
+                            v = walk(value, k);
+                            if (v !== undefined) {
+                                value[k] = v;
+                            } else {
+                                delete value[k];
+                            }
+                        }
+                    }
+                }
+                return reviver.call(holder, key, value);
+            }
+
+
+// Parsing happens in four stages. In the first stage, we replace certain
+// Unicode characters with escape sequences. JavaScript handles many characters
+// incorrectly, either silently deleting them, or treating them as line endings.
+
+            text = String(text);
+            cx.lastIndex = 0;
+            if (cx.test(text)) {
+                text = text.replace(cx, function (a) {
+                    return '\\u' +
+                        ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+                });
+            }
+
+// In the second stage, we run the text against regular expressions that look
+// for non-JSON patterns. We are especially concerned with '()' and 'new'
+// because they can cause invocation, and '=' because it can cause mutation.
+// But just to be safe, we want to reject all unexpected forms.
+
+// We split the second stage into 4 regexp operations in order to work around
+// crippling inefficiencies in IE's and Safari's regexp engines. First we
+// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
+// replace all simple value tokens with ']' characters. Third, we delete all
+// open brackets that follow a colon or comma or that begin the text. Finally,
+// we look to see that the remaining characters are only whitespace or ']' or
+// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
+
+            if (/^[\],:{}\s]*$/
+                    .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
+                        .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
+                        .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+
+// In the third stage we use the eval function to compile the text into a
+// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
+// in JavaScript: it can begin a block or an object literal. We wrap the text
+// in parens to eliminate the ambiguity.
+
+                j = eval('(' + text + ')');
+
+// In the optional fourth stage, we recursively walk the new structure, passing
+// each name/value pair to a reviver function for possible transformation.
+
+                return typeof reviver === 'function'
+                    ? walk({'': j}, '')
+                    : j;
+            }
+
+// If the text is not JSON parseable, then a SyntaxError is thrown.
+
+            throw new SyntaxError('JSON.parse');
+        };
+    }
+}());
index 0f29e51..678602a 100644 (file)
     var i,
         script,
         debug = false, /* Set to true to disable cached javascript */
-        version = (debug ? Math.random() : '2.0.6'),
+        version = (debug ? Math.random() : '2.1.0'),
         scripts = [
-            "js/jquery-1.5.2.min.js",
-            "js/jquery.lazyload.js",
+            "js/jquery-1.8.2.min.js",
+            "js/json2.js",
             "js/iscroll-min.js",
             "js/xbmc.core.js",
+            "js/xbmc.rpc.js",
             "js/MediaLibrary.js",
             "js/NowPlayingManager.js",
             "js/xbmc.init.js"
diff --git a/addons/webinterface.default/js/xbmc.rpc.js b/addons/webinterface.default/js/xbmc.rpc.js
new file mode 100644 (file)
index 0000000..cd448fe
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ *      Copyright (C) 2005-2012 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+(function (window) {
+
+    var xbmc = window.xbmc || {};
+
+    xbmc.rpc = {
+        'default_options': {
+            'contentType': 'application/json',
+            'dataType': 'json',
+            'type': 'POST',
+            'success': function () {
+                $('#spinner').hide();
+            }
+        },
+        'request': function (options) {
+            var request_options = jQuery.extend({}, this.default_options, options);
+            request_options.url = xbmc.core.JSON_RPC + '?' + options.method;
+            request_options.data = JSON.stringify({
+                'jsonrpc': '2.0',
+                'method': options.method,
+                'id': 1,
+                'params': request_options.params
+            });
+            return jQuery.ajax(request_options)
+        }
+    };
+
+    window.xbmc = xbmc;
+
+}(window));
+
index 95171f8..bd2f6f4 100644 (file)
@@ -589,13 +589,7 @@ case $host in
      use_dvdcss=no
      use_gles=yes
      use_cpu=cortex-a8
-     check_sdl_arch=[`file /opt/local/lib/libSDL_image.dylib | awk '{V=7; print $V}'`]
-     if test "x$check_sdl_arch" = "xi386"; then
-       use_texturepacker_native=yes
-       USE_TEXTUREPACKER_NATIVE_ROOT="/opt/local"
-     else
-       use_texturepacker=no
-     fi
+     use_texturepacker_native=yes
      ARCH="arm-osx"
      use_arch="arm"
      PYTHON_VERSION="2.6"
@@ -609,7 +603,6 @@ case $host in
      use_joystick=no
      use_vtbdecoder=no
      use_texturepacker_native=yes
-     USE_TEXTUREPACKER_NATIVE_ROOT="$prefix"
      ARCH="x86-osx"
      AC_SUBST(ARCH_DEFINES, "-DTARGET_POSIX -DTARGET_DARWIN -DTARGET_DARWIN_OSX -D_LINUX")
      ;;
@@ -1456,9 +1449,9 @@ if test "x$use_libcec" != "xno"; then
   # libcec is dyloaded, so we need to check for its headers and link any depends.
   if test "x$use_libcec" != "xno"; then
     if test "x$use_libcec" != "xauto"; then
-      PKG_CHECK_MODULES([CEC],[libcec >= 1.8.0],,[use_libcec="no";AC_MSG_ERROR($libcec_disabled)])
+      PKG_CHECK_MODULES([CEC],[libcec >= 2.0.0],,[use_libcec="no";AC_MSG_ERROR($libcec_disabled)])
     else
-      PKG_CHECK_MODULES([CEC],[libcec >= 1.8.0],,[use_libcec="no";AC_MSG_RESULT($libcec_disabled)])
+      PKG_CHECK_MODULES([CEC],[libcec >= 2.0.0],,[use_libcec="no";AC_MSG_RESULT($libcec_disabled)])
     fi
 
     if test "x$use_libcec" != "xno"; then
index fb5abf8..80d00bc 100644 (file)
@@ -3201,6 +3201,12 @@ msgctxt "#1273"
 msgid "AirPlay"
 msgstr ""
 
+#empty string id 1274
+
+msgctxt "#1275"
+msgid "Filter %s"
+msgstr ""
+
 #empty strings from id 1274 to 1299
 
 msgctxt "#1300"
@@ -4885,7 +4891,27 @@ msgctxt "#13510"
 msgid "Sync playback to display"
 msgstr ""
 
-#empty strings from id 13511 to 13549
+msgctxt "#13511"
+msgid "Choose art"
+msgstr ""
+
+msgctxt "#13512"
+msgid "Current art"
+msgstr ""
+
+msgctxt "#13513"
+msgid "Remote art"
+msgstr ""
+
+msgctxt "#13514"
+msgid "Local art"
+msgstr ""
+
+msgctxt "#13515"
+msgid "No art"
+msgstr ""
+
+#empty strings from id 13516 to 13549
 
 msgctxt "#13550"
 msgid "Pause during refresh rate change"
@@ -7135,7 +7161,23 @@ msgctxt "#19274"
 msgid "Please visit xbmc.org/pvr to learn more."
 msgstr ""
 
-#empty strings from id 19275 to 19498
+msgctxt "#19275"
+msgid "Conflict warning"
+msgstr ""
+
+msgctxt "#19276"
+msgid "Conflict error"
+msgstr ""
+
+msgctxt "#19277"
+msgid "Recording conflict"
+msgstr ""
+
+msgctxt "#19278"
+msgid "Recording error"
+msgstr ""
+
+#empty strings from id 19279 to 19498
 
 msgctxt "#19499"
 msgid "Other/Unknown"
@@ -8215,7 +8257,9 @@ msgctxt "#20187"
 msgid "UPnP"
 msgstr ""
 
-#empty string with id 20188
+msgctxt "#20188"
+msgid "Announce library updates via UPnP"
+msgstr ""
 
 msgctxt "#20189"
 msgid "Enable auto scrolling for plot & review"
@@ -9400,7 +9444,23 @@ msgctxt "#21465"
 msgid "Above video"
 msgstr ""
 
-#empty strings from id 21466 to 21799
+msgctxt "#21466"
+msgid "between"
+msgstr ""
+
+msgctxt "#21467"
+msgid "%.1f to %.1f"
+msgstr ""
+
+msgctxt "#21468"
+msgid "%d to %d"
+msgstr ""
+
+msgctxt "#21469"
+msgid "%s to %s"
+msgstr ""
+
+#empty strings from id 21470 to 21799
 
 msgctxt "#21800"
 msgid "File name"
@@ -10876,7 +10936,7 @@ msgid "Product ID"
 msgstr ""
 
 #empty strings from id 35505 to 35999
-
+#: xbmc/peripherals/devices/PeripheralCecAdapter.cpp
 msgctxt "#36000"
 msgid "Pulse-Eight CEC adapter"
 msgstr ""
@@ -10927,11 +10987,7 @@ msgctxt "#36012"
 msgid "Could not initialise the CEC adapter. Please check your settings."
 msgstr ""
 
-msgctxt "#36013"
-msgid "Unsupported libCEC interface version. %d is greater than the version XBMC supports (%d)"
-msgstr ""
-
-#empty string with id 36014
+#empty strings from id 36013 to 36014
 
 msgctxt "#36015"
 msgid "HDMI port number"
@@ -11023,3 +11079,21 @@ msgstr ""
 msgctxt "#36036"
 msgid "On start/stop"
 msgstr ""
+
+#: xbmc/peripherals/devices/PeripheralCecAdapter.cpp
+msgctxt "#36037"
+msgid "TV"
+msgstr ""
+
+msgctxt "#36038"
+msgid "Amplifier / AVR device"
+msgstr ""
+
+msgctxt "#36039"
+msgid "TV and AVR device (explicit)"
+msgstr ""
+
+msgctxt "#36040"
+msgid "Unsupported libCEC interface version. %x is lower than the version XBMC supports (%x)"
+msgstr ""
+
index 3c2db2f..10f0056 100644 (file)
@@ -141,6 +141,14 @@ DLLEXPORT void PVR_trigger_recording_update(void *hdl, void* cb)
   ((CB_PVRLib*)cb)->TriggerRecordingUpdate(((AddonCB*)hdl)->addonData);
 }
 
+DLLEXPORT void PVR_trigger_epg_update(void* hdl, void* cb, unsigned int iChannelUid)
+{
+  if (cb == NULL)
+    return;
+
+  ((CB_PVRLib*)cb)->TriggerEpgUpdate(((AddonCB*)hdl)->addonData, iChannelUid);
+}
+
 DLLEXPORT void PVR_free_demux_packet(void *hdl, void* cb, DemuxPacket* pPacket)
 {
   if (cb == NULL)
index 3280b15..62bdc49 100644 (file)
@@ -460,14 +460,14 @@ PLT_Service::IsSubscribable()
 |   PLT_Service::SetStateVariable
 +---------------------------------------------------------------------*/
 NPT_Result
-PLT_Service::SetStateVariable(const char* name, const char* value)
+PLT_Service::SetStateVariable(const char* name, const char* value, const bool clearonsend /*=false*/)
 {
     PLT_StateVariable* stateVariable = NULL;
     NPT_ContainerFind(m_StateVars, PLT_StateVariableNameFinder(name), stateVariable);
     if (stateVariable == NULL)
         return NPT_FAILURE;
 
-    return stateVariable->SetValue(value);
+    return stateVariable->SetValue(value, clearonsend);
 }
 
 /*----------------------------------------------------------------------
@@ -838,6 +838,13 @@ PLT_Service::NotifyChanged()
         delete sub;
     }
 
+    // some state variables must be cleared immediatly after sending
+    iter = vars_ready.GetFirstItem();
+    while (iter) {
+      PLT_StateVariable* var = *iter;
+      var->OnSendCompleted();
+      ++iter;
+    }
     return NPT_SUCCESS;
 }
 
index c03a552..9bd4d12 100644 (file)
@@ -216,8 +216,9 @@ public:
      when necessary.
      @param name state variable name
      @param value new State Variable value.
+     @param clearonsend whether the State Variable should clear immediatly in ::OnSendingCompleted
      */
-    NPT_Result SetStateVariable(const char* name, const char* value);
+    NPT_Result SetStateVariable(const char* name, const char* value, const bool clearonsend = false);
     
     /**
      Certain state variables notifications must not be sent faster than a certain 
index 229e304..47aeb5a 100644 (file)
@@ -48,7 +48,8 @@ NPT_SET_LOCAL_LOGGER("platinum.core.statevariable")
 PLT_StateVariable::PLT_StateVariable(PLT_Service* service) : 
     m_Service(service), 
     m_AllowedValueRange(NULL),
-    m_IsSendingEventsIndirectly(true)
+    m_IsSendingEventsIndirectly(true),
+    m_ShouldClearOnSend(false)
 {
 }
 
@@ -145,7 +146,7 @@ PLT_StateVariable::SetRate(NPT_TimeInterval rate)
 |   PLT_StateVariable::SetValue
 +---------------------------------------------------------------------*/
 NPT_Result
-PLT_StateVariable::SetValue(const char* value)
+PLT_StateVariable::SetValue(const char* value, const bool clearonsend /*=false*/)
 {
     if (value == NULL) {
         return NPT_FAILURE;
@@ -159,6 +160,7 @@ PLT_StateVariable::SetValue(const char* value)
         }
 
         m_Value = value;
+        m_ShouldClearOnSend = clearonsend;
         m_Service->AddChanged(this); 
     }
 
@@ -183,6 +185,16 @@ PLT_StateVariable::IsReadyToPublish()
 }
 
 /*----------------------------------------------------------------------
+|   PLT_StateVariable::OnSendCompleted
++---------------------------------------------------------------------*/
+void
+PLT_StateVariable::OnSendCompleted()
+{
+  if(m_ShouldClearOnSend)
+      m_Value = m_DefaultValue;
+}
+
+/*----------------------------------------------------------------------
 |   PLT_StateVariable::ValidateValue
 +---------------------------------------------------------------------*/
 NPT_Result
index 46ec9e9..465e95c 100644 (file)
@@ -115,8 +115,9 @@ public:
      it is an allowed value. Once the value is validated, it is marked for eventing by
      calling the PLT_Service AddChanged function.
      @param value new state variable value. Can be a comma separated list of values.
+     @param clearonsend whether the statevariable should be cleared immediatly after sending
      */
-    NPT_Result SetValue(const char* value);
+    NPT_Result SetValue(const char* value, const bool clearonsend = false);
     
     /**
      Validate the new value of the state variable.
@@ -173,6 +174,12 @@ protected:
     bool IsReadyToPublish();
     
     /**
+     * If this statevariable should clear after sending to all subscribers, clears the value without
+     * eventing the change
+     */
+    void OnSendCompleted();
+
+    /**
      Serialize the state variable into xml.
      */
        NPT_Result Serialize(NPT_XmlElementNode& node);
@@ -189,6 +196,7 @@ protected:
     NPT_String              m_DefaultValue;
     bool                    m_IsSendingEvents;
     bool                    m_IsSendingEventsIndirectly;
+    bool                    m_ShouldClearOnSend;
     NPT_TimeInterval        m_Rate;
     NPT_TimeStamp           m_LastEvent;
     NPT_Array<NPT_String*>  m_AllowedValues;
index f6eaf14..8d9704f 100644 (file)
 #define PLT_FILTER_MASK_ORIGINALTRACK               0x00000100
 #define PLT_FILTER_MASK_ACTOR                       0x00000200
 #define PLT_FILTER_MASK_AUTHOR                      0x00000400
-#define PLT_FILTER_MASK_DATE                        0x00000800
-#define PLT_FILTER_MASK_PROGRAMTITLE                0x00001000
-#define PLT_FILTER_MASK_SERIESTITLE                 0x00002000
-#define PLT_FILTER_MASK_EPISODE                     0x00004000
-#define PLT_FILTER_MASK_TITLE                       0x00008000
+#define PLT_FILTER_MASK_DIRECTOR                    0x00000800
+#define PLT_FILTER_MASK_DATE                        0x00001000
+#define PLT_FILTER_MASK_PROGRAMTITLE                0x00002000
+#define PLT_FILTER_MASK_SERIESTITLE                 0x00004000
+#define PLT_FILTER_MASK_EPISODE                     0x00008000
+#define PLT_FILTER_MASK_TITLE                       0x00010000
 
-#define PLT_FILTER_MASK_RES                         0x00010000
-#define PLT_FILTER_MASK_RES_DURATION                0x00020000
-#define PLT_FILTER_MASK_RES_SIZE                    0x00040000
-#define PLT_FILTER_MASK_RES_PROTECTION              0x00080000
-#define PLT_FILTER_MASK_RES_RESOLUTION              0x00100000
-#define PLT_FILTER_MASK_RES_BITRATE                 0x00200000
-#define PLT_FILTER_MASK_RES_BITSPERSAMPLE           0x00400000
-#define PLT_FILTER_MASK_RES_NRAUDIOCHANNELS                    0x00800000
-#define PLT_FILTER_MASK_RES_SAMPLEFREQUENCY                    0x01000000
+#define PLT_FILTER_MASK_RES                         0x00020000
+#define PLT_FILTER_MASK_RES_DURATION                0x00040000
+#define PLT_FILTER_MASK_RES_SIZE                    0x00080000
+#define PLT_FILTER_MASK_RES_PROTECTION              0x00100000
+#define PLT_FILTER_MASK_RES_RESOLUTION              0x00200000
+#define PLT_FILTER_MASK_RES_BITRATE                 0x00400000
+#define PLT_FILTER_MASK_RES_BITSPERSAMPLE           0x00800000
+#define PLT_FILTER_MASK_RES_NRAUDIOCHANNELS         0x01000000
+#define PLT_FILTER_MASK_RES_SAMPLEFREQUENCY         0x02000000
 
-#define PLT_FILTER_MASK_LONGDESCRIPTION             0x02000000
-#define PLT_FILTER_MASK_ICON                        0x04000000
+#define PLT_FILTER_MASK_LONGDESCRIPTION             0x04000000
+#define PLT_FILTER_MASK_ICON                        0x08000000
+#define PLT_FILTER_MASK_RATING                      0x10000000
 
-#define PLT_FILTER_MASK_TOC                                                    0x02000000
-#define PLT_FILTER_MASK_SEARCHCLASS                                    0x04000000
-#define PLT_FILTER_MASK_REFID                       0x08000000
+#define PLT_FILTER_MASK_TOC                         0x20000000
+#define PLT_FILTER_MASK_SEARCHCLASS                 0x40000000
+#define PLT_FILTER_MASK_REFID                       0x80000000
 
 #define PLT_FILTER_FIELD_TITLE                      "dc:title"
 #define PLT_FILTER_FIELD_CREATOR                    "dc:creator"
@@ -90,6 +92,7 @@
 #define PLT_FILTER_FIELD_ARTIST                     "upnp:artist"
 #define PLT_FILTER_FIELD_ACTOR                      "upnp:actor"
 #define PLT_FILTER_FIELD_AUTHOR                     "upnp:author"
+#define PLT_FILTER_FIELD_DIRECTOR                   "upnp:director"
 #define PLT_FILTER_FIELD_ALBUM                      "upnp:album"
 #define PLT_FILTER_FIELD_GENRE                      "upnp:genre"
 #define PLT_FILTER_FIELD_ALBUMARTURI                "upnp:albumArtURI"
 #define PLT_FILTER_FIELD_DESCRIPTION                "dc:description"
 #define PLT_FILTER_FIELD_LONGDESCRIPTION            "upnp:longDescription"
 #define PLT_FILTER_FIELD_ICON                       "upnp:icon"
+#define PLT_FILTER_FIELD_RATING                     "upnp:rating"
 #define PLT_FILTER_FIELD_ORIGINALTRACK              "upnp:originalTrackNumber"
 #define PLT_FILTER_FIELD_PROGRAMTITLE               "upnp:programTitle"
 #define PLT_FILTER_FIELD_SERIESTITLE                "upnp:seriesTitle"
index 5b974e8..0a55eef 100644 (file)
@@ -183,6 +183,9 @@ PLT_MediaObject::Reset()
     m_ExtraInfo.artist_discography_uri = "";
 
     m_MiscInfo.original_track_number = 0;
+    m_MiscInfo.last_position         = 0;
+    m_MiscInfo.last_time             = "";
+    m_MiscInfo.play_count            = -1;
     m_MiscInfo.dvdregioncode            = 0;
     m_MiscInfo.toc                                      = "";
     m_MiscInfo.user_annotation          = "";
@@ -250,6 +253,11 @@ PLT_MediaObject::ToDidl(NPT_UInt32 mask, NPT_String& didl)
         m_People.authors.ToDidl(didl, "author");
     }
     
+    // director
+    if (mask & PLT_FILTER_MASK_DIRECTOR) {
+        m_People.directors.ToDidl(didl, "director");
+    }
+
     // album
     if ((mask & PLT_FILTER_MASK_ALBUM) && !m_Affiliation.album.IsEmpty()) {
         didl += "<upnp:album>";
@@ -310,6 +318,13 @@ PLT_MediaObject::ToDidl(NPT_UInt32 mask, NPT_String& didl)
         didl += "</upnp:icon>";
     }
 
+    // rating
+    if ((mask & PLT_FILTER_MASK_RATING) && !m_Description.rating.IsEmpty()) {
+        didl += "<upnp:rating>";
+        PLT_Didl::AppendXmlEscape(didl, m_Description.rating);
+        didl += "</upnp:rating>";
+    }
+
     // original track number
     if ((mask & PLT_FILTER_MASK_ORIGINALTRACK) && m_MiscInfo.original_track_number > 0) {
         didl += "<upnp:originalTrackNumber>";
@@ -317,6 +332,27 @@ PLT_MediaObject::ToDidl(NPT_UInt32 mask, NPT_String& didl)
         didl += "</upnp:originalTrackNumber>";
     }
 
+    // last playback position
+    if (m_MiscInfo.last_position > 0) {
+        didl += "<upnp:lastPlaybackPosition>";
+        didl += NPT_String::FromInteger(m_MiscInfo.last_position);
+        didl += "</upnp:lastPlaybackPosition>";
+    }
+
+    // last playback datetime
+    if (!m_MiscInfo.last_time.IsEmpty()) {
+        didl += "<upnp:lastPlaybackTime>";
+        PLT_Didl::AppendXmlEscape(didl, m_MiscInfo.last_time);
+        didl += "</upnp:lastPlaybackTime>";
+    }
+
+    // playcount
+    if (m_MiscInfo.play_count > -1) {
+        didl += "<upnp:playbackCount>";
+        didl += NPT_String::FromInteger(m_MiscInfo.play_count);
+        didl += "</upnp:playbackCount>";
+    }
+
     // program title
     if (mask & PLT_FILTER_MASK_PROGRAMTITLE && !m_Recorded.program_title.IsEmpty()) {
         didl += "<upnp:programTitle>";
@@ -465,15 +501,22 @@ PLT_MediaObject::FromDidl(NPT_XmlElementNode* entry)
     m_Title = m_Title.SubString(0, 256);    
     m_ObjectClass.type =  m_ObjectClass.type.SubString(0, 256);
 
+    children.Clear();
     PLT_XmlHelper::GetChildren(entry, children, "artist", didl_namespace_upnp);
     m_People.artists.FromDidl(children);
     
+    children.Clear();
     PLT_XmlHelper::GetChildren(entry, children, "author", didl_namespace_upnp);
     m_People.authors.FromDidl(children);
     
+    children.Clear();
     PLT_XmlHelper::GetChildren(entry, children, "actors", didl_namespace_upnp);
     m_People.actors.FromDidl(children);
 
+    children.Clear();
+    PLT_XmlHelper::GetChildren(entry, children, "director", didl_namespace_upnp);
+    m_People.directors.FromDidl(children);
+
     PLT_XmlHelper::GetChildText(entry, "album", m_Affiliation.album, didl_namespace_upnp, 256);
     PLT_XmlHelper::GetChildText(entry, "programTitle", m_Recorded.program_title, didl_namespace_upnp);
     PLT_XmlHelper::GetChildText(entry, "seriesTitle", m_Recorded.series_title, didl_namespace_upnp);
@@ -493,6 +536,7 @@ PLT_MediaObject::FromDidl(NPT_XmlElementNode* entry)
     PLT_XmlHelper::GetChildText(entry, "description", m_Description.description, didl_namespace_dc);
     PLT_XmlHelper::GetChildText(entry, "longDescription", m_Description.long_description, didl_namespace_upnp);
     PLT_XmlHelper::GetChildText(entry, "icon", m_Description.icon_uri, didl_namespace_upnp);
+    PLT_XmlHelper::GetChildText(entry, "rating", m_Description.rating, didl_namespace_upnp);
        PLT_XmlHelper::GetChildText(entry, "toc", m_MiscInfo.toc, didl_namespace_upnp);
     
     // album arts
@@ -511,6 +555,25 @@ PLT_MediaObject::FromDidl(NPT_XmlElementNode* entry)
     if (NPT_FAILED(str.ToInteger(value))) value = 0;
     m_MiscInfo.original_track_number = value;
 
+    PLT_XmlHelper::GetChildText(entry, "lastPlaybackPosition", str, didl_namespace_upnp);
+    if (NPT_FAILED(str.ToInteger(value))) value = 0;
+    m_MiscInfo.last_position = value;
+
+    PLT_XmlHelper::GetChildText(entry, "lastPlaybackTime", m_MiscInfo.last_time, didl_namespace_dc, 256);
+    NPT_String parsed_last_time;
+    for (int format=0; format<=NPT_DateTime::FORMAT_RFC_1036; format++) {
+        NPT_DateTime date;
+        if (NPT_SUCCEEDED(date.FromString(m_MiscInfo.last_time, (NPT_DateTime::Format)format))) {
+            parsed_last_time = date.ToString((NPT_DateTime::Format)format);
+            break;
+        }
+    }
+    m_MiscInfo.last_time = parsed_last_time;
+
+    PLT_XmlHelper::GetChildText(entry, "playbackCount", str, didl_namespace_upnp);
+    if (NPT_FAILED(str.ToInteger(value))) value = -1;
+    m_MiscInfo.play_count = value;
+
     children.Clear();
     PLT_XmlHelper::GetChildren(entry, children, "res");
     for (NPT_Cardinal i=0; i<children.GetItemCount(); i++) {
index 3ebc3b0..84704b1 100644 (file)
@@ -91,7 +91,7 @@ typedef struct {
     PLT_PersonRoles actors;
     PLT_PersonRoles authors;
     NPT_String      producer; //TODO: can be multiple
-    NPT_String      director; //TODO: can be multiple
+    PLT_PersonRoles directors;
     NPT_String      publisher; //TODO: can be multiple
     NPT_String      contributor; // should match m_Creator (dc:creator) //TODO: can be multiple
 } PLT_PeopleInfo;
@@ -130,6 +130,9 @@ typedef struct {
     NPT_UInt32 original_track_number;
     NPT_String toc;
     NPT_String user_annotation; //TODO: can be multiple
+    NPT_UInt32 last_position;
+    NPT_String last_time;
+    NPT_Int32  play_count;
 } PLT_MiscInfo;
 
 typedef struct {
index 091ae00..0763b59 100644 (file)
@@ -202,8 +202,8 @@ PLT_SyncMediaBrowser::BrowseSync(PLT_BrowseDataReference& browse_data,
                                  const char*              object_id, 
                                  NPT_Int32                index, 
                                  NPT_Int32                count,
-                                 bool                     browse_metadata,
                                  const char*              filter, 
+                                 bool                     browse_metadata,
                                  const char*              sort)
 {
     NPT_Result res;
@@ -236,7 +236,8 @@ PLT_SyncMediaBrowser::BrowseSync(PLT_DeviceDataReference&      device,
                                  PLT_MediaObjectListReference& list,
                                  bool                          metadata, /* = false */
                                  NPT_Int32                     start, /* = 0 */
-                                 NPT_Cardinal                  max_results /* = 0 */)
+                                 NPT_Cardinal                  max_results, /* = 0 */
+                                 const char*                   filter)
 {
     NPT_Result res = NPT_FAILURE;
     NPT_Int32  index = start;
@@ -262,7 +263,8 @@ PLT_SyncMediaBrowser::BrowseSync(PLT_DeviceDataReference&      device,
             device,
             (const char*)object_id,
             index,
-            metadata?1:30, // DLNA recommendations for browsing children is no more than 30 at a time
+            metadata?1:200, // DLNA recommendations for browsing children is no more than 30 at a time
+            filter,
             metadata);         
         NPT_CHECK_LABEL_WARNING(res, done);
         
index e628af9..605ea31 100644 (file)
@@ -106,7 +106,8 @@ public:
                           PLT_MediaObjectListReference& list,
                           bool                          metadata = false,
                           NPT_Int32                     start = 0,
-                          NPT_Cardinal                  max_results = 0); // 0 means all
+                          NPT_Cardinal                  max_results = 0,
+                          const char*                   filter = "dc:date,upnp:genre,res,res@duration,res@size,upnp:albumArtURI,upnp:album,upnp:artist,upnp:author,searchable,childCount"); // explicitely specify res otherwise WMP won't return a URL!
 
     const NPT_Lock<PLT_DeviceMap>& GetMediaServersMap() const { return m_MediaServers; }
     bool IsCached(const char* uuid, const char* object_id);
@@ -117,8 +118,8 @@ protected:
                           const char*              object_id,
                           NPT_Int32                index, 
                           NPT_Int32                count,
+                          const char*              filter,
                           bool                     browse_metadata = false,
-                          const char*              filter = "dc:date,upnp:genre,res,res@duration,res@size,upnp:albumArtURI,upnp:album,upnp:artist,upnp:author,searchable,childCount", // explicitely specify res otherwise WMP won't return a URL!
                           const char*              sort = "");
 private:
     NPT_Result Find(const char* ip, PLT_DeviceDataReference& device);
index b521c14..edc6ea8 100644 (file)
@@ -7,7 +7,7 @@
 
 # lib name, version
 LIBNAME=libcec
-VERSION=1.8.1
+VERSION=2.0.0
 SOURCE=$(LIBNAME)-$(VERSION)
 
 # download location and format
diff --git a/lib/libshairport/011_fix_ipv4_fallback.patch b/lib/libshairport/011_fix_ipv4_fallback.patch
new file mode 100644 (file)
index 0000000..2c813f2
--- /dev/null
@@ -0,0 +1,10 @@
+--- src/socketlib.c    2012-07-14 22:49:30.000000000 +0200
++++ src/socketlib.c    2012-10-08 21:55:51.000000000 +0200
+@@ -118,6 +118,7 @@
+   int tEnable = 1;
+   setsockopt(tSock, SOL_SOCKET, SO_REUSEADDR, &tEnable, sizeof (tEnable));
++  server_addr->ai_addr->sa_family = server_addr->ai_family; // ensure that server_addr has same famliy than the socket
+   if (bind(tSock, server_addr->ai_addr, server_addr->ai_addrlen) < 0)
+   {
+     close(tSock);
index 69a27dd..98e46f2 100644 (file)
@@ -46,6 +46,7 @@ $(SOURCE): $(TARBALLS_LOCATION)/$(ARCHIVE)
        cd $(SOURCE); patch -p0 < ../008-add-missing-libs.patch
        cd $(SOURCE); patch -p0 < ../009_fix_ipv6.patch
        cd $(SOURCE); patch -p0 < ../010_handle_metadata.patch
+       cd $(SOURCE); patch -p0 < ../011_fix_ipv4_fallback.patch
        cd $(SOURCE); autoreconf -vif
        cd $(SOURCE); $(CONFIGURE)
 
index 9be6547..0480d22 100644 (file)
Binary files a/media/Fonts/teletext.ttf and b/media/Fonts/teletext.ttf differ
index 1e827d6..3891833 100644 (file)
@@ -1,3 +1,3 @@
 ; filename                        source of the file
 
-libcec-1.8.1.zip                  http://mirrors.xbmc.org/build-deps/win32/
+libcec-2.0.0.zip                  http://mirrors.xbmc.org/build-deps/win32/
index b9aa9fc..31079b9 100644 (file)
     <ClCompile Include="..\..\xbmc\cores\dvdplayer\DVDDemuxers\DVDDemuxPVRClient.cpp" />
     <ClCompile Include="..\..\xbmc\cores\dvdplayer\DVDInputStreams\DVDInputStreamBluray.cpp" />
     <ClCompile Include="..\..\xbmc\cores\dvdplayer\DVDInputStreams\DVDInputStreamPVRManager.cpp" />
-    <ClCompile Include="..\..\xbmc\cores\paplayer\BXAcodec.cpp" />
     <ClCompile Include="..\..\xbmc\cores\paplayer\PCMCodec.cpp" />
     <ClCompile Include="..\..\xbmc\cores\VideoRenderers\RenderCapture.cpp" />
     <ClCompile Include="..\..\xbmc\cores\VideoRenderers\VideoShaders\WinVideoFilter.cpp" />
     <ClCompile Include="..\..\xbmc\dialogs\GUIDialogGamepad.cpp" />
     <ClCompile Include="..\..\xbmc\dialogs\GUIDialogKaiToast.cpp" />
     <ClCompile Include="..\..\xbmc\dialogs\GUIDialogKeyboardGeneric.cpp" />
+    <ClCompile Include="..\..\xbmc\dialogs\GUIDialogMediaFilter.cpp" />
     <ClCompile Include="..\..\xbmc\dialogs\GUIDialogMediaSource.cpp" />
     <ClCompile Include="..\..\xbmc\dialogs\GUIDialogMuteBug.cpp" />
     <ClCompile Include="..\..\xbmc\dialogs\GUIDialogNumeric.cpp" />
     <ClCompile Include="..\..\xbmc\input\XBMC_keytable.cpp" />
     <ClCompile Include="..\..\xbmc\interfaces\AnnouncementManager.cpp" />
     <ClCompile Include="..\..\xbmc\interfaces\Builtins.cpp" />
-    <ClCompile Include="..\..\xbmc\interfaces\http-api\HttpApi.cpp" />
-    <ClCompile Include="..\..\xbmc\interfaces\http-api\XBMChttp.cpp" />
     <ClCompile Include="..\..\xbmc\interfaces\info\InfoBool.cpp" />
     <ClCompile Include="..\..\xbmc\interfaces\info\SkinVariable.cpp" />
     <ClCompile Include="..\..\xbmc\interfaces\json-rpc\AddonsOperations.cpp" />
     <ClCompile Include="..\..\xbmc\network\EventServer.cpp" />
     <ClCompile Include="..\..\xbmc\network\GUIDialogAccessPoints.cpp" />
     <ClCompile Include="..\..\xbmc\network\GUIDialogNetworkSetup.cpp" />
-    <ClCompile Include="..\..\xbmc\network\httprequesthandler\HTTPApiHandler.cpp" />
     <ClCompile Include="..\..\xbmc\network\httprequesthandler\HTTPImageHandler.cpp" />
     <ClCompile Include="..\..\xbmc\network\httprequesthandler\HTTPJsonRpcHandler.cpp" />
     <ClCompile Include="..\..\xbmc\network\httprequesthandler\HTTPVfsHandler.cpp" />
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release (DirectX)|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release (OpenGL)|Win32'">true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="..\..\xbmc\test\TestFileItem.cpp">
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug (DirectX)|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug (OpenGL)|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release (DirectX)|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release (OpenGL)|Win32'">true</ExcludedFromBuild>
+    </ClCompile>
     <ClCompile Include="..\..\xbmc\test\TestUtils.cpp">
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug (DirectX)|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug (OpenGL)|Win32'">true</ExcludedFromBuild>
     <ClInclude Include="..\..\xbmc\cores\paplayer\PCMCodec.h" />
     <ClInclude Include="..\..\xbmc\dialogs\GUIDialogKeyboardGeneric.h" />
     <ClInclude Include="..\..\xbmc\DbUrl.h" />
+    <ClInclude Include="..\..\xbmc\dialogs\GUIDialogMediaFilter.h" />
     <ClInclude Include="..\..\xbmc\filesystem\ImageFile.h" />
     <ClInclude Include="..\..\xbmc\filesystem\VideoDatabaseDirectory\DirectoryNodeTags.h" />
     <ClInclude Include="..\..\xbmc\filesystem\windows\WINFileSMB.h" />
     <ClInclude Include="..\..\xbmc\interfaces\json-rpc\IJSONRPCAnnouncer.h" />
     <ClInclude Include="..\..\xbmc\interfaces\json-rpc\JSONRPCUtils.h" />
     <ClInclude Include="..\..\xbmc\interfaces\json-rpc\GUIOperations.h" />
-    <ClInclude Include="..\..\xbmc\network\httprequesthandler\HTTPApiHandler.h" />
     <ClInclude Include="..\..\xbmc\network\httprequesthandler\HTTPJsonRpcHandler.h" />
     <ClInclude Include="..\..\xbmc\network\httprequesthandler\HTTPVfsHandler.h" />
     <ClInclude Include="..\..\xbmc\network\httprequesthandler\HTTPWebinterfaceAddonsHandler.h" />
     <ClCompile Include="..\..\xbmc\video\dialogs\GUIDialogVideoInfo.cpp" />
     <ClCompile Include="..\..\xbmc\video\dialogs\GUIDialogVideoOSD.cpp" />
     <ClCompile Include="..\..\xbmc\video\dialogs\GUIDialogVideoOverlay.cpp" />
-    <ClCompile Include="..\..\xbmc\video\dialogs\GUIDialogVideoScan.cpp" />
     <ClCompile Include="..\..\xbmc\video\dialogs\GUIDialogVideoSettings.cpp" />
     <ClCompile Include="..\..\xbmc\video\GUIViewStateVideo.cpp" />
     <ClCompile Include="..\..\xbmc\video\Teletext.cpp" />
     <ClInclude Include="..\..\xbmc\cores\dvdplayer\DVDDemuxers\DVDDemuxPVRClient.h" />
     <ClInclude Include="..\..\xbmc\cores\dvdplayer\DVDInputStreams\DVDInputStreamBluray.h" />
     <ClInclude Include="..\..\xbmc\cores\dvdplayer\DVDInputStreams\DVDInputStreamPVRManager.h" />
-    <ClInclude Include="..\..\xbmc\cores\paplayer\BXAcodec.h" />
     <ClInclude Include="..\..\xbmc\cores\VideoRenderers\RenderCapture.h" />
     <ClInclude Include="..\..\xbmc\cores\VideoRenderers\VideoShaders\WinVideoFilter.h" />
     <ClInclude Include="..\..\xbmc\CueDocument.h" />
     <ClInclude Include="..\..\xbmc\input\XBMC_vkeys.h" />
     <ClInclude Include="..\..\xbmc\interfaces\AnnouncementManager.h" />
     <ClInclude Include="..\..\xbmc\interfaces\Builtins.h" />
-    <ClInclude Include="..\..\xbmc\interfaces\http-api\HttpApi.h" />
-    <ClInclude Include="..\..\xbmc\interfaces\http-api\XBMChttp.h" />
     <ClInclude Include="..\..\xbmc\interfaces\IAnnouncer.h" />
     <ClInclude Include="..\..\xbmc\interfaces\info\InfoBool.h" />
     <ClInclude Include="..\..\xbmc\interfaces\info\SkinVariable.h" />
     <ClInclude Include="..\..\xbmc\video\dialogs\GUIDialogVideoInfo.h" />
     <ClInclude Include="..\..\xbmc\video\dialogs\GUIDialogVideoOSD.h" />
     <ClInclude Include="..\..\xbmc\video\dialogs\GUIDialogVideoOverlay.h" />
-    <ClInclude Include="..\..\xbmc\video\dialogs\GUIDialogVideoScan.h" />
     <ClInclude Include="..\..\xbmc\video\dialogs\GUIDialogVideoSettings.h" />
     <ClInclude Include="..\..\xbmc\video\GUIViewStateVideo.h" />
     <ClInclude Include="..\..\xbmc\video\Teletext.h" />
     </VisualStudio>
   </ProjectExtensions>
   <Import Project="$(SolutionDir)\$(ProjectFileName).targets.user" Condition="Exists('$(SolutionDir)\$(ProjectFileName).targets.user')" />
-</Project>
\ No newline at end of file
+</Project>
index 723ec29..505c119 100644 (file)
     <Filter Include="input\windows">
       <UniqueIdentifier>{2f7a07e4-ac48-4e30-beb3-550e50b59c09}</UniqueIdentifier>
     </Filter>
-    <Filter Include="interfaces\http-api">
-      <UniqueIdentifier>{3616033f-20f3-48c8-96bd-b07f2eed008e}</UniqueIdentifier>
-    </Filter>
     <Filter Include="interfaces\json-rpc">
       <UniqueIdentifier>{15fc3844-6b50-4424-ba2c-ac9bd85d3ab0}</UniqueIdentifier>
     </Filter>
     <ClCompile Include="..\..\xbmc\input\windows\IrssMessage.cpp">
       <Filter>input\windows</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\xbmc\interfaces\http-api\HttpApi.cpp">
-      <Filter>interfaces\http-api</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\xbmc\interfaces\http-api\XBMChttp.cpp">
-      <Filter>interfaces\http-api</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\xbmc\interfaces\json-rpc\AudioLibrary.cpp">
       <Filter>interfaces\json-rpc</Filter>
     </ClCompile>
     <ClCompile Include="..\..\xbmc\video\dialogs\GUIDialogVideoOverlay.cpp">
       <Filter>video\dialogs</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\xbmc\video\dialogs\GUIDialogVideoScan.cpp">
-      <Filter>video\dialogs</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\xbmc\video\dialogs\GUIDialogVideoSettings.cpp">
       <Filter>video\dialogs</Filter>
     </ClCompile>
     <ClCompile Include="..\..\xbmc\guilib\JpegIO.cpp">
       <Filter>guilib</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\xbmc\cores\paplayer\BXAcodec.cpp">
-      <Filter>cores\paplayer</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\xbmc\interfaces\info\SkinVariable.cpp">
       <Filter>interfaces\info</Filter>
     </ClCompile>
     <ClCompile Include="..\..\xbmc\filesystem\AFPDirectory.cpp">
       <Filter>filesystem</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\xbmc\network\httprequesthandler\HTTPApiHandler.cpp">
-      <Filter>network\httprequesthandler</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\xbmc\network\httprequesthandler\HTTPVfsHandler.cpp">
       <Filter>network\httprequesthandler</Filter>
     </ClCompile>
     <ClCompile Include="..\..\xbmc\cores\dvdplayer\DVDDemuxers\DVDDemuxBXA.cpp">
       <Filter>cores\dvdplayer\DVDDemuxers</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\xbmc\dialogs\GUIDialogMediaFilter.cpp">
+      <Filter>dialogs</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\xbmc\test\TestFileItem.cpp">
+      <Filter>test</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\xbmc\win32\pch.h">
     <ClInclude Include="..\..\xbmc\input\windows\IrssMessage.h">
       <Filter>input\windows</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\xbmc\interfaces\http-api\HttpApi.h">
-      <Filter>interfaces\http-api</Filter>
-    </ClInclude>
-    <ClInclude Include="..\..\xbmc\interfaces\http-api\XBMChttp.h">
-      <Filter>interfaces\http-api</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\xbmc\interfaces\json-rpc\AudioLibrary.h">
       <Filter>interfaces\json-rpc</Filter>
     </ClInclude>
     <ClInclude Include="..\..\xbmc\video\dialogs\GUIDialogVideoOverlay.h">
       <Filter>video\dialogs</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\xbmc\video\dialogs\GUIDialogVideoScan.h">
-      <Filter>video\dialogs</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\xbmc\video\dialogs\GUIDialogVideoSettings.h">
       <Filter>video\dialogs</Filter>
     </ClInclude>
     <ClInclude Include="..\..\xbmc\guilib\JpegIO.h">
       <Filter>guilib</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\xbmc\cores\paplayer\BXAcodec.h">
-      <Filter>cores\paplayer</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\xbmc\interfaces\info\SkinVariable.h">
       <Filter>interfaces\info</Filter>
     </ClInclude>
     <ClInclude Include="..\..\xbmc\network\httprequesthandler\IHTTPRequestHandler.h">
       <Filter>network\httprequesthandler</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\xbmc\network\httprequesthandler\HTTPApiHandler.h">
-      <Filter>network\httprequesthandler</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\xbmc\network\httprequesthandler\HTTPVfsHandler.h">
       <Filter>network\httprequesthandler</Filter>
     </ClInclude>
     <ClInclude Include="..\..\xbmc\utils\Screenshot.h">
       <Filter>utils</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\xbmc\dialogs\GUIDialogMediaFilter.h">
+      <Filter>dialogs</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="..\..\xbmc\win32\XBMC_PC.rc">
       <Filter>interfaces\swig</Filter>
     </None>
   </ItemGroup>
-</Project>
\ No newline at end of file
+</Project>
index 0ddc852..39bbb46 100644 (file)
@@ -2,5 +2,5 @@
 <node order="1" type="folder" visible="Library.HasContent(Movies)">
   <label>342</label>
   <path>videodb://1/2</path>
-  <icon>DefaultMovieTitle.png</icon>
+  <icon>DefaultMovies.png</icon>
 </node>
index dc33b15..93052a2 100644 (file)
@@ -2,5 +2,5 @@
 <node order="3" type="folder" visible="Library.HasContent(MusicVideos)">
   <label>20389</label>
   <path>videodb://3/2</path>
-  <icon>DefaultMusicVideoTitle.png</icon>
+  <icon>DefaultMusicVideos.png</icon>
 </node>
index f5d81d6..37d1487 100644 (file)
@@ -2,5 +2,5 @@
 <node order="2" type="folder" visible="Library.HasContent(TVShows)">
   <label>20343</label>
   <path>videodb://2/2</path>
-  <icon>DefaultTVShowTitle.png</icon>
+  <icon>DefaultTVShows.png</icon>
 </node>
index 8abd07f..0051c21 100644 (file)
   <peripheral vendor_product="2708:1001" bus="rpi" name="Raspberry Pi CEC Adapter" mapTo="cec">
     <setting key="enabled" type="bool" value="1" label="305" order="1" />
     <setting key="activate_source" type="bool" value="1" label="36020" order="2" />
-    <setting key="wake_devices" type="string" value="0" label="36007" order="3" />
-    <setting key="standby_devices" type="string" value="0" label="36008" order="4" />
-    <setting key="cec_standby_screensaver" type="bool" value="0" label="36009" order="5" />
-    <setting key="standby_pc_on_tv_standby" type="enum" value="13011" label="36029" order="6" lvalues="36028|13005|13011" />
-    <setting key="standby_tv_on_pc_standby" type="bool" value="1" label="36026" order="7" />
-    <setting key="send_inactive_source" type="bool" value="1" label="36025" order="8" />
+    <setting key="wake_devices" type="enum" value="36037" label="36007" lvalues="36037|36038|36039|231" order="3" />
+    <setting key="standby_devices" type="enum" value="36037" label="36008" lvalues="36037|36038|36039|231" order="4" />
+    <setting key="send_inactive_source" type="bool" value="1" label="36025" order="5" />
+    <setting key="cec_standby_screensaver" type="bool" value="0" label="36009" order="7" />
+    <setting key="standby_pc_on_tv_standby" type="enum" value="13011" label="36029" order="7" lvalues="36028|13005|13011" />
+    <setting key="standby_tv_on_pc_standby" type="bool" value="1" label="36026" order="8" />
     <setting key="use_tv_menu_language" type="bool" value="1" label="36018" order="9" />
 
     <setting key="tv_vendor" type="int" value="0" configurable="0" />
     <setting key="cec_hdmi_port" type="int" value="1" label="36015" configurable="0" />
     <setting key="connected_device" type="int" label="36019" value="0" configurable="0" />
     <setting key="port" type="string" value="" label="36022" configurable="0" />
+    <setting key="wake_devices_advanced" type="string" value="" configurable="0" />
+    <setting key="standby_devices_advanced" type="string" value="" configurable="0" />
+    <setting key="double_tap_timeout_ms" type="int" min="0" value="2000" configurable="0" />
   </peripheral>
 
   <peripheral vendor_product="2548:1001,2548:1002" bus="usb" name="Pulse-Eight CEC Adapter" mapTo="cec">
     <setting key="enabled" type="bool" value="1" label="305" order="1" />
     <setting key="activate_source" type="bool" value="1" label="36020" order="2" />
-    <setting key="wake_devices" type="string" value="0" label="36007" order="3" />
-    <setting key="standby_devices" type="string" value="0" label="36008" order="4" />
-    <setting key="cec_standby_screensaver" type="bool" value="0" label="36009" order="5" />
-    <setting key="standby_pc_on_tv_standby" type="enum" value="13011" label="36029" order="6" lvalues="36028|13005|13011" />
-    <setting key="standby_tv_on_pc_standby" type="bool" value="1" label="36026" order="7" />
-    <setting key="send_inactive_source" type="bool" value="1" label="36025" order="8" />
+    <setting key="wake_devices" type="enum" value="36037" label="36007" lvalues="36037|36038|36039|231" order="3" />
+    <setting key="standby_devices" type="enum" value="36037" label="36008" lvalues="36037|36038|36039|231" order="4" />
+    <setting key="send_inactive_source" type="bool" value="1" label="36025" order="5" />
+    <setting key="cec_standby_screensaver" type="bool" value="0" label="36009" order="6" />
+    <setting key="standby_pc_on_tv_standby" type="enum" value="13011" label="36029" order="7" lvalues="36028|13005|13011" />
+    <setting key="standby_tv_on_pc_standby" type="bool" value="1" label="36026" order="8" />
     <setting key="use_tv_menu_language" type="bool" value="1" label="36018" order="9" />
     <setting key="pause_playback_on_deactivate" type="bool" value="1" label="36033" order="10" />
-    <setting key="physical_address" type="string" label="36021" value="0" order="11" />
+    <setting key="connected_device" type="enum" label="36019" value="36037" lvalues="36037|36038" order="11" />
     <setting key="cec_hdmi_port" type="int" value="1" min="1" max="15" label="36015" order="12" />
-    <setting key="connected_device" type="int" label="36019" value="0" min="0" max="15" step="1" order="13" />
+    <setting key="physical_address" type="string" label="36021" value="0" order="13" />
     <setting key="port" type="string" value="" label="36022" order="14" />
 
     <setting key="tv_vendor" type="int" value="0" configurable="0" />
     <setting key="device_name" type="string" value="XBMC" configurable="0" />
     <setting key="device_type" type="int" value="1" configurable="0" />
+    <setting key="wake_devices_advanced" type="string" value="" configurable="0" />
+    <setting key="standby_devices_advanced" type="string" value="" configurable="0" />
+    <setting key="double_tap_timeout_ms" type="int" min="0" value="2000" configurable="0" />
   </peripheral>
 
   <peripheral vendor_product="15C2:32,15C2:33,15C2:34,15C2:35,15C2:36,15C2:37,15C2:38,15C2:39,15C2:3A,15C2:3B,15C2:3C,15C2:3D,15C2:3E,15C2:3F,15C2:41,15C2:42,15C2:43,15C2:44,15C2:45,15C2:46" bus="usb" name="iMON HID device" mapTo="imon">
diff --git a/tools/android/depends/libshairport/011_fix_ipv4_fallback.patch b/tools/android/depends/libshairport/011_fix_ipv4_fallback.patch
new file mode 100644 (file)
index 0000000..2c813f2
--- /dev/null
@@ -0,0 +1,10 @@
+--- src/socketlib.c    2012-07-14 22:49:30.000000000 +0200
++++ src/socketlib.c    2012-10-08 21:55:51.000000000 +0200
+@@ -118,6 +118,7 @@
+   int tEnable = 1;
+   setsockopt(tSock, SOL_SOCKET, SO_REUSEADDR, &tEnable, sizeof (tEnable));
++  server_addr->ai_addr->sa_family = server_addr->ai_family; // ensure that server_addr has same famliy than the socket
+   if (bind(tSock, server_addr->ai_addr, server_addr->ai_addrlen) < 0)
+   {
+     close(tSock);
index f730d6f..c8af95b 100644 (file)
@@ -34,6 +34,7 @@ $(PLATFORM): $(TARBALLS_LOCATION)/$(ARCHIVE) $(DEPS)
        cd $(PLATFORM); patch -p0 < ../008-add-missing-libs.patch
        cd $(PLATFORM); patch -p0 < ../009_fix_ipv6.patch
        cd $(PLATFORM); patch -p0 < ../010_handle_metadata.patch
+       cd $(PLATFORM); patch -p0 < ../011_fix_ipv4_fallback.patch
        cd $(PLATFORM); patch -p0 < ../android.patch
        cd $(PLATFORM); $(AUTORECONF) -vif
        cd $(PLATFORM); $(CONFIGURE)
index 354d127..6508df1 100644 (file)
@@ -24,6 +24,7 @@ $(PLATFORM): $(TARBALLS_LOCATION)/$(ARCHIVE)
          -DCMAKE_LIBRARY_PATH=$(PREFIX)/lib                 \
          -DCMAKE_INSTALL_NAME_DIR=$(PREFIX)/lib             \
          -DCMAKE_INSTALL_PREFIX=$(PREFIX)                   \
+         -DCMAKE_RANLIB=$(RANLIB)                           \
          -DCMAKE_FIND_ROOT_PATH="$(TOOLCHAIN)/sysroot/usr;$(PREFIX)" ..
 
 $(LIBDYLIB): $(PLATFORM)
index a2e145b..b1ff667 100644 (file)
@@ -1,6 +1,9 @@
 include Makefile.include
 
 BUILDTOOLS = gas-preprocessor help2man m4 autoconf automake libtool pkg-config yasm cmake sed tar dpkg swig
+ifeq ($(DARWIN), ios)
+BUILDTOOLS+= liblzo2-native libjpeg-turbo-native libpng-native libtiff-native libsdl-native libsdl_image-native
+endif
 
 SUBDIRS := \
        Backrow pcre expat gettext readline sqlite3 \
index 4cf486e..3f7bd05 100644 (file)
@@ -3,7 +3,7 @@ include ../config.site.mk
 
 # lib name, version
 LIBNAME=libcec
-VERSION=1.8.1
+VERSION=2.0.0
 SOURCE=$(LIBNAME)-$(VERSION)
 ARCHIVE=$(SOURCE).tar.gz
 
diff --git a/tools/darwin/depends/libjpeg-turbo-native/Makefile b/tools/darwin/depends/libjpeg-turbo-native/Makefile
new file mode 100644 (file)
index 0000000..f8c5979
--- /dev/null
@@ -0,0 +1,46 @@
+include ../Makefile.buildtools
+export NASM=$(TOOLCHAIN)/bin/yasm
+export CFLAGS=-I$(TOOLCHAIN)/include -fexceptions
+export LDFLAGS=-L$(TOOLCHAIN)/lib
+export CPPFLAGS=-I$(TOOLCHAIN)/include
+export CXXFLAGS=-I$(TOOLCHAIN)/include
+
+# lib name, version
+LIBNAME=libjpeg-turbo
+VERSION=1.2.0
+SOURCE=$(LIBNAME)-$(VERSION)
+ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz
+
+# configuration settings
+CONFIGURE=./configure --prefix=$(TOOLCHAIN) \
+  --with-jpeg8
+
+LIBDYLIB=$(SOURCE)/.libs/lib$(LIBNAME).dylib
+
+CLEAN_FILES=$(ARCHIVE) $(SOURCE)
+
+all: $(LIBDYLIB) .installed
+
+$(TARBALLS_LOCATION)/$(ARCHIVE):
+       $(RETRIEVE_TOOL) $(RETRIEVE_TOOL_FLAGS) $(BASE_URL)/$(ARCHIVE)
+
+$(SOURCE): $(TARBALLS_LOCATION)/$(ARCHIVE)
+       rm -rf $(SOURCE)
+       $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE)
+       echo $(SOURCE) > .gitignore
+       cd $(SOURCE); autoreconf -vif
+       cd $(SOURCE); $(CONFIGURE)
+
+$(LIBDYLIB): $(SOURCE)
+       make -j 1 -C $(SOURCE)
+
+.installed:
+       make -C $(SOURCE) install
+       touch $@
+
+clean:
+       make -C $(SOURCE) clean
+       rm -f .installed
+
+distclean::
+       rm -rf $(SOURCE) .installed
diff --git a/tools/darwin/depends/liblzo2-native/Makefile b/tools/darwin/depends/liblzo2-native/Makefile
new file mode 100644 (file)
index 0000000..e8d5c15
--- /dev/null
@@ -0,0 +1,42 @@
+include ../Makefile.buildtools
+export CFLAGS=-I$(TOOLCHAIN)/include
+export LDFLAGS=-L$(TOOLCHAIN)/lib
+export CPPFLAGS=-I$(TOOLCHAIN)/include
+export CXXFLAGS=-I$(TOOLCHAIN)/include
+
+# lib name, version
+LIBNAME=lzo
+VERSION=2.06
+SOURCE=$(LIBNAME)-$(VERSION)
+ARCHIVE=$(SOURCE).tar.gz
+
+# configuration settings
+CONFIGURE=./configure --prefix=$(TOOLCHAIN) \
+  --enable-shared=yes
+
+LIBDYLIB=$(SOURCE)/src/.libs/lib$(LIBNAME)2.dylib
+
+all: $(LIBDYLIB) .installed
+
+$(TARBALLS_LOCATION)/$(ARCHIVE):
+       $(RETRIEVE_TOOL) $(RETRIEVE_TOOL_FLAGS) $(BASE_URL)/$(ARCHIVE)
+
+$(SOURCE): $(TARBALLS_LOCATION)/$(ARCHIVE)
+       rm -rf $(SOURCE)
+       $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE)
+       echo $(SOURCE) > .gitignore
+       cd $(SOURCE); $(CONFIGURE)
+
+$(LIBDYLIB): $(SOURCE)
+       make -j $(MAKE_JOBS) -C $(SOURCE)
+
+.installed:
+       make -C $(SOURCE) install
+       touch $@
+
+clean:
+       make -C $(SOURCE) clean
+       rm -f .installed
+
+distclean::
+       rm -rf $(SOURCE) .installed
diff --git a/tools/darwin/depends/libpng-native/Makefile b/tools/darwin/depends/libpng-native/Makefile
new file mode 100644 (file)
index 0000000..1d5d9f5
--- /dev/null
@@ -0,0 +1,41 @@
+include ../Makefile.buildtools
+export CFLAGS=-I$(TOOLCHAIN)/include
+export LDFLAGS=-L$(TOOLCHAIN)/lib
+export CPPFLAGS=-I$(TOOLCHAIN)/include
+export CXXFLAGS=-I$(TOOLCHAIN)/include
+
+# lib name, version
+LIBNAME=libpng
+VERSION=1.2.38
+SOURCE=$(LIBNAME)-$(VERSION)
+ARCHIVE=$(SOURCE).tar.gz
+
+# configuration settings
+CONFIGURE=./configure --prefix=$(TOOLCHAIN)
+
+LIBDYLIB=$(SOURCE)/.libs/$(LIBNAME).dylib
+
+all: $(LIBDYLIB) .installed
+
+$(TARBALLS_LOCATION)/$(ARCHIVE):
+       $(RETRIEVE_TOOL) $(RETRIEVE_TOOL_FLAGS) $(BASE_URL)/$(ARCHIVE)
+
+$(SOURCE): $(TARBALLS_LOCATION)/$(ARCHIVE)
+       rm -rf $(SOURCE)
+       $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE)
+       echo $(SOURCE) > .gitignore
+       cd $(SOURCE); $(CONFIGURE)
+
+$(LIBDYLIB): $(SOURCE)
+       make -j $(MAKE_JOBS) -C $(SOURCE)
+
+.installed:
+       make -C $(SOURCE) install
+       touch $@
+
+clean:
+       make -C $(SOURCE) clean
+       rm -f .installed
+
+distclean::
+       rm -rf $(SOURCE) .installed
diff --git a/tools/darwin/depends/libsdl-native/01-SDL_SetWidthHeight.patch b/tools/darwin/depends/libsdl-native/01-SDL_SetWidthHeight.patch
new file mode 100644 (file)
index 0000000..0e26023
--- /dev/null
@@ -0,0 +1,33 @@
+Index: include/SDL_video.h
+===================================================================
+--- include/SDL_video.h        (revision 4116)
++++ include/SDL_video.h        (working copy)
+@@ -324,6 +324,11 @@
+ extern DECLSPEC SDL_Rect ** SDLCALL SDL_ListModes(SDL_PixelFormat *format, Uint32 flags);
+ /**
++* Alter the width and height of the current surface to the given sizes.
++*/
++extern DECLSPEC void SDLCALL SDL_SetWidthHeight(int width, int height);
++
++/**
+  * Set up a video mode with the specified width, height and bits-per-pixel.
+  *
+  * If 'bpp' is 0, it is treated as the current display bits per pixel.
+
+Index: src/video/SDL_video.c
+===================================================================
+--- src/video/SDL_video.c      (revision 4116)
++++ src/video/SDL_video.c      (working copy)
+@@ -1956,3 +1956,11 @@
+               return(0);
+       }
+ }
++
++void SDL_SetWidthHeight(int width, int height)
++{
++  if (current_video != NULL && current_video->screen != NULL) {
++    current_video->screen->w = width;
++    current_video->screen->h = height;
++  }
++}
diff --git a/tools/darwin/depends/libsdl-native/02-mmx.patch b/tools/darwin/depends/libsdl-native/02-mmx.patch
new file mode 100644 (file)
index 0000000..82f51aa
--- /dev/null
@@ -0,0 +1,12 @@
+--- src/video/mmx.h    Mon Feb 06 08:28:51 2006 +0000
++++ src/video/mmx.h    Sun Jan 30 13:38:57 2011 -0800
+@@ -355,7 +355,7 @@
+ #define       mmx_r2m(op, reg, mem) \
+       __asm__ __volatile__ (#op " %%" #reg ", %0" \
+-                            : "=X" (mem) \
++                            : "=m" (mem) \
+                             : /* nothing */ )
+ #define       mmx_r2r(op, regs, regd) \
+
diff --git a/tools/darwin/depends/libsdl-native/Makefile b/tools/darwin/depends/libsdl-native/Makefile
new file mode 100644 (file)
index 0000000..9bb4c1d
--- /dev/null
@@ -0,0 +1,45 @@
+include ../Makefile.buildtools
+export CFLAGS=-I$(TOOLCHAIN)/include
+export LDFLAGS=-L$(TOOLCHAIN)/lib
+export CPPFLAGS=-I$(TOOLCHAIN)/include
+export CXXFLAGS=-I$(TOOLCHAIN)/include
+
+# lib name, version
+LIBNAME=SDL
+VERSION=1.2.14
+SOURCE=$(LIBNAME)-$(VERSION)
+ARCHIVE=$(SOURCE).tar.gz
+
+# configuration settings
+CONFIGURE=./configure --prefix=$(TOOLCHAIN) \
+  --without-x --disable-video-x11
+
+LIBDYLIB=$(SOURCE)/.libs/$(LIBNAME).dylib
+
+all: $(LIBDYLIB) .installed
+
+$(TARBALLS_LOCATION)/$(ARCHIVE):
+       $(RETRIEVE_TOOL) $(RETRIEVE_TOOL_FLAGS) $(BASE_URL)/$(ARCHIVE)
+       echo $(ARCHIVE) > .gitignore
+
+$(SOURCE): $(TARBALLS_LOCATION)/$(ARCHIVE)
+       rm -rf $(SOURCE)
+       $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE)
+       echo $(SOURCE) > .gitignore
+       cd $(SOURCE); patch -p0 < ../01-SDL_SetWidthHeight.patch
+       cd $(SOURCE); patch -p0 < ../02-mmx.patch
+       cd $(SOURCE); $(CONFIGURE)
+
+$(LIBDYLIB): $(SOURCE)
+       make -j 1 -C $(SOURCE)
+
+.installed:
+       make -C $(SOURCE) install
+       touch $@
+
+clean:
+       make -C $(SOURCE) clean
+       rm -f .installed
+
+distclean::
+       rm -rf $(SOURCE) .installed
diff --git a/tools/darwin/depends/libsdl_image-native/Makefile b/tools/darwin/depends/libsdl_image-native/Makefile
new file mode 100644 (file)
index 0000000..786899b
--- /dev/null
@@ -0,0 +1,42 @@
+include ../Makefile.buildtools
+export CFLAGS=-I$(TOOLCHAIN)/include
+export LDFLAGS=-L$(TOOLCHAIN)/lib
+export CPPFLAGS=-I$(TOOLCHAIN)/include
+export CXXFLAGS=-I$(TOOLCHAIN)/include
+
+# lib name, version
+LIBNAME=SDL_image
+VERSION=1.2.7
+SOURCE=$(LIBNAME)-$(VERSION)
+ARCHIVE=$(SOURCE).tar.gz
+
+# configuration settings
+CONFIGURE=./configure --prefix=$(TOOLCHAIN) \
+   --disable-jpg-shared --disable-png-shared --disable-tif-shared --disable-sdltest
+
+LIBDYLIB=$(SOURCE)/.libs/$(LIBNAME).a
+
+all: $(LIBDYLIB) .installed
+
+$(TARBALLS_LOCATION)/$(ARCHIVE):
+       $(RETRIEVE_TOOL) $(RETRIEVE_TOOL_FLAGS) $(BASE_URL)/$(ARCHIVE)
+
+$(SOURCE): $(TARBALLS_LOCATION)/$(ARCHIVE)
+       rm -rf $(SOURCE)
+       $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE)
+       echo $(SOURCE) > .gitignore
+       cd $(SOURCE); $(CONFIGURE)
+
+$(LIBDYLIB): $(SOURCE)
+       make -j $(MAKE_JOBS) -C $(SOURCE)
+
+.installed:
+       make -C $(SOURCE) install
+       touch $@
+
+clean:
+       make -C $(SOURCE) clean
+       rm -f .installed
+
+distclean::
+       rm -rf $(SOURCE) .installed
diff --git a/tools/darwin/depends/libshairport/011_fix_ipv4_fallback.patch b/tools/darwin/depends/libshairport/011_fix_ipv4_fallback.patch
new file mode 100644 (file)
index 0000000..2c813f2
--- /dev/null
@@ -0,0 +1,10 @@
+--- src/socketlib.c    2012-07-14 22:49:30.000000000 +0200
++++ src/socketlib.c    2012-10-08 21:55:51.000000000 +0200
+@@ -118,6 +118,7 @@
+   int tEnable = 1;
+   setsockopt(tSock, SOL_SOCKET, SO_REUSEADDR, &tEnable, sizeof (tEnable));
++  server_addr->ai_addr->sa_family = server_addr->ai_family; // ensure that server_addr has same famliy than the socket
+   if (bind(tSock, server_addr->ai_addr, server_addr->ai_addrlen) < 0)
+   {
+     close(tSock);
index 4d9fef1..7c83316 100644 (file)
@@ -32,6 +32,7 @@ $(SOURCE): $(TARBALLS_LOCATION)/$(ARCHIVE)
        cd $(SOURCE); patch -p0 < ../008-add-missing-libs.patch
        cd $(SOURCE); patch -p0 < ../009_fix_ipv6.patch
        cd $(SOURCE); patch -p0 < ../010_handle_metadata.patch
+       cd $(SOURCE); patch -p0 < ../011_fix_ipv4_fallback.patch
        cd $(SOURCE); autoreconf -vif
        cd $(SOURCE); $(CONFIGURE)
 
diff --git a/tools/darwin/depends/libtiff-native/Makefile b/tools/darwin/depends/libtiff-native/Makefile
new file mode 100644 (file)
index 0000000..94ae0b1
--- /dev/null
@@ -0,0 +1,41 @@
+include ../Makefile.buildtools
+export CFLAGS=-I$(TOOLCHAIN)/include
+export LDFLAGS=-L$(TOOLCHAIN)/lib
+export CPPFLAGS=-I$(TOOLCHAIN)/include
+export CXXFLAGS=-I$(TOOLCHAIN)/include
+
+# lib name, version
+LIBNAME=tiff
+VERSION=3.8.2
+SOURCE=$(LIBNAME)-$(VERSION)
+ARCHIVE=$(SOURCE).tar.gz
+
+# configuration settings
+CONFIGURE=./configure --prefix=$(TOOLCHAIN)
+
+LIBDYLIB=$(SOURCE)/libtiff/.libs/lib$(LIBNAME).dylib
+
+all: $(LIBDYLIB) .installed
+
+$(TARBALLS_LOCATION)/$(ARCHIVE):
+       $(RETRIEVE_TOOL) $(RETRIEVE_TOOL_FLAGS) $(BASE_URL)/$(ARCHIVE)
+
+$(SOURCE): $(TARBALLS_LOCATION)/$(ARCHIVE)
+       rm -rf $(SOURCE)
+       $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE)
+       echo $(SOURCE) > .gitignore
+       cd $(SOURCE); $(CONFIGURE)
+
+$(LIBDYLIB): $(SOURCE)
+       make -j $(MAKE_JOBS) -C $(SOURCE)
+
+.installed:
+       make -C $(SOURCE) install
+       touch $@
+
+clean:
+       make -C $(SOURCE) clean
+       rm -f .installed
+
+distclean::
+       rm -rf $(SOURCE) .installed
index 4578390..d24fbc6 100644 (file)
@@ -5,7 +5,7 @@ XBMC_ADDONSDIR=../../../../addons
 
 # lib name, version
 LIBNAME=xbmc-pvr-addons
-VERSION=9e7a5ba2c1b9c32fbb79063c2466122dd2d2aa53
+VERSION=4904df3552a5762811b51d63ff9087756544d4cc
 SOURCE=$(LIBNAME)-$(VERSION)
 ARCHIVE=$(SOURCE).tar.gz
 
index f43f958..10095f1 100644 (file)
@@ -2,6 +2,13 @@ include ../Makefile.include
 
 SOURCE=../../../../
 
+ifeq ($(DARWIN), ios)
+include ../Makefile.buildtools
+export USE_TEXTUREPACKER_NATIVE_ROOT=$(TOOLCHAIN)
+else
+export USE_TEXTUREPACKER_NATIVE_ROOT=$(PREFIX)
+endif
+
 # configuration settings
 export PATH:=$(TOOLCHAIN)/bin:$(PREFIX)/bin:$(PATH)
 CONFIGURE=./configure --prefix=$(PREFIX) \
diff --git a/tools/rbp/depends/libshairport/011_fix_ipv4_fallback.patch b/tools/rbp/depends/libshairport/011_fix_ipv4_fallback.patch
new file mode 100644 (file)
index 0000000..2c813f2
--- /dev/null
@@ -0,0 +1,10 @@
+--- src/socketlib.c    2012-07-14 22:49:30.000000000 +0200
++++ src/socketlib.c    2012-10-08 21:55:51.000000000 +0200
+@@ -118,6 +118,7 @@
+   int tEnable = 1;
+   setsockopt(tSock, SOL_SOCKET, SO_REUSEADDR, &tEnable, sizeof (tEnable));
++  server_addr->ai_addr->sa_family = server_addr->ai_family; // ensure that server_addr has same famliy than the socket
+   if (bind(tSock, server_addr->ai_addr, server_addr->ai_addrlen) < 0)
+   {
+     close(tSock);
index 7993c0d..59c93d5 100644 (file)
@@ -30,8 +30,9 @@ $(SOURCE): $(TARBALLS_LOCATION)/$(ARCHIVE)
        cd $(SOURCE); patch -p0 < ../006_no_printf.patch
        cd $(SOURCE); patch -p0 < ../007_fix_syslog_defines.patch
        cd $(SOURCE); patch -p0 < ../008-add-missing-libs.patch
-       #cd $(SOURCE); patch -p0 < ../009_fix_ipv6.patch
+       cd $(SOURCE); patch -p0 < ../009_fix_ipv6.patch
        cd $(SOURCE); patch -p0 < ../010_handle_metadata.patch
+       cd $(SOURCE); patch -p0 < ../011_fix_ipv4_fallback.patch
        cd $(SOURCE); autoreconf -vif
        cd $(SOURCE); $(CONFIGURE)
 
index f85326e..7563160 100644 (file)
@@ -39,9 +39,6 @@
 #include "network/WebServer.h"
 #include "network/httprequesthandler/HTTPImageHandler.h"
 #include "network/httprequesthandler/HTTPVfsHandler.h"
-#ifdef HAS_HTTPAPI
-#include "network/httprequesthandler/HTTPApiHandler.h"
-#endif
 #ifdef HAS_JSONRPC
 #include "network/httprequesthandler/HTTPJsonRpcHandler.h"
 #endif
 #ifdef HAS_DBUS
 #include <dbus/dbus.h>
 #endif
-#ifdef HAS_HTTPAPI
-#include "interfaces/http-api/XBMChttp.h"
-#endif
 #ifdef HAS_JSONRPC
 #include "interfaces/json-rpc/JSONRPC.h"
 #include "network/TCPServer.h"
 #include "video/dialogs/GUIDialogVideoOSD.h"
 #include "music/dialogs/GUIDialogMusicOverlay.h"
 #include "video/dialogs/GUIDialogVideoOverlay.h"
+#include "video/VideoInfoScanner.h"
 
 // Dialog includes
 #include "music/dialogs/GUIDialogMusicOSD.h"
 #include "settings/GUIDialogProfileSettings.h"
 #include "settings/GUIDialogLockSettings.h"
 #include "settings/GUIDialogContentSettings.h"
-#include "video/dialogs/GUIDialogVideoScan.h"
 #include "dialogs/GUIDialogBusy.h"
 #include "dialogs/GUIDialogKeyboardGeneric.h"
 #include "dialogs/GUIDialogYesNo.h"
 #include "guilib/GUIControlFactory.h"
 #include "dialogs/GUIDialogCache.h"
 #include "dialogs/GUIDialogPlayEject.h"
+#include "dialogs/GUIDialogMediaFilter.h"
 #include "utils/XMLUtils.h"
 #include "addons/AddonInstaller.h"
 
@@ -382,9 +377,6 @@ CApplication::CApplication(void)
 #ifdef HAS_JSONRPC
   , m_httpJsonRpcHandler(*new CHTTPJsonRpcHandler)
 #endif
-#ifdef HAS_HTTPAPI
-  , m_httpApiHandler(*new CHTTPApiHandler)
-#endif
 #ifdef HAS_WEB_INTERFACE
   , m_httpWebinterfaceHandler(*new CHTTPWebinterfaceHandler)
   , m_httpWebinterfaceAddonsHandler(*new CHTTPWebinterfaceAddonsHandler)
@@ -455,9 +447,6 @@ CApplication::~CApplication(void)
   delete &m_WebServer;
   delete &m_httpImageHandler;
   delete &m_httpVfsHandler;
-#ifdef HAS_HTTPAPI
-  delete &m_httpApiHandler;
-#endif
 #ifdef HAS_JSONRPC
   delete &m_httpJsonRpcHandler;
 #endif
@@ -928,12 +917,13 @@ bool CApplication::InitWindow()
   }
   // set GUI res and force the clear of the screen
   g_graphicsContext.SetVideoResolution(g_guiSettings.m_LookAndFeelResolution);
+  g_fontManager.ReloadTTFFonts();
   return true;
 }
 
 bool CApplication::DestroyWindow()
 {
-  g_Windowing.DestroyRenderSystem();
+  g_fontManager.UnloadTTFFonts();
   return g_Windowing.DestroyWindow();
 }
 
@@ -1211,9 +1201,6 @@ bool CApplication::Initialize()
 #ifdef HAS_JSONRPC
   CWebServer::RegisterRequestHandler(&m_httpJsonRpcHandler);
 #endif
-#ifdef HAS_HTTPAPI
-  CWebServer::RegisterRequestHandler(&m_httpApiHandler);
-#endif
 #ifdef HAS_WEB_INTERFACE
   CWebServer::RegisterRequestHandler(&m_httpWebinterfaceAddonsHandler);
   CWebServer::RegisterRequestHandler(&m_httpWebinterfaceHandler);
@@ -1278,7 +1265,6 @@ bool CApplication::Initialize()
     g_windowManager.Add(new CGUIDialogNetworkSetup);  // window id = 128
     g_windowManager.Add(new CGUIDialogMediaSource);   // window id = 129
     g_windowManager.Add(new CGUIDialogProfileSettings); // window id = 130
-    g_windowManager.Add(new CGUIDialogVideoScan);      // window id = 133
     g_windowManager.Add(new CGUIDialogFavourites);     // window id = 134
     g_windowManager.Add(new CGUIDialogSongInfo);       // window id = 135
     g_windowManager.Add(new CGUIDialogSmartPlaylistEditor);       // window id = 136
@@ -1299,6 +1285,8 @@ bool CApplication::Initialize()
 
     g_windowManager.Add(new CGUIDialogPeripheralManager);
     g_windowManager.Add(new CGUIDialogPeripheralSettings);
+    
+    g_windowManager.Add(new CGUIDialogMediaFilter);   // window id = 151
 
     g_windowManager.Add(new CGUIWindowMusicPlayList);          // window id = 500
     g_windowManager.Add(new CGUIWindowMusicSongs);             // window id = 501
@@ -1535,17 +1523,10 @@ bool CApplication::StartWebServer()
 #ifdef HAS_WEB_INTERFACE
       CZeroconf::GetInstance()->PublishService("servers.webserver", "_http._tcp", g_infoManager.GetLabel(SYSTEM_FRIENDLY_NAME), webPort, txt);
 #endif
-#ifdef HAS_HTTPAPI
-      CZeroconf::GetInstance()->PublishService("servers.webapi", "_xbmc-web._tcp", g_infoManager.GetLabel(SYSTEM_FRIENDLY_NAME), webPort, txt);
-#endif
 #ifdef HAS_JSONRPC
       CZeroconf::GetInstance()->PublishService("servers.jsonrpc-http", "_xbmc-jsonrpc-h._tcp", g_infoManager.GetLabel(SYSTEM_FRIENDLY_NAME), webPort, txt);
 #endif
     }
-#ifdef HAS_HTTPAPI
-    if (g_settings.m_HttpApiBroadcastLevel >= 1)
-      CApplicationMessenger::Get().HttpApi("broadcastlevel; StartUp;1");
-#endif
 
     return started;
   }
@@ -2592,16 +2573,6 @@ bool CApplication::OnAppCommand(const CAction &action)
 
 bool CApplication::OnAction(const CAction &action)
 {
-#ifdef HAS_HTTPAPI
-  // Let's tell the outside world about this action, ignoring mouse moves
-  if (g_settings.m_HttpApiBroadcastLevel>=2 && action.GetID() != ACTION_MOUSE_MOVE)
-  {
-    CStdString tmp;
-    tmp.Format("%i",action.GetID());
-    CApplicationMessenger::Get().HttpApi("broadcastlevel; OnAction:"+tmp+";2");
-  }
-#endif
-
   // special case for switching between GUI & fullscreen mode.
   if (action.GetID() == ACTION_SHOW_GUI)
   { // Switch to fullscreen mode if we can
@@ -2753,7 +2724,7 @@ bool CApplication::OnAction(const CAction &action)
     return true;
   }
 
-  if (IsPlaying() && !CurrentFileItem().IsLiveTV())
+  if (IsPlaying())
   {
     // pause : pauses current audio song
     if (action.GetID() == ACTION_PAUSE && m_iPlaySpeed == 1)
@@ -2954,7 +2925,7 @@ void CApplication::FrameMove(bool processEvents, bool processGUI)
     // never set a frametime less than 2 fps to avoid problems when debuggin and on breaks
     if( frameTime > 0.5 ) frameTime = 0.5;
 
-    if (processGUI)
+    if (processGUI && m_renderGUI)
     {
       g_graphicsContext.Lock();
       // check if there are notifications to display
@@ -2978,19 +2949,18 @@ void CApplication::FrameMove(bool processEvents, bool processGUI)
 #endif
 
     // process input actions
-    ProcessHTTPApiButtons();
     ProcessJsonRpcButtons();
     ProcessRemote(frameTime);
     ProcessGamepad(frameTime);
     ProcessEventServer(frameTime);
     ProcessPeripherals(frameTime);
-    if (processGUI)
+    if (processGUI && m_renderGUI)
     {
       m_pInertialScrollingHandler->ProcessInertialScroll(frameTime);
       m_seekHandler->Process();
     }
   }
-  if (processGUI)
+  if (processGUI && m_renderGUI)
   {
     if (!m_bStop)
       g_windowManager.Process(CTimeUtils::GetFrameTime());
@@ -3172,79 +3142,6 @@ bool CApplication::ProcessMouse()
                           mouseaction.GetName()));
 }
 
-void  CApplication::CheckForTitleChange()
-{
-#ifdef HAS_HTTPAPI
-  if (g_settings.m_HttpApiBroadcastLevel>=1)
-  {
-    if (IsPlayingVideo())
-    {
-      const CVideoInfoTag* tagVal = g_infoManager.GetCurrentMovieTag();
-      if (m_pXbmcHttp && tagVal && !(tagVal->m_strTitle.IsEmpty()))
-      {
-        CStdString msg=m_pXbmcHttp->GetOpenTag()+"MovieTitle:"+tagVal->m_strTitle+m_pXbmcHttp->GetCloseTag();
-        if (m_prevMedia!=msg && g_settings.m_HttpApiBroadcastLevel>=1)
-        {
-          CApplicationMessenger::Get().HttpApi("broadcastlevel; MediaChanged:"+msg+";1");
-          m_prevMedia=msg;
-        }
-      }
-    }
-    else if (IsPlayingAudio())
-    {
-      const CMusicInfoTag* tagVal=g_infoManager.GetCurrentSongTag();
-      if (m_pXbmcHttp && tagVal)
-      {
-        CStdString msg="";
-        if (!tagVal->GetTitle().IsEmpty())
-          msg=m_pXbmcHttp->GetOpenTag()+"AudioTitle:"+tagVal->GetTitle()+m_pXbmcHttp->GetCloseTag();
-        if (!tagVal->GetArtist().empty())
-          msg+=m_pXbmcHttp->GetOpenTag()+"AudioArtist:"+StringUtils::Join(tagVal->GetArtist(), g_advancedSettings.m_musicItemSeparator)+m_pXbmcHttp->GetCloseTag();
-        if (m_prevMedia!=msg)
-        {
-          CApplicationMessenger::Get().HttpApi("broadcastlevel; MediaChanged:"+msg+";1");
-          m_prevMedia=msg;
-        }
-      }
-    }
-  }
-#endif
-}
-
-bool CApplication::ProcessHTTPApiButtons()
-{
-#ifdef HAS_HTTPAPI
-  if (m_pXbmcHttp)
-  {
-    // copy key from webserver, and reset it in case we're called again before
-    // whatever happens in OnKey()
-    CKey keyHttp(m_pXbmcHttp->GetKey());
-    m_pXbmcHttp->ResetKey();
-    if (keyHttp.GetButtonCode() != KEY_INVALID)
-    {
-      if (keyHttp.GetButtonCode() == KEY_VMOUSE) //virtual mouse
-      {
-        int actionID = ACTION_MOUSE_MOVE;
-        if (keyHttp.GetLeftTrigger() == 1)
-          actionID = ACTION_MOUSE_LEFT_CLICK;
-        else if (keyHttp.GetLeftTrigger() == 2)
-          actionID = ACTION_MOUSE_RIGHT_CLICK;
-        else if (keyHttp.GetLeftTrigger() == 3)
-          actionID = ACTION_MOUSE_MIDDLE_CLICK;
-        else if (keyHttp.GetRightTrigger() == 1)
-          actionID = ACTION_MOUSE_DOUBLE_CLICK;
-        CAction action(actionID, keyHttp.GetLeftThumbX(), keyHttp.GetLeftThumbY());
-        OnAction(action);
-      }
-      else
-        OnKey(keyHttp);
-      return true;
-    }
-  }
-#endif
-  return false;
-}
-
 bool CApplication::ProcessJsonRpcButtons()
 {
 #ifdef HAS_JSONRPC
@@ -3465,7 +3362,6 @@ bool CApplication::Cleanup()
     g_windowManager.Delete(WINDOW_DIALOG_VIDEO_OSD_SETTINGS);
     g_windowManager.Delete(WINDOW_DIALOG_AUDIO_OSD_SETTINGS);
     g_windowManager.Delete(WINDOW_DIALOG_VIDEO_BOOKMARKS);
-    g_windowManager.Delete(WINDOW_DIALOG_VIDEO_SCAN);
     g_windowManager.Delete(WINDOW_DIALOG_CONTENT_SETTINGS);
     g_windowManager.Delete(WINDOW_DIALOG_FAVOURITES);
     g_windowManager.Delete(WINDOW_DIALOG_SONG_INFO);
@@ -3477,6 +3373,7 @@ bool CApplication::Cleanup()
     g_windowManager.Delete(WINDOW_DIALOG_ADDON_SETTINGS);
     g_windowManager.Delete(WINDOW_DIALOG_ACCESS_POINTS);
     g_windowManager.Delete(WINDOW_DIALOG_SLIDER);
+    g_windowManager.Delete(WINDOW_DIALOG_MEDIA_FILTER);
 
     /* Delete PVR related windows and dialogs */
     g_windowManager.Delete(WINDOW_PVR);
@@ -3604,16 +3501,6 @@ void CApplication::Stop(int exitCode)
 
     g_alarmClock.StopThread();
 
-#ifdef HAS_HTTPAPI
-    if (m_pXbmcHttp)
-    {
-      if (g_settings.m_HttpApiBroadcastLevel >= 1)
-        CApplicationMessenger::Get().HttpApi("broadcastlevel; ShutDown;1");
-
-      m_pXbmcHttp->shuttingDown = true;
-    }
-#endif
-
     if( m_bSystemScreenSaverEnable )
       g_Windowing.EnableSystemScreenSaver(true);
 
@@ -3654,9 +3541,6 @@ void CApplication::Stop(int exitCode)
 #ifdef HAS_JSONRPC
   CWebServer::UnregisterRequestHandler(&m_httpJsonRpcHandler);
 #endif
-#ifdef HAS_HTTPAPI
-  CWebServer::UnregisterRequestHandler(&m_httpApiHandler);
-#endif
 #ifdef HAS_WEB_INTERFACE
   CWebServer::UnregisterRequestHandler(&m_httpWebinterfaceAddonsHandler);
   CWebServer::UnregisterRequestHandler(&m_httpWebinterfaceHandler);
@@ -4301,12 +4185,6 @@ void CApplication::OnPlayBackEnded()
   g_pythonParser.OnPlayBackEnded();
 #endif
 
-#ifdef HAS_HTTPAPI
-  // Let's tell the outside world as well
-  if (g_settings.m_HttpApiBroadcastLevel>=1)
-    CApplicationMessenger::Get().HttpApi("broadcastlevel; OnPlayBackEnded;1");
-#endif
-
   CVariant data(CVariant::VariantTypeObject);
   data["end"] = true;
   CAnnouncementManager::Announce(Player, "xbmc", "OnStop", m_itemCurrentFile, data);
@@ -4335,12 +4213,6 @@ void CApplication::OnPlayBackStarted()
   g_pythonParser.OnPlayBackStarted();
 #endif
 
-#ifdef HAS_HTTPAPI
-  // Let's tell the outside world as well
-  if (g_settings.m_HttpApiBroadcastLevel>=1)
-    CApplicationMessenger::Get().HttpApi("broadcastlevel; OnPlayBackStarted;1");
-#endif
-
   CGUIMessage msg(GUI_MSG_PLAYBACK_STARTED, 0, 0);
   g_windowManager.SendThreadMessage(msg);
 }
@@ -4353,12 +4225,6 @@ void CApplication::OnQueueNextItem()
   g_pythonParser.OnQueueNextItem(); // currently unimplemented
 #endif
 
-#ifdef HAS_HTTPAPI
-  // Let's tell the outside world as well
-  if (g_settings.m_HttpApiBroadcastLevel>=1)
-    CApplicationMessenger::Get().HttpApi("broadcastlevel; OnQueueNextItem;1");
-#endif
-
   if(IsPlayingAudio())
   {
     CLastfmScrobbler::GetInstance()->SubmitQueue();
@@ -4383,12 +4249,6 @@ void CApplication::OnPlayBackStopped()
   g_pythonParser.OnPlayBackStopped();
 #endif
 
-#ifdef HAS_HTTPAPI
-  // Let's tell the outside world as well
-  if (g_settings.m_HttpApiBroadcastLevel>=1)
-    CApplicationMessenger::Get().HttpApi("broadcastlevel; OnPlayBackStopped;1");
-#endif
-
   CVariant data(CVariant::VariantTypeObject);
   data["end"] = false;
   CAnnouncementManager::Announce(Player, "xbmc", "OnStop", m_itemCurrentFile, data);
@@ -4406,12 +4266,6 @@ void CApplication::OnPlayBackPaused()
   g_pythonParser.OnPlayBackPaused();
 #endif
 
-#ifdef HAS_HTTPAPI
-  // Let's tell the outside world as well
-  if (g_settings.m_HttpApiBroadcastLevel>=1)
-    CApplicationMessenger::Get().HttpApi("broadcastlevel; OnPlayBackPaused;1");
-#endif
-
   CVariant param;
   param["player"]["speed"] = 0;
   param["player"]["playerid"] = g_playlistPlayer.GetCurrentPlaylist();
@@ -4424,12 +4278,6 @@ void CApplication::OnPlayBackResumed()
   g_pythonParser.OnPlayBackResumed();
 #endif
 
-#ifdef HAS_HTTPAPI
-  // Let's tell the outside world as well
-  if (g_settings.m_HttpApiBroadcastLevel>=1)
-    CApplicationMessenger::Get().HttpApi("broadcastlevel; OnPlayBackResumed;1");
-#endif
-
   CVariant param;
   param["player"]["speed"] = 1;
   param["player"]["playerid"] = g_playlistPlayer.GetCurrentPlaylist();
@@ -4442,16 +4290,6 @@ void CApplication::OnPlayBackSpeedChanged(int iSpeed)
   g_pythonParser.OnPlayBackSpeedChanged(iSpeed);
 #endif
 
-#ifdef HAS_HTTPAPI
-  // Let's tell the outside world as well
-  if (g_settings.m_HttpApiBroadcastLevel>=1)
-  {
-    CStdString tmp;
-    tmp.Format("broadcastlevel; OnPlayBackSpeedChanged:%i;1",iSpeed);
-    CApplicationMessenger::Get().HttpApi(tmp);
-  }
-#endif
-
   CVariant param;
   param["player"]["speed"] = iSpeed;
   param["player"]["playerid"] = g_playlistPlayer.GetCurrentPlaylist();
@@ -4464,16 +4302,6 @@ void CApplication::OnPlayBackSeek(int iTime, int seekOffset)
   g_pythonParser.OnPlayBackSeek(iTime, seekOffset);
 #endif
 
-#ifdef HAS_HTTPAPI
-  // Let's tell the outside world as well
-  if (g_settings.m_HttpApiBroadcastLevel>=1)
-  {
-    CStdString tmp;
-    tmp.Format("broadcastlevel; OnPlayBackSeek:%i;1",iTime);
-    CApplicationMessenger::Get().HttpApi(tmp);
-  }
-#endif
-
   CVariant param;
   CJSONUtils::MillisecondsToTimeObject(iTime, param["player"]["time"]);
   CJSONUtils::MillisecondsToTimeObject(seekOffset, param["player"]["seekoffset"]);;
@@ -4488,16 +4316,6 @@ void CApplication::OnPlayBackSeekChapter(int iChapter)
 #ifdef HAS_PYTHON
   g_pythonParser.OnPlayBackSeekChapter(iChapter);
 #endif
-
-#ifdef HAS_HTTPAPI
-  // Let's tell the outside world as well
-  if (g_settings.m_HttpApiBroadcastLevel>=1)
-  {
-    CStdString tmp;
-    tmp.Format("broadcastlevel; OnPlayBackSkeekChapter:%i;1",iChapter);
-    CApplicationMessenger::Get().HttpApi(tmp);
-  }
-#endif
 }
 
 bool CApplication::IsPlaying() const
@@ -5342,9 +5160,6 @@ void CApplication::ProcessSlow()
     UPNP::CUPnP::GetInstance()->UpdateState();
 #endif
 
-  //Check to see if current playing Title has changed and whether we should broadcast the fact
-  CheckForTitleChange();
-
 #if defined(_LINUX) && defined(HAS_FILESYSTEM_SMB)
   smb.CheckIfIdle();
 #endif
@@ -5857,15 +5672,8 @@ void CApplication::StartVideoScan(const CStdString &strDirectory, bool scanAll)
   if (m_videoInfoScanner->IsScanning())
     return;
 
-  if (!g_guiSettings.GetBool("videolibrary.backgroundupdate"))
-  {
-    CGUIDialogVideoScan *videoScan = (CGUIDialogVideoScan *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
-    if (videoScan)
-    {
-      m_videoInfoScanner->SetObserver(videoScan);
-      videoScan->ShowScan();
-    }
-  }
+  m_videoInfoScanner->ShowDialog(true);
+
   m_videoInfoScanner->Start(strDirectory,scanAll);
 }
 
@@ -6029,6 +5837,13 @@ bool CApplication::IsPresentFrame()
   return ret;
 }
 
+void CApplication::SetRenderGUI(bool renderGUI)
+{
+  if (renderGUI && ! m_renderGUI)
+    g_windowManager.MarkDirty();
+  m_renderGUI = renderGUI;
+}
+
 #if defined(HAS_LINUX_NETWORK)
 CNetworkLinux& CApplication::getNetwork()
 {
index 12dd8e2..58b093a 100644 (file)
@@ -75,9 +75,6 @@ class CHTTPVfsHandler;
 #ifdef HAS_JSONRPC
 class CHTTPJsonRpcHandler;
 #endif
-#ifdef HAS_HTTPAPI
-class CHTTPApiHandler;
-#endif
 #ifdef HAS_WEB_INTERFACE
 class CHTTPWebinterfaceHandler;
 class CHTTPWebinterfaceAddonsHandler;
@@ -203,7 +200,6 @@ public:
   void CheckScreenSaverAndDPMS();
   void CheckPlayingProgress();
   void CheckAudioScrobblerStatus();
-  void CheckForTitleChange();
   void ActivateScreenSaver(bool forceType = false);
 
   virtual void Process();
@@ -294,9 +290,6 @@ public:
 #ifdef HAS_JSONRPC
   CHTTPJsonRpcHandler& m_httpJsonRpcHandler;
 #endif
-#ifdef HAS_HTTPAPI
-  CHTTPApiHandler& m_httpApiHandler;
-#endif
 #ifdef HAS_WEB_INTERFACE
   CHTTPWebinterfaceHandler& m_httpWebinterfaceHandler;
   CHTTPWebinterfaceAddonsHandler& m_httpWebinterfaceAddonsHandler;
@@ -371,6 +364,7 @@ public:
   bool SwitchToFullScreen();
 
   CSplash* GetSplash() { return m_splash; }
+  void SetRenderGUI(bool renderGUI);
 protected:
   bool LoadSkin(const CStdString& skinID);
   void LoadSkin(const boost::shared_ptr<ADDON::CSkinInfo>& skin);
@@ -452,7 +446,6 @@ protected:
   bool ProcessGamepad(float frameTime);
   bool ProcessEventServer(float frameTime);
   bool ProcessPeripherals(float frameTime);
-  bool ProcessHTTPApiButtons();
   bool ProcessJsonRpcButtons();
   bool ProcessJoystickEvent(const std::string& joystickName, int button, bool isAxis, float fAmount, unsigned int holdTime = 0);
   int  GetActiveWindowID(void);
index 3e59489..1e5ff8c 100644 (file)
 #include "guilib/LocalizeStrings.h"
 #include "threads/SingleLock.h"
 
-#ifdef HAS_HTTPAPI
-#include "interfaces/http-api/XBMChttp.h"
-#endif
-
 #include "playlists/PlayList.h"
 #include "FileItem.h"
 
@@ -539,39 +535,6 @@ void CApplicationMessenger::ProcessMessage(ThreadMessage *pMsg)
       }
       break;
 
-    case TMSG_HTTPAPI:
-    {
-#ifdef HAS_HTTPAPI
-      if (!m_pXbmcHttp)
-      {
-        m_pXbmcHttp = new CXbmcHttp();
-      }
-      switch (m_pXbmcHttp->xbmcCommand(pMsg->strParam))
-      {
-        case 1:
-          Restart();
-          break;
-
-        case 2:
-          Shutdown();
-          break;
-
-        case 3:
-          Quit();
-          break;
-
-        case 4:
-          Reset();
-          break;
-
-        case 5:
-          RestartApp();
-          break;
-      }
-#endif
-    }
-    break;
-
     case TMSG_EXECUTE_SCRIPT:
 #ifdef HAS_PYTHON
       g_pythonParser.evalFile(pMsg->strParam.c_str(),ADDON::AddonPtr());
@@ -803,13 +766,14 @@ void CApplicationMessenger::ProcessMessage(ThreadMessage *pMsg)
     case TMSG_DISPLAY_SETUP:
     {
       *((bool*)pMsg->lpVoid) = g_application.InitWindow();
-      g_application.ReloadSkin();
+      g_application.SetRenderGUI(true);
     }
     break;
     
     case TMSG_DISPLAY_DESTROY:
     {
       *((bool*)pMsg->lpVoid) = g_application.DestroyWindow();
+      g_application.SetRenderGUI(false);
     }
     break;
 
@@ -871,14 +835,6 @@ CStdString CApplicationMessenger::GetResponse()
   return tmp;
 }
 
-void CApplicationMessenger::HttpApi(string cmd, bool wait)
-{
-  SetResponse("");
-  ThreadMessage tMsg = {TMSG_HTTPAPI};
-  tMsg.strParam = cmd;
-  SendMessage(tMsg, wait);
-}
-
 void CApplicationMessenger::ExecBuiltIn(const CStdString &command, bool wait)
 {
   ThreadMessage tMsg = {TMSG_EXECUTE_BUILT_IN};
index 5957a82..f05be13 100644 (file)
@@ -88,8 +88,6 @@ namespace MUSIC_INFO
 #define TMSG_RENDERER_FLUSH       312
 #define TMSG_INHIBITIDLESHUTDOWN  313
 
-#define TMSG_HTTPAPI              400
-
 #define TMSG_NETWORKMESSAGE         500
 
 #define TMSG_GUI_DO_MODAL             600
@@ -206,7 +204,6 @@ public:
 
   CStdString GetResponse();
   int SetResponse(CStdString response);
-  void HttpApi(std::string cmd, bool wait = false);
   void ExecBuiltIn(const CStdString &command, bool wait = false);
 
   void NetworkMessage(DWORD dwMessage, DWORD dwParam = 0);
index b8071b5..f32de1f 100644 (file)
@@ -125,7 +125,7 @@ bool CAutoSwitch::ByFolders(const CFileItemList& vecItems)
     for (int i = 0; i < vecItems.Size(); i++)
     {
       const CFileItemPtr pItem = vecItems[i];
-      if (pItem->HasThumbnail())
+      if (pItem->HasArt("thumb"))
       {
         bThumbs = true;
         break;
@@ -156,7 +156,7 @@ bool CAutoSwitch::ByFiles(bool bHideParentDirItems, const CFileItemList& vecItem
     for (int i = 0; i < vecItems.Size(); i++)
     {
       const CFileItemPtr pItem = vecItems[i];
-      if (pItem->HasThumbnail())
+      if (pItem->HasArt("thumb"))
       {
         bThumbs = true;
         break;
@@ -185,7 +185,7 @@ bool CAutoSwitch::ByThumbPercent(bool bHideParentDirItems, int iPercent, const C
   for (int i = 0; i < vecItems.Size(); i++)
   {
     const CFileItemPtr pItem = vecItems[i];
-    if (pItem->HasThumbnail())
+    if (pItem->HasArt("thumb"))
     {
       iNumThumbs++;
       float fTempPercent = ( (float)iNumThumbs / (float)iNumItems ) * (float)100;
@@ -226,7 +226,7 @@ bool CAutoSwitch::ByFolderThumbPercentage(bool hideParentDirItems, int percent,
   for (int i = 0; i < vecItems.Size(); i++)
   {
     const CFileItemPtr item = vecItems[i];
-    if (item->m_bIsFolder && item->HasThumbnail())
+    if (item->m_bIsFolder && item->HasArt("thumb"))
     {
       numThumbs++;
       if (numThumbs >= 0.01f * percent * (numItems - fileCount))
index 4a70e59..c7d7b32 100644 (file)
@@ -39,6 +39,7 @@ public:
   const std::string& GetType() const { return m_type; }
   void AppendPath(const std::string &subPath);
 
+  virtual void AddOption(const std::string &key, const char *value) { CUrlOptions::AddOption(key, value); updateOptions(); }
   virtual void AddOption(const std::string &key, const std::string &value) { CUrlOptions::AddOption(key, value); updateOptions(); }
   virtual void AddOption(const std::string &key, int value) { CUrlOptions::AddOption(key, value); updateOptions(); }
   virtual void AddOption(const std::string &key, float value) { CUrlOptions::AddOption(key, value); updateOptions(); }
index 1a98157..f821ac4 100644 (file)
@@ -78,7 +78,7 @@ bool CFavourites::LoadFavourites(CStdString& strPath, CFileItemList& items)
       {
         CFileItemPtr item(new CFileItem(name));
         item->SetPath(favourite->FirstChild()->Value());
-        if (thumb) item->SetThumbnailImage(thumb);
+        if (thumb) item->SetArt("thumb", thumb);
         items.Add(item);
       }
     }
@@ -100,8 +100,8 @@ bool CFavourites::Save(const CFileItemList &items)
     const CFileItemPtr item = items[i];
     TiXmlElement favNode("favourite");
     favNode.SetAttribute("name", item->GetLabel().c_str());
-    if (item->HasThumbnail())
-      favNode.SetAttribute("thumb", item->GetThumbnailImage().c_str());
+    if (item->HasArt("thumb"))
+      favNode.SetAttribute("thumb", item->GetArt("thumb").c_str());
     TiXmlText execute(item->GetPath());
     favNode.InsertEndChild(execute);
     rootNode->InsertEndChild(favNode);
@@ -131,7 +131,7 @@ bool CFavourites::AddOrRemove(CFileItem *item, int contextWindow)
     CFileItemPtr favourite(new CFileItem(item->GetLabel()));
     if (item->GetLabel().IsEmpty())
       favourite->SetLabel(CUtil::GetTitleFromPath(item->GetPath(), item->m_bIsFolder));
-    favourite->SetThumbnailImage(item->GetThumbnailImage());
+    favourite->SetArt("thumb", item->GetArt("thumb"));
     favourite->SetPath(executePath);
     items.Add(favourite);
   }
index f36d1ce..09be35c 100644 (file)
@@ -82,7 +82,7 @@ CFileItem::CFileItem(const CSong& song)
   m_lStartPartNumber = 1;
   SetProperty("item_start", song.iStartOffset);
   m_lEndOffset = song.iEndOffset;
-  m_strThumbnailImage = song.strThumb;
+  SetArt("thumb", song.strThumb);
 }
 
 CFileItem::CFileItem(const CStdString &path, const CAlbum& album)
@@ -169,10 +169,7 @@ CFileItem::CFileItem(const CEpgInfoTag& tag)
   m_dateTime = tag.StartAsLocalTime();
 
   if (!tag.Icon().IsEmpty())
-  {
-    SetThumbnailImage(tag.Icon());
     SetIconImage(tag.Icon());
-  }
 }
 
 CFileItem::CFileItem(const CPVRChannel& channel)
@@ -217,10 +214,7 @@ CFileItem::CFileItem(const CPVRChannel& channel)
   }
 
   if (!channel.IconPath().IsEmpty())
-  {
-    SetThumbnailImage(channel.IconPath());
     SetIconImage(channel.IconPath());
-  }
 
   SetProperty("channelid", channel.ChannelID());
   SetProperty("path", channel.Path());
@@ -265,10 +259,7 @@ CFileItem::CFileItem(const CPVRTimerInfoTag& timer)
   m_dateTime = timer.StartAsLocalTime();
 
   if (!timer.ChannelIcon().IsEmpty())
-  {
-    SetThumbnailImage(timer.ChannelIcon());
     SetIconImage(timer.ChannelIcon());
-  }
 }
 
 CFileItem::CFileItem(const CArtist& artist)
@@ -398,7 +389,7 @@ CFileItem::CFileItem(const CMediaSource& share)
   m_iHasLock = share.m_iHasLock;
   m_iBadPwdCount = share.m_iBadPwdCount;
   m_iDriveType = share.m_iDriveType;
-  m_strThumbnailImage = share.m_strThumbnailImage;
+  SetArt("thumb", share.m_strThumbnailImage);
   SetLabelPreformated(true);
   if (IsDVD())
     GetVideoInfoTag()->m_strFileNameAndPath = share.strDiskUniqueId; // share.strDiskUniqueId contains disc unique id
@@ -1200,7 +1191,7 @@ bool CFileItem::IsReadOnly() const
 {
   if (IsParentFolder()) return true;
   if (m_bIsShareOrDrive) return true;
-  return !CUtil::SupportsFileOperations(m_strPath);
+  return !CUtil::SupportsWriteFileOperations(m_strPath);
 }
 
 void CFileItem::FillInDefaultIcon()
@@ -1472,8 +1463,8 @@ void CFileItem::UpdateInfo(const CFileItem &item, bool replaceLabels /*=true*/)
     SetLabel(item.GetLabel());
   if (replaceLabels && !item.GetLabel2().IsEmpty())
     SetLabel2(item.GetLabel2());
-  if (!item.GetThumbnailImage().IsEmpty())
-    SetThumbnailImage(item.GetThumbnailImage());
+  if (!item.GetArt("thumb").empty())
+    SetArt("thumb", item.GetArt("thumb"));
   if (!item.GetIconImage().IsEmpty())
     SetIconImage(item.GetIconImage());
   AppendProperties(item);
@@ -2793,16 +2784,10 @@ CStdString CFileItem::GetTBNFile() const
   return thumbFile;
 }
 
-CStdString CFileItem::GetUserVideoThumb() const
+CStdString CFileItem::FindLocalArt(const std::string &artFile, bool useFolder) const
 {
-  if (IsTuxBox())
-  {
-    if (!m_bIsFolder)
-      return g_tuxbox.GetPicon(GetLabel());
-    else return "";
-  }
-
-  if (m_strPath.IsEmpty()
+  // ignore a bunch that are meaningless
+  if (m_strPath.empty()
    || m_bIsShareOrDrive
    || IsInternetStream()
    || URIUtils::IsUPnP(m_strPath)
@@ -2814,46 +2799,71 @@ CStdString CFileItem::GetUserVideoThumb() const
    || IsDVD())
     return "";
 
+  CStdString thumb;
+  if (!m_bIsFolder)
+  {
+    thumb = GetLocalArt(artFile, false);
+    if (!thumb.empty() && CFile::Exists(thumb))
+      return thumb;
+  }
+  if ((useFolder || (m_bIsFolder && !IsFileFolder())) && !artFile.empty())
+  {
+    CStdString thumb2 = GetLocalArt(artFile, true);
+    if (!thumb2.empty() && thumb2 != thumb && CFile::Exists(thumb2))
+      return thumb2;
+  }
+  return "";
+}
 
-  // 1. check <filename>.tbn or <foldername>.tbn
-  CStdString fileThumb(GetTBNFile());
-  if (CFile::Exists(fileThumb))
-    return fileThumb;
+CStdString CFileItem::GetLocalArt(const std::string &artFile, bool useFolder) const
+{
+  // no retrieving of empty art files from folders
+  if (useFolder && artFile.empty())
+    return "";
 
-  if (IsOpticalMediaFile())
-  { // special case for optical media "folders" - check the parent folder (or parent of parent)
-    // TODO: A better way to handle this would be to treat stacked folders as folders rather than files.
-    CFileItem item(GetLocalMetadataPath(), true);
-    CStdString thumb(item.GetUserVideoThumb());
-    if (!thumb.IsEmpty())
-      return thumb;
+  CStdString strFile = m_strPath;
+  if (IsStack())
+  {
+/*    CFileItem item(CStackDirectory::GetFirstStackedFile(strFile),false);
+    CStdString localArt = item.GetLocalArt(artFile);
+    return localArt;
+    */
+    CStdString strPath;
+    URIUtils::GetParentPath(m_strPath,strPath);
+    URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(CStackDirectory::GetStackedTitlePath(strFile)),strFile);
   }
 
-  // 2. - check movie.tbn, as long as it's not a folder
-  if (!m_bIsFolder)
+  if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
   {
-    CStdString strPath, movietbnFile;
-    URIUtils::GetParentPath(m_strPath, strPath);
-    URIUtils::AddFileToFolder(strPath, "movie.tbn", movietbnFile);
-    if (CFile::Exists(movietbnFile))
-      return movietbnFile;
+    CStdString strPath, strParent;
+    URIUtils::GetDirectory(strFile,strPath);
+    URIUtils::GetParentPath(strPath,strParent);
+    URIUtils::AddFileToFolder(strParent,URIUtils::GetFileName(strFile),strFile);
   }
 
-  // 3. check folder image in_m_dvdThumbs (folder.jpg)
-  if (m_bIsFolder && !IsFileFolder())
+  if (IsMultiPath())
+    strFile = CMultiPathDirectory::GetFirstPath(m_strPath);
+
+  if (IsOpticalMediaFile())
+  { // optical media files should be treated like folders
+    useFolder = true;
+    strFile = GetLocalMetadataPath();
+  }
+  else if (useFolder)
+    strFile = URIUtils::GetDirectory(strFile);
+
+  if (strFile.empty()) // empty filepath -> nothing to find
+    return "";
+
+  if (useFolder)
+    return URIUtils::AddFileToFolder(strFile, artFile);
+  else
   {
-    CStdStringArray thumbs;
-    StringUtils::SplitString(g_advancedSettings.m_dvdThumbs, "|", thumbs);
-    for (unsigned int i = 0; i < thumbs.size(); ++i)
-    {
-      CStdString folderThumb(GetFolderThumb(thumbs[i]));
-      if (CFile::Exists(folderThumb))
-      {
-        return folderThumb;
-      }
-    }
+    if (artFile.empty()) // old thumbnail matching
+      return URIUtils::ReplaceExtension(strFile, ".tbn");
+    else
+      return URIUtils::ReplaceExtension(strFile, "-" + artFile);
   }
-  // No thumb found
   return "";
 }
 
@@ -2918,47 +2928,6 @@ CStdString CFileItem::GetBaseMoviePath(bool bUseFolderNames) const
   return strMovieName;
 }
 
-#ifdef UNIT_TESTING
-bool CFileItem::testGetBaseMoviePath()
-{
-  typedef struct
-  {
-    const char *file;
-    bool use_folder;
-    const char *base;
-  } testfiles;
-
-  const testfiles test_files[] = {{ "c:\\dir\\filename.avi", false, "c:\\dir\\filename.avi" },
-                                  { "c:\\dir\\filename.avi", true,  "c:\\dir\\" },
-                                  { "/dir/filename.avi", false, "/dir/filename.avi" },
-                                  { "/dir/filename.avi", true,  "/dir/" },
-                                  { "smb://somepath/file.avi", false, "smb://somepath/file.avi" },
-                                  { "smb://somepath/file.avi", true, "smb://somepath/" },
-                                  { "stack:///path/to/movie_name/cd1/some_file1.avi , /path/to/movie_name/cd2/some_file2.avi", false, "stack:///path/to/movie_name/cd1/some_file1.avi , /path/to/movie_name/cd2/some_file2.avi" },
-                                  { "stack:///path/to/movie_name/cd1/some_file1.avi , /path/to/movie_name/cd2/some_file2.avi", true,  "/path/to/movie_name/" },
-                                  { "/home/user/TV Shows/Dexter/S1/1x01.avi", false, "/home/user/TV Shows/Dexter/S1/1x01.avi" },
-                                  { "/home/user/TV Shows/Dexter/S1/1x01.avi", true, "/home/user/TV Shows/Dexter/S1/" },
-                                  { "rar://g%3a%5cmultimedia%5cmovies%5cSphere%2erar/Sphere.avi", true, "g:\\multimedia\\movies\\" },
-                                  { "/home/user/movies/movie_name/video_ts/VIDEO_TS.IFO", false, "/home/user/movies/movie_name/" },
-                                  { "/home/user/movies/movie_name/video_ts/VIDEO_TS.IFO", true, "/home/user/movies/movie_name/" },
-                                  { "/home/user/movies/movie_name/BDMV/index.bdmv", false, "/home/user/movies/movie_name/" },
-                                  { "/home/user/movies/movie_name/BDMV/index.bdmv", true, "/home/user/movies/movie_name/" }};
-
-  for (unsigned int i = 0; i < sizeof(test_files) / sizeof(testfiles); i++)
-  {
-    CFileItem item;
-    item.SetPath(test_files[i].file);
-    CStdString path = item.GetBaseMoviePath(test_files[i].use_folder);
-    if (path != test_files[i].base)
-    {
-      CLog::Log(LOGFATAL, "%s failed ('%s' -> '%s' != '%s')", __FUNCTION__, test_files[i].file, path.c_str(), test_files[i].base);
-      return false;
-    }
-  }
-  return true;
-}
-#endif
-
 CStdString CFileItem::GetLocalFanart() const
 {
   if (IsVideoDb())
@@ -3012,7 +2981,7 @@ CStdString CFileItem::GetLocalFanart() const
   CFileItemList items;
   CDirectory::GetDirectory(strDir, items, g_settings.m_pictureExtensions, DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO);
   if (IsOpticalMediaFile())
-  { // grab from the optical media parent folder as well - see GetUserVideoThumb
+  { // grab from the optical media parent folder as well
     CFileItemList moreItems;
     CDirectory::GetDirectory(GetLocalMetadataPath(), moreItems, g_settings.m_pictureExtensions, DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO);
     items.Append(moreItems);
@@ -3075,7 +3044,7 @@ bool CFileItem::LoadMusicTag()
     if (musicDatabase.GetSongByFileName(m_strPath, song))
     {
       GetMusicInfoTag()->SetSong(song);
-      SetThumbnailImage(song.strThumb);
+      SetArt("thumb", song.strThumb);
       return true;
     }
     musicDatabase.Close();
index 3b023f2..d3f83f0 100644 (file)
@@ -272,6 +272,24 @@ public:
    */
   CStdString GetLocalFanart() const;
 
+  /*! \brief Assemble the filename of a particular piece of local artwork for an item.
+             No file existence check is typically performed.
+   \param artFile the art file to search for.
+   \param useFolder whether to look in the folder for the art file. Defaults to false.
+   \return the path to the local artwork.
+   \sa FindLocalArt
+   */
+  CStdString GetLocalArt(const std::string &artFile, bool useFolder = false) const;
+
+  /*! \brief Assemble the filename of a particular piece of local artwork for an item,
+             and check for file existence.
+   \param artFile the art file to search for.
+   \param useFolder whether to look in the folder for the art file. Defaults to false.
+   \return the path to the local artwork if it exists, empty otherwise.
+   \sa GetLocalArt
+   */
+  CStdString FindLocalArt(const std::string &artFile, bool useFolder) const;
+
   // Gets the .tbn file associated with this item
   CStdString GetTBNFile() const;
   // Gets the folder image associated with this item (defaults to folder.jpg)
@@ -288,12 +306,7 @@ public:
    */
   CStdString GetBaseMoviePath(bool useFolderNames) const;
 
-#ifdef UNIT_TESTING
-  static bool testGetBaseMoviePath();
-#endif
-
   // Gets the user thumb, if it exists
-  CStdString GetUserVideoThumb() const;
   CStdString GetUserMusicThumb(bool alwaysCheckRemote = false) const;
 
   /*! \brief Get the path where we expect local metadata to reside.
index f137f32..f3ad5a8 100644 (file)
@@ -195,9 +195,11 @@ const infomap player_labels[] =  {{ "hasmedia",         PLAYER_HAS_MEDIA },
                                   { "chaptername",      PLAYER_CHAPTERNAME },
                                   { "starrating",       PLAYER_STAR_RATING },
                                   { "folderpath",       PLAYER_PATH },
-                                  { "filenameandpath",  PLAYER_FILEPATH }};
+                                  { "filenameandpath",  PLAYER_FILEPATH },
+                                  { "pauseenabled",     PLAYER_CAN_PAUSE },
+                                  { "seekenabled",      PLAYER_CAN_SEEK }};
 
-const infomap player_param[] =   {{ "property",         PLAYER_ITEM_PROPERTY }};
+const infomap player_param[] =   {{ "art",              PLAYER_ITEM_ART }};
 
 const infomap player_times[] =   {{ "seektime",         PLAYER_SEEKTIME },
                                   { "seekoffset",       PLAYER_SEEKOFFSET },
@@ -431,7 +433,10 @@ const infomap container_bools[] ={{ "onnext",           CONTAINER_MOVE_NEXT },
                                   { "currentpage",      CONTAINER_CURRENT_PAGE },
                                   { "scrolling",        CONTAINER_SCROLLING },
                                   { "hasnext",          CONTAINER_HAS_NEXT },
-                                  { "hasprevious",      CONTAINER_HAS_PREVIOUS }};
+                                  { "hasprevious",      CONTAINER_HAS_PREVIOUS },
+                                  { "canfilter",        CONTAINER_CAN_FILTER },
+                                  { "canfilteradvanced",CONTAINER_CAN_FILTERADVANCED },
+                                  { "filtered",         CONTAINER_FILTERED }};
 
 const infomap container_ints[] = {{ "row",              CONTAINER_ROW },
                                   { "column",           CONTAINER_COLUMN },
@@ -938,7 +943,11 @@ int CGUIInfoManager::TranslateSingleString(const CStdString &strCondition)
           return AddMultiInfo(GUIInfo(player_times[i].val, TranslateTimeFormat(prop.param())));
       }
       if (prop.name == "property")
+      {
+        if (prop.param().Equals("fanart_image"))
+          return AddMultiInfo(GUIInfo(PLAYER_ITEM_ART, ConditionalStringParameter("fanart")));
         return AddListItemProp(prop.param(), MUSICPLAYER_PROPERTY_OFFSET);
+      }
       return TranslateMusicPlayerString(prop.name);
     }
     else if (cat.name == "videoplayer")
@@ -1176,7 +1185,13 @@ int CGUIInfoManager::TranslateListItem(const Property &info)
       return listitem_labels[i].val;
   }
   if (info.name == "property" && info.num_params() == 1)
+  {
+    if (info.param().Equals("fanart_image"))
+      return AddListItemProp("fanart", LISTITEM_ART_OFFSET);
     return AddListItemProp(info.param());
+  }
+  if (info.name == "art" && info.num_params() == 1)
+    return AddListItemProp(info.param(), LISTITEM_ART_OFFSET);
   return 0;
 }
 
@@ -1839,7 +1854,7 @@ CStdString CGUIInfoManager::GetLabel(int info, int contextWindow, CStdString *fa
     {
       CGUIWindow *window = GetWindowWithCondition(contextWindow, WINDOW_CONDITION_IS_MEDIA_WINDOW);
       if (window)
-        return ((CGUIMediaWindow *)window)->CurrentDirectory().GetProperty("fanart_image").asString();
+        return ((CGUIMediaWindow *)window)->CurrentDirectory().GetArt("fanart");
     }
     break;
   case SYSTEM_RENDER_VENDOR:
@@ -2192,7 +2207,7 @@ bool CGUIInfoManager::GetBool(int condition1, int contextWindow, const CGUIListI
   {
     CGUIWindow *pWindow = GetWindowWithCondition(contextWindow, WINDOW_CONDITION_IS_MEDIA_WINDOW);
     if (pWindow)
-      bReturn = ((CGUIMediaWindow*)pWindow)->CurrentDirectory().HasThumbnail();
+      bReturn = ((CGUIMediaWindow*)pWindow)->CurrentDirectory().HasArt("thumb");
   }
   else if (condition == CONTAINER_HAS_NEXT || condition == CONTAINER_HAS_PREVIOUS || condition == CONTAINER_SCROLLING)
   {
@@ -2204,6 +2219,24 @@ bool CGUIInfoManager::GetBool(int condition1, int contextWindow, const CGUIListI
         bReturn = control->GetCondition(condition, 0);
     }
   }
+  else if (condition == CONTAINER_CAN_FILTER)
+  {
+    CGUIWindow *window = GetWindowWithCondition(contextWindow, WINDOW_CONDITION_IS_MEDIA_WINDOW);
+    if (window)
+      bReturn = !((CGUIMediaWindow*)window)->CanFilterAdvanced();
+  }
+  else if (condition == CONTAINER_CAN_FILTERADVANCED)
+  {
+    CGUIWindow *window = GetWindowWithCondition(contextWindow, WINDOW_CONDITION_IS_MEDIA_WINDOW);
+    if (window)
+      bReturn = ((CGUIMediaWindow*)window)->CanFilterAdvanced();
+  }
+  else if (condition == CONTAINER_FILTERED)
+  {
+    CGUIWindow *window = GetWindowWithCondition(contextWindow, WINDOW_CONDITION_IS_MEDIA_WINDOW);
+    if (window)
+      bReturn = ((CGUIMediaWindow*)window)->IsFiltered();
+  }
   else if (condition == VIDEOPLAYER_HAS_INFO)
     bReturn = ((m_currentFile->HasVideoInfoTag() && !m_currentFile->GetVideoInfoTag()->IsEmpty()) ||
                (m_currentFile->HasPVRChannelInfoTag()  && !m_currentFile->GetPVRChannelInfoTag()->IsEmpty()));
@@ -2297,6 +2330,12 @@ bool CGUIInfoManager::GetBool(int condition1, int contextWindow, const CGUIListI
     case PLAYER_CAN_RECORD:
       bReturn = g_application.m_pPlayer->CanRecord();
       break;
+    case PLAYER_CAN_PAUSE:
+      bReturn = g_application.m_pPlayer->CanPause();
+      break;
+    case PLAYER_CAN_SEEK:
+      bReturn = g_application.m_pPlayer->CanSeek();
+      break;
     case PLAYER_RECORDING:
       bReturn = g_application.m_pPlayer->IsRecording();
     break;
@@ -2935,9 +2974,9 @@ CStdString CGUIInfoManager::GetMultiInfoLabel(const GUIInfo &info, int contextWi
     if (m_seekOffset > 0)
       return "+" + seekOffset;
   }
-  else if (info.m_info == PLAYER_ITEM_PROPERTY)
+  else if (info.m_info == PLAYER_ITEM_ART)
   {
-    return m_currentFile->GetProperty(m_stringParameters[info.GetData1()]).asString();
+    return m_currentFile->GetArt(m_stringParameters[info.GetData1()]);
   }
   else if (info.m_info == SYSTEM_TIME)
   {
@@ -3064,7 +3103,7 @@ CStdString CGUIInfoManager::GetImage(int info, int contextWindow, CStdString *fa
     if (!g_application.IsPlayingAudio()) return "";
     if (fallback)
       *fallback = "DefaultAlbumCover.png";
-    return m_currentFile->HasThumbnail() ? m_currentFile->GetThumbnailImage() : "DefaultAlbumCover.png";
+    return m_currentFile->HasArt("thumb") ? m_currentFile->GetArt("thumb") : "DefaultAlbumCover.png";
   }
   else if (info == MUSICPLAYER_RATING)
   {
@@ -3082,7 +3121,7 @@ CStdString CGUIInfoManager::GetImage(int info, int contextWindow, CStdString *fa
     if (fallback)
       *fallback = "DefaultVideoCover.png";
     if(m_currentMovieThumb.IsEmpty())
-      return m_currentFile->HasThumbnail() ? m_currentFile->GetThumbnailImage() : "DefaultVideoCover.png";
+      return m_currentFile->HasArt("thumb") ? m_currentFile->GetArt("thumb") : "DefaultVideoCover.png";
     else return m_currentMovieThumb;
   }
   else if (info == CONTAINER_FOLDERTHUMB)
@@ -3095,13 +3134,13 @@ CStdString CGUIInfoManager::GetImage(int info, int contextWindow, CStdString *fa
   {
     CGUIWindow *window = GetWindowWithCondition(contextWindow, WINDOW_CONDITION_IS_MEDIA_WINDOW);
     if (window)
-      return ((CGUIMediaWindow *)window)->CurrentDirectory().GetProperty("tvshowthumb").asString();
+      return ((CGUIMediaWindow *)window)->CurrentDirectory().GetArt("tvshowthumb");
   }
   else if (info == CONTAINER_SEASONTHUMB)
   {
     CGUIWindow *window = GetWindowWithCondition(contextWindow, WINDOW_CONDITION_IS_MEDIA_WINDOW);
     if (window)
-      return ((CGUIMediaWindow *)window)->CurrentDirectory().GetProperty("seasonthumb").asString();
+      return ((CGUIMediaWindow *)window)->CurrentDirectory().GetArt("seasonthumb");
   }
   else if (info == LISTITEM_THUMB || info == LISTITEM_ICON || info == LISTITEM_ACTUAL_ICON ||
           info == LISTITEM_OVERLAY || info == LISTITEM_RATING || info == LISTITEM_STAR_RATING)
@@ -3319,12 +3358,13 @@ const CStdString CGUIInfoManager::GetMusicPlaylistInfo(const GUIInfo& info)
     playlistItem->GetMusicInfoTag()->SetLoaded();
   }
   // try to set a thumbnail
-  if (!playlistItem->HasThumbnail())
+  if (!playlistItem->HasArt("thumb"))
   {
-    CMusicThumbLoader::FillThumb(*playlistItem);
-    // still no thumb? then just the set the default cover TODO: remove me?
-    if (!playlistItem->HasThumbnail())
-      playlistItem->SetThumbnailImage("DefaultAlbumCover.png");
+    CMusicThumbLoader loader;
+    loader.LoadItem(playlistItem.get());
+    // still no thumb? then just the set the default cover
+    if (!playlistItem->HasArt("thumb"))
+      playlistItem->SetArt("thumb", "DefaultAlbumCover.png");
   }
   if (info.m_info == MUSICPLAYER_PLAYLISTPOS)
   {
@@ -3333,7 +3373,7 @@ const CStdString CGUIInfoManager::GetMusicPlaylistInfo(const GUIInfo& info)
     return strPosition;
   }
   else if (info.m_info == MUSICPLAYER_COVER)
-    return playlistItem->GetThumbnailImage();
+    return playlistItem->GetArt("thumb");
   return GetMusicTagLabel(info.m_info, playlistItem.get());
 }
 
@@ -3841,10 +3881,10 @@ void CGUIInfoManager::SetCurrentItem(CFileItem &item)
 void CGUIInfoManager::SetCurrentAlbumThumb(const CStdString thumbFileName)
 {
   if (CFile::Exists(thumbFileName))
-    m_currentFile->SetThumbnailImage(thumbFileName);
+    m_currentFile->SetArt("thumb", thumbFileName);
   else
   {
-    m_currentFile->SetThumbnailImage("");
+    m_currentFile->SetArt("thumb", "");
     m_currentFile->FillInDefaultIcon();
   }
 }
@@ -3870,8 +3910,8 @@ void CGUIInfoManager::SetCurrentSong(CFileItem &item)
       CLog::Log(LOGDEBUG,"Streaming media detected... using %s to find a thumb", g_application.m_strPlayListFile.c_str());
       CFileItem streamingItem(g_application.m_strPlayListFile,false);
       CMusicThumbLoader::FillThumb(streamingItem);
-      if (streamingItem.HasThumbnail())
-        m_currentFile->SetThumbnailImage(streamingItem.GetThumbnailImage());
+      if (streamingItem.HasArt("thumb"))
+        m_currentFile->SetArt("thumb", streamingItem.GetArt("thumb"));
     }
   }
   else
@@ -3901,7 +3941,7 @@ void CGUIInfoManager::SetCurrentMovie(CFileItem &item)
   }
 
   // Find a thumb for this file.
-  if (!item.HasThumbnail())
+  if (!item.HasArt("thumb"))
   {
     CVideoThumbLoader loader;
     loader.LoadItem(m_currentFile);
@@ -3923,12 +3963,12 @@ void CGUIInfoManager::SetCurrentMovie(CFileItem &item)
       CLog::Log(LOGDEBUG,"Streaming media detected... using %s to find a thumb", g_application.m_strPlayListFile.c_str());
       CFileItem thumbItem(g_application.m_strPlayListFile,false);
       if (CVideoThumbLoader::FillThumb(thumbItem))
-        item.SetThumbnailImage(thumbItem.GetThumbnailImage());
+        item.SetArt("thumb", thumbItem.GetArt("thumb"));
     }
   }
 
   item.FillInDefaultIcon();
-  m_currentMovieThumb = item.GetThumbnailImage();
+  m_currentMovieThumb = item.GetArt("thumb");
 }
 
 string CGUIInfoManager::GetSystemHeatInfo(int info)
@@ -4179,6 +4219,12 @@ CStdString CGUIInfoManager::GetItemLabel(const CFileItem *item, int info, CStdSt
   if (info >= CONDITIONAL_LABEL_START && info <= CONDITIONAL_LABEL_END)
     return GetSkinVariableString(info, false, item);
 
+  if (info >= LISTITEM_PROPERTY_START + LISTITEM_ART_OFFSET && info - (LISTITEM_PROPERTY_START + LISTITEM_ART_OFFSET) < (int)m_listitemProperties.size())
+  { // grab the art
+    std::string art = m_listitemProperties[info - (LISTITEM_PROPERTY_START + LISTITEM_ART_OFFSET)];
+    return item->GetArt(art);
+  }
+
   if (info >= LISTITEM_PROPERTY_START && info - LISTITEM_PROPERTY_START < (int)m_listitemProperties.size())
   { // grab the property
     CStdString property = m_listitemProperties[info - LISTITEM_PROPERTY_START];
@@ -4490,7 +4536,7 @@ CStdString CGUIInfoManager::GetItemLabel(const CFileItem *item, int info, CStdSt
     return item->GetIconImage();
   case LISTITEM_ICON:
     {
-      CStdString strThumb = item->GetThumbnailImage();
+      CStdString strThumb = item->GetArt("thumb");
       if (strThumb.IsEmpty())
         strThumb = item->GetIconImage();
       if (fallback)
@@ -4500,7 +4546,7 @@ CStdString CGUIInfoManager::GetItemLabel(const CFileItem *item, int info, CStdSt
   case LISTITEM_OVERLAY:
     return item->GetOverlayImage();
   case LISTITEM_THUMB:
-    return item->GetThumbnailImage();
+    return item->GetArt("thumb");
   case LISTITEM_FOLDERPATH:
     return CURL(item->GetPath()).GetWithoutUserDetails();
   case LISTITEM_FOLDERNAME:
index 576a68b..6e34ce4 100644 (file)
@@ -103,7 +103,9 @@ namespace INFO
 #define PLAYER_FILEPATH              46
 #define PLAYER_SEEKOFFSET            47
 #define PLAYER_PROGRESS_CACHE        48
-#define PLAYER_ITEM_PROPERTY         49
+#define PLAYER_ITEM_ART              49
+#define PLAYER_CAN_PAUSE             50
+#define PLAYER_CAN_SEEK              51
 
 #define WEATHER_CONDITIONS          100
 #define WEATHER_TEMPERATURE         101
@@ -289,6 +291,10 @@ namespace INFO
 #define LASTFM_CANLOVE              331
 #define LASTFM_CANBAN               332
 
+#define CONTAINER_CAN_FILTER         342
+#define CONTAINER_CAN_FILTERADVANCED 343
+#define CONTAINER_FILTERED           344
+
 #define CONTAINER_SCROLL_PREVIOUS   345 // NOTE: These 5 must be kept in this consecutive order
 #define CONTAINER_MOVE_PREVIOUS     346
 #define CONTAINER_STATIC            347
@@ -608,11 +614,12 @@ namespace INFO
 #define LISTITEM_PROGRESS           (LISTITEM_START + 102)
 #define LISTITEM_HAS_EPG            (LISTITEM_START + 103)
 
-#define LISTITEM_PROPERTY_START     (LISTITEM_START + 200)
+#define LISTITEM_PROPERTY_START     (LISTITEM_START + 100)
 #define LISTITEM_PROPERTY_END       (LISTITEM_PROPERTY_START + 1000)
 #define LISTITEM_END                (LISTITEM_PROPERTY_END)
 
-#define MUSICPLAYER_PROPERTY_OFFSET 900 // last 100 id's reserved for musicplayer props.
+#define MUSICPLAYER_PROPERTY_OFFSET 800 // 100 id's reserved for musicplayer props.
+#define LISTITEM_ART_OFFSET         900 // 100 id's reserved for listitem art.
 
 #define CONDITIONAL_LABEL_START       LISTITEM_END + 1 // 36001
 #define CONDITIONAL_LABEL_END         37000
index c83d23d..8b7db52 100644 (file)
@@ -30,7 +30,7 @@ using namespace XFILE;
 
 bool CMediaSource::IsWritable() const
 {
-  return CUtil::SupportsFileOperations(strPath);
+  return CUtil::SupportsWriteFileOperations(strPath);
 }
 
 void CMediaSource::FromNameAndPaths(const CStdString &category, const CStdString &name, const vector<CStdString> &paths)
index ddb400c..250dc25 100644 (file)
@@ -33,6 +33,8 @@
 #include "settings/Settings.h"
 #include "utils/TimeUtils.h"
 #include "utils/log.h"
+#include "Application.h"
+#include "interfaces/AnnouncementManager.h"
 
 using namespace std;
 using namespace PLAYLIST;
@@ -205,6 +207,7 @@ bool CPartyModeManager::Enable(PartyModeContext context /*= PARTYMODECONTEXT_MUS
 
   // done
   m_bEnabled = true;
+  Announce();
   return true;
 }
 
@@ -213,6 +216,7 @@ void CPartyModeManager::Disable()
   if (!IsEnabled())
     return;
   m_bEnabled = false;
+  Announce();
   CLog::Log(LOGINFO,"PARTY MODE MANAGER: Party mode disabled.");
 }
 
@@ -698,3 +702,15 @@ bool CPartyModeManager::IsEnabled(PartyModeContext context /* = PARTYMODECONTEXT
     return !m_bIsVideo;
   return true; // unknown, but we're enabled
 }
+
+void CPartyModeManager::Announce()
+{
+  if (g_application.IsPlaying())
+  {
+    CVariant data;
+    
+    data["player"]["playerid"] = g_playlistPlayer.GetCurrentPlaylist();
+    data["property"]["partymode"] = m_bEnabled;
+    ANNOUNCEMENT::CAnnouncementManager::Announce(ANNOUNCEMENT::Player, "xbmc", "OnPropertyChanged", data);
+  }
+}
index 72948a8..d6b341d 100644 (file)
@@ -72,6 +72,7 @@ private:
   std::pair<CStdString,CStdString> GetWhereClauseWithHistory() const;
   void AddToHistory(int type, int songID);
   void GetRandomSelection(std::vector< std::pair<int,int> > &in, unsigned int number, std::vector< std::pair<int, int> > &out);
+  void Announce();
 
   // state
   bool m_bEnabled;
index 2fbd9eb..4eda276 100644 (file)
@@ -33,6 +33,7 @@
 #include "music/tags/MusicInfoTag.h"
 #include "dialogs/GUIDialogKaiToast.h"
 #include "guilib/LocalizeStrings.h"
+#include "interfaces/AnnouncementManager.h"
 
 using namespace PLAYLIST;
 
@@ -466,6 +467,8 @@ void CPlayListPlayer::SetShuffle(int iPlaylist, bool bYesNo, bool bNotify /* = f
       // so dont do anything
     }
   }
+  
+  AnnouncePropertyChanged(iPlaylist, "shuffled", IsShuffled(iPlaylist));
 }
 
 bool CPlayListPlayer::IsShuffled(int iPlaylist) const
@@ -503,6 +506,21 @@ void CPlayListPlayer::SetRepeat(int iPlaylist, REPEAT_STATE state, bool bNotify
   }
 
   m_repeatState[iPlaylist] = state;
+
+  CVariant data;
+  switch (state)
+  {
+  case REPEAT_ONE:
+    data = "one";
+    break;
+  case REPEAT_ALL:
+    data = "all";
+    break;
+  default:
+    data = "off";
+    break;
+  }
+  AnnouncePropertyChanged(iPlaylist, "repeat", data);
 }
 
 REPEAT_STATE CPlayListPlayer::GetRepeat(int iPlaylist) const
@@ -654,3 +672,16 @@ void CPlayListPlayer::Swap(int iPlaylist, int indexItem1, int indexItem2)
   CGUIMessage msg(GUI_MSG_PLAYLIST_CHANGED, 0, 0);
   g_windowManager.SendMessage(msg);
 }
+
+void CPlayListPlayer::AnnouncePropertyChanged(int iPlaylist, const std::string &strProperty, const CVariant &value)
+{
+  if (strProperty.empty() || value.isNull() ||
+     (iPlaylist == PLAYLIST_VIDEO && !g_application.IsPlayingVideo()) ||
+     (iPlaylist == PLAYLIST_MUSIC && !g_application.IsPlayingAudio()))
+    return;
+
+  CVariant data;
+  data["player"]["playerid"] = iPlaylist;
+  data["property"][strProperty] = value;
+  ANNOUNCEMENT::CAnnouncementManager::Announce(ANNOUNCEMENT::Player, "xbmc", "OnPropertyChanged", data);
+}
index a725980..7614dc8 100644 (file)
@@ -30,6 +30,8 @@
 class CFileItem; typedef boost::shared_ptr<CFileItem> CFileItemPtr;
 class CFileItemList;
 
+class CVariant;
+
 namespace PLAYLIST
 {
 /*!
@@ -178,6 +180,8 @@ protected:
 
   void ReShuffle(int iPlaylist, int iPosition);
 
+  void AnnouncePropertyChanged(int iPlaylist, const std::string &strProperty, const CVariant &value);
+
   bool m_bPlayedFirstFile;
   bool m_bPlaybackStarted;
   int m_iFailedSongs;
index 239dd41..41c779d 100644 (file)
@@ -311,6 +311,23 @@ void CTextureCache::OnJobProgress(unsigned int jobID, unsigned int progress, uns
     CJobQueue::OnJobProgress(jobID, progress, total, job);
 }
 
+bool CTextureCache::Export(const CStdString &image, const CStdString &destination, bool overwrite)
+{
+  CStdString cachedHash;
+  CStdString cachedImage(GetCachedImage(image, cachedHash));
+  if (!cachedImage.IsEmpty())
+  {
+    CStdString dest = destination + URIUtils::GetExtension(cachedImage);
+    if (overwrite || !CFile::Exists(dest))
+    {
+      if (CFile::Cache(cachedImage, dest))
+        return true;
+      CLog::Log(LOGERROR, "%s failed exporting '%s' to '%s'", __FUNCTION__, cachedImage.c_str(), dest.c_str());
+    }
+  }
+  return false;
+}
+
 bool CTextureCache::Export(const CStdString &image, const CStdString &destination)
 {
   CStdString cachedHash;
index 228bb78..81ac2d0 100644 (file)
@@ -137,10 +137,12 @@ public:
 
   /*! \brief Export a (possibly) cached image to a file
    \param image url of the original image
-   \param destination url of the destination image
+   \param destination url of the destination image, excluding extension.
+   \param overwrite whether to overwrite the destination if it exists (TODO: Defaults to false)
    \return true if we successfully exported the file, false otherwise.
    */
-  bool Export(const CStdString &image, const CStdString &destination);
+  bool Export(const CStdString &image, const CStdString &destination, bool overwrite);
+  bool Export(const CStdString &image, const CStdString &destination); // TODO: BACKWARD COMPATIBILITY FOR MUSIC THUMBS
 private:
   // private construction, and no assignements; use the provided singleton methods
   CTextureCache();
index 8c35847..45d6b39 100644 (file)
@@ -128,7 +128,7 @@ bool CThumbExtractor::DoWork()
       CTextureCache::Get().AddCachedTexture(m_target, details);
       m_item.SetProperty("HasAutoThumb", true);
       m_item.SetProperty("AutoThumbImage", m_target);
-      m_item.SetThumbnailImage(CTextureCache::GetCachedPath(details.file));
+      m_item.SetArt("thumb", CTextureCache::GetCachedPath(details.file));
     }
   }
   else if (m_item.HasVideoInfoTag() && !m_item.GetVideoInfoTag()->HasStreamDetails())
@@ -188,6 +188,17 @@ static void SetupRarOptions(CFileItem& item, const CStdString& path)
   g_directoryCache.ClearDirectory(url.GetWithoutFilename());
 }
 
+vector<string> CVideoThumbLoader::GetArtTypes(const string &type)
+{
+  vector<string> ret;
+  ret.push_back("fanart");
+  ret.push_back("poster");
+  if (type == "tvshow" || type == "season" || type.empty())
+    ret.push_back("banner");
+  ret.push_back("thumb");
+  return ret;
+}
+
 /**
  * Look for a thumbnail for pItem.  If one does not exist, look for an autogenerated
  * thumbnail.  If that does not exist, attempt to autogenerate one.  Finally, check
@@ -226,52 +237,55 @@ bool CVideoThumbLoader::LoadItem(CFileItem* pItem)
     }
   }
 
-  // fanart
-  if (!pItem->HasProperty("fanart_image"))
+  // if we have no art, look for it all
+  map<string, string> artwork = pItem->GetArt();
+  if (artwork.empty())
   {
-    CStdString fanart = GetCachedImage(*pItem, "fanart");
-    if (fanart.IsEmpty())
+    vector<string> artTypes = GetArtTypes(pItem->HasVideoInfoTag() ? pItem->GetVideoInfoTag()->m_type : "");
+    for (vector<string>::const_iterator i = artTypes.begin(); i != artTypes.end(); ++i)
     {
-      fanart = pItem->GetLocalFanart();
-      if (!fanart.IsEmpty()) // cache it
-        SetCachedImage(*pItem, "fanart", fanart);
-    }
-    if (!fanart.IsEmpty())
-    {
-      CTextureCache::Get().BackgroundCacheImage(fanart);
-      pItem->SetProperty("fanart_image", fanart);
+      std::string type = *i;
+      std::string art = GetCachedImage(*pItem, type);
+      if (art.empty())
+      {
+        art = GetLocalArt(*pItem, type, type=="fanart");
+        if (!art.empty()) // cache it
+          SetCachedImage(*pItem, type, art);
+      }
+      if (!art.empty())
+      {
+        CTextureCache::Get().BackgroundCacheImage(art);
+        artwork.insert(make_pair(type, art));
+      }
     }
+    pItem->SetArt(artwork);
   }
 
-  // thumbnails
-  if (!pItem->HasThumbnail())
+  // thumbnails are special-cased due to auto-generation
+  if (!pItem->HasArt("thumb") && !pItem->m_bIsFolder && pItem->IsVideo())
   {
-    FillThumb(*pItem);
-    if (!pItem->HasThumbnail() && !pItem->m_bIsFolder && pItem->IsVideo())
+    // create unique thumb for auto generated thumbs
+    CStdString thumbURL = GetEmbeddedThumbURL(*pItem);
+    if (CTextureCache::Get().HasCachedImage(thumbURL))
     {
-      // create unique thumb for auto generated thumbs
-      CStdString thumbURL = GetEmbeddedThumbURL(*pItem);
-      if (CTextureCache::Get().HasCachedImage(thumbURL))
-      {
-        CTextureCache::Get().BackgroundCacheImage(thumbURL);
-        pItem->SetProperty("HasAutoThumb", true);
-        pItem->SetProperty("AutoThumbImage", thumbURL);
-        pItem->SetThumbnailImage(thumbURL);
-      }
-      else if (g_guiSettings.GetBool("myvideos.extractthumb") &&
-               g_guiSettings.GetBool("myvideos.extractflags"))
-      {
-        CFileItem item(*pItem);
-        CStdString path(item.GetPath());
-        if (URIUtils::IsInRAR(item.GetPath()))
-          SetupRarOptions(item,path);
+      CTextureCache::Get().BackgroundCacheImage(thumbURL);
+      pItem->SetProperty("HasAutoThumb", true);
+      pItem->SetProperty("AutoThumbImage", thumbURL);
+      pItem->SetArt("thumb", thumbURL);
+    }
+    else if (g_guiSettings.GetBool("myvideos.extractthumb") &&
+             g_guiSettings.GetBool("myvideos.extractflags"))
+    {
+      CFileItem item(*pItem);
+      CStdString path(item.GetPath());
+      if (URIUtils::IsInRAR(item.GetPath()))
+        SetupRarOptions(item,path);
 
-        CThumbExtractor* extract = new CThumbExtractor(item, path, true, thumbURL);
-        AddJob(extract);
+      CThumbExtractor* extract = new CThumbExtractor(item, path, true, thumbURL);
+      AddJob(extract);
 
-        m_database->Close();
-        return true;
-      }
+      m_database->Close();
+      return true;
     }
   }
 
@@ -355,7 +369,7 @@ bool CVideoThumbLoader::FillLibraryArt(CFileItem &item)
           tag.m_strPictureURL.Parse();
           CStdString thumb = CScraperUrl::GetThumbURL(tag.m_strPictureURL.GetFirstThumb());
           if (!thumb.IsEmpty())
-            item.SetThumbnailImage(thumb);
+            item.SetArt("thumb", thumb);
         }
       }
       else if (tag.m_type == "season")
@@ -368,7 +382,7 @@ bool CVideoThumbLoader::FillLibraryArt(CFileItem &item)
         CVideoInfoScanner::GetSeasonThumbs(show, seasons, true);
         map<int, string>::iterator season = seasons.find(tag.m_iSeason);
         if (season != seasons.end())
-          item.SetThumbnailImage(season->second);
+          item.SetArt("thumb", season->second);
       }
       // add to the database for next time around
       map<string, string> artwork = item.GetArt();
@@ -382,16 +396,16 @@ bool CVideoThumbLoader::FillLibraryArt(CFileItem &item)
         m_database->SetArtForItem(tag.m_iDbId, tag.m_type, "thumb", "");
     }
     // For episodes and seasons, we want to set fanart for that of the show
-    if (!item.HasProperty("fanart_image") && tag.m_iIdShow >= 0)
+    if (!item.HasArt("fanart") && tag.m_iIdShow >= 0)
     {
       map<string, string> showArt;
       if (m_database->GetArtForItem(tag.m_iIdShow, "tvshow", showArt))
       {
         map<string, string>::iterator i = showArt.find("fanart");
         if (i != showArt.end())
-          item.SetProperty("fanart_image", i->second);
+          item.SetArt("fanart", i->second);
         if ((i = showArt.find("thumb")) != showArt.end())
-          item.SetProperty("tvshowthumb", i->second);
+          item.SetArt("tvshowthumb", i->second);
       }
     }
     m_database->Close();
@@ -401,19 +415,41 @@ bool CVideoThumbLoader::FillLibraryArt(CFileItem &item)
 
 bool CVideoThumbLoader::FillThumb(CFileItem &item)
 {
-  if (item.HasThumbnail())
+  if (item.HasArt("thumb"))
     return true;
   CStdString thumb = GetCachedImage(item, "thumb");
   if (thumb.IsEmpty())
   {
-    thumb = item.GetUserVideoThumb();
+    thumb = GetLocalArt(item, "thumb");
     if (!thumb.IsEmpty())
       SetCachedImage(item, "thumb", thumb);
   }
-  item.SetThumbnailImage(thumb);
+  item.SetArt("thumb", thumb);
   return !thumb.IsEmpty();
 }
 
+std::string CVideoThumbLoader::GetLocalArt(const CFileItem &item, const std::string &type, bool checkFolder)
+{
+  std::string art;
+  if (!type.empty())
+  {
+    art = item.FindLocalArt(type + ".jpg", checkFolder);
+    if (art.empty())
+      art = item.FindLocalArt(type + ".png", checkFolder);
+  }
+  if (art.empty() && (type.empty() || type == "thumb"))
+  { // backward compatibility
+    art = item.FindLocalArt("", false);
+    if (art.empty() && (checkFolder || (item.m_bIsFolder && !item.IsFileFolder())))
+    { // try movie.tbn
+      art = item.FindLocalArt("movie.tbn", true);
+      if (art.empty()) // try folder.jpg
+        art = item.FindLocalArt("folder.jpg", true);
+    }
+  }
+  return art;
+}
+
 CStdString CVideoThumbLoader::GetEmbeddedThumbURL(const CFileItem &item)
 {
   CStdString path(item.GetPath());
@@ -460,7 +496,7 @@ bool CProgramThumbLoader::LoadItem(CFileItem *pItem)
 bool CProgramThumbLoader::FillThumb(CFileItem &item)
 {
   // no need to do anything if we already have a thumb set
-  CStdString thumb = item.GetThumbnailImage();
+  CStdString thumb = item.GetArt("thumb");
 
   if (thumb.IsEmpty())
   { // see whether we have a cached image for this item
@@ -476,7 +512,7 @@ bool CProgramThumbLoader::FillThumb(CFileItem &item)
   if (!thumb.IsEmpty())
   {
     CTextureCache::Get().BackgroundCacheImage(thumb);
-    item.SetThumbnailImage(thumb);
+    item.SetArt("thumb", thumb);
   }
   return true;
 }
@@ -537,7 +573,7 @@ bool CMusicThumbLoader::LoadItem(CFileItem* pItem)
       return true; // no fallback
   }
 
-  if (!pItem->HasProperty("fanart_image"))
+  if (!pItem->HasArt("fanart"))
   {
     if (pItem->HasMusicInfoTag() && !pItem->GetMusicInfoTag()->GetArtist().empty())
     {
@@ -548,13 +584,13 @@ bool CMusicThumbLoader::LoadItem(CFileItem* pItem)
       {
         string fanart = m_database->GetArtForItem(idArtist, "artist", "fanart");
         if (!fanart.empty())
-          pItem->SetProperty("fanart_image", fanart);
+          pItem->SetArt("fanart", fanart);
       }
       m_database->Close();
     }
   }
 
-  if (!pItem->HasThumbnail())
+  if (!pItem->HasArt("thumb"))
     FillThumb(*pItem);
 
   return true;
@@ -562,7 +598,7 @@ bool CMusicThumbLoader::LoadItem(CFileItem* pItem)
 
 bool CMusicThumbLoader::FillThumb(CFileItem &item)
 {
-  if (item.HasThumbnail())
+  if (item.HasArt("thumb"))
     return true;
   CStdString thumb = GetCachedImage(item, "thumb");
   if (thumb.IsEmpty())
@@ -571,7 +607,7 @@ bool CMusicThumbLoader::FillThumb(CFileItem &item)
     if (!thumb.IsEmpty())
       SetCachedImage(item, "thumb", thumb);
   }
-  item.SetThumbnailImage(thumb);
+  item.SetArt("thumb", thumb);
   return !thumb.IsEmpty();
 }
 
@@ -611,7 +647,7 @@ bool CMusicThumbLoader::FillLibraryArt(CFileItem &item)
     }
     if (tag.GetType() == "song" || tag.GetType() == "album")
     { // fanart from the artist
-      item.SetProperty("fanart_image", m_database->GetArtistArtForItem(tag.GetDatabaseId(), tag.GetType(), "fanart"));
+      item.SetArt("fanart", m_database->GetArtistArtForItem(tag.GetDatabaseId(), tag.GetType(), "fanart"));
     }
     m_database->Close();
   }
index 4411cfa..f75d384 100644 (file)
@@ -111,6 +111,21 @@ public:
    */
   static bool FillThumb(CFileItem &item);
 
+  /*! \brief Find a particular art type for a given item, optionally checking at the folder level
+   \param item the CFileItem to search.
+   \param type the type of art to look for.
+   \param checkFolder whether to also check the folder level for files. Defaults to false.
+   \return the art file (if found), else empty.
+   */
+  static std::string GetLocalArt(const CFileItem &item, const std::string &type, bool checkFolder = false);
+
+  /*! \brief return the available art types for a given media type
+   \param type the type of media.
+   \return a vector of art types.
+   \sa GetLocalArt
+   */
+  static std::vector<std::string> GetArtTypes(const std::string &type);
+
   /*! \brief helper function to retrieve a thumb URL for embedded video thumbs
    \param item a video CFileItem.
    \return a URL for the embedded thumb.
index 0b3fa8b..60a6a2a 100644 (file)
@@ -1702,7 +1702,7 @@ bool CUtil::MakeShortenPath(CStdString StrInput, CStdString& StrOutput, int iTex
   return true;
 }
 
-bool CUtil::SupportsFileOperations(const CStdString& strPath)
+bool CUtil::SupportsWriteFileOperations(const CStdString& strPath)
 {
   // currently only hd, smb, nfs and afp support delete and rename
   if (URIUtils::IsHD(strPath))
@@ -1710,7 +1710,7 @@ bool CUtil::SupportsFileOperations(const CStdString& strPath)
   if (URIUtils::IsSmb(strPath))
     return true;
   if (CUtil::IsTVRecording(strPath))
-    return CPVRDirectory::SupportsFileOperations(strPath);
+    return CPVRDirectory::SupportsWriteFileOperations(strPath);
   if (URIUtils::IsNfs(strPath))
     return true;
   if (URIUtils::IsAfp(strPath))
@@ -1722,16 +1722,24 @@ bool CUtil::SupportsFileOperations(const CStdString& strPath)
      * it hits the directory cache on the way through, which has the Live Channels and Guide
      * items cached.
      */
-    return CMythDirectory::SupportsFileOperations(strPath);
+    return CMythDirectory::SupportsWriteFileOperations(strPath);
   }
   if (URIUtils::IsStack(strPath))
-    return SupportsFileOperations(CStackDirectory::GetFirstStackedFile(strPath));
+    return SupportsWriteFileOperations(CStackDirectory::GetFirstStackedFile(strPath));
   if (URIUtils::IsMultiPath(strPath))
-    return CMultiPathDirectory::SupportsFileOperations(strPath);
+    return CMultiPathDirectory::SupportsWriteFileOperations(strPath);
 
   return false;
 }
 
+bool CUtil::SupportsReadFileOperations(const CStdString& strPath)
+{
+  if (URIUtils::IsVideoDb(strPath))
+    return false;
+
+  return true;
+}
+
 CStdString CUtil::GetDefaultFolderThumb(const CStdString &folderThumb)
 {
   if (g_TextureManager.HasTexture(folderThumb))
index 8c30abe..db917f7 100644 (file)
@@ -147,7 +147,20 @@ public:
 
   static double AlbumRelevance(const CStdString& strAlbumTemp1, const CStdString& strAlbum1, const CStdString& strArtistTemp1, const CStdString& strArtist1);
   static bool MakeShortenPath(CStdString StrInput, CStdString& StrOutput, int iTextMaxLength);
-  static bool SupportsFileOperations(const CStdString& strPath);
+  /*! \brief Checks wether the supplied path supports Write file operations (e.g. Rename, Delete, ...)
+
+   \param strPath the path to be checked
+
+   \return true if Write file operations are supported, false otherwise
+   */
+  static bool SupportsWriteFileOperations(const CStdString& strPath);
+  /*! \brief Checks wether the supplied path supports Read file operations (e.g. Copy, ...)
+
+   \param strPath the path to be checked
+
+   \return true if Read file operations are supported, false otherwise
+   */
+  static bool SupportsReadFileOperations(const CStdString& strPath);
   static CStdString GetDefaultFolderThumb(const CStdString &folderThumb);
 
 #ifdef UNIT_TESTING
index 25aa48b..47b600b 100644 (file)
@@ -82,6 +82,7 @@ INT CXBApplicationEx::Run(bool renderGUI)
   unsigned int lastFrameTime = 0;
   unsigned int frameTime = 0;
   const unsigned int noRenderFrameTime = 15;  // Simulates ~66fps
+  m_renderGUI = renderGUI;
 
 #ifdef XBMC_TRACK_EXCEPTIONS
   BYTE processExceptionCount = 0;
@@ -138,7 +139,7 @@ INT CXBApplicationEx::Run(bool renderGUI)
     try
     {
 #endif
-      if (!m_bStop) FrameMove(true, renderGUI);
+      if (!m_bStop) FrameMove(true, m_renderGUI);
       //reset exception count
 #ifdef XBMC_TRACK_EXCEPTIONS
       frameMoveExceptionCount = 0;
@@ -173,8 +174,8 @@ INT CXBApplicationEx::Run(bool renderGUI)
     try
     {
 #endif
-      if (renderGUI && !m_bStop) Render();
-      else if (!renderGUI)
+      if (m_renderGUI && !m_bStop) Render();
+      else if (!m_renderGUI)
       {
         frameTime = XbmcThreads::SystemClockMillis() - lastFrameTime;
         if(frameTime < noRenderFrameTime)
index 8283479..c8ef77c 100644 (file)
@@ -42,10 +42,12 @@ public:
   int  m_ExitCode;
   bool m_AppActive;
   bool m_AppFocused;
+  bool m_renderGUI;
 
   // Overridable functions for the 3D scene created by the app
   virtual bool Initialize() { return true; }
   virtual bool Cleanup() { return true; }
+  virtual void SetRenderGUI(bool renderGUI) {};
 
 public:
   // Functions to create, run, and clean up the application
index 29363a5..a5e1b81 100644 (file)
@@ -223,6 +223,7 @@ typedef void (*PVRTriggerChannelUpdate)(void *addonData);
 typedef void (*PVRTriggerTimerUpdate)(void *addonData);
 typedef void (*PVRTriggerRecordingUpdate)(void *addonData);
 typedef void (*PVRTriggerChannelGroupsUpdate)(void *addonData);
+typedef void (*PVRTriggerEpgUpdate)(void *addonData, unsigned int iChannelUid);
 
 typedef void (*PVRTransferChannelGroup)(void *addonData, const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP *group);
 typedef void (*PVRTransferChannelGroupMember)(void *addonData, const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP_MEMBER *member);
@@ -242,6 +243,7 @@ typedef struct CB_PVRLib
   PVRTriggerTimerUpdate         TriggerTimerUpdate;
   PVRTriggerRecordingUpdate     TriggerRecordingUpdate;
   PVRTriggerChannelGroupsUpdate TriggerChannelGroupsUpdate;
+  PVRTriggerEpgUpdate           TriggerEpgUpdate;
   PVRFreeDemuxPacket            FreeDemuxPacket;
   PVRAllocateDemuxPacket        AllocateDemuxPacket;
   PVRTransferChannelGroup       TransferChannelGroup;
index 5b4cd33..df0702c 100644 (file)
@@ -1112,7 +1112,7 @@ GUIHANDLE CAddonCallbacksGUI::ListItem_Create(void *addonData, const char *label
   if (iconImage)
     pItem->SetIconImage(iconImage);
   if (thumbnailImage)
-    pItem->SetThumbnailImage(thumbnailImage);
+    pItem->SetArt("thumb", thumbnailImage);
   if (path)
     pItem->SetPath(path);
 
@@ -1177,7 +1177,7 @@ void CAddonCallbacksGUI::ListItem_SetThumbnailImage(void *addonData, GUIHANDLE h
   if (!helper || !handle)
     return;
 
-  ((CFileItem*)handle)->SetThumbnailImage(image);
+  ((CFileItem*)handle)->SetArt("thumb", image);
 }
 
 void CAddonCallbacksGUI::ListItem_SetInfo(void *addonData, GUIHANDLE handle, const char *info)
index c78f52c..6aad7bf 100644 (file)
@@ -55,6 +55,7 @@ CAddonCallbacksPVR::CAddonCallbacksPVR(CAddon* addon)
   m_callbacks->TriggerChannelGroupsUpdate = PVRTriggerChannelGroupsUpdate;
   m_callbacks->TriggerTimerUpdate         = PVRTriggerTimerUpdate;
   m_callbacks->TriggerRecordingUpdate     = PVRTriggerRecordingUpdate;
+  m_callbacks->TriggerEpgUpdate           = PVRTriggerEpgUpdate;
   m_callbacks->FreeDemuxPacket            = PVRFreeDemuxPacket;
   m_callbacks->AllocateDemuxPacket        = PVRAllocateDemuxPacket;
   m_callbacks->TransferChannelGroup       = PVRTransferChannelGroup;
@@ -295,6 +296,30 @@ void CAddonCallbacksPVR::PVRTriggerChannelGroupsUpdate(void *addonData)
   g_PVRManager.TriggerChannelGroupsUpdate();
 }
 
+void CAddonCallbacksPVR::PVRTriggerEpgUpdate(void *addonData, unsigned int iChannelUid)
+{
+  // get the client
+  CPVRClient *client = GetPVRClient(addonData);
+  if (!client)
+  {
+    CLog::Log(LOGERROR, "PVR - %s - invalid handler data", __FUNCTION__);
+    return;
+  }
+
+  // get the channel
+  CPVRChannelPtr channel = g_PVRChannelGroups->GetByUniqueID(iChannelUid, client->GetID());
+  CEpg* epg(NULL);
+  // get the EPG for the channel
+  if (!channel || (epg = channel->GetEPG()) == NULL)
+  {
+    CLog::Log(LOGERROR, "PVR - %s - invalid channel or channel doesn't have an EPG", __FUNCTION__);
+    return;
+  }
+
+  // force an update
+  epg->ForceUpdate();
+}
+
 void CAddonCallbacksPVR::PVRFreeDemuxPacket(void *addonData, DemuxPacket* pPacket)
 {
   CDVDDemuxUtils::FreeDemuxPacket(pPacket);
index e2ee7be..12b21d5 100644 (file)
@@ -49,108 +49,115 @@ public:
   /*!
    * @brief Transfer a channel group from the add-on to XBMC. The group will be created if it doesn't exist.
    * @param addonData A pointer to the add-on.
-   * @param handle The handle containing a pointer to the CPVRChannelGroups instance that this group needs to be added to.
-   * @param group The entry to transfer.
+   * @param handle The handle parameter that XBMC used when requesting the channel groups list
+   * @param entry The entry to transfer to XBMC
    */
-  static void PVRTransferChannelGroup(void *addonData, const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP *group);
+  static void PVRTransferChannelGroup(void* addonData, const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP* entry);
 
   /*!
-   * @brief Transfer a channel group member from the add-on to XBMC. The channel will be added to the group if the group can be found.
+   * @brief Transfer a channel group member entry from the add-on to XBMC. The channel will be added to the group if the group can be found.
    * @param addonData A pointer to the add-on.
-   * @param handle The handle that initiated this action.
-   * @param member The entry to transfer.
+   * @param handle The handle parameter that XBMC used when requesting the channel group members list
+   * @param entry The entry to transfer to XBMC
    */
-  static void PVRTransferChannelGroupMember(void *addonData, const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP_MEMBER *member);
+  static void PVRTransferChannelGroupMember(void* addonData, const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP_MEMBER* entry);
 
   /*!
-   * @brief Transfer an EPG entry from the add-on to XBMC.
+   * @brief Transfer an EPG tag from the add-on to XBMC
    * @param addonData A pointer to the add-on.
-   * @param handle The handle that initiated this action.
-   * @param epgentry The entry to transfer.
+   * @param handle The handle parameter that XBMC used when requesting the EPG data
+   * @param entry The entry to transfer to XBMC
    */
-  static void PVRTransferEpgEntry(void *addonData, const ADDON_HANDLE handle, const EPG_TAG *epgentry);
+  static void PVRTransferEpgEntry(void* addonData, const ADDON_HANDLE handle, const EPG_TAG* entry);
 
   /*!
-   * @brief Transfer a channel entry from the add-on to XBMC.
+   * @brief Transfer a channel entry from the add-on to XBMC
    * @param addonData A pointer to the add-on.
-   * @param handle The handle that initiated this action.
-   * @param channel The entry to transfer.
+   * @param handle The handle parameter that XBMC used when requesting the channel list
+   * @param entry The entry to transfer to XBMC
    */
-  static void PVRTransferChannelEntry(void *addonData, const ADDON_HANDLE handle, const PVR_CHANNEL *channel);
+  static void PVRTransferChannelEntry(void* addonData, const ADDON_HANDLE handle, const PVR_CHANNEL* entry);
 
   /*!
-   * @brief Transfer a timer entry from the add-on to XBMC.
+   * @brief Transfer a timer entry from the add-on to XBMC
    * @param addonData A pointer to the add-on.
-   * @param handle The handle that initiated this action.
-   * @param timer The entry to transfer.
+   * @param handle The handle parameter that XBMC used when requesting the timers list
+   * @param entry The entry to transfer to XBMC
    */
-  static void PVRTransferTimerEntry(void *addonData, const ADDON_HANDLE handle, const PVR_TIMER *timer);
+  static void PVRTransferTimerEntry(void* addonData, const ADDON_HANDLE handle, const PVR_TIMER* entry);
 
   /*!
-   * @brief Transfer a recording entry from the add-on to XBMC.
+   * @brief Transfer a recording entry from the add-on to XBMC
    * @param addonData A pointer to the add-on.
-   * @param handle The handle that initiated this action.
-   * @param recording The entry to transfer.
+   * @param handle The handle parameter that XBMC used when requesting the recordings list
+   * @param entry The entry to transfer to XBMC
    */
-  static void PVRTransferRecordingEntry(void *addonData, const ADDON_HANDLE handle, const PVR_RECORDING *recording);
+  static void PVRTransferRecordingEntry(void* addonData, const ADDON_HANDLE handle, const PVR_RECORDING* entry);
 
   /*!
-   * @brief Add a menu hook to this add-on table.
+   * @brief Add or replace a menu hook for the context menu for this add-on
    * @param addonData A pointer to the add-on.
    * @param hook The hook to add.
    */
-  static void PVRAddMenuHook(void *addonData, PVR_MENUHOOK *hook);
+  static void PVRAddMenuHook(void* addonData, PVR_MENUHOOK* hook);
 
   /*!
-   * @brief Notify XBMC that a recording has started or stoppped.
+   * @brief Display a notification in XBMC that a recording started or stopped on the server
    * @param addonData A pointer to the add-on.
-   * @param strName The name of the recording.
-   * @param strFileName The filename of the recording.
-   * @param bOnOff True if the recording started, false if it stopped.
+   * @param strName The name of the recording to display
+   * @param strFileName The filename of the recording
+   * @param bOnOff True when recording started, false when it stopped
    */
-  static void PVRRecording(void *addonData, const char *strName, const char *strFileName, bool bOnOff);
+  static void PVRRecording(void* addonData, const char* strName, const char* strFileName, bool bOnOff);
 
   /*!
-   * @brief Ask the PVRManager to refresh it's channels list.
+   * @brief Request XBMC to update it's list of channels
    * @param addonData A pointer to the add-on.
    */
-  static void PVRTriggerChannelUpdate(void *addonData);
+  static void PVRTriggerChannelUpdate(voidaddonData);
 
   /*!
-   * @brief Ask the PVRManager to refresh it's timers list.
+   * @brief Request XBMC to update it's list of timers
    * @param addonData A pointer to the add-on.
    */
-  static void PVRTriggerTimerUpdate(void *addonData);
+  static void PVRTriggerTimerUpdate(voidaddonData);
 
   /*!
-   * @brief Ask the PVRManager to refresh it's recordings list.
+   * @brief Request XBMC to update it's list of recordings
    * @param addonData A pointer to the add-on.
    */
-  static void PVRTriggerRecordingUpdate(void *addonData);
+  static void PVRTriggerRecordingUpdate(voidaddonData);
 
   /*!
-   * @brief Ask the PVRManager to refresh it's channel groups list.
+   * @brief Request XBMC to update it's list of channel groups
    * @param addonData A pointer to the add-on.
    */
-  static void PVRTriggerChannelGroupsUpdate(void *addonData);
+  static void PVRTriggerChannelGroupsUpdate(voidaddonData);
 
   /*!
-   * @brief Free an allocated demux packet.
+   * @brief Schedule an EPG update for the given channel channel
+   * @param addonData A pointer to the add-on
+   * @param iChannelUid The unique id of the channel for this add-on
+   */
+  static void PVRTriggerEpgUpdate(void* addonData, unsigned int iChannelUid);
+
+  /*!
+   * @brief Free a packet that was allocated with AllocateDemuxPacket
    * @param addonData A pointer to the add-on.
    * @param pPacket The packet to free.
    */
-  static void PVRFreeDemuxPacket(void *addonData, DemuxPacket* pPacket);
+  static void PVRFreeDemuxPacket(voidaddonData, DemuxPacket* pPacket);
 
   /*!
-   * @brief Allocate a new demux packet.
+   * @brief Allocate a demux packet. Free with FreeDemuxPacket
    * @param addonData A pointer to the add-on.
-   * @param iDataSize The packet size.
+   * @param iDataSize The size of the data that will go into the packet
    * @return The allocated packet.
    */
-  static DemuxPacket* PVRAllocateDemuxPacket(void *addonData, int iDataSize = 0);
+  static DemuxPacket* PVRAllocateDemuxPacket(voidaddonData, int iDataSize = 0);
 
 private:
-  static PVR::CPVRClient *GetPVRClient(void *addonData);
+  static PVR::CPVRClient* GetPVRClient(void* addonData);
 
   CB_PVRLib    *m_callbacks; /*!< callback addresses */
   CAddon       *m_addon;     /*!< the addon */
index 0776b0f..06a359d 100644 (file)
@@ -48,7 +48,7 @@ namespace ADDON
     virtual void SaveSettings();
     virtual CStdString GetSetting(const CStdString& key);
 
-    bool Create();
+    ADDON_STATUS Create();
     virtual void Stop();
     void Destroy();
 
@@ -200,13 +200,14 @@ bool CAddonDll<TheDll, TheStruct, TheProps>::LoadDll()
 }
 
 template<class TheDll, typename TheStruct, typename TheProps>
-bool CAddonDll<TheDll, TheStruct, TheProps>::Create()
+ADDON_STATUS CAddonDll<TheDll, TheStruct, TheProps>::Create()
 {
+  ADDON_STATUS status(ADDON_STATUS_UNKNOWN);
   CLog::Log(LOGDEBUG, "ADDON: Dll Initializing - %s", Name().c_str());
   m_initialized = false;
 
   if (!LoadDll())
-    return false;
+    return ADDON_STATUS_PERMANENT_FAILURE;
 
   /* Allocate the helper function class to allow crosstalk over
      helper libraries */
@@ -216,13 +217,13 @@ bool CAddonDll<TheDll, TheStruct, TheProps>::Create()
      needed to become the AddOn running */
   try
   {
-    ADDON_STATUS status = m_pDll->Create(m_pHelpers->GetCallbacks(), m_pInfo);
+    status = m_pDll->Create(m_pHelpers->GetCallbacks(), m_pInfo);
     if (status == ADDON_STATUS_OK)
       m_initialized = true;
     else if ((status == ADDON_STATUS_NEED_SETTINGS) || (status == ADDON_STATUS_NEED_SAVEDSETTINGS))
     {
       m_needsavedsettings = (status == ADDON_STATUS_NEED_SAVEDSETTINGS);
-      if (TransferSettings() == ADDON_STATUS_OK)
+      if ((status = TransferSettings()) == ADDON_STATUS_OK)
         m_initialized = true;
       else
         new CAddonStatusHandler(ID(), status, "", false);
@@ -238,10 +239,10 @@ bool CAddonDll<TheDll, TheStruct, TheProps>::Create()
     HandleException(e, "m_pDll->Create");
   }
 
-  if  (!m_initialized)
+  if (!m_initialized)
     SAFE_DELETE(m_pHelpers);
 
-  return m_initialized;
+  return status;
 }
 
 template<class TheDll, typename TheStruct, typename TheProps>
index 716c2ac..6d3b08e 100644 (file)
@@ -72,7 +72,7 @@ bool CScreenSaver::CreateScreenSaver()
   m_pInfo->presets    = strdup(CSpecialProtocol::TranslatePath(Path()).c_str());
   m_pInfo->profile    = strdup(CSpecialProtocol::TranslatePath(Profile()).c_str());
 
-  if (CAddonDll<DllScreenSaver, ScreenSaver, SCR_PROPS>::Create())
+  if (CAddonDll<DllScreenSaver, ScreenSaver, SCR_PROPS>::Create() == ADDON_STATUS_OK)
     return true;
 
   return false;
index f9a5e68..5128f68 100644 (file)
@@ -82,7 +82,7 @@ bool CVisualisation::Create(int x, int y, int w, int h)
   m_pInfo->profile = strdup(CSpecialProtocol::TranslatePath(Profile()).c_str());
   m_pInfo->submodule = NULL;
 
-  if (CAddonDll<DllVisualisation, Visualisation, VIS_PROPS>::Create())
+  if (CAddonDll<DllVisualisation, Visualisation, VIS_PROPS>::Create() == ADDON_STATUS_OK)
   {
     // Start the visualisation
     CStdString strFile = URIUtils::GetFileName(g_application.CurrentFile());
index eec957e..37714f3 100644 (file)
@@ -32,7 +32,8 @@ enum ADDON_STATUS
   ADDON_STATUS_NEED_RESTART,
   ADDON_STATUS_NEED_SETTINGS,
   ADDON_STATUS_UNKNOWN,
-  ADDON_STATUS_NEED_SAVEDSETTINGS
+  ADDON_STATUS_NEED_SAVEDSETTINGS,
+  ADDON_STATUS_PERMANENT_FAILURE   /**< permanent failure, like failing to resolve methods */
 };
 
 typedef struct
index 3c143db..bf108a2 100644 (file)
@@ -513,6 +513,25 @@ extern "C"
   unsigned int GetChannelSwitchDelay(void);
 
   /*!
+   * Check if the backend support pausing the currently playing stream
+   * This will enable/disable the pause button in XBMC based on the return value
+   * @return false if the PVR addon/backend does not support pausing, true if possible
+   */
+  bool CanPauseStream();
+
+  /*!
+   * Check if the backend supports seeking for the currently playing stream
+   * This will enable/disable the rewind/forward buttons in XBMC based on the return value
+   * @return false if the PVR addon/backend does not support seeking, true if possible
+   */
+  bool CanSeekStream();
+
+  /*!
+   * @brief Notify the pvr addon that XBMC (un)paused the currently playing stream
+   */
+  void PauseStream(bool bPaused);
+
+  /*!
    * Called by XBMC to assign the function pointers of this add-on to pClient.
    * @param pClient The struct to assign the function pointers to.
    */
@@ -568,6 +587,9 @@ extern "C"
     pClient->SignalStatus                   = SignalStatus;
     pClient->GetLiveStreamURL               = GetLiveStreamURL;
     pClient->GetChannelSwitchDelay          = GetChannelSwitchDelay;
+    pClient->CanPauseStream                 = CanPauseStream;
+    pClient->PauseStream                    = PauseStream;
+    pClient->CanSeekStream                  = CanSeekStream;
 
     pClient->OpenRecordedStream             = OpenRecordedStream;
     pClient->CloseRecordedStream            = CloseRecordedStream;
index e48c349..675ca09 100644 (file)
@@ -72,10 +72,10 @@ struct DemuxPacket;
 #define PVR_STREAM_MAX_STREAMS 20
 
 /* current PVR API version */
-#define XBMC_PVR_API_VERSION "1.4.0"
+#define XBMC_PVR_API_VERSION "1.5.0"
 
 /* min. PVR API version */
-#define XBMC_PVR_MIN_API_VERSION "1.4.0"
+#define XBMC_PVR_MIN_API_VERSION "1.5.0"
 
 #ifdef __cplusplus
 extern "C" {
@@ -103,12 +103,15 @@ extern "C" {
    */
   typedef enum
   {
-    PVR_TIMER_STATE_NEW       = 0, /*!< @brief a new, unsaved timer */
-    PVR_TIMER_STATE_SCHEDULED = 1, /*!< @brief the timer is scheduled for recording */
-    PVR_TIMER_STATE_RECORDING = 2, /*!< @brief the timer is currently recordings */
-    PVR_TIMER_STATE_COMPLETED = 3, /*!< @brief the recording completed successfully */
-    PVR_TIMER_STATE_ABORTED   = 4, /*!< @brief recording started, but was aborted */
-    PVR_TIMER_STATE_CANCELLED = 5  /*!< @brief the timer was scheduled, but was canceled */
+    PVR_TIMER_STATE_NEW          = 0, /*!< @brief a new, unsaved timer */
+    PVR_TIMER_STATE_SCHEDULED    = 1, /*!< @brief the timer is scheduled for recording */
+    PVR_TIMER_STATE_RECORDING    = 2, /*!< @brief the timer is currently recordings */
+    PVR_TIMER_STATE_COMPLETED    = 3, /*!< @brief the recording completed successfully */
+    PVR_TIMER_STATE_ABORTED      = 4, /*!< @brief recording started, but was aborted */
+    PVR_TIMER_STATE_CANCELLED    = 5, /*!< @brief the timer was scheduled, but was canceled */
+    PVR_TIMER_STATE_CONFLICT_OK  = 6, /*!< @brief the scheduled timer conflicts with another one, but will be recorded */
+    PVR_TIMER_STATE_CONFLICT_NOK = 7, /*!< @brief the scheduled timer conflicts with another one and won't be recorded */
+    PVR_TIMER_STATE_ERROR        = 8  /*!< @brief the timer is scheduled, but can't be recorded for some reason */
   } PVR_TIMER_STATE;
 
   /*!
@@ -329,6 +332,9 @@ extern "C" {
     void         (__cdecl* DemuxFlush)(void);
     DemuxPacket* (__cdecl* DemuxRead)(void);
     unsigned int (__cdecl* GetChannelSwitchDelay)(void);
+    bool         (__cdecl* CanPauseStream)(void);
+    void         (__cdecl* PauseStream)(bool);
+    bool         (__cdecl* CanSeekStream)(void);
   } PVRClient;
 
 #ifdef __cplusplus
index 530fbdf..0abfafd 100644 (file)
@@ -188,12 +188,31 @@ bool CAEChannelInfo::operator!=(const CAEChannelInfo& rhs)
   return !(*this == rhs);
 }
 
-void CAEChannelInfo::operator+=(const enum AEChannel rhs)
+CAEChannelInfo& CAEChannelInfo::operator+=(const enum AEChannel& rhs)
 {
   ASSERT(m_channelCount < AE_CH_MAX);
   ASSERT(rhs > AE_CH_NULL && rhs < AE_CH_MAX);
 
   m_channels[m_channelCount++] = rhs;
+  return *this;
+}
+
+CAEChannelInfo& CAEChannelInfo::operator-=(const enum AEChannel& rhs)
+{
+  ASSERT(rhs > AE_CH_NULL && rhs < AE_CH_MAX);
+
+  unsigned int i = 0;
+  while(i < m_channelCount && m_channels[i] != rhs)
+    i++;
+  if (i >= m_channelCount)
+    return *this; // Channel not found
+
+  for(; i < m_channelCount-1; i++)
+    m_channels[i] = m_channels[i+1];
+
+  m_channels[i] = AE_CH_NULL;
+  m_channelCount--;
+  return *this;
 }
 
 const enum AEChannel CAEChannelInfo::operator[](unsigned int i) const
index 66f6bd7..1cd47da 100644 (file)
@@ -80,7 +80,8 @@ public:
   CAEChannelInfo& operator=(const enum AEStdChLayout rhs);
   bool operator==(const CAEChannelInfo& rhs);
   bool operator!=(const CAEChannelInfo& rhs);
-  void operator+=(const enum AEChannel rhs);
+  CAEChannelInfo& operator+=(const enum AEChannel& rhs);
+  CAEChannelInfo& operator-=(const enum AEChannel& rhs);
   const enum AEChannel operator[](unsigned int i) const;
   operator std::string();
 
index 1ada0ad..cdf38d3 100644 (file)
@@ -206,9 +206,9 @@ extern "C" void __stdcall init_emu_environ()
 extern "C" void __stdcall update_emu_environ()
 {
   // Use a proxy, if the GUI was configured as such
-  if (g_guiSettings.GetBool("network.usehttpproxy") &&
-      g_guiSettings.GetString("network.httpproxyserver") &&
-      g_guiSettings.GetString("network.httpproxyport"))
+  if (g_guiSettings.GetBool("network.usehttpproxy")
+      && !g_guiSettings.GetString("network.httpproxyserver").empty()
+      && !g_guiSettings.GetString("network.httpproxyport").empty())
   {
     CStdString strProxy;
     if (g_guiSettings.GetString("network.httpproxyusername") &&
index 5482342..2042026 100644 (file)
@@ -71,6 +71,24 @@ public:
 class CFileItem;
 class CRect;
 
+enum IPlayerAudioCapabilities
+{
+  IPC_AUD_ALL,
+  IPC_AUD_OFFSET,
+  IPC_AUD_AMP,
+  IPC_AUD_SELECT_STREAM,
+  IPC_AUD_OUTPUT_STEREO,
+  IPC_AUD_SELECT_OUTPUT
+};
+
+enum IPlayerSubtitleCapabilities
+{
+  IPC_SUBS_ALL,
+  IPC_SUBS_SELECT,
+  IPC_SUBS_EXTERNAL,
+  IPC_SUBS_OFFSET
+};
+
 class IPlayer
 {
 public:
@@ -84,6 +102,7 @@ public:
   virtual void OnNothingToQueueNotify() {}
   virtual bool CloseFile(){ return true;}
   virtual bool IsPlaying() const { return false;}
+  virtual bool CanPause() { return true; };
   virtual void Pause() = 0;
   virtual bool IsPaused() const = 0;
   virtual bool HasVideo() const = 0;
@@ -181,6 +200,33 @@ public:
   virtual CStdString GetPlayingTitle() { return ""; };
 
   virtual bool SwitchChannel(const PVR::CPVRChannel &channel) { return false; }
+
+  /*!
+   \brief If the player uses bypass mode, define its rendering capabilities
+   */
+  virtual void GetRenderFeatures(std::vector<int> &renderFeatures) {};
+  /*!
+   \brief If the player uses bypass mode, define its deinterlace algorithms
+   */
+  virtual void GetDeinterlaceMethods(std::vector<int> &deinterlaceMethods) {};
+  /*!
+   \brief If the player uses bypass mode, define how deinterlace is set
+   */
+  virtual void GetDeinterlaceModes(std::vector<int> &deinterlaceModes) {};
+  /*!
+   \brief If the player uses bypass mode, define its scaling capabilities
+   */
+  virtual void GetScalingMethods(std::vector<int> &scalingMethods) {};
+  /*!
+   \brief define the audio capabilities of the player (default=all)
+   */
+
+  virtual void GetAudioCapabilities(std::vector<int> &audioCaps) { audioCaps.assign(1,IPC_AUD_ALL); };
+  /*!
+   \brief define the subtitle capabilities of the player
+   */
+  virtual void GetSubtitleCapabilities(std::vector<int> &subCaps) { subCaps.assign(1,IPC_SUBS_ALL); };
+
 protected:
   IPlayerCallback& m_callback;
 };
index 5a27765..fdd0ad4 100644 (file)
@@ -56,7 +56,13 @@ enum ERENDERFEATURE
   RENDERFEATURE_NOISE,
   RENDERFEATURE_SHARPNESS,
   RENDERFEATURE_NONLINSTRETCH,
-  RENDERFEATURE_ROTATION
+  RENDERFEATURE_ROTATION,
+  RENDERFEATURE_STRETCH,
+  RENDERFEATURE_CROP,
+  RENDERFEATURE_ZOOM,
+  RENDERFEATURE_VERTICAL_SHIFT,
+  RENDERFEATURE_PIXEL_RATIO,
+  RENDERFEATURE_POSTPROCESS
 };
 
 typedef void (*RenderUpdateCallBackFn)(const void *ctx, const CRect &SrcRect, const CRect &DestRect);
index b64f5ae..9298e8a 100644 (file)
@@ -256,6 +256,15 @@ bool CLinuxRendererGL::ValidateRenderTarget()
     else
       CLog::Log(LOGNOTICE,"Using GL_TEXTURE_2D");
 
+    // function pointer for texture might change in
+    // call to LoadShaders
+    glFinish();
+    for (int i = 0 ; i < m_NumYV12Buffers ; i++)
+      (this->*m_textureDelete)(i);
+
+    // trigger update of video filters
+    m_scalingMethodGui = (ESCALINGMETHOD)-1;
+
      // create the yuv textures
     LoadShaders();
 
@@ -593,6 +602,7 @@ void CLinuxRendererGL::Flush()
 
   glFinish();
   m_bValidated = false;
+  m_fbo.fbo.Cleanup();
 }
 
 void CLinuxRendererGL::Update(bool bPauseDrawing)
@@ -847,7 +857,7 @@ void CLinuxRendererGL::UpdateVideoFilter()
     delete m_pVideoFilterShader;
     m_pVideoFilterShader = NULL;
   }
-  m_fbo.Cleanup();
+  m_fbo.fbo.Cleanup();
 
   VerifyGLState();
 
@@ -888,13 +898,13 @@ void CLinuxRendererGL::UpdateVideoFilter()
   case VS_SCALINGMETHOD_CUBIC:
     if (m_renderMethod & RENDER_GLSL)
     {
-      if (!m_fbo.Initialize())
+      if (!m_fbo.fbo.Initialize())
       {
         CLog::Log(LOGERROR, "GL: Error initializing FBO");
         break;
       }
 
-      if (!m_fbo.CreateAndBindToTexture(GL_TEXTURE_2D, m_sourceWidth, m_sourceHeight, GL_RGBA))
+      if (!m_fbo.fbo.CreateAndBindToTexture(GL_TEXTURE_2D, m_sourceWidth, m_sourceHeight, GL_RGBA))
       {
         CLog::Log(LOGERROR, "GL: Error creating texture and binding to FBO");
         break;
@@ -932,7 +942,7 @@ void CLinuxRendererGL::UpdateVideoFilter()
     delete m_pVideoFilterShader;
     m_pVideoFilterShader = NULL;
   }
-  m_fbo.Cleanup();
+  m_fbo.fbo.Cleanup();
 
   SetTextureFilter(GL_LINEAR);
   m_renderQuality = RQ_SINGLEPASS;
@@ -1141,7 +1151,7 @@ void CLinuxRendererGL::UnInit()
     (this->*m_textureDelete)(i);
 
   // cleanup framebuffer object if it was in use
-  m_fbo.Cleanup();
+  m_fbo.fbo.Cleanup();
   m_bValidated = false;
   m_bImageReady = false;
   m_bConfigured = false;
@@ -1299,6 +1309,12 @@ void CLinuxRendererGL::RenderSinglePass(int index, int field)
 
 void CLinuxRendererGL::RenderMultiPass(int index, int field)
 {
+  RenderToFBO(index, field);
+  RenderFromFBO();
+}
+
+void CLinuxRendererGL::RenderToFBO(int index, int field)
+{
   YUVPLANES &planes = m_buffers[index].fields[field];
 
   if (m_reloadShaders)
@@ -1307,6 +1323,21 @@ void CLinuxRendererGL::RenderMultiPass(int index, int field)
     LoadShaders(m_currentField);
   }
 
+  if (!m_fbo.fbo.IsValid())
+  {
+    if (!m_fbo.fbo.Initialize())
+    {
+      CLog::Log(LOGERROR, "GL: Error initializing FBO");
+      return;
+    }
+
+    if (!m_fbo.fbo.CreateAndBindToTexture(GL_TEXTURE_2D, m_sourceWidth, m_sourceHeight, GL_RGBA))
+    {
+      CLog::Log(LOGERROR, "GL: Error creating texture and binding to FBO");
+      return;
+    }
+  }
+
   glDisable(GL_DEPTH_TEST);
 
   // Y
@@ -1337,7 +1368,7 @@ void CLinuxRendererGL::RenderMultiPass(int index, int field)
     return;
   }
 
-  m_fbo.BeginRender();
+  m_fbo.fbo.BeginRender();
   VerifyGLState();
 
   m_pYUVShader->SetBlack(g_settings.m_currentVideoSettings.m_Brightness * 0.01f - 0.5f);
@@ -1375,15 +1406,15 @@ void CLinuxRendererGL::RenderMultiPass(int index, int field)
     CLog::Log(LOGERROR, "GL: Error enabling YUV shader");
   }
 
-  float imgwidth  = planes[0].rect.x2 - planes[0].rect.x1;
-  float imgheight = planes[0].rect.y2 - planes[0].rect.y1;
+  m_fbo.width  = planes[0].rect.x2 - planes[0].rect.x1;
+  m_fbo.height = planes[0].rect.y2 - planes[0].rect.y1;
   if (m_textureTarget == GL_TEXTURE_2D)
   {
-    imgwidth  *= planes[0].texwidth;
-    imgheight *= planes[0].texheight;
+    m_fbo.width  *= planes[0].texwidth;
+    m_fbo.height *= planes[0].texheight;
   }
-  imgwidth  *= planes[0].pixpertex_x;
-  imgheight *= planes[0].pixpertex_y;
+  m_fbo.width  *= planes[0].pixpertex_x;
+  m_fbo.height *= planes[0].pixpertex_y;
 
   // 1st Pass to video frame size
   glBegin(GL_QUADS);
@@ -1396,17 +1427,17 @@ void CLinuxRendererGL::RenderMultiPass(int index, int field)
   glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x2, planes[0].rect.y1);
   glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x2, planes[1].rect.y1);
   glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x2, planes[2].rect.y1);
-  glVertex2f(imgwidth, 0.0f);
+  glVertex2f(m_fbo.width, 0.0f);
 
   glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x2, planes[0].rect.y2);
   glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x2, planes[1].rect.y2);
   glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x2, planes[2].rect.y2);
-  glVertex2f(imgwidth, imgheight);
+  glVertex2f(m_fbo.width, m_fbo.height);
 
   glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x1, planes[0].rect.y2);
   glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x1, planes[1].rect.y2);
   glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x1, planes[2].rect.y2);
-  glVertex2f(0.0f    , imgheight);
+  glVertex2f(0.0f    , m_fbo.height);
 
   glEnd();
   VerifyGLState();
@@ -1422,7 +1453,7 @@ void CLinuxRendererGL::RenderMultiPass(int index, int field)
   glMatrixMode(GL_MODELVIEW);
   VerifyGLState();
 
-  m_fbo.EndRender();
+  m_fbo.fbo.EndRender();
 
   glActiveTextureARB(GL_TEXTURE1);
   glDisable(m_textureTarget);
@@ -1430,9 +1461,12 @@ void CLinuxRendererGL::RenderMultiPass(int index, int field)
   glDisable(m_textureTarget);
   glActiveTextureARB(GL_TEXTURE0);
   glDisable(m_textureTarget);
+}
 
-  glEnable(GL_TEXTURE_2D);
-  glBindTexture(GL_TEXTURE_2D, m_fbo.Texture());
+void CLinuxRendererGL::RenderFromFBO()
+{
+  glEnable(m_textureTarget);
+  glActiveTextureARB(GL_TEXTURE0);
   VerifyGLState();
 
   // Use regular normalized texture coordinates
@@ -1445,7 +1479,7 @@ void CLinuxRendererGL::RenderMultiPass(int index, int field)
     if (!m_pVideoFilterShader->GetTextureFilter(filter))
       filter = m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR;
 
-    m_fbo.SetFiltering(GL_TEXTURE_2D, filter);
+    m_fbo.fbo.SetFiltering(m_textureTarget, filter);
     m_pVideoFilterShader->SetSourceTexture(0);
     m_pVideoFilterShader->SetWidth(m_sourceWidth);
     m_pVideoFilterShader->SetHeight(m_sourceHeight);
@@ -1462,17 +1496,18 @@ void CLinuxRendererGL::RenderMultiPass(int index, int field)
   else
   {
     GLint filter = m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR;
-    m_fbo.SetFiltering(GL_TEXTURE_2D, filter);
+    m_fbo.fbo.SetFiltering(m_textureTarget, filter);
+    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   }
 
   VerifyGLState();
 
-  imgwidth  /= m_sourceWidth;
-  imgheight /= m_sourceHeight;
+  float imgwidth = m_fbo.width / m_sourceWidth;
+  float imgheight = m_fbo.height / m_sourceHeight;
 
   glBegin(GL_QUADS);
 
-  glMultiTexCoord2fARB(GL_TEXTURE0, 0.0f    , 0.0f);
+  glMultiTexCoord2fARB(GL_TEXTURE0, 0.0f, 0.0f);
   glVertex4f(m_rotatedDestCoords[0].x, m_rotatedDestCoords[0].y, 0, 1.0f );
 
   glMultiTexCoord2fARB(GL_TEXTURE0, imgwidth, 0.0f);
@@ -1481,7 +1516,7 @@ void CLinuxRendererGL::RenderMultiPass(int index, int field)
   glMultiTexCoord2fARB(GL_TEXTURE0, imgwidth, imgheight);
   glVertex4f(m_rotatedDestCoords[2].x, m_rotatedDestCoords[2].y, 0, 1.0f );
   
-  glMultiTexCoord2fARB(GL_TEXTURE0, 0.0f    , imgheight);
+  glMultiTexCoord2fARB(GL_TEXTURE0, 0.0f, imgheight);
   glVertex4f(m_rotatedDestCoords[3].x, m_rotatedDestCoords[3].y, 0, 1.0f );
 
   glEnd();
@@ -1493,6 +1528,7 @@ void CLinuxRendererGL::RenderMultiPass(int index, int field)
 
   VerifyGLState();
 
+  glBindTexture(m_textureTarget, 0);
   glDisable(m_textureTarget);
   VerifyGLState();
 }
@@ -3201,7 +3237,13 @@ bool CLinuxRendererGL::Supports(ERENDERFEATURE feature)
       return true;
   }
 
-  if (feature == RENDERFEATURE_ROTATION)
+  if (feature == RENDERFEATURE_STRETCH         ||
+      feature == RENDERFEATURE_CROP            ||
+      feature == RENDERFEATURE_ZOOM            ||
+      feature == RENDERFEATURE_VERTICAL_SHIFT  ||
+      feature == RENDERFEATURE_PIXEL_RATIO     ||
+      feature == RENDERFEATURE_POSTPROCESS     ||
+      feature == RENDERFEATURE_ROTATION)
     return true;
 
   return false;
index 77544e9..acebfe0 100644 (file)
@@ -213,12 +213,18 @@ protected:
 
   // renderers
   void RenderMultiPass(int renderBuffer, int field);  // multi pass glsl renderer
+  void RenderToFBO(int renderBuffer, int field);
+  void RenderFromFBO();
   void RenderSinglePass(int renderBuffer, int field); // single pass glsl renderer
   void RenderSoftware(int renderBuffer, int field);   // single pass s/w yuv2rgb renderer
   void RenderVDPAU(int renderBuffer, int field);      // render using vdpau hardware
   void RenderVAAPI(int renderBuffer, int field);      // render using vdpau hardware
 
-  CFrameBufferObject m_fbo;
+  struct
+  {
+    CFrameBufferObject fbo;
+    float width, height;
+  } m_fbo;
 
   int m_iYV12RenderBuffer;
   int m_NumYV12Buffers;
index ebaf5d8..40c91a5 100644 (file)
@@ -46,6 +46,7 @@
 #include "threads/SingleLock.h"
 #include "RenderCapture.h"
 #include "RenderFormats.h"
+#include "xbmc/Application.h"
 
 #if defined(__ARM_NEON__)
 #include "yuv2rgb.neon.h"
@@ -190,6 +191,13 @@ bool CLinuxRendererGLES::Configure(unsigned int width, unsigned int height, unsi
 
   m_RenderUpdateCallBackFn = NULL;
   m_RenderUpdateCallBackCtx = NULL;
+  if ((m_format == RENDER_FMT_BYPASS) && g_application.GetCurrentPlayer())
+  {
+    g_application.m_pPlayer->GetRenderFeatures(m_renderFeatures);
+    g_application.m_pPlayer->GetDeinterlaceMethods(m_deinterlaceMethods);
+    g_application.m_pPlayer->GetDeinterlaceModes(m_deinterlaceModes);
+    g_application.m_pPlayer->GetScalingMethods(m_scalingMethods);
+  }
 
   return true;
 }
@@ -1818,6 +1826,13 @@ void CLinuxRendererGLES::SetTextureFilter(GLenum method)
 
 bool CLinuxRendererGLES::Supports(ERENDERFEATURE feature)
 {
+  // Player controls render, let it dictate available render features
+  if((m_renderMethod & RENDER_BYPASS))
+  {
+    Features::iterator itr = std::find(m_renderFeatures.begin(),m_renderFeatures.end(), feature);
+    return itr != m_renderFeatures.end();
+  }
+
   if(feature == RENDERFEATURE_BRIGHTNESS)
     return false;
 
@@ -1836,9 +1851,16 @@ bool CLinuxRendererGLES::Supports(ERENDERFEATURE feature)
   if (feature == RENDERFEATURE_NONLINSTRETCH)
     return false;
 
-  if (feature == RENDERFEATURE_ROTATION)
+  if (feature == RENDERFEATURE_STRETCH         ||
+      feature == RENDERFEATURE_CROP            ||
+      feature == RENDERFEATURE_ZOOM            ||
+      feature == RENDERFEATURE_VERTICAL_SHIFT  ||
+      feature == RENDERFEATURE_PIXEL_RATIO     ||
+      feature == RENDERFEATURE_POSTPROCESS     ||
+      feature == RENDERFEATURE_ROTATION)
     return true;
 
+
   return false;
 }
 
@@ -1849,6 +1871,13 @@ bool CLinuxRendererGLES::SupportsMultiPassRendering()
 
 bool CLinuxRendererGLES::Supports(EDEINTERLACEMODE mode)
 {
+  // Player controls render, let it dictate available deinterlace modes
+  if((m_renderMethod & RENDER_BYPASS))
+  {
+    Features::iterator itr = std::find(m_deinterlaceModes.begin(),m_deinterlaceModes.end(), mode);
+    return itr != m_deinterlaceModes.end();
+  }
+
   if (mode == VS_DEINTERLACEMODE_OFF)
     return true;
 
@@ -1867,6 +1896,13 @@ bool CLinuxRendererGLES::Supports(EDEINTERLACEMODE mode)
 
 bool CLinuxRendererGLES::Supports(EINTERLACEMETHOD method)
 {
+  // Player controls render, let it dictate available deinterlace methods
+  if((m_renderMethod & RENDER_BYPASS))
+  {
+    Features::iterator itr = std::find(m_deinterlaceMethods.begin(),m_deinterlaceMethods.end(), method);
+    return itr != m_deinterlaceMethods.end();
+  }
+
   if(m_renderMethod & RENDER_OMXEGL)
     return false;
 
@@ -1890,6 +1926,13 @@ bool CLinuxRendererGLES::Supports(EINTERLACEMETHOD method)
 
 bool CLinuxRendererGLES::Supports(ESCALINGMETHOD method)
 {
+  // Player controls render, let it dictate available scaling methods
+  if((m_renderMethod & RENDER_BYPASS))
+  {
+    Features::iterator itr = std::find(m_scalingMethods.begin(),m_scalingMethods.end(), method);
+    return itr != m_scalingMethods.end();
+  }
+
   if(method == VS_SCALINGMETHOD_NEAREST
   || method == VS_SCALINGMETHOD_LINEAR)
     return true;
@@ -1899,6 +1942,15 @@ bool CLinuxRendererGLES::Supports(ESCALINGMETHOD method)
 
 EINTERLACEMETHOD CLinuxRendererGLES::AutoInterlaceMethod()
 {
+  // Player controls render, let it pick the auto-deinterlace method
+  if((m_renderMethod & RENDER_BYPASS))
+  {
+    if (m_deinterlaceMethods.size())
+      return ((EINTERLACEMETHOD)m_deinterlaceMethods[0]);
+    else
+      return VS_INTERLACEMETHOD_NONE;
+  }
+
   if(m_renderMethod & RENDER_OMXEGL)
     return VS_INTERLACEMETHOD_NONE;
 
index 875ee58..76b5437 100644 (file)
@@ -39,6 +39,7 @@ class CBaseTexture;
 namespace Shaders { class BaseYUV2RGBShader; }
 namespace Shaders { class BaseVideoFilterShader; }
 class COpenMaxVideo;
+typedef std::vector<int>     Features;
 
 #define NUM_BUFFERS 3
 
@@ -266,6 +267,11 @@ protected:
   ESCALINGMETHOD m_scalingMethod;
   ESCALINGMETHOD m_scalingMethodGui;
 
+  Features m_renderFeatures;
+  Features m_deinterlaceMethods;
+  Features m_deinterlaceModes;
+  Features m_scalingMethods;
+
   // clear colour for "black" bars
   float m_clearColour;
 
index 77e2057..7842089 100644 (file)
@@ -1036,6 +1036,16 @@ bool CWinRenderer::Supports(ERENDERFEATURE feature)
   if(feature == RENDERFEATURE_CONTRAST)
     return true;
 
+  if (feature == RENDERFEATURE_STRETCH         ||
+      feature == RENDERFEATURE_NONLINSTRETCH   ||
+      feature == RENDERFEATURE_CROP            ||
+      feature == RENDERFEATURE_ZOOM            ||
+      feature == RENDERFEATURE_VERTICAL_SHIFT  ||
+      feature == RENDERFEATURE_PIXEL_RATIO     ||
+      feature == RENDERFEATURE_POSTPROCESS)
+    return true;
+
+
   return false;
 }
 
index fd29e39..1a75b3a 100644 (file)
 #include "utils/LangCodeExpander.h"
 #include "utils/Variant.h"
 #include "windowing/WindowingFactory.h"
-#include "windowing/egl/WinEGLPlatform.h"
 
 // for external subtitles
 #include "xbmc/cores/dvdplayer/DVDClock.h"
 #include "xbmc/cores/dvdplayer/DVDPlayerSubtitle.h"
 #include "xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxVobsub.h"
+#include "settings/VideoSettings.h"
 
 // amlogic libplayer
 #include "AMLUtils.h"
@@ -2289,3 +2289,42 @@ void CAMLPlayer::RenderUpdateCallBack(const void *ctx, const CRect &SrcRect, con
   CAMLPlayer *player = (CAMLPlayer*)ctx;
   player->SetVideoRect(SrcRect, DestRect);
 }
+
+void CAMLPlayer::GetRenderFeatures(std::vector<int> &renderFeatures)
+{
+  renderFeatures.push_back(RENDERFEATURE_ZOOM);
+  renderFeatures.push_back(RENDERFEATURE_CONTRAST);
+  renderFeatures.push_back(RENDERFEATURE_BRIGHTNESS);
+  renderFeatures.push_back(RENDERFEATURE_STRETCH);
+}
+
+void CAMLPlayer::GetDeinterlaceMethods(std::vector<int> &deinterlaceMethods)
+{
+  deinterlaceMethods.push_back(VS_INTERLACEMETHOD_DEINTERLACE);
+}
+
+void CAMLPlayer::GetDeinterlaceModes(std::vector<int> &deinterlaceModes)
+{
+  deinterlaceModes.push_back(VS_DEINTERLACEMODE_AUTO);
+}
+
+void CAMLPlayer::GetScalingMethods(std::vector<int> &scalingMethods)
+{
+}
+
+void CAMLPlayer::GetAudioCapabilities(std::vector<int> &audioCaps)
+{
+  audioCaps.push_back(IPC_AUD_SELECT_STREAM);
+  audioCaps.push_back(IPC_AUD_SELECT_OUTPUT);
+#if !defined(TARGET_ANDROID)
+  audioCaps.push_back(IPC_AUD_OFFSET);
+#endif
+}
+
+void CAMLPlayer::GetSubtitleCapabilities(std::vector<int> &subCaps)
+{
+  subCaps.push_back(IPC_SUBS_EXTERNAL);
+  subCaps.push_back(IPC_SUBS_SELECT);
+  subCaps.push_back(IPC_SUBS_OFFSET);
+}
+
index 316e385..54d8fae 100644 (file)
@@ -165,6 +165,13 @@ public:
   virtual void  GetSubtitleCapabilities(Features* subCaps);
 */
 
+  virtual void  GetRenderFeatures(std::vector<int> &renderFeatures);
+  virtual void  GetDeinterlaceMethods(std::vector<int> &deinterlaceMethods);
+  virtual void  GetDeinterlaceModes(std::vector<int> &deinterlaceModes);
+  virtual void  GetScalingMethods(std::vector<int> &scalingMethods);
+  virtual void  GetAudioCapabilities(std::vector<int> &audioCaps);
+  virtual void  GetSubtitleCapabilities(std::vector<int> &subCaps);
+
 protected:
   virtual void  OnStartup();
   virtual void  OnExit();
index 93f0739..de04389 100644 (file)
 
 using namespace std;
 
+
+CPTSOutputQueue::CPTSOutputQueue()
+{
+  Flush();
+}
+
+void CPTSOutputQueue::Add(double pts, double delay, double duration)
+{
+  CSingleLock lock(m_sync);
+
+  // don't accept a re-add, since that would cause time moving back
+  double last = m_queue.empty() ? m_current.pts : m_queue.back().pts;
+  if(last == pts)
+    return;
+
+  TPTSItem item;
+  item.pts = pts;
+  item.timestamp = CDVDClock::GetAbsoluteClock() + delay;
+  item.duration = duration;
+
+  // first one is applied directly
+  if(m_queue.empty() && m_current.pts == DVD_NOPTS_VALUE)
+    m_current = item;
+  else
+    m_queue.push(item);
+
+  // call function to make sure the queue
+  // doesn't grow should nobody call it
+  Current();
+}
+void CPTSOutputQueue::Flush()
+{
+  CSingleLock lock(m_sync);
+
+  while( !m_queue.empty() ) m_queue.pop();
+  m_current.pts = DVD_NOPTS_VALUE;
+  m_current.timestamp = 0.0;
+  m_current.duration = 0.0;
+}
+
+double CPTSOutputQueue::Current()
+{
+  CSingleLock lock(m_sync);
+
+  if(!m_queue.empty() && m_current.pts == DVD_NOPTS_VALUE)
+  {
+    m_current = m_queue.front();
+    m_queue.pop();
+  }
+
+  while( !m_queue.empty() && CDVDClock::GetAbsoluteClock() >= m_queue.front().timestamp )
+  {
+    m_current = m_queue.front();
+    m_queue.pop();
+  }
+
+  if( m_current.timestamp == 0 ) return m_current.pts;
+
+  return m_current.pts + min(m_current.duration, (CDVDClock::GetAbsoluteClock() - m_current.timestamp));
+}
+
+
 CDVDAudio::CDVDAudio(volatile bool &bStop)
   : m_bStop(bStop)
 {
@@ -114,6 +176,7 @@ void CDVDAudio::Destroy()
   m_iBitsPerSample = 0;
   m_bPassthrough = false;
   m_bPaused = true;
+  m_time.Flush();
 }
 
 DWORD CDVDAudio::AddPacketsRenderer(unsigned char* data, DWORD len, CSingleLock &lock)
@@ -203,6 +266,10 @@ DWORD CDVDAudio::AddPackets(const DVDAudioFrame &audioframe)
     m_iBufferSize = len;
     memcpy(m_pBuffer, data, len);
   }
+
+  double time_added = DVD_SEC_TO_TIME(m_SecondsPerByte * (data - audioframe.data));
+  m_time.Add(audioframe.pts, GetDelay() - time_added, audioframe.duration);
+
   return total;
 }
 
@@ -276,6 +343,7 @@ void CDVDAudio::Pause()
 {
   CSingleLock lock (m_critSection);
   if (m_pAudioStream) m_pAudioStream->Pause();
+  m_time.Flush();
 }
 
 void CDVDAudio::Resume()
@@ -306,6 +374,7 @@ void CDVDAudio::Flush()
     m_pAudioStream->Flush();
   }
   m_iBufferSize = 0;
+  m_time.Flush();
 }
 
 bool CDVDAudio::IsValidFormat(const DVDAudioFrame &audioframe)
@@ -354,3 +423,10 @@ double CDVDAudio::GetCacheTotal()
     return 0.0;
   return m_pAudioStream->GetCacheTotal();
 }
+
+void CDVDAudio::SetPlayingPts(double pts)
+{
+  CSingleLock lock (m_critSection);
+  m_time.Flush();
+  m_time.Add(pts, GetDelay(), 0);
+}
index 2a3c58f..b2cbd46 100644 (file)
@@ -25,6 +25,7 @@
 #endif
 #include "threads/CriticalSection.h"
 #include "PlatformDefs.h"
+#include <queue>
 
 #include "cores/AudioEngine/Utils/AEChannelInfo.h"
 class IAEStream;
@@ -46,6 +47,22 @@ extern "C" {
 #endif
 typedef struct stDVDAudioFrame DVDAudioFrame;
 
+
+class CPTSOutputQueue
+{
+private:
+  typedef struct {double pts; double timestamp; double duration;} TPTSItem;
+  TPTSItem m_current;
+  std::queue<TPTSItem> m_queue;
+  CCriticalSection m_sync;
+
+public:
+  CPTSOutputQueue();
+  void Add(double pts, double delay, double duration);
+  void Flush();
+  double Current();
+};
+
 class CSingleLock;
 class IAudioCallback;
 
@@ -68,6 +85,8 @@ public:
   void Destroy();
   DWORD AddPackets(const DVDAudioFrame &audioframe);
   double GetDelay(); // returns the time it takes to play a packet if we add one at this time
+  double GetPlayingPts() { return m_time.Current(); }
+  void   SetPlayingPts(double pts);
   double GetCacheTime();  // returns total amount of data cached in audio output at this time
   double GetCacheTotal(); // returns total amount the audio device can buffer
   void Flush();
@@ -79,6 +98,7 @@ public:
 
   IAEStream *m_pAudioStream;
 protected:
+  CPTSOutputQueue m_time;
   DWORD AddPacketsRenderer(unsigned char* data, DWORD len, CSingleLock &lock);
   BYTE* m_pBuffer; // should be [m_dwPacketSize]
   DWORD m_iBufferSize;
index 9200ee2..8f81637 100644 (file)
@@ -492,7 +492,8 @@ int CDVDVideoCodecFFmpeg::Decode(BYTE* pData, int iSize, double dts, double pts)
     m_iLastKeyframe = 300;
 
   /* h264 doesn't always have keyframes + won't output before first keyframe anyway */
-  if(m_pCodecContext->codec_id == CODEC_ID_H264)
+  if(m_pCodecContext->codec_id == CODEC_ID_H264
+  || m_pCodecContext->codec_id == CODEC_ID_SVQ3)
     m_started = true;
 
   if(m_pHardware == NULL)
index 3132bbd..c080be2 100644 (file)
@@ -67,7 +67,7 @@ public:
   DemuxPacket* Read();
   bool SeekTime(int time, bool backwords = false, double* startpts = NULL) { return false; }
   void SetSpeed(int iSpeed) {};
-  int GetStreamLength() { return m_header.durationMs; }
+  int GetStreamLength() { return (int)m_header.durationMs; }
   CDemuxStream* GetStream(int iStreamId);
   int GetNrOfStreams();
   std::string GetFileName();
index 802f947..ecc536a 100644 (file)
@@ -43,6 +43,8 @@ CDVDDemux* CDVDFactoryDemuxer::CreateDemuxer(CDVDInputStream* pInputStream)
   // Try to open the AirTunes demuxer
   if (pInputStream->IsStreamType(DVDSTREAM_TYPE_FILE) && pInputStream->GetContent().compare("audio/x-xbmc-pcm") == 0 )
   {
+    // audio/x-xbmc-pcm this is the used codec for AirTunes
+    // (apples audio only streaming)
     auto_ptr<CDVDDemuxBXA> demuxer(new CDVDDemuxBXA());
     if(demuxer->Open(pInputStream))
       return demuxer.release();
index ab3595a..b3b7ae3 100644 (file)
@@ -71,6 +71,8 @@ public:
     virtual bool CanRecord() = 0;
     virtual bool IsRecording() = 0;
     virtual bool Record(bool bOnOff) = 0;
+    virtual bool CanPause() = 0;
+    virtual bool CanSeek() = 0;
   };
 
   class IDisplayTime
index eb0ee88..ee0a7a1 100644 (file)
@@ -245,7 +245,7 @@ bool CDVDInputStreamHTSP::UpdateItem(CFileItem& item)
   }
   CFileItem current(item);
   CHTSPSession::ParseItem(channel, m_tag, m_event, item);
-  item.SetThumbnailImage(channel.icon);
+  item.SetArt("thumb", channel.icon);
   return current.GetPath()  != item.GetPath()
       || current.m_strTitle != item.m_strTitle;
 }
index 98ae06c..bc669ee 100644 (file)
@@ -53,6 +53,9 @@ public:
   bool            IsRecording()       { return false; }
   bool            Record(bool bOnOff) { return false; }
 
+  bool            CanPause()          { return false; }
+  bool            CanSeek()           { return false; }
+
   int             GetTotalTime();
   int             GetTime();
 
index c0870aa..85b7614 100644 (file)
@@ -352,6 +352,21 @@ bool CDVDInputStreamPVRManager::Record(bool bOnOff)
   return false;
 }
 
+bool CDVDInputStreamPVRManager::CanPause()
+{
+  return g_PVRClients->CanPauseStream();
+}
+
+bool CDVDInputStreamPVRManager::CanSeek()
+{
+  return g_PVRClients->CanSeekStream();
+}
+
+void CDVDInputStreamPVRManager::Pause(bool bPaused)
+{
+  g_PVRClients->PauseStream(bPaused);
+}
+
 CStdString CDVDInputStreamPVRManager::GetInputFormat()
 {
   if (!m_pOtherStream && g_PVRManager.IsStarted())
index d84b1f0..f8bfcb9 100644 (file)
@@ -65,6 +65,9 @@ public:
   bool            CanRecord();
   bool            IsRecording();
   bool            Record(bool bOnOff);
+  bool            CanSeek();
+  bool            CanPause();
+  void            Pause(bool bPaused);
 
   bool            UpdateItem(CFileItem& item);
 
index bdca5cb..19ef8b4 100644 (file)
@@ -60,6 +60,9 @@ public:
   bool            IsRecording();
   bool            Record(bool bOnOff);
 
+  bool            CanPause() { return false; };
+  bool            CanSeek() { return false; };
+
   bool            UpdateItem(CFileItem& item);
 
 protected:
index cec4feb..b0defa3 100644 (file)
@@ -770,15 +770,6 @@ bool CDVDPlayer::ReadPacket(DemuxPacket*& packet, CDemuxStream*& stream)
 
     if(packet)
     {
-      if(packet->iStreamId == DMX_SPECIALID_STREAMCHANGE)
-      {
-        // reset the caching state for pvr streams
-        if (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER))
-          SetCaching(CACHESTATE_PVR);
-        CDVDDemuxUtils::FreeDemuxPacket(packet);
-        return true;
-      }
-
       UpdateCorrection(packet, m_offset_pts);
       if(packet->iStreamId < 0)
         return true;
@@ -804,6 +795,15 @@ bool CDVDPlayer::ReadPacket(DemuxPacket*& packet, CDemuxStream*& stream)
 
   if(packet)
   {
+    // stream changed, update and open defaults
+    if(packet->iStreamId == DMX_SPECIALID_STREAMCHANGE)
+    {
+        m_SelectionStreams.Clear(STREAM_NONE, STREAM_SOURCE_DEMUX);
+        m_SelectionStreams.Update(m_pInputStream, m_pDemuxer);
+        OpenDefaultStreams();
+        return true;
+    }
+
     UpdateCorrection(packet, m_offset_pts);
     // this groupId stuff is getting a bit messy, need to find a better way
     // currently it is used to determine if a menu overlay is associated with a picture
@@ -2024,6 +2024,9 @@ void CDVDPlayer::HandleMessages()
 
         double start = DVD_NOPTS_VALUE;
 
+        if (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER) && !m_State.canseek)
+          break;
+
         int time = msg.GetRestore() ? (int)m_Edl.RestoreCutTime(msg.GetTime()) : msg.GetTime();
         CLog::Log(LOGDEBUG, "demuxer seek to: %d", time);
         if (m_pDemuxer && m_pDemuxer->SeekTime(time, msg.GetBackward(), &start))
@@ -2184,6 +2187,12 @@ void CDVDPlayer::HandleMessages()
         if (speed != DVD_PLAYSPEED_PAUSE && m_playSpeed != DVD_PLAYSPEED_PAUSE && speed != m_playSpeed)
           m_callback.OnPlayBackSpeedChanged(speed / DVD_PLAYSPEED_NORMAL);
 
+        if (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER) && speed != m_playSpeed)
+        {
+          CDVDInputStreamPVRManager* pvrinputstream = static_cast<CDVDInputStreamPVRManager*>(m_pInputStream);
+          pvrinputstream->Pause( speed == 0 );
+        }
+
         // if playspeed is different then DVD_PLAYSPEED_NORMAL or DVD_PLAYSPEED_PAUSE
         // audioplayer, stops outputing audio to audiorendere, but still tries to
         // sleep an correct amount for each packet
@@ -2338,8 +2347,17 @@ void CDVDPlayer::SetPlaySpeed(int speed)
   SynchronizeDemuxer(100);
 }
 
+bool CDVDPlayer::CanPause()
+{
+  CSingleLock lock(m_StateSection);
+  return m_State.canpause;
+}
+
 void CDVDPlayer::Pause()
 {
+  if (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER) && !m_State.canpause)
+    return;
+
   if(m_playSpeed != DVD_PLAYSPEED_PAUSE && (m_caching == CACHESTATE_FULL || m_caching == CACHESTATE_PVR))
   {
     SetCaching(CACHESTATE_DONE);
@@ -2383,7 +2401,13 @@ bool CDVDPlayer::IsPassthrough() const
 
 bool CDVDPlayer::CanSeek()
 {
-  return GetTotalTime() > 0;
+  if (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER))
+  {
+    CSingleLock lock(m_StateSection);
+    return m_State.canseek;
+  }
+  else
+    return GetTotalTime() > 0;
 }
 
 void CDVDPlayer::Seek(bool bPlus, bool bLargeStep)
@@ -2397,6 +2421,8 @@ void CDVDPlayer::Seek(bool bPlus, bool bLargeStep)
     return;
   }
 #endif
+  if (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER) && !m_State.canseek)
+    return;
 
   if(((bPlus && GetChapter() < GetChapterCount())
   || (!bPlus && GetChapter() > 1)) && bLargeStep)
@@ -3805,6 +3831,13 @@ void CDVDPlayer::UpdatePlayState(double timeout)
       state.recording = pChannel->IsRecording();
     }
 
+    if (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER))
+    {
+      CDVDInputStreamPVRManager* pvrinputstream = static_cast<CDVDInputStreamPVRManager*>(m_pInputStream);
+      state.canpause = pvrinputstream->CanPause();
+      state.canseek = pvrinputstream->CanSeek();
+    }
+
     CDVDInputStream::IDisplayTime* pDisplayTime = dynamic_cast<CDVDInputStream::IDisplayTime*>(m_pInputStream);
     if (pDisplayTime && pDisplayTime->GetTotalTime() > 0)
     {
index cbb49d5..77d0f40 100644 (file)
@@ -195,6 +195,7 @@ public:
   virtual void GetVideoAspectRatio(float& fAR)                  { fAR = m_dvdPlayerVideo.GetAspectRatio(); }
   virtual bool CanRecord();
   virtual bool IsRecording();
+  virtual bool CanPause();
   virtual bool Record(bool bOnOff);
   virtual void SetAVDelay(float fValue = 0.0f);
   virtual float GetAVDelay();
@@ -415,6 +416,8 @@ protected:
       chapter_count = 0;
       canrecord     = false;
       recording     = false;
+      canpause      = false;
+      canseek       = false;
       demux_video   = "";
       demux_audio   = "";
       cache_bytes   = 0;
@@ -439,6 +442,9 @@ protected:
     bool canrecord;           // can input stream record
     bool recording;           // are we currently recording
 
+    bool canpause;            // pvr: can pause the current playing item
+    bool canseek;             // pvr: can seek in the current playing item
+
     std::string demux_video;
     std::string demux_audio;
 
index cb4bdab..f62b083 100644 (file)
 
 using namespace std;
 
-CPTSOutputQueue::CPTSOutputQueue()
-{
-  Flush();
-}
-
-void CPTSOutputQueue::Add(double pts, double delay, double duration)
-{
-  CSingleLock lock(m_sync);
-
-  TPTSItem item;
-  item.pts = pts;
-  item.timestamp = CDVDClock::GetAbsoluteClock() + delay;
-  item.duration = duration;
-
-  // first one is applied directly
-  if(m_queue.empty() && m_current.pts == DVD_NOPTS_VALUE)
-    m_current = item;
-  else
-    m_queue.push(item);
-
-  // call function to make sure the queue
-  // doesn't grow should nobody call it
-  Current();
-}
-void CPTSOutputQueue::Flush()
-{
-  CSingleLock lock(m_sync);
-
-  while( !m_queue.empty() ) m_queue.pop();
-  m_current.pts = DVD_NOPTS_VALUE;
-  m_current.timestamp = 0.0;
-  m_current.duration = 0.0;
-}
-
-double CPTSOutputQueue::Current()
-{
-  CSingleLock lock(m_sync);
-
-  if(!m_queue.empty() && m_current.pts == DVD_NOPTS_VALUE)
-  {
-    m_current = m_queue.front();
-    m_queue.pop();
-  }
-
-  while( !m_queue.empty() && CDVDClock::GetAbsoluteClock() >= m_queue.front().timestamp )
-  {
-    m_current = m_queue.front();
-    m_queue.pop();
-  }
-
-  if( m_current.timestamp == 0 ) return m_current.pts;
-
-  return m_current.pts + min(m_current.duration, (CDVDClock::GetAbsoluteClock() - m_current.timestamp));
-}
-
 void CPTSInputQueue::Add(int64_t bytes, double pts)
 {
   CSingleLock lock(m_sync);
@@ -298,9 +243,6 @@ void CDVDPlayerAudio::CloseStream(bool bWaitForBuffers)
     delete m_pAudioCodec;
     m_pAudioCodec = NULL;
   }
-
-  // flush any remaining pts values
-  m_ptsOutput.Flush();
 }
 
 // decode one audio frame and returns its uncompressed size
@@ -449,12 +391,11 @@ int CDVDPlayerAudio::DecodeFrame(DVDAudioFrame &audioframe, bool bDropPacket)
         m_audioClock = pMsgGeneralResync->m_timestamp;
 
       m_ptsInput.Flush();
-      m_ptsOutput.Flush();
-      m_ptsOutput.Add(m_audioClock, m_dvdAudio.GetDelay(), 0);
+      m_dvdAudio.SetPlayingPts(m_audioClock);
       if (pMsgGeneralResync->m_clock)
       {
         CLog::Log(LOGDEBUG, "CDVDPlayerAudio - CDVDMsg::GENERAL_RESYNC(%f, 1)", m_audioClock);
-        m_pClock->Discontinuity(m_ptsOutput.Current());
+        m_pClock->Discontinuity(m_dvdAudio.GetPlayingPts());
       }
       else
         CLog::Log(LOGDEBUG, "CDVDPlayerAudio - CDVDMsg::GENERAL_RESYNC(%f, 0)", m_audioClock);
@@ -469,7 +410,6 @@ int CDVDPlayerAudio::DecodeFrame(DVDAudioFrame &audioframe, bool bDropPacket)
     else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH))
     {
       m_dvdAudio.Flush();
-      m_ptsOutput.Flush();
       m_ptsInput.Flush();
       m_syncclock = true;
       m_stalled   = true;
@@ -515,7 +455,6 @@ int CDVDPlayerAudio::DecodeFrame(DVDAudioFrame &audioframe, bool bDropPacket)
       }
       else
       {
-        m_ptsOutput.Flush();
         m_syncclock = true;
         if (m_speed != DVD_PLAYSPEED_PAUSE)
           m_dvdAudio.Flush();
@@ -654,15 +593,6 @@ void CDVDPlayerAudio::Process()
         m_stalled = false;
     }
 
-    // store the delay for this pts value so we can calculate the current playing
-    if(packetadded)
-    {
-      if(m_speed == DVD_PLAYSPEED_PAUSE)
-        m_ptsOutput.Add(audioframe.pts, m_dvdAudio.GetDelay() - audioframe.duration, 0);
-      else
-        m_ptsOutput.Add(audioframe.pts, m_dvdAudio.GetDelay() - audioframe.duration, audioframe.duration);
-    }
-
     // signal to our parent that we have initialized
     if(m_started == false)
     {
@@ -670,7 +600,7 @@ void CDVDPlayerAudio::Process()
       m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_AUDIO));
     }
 
-    if( m_ptsOutput.Current() == DVD_NOPTS_VALUE )
+    if( m_dvdAudio.GetPlayingPts() == DVD_NOPTS_VALUE )
       continue;
 
     if( m_speed != DVD_PLAYSPEED_NORMAL )
@@ -712,7 +642,7 @@ void CDVDPlayerAudio::SetSyncType(bool passthrough)
 void CDVDPlayerAudio::HandleSyncError(double duration)
 {
   double clock = m_pClock->GetClock();
-  double error = m_ptsOutput.Current() - clock;
+  double error = m_dvdAudio.GetPlayingPts() - clock;
   int64_t now;
 
   if( fabs(error) > DVD_MSEC_TO_TIME(100) || m_syncclock )
@@ -745,9 +675,9 @@ void CDVDPlayerAudio::HandleSyncError(double duration)
   m_errorbuff += error;
   m_errorcount++;
 
-  //check if measured error for 1 second
+  //check if measured error for 2 seconds
   now = CurrentHostCounter();
-  if ((now - m_errortime) >= m_freq)
+  if ((now - m_errortime) >= m_freq * 2)
   {
     m_errortime = now;
     m_error = m_errorbuff / m_errorcount;
index 0523bd4..0b1d287 100644 (file)
@@ -63,21 +63,6 @@ typedef struct stDVDAudioFrame
   bool              passthrough;
 } DVDAudioFrame;
 
-class CPTSOutputQueue
-{
-private:
-  typedef struct {double pts; double timestamp; double duration;} TPTSItem;
-  TPTSItem m_current;
-  std::queue<TPTSItem> m_queue;
-  CCriticalSection m_sync;
-
-public:
-  CPTSOutputQueue();
-  void Add(double pts, double delay, double duration);
-  void Flush();
-  double Current();
-};
-
 class CPTSInputQueue
 {
 private:
@@ -131,7 +116,7 @@ public:
   CPTSOutputQueue m_ptsOutput;
   CPTSInputQueue  m_ptsInput;
 
-  double GetCurrentPts()                            { return m_ptsOutput.Current(); }
+  double GetCurrentPts()                            { return m_dvdAudio.GetPlayingPts(); }
 
   bool IsStalled()                                  { return m_stalled;  }
   bool IsPassthrough() const;
index 412bc18..bc40b21 100644 (file)
@@ -82,6 +82,8 @@
 #include "pvr/windows/GUIWindowPVR.h"
 #include "filesystem/PVRFile.h"
 
+#include "utils/StringUtils.h"
+
 using namespace XFILE;
 using namespace PVR;
 
@@ -769,15 +771,6 @@ bool COMXPlayer::ReadPacket(DemuxPacket*& packet, CDemuxStream*& stream)
 
     if(packet)
     {
-      if(packet->iStreamId == DMX_SPECIALID_STREAMCHANGE)
-      {
-        // reset the caching state for pvr streams
-        if (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER))
-          SetCaching(CACHESTATE_PVR);
-        CDVDDemuxUtils::FreeDemuxPacket(packet);
-        return true;
-      }
-
       UpdateCorrection(packet, m_offset_pts);
       if(packet->iStreamId < 0)
         return true;
@@ -803,6 +796,15 @@ bool COMXPlayer::ReadPacket(DemuxPacket*& packet, CDemuxStream*& stream)
 
   if(packet)
   {
+    // stream changed, update and open defaults
+    if(packet->iStreamId == DMX_SPECIALID_STREAMCHANGE)
+    {
+        m_SelectionStreams.Clear(STREAM_NONE, STREAM_SOURCE_DEMUX);
+        m_SelectionStreams.Update(m_pInputStream, m_pDemuxer);
+        OpenDefaultStreams();
+        return true;
+    }
+
     UpdateCorrection(packet, m_offset_pts);
     // this groupId stuff is getting a bit messy, need to find a better way
     // currently it is used to determine if a menu overlay is associated with a picture
@@ -2055,6 +2057,9 @@ void COMXPlayer::HandleMessages()
 
         double start = DVD_NOPTS_VALUE;
 
+        if (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER) && !m_State.canseek)
+          break;
+
         int time = msg.GetRestore() ? (int)m_Edl.RestoreCutTime(msg.GetTime()) : msg.GetTime();
         CLog::Log(LOGDEBUG, "demuxer seek to: %d", time);
         if (m_pDemuxer && m_pDemuxer->SeekTime(time, msg.GetBackward(), &start))
@@ -2216,6 +2221,12 @@ void COMXPlayer::HandleMessages()
         if (speed != DVD_PLAYSPEED_PAUSE && m_playSpeed != DVD_PLAYSPEED_PAUSE && speed != m_playSpeed)
           m_callback.OnPlayBackSpeedChanged(speed / DVD_PLAYSPEED_NORMAL);
 
+        if (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER) && speed != m_playSpeed)
+        {
+          CDVDInputStreamPVRManager* pvrinputstream = static_cast<CDVDInputStreamPVRManager*>(m_pInputStream);
+          pvrinputstream->Pause( speed == 0 );
+        }
+
         // if playspeed is different then DVD_PLAYSPEED_NORMAL or DVD_PLAYSPEED_PAUSE
         // audioplayer, stops outputing audio to audiorendere, but still tries to
         // sleep an correct amount for each packet
@@ -2375,8 +2386,17 @@ void COMXPlayer::SetPlaySpeed(int speed)
   SynchronizeDemuxer(100);
 }
 
+bool COMXPlayer::CanPause()
+{
+  CSingleLock lock(m_StateSection);
+  return m_State.canpause;
+}
+
 void COMXPlayer::Pause()
 {
+  if (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER) && !m_State.canpause)
+    return;
+
   if(m_playSpeed != DVD_PLAYSPEED_PAUSE && (m_caching == CACHESTATE_FULL || m_caching == CACHESTATE_PVR))
   {
     SetCaching(CACHESTATE_DONE);
@@ -2420,11 +2440,20 @@ bool COMXPlayer::IsPassthrough() const
 
 bool COMXPlayer::CanSeek()
 {
-  return GetTotalTime() > 0;
+  if (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER))
+  {
+    CSingleLock lock(m_StateSection);
+    return m_State.canseek;
+  }
+  else
+    return GetTotalTime() > 0;
 }
 
 void COMXPlayer::Seek(bool bPlus, bool bLargeStep)
 {
+  if (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER) && !m_State.canseek)
+    return;
+
   if(((bPlus && GetChapter() < GetChapterCount())
   || (!bPlus && GetChapter() > 1)) && bLargeStep)
   {
@@ -3753,6 +3782,13 @@ void COMXPlayer::UpdatePlayState(double timeout)
       state.recording = pChannel->IsRecording();
     }
 
+    if (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER))
+    {
+      CDVDInputStreamPVRManager* pvrinputstream = static_cast<CDVDInputStreamPVRManager*>(m_pInputStream);
+      state.canpause = pvrinputstream->CanPause();
+      state.canseek = pvrinputstream->CanSeek();
+    }
+
     CDVDInputStream::IDisplayTime* pDisplayTime = dynamic_cast<CDVDInputStream::IDisplayTime*>(m_pInputStream);
     if (pDisplayTime && pDisplayTime->GetTotalTime() > 0)
     {
@@ -3997,4 +4033,38 @@ void COMXPlayer::GetVideoAspectRatio(float &fAR)
   fAR = g_renderManager.GetAspectRatio();
 }
 
+void COMXPlayer::GetRenderFeatures(std::vector<int> &renderFeatures)
+{
+  renderFeatures.push_back(RENDERFEATURE_STRETCH);
+  renderFeatures.push_back(RENDERFEATURE_CROP);
+}
+
+void COMXPlayer::GetDeinterlaceMethods(std::vector<int> &deinterlaceMethods)
+{
+  deinterlaceMethods.push_back(VS_INTERLACEMETHOD_DEINTERLACE);
+}
+
+void COMXPlayer::GetDeinterlaceModes(std::vector<int> &deinterlaceModes)
+{
+  deinterlaceModes.push_back(VS_DEINTERLACEMODE_AUTO);
+  deinterlaceModes.push_back(VS_DEINTERLACEMODE_OFF);
+  deinterlaceModes.push_back(VS_DEINTERLACEMODE_FORCE);
+}
+
+void COMXPlayer::GetScalingMethods(std::vector<int> &scalingMethods)
+{
+}
+
+void COMXPlayer::GetAudioCapabilities(std::vector<int> &audioCaps)
+{
+  audioCaps.push_back(IPC_AUD_OFFSET);
+  audioCaps.push_back(IPC_AUD_SELECT_STREAM);
+  audioCaps.push_back(IPC_AUD_SELECT_OUTPUT);
+}
+
+void COMXPlayer::GetSubtitleCapabilities(std::vector<int> &subCaps)
+{
+  subCaps.push_back(IPC_SUBS_ALL);
+}
+
 #endif
index bcce379..5424232 100644 (file)
@@ -234,6 +234,7 @@ public:
   virtual void  UpdateApplication(double timeout);
   virtual bool  CanRecord();
   virtual bool  IsRecording();
+  virtual bool  CanPause();
   virtual bool  Record(bool bOnOff);
   virtual void  SetAVDelay(float fValue = 0.0f);
   virtual float GetAVDelay();
@@ -318,6 +319,13 @@ public:
 
   virtual int  OnDVDNavResult(void* pData, int iMessage);
   virtual bool OnAction(const CAction &action);
+
+  virtual void  GetRenderFeatures(std::vector<int> &renderFeatures);
+  virtual void  GetDeinterlaceMethods(std::vector<int> &deinterlaceMethods);
+  virtual void  GetDeinterlaceModes(std::vector<int> &deinterlaceModes);
+  virtual void  GetScalingMethods(std::vector<int> &scalingMethods);
+  virtual void  GetAudioCapabilities(std::vector<int> &audioCaps);
+  virtual void  GetSubtitleCapabilities(std::vector<int> &subCaps);
 protected:
   friend class COMXSelectionStreams;
 
@@ -378,6 +386,8 @@ protected:
       chapter_count = 0;
       canrecord     = false;
       recording     = false;
+      canpause      = false;
+      canseek       = false;
       demux_video   = "";
       demux_audio   = "";
       cache_bytes   = 0;
@@ -402,6 +412,9 @@ protected:
     bool canrecord;           // can input stream record
     bool recording;           // are we currently recording
 
+    bool canpause;            // pvr: can pause the current playing item
+    bool canseek;             // pvr: can seek in the current playing item
+
     std::string demux_video;
     std::string demux_audio;
 
diff --git a/xbmc/cores/paplayer/BXAcodec.cpp b/xbmc/cores/paplayer/BXAcodec.cpp
deleted file mode 100644 (file)
index c8b2b0c..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- *      Copyright (C) 2005-2012 Team XBMC
- *      http://www.xbmc.org
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with XBMC; see the file COPYING.  If not, see
- *  <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "system.h"
-#include "BXAcodec.h"
-#include "utils/EndianSwap.h"
-#include "cores/AudioEngine/Utils/AEUtil.h"
-
-BXACodec::BXACodec()
-{
-  m_SampleRate = 0;
-  m_Channels = 0;
-  m_BitsPerSample = 0;
-  m_Bitrate = 0;
-  m_CodecName = "XBMC PCM";
-}
-
-BXACodec::~BXACodec()
-{
-  DeInit();
-}
-
-bool BXACodec::Init(const CStdString &strFile, unsigned int filecache)
-{
-  if (!m_file.Open(strFile))
-    return false;
-
-  // read header
-  BXA_FmtHeader bxah;
-  m_file.Read(&bxah, sizeof(BXA_FmtHeader));
-
-  // file valid?
-  if (strncmp(bxah.fourcc, "BXA ", 4) != 0 || bxah.type != BXA_PACKET_TYPE_FMT)
-  {
-    return false;
-  }
-
-  m_SampleRate = bxah.sampleRate;
-  m_Channels = bxah.channels;
-  m_BitsPerSample = bxah.bitsPerSample;
-  m_TotalTime = bxah.durationMs;
-  m_Bitrate = bxah.sampleRate * bxah.channels * bxah.bitsPerSample;
-  m_DataFormat = AE_FMT_S16LE;
-
-  if (m_SampleRate == 0 || m_Channels == 0 || m_BitsPerSample == 0)
-  {
-    return false;
-  }
-
-  return true;
-}
-
-void BXACodec::DeInit()
-{
-  m_file.Close();
-}
-
-int64_t BXACodec::Seek(int64_t iSeekTime)
-{
-  return iSeekTime;
-}
-
-template <class T>
-class MiniScopedArray
-{
-public:
-       MiniScopedArray(int size) {m_arr = new T[size];}
-       ~MiniScopedArray() {delete[] m_arr;}
-       T* raw_data() {return m_arr;}
-private:
-       T* m_arr;
-};
-
-int BXACodec::ReadPCM(BYTE *pBuffer, int size, int *actualsize)
-{
-  *actualsize=0;
-
-  int iAmountRead;
-  //unsigned char data[size];
-  MiniScopedArray<char> data(size);
-  iAmountRead = m_file.Read(data.raw_data(), size);
-  if (iAmountRead > 0)
-  {
-    *actualsize=iAmountRead;
-    memcpy(pBuffer, data.raw_data(), iAmountRead <= size ? iAmountRead : size);
-    return READ_SUCCESS;
-  }
-
-  *actualsize = 0;
-  return READ_EOF;
-}
-
-bool BXACodec::CanInit()
-{
-  return true;
-}
-
-CAEChannelInfo BXACodec::GetChannelInfo()
-{
-  static enum AEChannel map[2][3] = {
-    {AE_CH_FC, AE_CH_NULL},
-    {AE_CH_FL, AE_CH_FR  , AE_CH_NULL}
-  };
-
-  if (m_Channels > 2)
-    return CAEUtil::GuessChLayout(m_Channels);
-
-  return CAEChannelInfo(map[m_Channels - 1]);
-}
diff --git a/xbmc/cores/paplayer/BXAcodec.h b/xbmc/cores/paplayer/BXAcodec.h
deleted file mode 100644 (file)
index 9ec6e60..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- *      Copyright (C) 2005-2012 Team XBMC
- *      http://www.xbmc.org
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with XBMC; see the file COPYING.  If not, see
- *  <http://www.gnu.org/licenses/>.
- *
- */
-
-#pragma once
-
-#include "ICodec.h"
-#include "filesystem/File.h"
-#include "CachingCodec.h"
-#ifdef _WIN32
-#define __attribute__(dummy_val)
-#else
-#include <config.h>
-#endif
-
-#ifdef _WIN32
-#pragma pack(push)
-#pragma pack(1)
-#endif
-
-typedef struct
-{
-  char fourcc[4];
-  uint32_t type;
-  uint32_t channels;
-  uint32_t sampleRate;
-  uint32_t bitsPerSample;
-  uint64_t durationMs;
-} __attribute__((__packed__)) BXA_FmtHeader;
-
-typedef struct
-{
-  char fourcc[4];
-  uint32_t type;
-  uint32_t length;
-} __attribute__((__packed__)) BXA_DataHeader;
-
-#ifdef _WIN32
-#pragma pack(pop)
-#endif
-
-#define BXA_PACKET_TYPE_FMT  1
-#define BXA_PACKET_TYPE_DATA 2
-
-class BXACodec : public CachingCodec
-{
-public:
-  BXACodec();
-  virtual ~BXACodec();
-
-  virtual bool Init(const CStdString &strFile, unsigned int filecache);
-  virtual void DeInit();
-  virtual int64_t Seek(int64_t iSeekTime);
-  virtual int ReadPCM(BYTE *pBuffer, int size, int *actualsize);
-  virtual bool CanInit();
-  virtual CAEChannelInfo GetChannelInfo();
-};
-
index 9f34d16..f1ce580 100644 (file)
@@ -40,7 +40,6 @@
 #endif
 #include "URL.h"
 #include "DVDPlayerCodec.h"
-#include "BXAcodec.h" 
 #include "PCMCodec.h"
 
 ICodec* CodecFactory::CreateCodec(const CStdString& strFileType)
@@ -139,9 +138,15 @@ ICodec* CodecFactory::CreateCodecDemux(const CStdString& strFile, const CStdStri
   else if( strContent.Equals("application/ogg") || strContent.Equals("audio/ogg"))
     return CreateOGGCodec(strFile,filecache);
   else if (strContent.Equals("audio/x-xbmc-pcm"))
-    return (ICodec*)new BXACodec();  
-   else if (strContent.Equals("audio/flac") || strContent.Equals("audio/x-flac") || strContent.Equals("application/x-flac"))
-     return new FLACCodec();
+  {
+    // audio/x-xbmc-pcm this is the used codec for AirTunes
+    // (apples audio only streaming)
+    DVDPlayerCodec *dvdcodec = new DVDPlayerCodec();
+    dvdcodec->SetContentType(strContent);
+    return dvdcodec;
+  }
+  else if (strContent.Equals("audio/flac") || strContent.Equals("audio/x-flac") || strContent.Equals("application/x-flac"))
+    return new FLACCodec();
 
   if (urlFile.GetProtocol() == "lastfm" || urlFile.GetProtocol() == "shout")
   {
index bc523a9..31cc8bd 100644 (file)
@@ -9,7 +9,6 @@ endif
 
 SRCS  = ADPCMCodec.cpp
 SRCS += AudioDecoder.cpp
-SRCS += BXAcodec.cpp
 SRCS += CDDAcodec.cpp
 SRCS += CodecFactory.cpp
 SRCS += DVDPlayerCodec.cpp
index c566e90..9773b35 100644 (file)
@@ -203,6 +203,11 @@ CStdString CDatabase::GetSingleValue(const CStdString &strTable, const CStdStrin
   return GetSingleValue(query, m_pDS);
 }
 
+CStdString CDatabase::GetSingleValue(const CStdString &query)
+{
+  return GetSingleValue(query, m_pDS);
+}
+
 bool CDatabase::DeleteValues(const CStdString &strTable, const CStdString &strWhereClause /* = CStdString() */)
 {
   bool bReturn = true;
index ac90182..c04b139 100644 (file)
@@ -83,6 +83,7 @@ public:
    * @return The requested value or an empty string if it wasn't found.
    */
   CStdString GetSingleValue(const CStdString &strTable, const CStdString &strColumn, const CStdString &strWhereClause = CStdString(), const CStdString &strOrderBy = CStdString());
+  CStdString GetSingleValue(const CStdString &query);
 
   /*! \brief Get a single value from a query on a dataset.
    \param query the query in question.
@@ -134,7 +135,7 @@ public:
    */
   bool CommitInsertQueries();
 
-  virtual bool GetFilter(const CDbUrl &dbUrl, Filter &filter) { return true; }
+  virtual bool GetFilter(CDbUrl &dbUrl, Filter &filter) { return true; }
   virtual bool BuildSQL(const CStdString &strBaseDir, const CStdString &strQuery, Filter &filter, CStdString &strSQL, CDbUrl &dbUrl);
 
 protected:
index dbcde7a..2d85136 100644 (file)
@@ -240,7 +240,10 @@ int MysqlDatabase::copy(const char *backup_name) {
     // create the new database
     sprintf(sql, "CREATE DATABASE `%s`", backup_name);
     if ( (ret=query_with_reconnect(sql)) != MYSQL_OK )
+    {
+      mysql_free_result(res);
       throw DbErrors("Can't create database for copy: '%s' (%d)", db.c_str(), ret);
+    }
 
     MYSQL_ROW row;
 
@@ -252,15 +255,22 @@ int MysqlDatabase::copy(const char *backup_name) {
               backup_name, row[0], row[0]);
 
       if ( (ret=query_with_reconnect(sql)) != MYSQL_OK )
+      {
+        mysql_free_result(res);
         throw DbErrors("Can't copy schema for table '%s'\nError: %s", db.c_str(), ret);
+      }
 
       // copy the table data
       sprintf(sql, "INSERT INTO %s.%s SELECT * FROM %s",
               backup_name, row[0], row[0]);
 
       if ( (ret=query_with_reconnect(sql)) != MYSQL_OK )
+      {
+        mysql_free_result(res);
         throw DbErrors("Can't copy data for table '%s'\nError: %s", row[0], ret);
+      }
     }
+    mysql_free_result(res);
 
     // after table are recreated and repopulated we can recreate views
     // grab a list of views and their definitions
@@ -279,7 +289,10 @@ int MysqlDatabase::copy(const char *backup_name) {
                 backup_name, row[0], row[1]);
 
         if ( (ret=query_with_reconnect(sql)) != MYSQL_OK )
+        {
+          mysql_free_result(resViews);
           throw DbErrors("Can't create view '%s'\nError: %s", db.c_str(), ret);
+        }
       }
       mysql_free_result(resViews);
     }
@@ -336,6 +349,7 @@ long MysqlDatabase::nextid(const char* sname) {
     lengths = mysql_fetch_lengths(res);
     CLog::Log(LOGINFO,"Next id is [%.*s] ", (int) lengths[0], row[0]);
     sprintf(sqlcmd,"update %s set nextid=%d where seq_name = '%s'",seq_table,id,sname);
+    mysql_free_result(res);
     if ((last_err = query_with_reconnect(sqlcmd) != 0)) return DB_UNEXPECTED_RESULT;
     return id;
   }
index 95db351..3c4e599 100644 (file)
@@ -493,14 +493,14 @@ bool CGUIDialogContextMenu::OnContextButton(const CStdString &type, const CFileI
       if (!share->m_strThumbnailImage.IsEmpty())
       {
         CFileItemPtr current(new CFileItem("thumb://Current", false));
-        current->SetThumbnailImage(share->m_strThumbnailImage);
+        current->SetArt("thumb", share->m_strThumbnailImage);
         current->SetLabel(g_localizeStrings.Get(20016));
         items.Add(current);
       }
-      else if (item->HasThumbnail())
+      else if (item->HasArt("thumb"))
       { // already have a thumb that the share doesn't know about - must be a local one, so we mayaswell reuse it.
         CFileItemPtr current(new CFileItem("thumb://Current", false));
-        current->SetThumbnailImage(item->GetThumbnailImage());
+        current->SetArt("thumb", item->GetArt("thumb"));
         current->SetLabel(g_localizeStrings.Get(20016));
         items.Add(current);
       }
@@ -509,7 +509,7 @@ bool CGUIDialogContextMenu::OnContextButton(const CStdString &type, const CFileI
       if (XFILE::CFile::Exists(folderThumb))
       {
         CFileItemPtr local(new CFileItem("thumb://Local", false));
-        local->SetThumbnailImage(folderThumb);
+        local->SetArt("thumb", folderThumb);
         local->SetLabel(g_localizeStrings.Get(20017));
         items.Add(local);
       }
index 36e0884..628cb68 100644 (file)
@@ -199,10 +199,10 @@ void CGUIDialogFavourites::OnSetThumb(int item)
   CFileItemList items;
 
   // Current
-  if (pItem->HasThumbnail())
+  if (pItem->HasArt("thumb"))
   {
     CFileItemPtr current(new CFileItem("thumb://Current", false));
-    current->SetThumbnailImage(pItem->GetThumbnailImage());
+    current->SetArt("thumb", pItem->GetArt("thumb"));
     current->SetLabel(g_localizeStrings.Get(20016));
     items.Add(current);
   }
@@ -219,7 +219,7 @@ void CGUIDialogFavourites::OnSetThumb(int item)
   if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(1030), thumb))
     return;
 
-  (*m_favourites)[item]->SetThumbnailImage(thumb);
+  (*m_favourites)[item]->SetArt("thumb", thumb);
   CFavourites::Save(*m_favourites);
   UpdateList();
 }
diff --git a/xbmc/dialogs/GUIDialogMediaFilter.cpp b/xbmc/dialogs/GUIDialogMediaFilter.cpp
new file mode 100644 (file)
index 0000000..3ea580a
--- /dev/null
@@ -0,0 +1,949 @@
+/*
+ *      Copyright (C) 2012 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "GUIDialogMediaFilter.h"
+#include "FileItem.h"
+#include "GUIUserMessages.h"
+#include "XBDateTime.h"
+#include "dialogs/GUIDialogSelect.h"
+#include "guilib/GUIWindowManager.h"
+#include "guilib/LocalizeStrings.h"
+#include "music/MusicDatabase.h"
+#include "playlists/SmartPlayList.h"
+#include "utils/MathUtils.h"
+#include "video/VideoDatabase.h"
+
+// list of controls
+#define CONTROL_HEADING             2
+// list of controls from CGUIDialogSettings
+#define CONTROL_GROUP_LIST          5
+#define CONTROL_DEFAULT_BUTTON      7
+#define CONTROL_DEFAULT_RADIOBUTTON 8
+#define CONTROL_DEFAULT_SPIN        9
+#define CONTROL_DEFAULT_SLIDER     10
+
+#define CONTROL_CLEAR_BUTTON       27
+#define CONTROL_OKAY_BUTTON        28
+#define CONTROL_CANCEL_BUTTON      29
+#define CONTROL_START              30
+
+#define CHECK_ALL                  -1
+#define CHECK_NO                    0
+#define CHECK_YES                   1
+#define CHECK_LABEL_ALL           593
+#define CHECK_LABEL_NO            106
+#define CHECK_LABEL_YES           107
+
+using namespace std;
+
+static const CGUIDialogMediaFilter::Filter filterList[] = {
+  { "movies",       FieldTitle,         556,    SettingInfo::EDIT,        CSmartPlaylistRule::OPERATOR_CONTAINS },
+  { "movies",       FieldRating,        563,    SettingInfo::RANGE,       CSmartPlaylistRule::OPERATOR_BETWEEN },
+  //{ "movies",       FieldTime,          180,    SettingInfo::TODO,        CSmartPlaylistRule::TODO },
+  { "movies",       FieldInProgress,    575,    SettingInfo::CHECK,       CSmartPlaylistRule::OPERATOR_FALSE },
+  { "movies",       FieldYear,          562,    SettingInfo::RANGE,       CSmartPlaylistRule::OPERATOR_BETWEEN },
+  { "movies",       FieldTag,           20459,  SettingInfo::BUTTON,      CSmartPlaylistRule::OPERATOR_EQUALS },
+  { "movies",       FieldGenre,         515,    SettingInfo::BUTTON,      CSmartPlaylistRule::OPERATOR_EQUALS },
+  { "movies",       FieldActor,         20337,  SettingInfo::BUTTON,      CSmartPlaylistRule::OPERATOR_EQUALS },
+  { "movies",       FieldDirector,      20339,  SettingInfo::BUTTON,      CSmartPlaylistRule::OPERATOR_EQUALS },
+  { "movies",       FieldStudio,        572,    SettingInfo::BUTTON,      CSmartPlaylistRule::OPERATOR_EQUALS },
+  //{ "movies",       FieldLastPlayed,    568,    SettingInfo::TODO,        CSmartPlaylistRule::TODO },
+  //{ "movies",       FieldDateAdded,     570,    SettingInfo::TODO,        CSmartPlaylistRule::TODO },
+
+  { "tvshows",      FieldTitle,         556,    SettingInfo::EDIT,        CSmartPlaylistRule::OPERATOR_CONTAINS },
+  //{ "tvshows",      FieldTvShowStatus,  126,    SettingInfo::TODO,        CSmartPlaylistRule::TODO },
+  { "tvshows",      FieldRating,        563,    SettingInfo::RANGE,       CSmartPlaylistRule::OPERATOR_BETWEEN },
+  { "tvshows",      FieldInProgress,    575,    SettingInfo::CHECK,       CSmartPlaylistRule::OPERATOR_FALSE },
+  { "tvshows",      FieldYear,          562,    SettingInfo::RANGE,       CSmartPlaylistRule::OPERATOR_BETWEEN },
+  { "tvshows",      FieldGenre,         515,    SettingInfo::BUTTON,      CSmartPlaylistRule::OPERATOR_EQUALS },
+  { "tvshows",      FieldActor,         20337,  SettingInfo::BUTTON,      CSmartPlaylistRule::OPERATOR_EQUALS },
+  { "tvshows",      FieldDirector,      20339,  SettingInfo::BUTTON,      CSmartPlaylistRule::OPERATOR_EQUALS },
+  { "tvshows",      FieldStudio,        572,    SettingInfo::BUTTON,      CSmartPlaylistRule::OPERATOR_EQUALS },
+  //{ "tvshows",      FieldDateAdded,     570,    SettingInfo::TODO,        CSmartPlaylistRule::TODO },
+
+  { "episodes",     FieldTitle,         556,    SettingInfo::EDIT,        CSmartPlaylistRule::OPERATOR_CONTAINS },
+  { "episodes",     FieldRating,        563,    SettingInfo::RANGE,       CSmartPlaylistRule::OPERATOR_BETWEEN },
+  { "episodes",     FieldAirDate,       20416,  SettingInfo::RANGE,       CSmartPlaylistRule::OPERATOR_BETWEEN },
+  { "episodes",     FieldInProgress,    575,    SettingInfo::CHECK,       CSmartPlaylistRule::OPERATOR_FALSE },
+  { "episodes",     FieldActor,         20337,  SettingInfo::BUTTON,      CSmartPlaylistRule::OPERATOR_EQUALS },
+  { "episodes",     FieldDirector,      20339,  SettingInfo::BUTTON,      CSmartPlaylistRule::OPERATOR_EQUALS },
+  //{ "episodes",     FieldLastPlayed,    568,    SettingInfo::TODO,        CSmartPlaylistRule::TODO },
+  //{ "episodes",     FieldDateAdded,     570,    SettingInfo::TODO,        CSmartPlaylistRule::TODO },
+
+  { "musicvideos",  FieldTitle,         556,    SettingInfo::EDIT,        CSmartPlaylistRule::OPERATOR_CONTAINS },
+  { "musicvideos",  FieldArtist,        557,    SettingInfo::BUTTON,      CSmartPlaylistRule::OPERATOR_EQUALS },
+  { "musicvideos",  FieldAlbum,         558,    SettingInfo::BUTTON,      CSmartPlaylistRule::OPERATOR_EQUALS },
+  //{ "musicvideos",  FieldTime,          180,    SettingInfo::TODO,        CSmartPlaylistRule::TODO },
+  { "musicvideos",  FieldYear,          562,    SettingInfo::RANGE,       CSmartPlaylistRule::OPERATOR_BETWEEN },
+  { "musicvideos",  FieldGenre,         515,    SettingInfo::BUTTON,      CSmartPlaylistRule::OPERATOR_EQUALS },
+  { "musicvideos",  FieldDirector,      20339,  SettingInfo::BUTTON,      CSmartPlaylistRule::OPERATOR_EQUALS },
+  { "musicvideos",  FieldStudio,        572,    SettingInfo::BUTTON,      CSmartPlaylistRule::OPERATOR_EQUALS },
+  //{ "musicvideos",  FieldLastPlayed,    568,    SettingInfo::TODO,        CSmartPlaylistRule::TODO },
+  //{ "musicvideos",  FieldDateAdded,     570,    SettingInfo::TODO,        CSmartPlaylistRule::TODO },
+
+  { "artists",      FieldArtist,        557,    SettingInfo::EDIT,        CSmartPlaylistRule::OPERATOR_CONTAINS },
+  { "artists",      FieldGenre,         515,    SettingInfo::BUTTON,      CSmartPlaylistRule::OPERATOR_EQUALS },
+
+  { "albums",       FieldAlbum,         556,    SettingInfo::EDIT,        CSmartPlaylistRule::OPERATOR_CONTAINS },
+  { "albums",       FieldArtist,        557,    SettingInfo::BUTTON,      CSmartPlaylistRule::OPERATOR_EQUALS },
+  { "albums",       FieldRating,        563,    SettingInfo::RANGE,       CSmartPlaylistRule::OPERATOR_BETWEEN },
+  { "albums",       FieldAlbumType,     564,    SettingInfo::BUTTON,      CSmartPlaylistRule::OPERATOR_EQUALS },
+  { "albums",       FieldYear,          562,    SettingInfo::RANGE,       CSmartPlaylistRule::OPERATOR_BETWEEN },
+  { "albums",       FieldGenre,         515,    SettingInfo::BUTTON,      CSmartPlaylistRule::OPERATOR_EQUALS },
+  { "albums",       FieldMusicLabel,    21899,  SettingInfo::BUTTON,      CSmartPlaylistRule::OPERATOR_EQUALS },
+
+  { "songs",        FieldTitle,         556,    SettingInfo::EDIT,        CSmartPlaylistRule::OPERATOR_CONTAINS },
+  { "songs",        FieldAlbum,         558,    SettingInfo::BUTTON,      CSmartPlaylistRule::OPERATOR_EQUALS },
+  { "songs",        FieldArtist,        557,    SettingInfo::BUTTON,      CSmartPlaylistRule::OPERATOR_EQUALS },
+  { "songs",        FieldTime,          180,    SettingInfo::RANGE,       CSmartPlaylistRule::OPERATOR_BETWEEN },
+  { "songs",        FieldRating,        563,    SettingInfo::RANGE,       CSmartPlaylistRule::OPERATOR_BETWEEN },
+  { "songs",        FieldYear,          562,    SettingInfo::RANGE,       CSmartPlaylistRule::OPERATOR_BETWEEN },
+  { "songs",        FieldGenre,         515,    SettingInfo::BUTTON,      CSmartPlaylistRule::OPERATOR_EQUALS },
+  { "songs",        FieldPlaycount,     567,    SettingInfo::RANGE,       CSmartPlaylistRule::OPERATOR_BETWEEN },
+  //{ "songs",        FieldLastPlayed,    568,    SettingInfo::TODO,        CSmartPlaylistRule::TODO },
+  //{ "songs",        FieldDateAdded,     570,    SettingInfo::TODO,        CSmartPlaylistRule::TODO },
+};
+
+#define NUM_FILTERS sizeof(filterList) / sizeof(CGUIDialogMediaFilter::Filter)
+
+CGUIDialogMediaFilter::CGUIDialogMediaFilter()
+    : CGUIDialogSettings(WINDOW_DIALOG_MEDIA_FILTER, "DialogMediaFilter.xml"),
+      m_dbUrl(NULL),
+      m_filter(NULL)
+{ }
+
+CGUIDialogMediaFilter::~CGUIDialogMediaFilter()
+{
+  Reset();
+}
+
+bool CGUIDialogMediaFilter::OnMessage(CGUIMessage& message)
+{
+  switch (message.GetMessage())
+  {
+    case GUI_MSG_CLICKED:
+    {
+      int control = message.GetSenderId();
+
+      if (control == CONTROL_CLEAR_BUTTON)
+      {
+        m_filter->Reset();
+        m_filter->SetType(m_mediaType);
+
+        for (map<uint32_t, Filter>::iterator filter = m_filters.begin(); filter != m_filters.end(); filter++)
+        {
+          filter->second.rule = NULL;
+          
+          switch (filter->second.type)
+          {
+            case SettingInfo::STRING:
+            case SettingInfo::EDIT:
+              ((CStdString *)filter->second.data)->clear();
+              break;
+
+            case SettingInfo::CHECK:
+              *(int *)filter->second.data = CHECK_ALL;
+              break;
+
+            case SettingInfo::BUTTON:
+              ((CStdString *)filter->second.data)->clear();
+              SET_CONTROL_LABEL2(filter->second.controlIndex, *(CStdString *)filter->second.data);
+              break;
+
+            case SettingInfo::RANGE:
+              *(((float **)filter->second.data)[0]) = m_settings[filter->second.controlIndex - CONTROL_START].min;
+              *(((float **)filter->second.data)[1]) = m_settings[filter->second.controlIndex - CONTROL_START].max;
+              break;
+
+            default:
+              continue;
+          }
+
+          UpdateSetting(filter->first);
+        }
+
+        CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_FILTER_ITEMS, 10); // 10 for advanced
+        g_windowManager.SendMessage(message);
+        return true;
+      }
+      break;
+    }
+
+    case GUI_MSG_WINDOW_DEINIT:
+    {
+      Reset();
+      break;
+    }
+
+    default:
+      break;
+  }
+
+  return CGUIDialogSettings::OnMessage(message);
+}
+
+void CGUIDialogMediaFilter::ShowAndEditMediaFilter(const std::string &path, CSmartPlaylist &filter)
+{
+  CGUIDialogMediaFilter *dialog = (CGUIDialogMediaFilter *)g_windowManager.GetWindow(WINDOW_DIALOG_MEDIA_FILTER);
+  if (dialog == NULL)
+    return;
+
+  // initialize and show the dialog
+  dialog->Initialize();
+  dialog->m_filter = &filter;
+  // must be called after setting the filter/smartplaylist
+  if (!dialog->SetPath(path))
+    return;
+
+  dialog->DoModal();
+}
+
+void CGUIDialogMediaFilter::OnWindowLoaded()
+{
+  CGUIDialogSettings::OnWindowLoaded();
+  // we don't need the cancel button so let's hide it
+  SET_CONTROL_HIDDEN(CONTROL_CANCEL_BUTTON);
+}
+
+void CGUIDialogMediaFilter::CreateSettings()
+{
+  if (m_filter == NULL)
+    return;
+
+  m_settings.clear();
+  int handledRules = 0;
+  for (unsigned int index = 0; index < NUM_FILTERS; index++)
+  {
+    if (filterList[index].mediaType != m_mediaType)
+      continue;
+
+    Filter filter = filterList[index];
+    filter.controlIndex = CONTROL_START + m_settings.size();
+
+    // check the smartplaylist if it contains a matching rule
+    for (vector<CSmartPlaylistRule>::iterator rule = m_filter->m_ruleCombination.m_rules.begin(); rule != m_filter->m_ruleCombination.m_rules.end(); rule++)
+    {
+      if (rule->m_field == filter.field)
+      {
+        filter.rule = &(*rule);
+        handledRules++;
+        break;
+      }
+    }
+
+    switch (filter.type)
+    {
+      case SettingInfo::STRING:
+      case SettingInfo::EDIT:
+      {
+        if (filter.rule != NULL && filter.rule->m_parameter.size() == 1)
+          filter.data = new CStdString(filter.rule->m_parameter.at(0));
+        else
+          filter.data = new CStdString();
+
+        if (filter.type == SettingInfo::STRING)
+          AddString(filter.field, filter.label, (CStdString *)filter.data);
+        else
+          AddEdit(filter.field, filter.label, (CStdString *)filter.data);
+        break;
+      }
+      
+      case SettingInfo::CHECK:
+      {
+        if (filter.rule == NULL)
+          filter.data = new int(CHECK_ALL);
+        else
+          filter.data = new int(filter.rule->m_operator == CSmartPlaylistRule::OPERATOR_TRUE ? CHECK_YES : CHECK_NO);
+
+        vector<pair<int, int> > entries;
+        entries.push_back(pair<int, int>(CHECK_ALL, CHECK_LABEL_ALL));
+        entries.push_back(pair<int, int>(CHECK_NO,  CHECK_LABEL_NO));
+        entries.push_back(pair<int, int>(CHECK_YES, CHECK_LABEL_YES));
+        AddSpin(filter.field, filter.label, (int *)filter.data, entries);
+        break;
+      }
+
+      case SettingInfo::BUTTON:
+      {
+        CStdString *values = new CStdString();
+        if (filter.rule != NULL && filter.rule->m_parameter.size() > 0)
+          *values = filter.rule->GetLocalizedParameter(m_mediaType);
+        filter.data = values;
+
+        AddButton(filter.field, filter.label);
+        break;
+      }
+
+      case SettingInfo::RANGE:
+      {
+        float min, interval, max;
+        RANGEFORMATFUNCTION format;
+        GetRange(filter, min, interval, max, format);
+
+        // don't create the filter if there's no real range
+        if (min == max)
+          break;
+
+        float *valueLower = new float();
+        float *valueUpper = new float();
+        if (filter.rule != NULL && filter.rule->m_parameter.size() == 2)
+        {
+          *valueLower = (float)strtod(filter.rule->m_parameter.at(0), NULL);
+          *valueUpper = (float)strtod(filter.rule->m_parameter.at(1), NULL);
+        }
+        else
+        {
+          *valueLower = min;
+          *valueUpper = max;
+
+          if (filter.rule != NULL)
+          {
+            DeleteRule(filter.field);
+            filter.rule = NULL;
+          }
+        }
+
+        AddRangeSlider(filter.field, filter.label, valueLower, valueUpper, min, interval, max, format);
+        filter.data = m_settings[filter.controlIndex - CONTROL_START].data;
+        break;
+      }
+
+      default:
+        filter.controlIndex = -1;
+        if (filter.rule != NULL)
+          handledRules--;
+        continue;
+    }
+
+    m_filters[filter.field] = filter;
+  }
+
+  // make sure that no change in capacity size is needed when adding new rules
+  // which would copy around the rules and our pointers in the Filter struct
+  // wouldn't work anymore
+  m_filter->m_ruleCombination.m_rules.reserve(m_filters.size() + (m_filter->m_ruleCombination.m_rules.size() - handledRules));
+}
+
+void CGUIDialogMediaFilter::SetupPage()
+{
+  CGUIDialogSettings::SetupPage();
+
+  // set the heading label based on the media type
+  uint32_t localizedMediaId = 0; 
+  if (m_mediaType == "movies")
+    localizedMediaId = 20342;
+  else if (m_mediaType == "tvshows")
+    localizedMediaId = 20343;
+  else if (m_mediaType == "episodes")
+    localizedMediaId = 20360;
+  else if (m_mediaType == "musicvideos")
+    localizedMediaId = 20389;
+  else if (m_mediaType == "artists")
+    localizedMediaId = 133;
+  else if (m_mediaType == "albums")
+    localizedMediaId = 132;
+  else if (m_mediaType == "songs")
+    localizedMediaId = 134;
+
+  CStdString format;
+  format.Format(g_localizeStrings.Get(1275).c_str(), g_localizeStrings.Get(localizedMediaId).c_str());
+  SET_CONTROL_LABEL(CONTROL_HEADING, format);
+
+  // now we can finally set the label/values of the button settings (genre, actors etc)
+  for (map<uint32_t, Filter>::const_iterator filter = m_filters.begin(); filter != m_filters.end(); filter++)
+  {
+    if (filter->second.type == SettingInfo::BUTTON &&
+        filter->second.controlIndex >= 0 && filter->second.data != NULL)
+      SET_CONTROL_LABEL2(filter->second.controlIndex, *(CStdString *)filter->second.data);
+  }
+
+  UpdateControls();
+}
+
+void CGUIDialogMediaFilter::OnSettingChanged(SettingInfo &setting)
+{
+  map<uint32_t, Filter>::iterator it = m_filters.find(setting.id);
+  if (it == m_filters.end())
+    return;
+
+  bool changed = true;
+  bool remove = false;
+  Filter& filter = it->second;
+
+  switch (filter.type)
+  {
+    case SettingInfo::STRING:
+    case SettingInfo::EDIT:
+    {
+      CStdString *str = static_cast<CStdString*>(filter.data);
+      if (!str->empty())
+      {
+        if (filter.rule == NULL)
+          filter.rule = AddRule(filter.field, filter.ruleOperator);
+        filter.rule->m_parameter.clear();
+        filter.rule->m_parameter.push_back(*str);
+      }
+      else
+        remove = true;
+        
+      break;
+    }
+    
+    case SettingInfo::CHECK:
+    {
+      int choice = *(int *)setting.data;
+      if (choice > CHECK_ALL)
+      {
+        CSmartPlaylistRule::SEARCH_OPERATOR ruleOperator = choice == CHECK_YES ? CSmartPlaylistRule::OPERATOR_TRUE : CSmartPlaylistRule::OPERATOR_FALSE;
+        if (filter.rule == NULL)
+          filter.rule = AddRule(filter.field, ruleOperator);
+        else
+          filter.rule->m_operator = ruleOperator;
+      }
+      else
+        remove = true;
+
+      break;
+    }
+
+    case SettingInfo::BUTTON:
+    {
+      CFileItemList items;
+      OnBrowse(filter, items);
+      
+      if (items.Size() > 0)
+      {
+        if (filter.rule == NULL)
+          filter.rule = AddRule(filter.field, filter.ruleOperator);
+
+        filter.rule->m_parameter.clear();
+        for (int index = 0; index < items.Size(); index++)
+          filter.rule->m_parameter.push_back(items[index]->GetLabel());
+
+        *(CStdString *)filter.data = filter.rule->GetLocalizedParameter(m_mediaType);
+      }
+      else
+      {
+        remove = true;
+        *(CStdString *)filter.data = "";
+      }
+
+      SET_CONTROL_LABEL2(filter.controlIndex, *(CStdString *)filter.data);
+      break;
+    }
+
+    case SettingInfo::RANGE:
+    {
+      SettingInfo &setting = m_settings[filter.controlIndex - CONTROL_START];
+      float *valueLower = ((float **)filter.data)[0];
+      float *valueUpper = ((float **)filter.data)[1];
+
+      if (*valueLower > setting.min || *valueUpper < setting.max)
+      {
+        if (filter.rule == NULL)
+          filter.rule = AddRule(filter.field, filter.ruleOperator);
+
+        filter.rule->m_parameter.clear();
+        if (filter.field == FieldAirDate)
+        {
+          CDateTime lower = (time_t)*valueLower;
+          CDateTime upper = (time_t)*valueUpper;
+          filter.rule->m_parameter.push_back(lower.GetAsDBDate());
+          filter.rule->m_parameter.push_back(upper.GetAsDBDate());
+        }
+        else
+        {
+          CStdString tmp;
+          tmp.Format("%.1f", *valueLower);
+          filter.rule->m_parameter.push_back(tmp);
+          tmp.clear();
+          tmp.Format("%.1f", *valueUpper);
+          filter.rule->m_parameter.push_back(tmp);
+        }
+      }
+      else
+      {
+        remove = true;
+        *((float **)filter.data)[0] = setting.min;
+        *((float **)filter.data)[1] = setting.max;
+      }
+      break;
+    }
+
+    default:
+      changed = false;
+      break;
+  }
+
+  // we need to remove the existing rule for the title
+  if (remove && filter.rule != NULL)
+  {
+    DeleteRule(filter.field);
+    filter.rule = NULL;
+  }
+
+  if (changed)
+  {
+    CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_FILTER_ITEMS, 10); // 10 for advanced
+    g_windowManager.SendMessage(message);
+
+    UpdateControls();
+  }
+}
+
+void CGUIDialogMediaFilter::Reset()
+{
+  delete m_dbUrl;
+  m_dbUrl = NULL;
+
+  // delete all the setting's data
+  for (map<uint32_t, Filter>::iterator filter = m_filters.begin(); filter != m_filters.end(); filter++)
+  {
+    switch (filter->second.type)
+    {
+      case SettingInfo::STRING:
+      case SettingInfo::EDIT:
+      case SettingInfo::BUTTON:
+        delete (CStdString *)filter->second.data;
+        break;
+
+      case SettingInfo::CHECK:
+        delete (int *)filter->second.data;
+        break;
+
+      case SettingInfo::RANGE:
+        if (filter->second.data != NULL)
+        {
+          delete ((float **)filter->second.data)[0];
+          delete ((float **)filter->second.data)[1];
+        }
+        delete (float *)filter->second.data;
+        break;
+
+      default:
+        continue;
+    }
+  }
+
+  m_filters.clear();
+}
+
+bool CGUIDialogMediaFilter::SetPath(const std::string &path)
+{
+  if (path.empty() || m_filter == NULL)
+    return false;
+
+  delete m_dbUrl;
+  bool video = false;
+  if (path.find("videodb://") == 0)
+  {
+    m_dbUrl = new CVideoDbUrl();
+    video = true;
+  }
+  else if (path.find("musicdb://") == 0)
+    m_dbUrl = new CMusicDbUrl();
+  else
+    return false;
+
+  if (!m_dbUrl->FromString(path) ||
+     (video && m_dbUrl->GetType() != "movies" && m_dbUrl->GetType() != "tvshows" && m_dbUrl->GetType() != "episodes" && m_dbUrl->GetType() != "musicvideos") ||
+     (!video && m_dbUrl->GetType() != "artists" && m_dbUrl->GetType() != "albums" && m_dbUrl->GetType() != "songs"))
+    return false;
+
+  // remove "filter" option
+  if (m_dbUrl->HasOption("filter"))
+    m_dbUrl->AddOption("filter", "");
+
+  if (video)
+    m_mediaType = ((CVideoDbUrl*)m_dbUrl)->GetItemType();
+  else
+    m_mediaType = m_dbUrl->GetType();
+
+  m_filter->SetType(m_mediaType);
+  return true;
+}
+
+void CGUIDialogMediaFilter::UpdateControls()
+{
+  for (map<uint32_t, Filter>::iterator itFilter = m_filters.begin(); itFilter != m_filters.end(); itFilter++)
+  {
+    if (itFilter->second.type == SettingInfo::BUTTON)
+    {
+      CFileItemList items;
+      OnBrowse(itFilter->second, items, true);
+
+      int size = items.Size();
+      if (items.Size() == 1 && items[0]->HasProperty("total"))
+        size = (int)items[0]->GetProperty("total").asInteger();
+
+      CStdString label = g_localizeStrings.Get(itFilter->second.label);
+      if (size <= 1)
+        CONTROL_DISABLE(itFilter->second.controlIndex);
+      else
+      {
+        CONTROL_ENABLE(itFilter->second.controlIndex);
+        label.Format("%s [%d]", label, size);
+      }
+      SET_CONTROL_LABEL(itFilter->second.controlIndex, label);
+    }
+  }
+}
+
+void CGUIDialogMediaFilter::OnBrowse(const Filter &filter, CFileItemList &items, bool countOnly /* = false */)
+{
+  CFileItemList selectItems;
+  if (m_mediaType == "movies" || m_mediaType == "tvshows" || m_mediaType == "episodes" || m_mediaType == "musicvideos")
+  {
+    CVideoDatabase videodb;
+    if (!videodb.Open())
+      return;
+
+    CSmartPlaylist tmpFilter = *m_filter;
+    for (vector<CSmartPlaylistRule>::iterator rule = tmpFilter.m_ruleCombination.m_rules.begin(); rule != tmpFilter.m_ruleCombination.m_rules.end(); rule++)
+    {
+      if (rule->m_field == filter.field)
+      {
+        tmpFilter.m_ruleCombination.m_rules.erase(rule);
+        break;
+      }
+    }
+
+    std::set<CStdString> playlists;
+    CDatabase::Filter dbfilter;
+    dbfilter.where = tmpFilter.GetWhereClause(videodb, playlists);
+
+    VIDEODB_CONTENT_TYPE type = VIDEODB_CONTENT_MOVIES;    
+    if (m_mediaType == "tvshows")
+      type = VIDEODB_CONTENT_TVSHOWS;
+    else if (m_mediaType == "episodes")
+      type = VIDEODB_CONTENT_EPISODES;
+    else if (m_mediaType == "musicvideos")
+      type = VIDEODB_CONTENT_MUSICVIDEOS;
+
+    if (filter.field == FieldGenre)
+      videodb.GetGenresNav(m_dbUrl->ToString(), selectItems, type, dbfilter, countOnly);
+    else if (filter.field == FieldActor || filter.field == FieldArtist)
+      videodb.GetActorsNav(m_dbUrl->ToString(), selectItems, type, dbfilter, countOnly);
+    else if (filter.field == FieldDirector)
+      videodb.GetDirectorsNav(m_dbUrl->ToString(), selectItems, type, dbfilter, countOnly);
+    else if (filter.field == FieldStudio)
+      videodb.GetStudiosNav(m_dbUrl->ToString(), selectItems, type, dbfilter, countOnly);
+    else if (filter.field == FieldAlbum)
+      videodb.GetMusicVideoAlbumsNav(m_dbUrl->ToString(), selectItems, -1, dbfilter, countOnly);
+    else if (filter.field == FieldTag)
+      videodb.GetTagsNav(m_dbUrl->ToString(), selectItems, type, dbfilter, countOnly);
+  }
+  else if (m_mediaType == "artists" || m_mediaType == "albums" || m_mediaType == "songs")
+  {
+    CMusicDatabase musicdb;
+    if (!musicdb.Open())
+      return;
+
+    CSmartPlaylist tmpFilter = *m_filter;
+    for (vector<CSmartPlaylistRule>::iterator rule = tmpFilter.m_ruleCombination.m_rules.begin(); rule != tmpFilter.m_ruleCombination.m_rules.end(); rule++)
+    {
+      if (rule->m_field == filter.field)
+      {
+        tmpFilter.m_ruleCombination.m_rules.erase(rule);
+        break;
+      }
+    }
+
+    std::set<CStdString> playlists;
+    CDatabase::Filter dbfilter;
+    dbfilter.where = tmpFilter.GetWhereClause(musicdb, playlists);
+    
+    if (filter.field == FieldGenre)
+      musicdb.GetGenresNav(m_dbUrl->ToString(), selectItems, dbfilter, countOnly);
+    else if (filter.field == FieldArtist)
+      musicdb.GetArtistsNav(m_dbUrl->ToString(), selectItems, m_mediaType == "albums", -1, -1, -1, dbfilter, SortDescription(), countOnly);
+    else if (filter.field == FieldAlbum)
+      musicdb.GetAlbumsNav(m_dbUrl->ToString(), selectItems, -1, -1, dbfilter, SortDescription(), countOnly);
+    else if (filter.field == FieldAlbumType)
+      musicdb.GetAlbumTypesNav(m_dbUrl->ToString(), selectItems, dbfilter, countOnly);
+    else if (filter.field == FieldMusicLabel)
+      musicdb.GetMusicLabelsNav(m_dbUrl->ToString(), selectItems, dbfilter, countOnly);
+  }
+
+  if (selectItems.Size() <= 0)
+    return;
+
+  if (countOnly)
+  {
+    items.Copy(selectItems);
+    return;
+  }
+
+  // sort the items
+  selectItems.Sort(SORT_METHOD_LABEL, SortOrderAscending);
+
+  CGUIDialogSelect* pDialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
+  pDialog->Reset();
+  pDialog->SetItems(&selectItems);
+  CStdString strHeading;
+  strHeading.Format(g_localizeStrings.Get(13401), g_localizeStrings.Get(filter.label));
+  pDialog->SetHeading(strHeading);
+  pDialog->SetMultiSelection(true);
+
+  if (filter.rule != NULL && !filter.rule->m_parameter.empty())
+    pDialog->SetSelected(filter.rule->m_parameter);
+
+  pDialog->DoModal();
+  if (pDialog->IsConfirmed())
+    items.Copy(pDialog->GetSelectedItems());
+  else
+    items.Clear();
+  pDialog->Reset();
+}
+
+CSmartPlaylistRule* CGUIDialogMediaFilter::AddRule(Field field, CSmartPlaylistRule::SEARCH_OPERATOR ruleOperator /* = CSmartPlaylistRule::OPERATOR_CONTAINS */)
+{
+  CSmartPlaylistRule rule;
+  rule.m_field = field;
+  rule.m_operator = ruleOperator;
+
+  m_filter->m_ruleCombination.m_rules.push_back(rule);
+  return &m_filter->m_ruleCombination.m_rules.at(m_filter->m_ruleCombination.m_rules.size() - 1);
+}
+
+void CGUIDialogMediaFilter::DeleteRule(Field field)
+{
+  for (vector<CSmartPlaylistRule>::iterator rule = m_filter->m_ruleCombination.m_rules.begin(); rule != m_filter->m_ruleCombination.m_rules.end(); rule++)
+  {
+    if (rule->m_field == field)
+    {
+      m_filter->m_ruleCombination.m_rules.erase(rule);
+      break;
+    }
+  }
+}
+
+void CGUIDialogMediaFilter::GetRange(const Filter &filter, float &min, float &interval, float &max, RANGEFORMATFUNCTION &formatFunction)
+{
+  if (filter.field == FieldRating)
+  {
+    if (m_mediaType == "movies" || m_mediaType == "tvshows" || m_mediaType == "episodes")
+    {
+      min = 0.0f;
+      interval = 0.1f;
+      max = 10.0f;
+      formatFunction = RangeAsFloat;
+    }
+    else if (m_mediaType == "albums" || m_mediaType == "songs")
+    {
+      min = 0.0f;
+      interval = 1.0f;
+      max = 5.0f;
+      formatFunction = RangeAsInt;
+    }
+  }
+  else if (filter.field == FieldYear)
+  {
+    formatFunction = RangeAsInt;
+    min = 0.0f;
+    interval = 1.0f;
+    max = 0.0f;
+
+    if (m_mediaType == "movies" || m_mediaType == "tvshows" || m_mediaType == "musicvideos")
+    {
+      CStdString table;
+      CStdString year;
+      if (m_mediaType == "movies")
+      {
+        table = "movieview";
+        year = DatabaseUtils::GetField(FieldYear, MediaTypeMovie, DatabaseQueryPartWhere);
+      }
+      else if (m_mediaType == "tvshows")
+      {
+        table = "tvshowview";
+        year.Format("strftime(\"%%Y\", %s)", DatabaseUtils::GetField(FieldYear, MediaTypeTvShow, DatabaseQueryPartWhere));
+      }
+      else if (m_mediaType == "musicvideos")
+      {
+        table = "musicvideoview";
+        year = DatabaseUtils::GetField(FieldYear, MediaTypeMusicVideo, DatabaseQueryPartWhere);
+      }
+
+      CDatabase::Filter filter;
+      filter.where = year + " > 0";
+      GetMinMax(table, year, min, max, filter);
+    }
+    else if (m_mediaType == "albums" || m_mediaType == "songs")
+    {
+      CStdString table;
+      MediaType mediaType;
+      if (m_mediaType == "albums")
+      {
+        table = "albumview";
+        mediaType = MediaTypeAlbum;
+      }
+      else if (m_mediaType == "songs")
+      {
+        table = "songview";
+        mediaType = MediaTypeSong;
+      }
+      else
+        return;
+
+      CDatabase::Filter filter;
+      filter.where = DatabaseUtils::GetField(FieldYear, mediaType, DatabaseQueryPartWhere) + " > 0";
+      GetMinMax(table, DatabaseUtils::GetField(FieldYear, mediaType, DatabaseQueryPartSelect), min, max, filter);
+    }
+  }
+  else if (filter.field == FieldAirDate)
+  {
+    formatFunction = RangeAsDate;
+    min = 0.0f;
+    interval = 1.0f;
+    max = 0.0f;
+
+    if (m_mediaType == "episodes")
+    {
+      CStdString field; field.Format("CAST(strftime(\"%%s\", c%02d) AS INTEGER)", VIDEODB_ID_EPISODE_AIRED);
+      
+      GetMinMax("episodeview", field, min, max);
+      interval = 60 * 60 * 24 * 7; // 1 week
+    }
+  }
+  else if (filter.field == FieldTime)
+  {
+    formatFunction = RangeAsTime;
+    min = 0.0f;
+    interval = 10.0f;
+    max = 0.0f;
+
+    if (m_mediaType == "songs")
+      GetMinMax("songview", "iDuration", min, max);
+  }
+  else if (filter.field == FieldPlaycount)
+  {
+    formatFunction = RangeAsInt;
+    min = 0.0f;
+    interval = 1.0f;
+    max = 0.0f;
+
+    if (m_mediaType == "songs")
+      GetMinMax("songview", "iTimesPlayed", min, max);
+  }
+}
+
+bool CGUIDialogMediaFilter::GetMinMax(const CStdString &table, const CStdString &field, float &min, float &max, const CDatabase::Filter &filter /* = CDatabase::Filter() */)
+{
+  if (table.empty() || field.empty())
+    return false;
+
+  CDatabase *db = NULL;
+  CDbUrl *dbUrl = NULL;
+  if (m_mediaType == "movies" || m_mediaType == "tvshows" || m_mediaType == "episodes" || m_mediaType == "musicvideos")
+  {
+    CVideoDatabase *videodb = new CVideoDatabase();
+    if (!videodb->Open())
+    {
+      delete videodb;
+      return false;
+    }
+
+    db = videodb;
+    dbUrl = new CVideoDbUrl();
+  }
+  else if (m_mediaType == "artists" || m_mediaType == "albums" || m_mediaType == "songs")
+  {
+    CMusicDatabase *musicdb = new CMusicDatabase();
+    if (!musicdb->Open())
+    {
+      delete musicdb;
+      return false;
+    }
+
+    db = musicdb;
+    dbUrl = new CMusicDbUrl();
+  }
+
+  if (db == NULL || !db->IsOpen() || dbUrl == NULL)
+  {
+    delete db;
+    delete dbUrl;
+    return false;
+  }
+
+  CDatabase::Filter extFilter = filter;
+  CStdString strSQLExtra;
+  if (!db->BuildSQL(m_dbUrl->ToString(), strSQLExtra, extFilter, strSQLExtra, *dbUrl))
+  {
+    delete db;
+    delete dbUrl;
+    return false;
+  }
+
+  CStdString strSQL = "SELECT %s FROM %s ";
+
+  min = (float)strtod(db->GetSingleValue(db->PrepareSQL(strSQL, CStdString("MIN(" + field + ")").c_str(), table.c_str()) + strSQLExtra).c_str(), NULL);
+  max = (float)strtod(db->GetSingleValue(db->PrepareSQL(strSQL, CStdString("MAX(" + field + ")").c_str(), table.c_str()) + strSQLExtra).c_str(), NULL);
+
+  db->Close();
+  delete db;
+  delete dbUrl;
+
+  return true;
+}
+
+CStdString CGUIDialogMediaFilter::RangeAsFloat(float valueLower, float valueUpper, float minimum)
+{
+  CStdString text;
+  if (valueLower != valueUpper)
+    text.Format(g_localizeStrings.Get(21467).c_str(), valueLower, valueUpper);
+  else
+    text.Format("%.1f", valueLower);
+  return text;
+}
+
+CStdString CGUIDialogMediaFilter::RangeAsInt(float valueLower, float valueUpper, float minimum)
+{
+  CStdString text;
+  if (valueLower != valueUpper)
+    text.Format(g_localizeStrings.Get(21468).c_str(), MathUtils::round_int((double)valueLower), MathUtils::round_int((double)valueUpper));
+  else
+    text.Format("%d", MathUtils::round_int((double)valueLower));
+  return text;
+}
+
+CStdString CGUIDialogMediaFilter::RangeAsDate(float valueLower, float valueUpper, float minimum)
+{
+  CDateTime from = (time_t)valueLower;
+  CDateTime to = (time_t)valueUpper;
+  CStdString text;
+  if (valueLower != valueUpper)
+    text.Format(g_localizeStrings.Get(21469).c_str(), from.GetAsLocalizedDate(), to.GetAsLocalizedDate());
+  else
+    text.Format("%s", from.GetAsLocalizedDate());
+  return text;
+}
+
+CStdString CGUIDialogMediaFilter::RangeAsTime(float valueLower, float valueUpper, float minimum)
+{
+  CDateTime from = (time_t)valueLower;
+  CDateTime to = (time_t)valueUpper;
+  CStdString text;
+  if (valueLower != valueUpper)
+    text.Format(g_localizeStrings.Get(21469).c_str(), from.GetAsLocalizedTime("mm:ss"), to.GetAsLocalizedTime("mm:ss"));
+  else
+    text.Format("%s", from.GetAsLocalizedTime("mm:ss"));
+  return text;
+}
diff --git a/xbmc/dialogs/GUIDialogMediaFilter.h b/xbmc/dialogs/GUIDialogMediaFilter.h
new file mode 100644 (file)
index 0000000..681f068
--- /dev/null
@@ -0,0 +1,82 @@
+#pragma once
+/*
+ *      Copyright (C) 2012 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <map>
+#include <string>
+
+#include "DbUrl.h"
+#include "dbwrappers/Database.h"
+#include "playlists/SmartPlayList.h"
+#include "settings/GUIDialogSettings.h"
+#include "utils/DatabaseUtils.h"
+#include "utils/StdString.h"
+
+class CFileItemList;
+
+class CGUIDialogMediaFilter : public CGUIDialogSettings
+{
+public:
+  CGUIDialogMediaFilter();
+  virtual ~CGUIDialogMediaFilter();
+
+  virtual bool OnMessage(CGUIMessage& message);
+
+  static void ShowAndEditMediaFilter(const std::string &path, CSmartPlaylist &filter);
+
+  typedef struct {
+    std::string mediaType;
+    Field field;
+    uint32_t label;
+    SettingInfo::SETTING_TYPE type;
+    CSmartPlaylistRule::SEARCH_OPERATOR ruleOperator;
+    void *data;
+    CSmartPlaylistRule *rule;
+    int controlIndex;
+  } Filter;
+
+protected:
+  virtual void OnWindowLoaded();
+
+  virtual void CreateSettings();
+  virtual void SetupPage();
+  virtual void OnSettingChanged(SettingInfo &setting);
+
+  void Reset();
+  bool SetPath(const std::string &path);
+  void UpdateControls();
+
+  void OnBrowse(const Filter &filter, CFileItemList &items, bool countOnly = false);
+  CSmartPlaylistRule* AddRule(Field field, CSmartPlaylistRule::SEARCH_OPERATOR ruleOperator = CSmartPlaylistRule::OPERATOR_CONTAINS);
+  void DeleteRule(Field field);
+  void GetRange(const Filter &filter, float &min, float &interval, float &max, RANGEFORMATFUNCTION &formatFunction);
+
+  bool GetMinMax(const CStdString &table, const CStdString &field, float &min, float &max, const CDatabase::Filter &filter = CDatabase::Filter());
+
+  static CStdString RangeAsFloat(float valueLower, float valueUpper, float minimum);
+  static CStdString RangeAsInt(float valueLower, float valueUpper, float minimum);
+  static CStdString RangeAsDate(float valueLower, float valueUpper, float minimum);
+  static CStdString RangeAsTime(float valueLower, float valueUpper, float minimum);
+
+  CDbUrl* m_dbUrl;
+  std::string m_mediaType;
+  CSmartPlaylist *m_filter;
+  std::map<uint32_t, Filter> m_filters;
+};
index 21f7903..e3afeef 100644 (file)
@@ -22,7 +22,6 @@
 #include "guilib/GUIKeyboardFactory.h"
 #include "GUIDialogFileBrowser.h"
 #include "video/windows/GUIWindowVideoBase.h"
-#include "video/dialogs/GUIDialogVideoScan.h"
 #include "guilib/GUIWindowManager.h"
 #include "Util.h"
 #include "utils/URIUtils.h"
@@ -154,7 +153,7 @@ bool CGUIDialogMediaSource::ShowAndAddMediaSource(const CStdString &type)
     }
     share.FromNameAndPaths(type, strName, dialog->GetPaths());
     if (dialog->m_paths->Size() > 0) {
-      share.m_strThumbnailImage = dialog->m_paths->Get(0)->GetThumbnailImage();
+      share.m_strThumbnailImage = dialog->m_paths->Get(0)->GetArt("thumb");
     }
     g_settings.AddShare(type, share);
   }
index 50a2974..f286370 100644 (file)
@@ -9,6 +9,7 @@ SRCS=GUIDialogBoxBase.cpp \
      GUIDialogGamepad.cpp \
      GUIDialogKaiToast.cpp \
      GUIDialogKeyboardGeneric.cpp \
+     GUIDialogMediaFilter.cpp \
      GUIDialogMediaSource.cpp \
      GUIDialogMuteBug.cpp \
      GUIDialogNumeric.cpp \
index f78b05b..9118c84 100644 (file)
@@ -145,7 +145,7 @@ bool CAddonsDirectory::GetDirectory(const CStdString& strPath, CFileItemList &it
             item->m_bIsFolder = true;
             CStdString thumb = GetIcon((TYPE)i);
             if (!thumb.IsEmpty() && g_TextureManager.HasTexture(thumb))
-              item->SetThumbnailImage(thumb);
+              item->SetArt("thumb", thumb);
             items.Add(item);
             break;
           }
@@ -251,14 +251,14 @@ CFileItemPtr CAddonsDirectory::FileItemFromAddon(AddonPtr &addon, const CStdStri
 
   if (!(basePath.Equals("addons://") && addon->Type() == ADDON_REPOSITORY))
     item->SetLabel2(addon->Version().c_str());
-  item->SetThumbnailImage(addon->Icon());
+  item->SetArt("thumb", addon->Icon());
   item->SetLabelPreformated(true);
   item->SetIconImage("DefaultAddon.png");
   if (!addon->FanArt().IsEmpty() && 
       (URIUtils::IsInternetStream(addon->FanArt()) || 
        CFile::Exists(addon->FanArt())))
   {
-    item->SetProperty("fanart_image", addon->FanArt());
+    item->SetArt("fanart", addon->FanArt());
   }
   CAddonDatabase::SetPropertiesFromAddon(addon, item);
   return item;
index 8ab2ad0..12db2a5 100644 (file)
@@ -66,7 +66,7 @@ bool CAndroidAppDirectory::GetDirectory(const CStdString& strPath, CFileItemList
       path.Format("androidapp://%s/%s/%s", url.GetHostName(), dirname,  applications[i].packageName);
       pItem->SetPath(path);
       pItem->SetLabel(applications[i].packageLabel);
-      pItem->SetThumbnailImage(path+".png");
+      pItem->SetArt("thumb", path+".png");
       items.Add(pItem);
     }
     return true;
index 8c744fb..bf01935 100644 (file)
@@ -218,7 +218,7 @@ int64_t CSimpleFileCache::Seek(int64_t iFilePosition)
 
   int64_t nDiff = iTarget - m_nWritePosition;
   if ( nDiff > 500000 || (nDiff > 0 && WaitForData((unsigned int)nDiff, 5000) == CACHE_RC_TIMEOUT)  ) {
-    CLog::Log(LOGWARNING,"%s - attempt to seek pass read data (seek to %"PRId64". max: %"PRId64". reset read pointer. (%"PRId64")", __FUNCTION__, iTarget, m_nWritePosition, iFilePosition);
+    CLog::Log(LOGWARNING,"%s - attempt to seek past read data (seek to %"PRId64". max: %"PRId64". reset read pointer. (%"PRId64")", __FUNCTION__, iTarget, m_nWritePosition, iFilePosition);
     return  CACHE_RC_ERROR;
   }
 
index 81f06f6..5878786 100644 (file)
@@ -652,7 +652,10 @@ void CCurlFile::ParseAndCorrectUrl(CURL &url2)
   else if( strProtocol.Equals("http")
        ||  strProtocol.Equals("https"))
   {
-    if (g_guiSettings.GetBool("network.usehttpproxy") && m_proxy.IsEmpty())
+    if (g_guiSettings.GetBool("network.usehttpproxy")
+        && !g_guiSettings.GetString("network.httpproxyserver").empty()
+        && !g_guiSettings.GetString("network.httpproxyport").empty()
+        && m_proxy.IsEmpty())
     {
       m_proxy = "http://" + g_guiSettings.GetString("network.httpproxyserver");
       m_proxy += ":" + g_guiSettings.GetString("network.httpproxyport");
index 5d13ffa..fcf1d64 100644 (file)
@@ -129,7 +129,6 @@ bool CFile::Cache(const CStdString& strFileName, const CStdString& strDest, XFIL
       return false;
     }
 
-    // 128k is optimal for xbox
     int iBufferSize = 128 * 1024;
 
     CAutoBuffer buffer(iBufferSize);
index a14b068..d6c4067 100644 (file)
@@ -453,7 +453,7 @@ bool CHTSPDirectory::GetDirectory(const CStdString& strPath, CFileItemList &item
       item->SetPath(url.Get());
       item->SetLabel(label);
       item->SetLabelPreformated(true);
-      item->SetThumbnailImage(it->second.icon);
+      item->SetArt("thumb", it->second.icon);
       items.Add(item);
     }
 
index b0ea9b6..34cb6df 100644 (file)
@@ -642,7 +642,7 @@ bool CHTSPSession::ParseItem(const SChannel& channel, int tagid, const SEvent& e
 
   item.SetPath(url.Get());
   item.m_strTitle = tag->m_strTitle;
-  item.SetThumbnailImage(channel.icon);
+  item.SetArt("thumb", channel.icon);
   item.SetMimeType("video/X-htsp");
   return true;
 }
index 9a9ae2f..11a007b 100644 (file)
@@ -306,12 +306,12 @@ void CMultiPathDirectory::MergeItems(CFileItemList &items)
             items.Size(), XbmcThreads::SystemClockMillis() - time);
 }
 
-bool CMultiPathDirectory::SupportsFileOperations(const CStdString &strPath)
+bool CMultiPathDirectory::SupportsWriteFileOperations(const CStdString &strPath)
 {
   vector<CStdString> paths;
   GetPaths(strPath, paths);
   for (unsigned int i = 0; i < paths.size(); ++i)
-    if (CUtil::SupportsFileOperations(paths[i]))
+    if (CUtil::SupportsWriteFileOperations(paths[i]))
       return true;
   return false;
 }
index 01f2292..20b84e4 100644 (file)
@@ -34,7 +34,7 @@ public:
   virtual bool Remove(const char* strPath);
 
   static CStdString GetFirstPath(const CStdString &strPath);
-  static bool SupportsFileOperations(const CStdString &strPath);
+  static bool SupportsWriteFileOperations(const CStdString &strPath);
   static bool GetPaths(const CStdString& strPath, std::vector<CStdString>& vecPaths);
   static bool HasPath(const CStdString& strPath, const CStdString& strPathToFind);
   static CStdString ConstructMultiPath(const std::vector<CStdString> &vecPaths);
index 687c299..8df83d7 100644 (file)
@@ -52,7 +52,7 @@ bool CMusicDatabaseDirectory::GetDirectory(const CStdString& strPath, CFileItemL
   for (int i=0;i<items.Size();++i)
   {
     CFileItemPtr item = items[i];
-    if (item->m_bIsFolder && !item->HasIcon() && !item->HasThumbnail())
+    if (item->m_bIsFolder && !item->HasIcon() && !item->HasArt("thumb"))
     {
       CStdString strImage = GetIcon(item->GetPath());
       if (!strImage.IsEmpty() && g_TextureManager.HasTexture(strImage))
index c3ea6a7..cd69df1 100644 (file)
@@ -73,7 +73,7 @@ bool CDirectoryNodeOverview::GetContent(CFileItemList& items) const
   bool showSingles = false;
   if (musicDatabase.Open())
   {
-    CDatabase::Filter filter("idAlbum IN (SELECT idAlbum FROM album WHERE strAlbum = '')");
+    CDatabase::Filter filter("songview.idAlbum IN (SELECT idAlbum FROM album WHERE strAlbum = '')");
     if (musicDatabase.GetSongsCount(filter) > 0)
       showSingles = true;
   }
index 05930aa..ad952c3 100644 (file)
@@ -36,9 +36,7 @@ bool CDirectoryNodeSingles::GetContent(CFileItemList& items) const
   if (!musicdatabase.Open())
     return false;
 
-  CDatabase::Filter filter;
-  filter.where = "idAlbum IN (SELECT idAlbum FROM album WHERE strAlbum = '')";
-  bool bSuccess=musicdatabase.GetSongsByWhere(BuildPath(), filter, items);
+  bool bSuccess=musicdatabase.GetSongsByWhere(BuildPath(), CDatabase::Filter(), items);
 
   musicdatabase.Close();
 
index 983b623..d0f986e 100644 (file)
@@ -141,7 +141,7 @@ bool CMythDirectory::GetGuide(const CStdString& base, CFileItemList &items)
       if (!icon.IsEmpty())
       {
         url.SetFileName("files/channels/" + URIUtils::GetFileName(icon)); // e.g. files/channels/tv3.jpg
-        item->SetThumbnailImage(url.Get());
+        item->SetArt("thumb", url.Get());
       }
 
       items.Add(item);
@@ -638,7 +638,7 @@ bool CMythDirectory::IsTvShow(const cmyth_proginfo_t program)
   return !IsMovie(program);
 }
 
-bool CMythDirectory::SupportsFileOperations(const CStdString& strPath)
+bool CMythDirectory::SupportsWriteFileOperations(const CStdString& strPath)
 {
   CURL url(strPath);
   CStdString filename = url.GetFileName();
index 3e70c0b..42833e1 100644 (file)
@@ -45,7 +45,7 @@ public:
   virtual bool IsAllowed(const CStdString &strFile) const { return true; };
   virtual DIR_CACHE_TYPE GetCacheType(const CStdString& strPath) const;
 
-  static bool SupportsFileOperations(const CStdString& strPath);
+  static bool SupportsWriteFileOperations(const CStdString& strPath);
   static bool IsLiveTV(const CStdString& strPath);
 
 private:
index 7b155db..cec07b2 100644 (file)
@@ -235,7 +235,7 @@ void CMythSession::SetFileItemMetaData(CFileItem &item, cmyth_proginfo_t program
     if (!chanicon.IsEmpty())
     {
       url.SetFileName("files/channels/" + URIUtils::GetFileName(chanicon)); // e.g. files/channels/tv3.jpg
-      item.SetThumbnailImage(url.Get());
+      item.SetArt("thumb", url.Get());
     }
   }
   else
@@ -246,7 +246,7 @@ void CMythSession::SetFileItemMetaData(CFileItem &item, cmyth_proginfo_t program
     if (m_dll->proginfo_rec_status(program) == RS_RECORDED)
     {
       url.SetFileName("files/" + URIUtils::GetFileName(GetValue(m_dll->proginfo_pathname(program))) + ".png");
-      item.SetThumbnailImage(url.Get());
+      item.SetArt("thumb", url.Get());
     }
   }
 }
index 0722004..57e7355 100644 (file)
@@ -321,13 +321,6 @@ NPT_XbmcFile::Open(NPT_File::OpenMode mode)
 
         bool result;
         CURL* url = new CURL(name);
-        /* path is not fully qualified so assume it's relative to home dir */
-        if (url->GetFileName().IsEmpty()) {
-            delete url;
-            CStdString homepath;
-            CUtil::GetHomePath(homepath);
-            url = new CURL(homepath + "/" + name);
-        }
 
         // compute mode
         if (mode & NPT_FILE_OPEN_MODE_WRITE) {
index 04609f1..d979190 100644 (file)
@@ -103,7 +103,7 @@ bool CPVRDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items
   return false;
 }
 
-bool CPVRDirectory::SupportsFileOperations(const CStdString& strPath)
+bool CPVRDirectory::SupportsWriteFileOperations(const CStdString& strPath)
 {
   CURL url(strPath);
   CStdString filename = url.GetFileName();
index df87c8f..25fa93a 100644 (file)
@@ -35,7 +35,7 @@ public:
   virtual bool GetDirectory(const CStdString& strPath, CFileItemList &items);
   virtual bool IsAllowed(const CStdString &strFile) const { return true; };
 
-  static bool SupportsFileOperations(const CStdString& strPath);
+  static bool SupportsWriteFileOperations(const CStdString& strPath);
   static bool IsLiveTV(const CStdString& strPath);
   static bool HasRecordings();
 
index 24205d4..6c084fd 100644 (file)
@@ -613,7 +613,10 @@ void CPluginDirectory::SetProperty(int handle, const CStdString &strProperty, co
   }
 
   CPluginDirectory *dir = globalHandles[handle];
-  dir->m_listItems->SetProperty(strProperty, strValue);
+  if (strProperty == "fanart_image")
+    dir->m_listItems->SetArt("fanart", strValue);
+  else
+    dir->m_listItems->SetProperty(strProperty, strValue);
 }
 
 void CPluginDirectory::CancelDirectory()
index 343c874..646ae08 100644 (file)
@@ -168,12 +168,12 @@ static void ParseItemMRSS(CFileItem* item, SResources& resources, TiXmlElement*
   else if(name == "thumbnail")
   {
     if(item_child->GetText() && IsPathToThumbnail(item_child->GetText()))
-      item->SetThumbnailImage(item_child->GetText());
+      item->SetArt("thumb", item_child->GetText());
     else
     {
       const char * url = item_child->Attribute("url");
       if(url && IsPathToThumbnail(url))
-        item->SetThumbnailImage(url);
+        item->SetArt("thumb", url);
     }
   }
   else if (name == "title")
@@ -263,9 +263,9 @@ static void ParseItemItunes(CFileItem* item, SResources& resources, TiXmlElement
   {
     const char * url = item_child->Attribute("href");
     if(url)
-      item->SetThumbnailImage(url);
+      item->SetArt("thumb", url);
     else
-      item->SetThumbnailImage(text);
+      item->SetArt("thumb", text);
   }
   else if(name == "summary")
     vtag->m_strPlot = text;
@@ -359,9 +359,9 @@ static void ParseItemVoddler(CFileItem* item, SResources& resources, TiXmlElemen
   {
     const char* url = element->Attribute("url");
     if(url)
-      item->SetProperty("fanart_image", url);
+      item->SetArt("fanart", url);
     else if(IsPathToThumbnail(text))
-      item->SetProperty("fanart_image", text);
+      item->SetArt("fanart", text);
   }
 }
 
@@ -371,7 +371,7 @@ static void ParseItemBoxee(CFileItem* item, SResources& resources, TiXmlElement*
   CStdString text = element->GetText();
 
   if     (name == "image")
-    item->SetThumbnailImage(text);
+    item->SetArt("thumb", text);
   else if(name == "user_agent")
     item->SetProperty("boxee:user_agent", text);
   else if(name == "content_type")
@@ -630,10 +630,8 @@ bool CRSSDirectory::GetDirectory(const CStdString& path, CFileItemList &items)
 
     item->SetProperty("isrss", "1");
     // Use channel image if item doesn't have one
-    if(item->GetThumbnailImage().IsEmpty() && !items.GetThumbnailImage().IsEmpty())
-    {
-      item->SetThumbnailImage(items.GetThumbnailImage());
-    }
+    if (!item->HasArt("thumb") && items.HasArt("thumb"))
+      item->SetArt("thumb", items.GetArt("thumb"));
 
     if (!item->GetPath().IsEmpty())
       items.Add(item);
index 5e7a7df..62346cb 100644 (file)
@@ -50,7 +50,7 @@ namespace XFILE
     return GetDirectory(playlist, items);
   }
   
-  bool CSmartPlaylistDirectory::GetDirectory(const CSmartPlaylist &playlist, CFileItemList& items)
+  bool CSmartPlaylistDirectory::GetDirectory(const CSmartPlaylist &playlist, CFileItemList& items, const CStdString &strBaseDir /* = "" */, bool filter /* = false */)
   {
     bool success = false, success2 = false;
     std::set<CStdString> playlists;
@@ -62,6 +62,8 @@ namespace XFILE
     if (g_guiSettings.GetBool("filelists.ignorethewhensorting"))
       sorting.sortAttributes = SortAttributeIgnoreArticle;
 
+    std::string option = !filter ? "xsp" : "filter";
+
     if (playlist.GetType().Equals("movies") ||
         playlist.GetType().Equals("tvshows") ||
         playlist.GetType().Equals("episodes"))
@@ -71,32 +73,48 @@ namespace XFILE
       {
         MediaType mediaType = DatabaseUtils::MediaTypeFromString(playlist.GetType());
 
-        CStdString strBaseDir;
-        switch (mediaType)
+        CStdString baseDir = strBaseDir;
+        if (strBaseDir.empty())
         {
-        case MediaTypeTvShow:
-        case MediaTypeEpisode:
-          strBaseDir = "videodb://2/2/";
-          break;
+          switch (mediaType)
+          {
+          case MediaTypeTvShow:
+          case MediaTypeEpisode:
+            baseDir = "videodb://2/2/";
+            break;
 
-        case MediaTypeMovie:
-          strBaseDir = "videodb://1/2/";
-          break;
+          case MediaTypeMovie:
+            baseDir = "videodb://1/2/";
+            break;
 
-        default:
-          return false;
+          default:
+            return false;
+          }
         }
 
         CVideoDbUrl videoUrl;
-        CStdString xsp;
-        if (!videoUrl.FromString(strBaseDir) || !playlist.SaveAsJson(xsp, false))
+        if (!videoUrl.FromString(baseDir))
           return false;
 
         // store the smartplaylist as JSON in the URL as well
-        videoUrl.AddOption("xsp", xsp);
+        CStdString xsp;
+        if (!playlist.IsEmpty())
+        {
+          if (!playlist.SaveAsJson(xsp, false))
+            return false;
+        }
+        videoUrl.AddOption(option, xsp);
         
-        CDatabase::Filter filter;
-        success = db.GetSortedVideos(mediaType, videoUrl.ToString(), sorting, items, filter, true);
+        CDatabase::Filter dbfilter;
+        success = db.GetSortedVideos(mediaType, videoUrl.ToString(), sorting, items, dbfilter, true);
+
+        // if we retrieve a list of episodes and we didn't receive
+        // a pre-defined base path, we need to fix it
+        if (strBaseDir.empty() && mediaType == MediaTypeEpisode)
+        {
+          videoUrl.AppendPath("-1/-1/");
+          items.SetPath(videoUrl.ToString());
+        }
         db.Close();
       }
     }
@@ -106,15 +124,20 @@ namespace XFILE
       if (db.Open())
       {
         CMusicDbUrl musicUrl;
-        CStdString xsp;
-        if (!musicUrl.FromString("musicdb://3/") || !playlist.SaveAsJson(xsp, false))
+        if (!musicUrl.FromString(!strBaseDir.empty() ? strBaseDir : "musicdb://3/"))
           return false;
 
         // store the smartplaylist as JSON in the URL as well
-        musicUrl.AddOption("xsp", xsp);
+        CStdString xsp;
+        if (!playlist.IsEmpty())
+        {
+          if (!playlist.SaveAsJson(xsp, false))
+            return false;
+        }
+        musicUrl.AddOption(option, xsp);
 
-        CDatabase::Filter filter;
-        success = db.GetAlbumsByWhere(musicUrl.ToString(), filter, items, sorting);
+        CDatabase::Filter dbfilter;
+        success = db.GetAlbumsByWhere(musicUrl.ToString(), dbfilter, items, sorting);
         items.SetContent("albums");
         db.Close();
       }
@@ -125,13 +148,17 @@ namespace XFILE
       if (db.Open())
       {
         CMusicDbUrl musicUrl;
-        CStdString xsp;
-
-        if (!musicUrl.FromString("musicdb://2/") || !playlist.SaveAsJson(xsp, false))
+        if (!musicUrl.FromString("musicdb://2/"))
           return false;
 
         // store the smartplaylist as JSON in the URL as well
-        musicUrl.AddOption("xsp", xsp);
+        CStdString xsp;
+        if (!playlist.IsEmpty())
+        {
+          if (!playlist.SaveAsJson(xsp, false))
+            return false;
+        }
+        musicUrl.AddOption(option, xsp);
 
         CDatabase::Filter filter;
         success = db.GetArtistsByWhere(musicUrl.ToString(), filter, items, sorting);
@@ -150,15 +177,20 @@ namespace XFILE
           songPlaylist.SetType("songs");
         
         CMusicDbUrl musicUrl;
-        CStdString xsp;
-        if (!musicUrl.FromString("musicdb://4/") || !songPlaylist.SaveAsJson(xsp, false))
+        if (!musicUrl.FromString(!strBaseDir.empty() ? strBaseDir : "musicdb://4/"))
           return false;
 
         // store the smartplaylist as JSON in the URL as well
-        musicUrl.AddOption("xsp", xsp);
+        CStdString xsp;
+        if (!songPlaylist.IsEmpty())
+        {
+          if (!songPlaylist.SaveAsJson(xsp, false))
+            return false;
+        }
+        musicUrl.AddOption(option, xsp);
 
-        CDatabase::Filter filter;
-        success = db.GetSongsByWhere(musicUrl.ToString(), filter, items, sorting);
+        CDatabase::Filter dbfilter;
+        success = db.GetSongsByWhere(musicUrl.ToString(), dbfilter, items, sorting);
         items.SetContent("songs");
         db.Close();
       }
@@ -173,12 +205,17 @@ namespace XFILE
           mvidPlaylist.SetType("musicvideos");
 
         CVideoDbUrl videoUrl;
-        CStdString xsp;
-        if (!videoUrl.FromString("videodb://3/2/") || !mvidPlaylist.SaveAsJson(xsp, false))
+        if (!videoUrl.FromString(!strBaseDir.empty() ? strBaseDir : "videodb://3/2/"))
           return false;
 
         // store the smartplaylist as JSON in the URL as well
-        videoUrl.AddOption("xsp", xsp);
+        CStdString xsp;
+        if (!mvidPlaylist.IsEmpty())
+        {
+          if (!mvidPlaylist.SaveAsJson(xsp, false))
+            return false;
+        }
+        videoUrl.AddOption(option, xsp);
         
         CFileItemList items2;
         success2 = db.GetSortedVideos(MediaTypeMusicVideo, videoUrl.ToString(), sorting, items2);
index 10a9a42..526d3a7 100644 (file)
@@ -36,7 +36,7 @@ namespace XFILE
     virtual bool ContainsFiles(const CStdString& strPath);
     virtual bool Remove(const char *strPath);
 
-    static bool GetDirectory(const CSmartPlaylist &playlist, CFileItemList& items);
+    static bool GetDirectory(const CSmartPlaylist &playlist, CFileItemList& items, const CStdString &strBaseDir = "", bool filter = false);
 
     static CStdString GetPlaylistByName(const CStdString& name, const CStdString& playlistType);
   };
index 11d1615..4b56eae 100644 (file)
@@ -75,7 +75,7 @@ bool CSourcesDirectory::GetDirectory(const VECSOURCES &sources, CFileItemList &i
       // CDetectDVDMedia::SetNewDVDShareUrl() caches disc thumb as special://temp/dvdicon.tbn
       CStdString strThumb = "special://temp/dvdicon.tbn";
       if (XFILE::CFile::Exists(strThumb))
-        pItem->SetThumbnailImage(strThumb);
+        pItem->SetArt("thumb", strThumb);
     }
     else if (pItem->GetPath().Left(9) == "addons://")
       strIcon = "DefaultHardDisk.png";
index 82d86ca..50739ec 100644 (file)
@@ -275,7 +275,7 @@ CUPnPDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items)
             CFileItemPtr pItem(new CFileItem((const char*)name));
             pItem->SetPath(CStdString((const char*) "upnp://" + uuid + "/"));
             pItem->m_bIsFolder = true;
-            pItem->SetThumbnailImage((const char*)(*device)->GetIconUrl("image/jpeg"));
+            pItem->SetArt("thumb", (const char*)(*device)->GetIconUrl("image/png"));
 
             items.Add(pItem);
 
@@ -355,10 +355,15 @@ CUPnPDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items)
         }
 #endif
 
+
+        // Browse and wait for result
+        PLT_MediaObjectListReference list;
+        NPT_Result res;
+        // we want all properties, so send empty filter
+        res = upnp->m_MediaBrowser->BrowseSync(device, object_id, list, false, 0, 0, "");
+
         // if error, return now, the device could have gone away
         // this will make us go back to the sources list
-        PLT_MediaObjectListReference list;
-        NPT_Result res = upnp->m_MediaBrowser->BrowseSync(device, object_id, list);
         if (NPT_FAILED(res)) goto failure;
 
         // empty list is ok
@@ -460,18 +465,36 @@ CUPnPDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items)
             // if there is a thumbnail available set it here
             if((*entry)->m_ExtraInfo.album_arts.GetItem(0))
                 // only considers first album art
-                pItem->SetThumbnailImage((const char*) (*entry)->m_ExtraInfo.album_arts.GetItem(0)->uri);
+                pItem->SetArt("thumb", (const char*) (*entry)->m_ExtraInfo.album_arts.GetItem(0)->uri);
             else if((*entry)->m_Description.icon_uri.GetLength())
-                pItem->SetThumbnailImage((const char*) (*entry)->m_Description.icon_uri);
+                pItem->SetArt("thumb", (const char*) (*entry)->m_Description.icon_uri);
 
             PLT_ProtocolInfo fanart_mask("xbmc.org", "*", "fanart", "*");
             for(unsigned i = 0; i < (*entry)->m_Resources.GetItemCount(); ++i) {
                 PLT_MediaItemResource& res = (*entry)->m_Resources[i];
                 if(res.m_ProtocolInfo.Match(fanart_mask)) {
-                    pItem->SetProperty("fanart_image", (const char*)res.m_Uri);
+                    pItem->SetArt("fanart", (const char*)res.m_Uri);
                     break;
                 }
             }
+            // set the watched overlay, as this will not be set later due to
+            // content set on file item list
+            if (pItem->HasVideoInfoTag()) {
+                int episodes = pItem->GetVideoInfoTag()->m_iEpisode;
+                int played   = pItem->GetVideoInfoTag()->m_playCount;
+                const std::string& type = pItem->GetVideoInfoTag()->m_type;
+                bool watched(false);
+                if (type == "tvshow" || type == "season") {
+                    pItem->SetProperty("totalepisodes", episodes);
+                    pItem->SetProperty("numepisodes", episodes);
+                    pItem->SetProperty("watchedepisodes", played);
+                    pItem->SetProperty("unwatchedepisodes", episodes - played);
+                    watched = (episodes && played == episodes);
+                }
+                else if (type == "episode" || type == "movie")
+                    watched = (played > 0);
+                pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, watched);
+            }
             items.Add(pItem);
 
             ++entry;
@@ -487,7 +510,10 @@ CUPnPDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items)
             max_count  = it->second;
           }
         }
-        items.SetContent(GetContentMapping(max_string));
+        std::string content = GetContentMapping(max_string);
+        items.SetContent(content);
+        if (content == "unknown")
+          items.AddSortMethod(SORT_METHOD_NONE, 551, LABEL_MASKS("%L", "%I", "%L", ""));
     }
 
 cleanup:
index 793c0f0..33a7139 100644 (file)
@@ -53,7 +53,7 @@ bool CVideoDatabaseDirectory::GetDirectory(const CStdString& strPath, CFileItemL
   for (int i=0;i<items.Size();++i)
   {
     CFileItemPtr item = items[i];
-    if (item->m_bIsFolder && !item->HasIcon() && !item->HasThumbnail())
+    if (item->m_bIsFolder && !item->HasIcon() && !item->HasArt("thumb"))
     {
       CStdString strImage = GetIcon(item->GetPath());
       if (!strImage.IsEmpty() && g_TextureManager.HasTexture(strImage))
index 8b2ecbe..b5449b1 100644 (file)
@@ -143,7 +143,7 @@ public:
 
   virtual bool OnMessage(CGUIMessage& message);
   virtual int GetID(void) const;
-  void SetID(int id) { m_controlID = id; };
+  virtual void SetID(int id) { m_controlID = id; };
   virtual bool HasID(int id) const;
   virtual bool HasVisibleID(int id) const;
   int GetParentID() const;
index 24863b1..eb78bee 100644 (file)
@@ -239,6 +239,17 @@ void GUIFontManager::ReloadTTFFonts(void)
   }
 }
 
+void GUIFontManager::UnloadTTFFonts()
+{
+  for (vector<CGUIFontTTFBase*>::iterator i = m_vecFontFiles.begin(); i != m_vecFontFiles.end(); i++)
+    delete (*i);
+
+  m_vecFontFiles.clear();
+
+  for (vector<CGUIFont*>::iterator i = m_vecFonts.begin(); i != m_vecFonts.end(); i++)
+    (*i)->SetFont(NULL);
+}
+
 void GUIFontManager::Unload(const CStdString& strFontName)
 {
   for (vector<CGUIFont*>::iterator iFont = m_vecFonts.begin(); iFont != m_vecFonts.end(); ++iFont)
index 5d9b490..77d9864 100644 (file)
@@ -78,9 +78,11 @@ public:
   bool IsFontSetUnicode(const CStdString& strFontSet);
   bool GetFirstFontSetUnicode(CStdString& strFontSet);
 
+  void ReloadTTFFonts();
+  void UnloadTTFFonts();
+
 protected:
   void RescaleFontSizeAndAspect(float *size, float *aspect, const RESOLUTION_INFO &sourceRes, bool preserveAspect) const;
-  void ReloadTTFFonts();
   void LoadFonts(const TiXmlNode* fontNode);
   CGUIFontTTFBase* GetFontFile(const CStdString& strFontFile);
   bool OpenFontFile(CXBMCTinyXML& xmlDoc);
index 549a580..b707ba5 100644 (file)
@@ -41,7 +41,6 @@ CGUIListItem::CGUIListItem(void)
   m_strLabel = "";
   m_bSelected = false;
   m_strIcon = "";
-  m_strThumbnailImage = "";
   m_overlayIcon = ICON_OVERLAY_NONE;
   m_layout = NULL;
   m_focusedLayout = NULL;
@@ -55,7 +54,6 @@ CGUIListItem::CGUIListItem(const CStdString& strLabel)
   SetSortLabel(strLabel);
   m_bSelected = false;
   m_strIcon = "";
-  m_strThumbnailImage = "";
   m_overlayIcon = ICON_OVERLAY_NONE;
   m_layout = NULL;
   m_focusedLayout = NULL;
@@ -111,17 +109,43 @@ const CStdStringW& CGUIListItem::GetSortLabel() const
   return m_sortLabel;
 }
 
-void CGUIListItem::SetThumbnailImage(const CStdString& strThumbnail)
+void CGUIListItem::SetArt(const std::string &type, const std::string &url)
 {
-  if (m_strThumbnailImage == strThumbnail)
-    return;
-  m_strThumbnailImage = strThumbnail;
+  ArtMap::iterator i = m_art.find(type);
+  if (i == m_art.end() || i->second != url)
+  {
+    m_art[type] = url;
+    SetInvalid();
+  }
+}
+
+void CGUIListItem::SetArt(const map<string, string> &art)
+{
+  m_art = art;
+  // ensure that the fallback "thumb" is available
+  if (m_art.find("thumb") == m_art.end())
+  {
+    if (HasArt("poster"))
+      m_art["thumb"] = m_art["poster"];
+    else if (HasArt("banner"))
+      m_art["thumb"] = m_art["banner"];
+  }
+  
   SetInvalid();
 }
 
-const CStdString& CGUIListItem::GetThumbnailImage() const
+std::string CGUIListItem::GetArt(const std::string &type) const
 {
-  return m_strThumbnailImage;
+  ArtMap::const_iterator i = m_art.find(type);
+  if (i != m_art.end())
+    return i->second;
+  return "";
+}
+
+bool CGUIListItem::HasArt(const std::string &type) const
+{
+  ArtMap::const_iterator i = m_art.find(type);
+  return (i != m_art.end() && !i->second.empty());
 }
 
 void CGUIListItem::SetIconImage(const CStdString& strIcon)
@@ -171,23 +195,9 @@ CStdString CGUIListItem::GetOverlayImage() const
   }
 }
 
-map<string, string> CGUIListItem::GetArt() const
-{
-  map<string, string> art;
-  if (HasThumbnail())
-    art.insert(make_pair("thumb", GetThumbnailImage()));
-  if (HasProperty("fanart_image"))
-    art.insert(make_pair("fanart", GetProperty("fanart_image").asString()));
-  return art;
-}
-
-void CGUIListItem::SetArt(const map<string, string> &art)
+const map<string, string> &CGUIListItem::GetArt() const
 {
-  map<string, string>::const_iterator i = art.find("thumb");
-  if (i != art.end())
-    SetThumbnailImage(i->second);
-  if ((i = art.find("fanart")) != art.end())
-    SetProperty("fanart_image", i->second);
+  return m_art;
 }
 
 void CGUIListItem::Select(bool bOnOff)
@@ -200,12 +210,6 @@ bool CGUIListItem::HasIcon() const
   return (m_strIcon.size() != 0);
 }
 
-
-bool CGUIListItem::HasThumbnail() const
-{
-  return (m_strThumbnailImage.size() != 0);
-}
-
 bool CGUIListItem::HasOverlay() const
 {
   return (m_overlayIcon != CGUIListItem::ICON_OVERLAY_NONE);
@@ -225,10 +229,10 @@ const CGUIListItem& CGUIListItem::operator =(const CGUIListItem& item)
   FreeMemory();
   m_bSelected = item.m_bSelected;
   m_strIcon = item.m_strIcon;
-  m_strThumbnailImage = item.m_strThumbnailImage;
   m_overlayIcon = item.m_overlayIcon;
   m_bIsFolder = item.m_bIsFolder;
   m_mapProperties = item.m_mapProperties;
+  m_art = item.m_art;
   SetInvalid();
   return *this;
 }
@@ -241,7 +245,6 @@ void CGUIListItem::Archive(CArchive &ar)
     ar << m_strLabel;
     ar << m_strLabel2;
     ar << m_sortLabel;
-    ar << m_strThumbnailImage;
     ar << m_strIcon;
     ar << m_bSelected;
     ar << m_overlayIcon;
@@ -251,6 +254,12 @@ void CGUIListItem::Archive(CArchive &ar)
       ar << it->first;
       ar << it->second;
     }
+    ar << (int)m_art.size();
+    for (ArtMap::const_iterator i = m_art.begin(); i != m_art.end(); i++)
+    {
+      ar << i->first;
+      ar << i->second;
+    }
   }
   else
   {
@@ -258,7 +267,6 @@ void CGUIListItem::Archive(CArchive &ar)
     ar >> m_strLabel;
     ar >> m_strLabel2;
     ar >> m_sortLabel;
-    ar >> m_strThumbnailImage;
     ar >> m_strIcon;
     ar >> m_bSelected;
 
@@ -270,12 +278,20 @@ void CGUIListItem::Archive(CArchive &ar)
     ar >> mapSize;
     for (int i = 0; i < mapSize; i++)
     {
-      CStdString key;
+      std::string key;
       CVariant value;
       ar >> key;
       ar >> value;
       SetProperty(key, value);
     }
+    ar >> mapSize;
+    for (int i = 0; i < mapSize; i++)
+    {
+      std::string key, value;
+      ar >> key;
+      ar >> value;
+      m_art.insert(make_pair(key, value));
+    }
   }
 }
 void CGUIListItem::Serialize(CVariant &value)
@@ -283,8 +299,7 @@ void CGUIListItem::Serialize(CVariant &value)
   value["isFolder"] = m_bIsFolder;
   value["strLabel"] = m_strLabel;
   value["strLabel2"] = m_strLabel2;
-  value["sortLabel"] = CStdString(m_sortLabel);
-  value["strThumbnailImage"] = m_strThumbnailImage;
+  value["sortLabel"] = m_sortLabel;
   value["strIcon"] = m_strIcon;
   value["selected"] = m_bSelected;
 
@@ -292,12 +307,16 @@ void CGUIListItem::Serialize(CVariant &value)
   {
     value["properties"][it->first] = it->second;
   }
+  for (ArtMap::const_iterator it = m_art.begin(); it != m_art.end(); it++)
+    value["art"][it->first] = it->second;
 }
 
 void CGUIListItem::FreeIcons()
 {
   FreeMemory();
-  m_strThumbnailImage = "";
+  ArtMap::iterator i = m_art.find("thumb");
+  if (i != m_art.end())
+    m_art.erase(i);
   m_strIcon = "";
   SetInvalid();
 }
index 930ebe2..9e35330 100644 (file)
@@ -45,6 +45,8 @@ class CVariant;
 class CGUIListItem
 {
 public:
+  typedef std::map<std::string, std::string> ArtMap;
+
   enum GUIIconOverlay { ICON_OVERLAY_NONE = 0,
                         ICON_OVERLAY_RAR,
                         ICON_OVERLAY_ZIP,
@@ -72,25 +74,40 @@ public:
   void SetIconImage(const CStdString& strIcon);
   const CStdString& GetIconImage() const;
 
-  void SetThumbnailImage(const CStdString& strThumbnail);
-  const CStdString& GetThumbnailImage() const;
-
   void SetOverlayImage(GUIIconOverlay icon, bool bOnOff=false);
   CStdString GetOverlayImage() const;
 
+  /*! \brief Set a particular art type for an item
+   \param type type of art to set.
+   \param url the url of the art.
+   */
+  void SetArt(const std::string &type, const std::string &url);
+
   /*! \brief set artwork for an item
-   Sets thumb and fanart image
    \param map a type:url map for artwork
    \sa GetArt
    */
-  void SetArt(const std::map<std::string, std::string> &art);
+  void SetArt(const ArtMap &art);
+
+  /*! \brief Get a particular art type for an item
+   \param type type of art to fetch.
+   \return the art URL, if available, else empty.
+   */
+  std::string GetArt(const std::string &type) const;
 
   /*! \brief get artwork for an item
    Retrieves artwork in a type:url map
    \return a type:url map for artwork
    \sa SetArt
    */
-  std::map<std::string, std::string> GetArt() const;
+  const ArtMap &GetArt() const;
+
+  /*! \brief Check whether an item has a particular piece of art
+   Equivalent to !GetArt(type).empty()
+   \param type type of art to set.
+   \return true if the item has that art set, false otherwise.
+   */
+  bool HasArt(const std::string &type) const;
 
   void SetSortLabel(const CStdString &label);
   void SetSortLabel(const CStdStringW &label);
@@ -100,7 +117,6 @@ public:
   bool IsSelected() const;
 
   bool HasIcon() const;
-  bool HasThumbnail() const;
   bool HasOverlay() const;
   virtual bool IsFileItem() const { return false; };
 
@@ -141,7 +157,6 @@ public:
 
 protected:
   CStdString m_strLabel2;     // text of column2
-  CStdString m_strThumbnailImage; // filename of thumbnail
   CStdString m_strIcon;      // filename of icon
   GUIIconOverlay m_overlayIcon; // type of overlay icon
 
@@ -162,6 +177,8 @@ protected:
 private:
   CStdStringW m_sortLabel;    // text for sorting. Need to be UTF16 for proper sorting
   CStdString m_strLabel;      // text of column1
+
+  ArtMap m_art;
 };
 #endif
 
index c2c3536..2c13781 100644 (file)
@@ -32,19 +32,26 @@ static const SliderAction actions[] = {
 CGUISliderControl::CGUISliderControl(int parentID, int controlID, float posX, float posY, float width, float height, const CTextureInfo& backGroundTexture, const CTextureInfo& nibTexture, const CTextureInfo& nibTextureFocus, int iType)
     : CGUIControl(parentID, controlID, posX, posY, width, height)
     , m_guiBackground(posX, posY, width, height, backGroundTexture)
-    , m_guiMid(posX, posY, width, height, nibTexture)
-    , m_guiMidFocus(posX, posY, width, height, nibTextureFocus)
+    , m_guiSelectorLower(posX, posY, width, height, nibTexture)
+    , m_guiSelectorUpper(posX, posY, width, height, nibTexture)
+    , m_guiSelectorLowerFocus(posX, posY, width, height, nibTextureFocus)
+    , m_guiSelectorUpperFocus(posX, posY, width, height, nibTextureFocus)
 {
   m_iType = iType;
-  m_iPercent = 0;
+  m_rangeSelection = false;
+  m_currentSelector = RangeSelectorLower; // use lower selector by default
+  m_percentValues[0] = 0;
+  m_percentValues[1] = 100;
   m_iStart = 0;
   m_iEnd = 100;
   m_iInterval = 1;
   m_fStart = 0.0f;
   m_fEnd = 1.0f;
   m_fInterval = 0.1f;
-  m_iValue = 0;
-  m_fValue = 0.0;
+  m_intValues[0] = m_iStart;
+  m_intValues[1] = m_iEnd;
+  m_floatValues[0] = m_fStart;
+  m_floatValues[1] = m_fEnd;
   ControlType = GUICONTROL_SLIDER;
   m_iInfoCode = 0;
   m_dragging = false;
@@ -76,35 +83,53 @@ void CGUISliderControl::Process(unsigned int currentTime, CDirtyRegionList &dirt
   dirty |= m_guiBackground.SetWidth(m_width);
   dirty |= m_guiBackground.Process(currentTime);
 
+  CGUITexture &nibLower = (m_bHasFocus && !IsDisabled() && m_currentSelector == RangeSelectorLower) ? m_guiSelectorLowerFocus : m_guiSelectorLower;
+  dirty |= ProcessSelector(nibLower, currentTime, fScaleY, RangeSelectorLower);
+  if (m_rangeSelection)
+  {
+    CGUITexture &nibUpper = (m_bHasFocus && !IsDisabled() && m_currentSelector == RangeSelectorUpper) ? m_guiSelectorUpperFocus : m_guiSelectorUpper;
+    dirty |= ProcessSelector(nibUpper, currentTime, fScaleY, RangeSelectorUpper);
+  }
+
+  if (dirty)
+    MarkDirtyRegion();
+
+  CGUIControl::Process(currentTime, dirtyregions);
+}
+
+bool CGUISliderControl::ProcessSelector(CGUITexture &nib, unsigned int currentTime, float fScaleY, RangeSelector selector)
+{
+  bool dirty = false;
   // we render the nib centered at the appropriate percentage, except where the nib
   // would overflow the background image
-  CGUITexture &nib = (m_bHasFocus && !IsDisabled()) ? m_guiMidFocus : m_guiMid;
-
   dirty |= nib.SetHeight(nib.GetTextureHeight() * fScaleY);
   dirty |= nib.SetWidth(nib.GetHeight() * 2);
-  CAspectRatio ratio(CAspectRatio::AR_KEEP); ratio.align = ASPECT_ALIGN_LEFT | ASPECT_ALIGNY_CENTER;
+  CAspectRatio ratio(CAspectRatio::AR_KEEP);
+  ratio.align = ASPECT_ALIGN_LEFT | ASPECT_ALIGNY_CENTER;
   dirty |= nib.SetAspectRatio(ratio);
   CRect rect = nib.GetRenderRect();
 
-  float offset = GetProportion() * m_width - rect.Width() / 2;
+  float offset = GetProportion(selector) * m_width - rect.Width() / 2;
   if (offset > m_width - rect.Width())
     offset = m_width - rect.Width();
   if (offset < 0)
     offset = 0;
-  dirty |= nib.SetPosition(m_guiBackground.GetXPosition() + offset, m_guiBackground.GetYPosition() );
+  dirty |= nib.SetPosition(m_guiBackground.GetXPosition() + offset, m_guiBackground.GetYPosition());
   dirty |= nib.Process(currentTime);
 
-  if (dirty)
-    MarkDirtyRegion();
-
-  CGUIControl::Process(currentTime, dirtyregions);
+  return dirty;
 }
 
 void CGUISliderControl::Render()
 {
   m_guiBackground.Render();
-  CGUITexture &nib = (m_bHasFocus && !IsDisabled()) ? m_guiMidFocus : m_guiMid;
-  nib.Render();
+  CGUITexture &nibLower = (m_bHasFocus && !IsDisabled() && m_currentSelector == RangeSelectorLower) ? m_guiSelectorLowerFocus : m_guiSelectorLower;
+  nibLower.Render();
+  if (m_rangeSelection)
+  {
+    CGUITexture &nibUpper = (m_bHasFocus && !IsDisabled() && m_currentSelector == RangeSelectorUpper) ? m_guiSelectorUpperFocus : m_guiSelectorUpper;
+    nibUpper.Render();
+  }
   CGUIControl::Render();
 }
 
@@ -121,7 +146,8 @@ bool CGUISliderControl::OnMessage(CGUIMessage& message)
 
     case GUI_MSG_LABEL_RESET:
       {
-        SetPercentage(0);
+        SetPercentage(0, RangeSelectorLower);
+        SetPercentage(100, RangeSelectorUpper);
         return true;
       }
       break;
@@ -137,42 +163,83 @@ bool CGUISliderControl::OnAction(const CAction &action)
   {
   case ACTION_MOVE_LEFT:
     //case ACTION_OSD_SHOW_VALUE_MIN:
-    Move( -1);
+    Move(-1);
     return true;
-    break;
 
   case ACTION_MOVE_RIGHT:
     //case ACTION_OSD_SHOW_VALUE_PLUS:
     Move(1);
     return true;
-    break;
+
+  case ACTION_SELECT_ITEM:
+    // switch between the two sliders
+    SwitchRangeSelector();
+    return true;
+
   default:
-    return CGUIControl::OnAction(action);
+    break;
   }
+
+  return CGUIControl::OnAction(action);
 }
 
 void CGUISliderControl::Move(int iNumSteps)
 {
+  bool rangeSwap = false;
   switch (m_iType)
   {
   case SPIN_CONTROL_TYPE_FLOAT:
-    m_fValue += m_fInterval * iNumSteps;
-    if (m_fValue < m_fStart) m_fValue = m_fStart;
-    if (m_fValue > m_fEnd) m_fValue = m_fEnd;
-    break;
+    {
+      float &value = m_floatValues[m_currentSelector];
+      value += m_fInterval * iNumSteps;
+      if (value < m_fStart) value = m_fStart;
+      if (value > m_fEnd) value = m_fEnd;
+      if (m_floatValues[0] > m_floatValues[1])
+      {
+        float valueLower = m_floatValues[0];
+        m_floatValues[0] = m_floatValues[1];
+        m_floatValues[1] = valueLower;
+        rangeSwap = true;
+      }
+      break;
+    }
 
   case SPIN_CONTROL_TYPE_INT:
-    m_iValue += m_iInterval * iNumSteps;
-    if (m_iValue < m_iStart) m_iValue = m_iStart;
-    if (m_iValue > m_iEnd) m_iValue = m_iEnd;
-    break;
+    {
+      int &value = m_intValues[m_currentSelector];
+      value += m_iInterval * iNumSteps;
+      if (value < m_iStart) value = m_iStart;
+      if (value > m_iEnd) value = m_iEnd;
+      if (m_intValues[0] > m_intValues[1])
+      {
+        int valueLower = m_intValues[0];
+        m_intValues[0] = m_intValues[1];
+        m_intValues[1] = valueLower;
+        rangeSwap = true;
+      }
+      break;
+    }
 
   default:
-    m_iPercent += m_iInterval * iNumSteps;
-    if (m_iPercent < 0) m_iPercent = 0;
-    if (m_iPercent > 100) m_iPercent = 100;
-    break;
+    {
+      int &value = m_percentValues[m_currentSelector];
+      value += m_iInterval * iNumSteps;
+      if (value < 0) value = 0;
+      if (value > 100) value = 100;
+      if (m_percentValues[0] > m_percentValues[1])
+      {
+        int valueLower = m_percentValues[0];
+        m_percentValues[0] = m_percentValues[1];
+        m_percentValues[1] = valueLower;
+        rangeSwap = true;
+      }
+      break;
+    }
   }
+
+  if (rangeSwap)
+    SwitchRangeSelector();
+
   SendClick();
 }
 
@@ -190,56 +257,130 @@ void CGUISliderControl::SendClick()
   }
 }
 
-void CGUISliderControl::SetPercentage(int iPercent)
+void CGUISliderControl::SetRangeSelection(bool rangeSelection)
+{
+  if (m_rangeSelection == rangeSelection)
+    return;
+
+  m_rangeSelection = rangeSelection;
+  SetRangeSelector(RangeSelectorLower);
+  SetInvalid();
+}
+
+void CGUISliderControl::SetRangeSelector(RangeSelector selector)
+{
+  if (m_currentSelector == selector)
+    return;
+
+  m_currentSelector = selector;
+  SetInvalid();
+}
+
+void CGUISliderControl::SwitchRangeSelector()
+{
+  if (m_currentSelector == RangeSelectorLower)
+    SetRangeSelector(RangeSelectorUpper);
+  else
+    SetRangeSelector(RangeSelectorLower);
+}
+
+void CGUISliderControl::SetPercentage(int iPercent, RangeSelector selector /* = RangeSelectorLower */)
 {
   if (iPercent > 100) iPercent = 100;
-  if (iPercent < 0) iPercent = 0;
-  m_iPercent = iPercent;
+  else if (iPercent < 0) iPercent = 0;
+
+  int iPercentLower = selector == RangeSelectorLower ? iPercent : m_percentValues[0];
+  int iPercentUpper = selector == RangeSelectorUpper ? iPercent : m_percentValues[1];
+
+  if (!m_rangeSelection || iPercentLower <= iPercentUpper)
+  {
+    m_percentValues[0] = iPercentLower;
+    m_percentValues[1] = iPercentUpper;
+  }
+  else
+  {
+    m_percentValues[0] = iPercentUpper;
+    m_percentValues[1] = iPercentLower;
+  }
 }
 
-int CGUISliderControl::GetPercentage() const
+int CGUISliderControl::GetPercentage(RangeSelector selector /* = RangeSelectorLower */) const
 {
-  return m_iPercent;
+  return m_percentValues[selector];
 }
 
-void CGUISliderControl::SetIntValue(int iValue)
+void CGUISliderControl::SetIntValue(int iValue, RangeSelector selector /* = RangeSelectorLower */)
 {
   if (m_iType == SPIN_CONTROL_TYPE_FLOAT)
-    m_fValue = (float)iValue;
+    SetFloatValue((float)iValue);
   else if (m_iType == SPIN_CONTROL_TYPE_INT)
-    m_iValue = iValue;
+  {
+    if (iValue > m_iEnd) iValue = m_iEnd;
+    else if (iValue < m_iStart) iValue = m_iStart;
+
+    int iValueLower = selector == RangeSelectorLower ? iValue : m_intValues[0];
+    int iValueUpper = selector == RangeSelectorUpper ? iValue : m_intValues[1];
+
+    if (!m_rangeSelection || iValueLower <= iValueUpper)
+    {
+      m_intValues[0] = iValueLower;
+      m_intValues[1] = iValueUpper;
+    }
+    else
+    {
+      m_intValues[0] = iValueUpper;
+      m_intValues[1] = iValueLower;
+    }
+  }
   else
     SetPercentage(iValue);
 }
 
-int CGUISliderControl::GetIntValue() const
+int CGUISliderControl::GetIntValue(RangeSelector selector /* = RangeSelectorLower */) const
 {
   if (m_iType == SPIN_CONTROL_TYPE_FLOAT)
-    return (int)m_fValue;
+    return (int)m_floatValues[selector];
   else if (m_iType == SPIN_CONTROL_TYPE_INT)
-    return m_iValue;
+    return m_intValues[selector];
   else
-    return m_iPercent;
+    return m_percentValues[selector];
 }
 
-void CGUISliderControl::SetFloatValue(float fValue)
+void CGUISliderControl::SetFloatValue(float fValue, RangeSelector selector /* = RangeSelectorLower */)
 {
   if (m_iType == SPIN_CONTROL_TYPE_FLOAT)
-    m_fValue = fValue;
+  {
+    if (fValue > m_fEnd) fValue = m_fEnd;
+    else if (fValue < m_fStart) fValue = m_fStart;
+
+    float fValueLower = selector == RangeSelectorLower ? fValue : m_floatValues[0];
+    float fValueUpper = selector == RangeSelectorUpper ? fValue : m_floatValues[1];
+
+    if (!m_rangeSelection || fValueLower <= fValueUpper)
+    {
+      m_floatValues[0] = fValueLower;
+      m_floatValues[1] = fValueUpper;
+    }
+    else
+    {
+      m_floatValues[0] = fValueUpper;
+      m_floatValues[1] = fValueLower;
+    }
+  }
   else if (m_iType == SPIN_CONTROL_TYPE_INT)
-    m_iValue = (int)fValue;
+    SetIntValue((int)fValue);
   else
     SetPercentage((int)fValue);
 }
 
-float CGUISliderControl::GetFloatValue() const
+float CGUISliderControl::GetFloatValue(RangeSelector selector /* = RangeSelectorLower */) const
 {
   if (m_iType == SPIN_CONTROL_TYPE_FLOAT)
-    return m_fValue;
+    return m_floatValues[selector];
   else if (m_iType == SPIN_CONTROL_TYPE_INT)
-    return (float)m_iValue;
+    return (float)m_intValues[selector];
   else
-    return (float)m_iPercent;
+    return (float)m_percentValues[selector];
 }
 
 void CGUISliderControl::SetIntInterval(int iInterval)
@@ -264,8 +405,8 @@ void CGUISliderControl::SetRange(int iStart, int iEnd)
     SetFloatRange((float)iStart,(float)iEnd);
   else
   {
-    m_iStart = iStart;
-    m_iEnd = iEnd;
+    m_intValues[0] = m_iStart = iStart;
+    m_intValues[1] = m_iEnd = iEnd;
   }
 }
 
@@ -275,8 +416,8 @@ void CGUISliderControl::SetFloatRange(float fStart, float fEnd)
     SetRange((int)fStart, (int)fEnd);
   else
   {
-    m_fStart = fStart;
-    m_fEnd = fEnd;
+    m_floatValues[0] = m_fStart = fStart;
+    m_floatValues[1] = m_fEnd = fEnd;
   }
 }
 
@@ -284,38 +425,47 @@ void CGUISliderControl::FreeResources(bool immediately)
 {
   CGUIControl::FreeResources(immediately);
   m_guiBackground.FreeResources(immediately);
-  m_guiMid.FreeResources(immediately);
-  m_guiMidFocus.FreeResources(immediately);
+  m_guiSelectorLower.FreeResources(immediately);
+  m_guiSelectorUpper.FreeResources(immediately);
+  m_guiSelectorLowerFocus.FreeResources(immediately);
+  m_guiSelectorUpperFocus.FreeResources(immediately);
 }
 
 void CGUISliderControl::DynamicResourceAlloc(bool bOnOff)
 {
   CGUIControl::DynamicResourceAlloc(bOnOff);
   m_guiBackground.DynamicResourceAlloc(bOnOff);
-  m_guiMid.DynamicResourceAlloc(bOnOff);
-  m_guiMidFocus.DynamicResourceAlloc(bOnOff);
+  m_guiSelectorLower.DynamicResourceAlloc(bOnOff);
+  m_guiSelectorUpper.DynamicResourceAlloc(bOnOff);
+  m_guiSelectorLowerFocus.DynamicResourceAlloc(bOnOff);
+  m_guiSelectorUpperFocus.DynamicResourceAlloc(bOnOff);
 }
 
 void CGUISliderControl::AllocResources()
 {
   CGUIControl::AllocResources();
   m_guiBackground.AllocResources();
-  m_guiMid.AllocResources();
-  m_guiMidFocus.AllocResources();
+  m_guiSelectorLower.AllocResources();
+  m_guiSelectorUpper.AllocResources();
+  m_guiSelectorLowerFocus.AllocResources();
+  m_guiSelectorUpperFocus.AllocResources();
 }
 
 void CGUISliderControl::SetInvalid()
 {
   CGUIControl::SetInvalid();
   m_guiBackground.SetInvalid();
-  m_guiMid.SetInvalid();
-  m_guiMidFocus.SetInvalid();
+  m_guiSelectorLower.SetInvalid();
+  m_guiSelectorUpper.SetInvalid();
+  m_guiSelectorLowerFocus.SetInvalid();
+  m_guiSelectorUpperFocus.SetInvalid();
 }
 
 bool CGUISliderControl::HitTest(const CPoint &point) const
 {
   if (m_guiBackground.HitTest(point)) return true;
-  if (m_guiMid.HitTest(point)) return true;
+  if (m_guiSelectorLower.HitTest(point)) return true;
+  if (m_rangeSelection && m_guiSelectorUpper.HitTest(point)) return true;
   return false;
 }
 
@@ -324,19 +474,39 @@ void CGUISliderControl::SetFromPosition(const CPoint &point)
   float fPercent = (point.x - m_guiBackground.GetXPosition()) / m_guiBackground.GetWidth();
   if (fPercent < 0) fPercent = 0;
   if (fPercent > 1) fPercent = 1;
+
+  RangeSelector selector = RangeSelectorLower;
   switch (m_iType)
   {
   case SPIN_CONTROL_TYPE_FLOAT:
-    m_fValue = m_fStart + (m_fEnd - m_fStart) * fPercent;
-    break;
+    {
+      float fValue = m_fStart + (m_fEnd - m_fStart) * fPercent;
+      if (m_rangeSelection && fValue >= m_floatValues[1])
+        selector = RangeSelectorUpper;
+
+      SetFloatValue(fValue, selector);
+      break;
+    }
 
   case SPIN_CONTROL_TYPE_INT:
-    m_iValue = (int)(m_iStart + (float)(m_iEnd - m_iStart) * fPercent + 0.49f);
-    break;
+    {
+      int iValue = (int)(m_iStart + (float)(m_iEnd - m_iStart) * fPercent + 0.49f);
+      if (m_rangeSelection && iValue >= m_intValues[1])
+        selector = RangeSelectorUpper;
+
+      SetIntValue(iValue, selector);
+      break;
+    }
 
   default:
-    m_iPercent = (int)(fPercent * 100 + 0.49f);
-    break;
+    {
+      int iValue = (int)(fPercent * 100 + 0.49f);
+      if (m_rangeSelection && iValue >= m_percentValues[1])
+        selector = RangeSelectorUpper;
+
+      SetPercentage(iValue, selector);
+      break;
+    }
   }
   SendClick();
 }
@@ -411,11 +581,26 @@ CStdString CGUISliderControl::GetDescription() const
     return m_textValue;
   CStdString description;
   if (m_iType == SPIN_CONTROL_TYPE_FLOAT)
-    description.Format("%2.2f", m_fValue);
+  {
+    if (m_rangeSelection)
+      description.Format("[%2.2f, %2.2f]", m_floatValues[0], m_floatValues[1]);
+    else
+      description.Format("%2.2f", m_floatValues[0]);
+  }
   else if (m_iType == SPIN_CONTROL_TYPE_INT)
-    description.Format("%i", m_iValue);
+  {
+    if (m_rangeSelection)
+      description.Format("[%i, %i]", m_intValues[0], m_intValues[1]);
+    else
+      description.Format("%i", m_intValues[0]);
+  }
   else
-    description.Format("%i%%", m_iPercent);
+  {
+    if (m_rangeSelection)
+      description.Format("[%i%%, %i%%]", m_percentValues[0], m_percentValues[1]);
+    else
+      description.Format("%i%%", m_percentValues[0]);
+  }
   return description;
 }
 
@@ -423,19 +608,21 @@ bool CGUISliderControl::UpdateColors()
 {
   bool changed = CGUIControl::UpdateColors();
   changed |= m_guiBackground.SetDiffuseColor(m_diffuseColor);
-  changed |= m_guiMid.SetDiffuseColor(m_diffuseColor);
-  changed |= m_guiMidFocus.SetDiffuseColor(m_diffuseColor);
+  changed |= m_guiSelectorLower.SetDiffuseColor(m_diffuseColor);
+  changed |= m_guiSelectorUpper.SetDiffuseColor(m_diffuseColor);
+  changed |= m_guiSelectorLowerFocus.SetDiffuseColor(m_diffuseColor);
+  changed |= m_guiSelectorUpperFocus.SetDiffuseColor(m_diffuseColor);
 
   return changed;
 }
 
-float CGUISliderControl::GetProportion() const
+float CGUISliderControl::GetProportion(RangeSelector selector /* = RangeSelectorLower */) const
 {
   if (m_iType == SPIN_CONTROL_TYPE_FLOAT)
-    return (m_fValue - m_fStart) / (m_fEnd - m_fStart);
+    return (GetFloatValue(selector) - m_fStart) / (m_fEnd - m_fStart);
   else if (m_iType == SPIN_CONTROL_TYPE_INT)
-    return (float)(m_iValue - m_iStart) / (float)(m_iEnd - m_iStart);
-  return 0.01f * m_iPercent;
+    return (float)(GetIntValue(selector) - m_iStart) / (float)(m_iEnd - m_iStart);
+  return 0.01f * GetPercentage(selector);
 }
 
 void CGUISliderControl::SetAction(const CStdString &action)
index 6b8fbfa..7ea0caa 100644 (file)
@@ -51,6 +51,11 @@ class CGUISliderControl :
       public CGUIControl
 {
 public:
+  typedef enum {
+    RangeSelectorLower = 0,
+    RangeSelectorUpper = 1
+  } RangeSelector;
+
   CGUISliderControl(int parentID, int controlID, float posX, float posY, float width, float height, const CTextureInfo& backGroundTexture, const CTextureInfo& mibTexture, const CTextureInfo& nibTextureFocus, int iType);
   virtual ~CGUISliderControl(void);
   virtual CGUISliderControl *Clone() const { return new CGUISliderControl(*this); };
@@ -65,13 +70,17 @@ public:
   virtual void SetRange(int iStart, int iEnd);
   virtual void SetFloatRange(float fStart, float fEnd);
   virtual bool OnMessage(CGUIMessage& message);
+  bool ProcessSelector(CGUITexture &nib, unsigned int currentTime, float fScaleY, RangeSelector selector);
+  void SetRangeSelection(bool rangeSelection);
+  void SetRangeSelector(RangeSelector selector);
+  void SwitchRangeSelector();
   void SetInfo(int iInfo);
-  void SetPercentage(int iPercent);
-  int GetPercentage() const;
-  void SetIntValue(int iValue);
-  int GetIntValue() const;
-  void SetFloatValue(float fValue);
-  float GetFloatValue() const;
+  void SetPercentage(int iPercent, RangeSelector selector = RangeSelectorLower);
+  int GetPercentage(RangeSelector selector = RangeSelectorLower) const;
+  void SetIntValue(int iValue, RangeSelector selector = RangeSelectorLower);
+  int GetIntValue(RangeSelector selector = RangeSelectorLower) const;
+  void SetFloatValue(float fValue, RangeSelector selector = RangeSelectorLower);
+  float GetFloatValue(RangeSelector selector = RangeSelectorLower) const;
   void SetIntInterval(int iInterval);
   void SetFloatInterval(float fInterval);
   void SetType(int iType) { m_iType = iType; };
@@ -87,25 +96,30 @@ protected:
   /*! \brief Get the current position of the slider as a proportion
    \return slider position in the range [0,1]
    */
-  float GetProportion() const;
+  float GetProportion(RangeSelector selector = RangeSelectorLower) const;
   
   /*! \brief Send a click message (and/or action) to the app in response to a slider move
    */
   void SendClick();
 
   CGUITexture m_guiBackground;
-  CGUITexture m_guiMid;
-  CGUITexture m_guiMidFocus;
+  CGUITexture m_guiSelectorLower;
+  CGUITexture m_guiSelectorUpper;
+  CGUITexture m_guiSelectorLowerFocus;
+  CGUITexture m_guiSelectorUpperFocus;
   int m_iType;
 
-  int m_iPercent;
+  bool m_rangeSelection;
+  RangeSelector m_currentSelector;
+
+  int m_percentValues[2];
 
-  int m_iValue;
+  int m_intValues[2];
   int m_iStart;
   int m_iInterval;
   int m_iEnd;
 
-  float m_fValue;
+  float m_floatValues[2];
   float m_fStart;
   float m_fInterval;
   float m_fEnd;
index 7028aac..26d28ae 100644 (file)
@@ -49,7 +49,7 @@ CGUIStaticItem::CGUIStaticItem(const TiXmlElement *item, int parentID) : CFileIt
     CGUIControlFactory::GetActions(item, "onclick", m_clickActions);
     SetLabel(label.GetLabel(parentID));
     SetLabel2(label2.GetLabel(parentID));
-    SetThumbnailImage(thumb.GetLabel(parentID, true));
+    SetArt("thumb", thumb.GetLabel(parentID, true));
     SetIconImage(icon.GetLabel(parentID, true));
     if (!label.IsConstant())  m_info.push_back(make_pair(label, "label"));
     if (!label2.IsConstant()) m_info.push_back(make_pair(label2, "label2"));
@@ -82,7 +82,7 @@ CGUIStaticItem::CGUIStaticItem(const TiXmlElement *item, int parentID) : CFileIt
     SetLabel(CGUIInfoLabel::GetLabel(label, parentID));
     SetPath(item->FirstChild()->Value());
     SetLabel2(CGUIInfoLabel::GetLabel(label2, parentID));
-    SetThumbnailImage(CGUIInfoLabel::GetLabel(thumb, parentID, true));
+    SetArt("thumb", CGUIInfoLabel::GetLabel(thumb, parentID, true));
     SetIconImage(CGUIInfoLabel::GetLabel(icon, parentID, true));
     m_iprogramCount = id ? atoi(id) : 0;
   }
@@ -101,7 +101,7 @@ void CGUIStaticItem::UpdateProperties(int contextWindow)
     else if (name.Equals("label2"))
       SetLabel2(value);
     else if (name.Equals("thumb"))
-      SetThumbnailImage(value);
+      SetArt("thumb", value);
     else if (name.Equals("icon"))
       SetIconImage(value);
     else
index a82e00d..58a6349 100644 (file)
@@ -53,7 +53,6 @@ CGUIWindow::CGUIWindow(int id, const CStdString &xmlFile)
 {
   SetID(id);
   SetProperty("xmlfile", xmlFile);
-  m_idRange.push_back(id);
   m_lastControlID = 0;
   m_overlayState = OVERLAY_STATE_PARENT_WINDOW;   // Use parent or previous window's state
   m_isDialog = false;
@@ -1063,6 +1062,13 @@ void CGUIWindow::ClearBackground()
     g_graphicsContext.Clear(color);
 }
 
+void CGUIWindow::SetID(int id)
+{
+  CGUIControlGroup::SetID(id);
+  m_idRange.clear();
+  m_idRange.push_back(id);
+}
+
 bool CGUIWindow::HasID(int controlID) const
 {
   for (std::vector<int>::const_iterator it = m_idRange.begin(); it != m_idRange.end() ; it++)
index 044f6a4..1576d32 100644 (file)
@@ -125,6 +125,7 @@ public:
   virtual bool OnMessage(CGUIMessage& message);
 
   bool ControlGroupHasFocus(int groupID, int controlID);
+  virtual void SetID(int id);
   virtual bool HasID(int controlID) const;
   const std::vector<int>& GetIDRange() const { return m_idRange; };
   int GetPreviousWindow() { return m_previousWindow; };
index 98634de..32c3dfd 100644 (file)
 #define ACTION_SUBTITLE_VSHIFT_DOWN   231 // shift down subtitles in DVDPlayer
 #define ACTION_SUBTITLE_ALIGN         232 // toggle vertical alignment of subtitles
 
+#define ACTION_FILTER                 233
+
 // Window ID defines to make the code a bit more readable
 #define WINDOW_INVALID                     9999
 #define WINDOW_HOME                       10000
 #define WINDOW_DIALOG_PROFILE_SETTINGS    10130
 #define WINDOW_DIALOG_LOCK_SETTINGS       10131
 #define WINDOW_DIALOG_CONTENT_SETTINGS    10132
-#define WINDOW_DIALOG_VIDEO_SCAN          10133
 #define WINDOW_DIALOG_FAVOURITES          10134
 #define WINDOW_DIALOG_SONG_INFO           10135
 #define WINDOW_DIALOG_SMART_PLAYLIST_EDITOR 10136
 #define WINDOW_DIALOG_PERIPHERAL_MANAGER  10149
 #define WINDOW_DIALOG_PERIPHERAL_SETTINGS 10150
 #define WINDOW_DIALOG_EXT_PROGRESS        10151
+#define WINDOW_DIALOG_MEDIA_FILTER        10152
 
 #define WINDOW_MUSIC_PLAYLIST             10500
 #define WINDOW_MUSIC_FILES                10501
index 35d0c1a..7ee0c23 100644 (file)
@@ -70,11 +70,13 @@ void CBaseTexture::Allocate(unsigned int width, unsigned int height, unsigned in
     while (GetPitch() < g_Windowing.GetMinDXTPitch())
       m_textureWidth += GetBlockSize();
 
+#if !defined(TARGET_RASPBERRY_PI)
   if (!g_Windowing.SupportsNPOT((m_format & XB_FMT_DXT_MASK) != 0))
   {
     m_textureWidth = PadPow2(m_textureWidth);
     m_textureHeight = PadPow2(m_textureHeight);
   }
+#endif
   if (m_format & XB_FMT_DXT_MASK)
   { // DXT textures must be a multiple of 4 in width and height
     m_textureWidth = ((m_textureWidth + 3) / 4) * 4;
@@ -249,12 +251,32 @@ bool CBaseTexture::LoadFromFileInternal(const CStdString& texturePath, unsigned
         if (autoRotate && omx_image.GetOrientation())
           m_orientation = omx_image.GetOrientation() - 1;
 
-        if(omx_image.GetDecodedData())
+        if(m_textureWidth != omx_image.GetDecodedWidth() || m_textureHeight != omx_image.GetDecodedHeight())
+        {
+          unsigned int imagePitch = GetPitch(m_imageWidth);
+          unsigned int imageRows = GetRows(m_imageHeight);
+          unsigned int texturePitch = GetPitch(m_textureWidth);
+          unsigned int textureRows = GetRows(m_textureHeight);
+          unsigned int blockSize = GetBlockSize();
+
+          unsigned char *src = omx_image.GetDecodedData();
+          unsigned char *dst = m_pixels;
+          for (unsigned int y = 0; y < imageRows; y++)
+          {
+            memcpy(dst, src, imagePitch);
+            src += imagePitch;
+            dst += texturePitch;
+          }
+        }
+        else
         {
-          int size = ( ( GetPitch() * GetRows() ) > omx_image.GetDecodedSize() ) ?
-                           omx_image.GetDecodedSize() : ( GetPitch() * GetRows() );
+          if(omx_image.GetDecodedData())
+          {
+            int size = ( ( GetPitch() * GetRows() ) > omx_image.GetDecodedSize() ) ?
+                             omx_image.GetDecodedSize() : ( GetPitch() * GetRows() );
 
-          memcpy(m_pixels, (unsigned char *)omx_image.GetDecodedData(), size);
+            memcpy(m_pixels, (unsigned char *)omx_image.GetDecodedData(), size);
+          }
         }
 
         omx_image.Close();
index 5a23ddd..2b29a1a 100644 (file)
@@ -189,6 +189,7 @@ static const ActionMapping actions[] =
         {"jumpsms7"          , ACTION_JUMP_SMS7},
         {"jumpsms8"          , ACTION_JUMP_SMS8},
         {"jumpsms9"          , ACTION_JUMP_SMS9},
+        {"filter"            , ACTION_FILTER},
         {"filterclear"       , ACTION_FILTER_CLEAR},
         {"filtersms2"        , ACTION_FILTER_SMS2},
         {"filtersms3"        , ACTION_FILTER_SMS3},
@@ -298,7 +299,6 @@ static const ActionMapping windows[] =
         {"profilesettings"          , WINDOW_DIALOG_PROFILE_SETTINGS},
         {"locksettings"             , WINDOW_DIALOG_LOCK_SETTINGS},
         {"contentsettings"          , WINDOW_DIALOG_CONTENT_SETTINGS},
-        {"videoscan"                , WINDOW_DIALOG_VIDEO_SCAN},
         {"songinformation"          , WINDOW_DIALOG_SONG_INFO},
         {"smartplaylisteditor"      , WINDOW_DIALOG_SMART_PLAYLIST_EDITOR},
         {"smartplaylistrule"        , WINDOW_DIALOG_SMART_PLAYLIST_RULE},
@@ -336,7 +336,8 @@ static const ActionMapping windows[] =
         {"startup"                  , WINDOW_STARTUP_ANIM},
         {"peripherals"              , WINDOW_DIALOG_PERIPHERAL_MANAGER},
         {"peripheralsettings"       , WINDOW_DIALOG_PERIPHERAL_SETTINGS},
-        {"extendedprogressdialog"   , WINDOW_DIALOG_EXT_PROGRESS}};
+        {"extendedprogressdialog"   , WINDOW_DIALOG_EXT_PROGRESS},
+        {"mediafilter"              , WINDOW_DIALOG_MEDIA_FILTER}};
 
 static const ActionMapping mousecommands[] =
 {
index 5907113..16f46de 100644 (file)
@@ -113,7 +113,10 @@ void CAnnouncementManager::Announce(AnnouncementFlag flag, const char *sender, c
       }
     }
 
-    CVideoDatabase::VideoContentTypeToString((VIDEODB_CONTENT_TYPE)item->GetVideoContentType(), type);
+    if (!item->GetVideoInfoTag()->m_type.empty())
+      type = item->GetVideoInfoTag()->m_type;
+    else
+      CVideoDatabase::VideoContentTypeToString((VIDEODB_CONTENT_TYPE)item->GetVideoContentType(), type);
 
     if (id <= 0)
     {
index ac4e7b2..882aaa1 100644 (file)
@@ -33,7 +33,6 @@
 #include "dialogs/GUIDialogKaiToast.h"
 #include "dialogs/GUIDialogNumeric.h"
 #include "dialogs/GUIDialogProgress.h"
-#include "video/dialogs/GUIDialogVideoScan.h"
 #include "dialogs/GUIDialogYesNo.h"
 #include "GUIUserMessages.h"
 #include "windows/GUIWindowLoginScreen.h"
@@ -772,13 +771,7 @@ int CBuiltins::Execute(const CStdString& execString)
     else if( parameter.Equals("record") )
     {
       if( g_application.IsPlaying() && g_application.m_pPlayer && g_application.m_pPlayer->CanRecord())
-      {
-#ifdef HAS_WEB_SERVER_BROADCAST
-        if (m_pXbmcHttp && g_settings.m_HttpApiBroadcastLevel>=1)
-          CApplicationMessenger::Get().HttpApi(g_application.m_pPlayer->IsRecording()?"broadcastlevel; RecordStopping;1":"broadcastlevel; RecordStarting;1");
-#endif
         g_application.m_pPlayer->Record(!g_application.m_pPlayer->IsRecording());
-      }
     }
     else if (parameter.Left(9).Equals("partymode"))
     {
@@ -1255,14 +1248,7 @@ int CBuiltins::Execute(const CStdString& execString)
       g_application.StopMusicScan();
 
     if (g_application.IsVideoScanning())
-    {
       g_application.StopVideoScan();
-      CGUIDialogVideoScan *videoScan = (CGUIDialogVideoScan *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
-      if (videoScan)
-      {
-        videoScan->Close(true);
-      }
-    }
 
     ADDON::CAddonMgr::Get().StopServices(true);
 
diff --git a/xbmc/interfaces/http-api/HttpApi.cpp b/xbmc/interfaces/http-api/HttpApi.cpp
deleted file mode 100644 (file)
index 16ad9e9..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-#include "HttpApi.h"
-#include "utils/log.h"
-#include "XBMChttp.h"
-#include "Application.h"
-#include "ApplicationMessenger.h"
-
-#define MAX_PARAS 20
-
-CStdString CHttpApi::WebMethodCall(CStdString &command, CStdString &parameter)
-{
-  CStdString response = MethodCall(command, parameter);
-  response.Format("%s%s%s", m_pXbmcHttp->incWebHeader ? "<html>\n" : "", response.c_str(), m_pXbmcHttp->incWebFooter ? "\n</html>\n" : "");
-  return response;
-}
-
-CStdString CHttpApi::MethodCall(CStdString &command, CStdString &parameter)
-{
-  if (parameter.IsEmpty())
-    checkForFunctionTypeParas(command, parameter);
-
-  int cnt=0;
-
-  if (!parameter.IsEmpty())
-    CApplicationMessenger::Get().HttpApi(command + "; " + parameter, true);
-  else
-    CApplicationMessenger::Get().HttpApi(command, true);
-
-  //wait for response - max 20s
-  Sleep(0);
-  CStdString response = CApplicationMessenger::Get().GetResponse();
-
-  while (response=="[No response yet]" && cnt++<200 && !g_application.m_bStop)
-  {
-    response=CApplicationMessenger::Get().GetResponse();
-    CLog::Log(LOGDEBUG, "HttpApi: waiting %d", cnt);
-    Sleep(100);
-  }
-
-  return m_pXbmcHttp->userHeader + response + m_pXbmcHttp->userFooter;
-}
-
-bool CHttpApi::checkForFunctionTypeParas(CStdString &cmd, CStdString &paras)
-{
-  int open, close;
-  open = cmd.Find("(");
-  if (open>0)
-  {
-    close=cmd.length();
-    while (close>open && cmd.Mid(close,1)!=")")
-      close--;
-    if (close>open)
-    {
-      paras = cmd.Mid(open + 1, close - open - 1);
-      cmd = cmd.Left(open);
-      return (close-open)>1;
-    }
-  }
-  return false;
-}
-
-int CHttpApi::xbmcCommand(const CStdString &parameter)
-{
-  return m_pXbmcHttp->xbmcCommand(parameter);
-}
diff --git a/xbmc/interfaces/http-api/HttpApi.h b/xbmc/interfaces/http-api/HttpApi.h
deleted file mode 100644 (file)
index 39576c5..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#pragma once
-
-#include "utils/StdString.h"
-
-class CHttpApi
-{
-public:
-  static CStdString WebMethodCall(CStdString &command, CStdString &parameter);
-  static CStdString MethodCall(CStdString &command, CStdString &parameter);
-  static bool checkForFunctionTypeParas(CStdString &cmd, CStdString &paras);
-  static int xbmcCommand(const CStdString &parameter);
-};
diff --git a/xbmc/interfaces/http-api/Makefile b/xbmc/interfaces/http-api/Makefile
deleted file mode 100644 (file)
index d365161..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-SRCS=HttpApi.cpp XBMChttp.cpp
-
-LIB=http-api.a
-
-include ../../../Makefile.include
--include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS)))
diff --git a/xbmc/interfaces/http-api/XBMCConfiguration.cpp b/xbmc/interfaces/http-api/XBMCConfiguration.cpp
deleted file mode 100644 (file)
index 302bdb6..0000000
+++ /dev/null
@@ -1,696 +0,0 @@
-/*
- *      Copyright (C) 2005-2012 Team XBMC
- *      http://www.xbmc.org
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with XBMC; see the file COPYING.  If not, see
- *  <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "Settings.h"
-#include "XBMCConfiguration.h"
-#include "Util.h"
-#include "URL.h"
-
-CXbmcConfiguration::CXbmcConfiguration()
-{
-       xbmcCfgLoaded = false;
-}
-
-CXbmcConfiguration::~CXbmcConfiguration()
-{
-
-}
-
-/*
- * Load sources.xml
- */
-int CXbmcConfiguration::Load()
-{
-       if (!xbmcCfgLoaded)
-       {
-    if (!xbmcCfg.LoadFile(g_settings.GetSourcesFile())) return -1;
-               xbmcCfgLoaded = true;
-       }
-       return 0;
-}
-
-/*
- * Retrieve size of bookmark type (type)
- * var type has to be set to a bookmark name (like video, music ...)
- */
-int CXbmcConfiguration::BookmarkSize( int eid, webs_t wp, CStdString& response, int argc, char_t **argv)
-{
-       char_t *type = NULL;
-
-       // asp function is called within a script, get arguments
-       if (ejArgs(argc, argv, T((char*)"%s"),&type) < 1)
-       {
-           if (eid!=-1) websError(wp, 500, T((char*)"Insufficient args\n"));
-              else response="Error:Insufficient args";
-               return -1;
-       }
-
-  VECSOURCES *pShares = g_settings.GetSourcesFromType(type);
-  if (pShares)
-  {
-    char buffer[10];
-    sprintf(buffer,"%i",pShares->size());
-
-    if (eid!=-1)
-      ejSetResult( eid, buffer);
-    else
-    {
-      CStdString tmp;
-      tmp.Format("%i", pShares->size());
-      response="" + tmp;
-    }
-
-    return 0;
-  }
-
-  if (eid!=-1) websError(wp, 500, T((char*)"Bookmark type does not exist\n")); 
-  else response="Error:Bookmark type does not exist";
-  return -1;
-
-/*     // load sources.xml, write a messages if file could not be loaded
-       if (Load() == -1)
-       {
-    eid!=-1 ? websError(wp, 500, T("Could not load sources.xml\n")):
-              response="Error:Could not load sources.xml";
-               return -1;
-       }
-
-       // return number of
-       TiXmlElement *pRootElement = xbmcCfg.RootElement();
-       TiXmlNode *pNode = NULL;
-
-       pNode = pRootElement->FirstChild(type);
-
-       if (!pNode)
-       {
-    eid!=-1 ? websError(wp, 500, T("Bookmark type does not exist\n")):
-              response="Error:Bookmark type does not exist";
-               return -1;
-       }
-
-       TiXmlNode *pIt = NULL;
-       char buffer[10];
-       int counter = 0;
-
-       while(pIt = pNode->IterateChildren("bookmark", pIt))    counter++;
-  if (eid!=-1) 
-    ejSetResult( eid, itoa(counter, buffer, 10));
-  else
-  {
-    CStdString tmp;
-    tmp.Format("%s", itoa(counter, buffer, 10));
-    response="" + tmp;
-  }
-       return 0;*/
-}
-
-/*
- * Get bookmark (type, parameter, id)
- * var type has to be set to a bookmark name (like video, music ...)
- * var paramater = "name" or "path"
- * var id = position of bookmark
- */
-int CXbmcConfiguration::GetBookmark( int eid, webs_t wp, CStdString& response, int argc, char_t **argv)
-{
-       char_t  *parameter, *type, *id = NULL;
-
-       // asp function is called within a script, get arguments
-       if (ejArgs(argc, argv, T((char*)"%s %s %s"), &type, &parameter, &id) < 3) {
-          if (eid!=-1) websError(wp, 500, T((char*)"Insufficient args\n"));
-            else response="Error:Insufficient args";
-               return -1;
-       }
-
-  int nr = 0;
-  try { nr = atoi(id); }
-  catch (...)
-  {
-    if (eid!=-1) websError(wp, 500, T((char*)"Id is not a number\n"));
-      else response="Error:Id is not a number";
-    return -1;
-  }
-
-  VECSOURCES* pShares = g_settings.GetSourcesFromType(type);
-  if (!pShares)
-  {
-    if (eid!=-1) websError(wp, 500, T((char*)"Bookmark type does not exist\n"));
-      else response="Error:Bookmark type does not exist";
-    return -1;
-  }
-  if (nr > 0 && nr <= (int)pShares->size())
-  {
-    const CMediaSource& share = (*pShares)[nr-1];
-    if (CStdString(parameter).Equals("path"))
-    {
-      if (eid!=-1)
-        ejSetResult( eid, const_cast<char*>(share.strPath.c_str()));
-      else
-      {
-        CStdString tmp;
-        tmp.Format("%s",share.strPath);
-        response="" + tmp;
-      }
-    }
-    else if (CStdString(parameter).Equals("name"))
-    {
-      if (eid!=-1)
-        ejSetResult( eid, const_cast<char*>(share.strName.c_str()));
-      else
-      {
-        CStdString tmp;
-        tmp.Format("%s",share.strName);
-        response="" + tmp;
-      }
-    }
-    else
-    {
-      if (eid!=-1) websError(wp, 500, T((char*)"Parameter not known\n")); 
-        else response="Error:Parameter not known";
-    }
-    return 0;
-  }
-
-  if (eid!=-1) websError(wp, 500, T((char*)"Position not found\n"));
-    else response="Error:Position not found";
-  return -1;
-
-
-       /*// load sources.xml, write a messages if file could not be loaded
-       if (Load() == -1)
-       {
-    eid!=-1 ? websError(wp, 500, T("Could not load sources.xml\n")):
-              response="Error:Could not load sources.xml";
-               return -1;
-       }
-
-       // Return bookmark of
-       TiXmlElement *pRootElement = xbmcCfg.RootElement();
-       TiXmlNode *pNode = NULL;
-       TiXmlNode *pIt = NULL;
-
-       int nr = 0;
-       try { nr = atoi(id); }
-       catch (...)
-       {
-    eid!=-1 ? websError(wp, 500, T("Id is not a number\n")):
-              response="Error:Id is not a number";
-               return -1;
-       }
-
-       pNode = pRootElement->FirstChild(type);
-
-       // if valid bookmark, find child at pos (id)
-       if (pNode)
-               for (int i = 0; i < nr; i++) pIt = pNode->IterateChildren("bookmark", pIt);
-       if (pIt)
-       {
-               // user wants the name of the bookmark.
-               if (!strcmp(parameter, "name"))
-               {
-                       if (pIt->FirstChild("name"))
-                       {
-        if (eid!=-1)
-          ejSetResult( eid, (char*)pIt->FirstChild("name")->FirstChild()->Value());
-        else
-        {
-          CStdString tmp;
-          tmp.Format("%s",(char*)pIt->FirstChild("name")->FirstChild()->Value());
-          response="" + tmp;
-        }
-                       }
-               }
-               // user wants the path of the bookmark.
-               else if (!strcmp(parameter, "path"))
-               {
-                       if (pIt->FirstChild("path"))
-                       {
-        if (eid!=-1)
-          ejSetResult( eid, (char*)pIt->FirstChild("path")->FirstChild()->Value());
-        else
-        {
-          CStdString tmp;
-          tmp.Format("%s",(char*)pIt->FirstChild("path")->FirstChild()->Value());
-          response="" + tmp ;
-        }
-                       }
-               }
-    else
-      eid!=-1 ? websError(wp, 500, T("Parameter not known\n")):
-                response="Error:Parameter not known";
-       }
-  else
-  {
-    eid!=-1 ? websError(wp, 500, T("Position not found\n")):
-              response="Error:Position not found";
-    return -1;
-  }
-       return 0;*/
-}
-
-/*
- * Add a new bookmark (type, name, path)
- * Add a new bookmark (type, name, path, position)
- * Add a new bookmark (type, name, path, thumbnail, position)
- * var type has to be set to a bookmark name (like video, music ...)
- * var name = share name
- * var path = path
- * var thumbnail = thumbnail image (not required)
- * var postition = position where bookmark should be placed (not required)
- */
-int CXbmcConfiguration::AddBookmark( int eid, webs_t wp, CStdString& response, int argc, char_t **argv)
-{
-  char_t    *type, *name, *path, *thumbnail = NULL, *position = NULL;
-  int numParas;
-
-  // asp function is called within a script, get arguments
-  numParas=ejArgs(argc, argv, T((char*)"%s %s %s %s %s"), &type, &name, &path, &thumbnail, &position);
-  if ( numParas< 3) 
-  {
-    if (eid!=-1)
-       websError(wp, 500, T((char*)"Insufficient args\n use: function(command, type, name, path, [thumbnail], [position])"));
-    else
-       response="Error:Insufficient args, use: function(command, type, name, path, [thumbnail], [position])";
-    return -1;
-  }
-
-  CMediaSource share;
-  share.strName = name;
-  if (numParas==4)
-  {
-         position=thumbnail;
-         thumbnail=NULL;
-  }
-  if (numParas==5)
-    share.m_strThumbnailImage = thumbnail;
-  CStdString strPath=path;
-  CUtil::AddSlashAtEnd(strPath);
-
-  share.strPath = strPath;
-  share.vecPaths.push_back(strPath.c_str());
-  g_settings.AddShare(type,share);
-
-  return 0;
-/*
-       // load sources.xml, write a messages if file could not be loaded
-       if (Load() == -1)
-       {
-    eid!=-1 ? websError(wp, 500, T("Could not load sources.xml\n")):
-              response="Error:Could not load sources.xml";
-    return -1;
-       }
-
-       TiXmlElement *pRootElement = xbmcCfg.RootElement();
-       TiXmlNode *pNode = NULL;
-       TiXmlNode *pIt = NULL;
-
-       pNode = pRootElement->FirstChild(type);
-       
-       // create a new Element
-       TiXmlText xmlName(name);
-       TiXmlText xmlPath(path);
-       TiXmlElement eName("name");
-       TiXmlElement ePath("path");
-       eName.InsertEndChild(xmlName);
-       ePath.InsertEndChild(xmlPath);
-
-       TiXmlElement bookmark("bookmark");
-       bookmark.InsertEndChild(eName);
-       bookmark.InsertEndChild(ePath);
-
-       //if postion == NULL add bookmark at end of the other bookmarks
-       if (position)
-       {
-               //isert after postion 'position'
-               int nr = 0;
-               try { nr = atoi(position); }
-               catch (...)
-               {
-      eid!=-1 ? websError(wp, 500, T("position is not a number\n")):
-                response="Error:position is not a number";
-                       return -1;
-               }
-
-               // find bookmark at position
-               if (pNode)
-                       for (int i = 0; i < nr; i++) pIt = pNode->IterateChildren("bookmark", pIt);
-               if (pIt)
-      pNode->ToElement()->InsertAfterChild(pIt, bookmark);
-    else
-    {
-      eid!=-1 ? websError(wp, 500, T("Position not found\n")):
-                response="Error:Position not found";
-      return -1;
-    }
-       }
-       else
-       {
-               pNode->ToElement()->InsertEndChild(bookmark);
-       }
-       return 0;*/
-}
-
-/*
- * Save bookmark (type, name, path, position)
- * var type has to be set to a bookmark name (like video, music ...)
- * var name = new share name
- * var path = new path
- * var postition = position where bookmark should be placed
- */
-int CXbmcConfiguration::SaveBookmark( int eid, webs_t wp, CStdString& response, int argc, char_t **argv)
-{
-       char_t  *type, *name, *path, *position = NULL;
-
-       // asp function is called within a script, get arguments
-       if (ejArgs(argc, argv, T((char*)"%s %s %s %s"), &type, &name, &path, &position) < 4) {
-        if (eid!=-1) websError(wp, 500, T((char*)"Insufficient args\n use: function(command, type, name, path, postion)"));
-          else response="Error:Insufficient args, use: function(command, type, name, path, postion)";
-               return -1;
-       }
-  VECSOURCES* pShares = g_settings.GetSourcesFromType(type);
-  int nr = 0;
-       try { nr = atoi(position); }
-       catch (...)
-       {
-          if (eid!=-1) websError(wp, 500, T((char*)"Id is not a number\n"));
-              else response="Error:Id is not a number";
-         return -1;
-       }
-
-  if (nr > 0 && nr <= (int)pShares->size()) // update share
-  {
-    const CMediaSource& share = (*pShares)[nr-1];
-    g_settings.UpdateSource(type, share.strName, "path", path);
-    g_settings.UpdateSource(type, share.strName, "name", name);
-    g_settings.SaveSources();
-    return 0;
-  }
-  
-  if (eid!=-1) websError(wp, 500, T((char*)"Position not found\n"));
-    else response="Error:Position not found";
-  return -1;
-
-
-/*     // load sources.xml, write a messages if file could not be loaded
-       if (Load() == -1)
-       {
-    eid!=-1 ? websError(wp, 500, T("Could not load sources.xml\n")):
-              response="Error:Could not load sources.xml";
-    return -1;
-       }
-
-       TiXmlElement *pRootElement = xbmcCfg.RootElement();
-       TiXmlNode *pNode = NULL;
-       TiXmlNode *pIt = NULL;
-
-       pNode = pRootElement->FirstChild(type);
-
-       int nr = 0;
-       try { nr = atoi(position); }
-       catch (...)
-       {
-    eid!=-1 ? websError(wp, 500, T("Id is not a number\n")):
-              response="Error:Id is not a number";
-               return -1;
-       }
-
-       // find bookmark at position
-       if (pNode)
-               for (int i = 0; i < nr; i++) pIt = pNode->IterateChildren("bookmark", pIt);
-       if (pIt)
-       {
-               pIt->FirstChild("name")->FirstChild()->SetValue(name);
-               pIt->FirstChild("path")->FirstChild()->SetValue(path);
-       }
-  else
-  {
-    eid!=-1 ? websError(wp, 500, T("Position not found\n")):
-              response="Error:Position not found";
-    return -1;
-  }*/
-  
-       return 0;
-}
-
-/*
- * Remove bookmark (type, name, path, position)
- * var type has to be set to a bookmark name (like video, music ...)
- * var postition = bookmark at position that should be removed
- */
-int CXbmcConfiguration::RemoveBookmark( int eid, webs_t wp, CStdString& response, int argc, char_t **argv)
-{
-       char_t  *type, *position = NULL;
-
-       // asp function is called within a script, get arguments
-       if (ejArgs(argc, argv, T((char*)"%s %s"), &type, &position) < 2) {
-          if(eid!=-1)
-            websError(wp, 500, T((char*)"Insufficient args\n use: function(type, position)"));
-          else
-            response="Error:Insufficient args, use: function(type, position)";
-         return -1;
-       }
-
-       int nr = 0;
-       try { nr = atoi(position); }
-       catch (...)
-       {
-          if (eid!=-1) websError(wp, 500, T((char*)"Id is not a number\n"));
-            else response="Error:position is not a number";
-         return -1;
-       }
-
-  VECSOURCES* pShares = g_settings.GetSourcesFromType(type);
-  const CMediaSource& share = (*pShares)[nr-1];
-  if (g_settings.DeleteSource(type,share.strName,share.strPath))
-    return 0;
-
-  if (eid!=-1) websError(wp, 500, T((char*)"Position not found\n"));
-    else response="Error:Position not found";
-  return -1;
-  /*
-       // load sources.xml, write a messages if file could not be loaded
-       if (Load() == -1)
-       {
-    eid!=-1 ? websError(wp, 500, T("Could not load sources.xml\n")):
-              response="Error:Could not load sources.xml";
-    return -1;
-       }
-
-       TiXmlElement *pRootElement = xbmcCfg.RootElement();
-       TiXmlNode *pNode = NULL;
-       TiXmlNode *pIt = NULL;
-
-       pNode = pRootElement->FirstChild(type);
-
-       int nr = 0;
-       try { nr = atoi(position); }
-       catch (...)
-       {
-    eid!=-1 ? websError(wp, 500, T("Id is not a number\n")):
-              response="Error:position is not a number";
-               return -1;
-       }
-
-       // find bookmark at position
-       if (pNode)
-               for (int i = 0; i < nr; i++) pIt = pNode->IterateChildren("bookmark", pIt);
-
-       if (pIt)
-    pNode->RemoveChild(pIt);
-  else
-  {
-    eid!=-1 ? websError(wp, 500, T("Position not found\n")):
-              response="Error:Position not found";
-    return -1;
-  }
-       return 0;*/
-}
-
-/*
- * Save configuration to a file (filename)
- * var filename = filename to which the configuration has to be written
- * is only a filename is specified and no directory we save it in the same dir that
- * our executable is in.
- */
-int CXbmcConfiguration::SaveConfiguration( int eid, webs_t wp, CStdString& response, int argc, char_t **argv)
-{
-  if (eid!=-1) websError(wp, 500, T((char*)"Deprecated\n"));
-    else response="Error:Functino is deprecated";
-  return -1;
-
-  char_t       *filename = NULL;
-
-       // asp function is called within a script, get arguments
-       if (ejArgs(argc, argv, T((char*)"%s"), &filename) < 1) {
-           if (eid!=-1) websError(wp, 500, T((char*)"Insufficient args\n use: function(filename)"));
-              else response="Error:Insufficient args, use: function(filename)";
-          return -1;
-       }
-
-       // load sources.xml, write a messages if file could not be loaded
-       if (Load() == -1) 
-       {
-          if (eid!=-1) websError(wp, 500, T((char*)"Could not load sources.xml\n"));
-              else response="Error:Could not load sources.xml";
-          return -1;
-       }
-
-       // Save configuration to file
-       CStdString strPath(filename);
-  if (!CURL::IsFullPath(strPath))
-       {
-               // only filename specified, so use our homedir as base.
-    strPath = CUtil::AddFileToFolder("special://home/", filename);
-       }
-
-  if (!xbmcCfg.SaveFile(strPath))
-       {
-          if (eid!=-1) websError(wp, 500, T((char*)"Could not save to file\n"));
-            else response="Error:Could not save to file";
-         return -1;
-       }
-       return 0;
-}
-
-/*
- * Get value from configuration (name)
- * var name = option name
- */
-int CXbmcConfiguration::GetOption( int eid, webs_t wp, CStdString& response, int argc, char_t **argv)
-{
-  if (eid!=-1) websError(wp, 500, T((char*)"Deprecated\n"));
-    else response="Error:Functino is deprecated";
-return -1;
-
- /* 
-  char_t* name = NULL;
-
-       // asp function is called within a script, get arguments
-       if (ejArgs(argc, argv, T("%s"), &name) < 1) {
-    eid!=-1 ? websError(wp, 500, T("Insufficient args\n")):
-              response="Error:Insufficient args";
-               return -1;
-       }
-
-       // load sources.xml, write a messages if file could not be loaded
-       if (Load() == -1)
-       {
-    eid!=-1 ? websError(wp, 500, T("Could not load sources.xml\n")):
-              response="Error:Could not load sources.xml";;
-               return -1;
-       }
-
-       // get first option from xml file
-       // we have to check if there arent any other childs in this element
-       TiXmlElement *pRootElement = xbmcCfg.RootElement();
-       TiXmlElement *pElement = NULL;
-       pElement = pRootElement->FirstChildElement(name);
-
-       if (pElement)
-       {
-               if (pElement->FirstChild() && pElement->FirstChild()->FirstChild() == NULL)
-               {
-                       char* value = (char*)pElement->FirstChild()->Value();
-                       if (value) 
-        if (eid!=-1)
-          ejSetResult(eid, value);
-        else
-        {
-          CStdString tmp;
-          tmp.Format("%s",value);
-          response="" + tmp;
-        }
-               }
-               // option exist, but no value is set. Default is "-"
-               else 
-                {
-                   if (eid!=-1) 
-                      ejSetResult(eid, "-");
-                   else
-                      response="";
-                }
-       }
-       else
-       {
-               // option not found in xml file
-               // set value to "-"
-                if (eid!=-1) 
-                   ejSetResult(eid, "");
-                else
-                   response="Error:Not found";
-  }
-       return 0;
-*/
-}
-
-/*
- * Set value for option in configuration (name, value)
- * var name = option name
- * var value = new value
- */
-int CXbmcConfiguration::SetOption( int eid, webs_t wp, CStdString& response, int argc, char_t **argv)
-{
-  if (eid!=-1) websError(wp, 500, T((char*)"Deprecated\n"));
-    else response="Error:Functino is deprecated";
-
-  return -1;
-}
-
-/*
- * Check if option is a valid one in sources.xml
- */
-bool CXbmcConfiguration::IsValidOption(char* option)
-{
-       if (!strcmp("subtitles", option)) return true;
-       if (!strcmp("thumbnails", option)) return true;
-       if (!strcmp("shortcuts", option)) return true;
-       if (!strcmp("albums", option)) return true;
-       if (!strcmp("recordings", option)) return true;
-       if (!strcmp("screenshots", option)) return true;
-       return false;
-}
-
-bool XbmcWebConfigInit()
-{
-  if (!pXbmcWebConfig) {
-    pXbmcWebConfig = new CXbmcConfiguration();
-       return true;
-  }
-  else
-       return false;
-}
-
-void XbmcWebConfigRelease()
-{
-  if (pXbmcWebConfig)
-  {
-       delete pXbmcWebConfig;
-       pXbmcWebConfig=NULL;
-  }
-}
-
-int XbmcWebsHttpAPIConfigBookmarkSize(CStdString& response, int argc, char_t **argv) { return pXbmcWebConfig ? pXbmcWebConfig->BookmarkSize(-1, NULL, response, argc, argv) : -1; }
-int XbmcWebsHttpAPIConfigGetBookmark(CStdString& response, int argc, char_t **argv) { return pXbmcWebConfig ? pXbmcWebConfig->GetBookmark(-1, NULL, response, argc, argv) : -1; }
-int XbmcWebsHttpAPIConfigAddBookmark(CStdString& response, int argc, char_t **argv) { return pXbmcWebConfig ? pXbmcWebConfig->AddBookmark(-1, NULL, response, argc, argv) : -1; }
-int XbmcWebsHttpAPIConfigSaveBookmark(CStdString& response, int argc, char_t **argv) { return pXbmcWebConfig ? pXbmcWebConfig->SaveBookmark(-1, NULL, response, argc, argv) : -1; }
-int XbmcWebsHttpAPIConfigRemoveBookmark(CStdString& response, int argc, char_t **argv) { return pXbmcWebConfig ? pXbmcWebConfig->RemoveBookmark(-1, NULL, response, argc, argv) : -1; }
-int XbmcWebsHttpAPIConfigSaveConfiguration(CStdString& response, int argc, char_t **argv) { return pXbmcWebConfig ? pXbmcWebConfig->SaveConfiguration(-1, NULL, response, argc, argv) : -1; }
-int XbmcWebsHttpAPIConfigGetOption(CStdString& response, int argc, char_t **argv) { return pXbmcWebConfig ? pXbmcWebConfig->GetOption(-1, NULL, response, argc, argv) : -1; }
-int XbmcWebsHttpAPIConfigSetOption(CStdString& response, int argc, char_t **argv) { return pXbmcWebConfig ? pXbmcWebConfig->SetOption(-1, NULL, response, argc, argv) : -1; }
-
diff --git a/xbmc/interfaces/http-api/XBMCConfiguration.h b/xbmc/interfaces/http-api/XBMCConfiguration.h
deleted file mode 100644 (file)
index d37fb35..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#pragma once
-
-#undef min
-#undef max
-#include <algorithm>
-#include "utils/XBMCTinyXML.h"
-
-typedef char char_t;
-typedef struct websRec *webs_t;
-
-class CXbmcConfiguration
-{
-public:
-       CXbmcConfiguration();
-       ~CXbmcConfiguration();
-
-       int             BookmarkSize( int eid, webs_t wp, CStdString& response, int argc, char_t **argv);
-       int             GetBookmark( int eid, webs_t wp, CStdString& response, int argc, char_t **argv);
-       int             AddBookmark( int eid, webs_t wp, CStdString& response, int argc, char_t **argv);
-       int             SaveBookmark( int eid, webs_t wp, CStdString& response, int argc, char_t **argv);
-       int             RemoveBookmark( int eid, webs_t wp, CStdString& response, int argc, char_t **argv);
-       int             SaveConfiguration( int eid, webs_t wp, CStdString& response, int argc, char_t **argv);
-       int             GetOption( int eid, webs_t wp, CStdString& response, int argc, char_t **argv);
-       int             SetOption( int eid, webs_t wp, CStdString& response, int argc, char_t **argv);
-private:
-       int             Load();
-       bool    IsValidOption(char* option);
-
-       CXBMCTinyXML    xbmcCfg;
-       bool    xbmcCfgLoaded;
-};
-
-
-  bool XbmcWebConfigInit();
-  void XbmcWebConfigRelease();
-
-  int XbmcWebsHttpAPIConfigBookmarkSize(CStdString& response, int argc, char_t **argv);
-  int XbmcWebsHttpAPIConfigGetBookmark(CStdString& response, int argc, char_t **argv);
-  int XbmcWebsHttpAPIConfigAddBookmark(CStdString& response, int argc, char_t **argv);
-  int XbmcWebsHttpAPIConfigSaveBookmark(CStdString& response, int argc, char_t **argv);
-  int XbmcWebsHttpAPIConfigRemoveBookmark(CStdString& response, int argc, char_t **argv);
-  int XbmcWebsHttpAPIConfigSaveConfiguration(CStdString& response, int argc, char_t **argv);
-  int XbmcWebsHttpAPIConfigGetOption(CStdString& response, int argc, char_t **argv);
-  int XbmcWebsHttpAPIConfigSetOption(CStdString& response, int argc, char_t **argv);
diff --git a/xbmc/interfaces/http-api/XBMChttp.cpp b/xbmc/interfaces/http-api/XBMChttp.cpp
deleted file mode 100644 (file)
index f01b710..0000000
+++ /dev/null
@@ -1,3159 +0,0 @@
-
-/******************************** Description *********************************/
-
-/*
- *  This module provides an API over HTTP between the web server and XBMC
- *
- *            heavily based on XBMCweb.cpp
- */
-
-/********************************* Includes ***********************************/
-
-#include "threads/SystemClock.h"
-#include "Application.h"
-#include "ApplicationMessenger.h"
-#include "XBMCConfiguration.h"
-#include "XBMChttp.h"
-//#include "includes.h"
-#include "guilib/GUIWindowManager.h"
-
-#include "playlists/PlayListFactory.h"
-#include "Util.h"
-#include "utils/Screenshot.h"
-#include "PlayListPlayer.h"
-#include "playlists/PlayList.h"
-#include "filesystem/CurlFile.h" 
-#include "filesystem/HDDirectory.h" 
-#include "filesystem/CDDADirectory.h"
-#include "filesystem/SpecialProtocol.h"
-#include "video/VideoDatabase.h"
-#include "guilib/GUIButtonControl.h"
-#include "GUIInfoManager.h"
-#include "music/tags/MusicInfoTagLoaderFactory.h"
-#include "music/infoscanner/MusicInfoScraper.h"
-#include "addons/AddonManager.h"
-#include "music/MusicDatabase.h"
-#include "GUIUserMessages.h"
-#include "pictures/GUIWindowSlideShow.h"
-#include "windows/GUIMediaWindow.h"
-#include "windows/GUIWindowFileManager.h"
-#include "filesystem/Directory.h"
-#include "filesystem/VirtualDirectory.h"
-#include "filesystem/Directory.h"
-#include "music/tags/MusicInfoTag.h"
-#include "pictures/PictureInfoTag.h"
-#include "FileItem.h"
-#include "settings/Settings.h"
-#include "settings/AdvancedSettings.h"
-#include "settings/GUISettings.h"
-#include "filesystem/DirectoryFactory.h"
-#include "filesystem/File.h"
-#include "guilib/LocalizeStrings.h"
-#include "utils/StringUtils.h"
-#include "utils/TimeUtils.h"
-#include "utils/URIUtils.h"
-#include "utils/log.h"
-#include "TextureCache.h"
-#include "ThumbLoader.h"
-#include "URL.h"
-
-#ifdef _WIN32
-extern "C" FILE *fopen_utf8(const char *_Filename, const char *_Mode);
-#else
-#define fopen_utf8 fopen
-#endif
-
-using namespace std;
-using namespace MUSIC_GRABBER;
-using namespace XFILE;
-using namespace PLAYLIST;
-using namespace MUSIC_INFO;
-using namespace ADDON;
-
-#define XML_MAX_INNERTEXT_SIZE 256
-#define MAX_PARAS 20
-#define NO_EID -1
-
-CXbmcHttp* m_pXbmcHttp;
-
-
-CUdpBroadcast::CUdpBroadcast() : CUdpClient()
-{
-  Create();
-}
-
-CUdpBroadcast::~CUdpBroadcast()
-{
-  Destroy();
-}
-
-bool CUdpBroadcast::broadcast(CStdString message, int port)
-{
-  if (port>0)
-    return Broadcast(port, message);
-  else
-    return false;
-}
-
-
-CXbmcHttp::CXbmcHttp()
-{
-  resetTags();
-  CKey temp;
-  key = temp;
-  lastKey = temp;
-  lastThumbFn="";
-  lastPlayingInfo="";
-  lastSlideInfo="";
-  repeatKeyRate=0;
-  MarkTime=0;
-  pUdpBroadcast=NULL;
-  shuttingDown=false;
-  autoGetPictureThumbs=true;
-  tempSkipWebFooterHeader=false;
-}
-
-CXbmcHttp::~CXbmcHttp()
-{
-  if (pUdpBroadcast)
-  {
-    delete pUdpBroadcast;
-    pUdpBroadcast=NULL;
-  }
-  CLog::Log(LOGDEBUG, "xbmcHttp ends");
-}
-
-/*
-** encode
-**
-** base64 encode a stream adding padding and line breaks as per spec.
-*/
-CStdString CXbmcHttp::encodeFileToBase64(const CStdString &inFilename, int linesize )
-{
-  unsigned char in[3];//, out[4];
-  int len, blocksout = 0;
-  CStdString strBase64="";
-
-//  Translation Table as described in RFC1113
-  static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-  CFile file;
-  bool bOutput=false;
-  if (file.Open(inFilename.c_str())) 
-  {
-    while( file.GetPosition() != file.GetLength() ) 
-    {
-      memset(in, 0, sizeof(in));
-      len = file.Read(in, 3);
-      if( len ) 
-      {
-        strBase64 += cb64[ in[0] >> 2 ];
-        strBase64 += cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
-        strBase64 += (unsigned char) (len > 1 ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '=');
-        strBase64 += (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '=');
-        blocksout++;
-      }
-      if(linesize == 0 && file.GetPosition() == file.GetLength())
-        bOutput=true;
-      else if ((linesize > 0) && (blocksout >= (linesize/4) || (file.GetPosition() == file.GetLength())))
-        bOutput=true;
-      if (bOutput)
-      {
-        if( blocksout && linesize > 0 )
-          strBase64 += "\r";
-        if( blocksout )
-          strBase64 += closeTag ;
-        blocksout = 0;
-        bOutput=false;
-      }
-    }
-    file.Close();
-  }
-  return strBase64;
-}
-
-/*
-** decode
-**
-** decode a base64 encoded stream discarding padding, line breaks and noise
-*/
-bool CXbmcHttp::decodeBase64ToFile( const CStdString &inString, const CStdString &outfilename, bool append)
-{
-  unsigned char in[4], v; //out[3];
-  bool ret=true;
-  int i, len ;
-  unsigned int ptr=0;
-  FILE *outfile;
-
-  memset(in, 0, sizeof(in));
-
-// Translation Table to decode
-  static const char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
-
-  try
-  {
-    if (append)
-      outfile = fopen_utf8(CSpecialProtocol::TranslatePath(outfilename).c_str(), "ab" );
-    else
-      outfile = fopen_utf8(CSpecialProtocol::TranslatePath(outfilename).c_str(), "wb" );
-    while( ptr < inString.length() )
-    {
-      for( len = 0, i = 0; i < 4 && ptr < inString.length(); i++ ) 
-      {
-        v = 0;
-        while( ptr < inString.length() && v == 0 ) 
-        {
-          v = (unsigned char) inString[ptr];
-          ptr++;
-          v = (unsigned char) ((v < 43 || v > 122) ? 0 : cd64[ v - 43 ]);
-          if( v )
-            v = (unsigned char) ((v == '$') ? 0 : v - 61);
-        }
-        if( ptr < inString.length() ) {
-          len++;
-          if( v ) 
-            in[ i ] = (unsigned char) (v - 1);
-        }
-        else 
-          in[i] = 0;
-      }
-      if( len ) 
-      {
-        putc((unsigned char ) ((in[0] << 2 | in[1] >> 4) & 255), outfile );
-        putc((unsigned char ) ((in[1] << 4 | in[2] >> 2) & 255), outfile );
-        putc((unsigned char ) ((in[2] << 6) & 0xc0) | in[3], outfile );
-      }
-    }
-    fclose(outfile);
-  }
-  catch (...)
-  {
-    ret=false;
-  }
-  return ret;
-}
-
-int64_t CXbmcHttp::fileSize(const CStdString &filename)
-{
-  if (CFile::Exists(filename))
-  {
-    struct __stat64 s64;
-    if (CFile::Stat(filename, &s64) == 0)
-      return s64.st_size;
-    else
-      return -1;
-  }
-  else
-    return -1;
-}
-
-void CXbmcHttp::resetTags()
-{
-  openTag="<li>"; 
-  closeTag="\n";
-  userHeader="";
-  userFooter="";
-  openRecordSet="";
-  closeRecordSet="";
-  openRecord="";
-  closeRecord="";
-  openField="<field>";
-  closeField="</field>";
-  openBroadcast="<b>";
-  closeBroadcast="</b>";
-  incWebHeader=true;
-  incWebFooter=true;
-  closeFinalTag=false;
-}
-
-CStdString CXbmcHttp::procMask(CStdString mask)
-{
-  mask=mask.ToLower();
-  if(mask=="[music]")
-    return g_settings.m_musicExtensions;
-  if(mask=="[video]")
-    return g_settings.m_videoExtensions;
-  if(mask=="[pictures]")
-    return g_settings.m_pictureExtensions;
-  if(mask=="[files]")
-    return "";
-  return mask;
-}
-
-int CXbmcHttp::splitParameter(const CStdString &parameter, CStdString& command, CStdString paras[], const CStdString &sep)
-//returns -1 if no command, -2 if too many parameters else the number of parameters
-//assumption: sep.length()==1
-{
-  unsigned int num=0, p;
-  CStdString empty="";
-
-  paras[0]="";
-  for (p=0; p<parameter.length(); p++)
-  {
-    if (parameter.Mid(p,1)==sep)
-    {
-      if (p<parameter.length()-1)
-      {
-        if (parameter.Mid(p+1,1)==sep)
-        {
-          paras[num]+=sep;
-          p+=1;
-        }
-        else
-        {
-          if (command!="")
-          {
-            paras[num]=paras[num].Trim();
-            num++;
-            if (num==MAX_PARAS)
-              return -2;
-          }
-          else
-          {
-            command=paras[0];
-            paras[0]=empty;
-            p++; //the ";" after the command is always followed by a space which we can jump over
-          }
-        }
-      }
-      else
-      {
-        if (command!="")
-        {
-          paras[num]=paras[num].Trim();
-          num++;
-          if (num==MAX_PARAS)
-            return -2;
-        }
-        else
-        {
-          command=paras[0];
-          paras[0]=empty;
-        }
-      }
-    }
-    else
-    {
-      paras[num]+=parameter.Mid(p,1);
-    }
-  }
-  if (command=="")
-    if (paras[0]!="")
-    {
-      command=paras[0];
-      return 0;
-    }
-    else
-      return -1;
-  else
-  {
-    paras[num]=paras[num].Trim();
-    return num+1;
-  }
-}
-
-
-bool CXbmcHttp::playableFile(const CStdString &filename)
-{
-  CFileItem item(filename, false);  
-  return item.IsInternetStream() || CFile::Exists(filename);
-}
-
-int CXbmcHttp::SetResponse(const CStdString &response)
-{
-  if (response.length()>=closeTag.length())
-  {
-    if ((response.Right(closeTag.length())!=closeTag) && closeFinalTag) 
-      return CApplicationMessenger::Get().SetResponse(response+closeTag);
-  }
-  else 
-    if (closeFinalTag)
-      return CApplicationMessenger::Get().SetResponse(response+closeTag);
-  return CApplicationMessenger::Get().SetResponse(response);
-}
-
-int CXbmcHttp::displayDir(int numParas, CStdString paras[]) 
-{
-  //mask = ".mp3|.wma" or one of "[music]", "[video]", "[pictures]", "[files]"-> matching files
-  //mask = "*" or "/" -> just folders
-  //mask = "" -> all files and folder
-  //option = "1" (or "showdate") -> append date&time to file name
-  //option = "size" -> just return the number of entries
-
-  CFileItemList dirItems;
-  CStdString output="";
-
-  CStdString  folder, mask="", option="";
-  int lineStart=0, numLines=-1;
-
-  if (numParas==0)
-  {
-    return SetResponse(openTag+"Error:Missing folder");
-  }
-  folder = paras[0];
-  if (folder.IsEmpty())
-  {
-    return SetResponse(openTag+"Error:Missing folder");
-  }
-  if (numParas>1)
-    mask = procMask(paras[1]);
-  if (numParas>2)
-    option = paras[2].ToLower();
-  if (numParas>3)
-    lineStart = atoi(paras[3]);
-  if (numParas>4)
-    numLines = atoi(paras[4]);
-  if (!CDirectory::GetDirectory(folder, dirItems, mask))
-  {
-    return SetResponse(openTag+"Error: " + folder + "Not folder");
-  }
-  if (option=="size")
-  {
-    CStdString tmp;
-    tmp.Format("%i", dirItems.Size());
-    return SetResponse(openTag+tmp);
-  }
-  dirItems.Sort(SORT_METHOD_LABEL, SortOrderAscending);
-  if (lineStart > dirItems.Size() || lineStart < 0)
-    return SetResponse(openTag+"Error:Line start value out of range");
-  if (numLines == -1)
-    numLines = dirItems.Size();
-  if (numLines + lineStart > dirItems.Size())
-    numLines=dirItems.Size()-lineStart;
-  for (int i = lineStart; i < lineStart + numLines; ++i)
-  {
-    CFileItemPtr itm = dirItems[i];
-    CStdString aLine;
-    if (mask=="*" || mask=="/" || (mask =="" && itm->m_bIsFolder))
-    {
-      if (!URIUtils::HasSlashAtEnd(itm->GetPath()))
-        aLine = closeTag + openTag + itm->GetPath() + "\\" ;
-      else
-        aLine = closeTag + openTag + itm->GetPath();
-    }
-    else if (!itm->m_bIsFolder)
-      aLine = closeTag + openTag + itm->GetPath();
-
-    if (!aLine.IsEmpty())
-    {
-      if (option=="1" || option=="showdate")
-        output += aLine + "  ;" + itm->m_dateTime.GetAsLocalizedDateTime();
-      else
-        output += aLine;
-    }
-  }
-  return SetResponse(output);
-}
-
-void CXbmcHttp::SetCurrentMediaItem(CFileItem& newItem)
-{
-  //  No audio file, we are finished here
-  if (!newItem.IsAudio() )
-    return;
-
-  //  we have a audio file.
-  //  Look if we have this file in database...
-  bool bFound=false;
-  CMusicDatabase musicdatabase;
-  if (musicdatabase.Open())
-  {
-    CSong song;
-    bFound=musicdatabase.GetSongByFileName(newItem.GetPath(), song);
-    newItem.GetMusicInfoTag()->SetSong(song);
-    musicdatabase.Close();
-  }
-  if (!bFound && g_guiSettings.GetBool("musicfiles.usetags"))
-  {
-    //  ...no, try to load the tag of the file.
-    auto_ptr<IMusicInfoTagLoader> pLoader(CMusicInfoTagLoaderFactory::CreateLoader(newItem.GetPath()));
-    //  Do we have a tag loader for this file type?
-    if (pLoader.get() != NULL)
-      pLoader->Load(newItem.GetPath(),*newItem.GetMusicInfoTag());
-  }
-
-  //  If we have tag information, ...
-  if (newItem.HasMusicInfoTag() && newItem.GetMusicInfoTag()->Loaded())
-  {
-    CApplicationMessenger::Get().SetCurrentSongTag(*newItem.GetMusicInfoTag());
-  }
-}
-
-int CXbmcHttp::FindPathInPlayList(int playList, CStdString path)
-{   
-  CPlayList& thePlayList = g_playlistPlayer.GetPlaylist(playList);
-  for (int i = 0; i < thePlayList.size(); i++)
-  {
-    CFileItemPtr item = thePlayList[i];
-    if (path==item->GetPath())
-      return i;
-  }
-  return -1;
-}
-
-void CXbmcHttp::AddItemToPlayList(const CFileItemPtr &pItem, int playList, int sortMethod, CStdString mask, bool recursive)
-//if playlist==-1 then use slideshow
-{
-  if (pItem->m_bIsFolder)
-  {
-    // recursive
-    if (pItem->IsParentFolder()) return;
-    CStdString strDirectory=pItem->GetPath();
-    CFileItemList items;
-    CDirectory::GetDirectory(pItem->GetPath(), items, mask);
-    items.Sort(SORT_METHOD_LABEL, SortOrderAscending);
-    for (int i=0; i < items.Size(); ++i)
-      if (!(CFileItem*)items[i]->m_bIsFolder || recursive)
-        AddItemToPlayList(items[i], playList, sortMethod, mask, recursive);
-  }
-  else
-  {
-    //selected item is a file, add it to playlist
-    if (playList==-1)
-    {
-      CGUIWindowSlideShow *pSlideShow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
-      if (!pSlideShow)
-        return ;
-      pSlideShow->Add(pItem.get());
-    }
-    else
-      g_playlistPlayer.Add(playList, pItem);
-  }
-}
-
-
-bool CXbmcHttp::LoadPlayList(CStdString strPath, int iPlaylist, bool clearList, bool autoStart)
-{
-  CFileItem *item = new CFileItem(URIUtils::GetFileName(strPath));
-  item->SetPath(strPath);
-
-  auto_ptr<CPlayList> pPlayList (CPlayListFactory::Create(*item));
-  if ( NULL == pPlayList.get())
-    return false;
-  if (!pPlayList->Load(item->GetPath()))
-    return false;
-
-  CPlayList& playlist = (*pPlayList);
-
-  if (playlist.size() == 0)
-    return false;
-
-  // first item of the list, used to determine the intent
-  CFileItemPtr playlistItem = playlist[0];
-
-  if ((playlist.size() == 1) && (autoStart))
-  {
-    // just 1 song? then play it (no need to have a playlist of 1 song)
-    CApplicationMessenger::Get().MediaPlay(playlistItem->GetPath());
-    return true;
-  }
-
-  if (clearList)
-    g_playlistPlayer.ClearPlaylist(iPlaylist);
-
-  g_playlistPlayer.Add(iPlaylist, *pPlayList);
-
-  if (autoStart)
-    if (g_playlistPlayer.GetPlaylist( iPlaylist ).size() )
-    {
-      g_playlistPlayer.SetCurrentPlaylist(iPlaylist);
-      g_playlistPlayer.Reset();
-      CApplicationMessenger::Get().PlayListPlayerPlay();
-      return true;
-    } 
-    else
-      return false;
-  else
-    return true;
-  return false;
-}
-
-void CXbmcHttp::copyThumb(CStdString srcFn, CStdString destFn)
-//Copies src file to dest, unless src=="" or src doesn't exist in which case dest is deleted
-{
-
-  if (destFn=="")
-    return;
-  if (srcFn=="")
-  {
-    try
-    {
-      if (CFile::Exists(destFn))
-        CFile::Delete(destFn);
-      lastThumbFn=srcFn;
-    }
-    catch (...)
-    {
-    }
-  }
-  else
-    if (srcFn!=lastThumbFn)
-      try
-      {
-        lastThumbFn=srcFn;
-        if (CFile::Exists(srcFn))
-          CFile::Cache(srcFn, destFn);
-      }
-      catch (...)
-      {
-        return;
-      }
-}
-
-int CXbmcHttp::xbmcGetMediaLocation(int numParas, CStdString paras[])
-{
-  // getmediadirectory&parameter=type;location;options
-  // options = showdate, pathsonly
-  // returns a listing of
-  // label;path;0|1=folder;date
-
-  int iType = -1;
-  CStdString strType;
-  CStdString strMask;
-  CStdString strLocation;
-  CStdString strOutput;
-
-  if (numParas < 1)
-    return SetResponse(openTag+"Error: must supply media type at minimum");
-  else
-  {
-    if (paras[0].Equals("music"))
-      iType = 0;
-    else if (paras[0].Equals("video"))
-      iType = 1;
-    else if (paras[0].Equals("pictures"))
-      iType = 2;
-    else if (paras[0].Equals("files"))
-      iType = 3;
-    if (iType < 0)
-      return SetResponse(openTag+"Error: invalid media type; valid options are music, video, pictures");
-
-    strType = paras[0].ToLower();
-    if (numParas > 1)
-      strLocation = paras[1];
-  }
-
-  // handle options
-  bool bShowDate = false;
-  bool bPathsOnly = false;
-  bool bSize = false;
-  int lineStart=0, numLines=-1;
-  if (numParas > 2)
-  {
-    for (int i = 2; i < numParas; ++i)
-    {
-      if (paras[i].Equals("showdate"))
-        bShowDate = true;
-      else if (paras[i].Equals("pathsonly"))
-        bPathsOnly = true;
-      else if (paras[i].Equals("size"))
-        bSize = true;
-      else if (StringUtils::IsNaturalNumber(paras[i]))
-      {
-        lineStart=atoi(paras[i]);
-        i++;
-        if (i<numParas)
-          if (StringUtils::IsNaturalNumber(paras[i]))
-          {
-            numLines=atoi(paras[i]);
-            i++;
-          }
-      }
-    }
-    // pathsonly and showdate are mutually exclusive, pathsonly wins
-    if (bPathsOnly)
-      bShowDate = false;
-  }
-
-  VECSOURCES *pShares = NULL;
-  enum SHARETYPES { MUSIC, VIDEO, PICTURES, FILES };
-  switch(iType)
-  {
-  case MUSIC:
-    {
-      pShares = &g_settings.m_musicSources;
-      strMask = g_settings.m_musicExtensions;
-    }
-    break;
-  case VIDEO:
-    {
-      pShares = &g_settings.m_videoSources;
-      strMask = g_settings.m_videoExtensions;
-    }
-    break;
-  case PICTURES:
-    {
-      pShares = &g_settings.m_pictureSources;
-      strMask = g_settings.m_pictureExtensions;
-    }
-    break;
-  case FILES:
-    {
-      pShares = &g_settings.m_fileSources;
-      strMask = "";
-    }
-    break;
-  }
-
-  if (!pShares)
-    return SetResponse(openTag+"Error");
-
-  // TODO: Why are we insisting the passed path has anything to do with
-  //       the shares in question??
-  //       Surely we should just grab the directory regardless??
-  // 
-  // kraqh3d's response:
-  // When I added this function, it was meant to behave more like Xbmc internally.
-  // This code emulates the CVirtualDirectory class which does not allow arbitrary
-  // fetching of directories. (nor does ActivateWindow for that matter.)
-  // You can still use the older "getDirectory" command which is unbounded and will
-  // fetch any old folder.
-
-  // special locations
-  bool bSpecial = false;
-  CURL url(strLocation);
-  if (url.GetProtocol() == "rar" || url.GetProtocol() == "zip")
-    bSpecial = true;
-  if (strType.Equals("music"))
-  {
-    if (url.GetProtocol() == "musicdb")
-      bSpecial = true;
-    else if (strLocation.Equals("$playlists"))
-    {
-      strLocation = "special://musicplaylists/";
-      bSpecial = true;
-    }
-  }
-  else if (strType.Equals("video"))
-  {
-    if (strLocation.Equals("$playlists"))
-    {
-      strLocation = "special://videoplaylists/";
-      bSpecial = true;
-    }
-  }
-
-  if (!strLocation.IsEmpty() && !bSpecial)
-  {
-    VECSOURCES VECSOURCES = *pShares;
-    bool bIsShareName = false;
-    int iIndex = CUtil::GetMatchingSource(strLocation, VECSOURCES, bIsShareName);
-    if (iIndex < 0 || iIndex >= (int)VECSOURCES.size())
-    {
-      CStdString strError = "Error: invalid location, " + strLocation;
-      return SetResponse(openTag+strError);
-    }
-    if (bIsShareName)
-      strLocation = VECSOURCES[iIndex].strPath;
-  }
-
-  CFileItemList items;
-  if (strLocation.IsEmpty())
-  {
-    CStdString params[2];
-    params[0] = strType;
-    params[1] = "appendone";
-    if (bPathsOnly)
-      params[1] = "pathsonly";
-    return xbmcGetSources(2, params);
-  }
-  else if (!CDirectory::GetDirectory(strLocation, items, strMask))
-  {
-    CStdString strError = "Error: could not get location, " + strLocation;
-    return SetResponse(openTag+strError);
-  }
-  if (bSize)
-  {
-    CStdString tmp;
-    tmp.Format("%i",items.Size());
-    return SetResponse(openTag+tmp);
-  }    
-  items.Sort(SORT_METHOD_LABEL, SortOrderAscending);
-  CStdString strLine;
-  if (lineStart>items.Size() || lineStart<0)
-    return SetResponse(openTag+"Error:Line start value out of range");
-  if (numLines==-1)
-    numLines=items.Size();
-  if ((numLines+lineStart)>items.Size())
-    numLines=items.Size()-lineStart;
-  for (int i=lineStart; i<lineStart+numLines; ++i)
-  {
-    CFileItemPtr item = items[i];
-    CStdString strLabel = item->GetLabel();
-    strLabel.Replace(";",";;");
-    CStdString strPath = item->GetPath();
-    strPath.Replace(";",";;");
-    CStdString strFolder = "0";
-    if (item->m_bIsFolder)
-    {
-      if (!item->IsFileFolder() && !URIUtils::HasSlashAtEnd(strPath))
-          URIUtils::AddSlashAtEnd(strPath);
-      strFolder = "1";
-    }
-    strLine = openTag;
-    if (!bPathsOnly)
-      strLine += strLabel + ";";
-    strLine += strPath;
-    if (!bPathsOnly)
-      strLine += ";" + strFolder;
-    if (bShowDate)
-    {
-      strLine += ";" + item->m_dateTime.GetAsLocalizedDateTime();
-    }
-    strLine += closeTag;
-    strOutput += strLine;
-  }
-  return SetResponse(strOutput);
-}
-
-int CXbmcHttp::xbmcGetXBEID(int numParas, CStdString paras[])
-{
-  return SetResponse(openTag+"Error:Missing Parameter");
-}
-
-int CXbmcHttp::xbmcGetXBETitle(int numParas, CStdString paras[])
-{
-  return SetResponse(openTag+"Error:Missing Parameter");
-}
-
-int CXbmcHttp::xbmcGetSources(int numParas, CStdString paras[])
-{
-  // returns the share listing in this format:
-  // type;name;path
-  // literal semicolons are translated into ;;
-  // options include the type, and pathsonly boolean
-
-  int iStart = 0;
-  int iEnd   = 4;
-  bool bShowType = true;
-  bool bShowName = true;
-
-  if (numParas > 0)
-  {
-    if (paras[0].Equals("music"))
-    {
-      iStart = 0;
-      iEnd   = 1;
-      bShowType = false;
-    }
-    else if (paras[0].Equals("video"))
-    {
-      iStart = 1;
-      iEnd   = 2;
-      bShowType = false;
-    }
-    else if (paras[0].Equals("pictures"))
-    {
-      iStart = 2;
-      iEnd   = 3;
-      bShowType = false;
-    }
-    else if (paras[0].Equals("files"))
-    {
-      iStart = 3;
-      iEnd   = 4;
-      bShowType = false;
-    }
-    else
-      numParas = 0;
-  }
-
-  bool bAppendOne = false;
-  if (numParas > 1)
-  {
-    // special case where getmedialocation calls getshares
-    if (paras[1].Equals("appendone"))
-      bAppendOne = true;
-    else if (paras[1].Equals("pathsonly"))
-      bShowName = false;
-  }
-
-  CStdString strOutput;
-  enum SHARETYPES { MUSIC, VIDEO, PICTURES, FILES };
-  for (int i = iStart; i < iEnd; ++i)
-  {
-    CStdString strType;
-    VECSOURCES *pShares = NULL;
-    switch(i)
-    {
-    case MUSIC:
-      {
-        strType = "music";
-        pShares = &g_settings.m_musicSources;
-      }
-      break;
-    case VIDEO:
-      {
-        strType = "video";
-        pShares = &g_settings.m_videoSources;
-      }
-      break;
-    case PICTURES:
-      {
-        strType = "pictures";
-        pShares = &g_settings.m_pictureSources;
-      }
-      break;
-    case FILES:
-      {
-        strType = "files";
-        pShares = &g_settings.m_fileSources;
-      }
-      break;
-    }
-
-    if (!pShares)
-      return SetResponse(openTag+"Error");
-    
-    VECSOURCES VECSOURCES = *pShares;
-    for (int j = 0; j < (int)VECSOURCES.size(); ++j)
-    {
-      CMediaSource share = VECSOURCES.at(j);
-      CStdString strName = share.strName;
-      strName.Replace(";", ";;");
-      CStdString strPath = share.strPath;
-      strPath.Replace(";", ";;");
-      URIUtils::AddSlashAtEnd(strPath);
-      CStdString strLine = openTag;
-      if (bShowType)
-        strLine += strType + ";";
-      if (bShowName)
-        strLine += strName + ";";
-      strLine += strPath;
-      if (bAppendOne)
-        strLine += ";1";
-      strLine += closeTag;
-      strOutput += strLine;
-    }
-  }
-  return SetResponse(strOutput);
-}
-
-int CXbmcHttp::xbmcQueryMusicDataBase(int numParas, CStdString paras[])
-{
-  if (numParas==0)
-    return SetResponse(openTag+"Error:Missing Parameter");
-  else
-  {
-    CMusicDatabase musicdatabase;
-    if (musicdatabase.Open())
-    {
-      int response;
-      CStdString sql = musicdatabase.PrepareSQL(paras[0]);
-      CStdString result;
-      if (musicdatabase.GetArbitraryQuery(sql, openRecordSet, closeRecordSet, openRecord, closeRecord, openField, closeField, result))
-        response = SetResponse(result);
-      else
-        response = SetResponse(openTag+"Error:"+result);
-      musicdatabase.Close();
-      return response;
-    }
-    else
-      return SetResponse(openTag+"Error:Could not open database");
-  }
-  return true;
-}
-
-int CXbmcHttp::xbmcQueryVideoDataBase(int numParas, CStdString paras[])
-{
-  if (numParas==0)
-    return SetResponse(openTag+"Error:Missing Parameter");
-  else
-  {
-  CVideoDatabase videodatabase;
-  if (videodatabase.Open())
-  {
-    int response;
-    CStdString result;
-    CStdString sql = videodatabase.PrepareSQL(paras[0]);
-    if (videodatabase.GetArbitraryQuery(sql, openRecordSet, closeRecordSet, openRecord, closeRecord, openField, closeField, result))
-      response = SetResponse(result);
-    else
-      response = SetResponse(openTag+"Error:"+result);
-    videodatabase.Close();
-    return response;
-  }
-  else
-    return SetResponse(openTag+"Error:Could not open database");
-  }
-  return true;
-}
-
-int CXbmcHttp::xbmcExecVideoDataBase(int numParas, CStdString paras[])
-{
-  if (numParas==0)
-    return SetResponse(openTag+"Error:Missing Parameter");
-  else
-  {
-    CVideoDatabase videodatabase;
-    if (videodatabase.Open())
-    {
-      int response;
-      CStdString result;
-      CStdString sql = videodatabase.PrepareSQL(paras[0]);
-      if (videodatabase.ArbitraryExec(sql))
-        response = SetResponse(openTag+"SQL Exec Done");
-      else
-        response = SetResponse(openTag+"Error:SQL Exec Failed");
-      videodatabase.Close();
-      return response;
-    }
-    else
-      return SetResponse(openTag+"Error:Could not open database");
-  }
-  return true;
-}
-
-int CXbmcHttp::xbmcExecMusicDataBase(int numParas, CStdString paras[])
-{
-  if (numParas==0)
-    return SetResponse(openTag+"Error:Missing Parameter");
-  else
-  {
-    CMusicDatabase musicdatabase;
-    if (musicdatabase.Open())
-    {
-      int response;
-      CStdString result;
-      CStdString sql = musicdatabase.PrepareSQL(paras[0]);
-      if (musicdatabase.ArbitraryExec(sql))
-        response = SetResponse(openTag+"SQL Exec Done");
-      else
-        response = SetResponse(openTag+"Error:SQL Exec Failed");
-      musicdatabase.Close();
-      return response;
-    }
-    else
-      return SetResponse(openTag+"Error:Could not open database");
-  }
-  return true;
-}
-
-int CXbmcHttp::xbmcAddToPlayListFromDB(int numParas, CStdString paras[])
-{
-  if (numParas == 0)
-    return SetResponse(openTag+"Error: Missing Parameter");
-
-  CStdString type  = paras[0];
-  
-  // Perform open query if empty where clause
-  if (paras[1] == "")
-    paras[1] = "1 = 1";
-  CStdString where = paras[1];
-
-  int playList;
-  CFileItemList filelist;
-  if (type.Equals("songs"))
-  {
-    playList = PLAYLIST_MUSIC;
-
-    CMusicDatabase musicdatabase;
-    if (!musicdatabase.Open())
-      return SetResponse(openTag+ "Error: Could not open music database");
-    musicdatabase.GetSongsByWhere("musicdb://4/", where, filelist);
-    musicdatabase.Close();
-  }
-  else if (type.Equals("movies") || 
-           type.Equals("episodes") ||
-           type.Equals("musicvideos"))
-  {
-    playList = PLAYLIST_VIDEO;
-
-    CVideoDatabase videodatabase;
-    if (!videodatabase.Open())
-      return SetResponse(openTag+"Error: Could not open video database");
-
-    if (type.Equals("movies"))
-      videodatabase.GetMoviesByWhere("videodb://1/2/", where, filelist);
-    else if (type.Equals("episodes"))
-      videodatabase.GetEpisodesByWhere("videodb://2/2/", where, filelist);
-    else if (type.Equals("musicvideos"))
-      videodatabase.GetMusicVideosByWhere("videodb://3/2/", where, filelist);
-    videodatabase.Close();
-  }
-  else
-    return SetResponse(openTag+"Invalid type. Must be songs,music,episodes or musicvideo");
-
-  if (filelist.Size() == 0)
-    return SetResponse(openTag+"Nothing added");
-
-  g_playlistPlayer.Add(playList, filelist);
-  return SetResponse(openTag+"OK");
-}
-
-int CXbmcHttp::xbmcAddToPlayList(int numParas, CStdString paras[])
-{
-  //parameters=playList;mask;recursive
-  CStdString strFileName, mask="";
-  bool changed=false, recursive=true;
-  int playList ;
-
-  if (numParas==0)
-    return SetResponse(openTag+"Error:Missing Parameter");
-  else
-  {
-    if (numParas==1) //no playlist and no mask
-      playList=g_playlistPlayer.GetCurrentPlaylist();
-    else
-    {
-      playList=atoi(paras[1]);
-      if (playList==-1)
-        playList=g_playlistPlayer.GetCurrentPlaylist();
-      if(numParas>2) //includes mask
-        mask=procMask(paras[2]);
-      if (numParas>3) //recursive
-        recursive=(paras[3]=="1");
-    }
-    strFileName=paras[0] ;
-    CURL::Decode(strFileName);
-    CFileItemPtr pItem(new CFileItem(strFileName));
-    pItem->SetPath(strFileName);
-    if (pItem->IsPlayList())
-      changed=LoadPlayList(pItem->GetPath(), playList, false, false);
-    else
-    {
-      bool bResult = CDirectory::Exists(pItem->GetPath());
-      pItem->m_bIsFolder=bResult;
-      pItem->m_bIsShareOrDrive=false;
-      if (bResult || CFile::Exists(pItem->GetPath()))
-      {
-        AddItemToPlayList(pItem, playList, 0, mask, recursive);
-        changed=true;
-      }
-    }
-    if (changed)
-    {
-      return SetResponse(openTag+"OK");
-    }
-    else
-      return SetResponse(openTag+"Error");
-  }
-}
-
-int CXbmcHttp::xbmcGetTagFromFilename(int numParas, CStdString paras[]) 
-{
-  CStdString strFileName;
-  if (numParas==0) {
-    return SetResponse(openTag+"Error:Missing Parameter");
-  }
-  strFileName=URIUtils::GetFileName(paras[0]);
-  CFileItem *pItem = new CFileItem(strFileName);
-  pItem->SetPath(paras[0]);
-  if (!pItem->IsAudio())
-  {
-    delete pItem;
-    return SetResponse(openTag+"Error:Not Audio");
-  }
-
-  CMusicInfoTag* tag=pItem->GetMusicInfoTag();
-  bool bFound=false;
-  CSong song;
-  CMusicDatabase musicdatabase;
-  if (musicdatabase.Open())
-  {
-    bFound=musicdatabase.GetSongByFileName(pItem->GetPath(), song);
-    musicdatabase.Close();
-  }
-  if (bFound)
-  {
-    SYSTEMTIME systime;
-    systime.wYear=song.iYear;
-    tag->SetReleaseDate(systime);
-    tag->SetTrackNumber(song.iTrack);
-    tag->SetAlbum(song.strAlbum);
-    tag->SetArtist(song.artist);
-    tag->SetGenre(song.genre);
-    tag->SetTitle(song.strTitle);
-    tag->SetDuration(song.iDuration);
-    tag->SetLoaded(true);
-  }
-  else
-    if (g_guiSettings.GetBool("musicfiles.usetags"))
-    {
-      // get correct tag parser
-      auto_ptr<IMusicInfoTagLoader> pLoader (CMusicInfoTagLoaderFactory::CreateLoader(pItem->GetPath()));
-      if (NULL != pLoader.get())
-      {            
-        // get id3tag
-        if ( !pLoader->Load(pItem->GetPath(),*tag))
-          tag->SetLoaded(false);
-      }
-      else
-      {
-        return SetResponse(openTag+"Error:Could not load TagLoader");
-      }
-    }
-    else
-    {
-      return SetResponse(openTag+"Error:System not set to use tags");
-    }
-  if (tag->Loaded())
-  {
-    CStdString output, tmp;
-
-    output = openTag+"Artist:" + StringUtils::Join(tag->GetArtist(), g_advancedSettings.m_musicItemSeparator);
-    output += closeTag+openTag+"Album:" + tag->GetAlbum();
-    output += closeTag+openTag+"Title:" + tag->GetTitle();
-    tmp.Format("%i", tag->GetTrackNumber());
-    output += closeTag+openTag+"Track number:" + tmp;
-    tmp.Format("%i", tag->GetDuration());
-    output += closeTag+openTag+"Duration:" + tmp;
-    output += closeTag+openTag+"Genre:" + StringUtils::Join(tag->GetGenre(), g_advancedSettings.m_musicItemSeparator);
-    SYSTEMTIME stTime;
-    tag->GetReleaseDate(stTime);
-    tmp.Format("%i", stTime.wYear);
-    output += closeTag+openTag+"Release year:" + tmp;
-    CMusicThumbLoader::FillThumb(*pItem);
-    if (pItem->HasThumbnail())
-      output += closeTag+openTag+"Thumb:" + pItem->GetThumbnailImage() ;
-    else {
-      output += closeTag+openTag+"Thumb:[None]";
-    }
-    delete pItem;
-    return SetResponse(output);
-  }
-  else
-  {
-    delete pItem;
-    return SetResponse(openTag+"Error:No tag info");
-  }
-}
-
-int CXbmcHttp::xbmcClearPlayList(int numParas, CStdString paras[])
-{
-  int playList ;
-  if (numParas==0)
-    playList = g_playlistPlayer.GetCurrentPlaylist() ;
-  else
-    playList=atoi(paras[0]) ;
-  g_playlistPlayer.ClearPlaylist( playList );
-  return SetResponse(openTag+"OK");
-}
-
-int CXbmcHttp::xbmcGetDirectory(int numParas, CStdString paras[])
-{
-  if (numParas>0)
-    return displayDir(numParas, paras);
-  else
-    return SetResponse(openTag+"Error:No path") ;
-}
-
-int CXbmcHttp::xbmcGetMovieDetails(int numParas, CStdString paras[])
-{
-  if (numParas>0)
-  {
-    CFileItem *item = new CFileItem(paras[0]);
-    item->SetPath(paras[0]);
-    if (item->IsVideo()) {
-      CVideoDatabase m_database;
-      CVideoInfoTag aMovieRec;
-      m_database.Open();
-      if (m_database.HasMovieInfo(paras[0].c_str()))
-      {
-        CStdString thumb, output, tmp;
-        m_database.GetMovieInfo(paras[0].c_str(),aMovieRec);
-        tmp.Format("%i", aMovieRec.m_iYear);
-        output = closeTag+openTag+"Year:" + tmp;
-        output += closeTag+openTag+"Director:" + StringUtils::Join(aMovieRec.m_director, g_advancedSettings.m_videoItemSeparator);
-        output += closeTag+openTag+"Title:" + aMovieRec.m_strTitle;
-        output += closeTag+openTag+"Plot:" + aMovieRec.m_strPlot;
-        output += closeTag+openTag+"Genre:" + StringUtils::Join(aMovieRec.m_genre, g_advancedSettings.m_videoItemSeparator);
-        CStdString strRating;
-        strRating.Format("%3.3f", aMovieRec.m_fRating);
-        if (strRating=="") strRating="0.0";
-        output += closeTag+openTag+"Rating:" + strRating;
-        CStdString cast = aMovieRec.GetCast(true);
-        /*for (CVideoInfoTag::iCast it = aMovieRec.m_cast.begin(); it != aMovieRec.m_cast.end(); ++it)
-        {
-          CStdString character;
-          character.Format("%s %s %s\n", it->first.c_str(), g_localizeStrings.Get(20347).c_str(), it->second.c_str());
-          cast += character;
-        }*/
-        output += closeTag+openTag+"Cast:" + cast;
-        if (!CVideoThumbLoader::FillThumb(*item))
-          thumb = "[None]";
-        else
-          thumb = CTextureCache::GetWrappedImageURL(item->GetThumbnailImage());
-        output += closeTag+openTag+"Thumb:" + thumb;
-        m_database.Close();
-        delete item;
-        return SetResponse(output);
-      }
-      else
-      {
-        m_database.Close();
-        delete item;
-        return SetResponse(openTag+"Error:Not found");
-      }
-    }
-    else
-    {
-      delete item;
-      return SetResponse(openTag+"Error:Not a video") ;
-    }
-  }
-  else
-    return SetResponse(openTag+"Error:No file name") ;
-}
-
-int CXbmcHttp::xbmcGetCurrentlyPlaying(int numParas, CStdString paras[])
-//paras: filename_to_save_thumb, filename_if_nothing_playing, only_return_info_if_changed,
-//       extendedVersion, filename_to_save_slide_thumb, filename_if_no_slide_playing
-{
-  CStdString output="", tmp="", tag="", thumbFn="", thumbNothingPlaying="", thumb="", thumbSlideFn="";
-  bool justChange=false, changed=false, extended=false, slideChanged=false;
-  if (numParas>0)
-    thumbFn=paras[0];
-  if (numParas>1)
-    thumbNothingPlaying=paras[1];
-  if (numParas>2)
-    justChange=paras[2].ToLower()=="true";
-  if (numParas>3)
-    extended=paras[3].ToLower()=="true";
-  if (numParas>4)
-    thumbSlideFn=paras[4];
-  if (!extended)
-     thumbSlideFn=thumbFn;
-  CStdString prefix="";
-  if (extended)
-    prefix="Slide";
-  CGUIWindowSlideShow *pSlideShow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
-  CStdString slideOutput="";
-  if (g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW && pSlideShow)
-  {
-    const CFileItemPtr slide = pSlideShow->GetCurrentSlide();
-    slideOutput=openTag+prefix+"Filename:"+slide->GetPath();
-    if (lastSlideInfo!=slideOutput)
-    {
-      slideChanged=true;
-      lastSlideInfo=slideOutput;
-    }
-    if (!justChange || slideChanged)
-    {
-      slideOutput+=closeTag+openTag+prefix+"Type:Picture" ;
-      CStdString resolution = "0x0";
-      if (slide && slide->HasPictureInfoTag() && slide->GetPictureInfoTag()->Loaded())
-        resolution = slide->GetPictureInfoTag()->GetInfo(SLIDE_RESOLUTION);
-      slideOutput+=closeTag+openTag+prefix+"Resolution:" + resolution;
-      CFileItem item(*slide);
-      CStdString thumbURL = CTextureCache::GetWrappedThumbURL(item.GetPath());
-      if (autoGetPictureThumbs || CTextureCache::Get().HasCachedImage(thumbURL))
-        thumb = thumbURL;
-      if (thumb.IsEmpty())
-      {
-        thumb = "[None]";
-        copyThumb("DefaultPicture.png",thumbSlideFn);
-      }
-      else
-        copyThumb(thumb,thumbSlideFn);
-      slideOutput+=closeTag+openTag+"Thumb:"+thumb;
-    }
-    if (slideChanged)
-      slideOutput+=closeTag+openTag+prefix+"Changed:True";
-    else  
-      slideOutput+=closeTag+openTag+prefix+"Changed:False";
-    if (!extended)
-    {
-      if (justChange && !slideChanged)
-        return SetResponse(openTag+"Changed:False");
-      else
-        return SetResponse(slideOutput);
-        }
-  }
-  CFileItem &fileItem = g_application.CurrentFileItem();
-  if (fileItem.GetPath().IsEmpty())
-  {
-    output=openTag+"Filename:[Nothing Playing]";
-    if (lastPlayingInfo!=output)
-    {
-      changed=true;
-      lastPlayingInfo=output;
-    }
-    if (justChange && !changed && !slideChanged)
-      return SetResponse(openTag+"Changed:False");
-    copyThumb(thumbNothingPlaying,thumbFn);
-    if (extended && slideOutput!="")
-      return SetResponse(slideOutput+closeTag+output);
-    else
-      return SetResponse(output);
-  }
-  else
-  {
-    CURL url(fileItem.GetPath());
-    CStdString strPath(url.GetWithoutUserDetails());
-    CURL::Decode(strPath);
-    output = openTag + "Filename:" + strPath;  // currently playing item filename
-    if (g_application.IsPlaying())
-      if (!g_application.m_pPlayer->IsPaused())
-        output+=closeTag+openTag+"PlayStatus:Playing";
-      else
-        output+=closeTag+openTag+"PlayStatus:Paused";
-    else
-      output+=closeTag+openTag+"PlayStatus:Stopped";
-    if (g_application.IsPlayingVideo())
-    { // Video information (don't need to worry about the slide stuff since video and slideshow don't mix!)
-      tmp.Format("%i",g_playlistPlayer.GetCurrentSong());
-      output+=closeTag+openTag+"VideoNo:"+tmp;  // current item # in playlist
-      output+=closeTag+openTag+"Type"+tag+":Video" ;
-      const CVideoInfoTag* tagVal=g_infoManager.GetCurrentMovieTag();
-      if (tagVal)
-      {
-        if (!tagVal->m_strShowTitle.IsEmpty())
-          output+=closeTag+openTag+"Show Title"+tag+":"+tagVal->m_strShowTitle ;
-        if (!tagVal->m_strTitle.IsEmpty())
-          output+=closeTag+openTag+"Title"+tag+":"+tagVal->m_strTitle ;
-        //now have enough info to check for a change
-        if (lastPlayingInfo!=output)
-        {
-          changed=true;
-          lastPlayingInfo=output;
-        }
-        if (justChange && !changed)
-          return SetResponse(openTag+"Changed:False");
-        //if still here, continue collecting info
-        if (!tagVal->m_genre.empty())
-          output+=closeTag+openTag+"Genre"+tag+":"+StringUtils::Join(tagVal->m_genre, g_advancedSettings.m_videoItemSeparator);
-        if (!tagVal->m_studio.empty())
-          output+=closeTag+openTag+"Studio"+tag+":"+StringUtils::Join(tagVal->m_studio, g_advancedSettings.m_videoItemSeparator);
-        if (tagVal && tagVal->m_director.size() > 0)
-          output+=closeTag+openTag+"Director"+tag+":"+StringUtils::Join(tagVal->m_director, g_advancedSettings.m_videoItemSeparator);
-        if (tagVal->m_writingCredits.size() > 0)
-          output+=closeTag+openTag+"Writer"+tag+":"+StringUtils::Join(tagVal->m_writingCredits, g_advancedSettings.m_videoItemSeparator);
-        if (!tagVal->m_strTagLine.IsEmpty())
-          output+=closeTag+openTag+"Tagline"+tag+":"+tagVal->m_strTagLine;
-        if (!tagVal->m_strPlotOutline.IsEmpty())
-          output+=closeTag+openTag+"Plotoutline"+tag+":"+tagVal->m_strPlotOutline;
-        if (!tagVal->m_strPlot.IsEmpty())
-          output+=closeTag+openTag+"Plot"+tag+":"+tagVal->m_strPlot;    
-        if (tagVal->m_fRating != 0.0f)  // only non-zero ratings are of interest
-          output.Format("%s%03.1f (%s %s)",output+closeTag+openTag+"Rating"+tag+":",tagVal->m_fRating, tagVal->m_strVotes, g_localizeStrings.Get(20350));
-        if (!tagVal->m_strOriginalTitle.IsEmpty())
-          output+=closeTag+openTag+"Original Title"+tag+":"+tagVal->m_strOriginalTitle;
-        if (tagVal->m_premiered.IsValid())
-          output+=closeTag+openTag+"Premiered"+tag+":"+tagVal->m_premiered.GetAsLocalizedDate();
-        if (!tagVal->m_strStatus.IsEmpty())
-          output+=closeTag+openTag+"Status"+tag+":"+tagVal->m_strStatus;
-        if (!tagVal->m_strProductionCode.IsEmpty())
-          output+=closeTag+openTag+"Production Code"+tag+":"+tagVal->m_strProductionCode;
-        if (tagVal->m_firstAired.IsValid())
-          output+=closeTag+openTag+"First Aired"+tag+":"+tagVal->m_firstAired.GetAsLocalizedDate();
-        if (tagVal->m_iYear != 0)
-          output.Format("%s%i",output+closeTag+openTag+"Year"+tag+":",tagVal->m_iYear);
-        if (tagVal->m_iSeason != -1)
-          output.Format("%s%i",output+closeTag+openTag+"Season"+tag+":",tagVal->m_iSeason);
-        if (tagVal->m_iEpisode != -1)
-          output.Format("%s%i",output+closeTag+openTag+"Episode"+tag+":",tagVal->m_iEpisode);
-      }
-      else
-      {
-        //now have enough info to estimate a change
-        if (lastPlayingInfo!=output)
-        {
-          changed=true;
-          lastPlayingInfo=output;
-        }
-        if (justChange && !changed)
-         return SetResponse(openTag+"Changed:False");
-        //if still here, continue collecting info
-      }
-      thumb=g_infoManager.GetImage(VIDEOPLAYER_COVER, (DWORD)-1);
-
-      copyThumb(thumb,thumbFn);
-      output+=closeTag+openTag+"Thumb"+tag+":"+thumb;
-    }
-    else if (g_application.IsPlayingAudio())
-    { // Audio information
-      tmp.Format("%i",g_playlistPlayer.GetCurrentSong());
-      output+=closeTag+openTag+"SongNo:"+tmp;  // current item # in playlist
-      output+=closeTag+openTag+"Type"+tag+":Audio";
-      const CMusicInfoTag* tagVal=g_infoManager.GetCurrentSongTag();
-      if (tagVal && !tagVal->GetTitle().IsEmpty())
-        output+=closeTag+openTag+"Title"+tag+":"+tagVal->GetTitle();
-      if (tagVal && tagVal->GetTrackNumber())
-      {
-        CStdString tmp;
-        tmp.Format("%i",(int)tagVal->GetTrackNumber());
-        output+=closeTag+openTag+"Track"+tag+":"+tmp;
-      }
-      if (tagVal && !tagVal->GetArtist().empty())
-        output+=closeTag+openTag+"Artist"+tag+":"+StringUtils::Join(tagVal->GetArtist(), g_advancedSettings.m_musicItemSeparator);
-      if (tagVal && !tagVal->GetAlbum().IsEmpty())
-        output+=closeTag+openTag+"Album"+tag+":"+tagVal->GetAlbum();
-      //now have enough info to check for a change
-      if (lastPlayingInfo!=output)
-      {
-        changed=true;
-        lastPlayingInfo=output;
-      }
-      if (justChange && !changed && !slideChanged)
-        return SetResponse(openTag+"Changed:False");
-      //if still here, continue collecting info
-      if (tagVal && !tagVal->GetGenre().empty())
-        output+=closeTag+openTag+"Genre"+tag+":"+StringUtils::Join(tagVal->GetGenre(), g_advancedSettings.m_musicItemSeparator);
-      if (tagVal && tagVal->GetYear())
-        output+=closeTag+openTag+"Year"+tag+":"+tagVal->GetYearString();
-      if (tagVal && tagVal->GetURL())
-        output+=closeTag+openTag+"URL"+tag+":"+tagVal->GetURL();
-      if (tagVal && g_infoManager.GetMusicLabel(MUSICPLAYER_LYRICS))
-        output+=closeTag+openTag+"Lyrics"+tag+":"+g_infoManager.GetMusicLabel(MUSICPLAYER_LYRICS);
-
-      // TODO: Should this be a tagitem member?? (wouldn't have vbr updates though)
-      CStdString bitRate(g_infoManager.GetMusicLabel(MUSICPLAYER_BITRATE)); 
-      // TODO: This should be a static tag item
-      CStdString sampleRate(g_infoManager.GetMusicLabel(MUSICPLAYER_SAMPLERATE));
-      if (!bitRate.IsEmpty())
-        output+=closeTag+openTag+"Bitrate"+tag+":"+bitRate;  
-      if (!sampleRate.IsEmpty())
-        output+=closeTag+openTag+"Samplerate"+tag+":"+sampleRate;  
-      thumb=g_infoManager.GetImage(MUSICPLAYER_COVER, (DWORD)-1);
-      copyThumb(thumb,thumbFn);
-      output+=closeTag+openTag+"Thumb"+tag+":"+thumb;
-    }
-    output+=closeTag+openTag+"Time:"+g_infoManager.GetCurrentPlayTime();
-    output+=closeTag+openTag+"Duration:";
-    output += g_infoManager.GetDuration();
-    tmp.Format("%i",(int)g_application.GetPercentage());
-    output+=closeTag+openTag+"Percentage:"+tmp;
-    // file size
-    if (!fileItem.m_dwSize)
-      fileItem.m_dwSize = fileSize(fileItem.GetPath());
-    if (fileItem.m_dwSize)
-    {
-      tmp.Format("%"PRId64,fileItem.m_dwSize);
-      output+=closeTag+openTag+"File size:"+tmp;
-    }
-    if (changed)
-      output+=closeTag+openTag+"Changed:True";
-    else  
-      output+=closeTag+openTag+"Changed:False";
-  }
-  if (extended && slideOutput!="")
-    return SetResponse(slideOutput+closeTag+output);
-  else
-    return SetResponse(output);
-}
-
-int CXbmcHttp::xbmcGetMusicLabel(int numParas, CStdString paras[])
-{
-  if (numParas<1)
-    return SetResponse(openTag+"Error:Missing Parameter");
-  else
-  {
-    int item=(int)atoi(paras[0].c_str());
-    return SetResponse(openTag+g_infoManager.GetMusicLabel(item));
-  }
-}
-
-int CXbmcHttp::xbmcGetVideoLabel(int numParas, CStdString paras[])
-{
-  if (numParas<1)
-    return SetResponse(openTag+"Error:Missing Parameter");
-  else
-  {
-    int item=(int)atoi(paras[0].c_str());
-    return SetResponse(openTag+g_infoManager.GetVideoLabel(item));
-  }
-}
-
-int CXbmcHttp::xbmcGetPercentage()
-{
-  if (g_application.m_pPlayer)
-  {
-    CStdString tmp;
-    tmp.Format("%i",(int)g_application.GetPercentage());
-    return SetResponse(openTag + tmp ) ;
-  }
-  else
-    return SetResponse(openTag+"Error");
-}
-
-int CXbmcHttp::xbmcSeekPercentage(int numParas, CStdString paras[], bool relative)
-{
-  if (numParas<1)
-    return SetResponse(openTag+"Error:Missing Parameter");
-  else
-  {
-    if (g_application.m_pPlayer)
-    {
-      float percent=(float)atof(paras[0].c_str());
-      if (relative)
-      {
-        double newPos = g_application.GetTime() + percent * 0.01 * g_application.GetTotalTime();
-        if ((newPos>=0) && (newPos/1000<=g_infoManager.GetTotalPlayTime()))
-        {
-          g_application.SeekTime(newPos);
-          return SetResponse(openTag+"OK");
-        }
-        else
-          return SetResponse(openTag+"Error:Out of range");
-      }
-      else
-      {
-        g_application.SeekPercentage(percent);
-        return SetResponse(openTag+"OK");
-      }
-    }
-    else
-      return SetResponse(openTag+"Error:Loading mPlayer");
-  }
-}
-
-int CXbmcHttp::xbmcMute()
-{
-  g_application.ToggleMute();
-  return SetResponse(openTag+"OK");
-}
-
-int CXbmcHttp::xbmcSetVolume(int numParas, CStdString paras[])
-{
-  if (numParas<1)
-    return SetResponse(openTag+"Error:Missing Parameter");
-  else
-  {
-    int iPercent = atoi(paras[0].c_str());
-    g_application.SetVolume((float)iPercent, true);
-    return SetResponse(openTag+"OK");
-  }
-}
-
-int CXbmcHttp::xbmcGetVolume()
-{
-  CStdString tmp;
-  tmp.Format("%i",g_application.GetVolume());
-  return SetResponse(openTag + tmp);
-}
-
-int CXbmcHttp::xbmcClearSlideshow()
-{
-  CGUIWindowSlideShow *pSlideShow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
-  if (!pSlideShow)
-    return SetResponse(openTag+"Error:Could not create slideshow");
-  else
-  {
-    pSlideShow->Reset();
-    return SetResponse(openTag+"OK");
-  }
-}
-
-int CXbmcHttp::xbmcPlaySlideshow(int numParas, CStdString paras[])
-{ // (filename(;1)) -> 1 indicates recursive
-  // TODO: add suoport for new random and notrandom options
-  unsigned int recursive = 0;
-  if (numParas>1 && paras[1].Equals("1"))
-    recursive=1;
-  CGUIMessage msg(GUI_MSG_START_SLIDESHOW, 0, 0, recursive);
-  if (numParas==0)
-    msg.SetStringParam("");
-  else
-    msg.SetStringParam(paras[0]);
-  CGUIWindow *pWindow = g_windowManager.GetWindow(WINDOW_SLIDESHOW);
-  if (pWindow) pWindow->OnMessage(msg);
-  return SetResponse(openTag+"OK");
-}
-
-int CXbmcHttp::xbmcSlideshowSelect(int numParas, CStdString paras[])
-{
-  if (numParas<1)
-    return SetResponse(openTag+"Error:Missing filename");
-  else
-  {
-    CGUIWindowSlideShow *pSlideShow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
-    if (!pSlideShow)
-      return SetResponse(openTag+"Error:Could not create slideshow");
-    else
-    {
-      pSlideShow->Select(paras[0]);
-      return SetResponse(openTag+"OK");
-    }
-  }
-}
-
-int CXbmcHttp::xbmcAddToSlideshow(int numParas, CStdString paras[])
-//filename;mask;recursive=1
-{
-  CStdString mask="";
-  bool recursive=true;
-  if (numParas<1)
-    return SetResponse(openTag+"Error:Missing parameter");
-  if (numParas>1)
-    mask=procMask(paras[1]);
-  if (numParas>2)
-    recursive=paras[2]=="1";
-  CFileItemPtr pItem(new CFileItem(paras[0]));
-  pItem->m_bIsShareOrDrive=false;
-  pItem->SetPath(paras[0]);
-  // if its not a picture type, test to see if its a folder
-  if (!pItem->IsPicture())
-  {
-    IDirectory *pDirectory = CDirectoryFactory::Create(pItem->GetPath());
-    if (!pDirectory)
-      return SetResponse(openTag+"Error");  
-    bool bResult=pDirectory->Exists(pItem->GetPath());
-    pItem->m_bIsFolder=bResult;
-  }
-  AddItemToPlayList(pItem, -1, 0, mask, recursive); //add to slideshow
-  return SetResponse(openTag+"OK");
-}
-
-int CXbmcHttp::xbmcSetPlaySpeed(int numParas, CStdString paras[])
-{
-  if (numParas>0) {
-    g_application.SetPlaySpeed(atoi(paras[0]));
-    return SetResponse(openTag+"OK");
-  }
-  else
-    return SetResponse(openTag+"Error:Missing parameter");
-}
-
-int CXbmcHttp::xbmcGetPlaySpeed()
-{
-  CStdString strSpeed;
-  strSpeed.Format("%i", g_application.GetPlaySpeed());
-  return SetResponse(openTag + strSpeed );
-}
-
-int CXbmcHttp::xbmcGetGUIDescription()
-{
-  CStdString strWidth, strHeight;
-  strWidth.Format("%i", g_graphicsContext.GetWidth());
-  strHeight.Format("%i", g_graphicsContext.GetHeight());
-  return SetResponse(openTag+"Width:" + strWidth + closeTag+openTag+"Height:" + strHeight  );
-}
-
-int CXbmcHttp::xbmcGetGUIStatus()
-{
-  CStdString output, tmp, strTmp;
-  CGUIMediaWindow *mediaWindow = (CGUIMediaWindow *)g_windowManager.GetWindow(WINDOW_MUSIC_FILES);
-  if (mediaWindow)
-    output = closeTag+openTag+"MusicPath:" + mediaWindow->CurrentDirectory().GetPath();
-  mediaWindow = (CGUIMediaWindow *)g_windowManager.GetWindow(WINDOW_VIDEO_FILES);
-  if (mediaWindow)
-    output += closeTag+openTag+"VideoPath:" + mediaWindow->CurrentDirectory().GetPath();
-  mediaWindow = (CGUIMediaWindow *)g_windowManager.GetWindow(WINDOW_PICTURES);
-  if (mediaWindow)
-    output += closeTag+openTag+"PicturePath:" + mediaWindow->CurrentDirectory().GetPath();
-  mediaWindow = (CGUIMediaWindow *)g_windowManager.GetWindow(WINDOW_PROGRAMS);
-  if (mediaWindow)
-    output += closeTag+openTag+"ProgramsPath:" + mediaWindow->CurrentDirectory().GetPath();
-  CGUIWindowFileManager *fileManager = (CGUIWindowFileManager *)g_windowManager.GetWindow(WINDOW_FILES);
-  if (fileManager)
-  {
-    output += closeTag+openTag+"FilesPath1:" + fileManager->CurrentDirectory(0).GetPath();
-    output += closeTag+openTag+"FilesPath2:" + fileManager->CurrentDirectory(1).GetPath();
-  }
-  int iWin=g_windowManager.GetActiveWindow();
-  CGUIWindow* pWindow=g_windowManager.GetWindow(iWin);  
-  tmp.Format("%i", iWin);
-  output += openTag+"ActiveWindow:" + tmp;
-  if (pWindow)
-  {
-    output += closeTag+openTag+"ActiveWindowName:" + g_localizeStrings.Get(iWin) ; 
-    CGUIControl* pControl=pWindow->GetFocusedControl();
-    if (pControl)
-    {
-      CStdString id;
-      id.Format("%d",(int)pControl->GetID());
-      output += closeTag+openTag+"ControlId:" + id;
-      strTmp = pControl->GetDescription();
-      if (pControl->GetControlType() == CGUIControl::GUICONTROL_BUTTON)
-      {
-        output += closeTag+openTag+"Type:Button";
-        if (strTmp!="")
-          output += closeTag+openTag+"Description:" + strTmp;
-        if (((CGUIButtonControl *)pControl)->HasClickActions())
-          output += closeTag+openTag+"Execution:" + ((CGUIButtonControl *)pControl)->GetClickActions().GetFirstAction();
-      }
-      else if (pControl->GetControlType() == CGUIControl::GUICONTROL_SPIN)
-      {
-        output += closeTag+openTag+"Type:Spin"+closeTag+openTag+"Description:" + strTmp;
-      }
-    }
-  }
-  return SetResponse(output);
-}
-
-int CXbmcHttp::xbmcGetThumb(int numParas, CStdString paras[], bool bGetThumb)
-{
-  CStdString thumb="";
-  int linesize=80;
-  if (numParas<1)
-    return SetResponse(openTag+"Error:Missing parameter");
-  bool bImgTag=false;
-  // only allow the old GetThumb command to accept "imgtag"
-  if (bGetThumb && numParas==2 && paras[1].Equals("imgtag"))
-  {
-    bImgTag=true;
-    thumb="<img src=\"data:image/jpg;base64,";
-    linesize=0;
-  }
-  if (numParas>1)
-     tempSkipWebFooterHeader=paras[1].ToLower() == "bare";
-  if (numParas>2)
-     tempSkipWebFooterHeader=paras[2].ToLower() == "bare";
-  if (URIUtils::IsRemote(paras[0]))
-  {
-    CStdString strDest="special://temp/xbmcDownloadFile.tmp";
-    CFile::Cache(paras[0], strDest, NULL, NULL) ;
-    if (CFile::Exists(strDest))
-    {
-      thumb+=encodeFileToBase64(strDest,linesize);
-      CFile::Delete(strDest);
-    }
-    else
-    {
-      return SetResponse(openTag+"Error");
-    }
-  }
-  else
-    thumb+=encodeFileToBase64(paras[0],linesize);
-
-  if (bImgTag)
-  {
-    thumb+="\" alt=\"Your browser doesnt support this\" title=\"";
-    thumb+=paras[0];
-    thumb+="\">";
-  }
-  return SetResponse(thumb) ;
-}
-
-int CXbmcHttp::xbmcGetThumbFilename(int numParas, CStdString paras[])
-{
-  return SetResponse(openTag+"Error:Deprecated function") ;
-}
-
-int CXbmcHttp::xbmcPlayerPlayFile(int numParas, CStdString paras[])
-{
-  int iPlaylist = g_playlistPlayer.GetCurrentPlaylist();
-  if (numParas<1)
-    return SetResponse(openTag+"Error:Missing file parameter");
-  if (numParas>1)
-    iPlaylist = atoi(paras[1]);
-  CFileItem item(paras[0], FALSE);
-  if (iPlaylist == PLAYLIST_NONE)
-    iPlaylist = PLAYLIST_MUSIC;
-  if (item.IsPlayList())
-  {
-    LoadPlayList(paras[0], iPlaylist, true, true);
-    CStdString strPlaylist;
-    strPlaylist.Format("%i", iPlaylist);
-    return SetResponse(openTag+"OK:Playlist="+strPlaylist);
-  }
-  else
-  {
-    CApplicationMessenger::Get().MediaPlay(paras[0]);
-    if(g_application.IsPlaying())
-      return SetResponse(openTag+"OK");
-  }
-  return SetResponse(openTag+"Error:Could not play file");
-}
-
-int CXbmcHttp::xbmcGetCurrentPlayList()
-{
-  CStdString tmp;
-  tmp.Format("%i", g_playlistPlayer.GetCurrentPlaylist());
-  return SetResponse(openTag + tmp  );
-}
-
-int CXbmcHttp::xbmcSetCurrentPlayList(int numParas, CStdString paras[])
-{
-  if (numParas<1) 
-    return SetResponse(openTag+"Error:Missing playlist") ;
-  else {
-    g_playlistPlayer.SetCurrentPlaylist(atoi(paras[0].c_str()));
-    return SetResponse(openTag+"OK") ;
-  }
-}
-
-int CXbmcHttp::xbmcGetPlayListContents(int numParas, CStdString paras[])
-{
-  // option = showindex -> index;path
-  // option = showtitle -> path;tracktitle
-  // option = showduration -> path;duration
-
-  CStdString list="";
-  int playList = g_playlistPlayer.GetCurrentPlaylist();
-  bool bShowIndex = false;
-  bool bShowTitle = false;
-  bool bShowDuration = false;
-  for (int i = 0; i < numParas; ++i)
-  {
-    if (paras[i].Equals("showindex"))
-      bShowIndex = true;
-    else if (paras[i].Equals("showtitle"))
-      bShowTitle = true;
-    else if (paras[i].Equals("showduration"))
-      bShowDuration = true;
-    else if (StringUtils::IsNaturalNumber(paras[i]))
-      playList = atoi(paras[i]);
-  }
-  CPlayList& thePlayList = g_playlistPlayer.GetPlaylist(playList);
-  if (thePlayList.size()==0)
-    list=openTag+"[Empty]" ;
-  bool bIsMusic = (playList == PLAYLIST_MUSIC);
-  bool bIsVideo = (playList == PLAYLIST_VIDEO);
-  for (int i = 0; i < thePlayList.size(); i++)
-  {
-    CFileItemPtr item = thePlayList[i];
-    const CMusicInfoTag* tagVal = NULL;
-    const CVideoInfoTag* tagVid = NULL;
-    if (bIsMusic)
-      tagVal = item->GetMusicInfoTag();
-    if (bIsVideo)
-      tagVid = item->GetVideoInfoTag();
-    CStdString strInfo;
-    if (bShowIndex)
-      strInfo.Format("%i;", i);
-    if (tagVal && tagVal->GetURL()!="")
-      strInfo += tagVal->GetURL();
-    else
-      strInfo += item->GetPath();
-    if (bShowTitle)
-    {
-      if (tagVal)
-        strInfo += ';' + tagVal->GetTitle();
-      else if (tagVid)
-        strInfo += ';' + tagVid->m_strTitle;
-    }
-    if (bShowDuration)
-    {
-      CStdString duration;
-      if (tagVal)
-        duration = StringUtils::SecondsToTimeString(tagVal->GetDuration(), TIME_FORMAT_GUESS);
-      else if (tagVid)
-        duration = tagVid->m_strRuntime;
-      if (!duration.IsEmpty())
-        strInfo += ';' + duration;
-    }
-    list += closeTag + openTag + strInfo;
-  }
-  return SetResponse(list) ;
-}
-
-int CXbmcHttp::xbmcGetPlayListLength(int numParas, CStdString paras[])
-{
-  int playList;
-
-  if (numParas<1) 
-    playList=g_playlistPlayer.GetCurrentPlaylist();
-  else
-    playList=atoi(paras[0]);
-  CPlayList& thePlayList = g_playlistPlayer.GetPlaylist(playList);
-
-  CStdString tmp;
-  tmp.Format("%i", thePlayList.size());
-  return SetResponse(openTag + tmp );
-}
-
-int CXbmcHttp::xbmcGetSlideshowContents()
-{
-  CStdString list="";
-  CGUIWindowSlideShow *pSlideShow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
-  if (!pSlideShow)
-    return SetResponse(openTag+"Error");
-  else
-  {
-    const CFileItemList &slideshowContents = pSlideShow->GetSlideShowContents();
-    if (slideshowContents.Size()==0)
-      list=openTag+"[Empty]" ;
-    else
-    for (int i = 0; i < slideshowContents.Size(); ++i)
-      list += closeTag+openTag + slideshowContents[i]->GetPath();
-    return SetResponse(list) ;
-  }
-}
-
-int CXbmcHttp::xbmcGetPlayListSong(int numParas, CStdString paras[])
-{
-  CStdString Filename;
-  int iSong;
-
-  if (numParas<1) 
-  {
-    CStdString tmp;
-    tmp.Format("%i", g_playlistPlayer.GetCurrentSong());
-    return SetResponse(openTag + tmp );
-  }
-  else {
-    CPlayList thePlayList;
-    iSong=atoi(paras[0]);  
-    if (iSong!=-1){
-      thePlayList=g_playlistPlayer.GetPlaylist( g_playlistPlayer.GetCurrentPlaylist() );
-      if (thePlayList.size()>iSong) {
-        Filename=thePlayList[iSong]->GetPath();
-        return SetResponse(openTag + Filename );
-      }
-    }
-  }
-  return SetResponse(openTag+"Error");
-}
-
-int CXbmcHttp::xbmcSetPlayListSong(int numParas, CStdString paras[])
-{
-  if (numParas<1)
-    return SetResponse(openTag+"Error:Missing song number");
-  else
-  {
-    g_playlistPlayer.Play(atoi(paras[0].c_str()));
-    return SetResponse(openTag+"OK");
-  }
-}
-
-int CXbmcHttp::xbmcPlayListNext()
-{
-  g_playlistPlayer.PlayNext();
-  return SetResponse(openTag+"OK");
-}
-
-int CXbmcHttp::xbmcPlayListPrev()
-{
-  g_playlistPlayer.PlayPrevious();
-  return SetResponse(openTag+"OK");
-}
-
-int CXbmcHttp::xbmcRemoveFromPlayList(int numParas, CStdString paras[])
-{
-  if (numParas > 0)
-  {
-    int iPlaylist = g_playlistPlayer.GetCurrentPlaylist();
-    CStdString strItem = paras[0];
-    int itemToRemove;
-    if (numParas > 1)
-      iPlaylist = atoi(paras[1]);
-    if (StringUtils::IsNaturalNumber(strItem))
-      itemToRemove=atoi(strItem);
-    else
-      itemToRemove=FindPathInPlayList(iPlaylist, strItem);
-    // The current playing song can't be removed
-    if (g_playlistPlayer.GetCurrentPlaylist() == PLAYLIST_MUSIC && g_application.IsPlayingAudio()
-      && g_playlistPlayer.GetCurrentSong() == itemToRemove)
-      return SetResponse(openTag+"Error:Can't remove current playing song");
-    if (itemToRemove<0 || itemToRemove>=g_playlistPlayer.GetPlaylist(iPlaylist).size())
-      return SetResponse(openTag+"Error:Item not found or parameter out of range");
-    g_playlistPlayer.Remove(PLAYLIST_MUSIC, itemToRemove);
-    return SetResponse(openTag+"OK");
-  }
-  else
-    return SetResponse(openTag+"Error:Missing parameter");
-}
-
-CStdString CXbmcHttp::GetOpenTag()
-{
-  return openTag;
-}
-
-CStdString CXbmcHttp::GetCloseTag()
-{
-  return closeTag;
-}
-
-CKey CXbmcHttp::GetKey()
-{
-  if (repeatKeyRate!=0)
-    if ((XbmcThreads::SystemClockMillis() - MarkTime) >=  repeatKeyRate)
-    {
-      MarkTime=XbmcThreads::SystemClockMillis();
-      key=lastKey;
-    }
-  return key;
-}
-
-void CXbmcHttp::ResetKey()
-{
-  CKey newKey;
-  key = newKey;
-}
-
-int CXbmcHttp::xbmcSetKey(int numParas, CStdString paras[])
-{
-  uint32_t buttonCode=0;
-  uint8_t leftTrigger=0, rightTrigger=0;
-  float fLeftThumbX=0.0f, fLeftThumbY=0.0f, fRightThumbX=0.0f, fRightThumbY=0.0f ;
-  if (numParas<1)
-    return SetResponse(openTag+"Error:Missing parameters");
-  else
-  {
-    buttonCode=(uint32_t) strtol(paras[0], NULL, 0);
-    if (numParas>1) {
-      leftTrigger=(uint8_t) atoi(paras[1]) ;
-      if (numParas>2) {
-        rightTrigger=(uint8_t) atoi(paras[2]) ;
-        if (numParas>3) {
-          fLeftThumbX=(float) atof(paras[3]) ;
-          if (numParas>4) {
-            fLeftThumbY=(float) atof(paras[4]) ;
-            if (numParas>5) {
-              fRightThumbX=(float) atof(paras[5]) ;
-              if (numParas>6)
-                fRightThumbY=(float) atof(paras[6]) ;
-            }
-          }
-        }
-      }
-    }
-    CKey tempKey(buttonCode, leftTrigger, rightTrigger, fLeftThumbX, fLeftThumbY, fRightThumbX, fRightThumbY) ;
-    tempKey.SetFromService(true);
-    key = tempKey;
-    lastKey = key;
-    return SetResponse(openTag+"OK");
-  }
-}
-
-int CXbmcHttp::xbmcSetKeyRepeat(int numParas, CStdString paras[])
-{
-  if (numParas!=1)
-    return SetResponse(openTag+"Error:Should be only one parameter");
-  else
-  {
-    repeatKeyRate = atoi(paras[0]);
-    return SetResponse(openTag+"OK");
-  }
-}
-
-int CXbmcHttp::xbmcAction(int numParas, CStdString paras[], int theAction)
-{
-  bool showingSlideshow=(g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW);
-
-  switch(theAction)
-  {
-  case 1:
-  case 8:
-    if (showingSlideshow && theAction!=8) {
-      CGUIWindowSlideShow *pSlideShow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
-      if (pSlideShow)
-        pSlideShow->OnAction(CAction(ACTION_PAUSE));
-    }
-    else
-      CApplicationMessenger::Get().MediaPause();
-    return SetResponse(openTag+"OK");
-    break;
-  case 2:
-  case 9:
-    if (showingSlideshow && theAction!=9) {
-      CGUIWindowSlideShow *pSlideShow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
-      if (pSlideShow)
-        pSlideShow->OnAction(CAction(ACTION_STOP));
-    }
-    else
-      CApplicationMessenger::Get().MediaStop();
-    return SetResponse(openTag+"OK");
-    break;
-  case 3:
-  case 10:
-    if (showingSlideshow && theAction!=10) {
-      CGUIWindowSlideShow *pSlideShow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
-      if (pSlideShow)
-        pSlideShow->OnAction(CAction(ACTION_NEXT_PICTURE));
-    }
-    else
-      g_playlistPlayer.PlayNext();
-    return SetResponse(openTag+"OK");
-    break;
-  case 4:
-  case 11:
-    if (showingSlideshow && theAction!=11) {
-      CGUIWindowSlideShow *pSlideShow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
-      if (pSlideShow)
-        pSlideShow->OnAction(CAction(ACTION_PREV_PICTURE));
-    }
-    else
-      g_playlistPlayer.PlayPrevious();
-    return SetResponse(openTag+"OK");
-    break;
-  case 5:
-    if (showingSlideshow)
-    {
-      CGUIWindowSlideShow *pSlideShow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
-      if (pSlideShow) {
-        pSlideShow->OnAction(CAction(ACTION_ROTATE_PICTURE_CW));
-        return SetResponse(openTag+"OK");
-      }
-      else
-        return SetResponse(openTag+"Error");
-    }
-    else
-      return SetResponse(openTag+"Error");
-    break;
-  case 6:
-    if (showingSlideshow)
-    {
-      CGUIWindowSlideShow *pSlideShow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
-      if (pSlideShow) {
-        if (numParas>1) {
-          CAction action(ACTION_ANALOG_MOVE, (float)atof(paras[0]), (float)atof(paras[1]));
-          pSlideShow->OnAction(action);
-          return SetResponse(openTag+"OK");
-        }
-        else
-          return SetResponse(openTag+"Error:Missing parameters");
-      }
-      else
-        return SetResponse(openTag+"Error");
-    }
-    else
-      return SetResponse(openTag+"Error");
-    break;
-  case 7:
-    if (showingSlideshow)
-    {
-      CGUIWindowSlideShow *pSlideShow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
-      if (pSlideShow) {
-        if (numParas>0)
-        {
-          pSlideShow->OnAction(CAction(ACTION_ZOOM_LEVEL_NORMAL+atoi(paras[0])));
-          return SetResponse(openTag+"OK");
-        }
-        else
-          return SetResponse(openTag+"Error:Missing parameters");
-      }
-      else
-        return SetResponse(openTag+"Error");
-    }
-    else
-      return SetResponse(openTag+"Error");
-    break;
-  default:
-    return SetResponse(openTag+"Error");
-  }
-}
-
-int CXbmcHttp::xbmcExit(int theAction)
-{
-  if (theAction>0 && theAction<6)
-  {
-    SetResponse(openTag+"OK");
-    shuttingDown=true;
-    return theAction;
-  }
-  else
-    return SetResponse(openTag+"Error");
-}
-
-int CXbmcHttp::xbmcLookupAlbum(int numParas, CStdString paras[])
-// paras: album
-//        album, artist
-//        album, artist, 1
-{
-  CStdString albums="", album, artist="", tmp;
-  double relevance;
-  bool rel = false;
-  AddonPtr addon;
-  if (!CAddonMgr::Get().GetDefault(ADDON_SCRAPER_ALBUMS, addon))
-    return -1;
-  ScraperPtr info = boost::dynamic_pointer_cast<CScraper>(addon);
-  if (!info)
-    return -1;
-
-  CMusicInfoScraper scraper(info); 
-
-  info->ClearCache();
-
-  if (numParas<1)
-    return SetResponse(openTag+"Error:Missing album name");
-  else
-  {
-    try
-    {
-      int cnt=0;
-      album=paras[0];
-      if (numParas>1)
-      {
-        artist = paras[1];
-        scraper.FindAlbumInfo(album, artist);
-        if (numParas>2)
-          rel = (paras[2]=="1");
-      }
-      else
-        scraper.FindAlbumInfo(album);
-      //wait a max of 20s
-      while (!scraper.Completed() && cnt++<200)
-        Sleep(100);
-      if (scraper.Succeeded())
-      {
-        // did we find at least 1 album?
-        int iAlbumCount=scraper.GetAlbumCount();
-        if (iAlbumCount >=1)
-        {
-          for (int i=0; i < iAlbumCount; ++i)
-          {
-            CMusicAlbumInfo& info = scraper.GetAlbum(i);
-            albums += closeTag+openTag + info.GetTitle2() + "<@@>" + info.GetAlbumURL().m_url[0].m_url;
-            if (rel)
-            {
-              relevance = CUtil::AlbumRelevance(info.GetAlbum().strAlbum, album, StringUtils::Join(info.GetAlbum().artist, g_advancedSettings.m_musicItemSeparator), artist);
-              tmp.Format("%f",relevance);
-              albums += "<@@@>"+tmp;
-            }
-          }
-          return SetResponse(albums) ;
-        }
-        else
-          return SetResponse(openTag+"Error:No albums found") ;
-      }
-      else
-        return SetResponse(openTag+"Error:Scraping") ;
-    }
-    catch (...)
-    {
-      return SetResponse(openTag+"Error");
-    }
-  }
-}
-
-int CXbmcHttp::xbmcChooseAlbum(int numParas, CStdString paras[])
-{
-  CStdString output="";
-
-  if (numParas<1)
-    return SetResponse(openTag+"Error:Missing album name");
-  else
-    try
-    {
-      CMusicAlbumInfo musicInfo;//("", "") ;
-      XFILE::CCurlFile http;
-      ScraperPtr info; // TODO - WTF is this code supposed to do?
-      if (musicInfo.Load(http,info))
-      {
-        if (musicInfo.GetAlbum().thumbURL.m_url.size() > 0)
-         output=openTag+"image:" + musicInfo.GetAlbum().thumbURL.m_url[0].m_url;
-
-        output+=closeTag+openTag+"review:" + musicInfo.GetAlbum().strReview;
-        return SetResponse(output) ;
-      }
-      else
-        return SetResponse(openTag+"Error:Loading musinInfo");
-    }
-    catch (...)
-    {
-      return SetResponse(openTag+"Error:Exception");
-    }
-}
-
-int CXbmcHttp::xbmcDownloadInternetFile(int numParas, CStdString paras[])
-{
-  CStdString src, dest="";
-
-  if (numParas<1)
-    return SetResponse(openTag+"Error:Missing parameter");
-  else
-  {
-    src=paras[0];
-    if (numParas>1)
-      dest=paras[1];
-    if (dest=="")
-      dest="special://temp/xbmcDownloadInternetFile.tmp" ;
-    if (src=="")
-      return SetResponse(openTag+"Error:Missing parameter");
-    else
-    {
-      try
-      {
-        if (numParas>1)
-          tempSkipWebFooterHeader=paras[1].ToLower() == "bare";
-        if (numParas>2)
-          tempSkipWebFooterHeader=paras[2].ToLower() == "bare";
-        XFILE::CCurlFile http;
-        http.Download(src, dest);
-        CStdString encoded="";
-        encoded=encodeFileToBase64(dest, 80);
-        if (encoded=="")
-          return SetResponse(openTag+"Error:Nothing downloaded");
-        {
-          if (dest=="special://temp/xbmcDownloadInternetFile.tmp")
-            CFile::Delete(dest);
-          return SetResponse(encoded) ;
-        }
-      }
-      catch (...)
-      {
-        return SetResponse(openTag+"Error:Exception");
-      }
-    }
-  }
-}
-
-int CXbmcHttp::xbmcSetFile(int numParas, CStdString paras[])
-//parameter = destFilename ; base64String ; ( first | continue | last )
-{
-  if (numParas<2)
-    return SetResponse(openTag+"Error:Missing parameter");
-  else
-  {
-    paras[1].Replace(" ","+");
-    CStdString tmpFile = "special://temp/xbmcTemp.tmp";
-    if (numParas>2)
-    {
-      if (paras[2].ToLower() == "first")
-        decodeBase64ToFile(paras[1], tmpFile);
-      else if (paras[2].ToLower() == "continue")
-        decodeBase64ToFile(paras[1], tmpFile, true);
-      else if (paras[2].ToLower() == "last")
-      {
-        decodeBase64ToFile(paras[1], tmpFile, true);
-        CFile::Cache(tmpFile, paras[0].c_str(), NULL, NULL) ;
-        CFile::Delete(tmpFile);
-      }
-      else
-        return  SetResponse(openTag+"Error:Unknown 2nd parameter");
-    }
-    else
-    {
-      decodeBase64ToFile(paras[1], tmpFile);
-      CFile::Cache(tmpFile, paras[0].c_str(), NULL, NULL) ;
-      CFile::Delete(tmpFile);
-    }
-    return SetResponse(openTag+"OK");
-  }
-}
-
-int CXbmcHttp::xbmcCopyFile(int numParas, CStdString paras[])
-//parameter = srcFilename ; destFilename
-// both file names are relative to the server, not the calling client
-{
-  if (numParas<2)
-    return SetResponse(openTag+"Error:Missing parameter");
-  else
-  {
-    if (CFile::Exists(paras[0].c_str()))
-    {
-      CFile::Cache(paras[0].c_str(), paras[1].c_str(), NULL, NULL) ;
-      return SetResponse(openTag+"OK");
-    }
-    else
-      return SetResponse(openTag+"Error:Source file not found");
-  }
-}
-
-
-int CXbmcHttp::xbmcFileSize(int numParas, CStdString paras[])
-{
-  if (numParas<1)
-    return SetResponse(openTag+"Error:Missing parameter");
-  else
-  {
-    int64_t filesize=fileSize(paras[0]);
-    if (filesize>-1)
-    {
-      CStdString tmp;
-      tmp.Format("%"PRId64,filesize);
-      return SetResponse(openTag+tmp);
-    }
-    else
-      return SetResponse(openTag+"Error:Source file not found");
-  }
-}
-
-int CXbmcHttp::xbmcDeleteFile(int numParas, CStdString paras[])
-{
-  if (numParas<1) 
-    return SetResponse(openTag+"Error:Missing parameter");
-  else
-  {
-    try
-    {
-      if (CFile::Exists(paras[0]))
-      {
-        CFile::Delete(paras[0]);
-        return SetResponse(openTag+"OK");
-      }
-      else
-        return SetResponse(openTag+"Error:File not found");
-    }
-    catch (...)
-    {
-      return SetResponse(openTag+"Error");
-    }
-  }
-}
-
-int CXbmcHttp::xbmcFileExists(int numParas, CStdString paras[])
-{
-  if (numParas<1) 
-    return SetResponse(openTag+"Error:Missing parameter");
-  else
-  {
-    try
-    {
-      if (CFile::Exists(paras[0]))
-      {
-        return SetResponse(openTag+"True");
-      }
-      else
-        return SetResponse(openTag+"False");
-    }
-    catch (...)
-    {
-      return SetResponse(openTag+"Error");
-    }
-  }
-}
-
-int CXbmcHttp::xbmcShowPicture(int numParas, CStdString paras[])
-{
-  if (numParas<1) 
-    return SetResponse(openTag+"Error:Missing parameter");
-  else
-  {
-    if (!playableFile(paras[0]))
-      return SetResponse(openTag+"Error:Unable to open file");
-    CApplicationMessenger::Get().PictureShow(paras[0]);
-    return SetResponse(openTag+"OK");
-  }
-}
-
-int CXbmcHttp::xbmcGetCurrentSlide()
-{
-  CGUIWindowSlideShow *pSlideShow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
-  if (!pSlideShow)
-    return SetResponse(openTag+"Error:Could not access slideshown");
-  else
-  {
-    const CFileItemPtr slide=pSlideShow->GetCurrentSlide();
-    if (!slide)
-      return SetResponse(openTag + "[None]");
-    return SetResponse(openTag + slide->GetPath());
-  }
-}
-
-int CXbmcHttp::xbmcExecBuiltIn(int numParas, CStdString paras[])
-{
-  if (numParas<1) 
-    return SetResponse(openTag+"Error:Missing parameter");
-  else
-  {
-    CApplicationMessenger::Get().ExecBuiltIn(paras[0]);
-    return SetResponse(openTag+"OK");
-  }
-}
-
-int CXbmcHttp::xbmcGUISetting(int numParas, CStdString paras[])
-//parameter=type;name(;value)
-//type=0->int, 1->bool, 2->float, 3->string
-{
-  if (numParas<2)
-    return SetResponse(openTag+"Error:Missing parameters");
-  else
-  {
-    paras[1].MakeLower();
-    CStdString tmp;
-    if (numParas<3)
-      switch (atoi(paras[0])) 
-      {
-        case 0:  //  int
-          tmp.Format("%i", g_guiSettings.GetInt(paras[1]));
-          return SetResponse(openTag + tmp );
-          break;
-        case 1: // bool
-          if (g_guiSettings.GetBool(paras[1])==0)
-            return SetResponse(openTag+"False");
-          else
-            return SetResponse(openTag+"True");
-          break;
-        case 2: // float
-          tmp.Format("%f", g_guiSettings.GetFloat(paras[1]));
-          return SetResponse(openTag + tmp);
-          break;
-        case 3: // string
-          tmp.Format("%s", g_guiSettings.GetString(paras[1]));
-          return SetResponse(openTag + tmp);
-          break;
-        default:
-          return SetResponse(openTag+"Error:Unknown type");
-          break;
-      }
-    else
-    {
-      switch (atoi(paras[0])) 
-      {
-        case 0:  //  int
-          g_guiSettings.SetInt(paras[1], atoi(paras[2]));
-          return SetResponse(openTag+"OK");
-          break;
-        case 1: // bool
-          g_guiSettings.SetBool(paras[1], (paras[2].ToLower()=="true"));
-          return SetResponse(openTag+"OK");
-          break;
-        case 2: // float
-          g_guiSettings.SetFloat(paras[1], (float)atof(paras[2]));
-          return SetResponse(openTag+"OK");
-          break;
-        case 3: // string
-          g_guiSettings.SetString(paras[1], paras[2]);
-          return SetResponse(openTag+"OK");
-          break;
-        default:
-          return SetResponse(openTag+"Error:Unknown type");
-          break;
-      }     
-    }
-  }
-  return 0; // not reached
-}
-
-int CXbmcHttp::xbmcSTSetting(int numParas, CStdString paras[])
-{
-  if (numParas<1)
-    return SetResponse(openTag+"Error:Missing parameters");
-  else
-  {
-    CStdString tmp;
-    CStdString strInfo = "";
-    int i;
-    for (i=0; i<numParas; i++)
-    {
-      if (paras[i]=="myvideowatchmode")
-      {
-        CGUIWindow *window = g_windowManager.GetWindow(WINDOW_VIDEO_NAV);
-        int watchMode = (window) ? g_settings.GetWatchMode(((CGUIMediaWindow *)window)->CurrentDirectory().GetContent()) : VIDEO_SHOW_ALL;
-        tmp.Format("%i", watchMode);
-      }
-      else if (paras[i]=="mymusicstartwindow")
-        tmp.Format("%i",g_settings.m_iMyMusicStartWindow);
-      else if (paras[i]=="videostartwindow")
-        tmp.Format("%i",g_settings.m_iVideoStartWindow);
-      else if (paras[i]=="myvideostack")
-        tmp.Format("%i",g_settings.m_videoStacking ? 1 : 0);
-      else if (paras[i]=="additionalsubtitledirectorychecked")
-        tmp.Format("%i",g_settings.iAdditionalSubtitleDirectoryChecked);
-      else if (paras[i]=="httpapibroadcastport")
-        tmp.Format("%i",g_settings.m_HttpApiBroadcastPort);
-      else if (paras[i]=="httpapibroadcastlevel")
-        tmp.Format("%i",g_settings.m_HttpApiBroadcastLevel);
-      else if (paras[i]=="volumelevel")
-        tmp.Format("%i",g_application.GetVolume());
-      else if (paras[i]=="systemtimetotalup")
-        tmp.Format("%i",g_settings.m_iSystemTimeTotalUp);
-      else if (paras[i]=="mute")
-        tmp = (g_settings.m_bMute==0) ? "False" : "True";
-      else if (paras[i]=="startvideowindowed")
-        tmp = (g_settings.m_bStartVideoWindowed==0) ? "False" : "True";
-      else if (paras[i]=="myvideonavflatten")
-        tmp = (g_settings.m_bMyVideoNavFlatten==0) ? "False" : "True";
-      else if (paras[i]=="myvideoplaylistshuffle")
-        tmp = (g_settings.m_bMyVideoPlaylistShuffle==0) ? "False" : "True";
-      else if (paras[i]=="myvideoplaylistrepeat")
-        tmp = (g_settings.m_bMyVideoPlaylistRepeat==0) ? "False" : "True";
-      else if (paras[i]=="mymusicplaylistshuffle")
-        tmp = (g_settings.m_bMyMusicPlaylistShuffle==0) ? "False" : "True";
-      else if (paras[i]=="mymusicplaylistrepeat")
-        tmp = (g_settings.m_bMyMusicPlaylistRepeat==0) ? "False" : "True";
-      else if (paras[i]=="mymusicsongthumbinvis")
-        tmp = (g_settings.m_bMyMusicSongThumbInVis==0) ? "False" : "True";
-      else if (paras[i]=="mymusicsonginfoinvis")
-        tmp = (g_settings.m_bMyMusicSongInfoInVis==0) ? "False" : "True";
-      else if (paras[i]=="zoomamount")
-        tmp.Format("%f", g_settings.m_fZoomAmount);
-      else if (paras[i]=="pixelratio")
-        tmp.Format("%f", g_settings.m_fPixelRatio);
-      else if (paras[i]=="pictureextensions")
-        tmp = g_settings.m_pictureExtensions;
-      else if (paras[i]=="musicextensions")
-        tmp = g_settings.m_musicExtensions;
-      else if (paras[i]=="videoextensions")
-        tmp = g_settings.m_videoExtensions;
-      else if (paras[i]=="logfolder")
-        tmp = g_settings.m_logFolder;
-      else
-        tmp = "Error:Unknown setting " + paras[i];
-      strInfo += openTag + tmp;
-    }
-    return SetResponse(strInfo);
-  }
-  return 0; // not reached
-}
-
-int CXbmcHttp::xbmcConfig(int numParas, CStdString paras[])
-{
-/*  int argc=0, ret=-1;
-  char_t* argv[20]; 
-  CStdString response="";
-  
-  if (numParas<1) {
-    return SetResponse(openTag+"Error:Missing paramters");
-  }
-  if (numParas>1){
-    for (argc=0; argc<numParas-1;argc++)
-      argv[argc]=(char_t*)paras[argc+1].c_str();
-  }
-  argv[argc]=NULL;
-  bool createdWebConfigObj = XbmcWebConfigInit();
-  if (paras[0]=="bookmarksize")
-  {
-    ret=XbmcWebsHttpAPIConfigBookmarkSize(response, argc, argv);
-    if (ret!=-1)
-      ret=1;
-  }
-  else if (paras[0]=="getbookmark")
-  {
-    ret=XbmcWebsHttpAPIConfigGetBookmark(response, argc, argv);
-    if (ret!=-1)
-      ret=1;
-  }
-  else if (paras[0]=="addbookmark") 
-    ret=XbmcWebsHttpAPIConfigAddBookmark(response, argc, argv);
-  else if (paras[0]=="savebookmark")
-    ret=XbmcWebsHttpAPIConfigSaveBookmark(response, argc, argv);
-  else if (paras[0]=="removebookmark")
-    ret=XbmcWebsHttpAPIConfigRemoveBookmark(response, argc, argv);
-  else if (paras[0]=="saveconfiguration")
-    ret=XbmcWebsHttpAPIConfigSaveConfiguration(response, argc, argv);
-  else if (paras[0]=="getoption")
-  {
-    //getoption has been deprecated so the following is just to prevent (my) legacy client code breaking (to be removed later)
-    if (paras[1]=="pictureextensions")
-      response=openTag+g_settings.m_pictureExtensions;
-    else if (paras[1]=="videoextensions")
-      response=openTag+g_settings.m_videoExtensions;
-    else if (paras[1]=="musicextensions")
-      response=openTag+g_settings.m_musicExtensions;
-    else
-      response=openTag+"Error:Function is deprecated";
-    //ret=XbmcWebsHttpAPIConfigGetOption(response, argc, argv);
-    //if (ret!=-1)
-    ret=1;
-  }
-  else if (paras[0]=="setoption")
-    ret=XbmcWebsHttpAPIConfigSetOption(response, argc, argv);
-  else
-  {
-    return SetResponse(openTag+"Error:Unknown Config Command");
-  }
-  if (createdWebConfigObj)
-    XbmcWebConfigRelease();
-  if (ret==-1)*/
-    return SetResponse(openTag+"Error:Deprecated");
-/*  else
-  {
-    return SetResponse(openTag+response);
-  }*/
-}
-
-int CXbmcHttp::xbmcGetSystemInfo(int numParas, CStdString paras[])
-{
-  if (numParas<1)
-    return SetResponse(openTag+"Error:Missing Parameter");
-  else
-  {
-    CStdString strInfo = "";
-    int i;
-    for (i=0; i<numParas; i++)
-    {
-      CStdString strTemp = (CStdString) g_infoManager.GetLabel(atoi(paras[i]));
-      if (strTemp.IsEmpty())
-        strTemp = "Error:No information retrieved for " + paras[i];
-      strInfo += openTag + strTemp;
-    }
-    return SetResponse(strInfo);
-  }
-}
-
-int CXbmcHttp::xbmcGetSystemInfoByName(int numParas, CStdString paras[])
-{
-  if (numParas<1)
-    return SetResponse(openTag+"Error:Missing Parameter");
-  else
-  {
-    CStdString strInfo = "";
-    int i;
-    for (i=0; i<numParas; i++)
-    {
-      CStdString strTemp = (CStdString) g_infoManager.GetLabel(g_infoManager.TranslateString(paras[i]));
-      if (strTemp.IsEmpty())
-        strTemp = "Error:No information retrieved for " + paras[i];
-      strInfo += openTag + strTemp;
-    }
-    if(strInfo.Find("�") && strInfo.Find("�"))
-    {
-      // The Charset Converter ToUtf8() will add. only in this case= "�" a char "°" during converting, 
-      // which is the right value for the GUI!
-      // A length depending fix in CCharsetConverter::stringCharsetToUtf8() will couse a wrong char in GUI. 
-      // So just for http, we remove the "�", to fix BUG ID:[1586251]
-      strInfo.Replace("�","");
-    }
-    return SetResponse(strInfo);
-  }
-}
-
-
-bool CXbmcHttp::xbmcBroadcast(CStdString message, int level)
-{
-  if  ((g_settings.m_HttpApiBroadcastLevel & 255)>=level)
-  {
-    if (!pUdpBroadcast)
-      pUdpBroadcast = new CUdpBroadcast();
-    CStdString LocalAddress="";
-       if (g_application.getNetwork().GetFirstConnectedInterface())
-      LocalAddress = g_application.getNetwork().GetFirstConnectedInterface()->GetCurrentIPAddress();
-    CStdString msg;
-    if ((g_settings.m_HttpApiBroadcastLevel & 128)==128)
-               message += ";"+LocalAddress;
-       if ((g_settings.m_HttpApiBroadcastLevel & 256)==256)
-               message += ";"+LocalAddress+" "+g_guiSettings.GetString("services.webserverport");
-    msg.Format(openBroadcast+message+";%i"+closeBroadcast, level);
-    return pUdpBroadcast->broadcast(msg, g_settings.m_HttpApiBroadcastPort);
-  }
-  else
-    return true;
-}
-
-int CXbmcHttp::xbmcBroadcast(int numParas, CStdString paras[])
-{
-  if (numParas>0)
-  {
-    if (!pUdpBroadcast)
-      pUdpBroadcast = new CUdpBroadcast();
-    bool succ;
-    if (numParas>1)
-      succ=pUdpBroadcast->broadcast(paras[0], atoi(paras[1]));
-    else
-      succ=pUdpBroadcast->broadcast(paras[0], g_settings.m_HttpApiBroadcastPort);
-    if (succ)
-      return SetResponse(openTag+"OK");
-    else
-      return SetResponse(openTag+"Error: calling broadcast");
-  }
-  else
-    return SetResponse(openTag+"Error:Wrong number of parameters");
-}
-
-int CXbmcHttp::xbmcSetBroadcast(int numParas, CStdString paras[])
-{
-  if (numParas>0)
-  {
-    g_settings.m_HttpApiBroadcastLevel=atoi(paras[0]);
-    if (g_settings.m_HttpApiBroadcastLevel==128)
-      g_settings.m_HttpApiBroadcastLevel=0;
-    if (numParas>1)
-      g_settings.m_HttpApiBroadcastPort=atoi(paras[1]);
-    return SetResponse(openTag+"OK");
-  }
-  else
-    return SetResponse(openTag+"Error:Wrong number of parameters");
-}
-
-int CXbmcHttp::xbmcGetBroadcast()
-{
-  CStdString tmp;
-  tmp.Format("%i;%i", g_settings.m_HttpApiBroadcastLevel,g_settings.m_HttpApiBroadcastPort);
-  return SetResponse(openTag+tmp);
-}
-
-int CXbmcHttp::xbmcGetSkinSetting(int numParas, CStdString paras[])
-//parameter=type;name
-//type: 0=bool, 1=string
-{
-  if (numParas<2)
-    return SetResponse(openTag+"Error:Missing parameters");
-  else
-  {
-    if (atoi(paras[0]) == 0)
-    {
-      int string = g_settings.TranslateSkinBool(paras[1]);
-      bool value = g_settings.GetSkinBool(string);
-      if (value==false)
-        return SetResponse(openTag+"False");
-      else
-        return SetResponse(openTag+"True");
-    }
-    else
-    {
-      int string = g_settings.TranslateSkinString(paras[1]);
-      CStdString value = g_settings.GetSkinString(string);
-      return SetResponse(openTag+value);
-    }
-  }
-}
-
-int CXbmcHttp::xbmcTakeScreenshot(int numParas, CStdString paras[])
-//no paras
-//filename, flash, rotation, width, height, quality
-//filename, flash, rotation, width, height, quality, download
-//filename, flash, rotation, width, height, quality, download, imgtag
-//filename can be blank
-{
-  if (numParas<1)
-    CScreenShot::TakeScreenshot();
-  else
-    return SetResponse(openTag+"Error: xbmcTakeScreenshot with params depracated");
-  return SetResponse(openTag+"OK");
-}
-
-int CXbmcHttp::xbmcAutoGetPictureThumbs(int numParas, CStdString paras[])
-{
-  if (numParas<1)
-    return SetResponse(openTag+"Error:Missing parameter");
-  else
-  {
-    autoGetPictureThumbs = (paras[0].ToLower()=="true");
-    return SetResponse(openTag+"OK");
-  }
-}
-
-int CXbmcHttp::xbmcOnAction(int numParas, CStdString paras[])
-{
-  if (numParas!=1)
-    return SetResponse(openTag+"Error:There must be one and only one parameter");
-  g_application.OnAction(CAction(atoi(paras[0])));
-  return SetResponse(openTag+"OK");
-}
-
-int CXbmcHttp::xbmcRecordStatus(int numParas, CStdString paras[])
-{
-  if (numParas!=0)
-    return SetResponse(openTag+"Error:Too many parameters");
-  else if( g_application.IsPlaying() && g_application.m_pPlayer && g_application.m_pPlayer->CanRecord())
-    return SetResponse(g_application.m_pPlayer->IsRecording()?openTag+"Recording":openTag+"Not recording");
-  else
-    return SetResponse(openTag+"Can't record");
-}
-
-int CXbmcHttp::xbmcGetLogLevel()
-{
-  CStdString level;
-  level.Format("%i", g_advancedSettings.m_logLevel);
-  return SetResponse(openTag+level);
-}
-
-int CXbmcHttp::xbmcSetLogLevel(int numParas, CStdString paras[])
-{
-  if (numParas!=1)
-    return SetResponse(openTag+"Error:Must have one parameter");
-  else
-  {
-    g_advancedSettings.m_logLevel=atoi(paras[0]);
-     return SetResponse(openTag+"OK");
-  }
-}
-
-int CXbmcHttp::xbmcWebServerStatus(int numParas, CStdString paras[])
-{
-/*  if (numParas==0)
-  {
-    if (g_application.m_pWebServer)
-      return SetResponse(openTag+"On");
-    else
-      return SetResponse(openTag+"Off");
-  }
-  else if (paras[0].ToLower().Equals("on"))
-  {
-    if (g_application.m_pWebServer)
-      return SetResponse(openTag+"Already on");
-    else
-    {
-      g_application.StartWebServer();
-      return SetResponse(openTag+"OK");
-    }
-  }
-  else
-    if (paras[0].ToLower().Equals("off"))
-      if (!g_application.m_pWebServer)
-        return SetResponse(openTag+"Already off");
-      else
-      {
-        g_application.StopWebServer(true);
-        return SetResponse(openTag+"OK");
-      }
-    else
-        return SetResponse(openTag+"Error:Unknown parameter");*/
-  return false;
-}
-
-int CXbmcHttp::xbmcSetResponseFormat(int numParas, CStdString paras[])
-{
-  if (numParas==0)
-  {
-    resetTags();
-    return SetResponse(openTag+"OK");
-  }
-  else if ((numParas % 2)==1)
-    return SetResponse(openTag+"Error:Missing parameter");
-  else
-  {
-    CStdString para;
-    for (int i=0; i<numParas; i+=2)
-    {
-      para=paras[i].ToLower();
-      if (para=="webheader")
-        incWebHeader=(paras[i+1].ToLower()=="true");
-      else if (para=="webfooter")
-        incWebFooter=(paras[i+1].ToLower()=="true");
-      else if (para=="header")
-        userHeader=paras[i+1];
-      else if (para=="footer")
-        userFooter=paras[i+1];
-      else if (para=="opentag")
-        openTag=paras[i+1];
-      else if (para=="closetag")
-        closeTag=paras[i+1];
-      else if (para=="closefinaltag")
-        closeFinalTag=(paras[i+1].ToLower()=="true");
-      else if (para=="openrecordset")
-        openRecordSet=paras[i+1]; 
-      else if (para=="closerecordset")
-        closeRecordSet=paras[i+1];
-      else if (para=="openrecord")
-        openRecord=paras[i+1];
-      else if (para=="closerecord")
-        closeRecord=paras[i+1];
-      else if (para=="openfield")
-        openField=paras[i+1];
-      else if (para=="closefield")
-        closeField=paras[i+1];
-      else if (para=="openbroadcast")
-        openBroadcast=paras[i+1];
-      else if (para=="closebroadcast")
-        closeBroadcast=paras[i+1];
-      else
-        return SetResponse(openTag+"Error:Unknown parameter:"+para);
-    }
-    return SetResponse(openTag+"OK");
-  }
-}
-
-
-int CXbmcHttp::xbmcHelp()
-{
-  CStdString output;
-  output="<p><b>XBMC HTTP API Commands</b></p><p>There are two alternative but equivalent syntax forms:</p>";
-  output+="<p><b>Syntax 1: http://xbmc-host/xbmcCmds/xbmcHttp?command=</b>command<b>&ampparameter=</b>first_parameter<b>;</b>second_parameter<b>;...</b></p>";
-  output+="<p><b>Syntax 2: http://xbmc-host/xbmcCmds/xbmcHttp?command=</b>command<b>(</b>first_parameter<b>;</b>second_parameter<b>;...</b><b>)</b></p>";
-  output+="<p>Note the use of the semi colon to separate multiple parameters.</p><p>The commands are case insensitive.</p>";
-  output+= "<p>The full documentation can be found here: <a  href=\"http://wiki.xbmc.org/index.php?title=WebServerHTTP-API\">http://wiki.xbmc.org/index.php?title=WebServerHTTP-API</a></p>";
-  return SetResponse(output);
-}
-
-
-int CXbmcHttp::xbmcCommand(const CStdString &parameter)
-{
-  if (shuttingDown)
-    return -1;
-  int numParas, retVal=false;
-  CStdString command, paras[MAX_PARAS];
-  numParas = splitParameter(parameter, command, paras, ";");
-  if (parameter.length()<300)
-    CLog::Log(LOGDEBUG, "HttpApi Start command: %s  paras: %s", command.c_str(), parameter.c_str());
-  else
-    CLog::Log(LOGDEBUG, "HttpApi Start command: %s  paras: [not recorded]", command.c_str());
-  tempSkipWebFooterHeader=false;
-  command=command.ToLower();
-  if (numParas>=0)
-  {
-    if (command == "clearplaylist")                   retVal = xbmcClearPlayList(numParas, paras);  
-      else if (command == "addtoplaylist")            retVal = xbmcAddToPlayList(numParas, paras);  
-      else if (command == "addtoplaylistfromdb")      retVal = xbmcAddToPlayListFromDB(numParas, paras);  
-      else if (command == "playfile")                 retVal = xbmcPlayerPlayFile(numParas, paras); 
-      else if (command == "pause")                    retVal = xbmcAction(numParas, paras,1);
-      else if (command == "stop")                     retVal = xbmcAction(numParas, paras,2);
-      else if (command == "playnext")                 retVal = xbmcAction(numParas, paras,3);
-      else if (command == "playprev")                 retVal = xbmcAction(numParas, paras,4);
-      else if (command == "rotate")                   retVal = xbmcAction(numParas, paras,5);
-      else if (command == "move")                     retVal = xbmcAction(numParas, paras,6);
-      else if (command == "zoom")                     retVal = xbmcAction(numParas, paras,7);
-      else if (command == "pauseexslide")             retVal = xbmcAction(numParas, paras,8);
-      else if (command == "stopexslide")              retVal = xbmcAction(numParas, paras,9);
-      else if (command == "playnextexslide")          retVal = xbmcAction(numParas, paras,10);
-      else if (command == "playprevexslide")          retVal = xbmcAction(numParas, paras,11);
-      else if (command == "restart")                  retVal = xbmcExit(1);
-      else if (command == "shutdown")                 retVal = xbmcExit(2);
-      else if (command == "exit")                     retVal = xbmcExit(3);
-      else if (command == "reset")                    retVal = xbmcExit(4);
-      else if (command == "restartapp")               retVal = xbmcExit(5);
-      else if (command == "getcurrentlyplaying")      retVal = xbmcGetCurrentlyPlaying(numParas, paras); 
-      else if (command == "getxbeid")                 retVal = xbmcGetXBEID(numParas, paras); 
-      else if (command == "getxbetitle")              retVal = xbmcGetXBETitle(numParas, paras); 
-      else if (command == "getshares")                retVal = xbmcGetSources(numParas, paras); 
-      else if (command == "getdirectory")             retVal = xbmcGetDirectory(numParas, paras); 
-      else if (command == "getmedialocation")         retVal = xbmcGetMediaLocation(numParas, paras); 
-      else if (command == "gettagfromfilename")       retVal = xbmcGetTagFromFilename(numParas, paras);
-      else if (command == "getcurrentplaylist")       retVal = xbmcGetCurrentPlayList();
-      else if (command == "setcurrentplaylist")       retVal = xbmcSetCurrentPlayList(numParas, paras);
-      else if (command == "getplaylistcontents")      retVal = xbmcGetPlayListContents(numParas, paras);
-      else if (command == "getplaylistlength")        retVal = xbmcGetPlayListLength(numParas, paras);
-      else if (command == "removefromplaylist")       retVal = xbmcRemoveFromPlayList(numParas, paras);
-      else if (command == "setplaylistsong")          retVal = xbmcSetPlayListSong(numParas, paras);
-      else if (command == "getplaylistsong")          retVal = xbmcGetPlayListSong(numParas, paras);
-      else if (command == "playlistnext")             retVal = xbmcPlayListNext();
-      else if (command == "playlistprev")             retVal = xbmcPlayListPrev();
-      else if (command == "getmusiclabel")            retVal = xbmcGetMusicLabel(numParas, paras);
-      else if (command == "getvideolabel")            retVal = xbmcGetVideoLabel(numParas, paras);
-      else if (command == "getpercentage")            retVal = xbmcGetPercentage();
-      else if (command == "seekpercentage")           retVal = xbmcSeekPercentage(numParas, paras, false);
-      else if (command == "seekpercentagerelative")   retVal = xbmcSeekPercentage(numParas, paras, true);
-      else if (command == "setvolume")                retVal = xbmcSetVolume(numParas, paras);
-      else if (command == "getvolume")                retVal = xbmcGetVolume();
-      else if (command == "mute")                     retVal = xbmcMute();
-      else if (command == "setplayspeed")             retVal = xbmcSetPlaySpeed(numParas, paras);
-      else if (command == "getplayspeed")             retVal = xbmcGetPlaySpeed();
-      else if (command == "filedownload")             retVal = xbmcGetThumb(numParas, paras, false);
-      else if (command == "getthumbfilename")         retVal = xbmcGetThumbFilename(numParas, paras);
-      else if (command == "lookupalbum")              retVal = xbmcLookupAlbum(numParas, paras);
-      else if (command == "choosealbum")              retVal = xbmcChooseAlbum(numParas, paras);
-      else if (command == "filedownloadfrominternet") retVal = xbmcDownloadInternetFile(numParas, paras);
-      else if (command == "filedelete")               retVal = xbmcDeleteFile(numParas, paras);
-      else if (command == "filecopy")                 retVal = xbmcCopyFile(numParas, paras);
-      else if (command == "filesize")                 retVal = xbmcFileSize(numParas, paras);
-      else if (command == "getmoviedetails")          retVal = xbmcGetMovieDetails(numParas, paras);
-      else if (command == "showpicture")              retVal = xbmcShowPicture(numParas, paras);
-      else if (command == "sendkey")                  retVal = xbmcSetKey(numParas, paras);
-      else if (command == "keyrepeat")                retVal = xbmcSetKeyRepeat(numParas, paras);
-      else if (command == "fileexists")               retVal = xbmcFileExists(numParas, paras);
-      else if (command == "fileupload")               retVal = xbmcSetFile(numParas, paras);
-      else if (command == "getguistatus")             retVal = xbmcGetGUIStatus();
-      else if (command == "execbuiltin")              retVal = xbmcExecBuiltIn(numParas, paras);
-      else if (command == "config")                   retVal = xbmcConfig(numParas, paras);
-      else if (command == "stsetting")                retVal = xbmcSTSetting(numParas, paras);
-      else if (command == "help")                     retVal = xbmcHelp();
-      else if (command == "getsysteminfo")            retVal = xbmcGetSystemInfo(numParas, paras);
-      else if (command == "getsysteminfobyname")      retVal = xbmcGetSystemInfoByName(numParas, paras);
-      else if (command == "addtoslideshow")           retVal = xbmcAddToSlideshow(numParas, paras);
-      else if (command == "clearslideshow")           retVal = xbmcClearSlideshow();
-      else if (command == "playslideshow")            retVal = xbmcPlaySlideshow(numParas, paras);
-      else if (command == "getslideshowcontents")     retVal = xbmcGetSlideshowContents();
-      else if (command == "slideshowselect")          retVal = xbmcSlideshowSelect(numParas, paras);
-      else if (command == "getcurrentslide")          retVal = xbmcGetCurrentSlide();
-      else if (command == "getguisetting")            retVal = xbmcGUISetting(numParas, paras);
-      else if (command == "setguisetting")            retVal = xbmcGUISetting(numParas, paras);
-      else if (command == "takescreenshot")           retVal = xbmcTakeScreenshot(numParas, paras);
-      else if (command == "getguidescription")        retVal = xbmcGetGUIDescription();
-      else if (command == "setautogetpicturethumbs")  retVal = xbmcAutoGetPictureThumbs(numParas, paras);
-      else if (command == "setresponseformat")        retVal = xbmcSetResponseFormat(numParas, paras);
-      else if (command == "querymusicdatabase")       retVal = xbmcQueryMusicDataBase(numParas, paras);
-      else if (command == "queryvideodatabase")       retVal = xbmcQueryVideoDataBase(numParas, paras);
-      else if (command == "execmusicdatabase")        retVal = xbmcExecMusicDataBase(numParas, paras);
-      else if (command == "execvideodatabase")        retVal = xbmcExecVideoDataBase(numParas, paras);
-      else if (command == "broadcast")                retVal = xbmcBroadcast(numParas, paras);
-      else if (command == "setbroadcast")             retVal = xbmcSetBroadcast(numParas, paras);
-      else if (command == "getbroadcast")             retVal = xbmcGetBroadcast();
-      else if (command == "action")                   retVal = xbmcOnAction(numParas, paras);
-      else if (command == "getrecordstatus")          retVal = xbmcRecordStatus(numParas, paras);
-      else if (command == "webserverstatus")          retVal = xbmcWebServerStatus(numParas, paras);
-      else if (command == "setloglevel")              retVal = xbmcSetLogLevel(numParas, paras);
-      else if (command == "getloglevel")              retVal = xbmcGetLogLevel();
-
-      //only callable internally
-      else if (command == "broadcastlevel")
-      {
-        retVal = xbmcBroadcast(paras[0], atoi(paras[1]));
-        retVal = 0;
-      }
-
-      //Old command names
-      else if (command == "deletefile")               retVal = xbmcDeleteFile(numParas, paras);
-      else if (command == "copyfile")                 retVal = xbmcCopyFile(numParas, paras);
-      else if (command == "downloadinternetfile")     retVal = xbmcDownloadInternetFile(numParas, paras);
-      else if (command == "getthumb")                 retVal = xbmcGetThumb(numParas, paras, true);
-      else if (command == "guisetting")               retVal = xbmcGUISetting(numParas, paras);
-      else if (command == "setfile")                  retVal = xbmcSetFile(numParas, paras);
-      else if (command == "setkey")                   retVal = xbmcSetKey(numParas, paras);
-
-      else
-        retVal = SetResponse(openTag+"Error:Unknown command");
-
-  }
-  else if (numParas==-2)
-    retVal = SetResponse(openTag+"Error:Too many parameters");
-  else
-    retVal = SetResponse(openTag+"Error:Missing command");
-//relinquish the remainder of time slice
-  Sleep(0);
-  //CLog::Log(LOGDEBUG, "HttpApi Finished command: %s", command.c_str());
-  return retVal;
-}
diff --git a/xbmc/interfaces/http-api/XBMChttp.h b/xbmc/interfaces/http-api/XBMChttp.h
deleted file mode 100644 (file)
index a3b9a95..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-#pragma once
-
-#include "network/UdpClient.h"
-#include "guilib/Key.h"
-#include "boost/shared_ptr.hpp"
-
-/******************************** Description *********************************/
-
-/* 
- *  Header file that provides an API over HTTP between the web server and XBMC
- *
- *            heavily based on XBMCweb.h
- */
-
-/********************************* Includes ***********************************/
-
-typedef char char_t;
-
-class CFileItem; typedef boost::shared_ptr<CFileItem> CFileItemPtr;
-
-
-
-class CUdpBroadcast : public CUdpClient
-{
-public:
-  CUdpBroadcast();
-  ~CUdpBroadcast();
-  bool broadcast(CStdString message, int port);
-};
-
-class CXbmcHttp
-{
-public:
-  CStdString userHeader, userFooter;
-  bool incWebFooter, incWebHeader, shuttingDown, tempSkipWebFooterHeader;
-
-  CXbmcHttp();
-  ~CXbmcHttp();
-
-  int xbmcCommand(const CStdString &parameter);
-  int xbmcAddToPlayList(int numParas, CStdString paras[]);
-  int xbmcAddToPlayListFromDB(int numParas, CStdString paras[]);
-  int xbmcPlayerPlayFile(int numParas, CStdString paras[]); 
-  int xbmcClearPlayList(int numParas, CStdString paras[]); 
-  int xbmcGetCurrentlyPlaying(int numParas, CStdString paras[]); 
-  int xbmcGetXBEID(int numParas, CStdString paras[]); 
-  int xbmcGetXBETitle(int numParas, CStdString paras[]); 
-  int xbmcGetSources(int numParas, CStdString paras[]);
-  int xbmcGetMediaLocation(int numParas, CStdString paras[]);
-  int xbmcGetDirectory(int numParas, CStdString paras[]);
-  int xbmcGetTagFromFilename(int numParas, CStdString paras[]); 
-  int xbmcGetCurrentPlayList();
-  int xbmcSetCurrentPlayList(int numParas, CStdString paras[]);
-  int xbmcGetPlayListContents(int numParas, CStdString paras[]);
-  int xbmcGetPlayListLength(int numParas, CStdString paras[]);
-  int xbmcRemoveFromPlayList(int numParas, CStdString paras[]);
-  int xbmcSetPlayListSong(int numParas, CStdString paras[]);
-  int xbmcGetPlayListSong(int numParas, CStdString paras[]);
-  int xbmcSetPlaySpeed(int numParas, CStdString paras[]);
-  int xbmcGetPlaySpeed();
-  int xbmcPlayListNext();
-  int xbmcPlayListPrev();
-  int xbmcSetVolume(int numParas, CStdString paras[]);
-  int xbmcGetVolume();
-  int xbmcMute();
-  int xbmcGetPercentage();
-  int xbmcSeekPercentage(int numParas, CStdString paras[], bool relative);
-  int xbmcAction(int numParas, CStdString paras[], int theAction);
-  int xbmcExit(int theAction);
-  int xbmcGetThumb(int numParas, CStdString paras[], bool bGetThumb);
-  int xbmcGetThumbFilename(int numParas, CStdString paras[]);
-  int xbmcLookupAlbum(int numParas, CStdString paras[]);
-  int xbmcChooseAlbum(int numParas, CStdString paras[]);
-  int xbmcQueryMusicDataBase(int numParas, CStdString paras[]);
-  int xbmcQueryVideoDataBase(int numParas, CStdString paras[]);
-  int xbmcExecMusicDataBase(int numParas, CStdString paras[]);
-  int xbmcExecVideoDataBase(int numParas, CStdString paras[]);
-  int xbmcDownloadInternetFile(int numParas, CStdString paras[]);
-  int xbmcSetKey(int numParas, CStdString paras[]);
-  int xbmcSetKeyRepeat(int numParas, CStdString paras[]);
-  int xbmcGetMovieDetails(int numParas, CStdString paras[]);
-  int xbmcDeleteFile(int numParas, CStdString paras[]);
-  int xbmcCopyFile(int numParas, CStdString paras[]);
-  int xbmcSetFile(int numParas, CStdString paras[]);
-  int xbmcFileExists(int numParas, CStdString paras[]);
-  int xbmcFileSize(int numParas, CStdString paras[]);
-  int xbmcShowPicture(int numParas, CStdString paras[]);
-  int xbmcGetGUIStatus();
-  int xbmcExecBuiltIn(int numParas, CStdString paras[]);
-  int xbmcSTSetting(int numParas, CStdString paras[]);
-  int xbmcConfig(int numParas, CStdString paras[]);
-  int xbmcHelp();
-  int xbmcGetSystemInfo(int numParas, CStdString paras[]);
-  int xbmcGetSystemInfoByName(int numParas, CStdString paras[]);
-  int xbmcAddToSlideshow(int numParas, CStdString paras[]);
-  int xbmcClearSlideshow();
-  int xbmcPlaySlideshow(int numParas, CStdString paras[]);
-  int xbmcSlideshowSelect(int numParas, CStdString paras[]);
-  int xbmcGetSlideshowContents();
-  int xbmcGetCurrentSlide();
-  int xbmcGUISetting(int numParas, CStdString paras[]);
-  int xbmcTakeScreenshot(int numParas, CStdString paras[]);
-  int xbmcGetGUIDescription();
-  int xbmcAutoGetPictureThumbs(int numParas, CStdString paras[]);
-  int xbmcSetResponseFormat(int numParas, CStdString paras[]);
-  int xbmcBroadcast(int numParas, CStdString paras[]);
-  bool xbmcBroadcast(CStdString message, int level=0);
-  int xbmcSetBroadcast(int numParas, CStdString paras[]);
-  int xbmcGetBroadcast();
-  int xbmcOnAction(int numParas, CStdString paras[]);
-  int xbmcRecordStatus(int numParas, CStdString paras[]);
-  int xbmcGetMusicLabel(int numParas, CStdString paras[]);
-  int xbmcGetVideoLabel(int numParas, CStdString paras[]);
-  int xbmcGetSkinSetting(int numParas, CStdString paras[]);
-  int xbmcWebServerStatus(int numParas, CStdString paras[]);
-  int xbmcGetLogLevel();
-  int xbmcSetLogLevel(int numParas, CStdString paras[]);
-  CKey GetKey();
-  void ResetKey();
-  CStdString GetOpenTag();
-  CStdString GetCloseTag();
-
-private:
-  CKey key;
-  CUdpBroadcast* pUdpBroadcast;
-  CUdpClient UdpClient;
-  CKey lastKey;
-  unsigned int repeatKeyRate; //ms
-  unsigned int MarkTime;
-  bool autoGetPictureThumbs;
-  CStdString lastThumbFn, lastPlayingInfo, lastSlideInfo;
-  CStdString openTag, closeTag,  openRecordSet, closeRecordSet, openRecord, closeRecord, openField, closeField, openBroadcast, closeBroadcast;
-  bool  closeFinalTag;
-
-  void encodeblock( unsigned char in[3], unsigned char out[4], int len );
-  CStdString encodeFileToBase64(const CStdString &inFilename, int linesize );
-  void decodeblock( unsigned char in[4], unsigned char out[3] );
-  bool decodeBase64ToFile( const CStdString &inString, const CStdString &outfilename, bool append = false );
-  int64_t fileSize(const CStdString &filename);
-  void resetTags();
-  CStdString procMask(CStdString mask);
-  int splitParameter(const CStdString &parameter, CStdString& command, CStdString paras[], const CStdString &sep);
-  bool playableFile(const CStdString &filename);
-  int SetResponse(const CStdString &response);
-  int displayDir(int numParas, CStdString paras[]);
-  void SetCurrentMediaItem(CFileItem& newItem);
-  void AddItemToPlayList(const CFileItemPtr &pItem, int playList, int sortMethod, CStdString mask, bool recursive);
-  void LoadPlayListOld(const CStdString& strPlayList, int playList);
-  bool LoadPlayList(CStdString strPath, int iPlaylist, bool clearList, bool autoStart);
-  void copyThumb(CStdString srcFn, CStdString destFn);
-  int FindPathInPlayList(int playList, CStdString path);
-};
-
-/****************
- *  Command names
- */
-#define WEB_COMMAND T("command")
-#define WEB_PARAMETER T("parameter")
-
-extern CXbmcHttp* m_pXbmcHttp; //make it global so Application.cpp can access it for key/button messages
index 13e5608..0b52ee8 100644 (file)
@@ -76,7 +76,7 @@ JSONRPC_STATUS CAudioLibrary::GetArtists(const CStdString &method, ITransportLay
     return InvalidParams;
 
   CFileItemList items;
-  if (!musicdatabase.GetArtistsNav(musicUrl.ToString(), items, albumArtistsOnly, genreID, albumID, songID, sorting))
+  if (!musicdatabase.GetArtistsNav(musicUrl.ToString(), items, albumArtistsOnly, genreID, albumID, songID, CDatabase::Filter(), sorting))
     return InternalError;
 
   // Add "artist" to "properties" array by default
@@ -154,7 +154,7 @@ JSONRPC_STATUS CAudioLibrary::GetAlbums(const CStdString &method, ITransportLaye
     return InvalidParams;
 
   CFileItemList items;
-  if (!musicdatabase.GetAlbumsNav(musicUrl.ToString(), items, genreID, artistID, sorting))
+  if (!musicdatabase.GetAlbumsNav(musicUrl.ToString(), items, genreID, artistID, CDatabase::Filter(), sorting))
     return InternalError;
 
   int size = items.Size();
index 82873fe..3b06be3 100644 (file)
@@ -18,7 +18,9 @@
  *
  */
 
+#include <map>
 #include <string.h>
+
 #include "FileItemHandler.h"
 #include "PlaylistOperations.h"
 #include "AudioLibrary.h"
@@ -41,111 +43,138 @@ using namespace MUSIC_INFO;
 using namespace JSONRPC;
 using namespace XFILE;
 
-void CFileItemHandler::FillDetails(ISerializable* info, CFileItemPtr item, const CVariant& fields, CVariant &result, CThumbLoader *thumbLoader /* = NULL */)
+bool CFileItemHandler::GetField(const std::string &field, const CVariant &info, const CFileItemPtr &item, CVariant &result, bool &fetchedArt, CThumbLoader *thumbLoader /* = NULL */)
 {
-  if (info == NULL || fields.size() == 0)
-    return;
-
-  CVariant serialization;
-  info->Serialize(serialization);
-
-  bool fetchedArt = false;
+  if (result.isMember(field) && !result[field].empty())
+    return true;
 
-  for (unsigned int i = 0; i < fields.size(); i++)
+  if (info.isMember(field) && !info[field].isNull())
   {
-    CStdString field = fields[i].asString();
+    result[field] = info[field];
+    return true;
+  }
 
-    if (item)
+  if (item)
+  {
+    if (item->IsAlbum())
     {
-      if (item->IsAlbum() && field.Equals("albumlabel"))
-        field = "label";
-      if (item->IsAlbum())
+      if (field == "albumlabel")
       {
-        if (field == "label")
-        {
-          result["albumlabel"] = item->GetProperty("album_label");
-          continue;
-        }
-        if (item->HasProperty("album_" + field + "_array"))
-        {
-          result[field] = item->GetProperty("album_" + field + "_array");
-          continue;
-        }
-        if (item->HasProperty("album_" + field))
-        {
-          result[field] = item->GetProperty("album_" + field);
-          continue;
-        }
+        result[field] = item->GetProperty("album_label");
+        return true;
       }
-
-      if (item->HasProperty("artist_" + field + "_array"))
+      if (item->HasProperty("album_" + field + "_array"))
       {
-        result[field] = item->GetProperty("artist_" + field + "_array");
-        continue;
+        result[field] = item->GetProperty("album_" + field + "_array");
+        return true;
       }
-      if (item->HasProperty("artist_" + field))
+      if (item->HasProperty("album_" + field))
       {
-        result[field] = item->GetProperty("artist_" + field);
-        continue;
+        result[field] = item->GetProperty("album_" + field);
+        return true;
       }
+    }
+    
+    if (item->HasProperty("artist_" + field + "_array"))
+    {
+      result[field] = item->GetProperty("artist_" + field + "_array");
+      return true;
+    }
+    if (item->HasProperty("artist_" + field))
+    {
+      result[field] = item->GetProperty("artist_" + field);
+      return true;
+    }
 
-      if (field == "thumbnail")
+    if (field == "art")
+    {
+      if (thumbLoader != NULL && item->GetArt().size() <= 0 && !fetchedArt &&
+        ((item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_iDbId > -1) || (item->HasMusicInfoTag() && item->GetMusicInfoTag()->GetDatabaseId() > -1)))
       {
-        if (thumbLoader != NULL && !item->HasThumbnail() && !fetchedArt &&
-           ((item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_iDbId > -1) || (item->HasMusicInfoTag() && item->GetMusicInfoTag()->GetDatabaseId() > -1)))
-        {
-          thumbLoader->FillLibraryArt(*item);
-          fetchedArt = true;
-        }
-        else if (item->HasPictureInfoTag() && !item->HasThumbnail())
-          item->SetThumbnailImage(CTextureCache::GetWrappedThumbURL(item->GetPath()));
-
-        if (item->HasThumbnail())
-          result["thumbnail"] = CTextureCache::GetWrappedImageURL(item->GetThumbnailImage());
-        else
-          result["thumbnail"] = "";
-        continue;
+        thumbLoader->FillLibraryArt(*item);
+        fetchedArt = true;
       }
 
-      if (field == "fanart")
+      result["art"] = item->GetArt();
+      return true;
+    }
+    
+    if (field == "thumbnail")
+    {
+      if (thumbLoader != NULL && !item->HasArt("thumb") && !fetchedArt &&
+        ((item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_iDbId > -1) || (item->HasMusicInfoTag() && item->GetMusicInfoTag()->GetDatabaseId() > -1)))
       {
-        if (thumbLoader != NULL && !item->HasProperty("fanart_image") && !fetchedArt &&
-           ((item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_iDbId > -1) || (item->HasMusicInfoTag() && item->GetMusicInfoTag()->GetDatabaseId() > -1)))
-        {
-          thumbLoader->FillLibraryArt(*item);
-          fetchedArt = true;
-        }
-
-        if (item->HasProperty("fanart_image"))
-          result["fanart"] = CTextureCache::GetWrappedImageURL(item->GetProperty("fanart_image").asString());
-        else
-          result["fanart"] = "";
-        continue;
+        thumbLoader->FillLibraryArt(*item);
+        fetchedArt = true;
       }
-
-      if (item->HasVideoInfoTag() && item->GetVideoContentType() == VIDEODB_CONTENT_TVSHOWS)
+      else if (item->HasPictureInfoTag() && !item->HasArt("thumb"))
+        item->SetArt("thumb", CTextureCache::GetWrappedThumbURL(item->GetPath()));
+      
+      if (item->HasArt("thumb"))
+        result["thumbnail"] = CTextureCache::GetWrappedImageURL(item->GetArt("thumb"));
+      else
+        result["thumbnail"] = "";
+      
+      return true;
+    }
+    
+    if (field == "fanart")
+    {
+      if (thumbLoader != NULL && !item->HasArt("fanart") && !fetchedArt &&
+        ((item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_iDbId > -1) || (item->HasMusicInfoTag() && item->GetMusicInfoTag()->GetDatabaseId() > -1)))
       {
-        if (item->GetVideoInfoTag()->m_iSeason < 0 && field == "season")
-        {
-          result[field] = (int)item->GetProperty("totalseasons").asInteger();
-          continue;
-        }
-        if (field == "watchedepisodes")
-        {
-          result[field] = (int)item->GetProperty("watchedepisodes").asInteger();
-          continue;
-        }
+        thumbLoader->FillLibraryArt(*item);
+        fetchedArt = true;
       }
-
-      if (field == "lastmodified" && item->m_dateTime.IsValid())
+      
+      if (item->HasArt("fanart"))
+        result["fanart"] = CTextureCache::GetWrappedImageURL(item->GetArt("fanart"));
+      else
+        result["fanart"] = "";
+      
+      return true;
+    }
+    
+    if (item->HasVideoInfoTag() && item->GetVideoContentType() == VIDEODB_CONTENT_TVSHOWS)
+    {
+      if (item->GetVideoInfoTag()->m_iSeason < 0 && field == "season")
+      {
+        result[field] = (int)item->GetProperty("totalseasons").asInteger();
+        return true;
+      }
+      if (field == "watchedepisodes")
       {
-        result[field] = item->m_dateTime.GetAsLocalizedDateTime();
-        continue;
+        result[field] = (int)item->GetProperty("watchedepisodes").asInteger();
+        return true;
       }
     }
+    
+    if (field == "lastmodified" && item->m_dateTime.IsValid())
+    {
+      result[field] = item->m_dateTime.GetAsLocalizedDateTime();
+      return true;
+    }
+  }
+
+  return false;
+}
+
+void CFileItemHandler::FillDetails(const ISerializable *info, const CFileItemPtr &item, std::set<std::string> &fields, CVariant &result, CThumbLoader *thumbLoader /* = NULL */)
+{
+  if (info == NULL || fields.size() == 0)
+    return;
+
+  CVariant serialization;
+  info->Serialize(serialization);
+
+  bool fetchedArt = false;
 
-    if (serialization.isMember(field) && !serialization[field].isNull() && (!result.isMember(field) || result[field].empty()))
-      result[field] = serialization[field];
+  std::set<std::string> originalFields = fields;
+
+  for (std::set<std::string>::const_iterator fieldIt = originalFields.begin(); fieldIt != originalFields.end(); fieldIt++)
+  {
+    if (GetField(*fieldIt, serialization, item, result, fetchedArt, thumbLoader))
+      fields.erase(*fieldIt);
   }
 }
 
@@ -179,11 +208,18 @@ void CFileItemHandler::HandleFileItemList(const char *ID, bool allowFile, const
       thumbLoader->Initialize();
   }
 
+  std::set<std::string> fields;
+  if (parameterObject.isMember("properties") && parameterObject["properties"].isArray())
+  {
+    for (CVariant::const_iterator_array field = parameterObject["properties"].begin_array(); field != parameterObject["properties"].end_array(); field++)
+      fields.insert(field->asString());
+  }
+
   for (int i = start; i < end; i++)
   {
     CVariant object;
     CFileItemPtr item = items.Get(i);
-    HandleFileItem(ID, allowFile, resultname, item, parameterObject, parameterObject["properties"], result, true, thumbLoader);
+    HandleFileItem(ID, allowFile, resultname, item, parameterObject, fields, result, true, thumbLoader);
   }
 
   delete thumbLoader;
@@ -191,28 +227,37 @@ void CFileItemHandler::HandleFileItemList(const char *ID, bool allowFile, const
 
 void CFileItemHandler::HandleFileItem(const char *ID, bool allowFile, const char *resultname, CFileItemPtr item, const CVariant &parameterObject, const CVariant &validFields, CVariant &result, bool append /* = true */, CThumbLoader *thumbLoader /* = NULL */)
 {
+  std::set<std::string> fields;
+  if (parameterObject.isMember("properties") && parameterObject["properties"].isArray())
+  {
+    for (CVariant::const_iterator_array field = parameterObject["properties"].begin_array(); field != parameterObject["properties"].end_array(); field++)
+      fields.insert(field->asString());
+  }
+
+  HandleFileItem(ID, allowFile, resultname, item, parameterObject, fields, result, append, thumbLoader);
+}
+
+void CFileItemHandler::HandleFileItem(const char *ID, bool allowFile, const char *resultname, CFileItemPtr item, const CVariant &parameterObject, const std::set<std::string> &validFields, CVariant &result, bool append /* = true */, CThumbLoader *thumbLoader /* = NULL */)
+{
   CVariant object;
-  bool hasFileField = false;
+  std::set<std::string> fields(validFields.begin(), validFields.end());
 
   if (item.get())
   {
-    for (unsigned int i = 0; i < validFields.size(); i++)
+    std::set<std::string>::const_iterator fileField = fields.find("file");
+    if (fileField != fields.end())
     {
-      CStdString field = validFields[i].asString();
-
-      if (field == "file")
-        hasFileField = true;
-    }
-
-    if (allowFile && hasFileField)
-    {
-      if (item->HasVideoInfoTag() && !item->GetVideoInfoTag()->GetPath().IsEmpty())
-          object["file"] = item->GetVideoInfoTag()->GetPath().c_str();
-      if (item->HasMusicInfoTag() && !item->GetMusicInfoTag()->GetURL().IsEmpty())
-        object["file"] = item->GetMusicInfoTag()->GetURL().c_str();
+      if (allowFile)
+      {
+        if (item->HasVideoInfoTag() && !item->GetVideoInfoTag()->GetPath().IsEmpty())
+            object["file"] = item->GetVideoInfoTag()->GetPath().c_str();
+        if (item->HasMusicInfoTag() && !item->GetMusicInfoTag()->GetURL().IsEmpty())
+          object["file"] = item->GetMusicInfoTag()->GetURL().c_str();
 
-      if (!object.isMember("file"))
-        object["file"] = item->GetPath().c_str();
+        if (!object.isMember("file"))
+          object["file"] = item->GetPath().c_str();
+      }
+      fields.erase(fileField);
     }
 
     if (ID)
@@ -260,14 +305,14 @@ void CFileItemHandler::HandleFileItem(const char *ID, bool allowFile, const char
       }
     }
 
-    FillDetails(item.get(), item, validFields, object, thumbLoader);
-
     if (item->HasVideoInfoTag())
-      FillDetails(item->GetVideoInfoTag(), item, validFields, object, thumbLoader);
+      FillDetails(item->GetVideoInfoTag(), item, fields, object, thumbLoader);
     if (item->HasMusicInfoTag())
-      FillDetails(item->GetMusicInfoTag(), item, validFields, object, thumbLoader);
+      FillDetails(item->GetMusicInfoTag(), item, fields, object, thumbLoader);
     if (item->HasPictureInfoTag())
-      FillDetails(item->GetPictureInfoTag(), item, validFields, object, thumbLoader);
+      FillDetails(item->GetPictureInfoTag(), item, fields, object, thumbLoader);
+    
+    FillDetails(item.get(), item, fields, object, thumbLoader);
 
     if (deleteThumbloader)
       delete thumbLoader;
index 8194468..69379b7 100644 (file)
@@ -19,6 +19,8 @@
  *
  */
 
+#include <set>
+
 #include "JSONRPC.h"
 #include "JSONUtils.h"
 #include "FileItem.h"
@@ -30,13 +32,15 @@ namespace JSONRPC
   class CFileItemHandler : public CJSONUtils
   {
   protected:
-    static void FillDetails(ISerializable* info, CFileItemPtr item, const CVariant& fields, CVariant &result, CThumbLoader *thumbLoader = NULL);
+    static void FillDetails(const ISerializable *info, const CFileItemPtr &item, std::set<std::string> &fields, CVariant &result, CThumbLoader *thumbLoader = NULL);
     static void HandleFileItemList(const char *ID, bool allowFile, const char *resultname, CFileItemList &items, const CVariant &parameterObject, CVariant &result, bool sortLimit = true);
     static void HandleFileItemList(const char *ID, bool allowFile, const char *resultname, CFileItemList &items, const CVariant &parameterObject, CVariant &result, int size, bool sortLimit = true);
     static void HandleFileItem(const char *ID, bool allowFile, const char *resultname, CFileItemPtr item, const CVariant &parameterObject, const CVariant &validFields, CVariant &result, bool append = true, CThumbLoader *thumbLoader = NULL);
+    static void HandleFileItem(const char *ID, bool allowFile, const char *resultname, CFileItemPtr item, const CVariant &parameterObject, const std::set<std::string> &validFields, CVariant &result, bool append = true, CThumbLoader *thumbLoader = NULL);
 
     static bool FillFileItemList(const CVariant &parameterObject, CFileItemList &list);
   private:
     static void Sort(CFileItemList &items, const CVariant& parameterObject);
+    static bool GetField(const std::string &field, const CVariant &info, const CFileItemPtr &item, CVariant &result, bool &fetchedArt, CThumbLoader *thumbLoader = NULL);
   };
 }
index 27dd166..477ceb2 100644 (file)
@@ -70,6 +70,10 @@ namespace JSONRPC
         "{ \"type\": \"string\", \"enum\": [ \"toggle\" ], \"required\": true }"
       "]"
     "}",
+    "\"Global.String.NotEmpty\": {"
+      "\"type\": \"string\","
+      "\"minLength\": 1"
+    "}",
     "\"Configuration.Notifications\": {"
       "\"type\": \"object\","
       "\"properties\": {"
@@ -327,6 +331,16 @@ namespace JSONRPC
         "\"thumbnail\": { \"type\": \"string\" }"
       "}"
     "}",
+    "\"Media.Artwork\": {"
+      "\"type\": \"object\","
+      "\"properties\": {"
+        "\"thumb\": { \"$ref\": \"Global.String.NotEmpty\" },"
+        "\"poster\": { \"$ref\": \"Global.String.NotEmpty\" },"
+        "\"banner\": { \"$ref\": \"Global.String.NotEmpty\" },"
+        "\"fanart\": { \"$ref\": \"Global.String.NotEmpty\" }"
+      "},"
+      "\"additionalProperties\": { \"$ref\": \"Global.String.NotEmpty\" }"
+    "}",
     "\"Library.Fields.Genre\": {"
       "\"extends\": \"Item.Fields.Base\","
       "\"items\": { \"type\": \"string\", \"enum\": [ \"title\", \"thumbnail\" ] }"
@@ -444,13 +458,13 @@ namespace JSONRPC
                   "\"playcount\", \"writer\", \"studio\", \"mpaa\", \"cast\", \"country\","
                   "\"imdbnumber\", \"runtime\", \"set\", \"showlink\", \"streamdetails\","
                   "\"top250\", \"votes\", \"fanart\", \"thumbnail\", \"file\", \"sorttitle\","
-                  "\"resume\", \"setid\", \"dateadded\", \"tag\" ]"
+                  "\"resume\", \"setid\", \"dateadded\", \"tag\", \"art\" ]"
       "}"
     "}",
     "\"Video.Fields.MovieSet\": {"
       "\"extends\": \"Item.Fields.Base\","
       "\"items\": { \"type\": \"string\","
-        "\"enum\": [ \"title\", \"playcount\", \"fanart\", \"thumbnail\" ]"
+        "\"enum\": [ \"title\", \"playcount\", \"fanart\", \"thumbnail\", \"art\" ]"
       "}"
     "}",
     "\"Video.Fields.TVShow\": {"
@@ -462,14 +476,14 @@ namespace JSONRPC
                   "\"imdbnumber\", \"premiered\", \"votes\", \"lastplayed\","
                   "\"fanart\", \"thumbnail\", \"file\", \"originaltitle\","
                   "\"sorttitle\", \"episodeguide\", \"season\", \"watchedepisodes\","
-                  "\"dateadded\", \"tag\", \"lastplayed\" ]"
+                  "\"dateadded\", \"tag\", \"lastplayed\", \"art\" ]"
       "}"
     "}",
     "\"Video.Fields.Season\": {"
       "\"extends\": \"Item.Fields.Base\","
       "\"items\": { \"type\": \"string\","
         "\"enum\": [ \"season\", \"showtitle\", \"playcount\", \"episode\", \"fanart\", \"thumbnail\", \"tvshowid\","
-                  "\"watchedepisodes\" ]"
+                  "\"watchedepisodes\", \"art\" ]"
       "}"
     "}",
     "\"Video.Fields.Episode\": {"
@@ -480,7 +494,8 @@ namespace JSONRPC
                   "\"firstaired\", \"playcount\", \"runtime\", \"director\","
                   "\"productioncode\", \"season\", \"episode\", \"originaltitle\","
                   "\"showtitle\", \"cast\", \"streamdetails\", \"lastplayed\", \"fanart\","
-                  "\"thumbnail\", \"file\", \"resume\", \"tvshowid\", \"dateadded\" ]"
+                  "\"thumbnail\", \"file\", \"resume\", \"tvshowid\", \"dateadded\","
+                  "\"uniqueid\", \"art\" ]"
       "}"
     "}",
     "\"Video.Fields.MusicVideo\": {"
@@ -489,7 +504,8 @@ namespace JSONRPC
         "\"enum\": [ \"title\", \"playcount\", \"runtime\", \"director\","
                   "\"studio\", \"year\", \"plot\", \"album\", \"artist\","
                   "\"genre\", \"track\", \"streamdetails\", \"lastplayed\","
-                  "\"fanart\", \"thumbnail\", \"file\", \"resume\", \"dateadded\", \"tag\" ]"
+                  "\"fanart\", \"thumbnail\", \"file\", \"resume\", \"dateadded\","
+                  "\"tag\", \"art\" ]"
       "}"
     "}",
     "\"Video.Cast\": {"
@@ -550,7 +566,8 @@ namespace JSONRPC
     "\"Video.Details.Base\": {"
       "\"extends\": \"Media.Details.Base\","
       "\"properties\": {"
-        "\"playcount\": { \"type\": \"integer\" }"
+        "\"playcount\": { \"type\": \"integer\" },"
+        "\"art\": { \"$ref\": \"Media.Artwork\" }"
       "}"
     "}",
     "\"Video.Details.Media\": {"
@@ -612,6 +629,7 @@ namespace JSONRPC
     "\"Video.Details.MovieSet.Extended\": {"
       "\"extends\": \"Video.Details.MovieSet\","
       "\"properties\": {"
+        "\"limits\": { \"$ref\": \"List.LimitsReturned\", \"required\": true },"
         "\"movies\": { \"type\": \"array\","
           "\"items\": { \"$ref\": \"Video.Details.Movie\" }"
         "}"
@@ -660,6 +678,7 @@ namespace JSONRPC
         "\"productioncode\": { \"type\": \"string\" },"
         "\"season\": { \"type\": \"integer\" },"
         "\"episode\": { \"type\": \"integer\" },"
+        "\"uniqueid\": { \"type\": \"object\", \"additionalProperties\": { \"type\": \"string\", \"minLength\": 1 } },"
         "\"originaltitle\": { \"type\": \"string\" },"
         "\"showtitle\": { \"type\": \"string\" },"
         "\"cast\": { \"$ref\": \"Video.Cast\" },"
@@ -932,7 +951,7 @@ namespace JSONRPC
                   "\"runtime\", \"set\", \"showlink\", \"streamdetails\", \"top250\", \"votes\","
                   "\"firstaired\", \"season\", \"episode\", \"showtitle\", \"thumbnail\", \"file\","
                   "\"resume\", \"artistid\", \"albumid\", \"tvshowid\", \"setid\", \"watchedepisodes\","
-                  "\"disc\", \"tag\" ]"
+                  "\"disc\", \"tag\", \"art\" ]"
       "}"
     "}",
     "\"List.Item.All\": {"
@@ -2392,7 +2411,8 @@ namespace JSONRPC
         "{ \"name\": \"showlink\", \"type\": [ \"null\", { \"$ref\": \"Array.String\", \"required\": true } ], \"default\": null },"
         "{ \"name\": \"thumbnail\", \"$ref\": \"Optional.String\" },"
         "{ \"name\": \"fanart\", \"$ref\": \"Optional.String\" },"
-        "{ \"name\": \"tag\", \"type\": [ \"null\", { \"$ref\": \"Array.String\", \"required\": true } ], \"default\": null }"
+        "{ \"name\": \"tag\", \"type\": [ \"null\", { \"$ref\": \"Array.String\", \"required\": true } ], \"default\": null },"
+        "{ \"name\": \"art\", \"type\": [ \"null\", { \"$ref\": \"Media.Artwork\", \"required\": true } ], \"default\": null }"
       "],"
       "\"returns\": \"string\""
     "}",
@@ -2419,7 +2439,8 @@ namespace JSONRPC
         "{ \"name\": \"episodeguide\", \"$ref\": \"Optional.String\" },"
         "{ \"name\": \"thumbnail\", \"$ref\": \"Optional.String\" },"
         "{ \"name\": \"fanart\", \"$ref\": \"Optional.String\" },"
-        "{ \"name\": \"tag\", \"type\": [ \"null\", { \"$ref\": \"Array.String\", \"required\": true } ], \"default\": null }"
+        "{ \"name\": \"tag\", \"type\": [ \"null\", { \"$ref\": \"Array.String\", \"required\": true } ], \"default\": null },"
+        "{ \"name\": \"art\", \"type\": [ \"null\", { \"$ref\": \"Media.Artwork\", \"required\": true } ], \"default\": null }"
       "],"
       "\"returns\": \"string\""
     "}",
@@ -2445,7 +2466,8 @@ namespace JSONRPC
         "{ \"name\": \"episode\", \"$ref\": \"Optional.Integer\" },"
         "{ \"name\": \"originaltitle\", \"$ref\": \"Optional.String\" },"
         "{ \"name\": \"thumbnail\", \"$ref\": \"Optional.String\" },"
-        "{ \"name\": \"fanart\", \"$ref\": \"Optional.String\" }"
+        "{ \"name\": \"fanart\", \"$ref\": \"Optional.String\" },"
+        "{ \"name\": \"art\", \"type\": [ \"null\", { \"$ref\": \"Media.Artwork\", \"required\": true } ], \"default\": null }"
       "],"
       "\"returns\": \"string\""
     "}",
@@ -2470,7 +2492,8 @@ namespace JSONRPC
         "{ \"name\": \"lastplayed\", \"$ref\": \"Optional.String\" },"
         "{ \"name\": \"thumbnail\", \"$ref\": \"Optional.String\" },"
         "{ \"name\": \"fanart\", \"$ref\": \"Optional.String\" },"
-        "{ \"name\": \"tag\", \"type\": [ \"null\", { \"$ref\": \"Array.String\", \"required\": true } ], \"default\": null }"
+        "{ \"name\": \"tag\", \"type\": [ \"null\", { \"$ref\": \"Array.String\", \"required\": true } ], \"default\": null },"
+        "{ \"name\": \"art\", \"type\": [ \"null\", { \"$ref\": \"Media.Artwork\", \"required\": true } ], \"default\": null }"
       "],"
       "\"returns\": \"string\""
     "}",
@@ -2954,6 +2977,20 @@ namespace JSONRPC
       "],"
       "\"returns\": null"
     "}",
+    "\"Player.OnPropertyChanged\": {"
+      "\"type\": \"notification\","
+      "\"description\": \"A property of the playing items has changed.\","
+      "\"params\": ["
+        "{ \"name\": \"sender\", \"type\": \"string\", \"required\": true },"
+        "{ \"name\": \"data\", \"type\": \"object\", \"required\": true,"
+          "\"properties\": {"
+            "\"property\": { \"$ref\": \"Player.Property.Value\" },"
+            "\"player\": { \"$ref\": \"Player.Notifications.Player\", \"required\": true }"
+          "}"
+        "}"
+      "],"
+      "\"returns\": null"
+    "}",
     "\"Playlist.OnAdd\": {"
       "\"type\": \"notification\","
       "\"description\": \"A playlist item has been added.\","
index c667f38..21382df 100644 (file)
@@ -141,7 +141,7 @@ JSONRPC_STATUS CVideoLibrary::GetMovieSetDetails(const CStdString &method, ITran
   if (!videodatabase.GetMoviesNav("videodb://1/2/", items, -1, -1, -1, -1, -1, -1, id))
     return InternalError;
 
-  return GetAdditionalMovieDetails(parameterObject["movies"], items, result["setdetails"]["items"], videodatabase, true);
+  return GetAdditionalMovieDetails(parameterObject["movies"], items, result["setdetails"], videodatabase, true);
 }
 
 JSONRPC_STATUS CVideoLibrary::GetTVShows(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
@@ -935,4 +935,13 @@ void CVideoLibrary::UpdateVideoTag(const CVariant &parameterObject, CVideoInfoTa
     artwork["fanart"] = parameterObject["fanart"].asString();
   if (ParameterNotNull(parameterObject, "tag"))
     CopyStringArray(parameterObject["tag"], details.m_tags);
+  if (ParameterNotNull(parameterObject, "art"))
+  {
+    CVariant art = parameterObject["art"];
+    for (CVariant::const_iterator_map artIt = art.begin_map(); artIt != art.end_map(); artIt++)
+    {
+      if (!artIt->second.asString().empty())
+        artwork[artIt->first] = artIt->second.asString();
+    }
+  }
 }
index 43b6d9e..7dd826d 100644 (file)
       { "name": "showlink", "type": [ "null", { "$ref": "Array.String", "required": true } ], "default": null },
       { "name": "thumbnail", "$ref": "Optional.String" },
       { "name": "fanart", "$ref": "Optional.String" },
-      { "name": "tag", "type": [ "null", { "$ref": "Array.String", "required": true } ], "default": null }
+      { "name": "tag", "type": [ "null", { "$ref": "Array.String", "required": true } ], "default": null },
+      { "name": "art", "type": [ "null", { "$ref": "Media.Artwork", "required": true } ], "default": null }
     ],
     "returns": "string"
   },
       { "name": "episodeguide", "$ref": "Optional.String" },
       { "name": "thumbnail", "$ref": "Optional.String" },
       { "name": "fanart", "$ref": "Optional.String" },
-      { "name": "tag", "type": [ "null", { "$ref": "Array.String", "required": true } ], "default": null }
+      { "name": "tag", "type": [ "null", { "$ref": "Array.String", "required": true } ], "default": null },
+      { "name": "art", "type": [ "null", { "$ref": "Media.Artwork", "required": true } ], "default": null }
     ],
     "returns": "string"
   },
       { "name": "episode", "$ref": "Optional.Integer" },
       { "name": "originaltitle", "$ref": "Optional.String" },
       { "name": "thumbnail", "$ref": "Optional.String" },
-      { "name": "fanart", "$ref": "Optional.String" }
+      { "name": "fanart", "$ref": "Optional.String" },
+      { "name": "art", "type": [ "null", { "$ref": "Media.Artwork", "required": true } ], "default": null }
     ],
     "returns": "string"
   },
       { "name": "lastplayed", "$ref": "Optional.String" },
       { "name": "thumbnail", "$ref": "Optional.String" },
       { "name": "fanart", "$ref": "Optional.String" },
-      { "name": "tag", "type": [ "null", { "$ref": "Array.String", "required": true } ], "default": null }
+      { "name": "tag", "type": [ "null", { "$ref": "Array.String", "required": true } ], "default": null },
+      { "name": "art", "type": [ "null", { "$ref": "Media.Artwork", "required": true } ], "default": null }
     ],
     "returns": "string"
   },
index 1559933..e024b68 100644 (file)
     ],
     "returns": null
   },
+  "Player.OnPropertyChanged": {
+    "type": "notification",
+    "description": "A property of the playing items has changed.",
+    "params": [
+      { "name": "sender", "type": "string", "required": true },
+      { "name": "data", "type": "object", "required": true,
+        "properties": {
+          "property": { "$ref": "Player.Property.Value" },
+          "player": { "$ref": "Player.Notifications.Player", "required": true }
+        }
+      }
+    ],
+    "returns": null
+  },
   "Playlist.OnAdd": {
     "type": "notification",
     "description": "A playlist item has been added.",
index 7f64d28..00f5677 100644 (file)
       { "type": "string", "enum": [ "toggle" ], "required": true }
     ]
   },
+  "Global.String.NotEmpty": {
+    "type": "string",
+    "minLength": 1
+  },
   "Configuration.Notifications": {
     "type": "object",
     "properties": {
       "thumbnail": { "type": "string" }
     }
   },
+  "Media.Artwork": {
+    "type": "object",
+    "properties": {
+      "thumb": { "$ref": "Global.String.NotEmpty" },
+      "poster": { "$ref": "Global.String.NotEmpty" },
+      "banner": { "$ref": "Global.String.NotEmpty" },
+      "fanart": { "$ref": "Global.String.NotEmpty" }
+    },
+    "additionalProperties": { "$ref": "Global.String.NotEmpty" }
+  },
   "Library.Fields.Genre": {
     "extends": "Item.Fields.Base",
     "items": { "type": "string", "enum": [ "title", "thumbnail" ] }
                 "playcount", "writer", "studio", "mpaa", "cast", "country",
                 "imdbnumber", "runtime", "set", "showlink", "streamdetails",
                 "top250", "votes", "fanart", "thumbnail", "file", "sorttitle",
-                "resume", "setid", "dateadded", "tag" ]
+                "resume", "setid", "dateadded", "tag", "art" ]
     }
   },
   "Video.Fields.MovieSet": {
     "extends": "Item.Fields.Base",
     "items": { "type": "string",
-      "enum": [ "title", "playcount", "fanart", "thumbnail" ]
+      "enum": [ "title", "playcount", "fanart", "thumbnail", "art" ]
     }
   },
   "Video.Fields.TVShow": {
                 "imdbnumber", "premiered", "votes", "lastplayed",
                 "fanart", "thumbnail", "file", "originaltitle",
                 "sorttitle", "episodeguide", "season", "watchedepisodes",
-                "dateadded", "tag", "lastplayed" ]
+                "dateadded", "tag", "lastplayed", "art" ]
     }
   },
   "Video.Fields.Season": {
     "extends": "Item.Fields.Base",
     "items": { "type": "string",
       "enum": [ "season", "showtitle", "playcount", "episode", "fanart", "thumbnail", "tvshowid",
-                "watchedepisodes" ]
+                "watchedepisodes", "art" ]
     }
   },
   "Video.Fields.Episode": {
                 "firstaired", "playcount", "runtime", "director",
                 "productioncode", "season", "episode", "originaltitle",
                 "showtitle", "cast", "streamdetails", "lastplayed", "fanart",
-                "thumbnail", "file", "resume", "tvshowid", "dateadded" ]
+                "thumbnail", "file", "resume", "tvshowid", "dateadded",
+                "uniqueid", "art" ]
     }
   },
   "Video.Fields.MusicVideo": {
       "enum": [ "title", "playcount", "runtime", "director",
                 "studio", "year", "plot", "album", "artist",
                 "genre", "track", "streamdetails", "lastplayed",
-                "fanart", "thumbnail", "file", "resume", "dateadded", "tag" ]
+                "fanart", "thumbnail", "file", "resume", "dateadded",
+                "tag", "art" ]
     }
   },
   "Video.Cast": {
   "Video.Details.Base": {
     "extends": "Media.Details.Base",
     "properties": {
-      "playcount": { "type": "integer" }
+      "playcount": { "type": "integer" },
+      "art": { "$ref": "Media.Artwork" }
     }
   },
   "Video.Details.Media": {
   "Video.Details.MovieSet.Extended": {
     "extends": "Video.Details.MovieSet",
     "properties": {
+      "limits": { "$ref": "List.LimitsReturned", "required": true },
       "movies": { "type": "array",
         "items": { "$ref": "Video.Details.Movie" }
       }
       "productioncode": { "type": "string" },
       "season": { "type": "integer" },
       "episode": { "type": "integer" },
+      "uniqueid": { "type": "object", "additionalProperties": { "type": "string", "minLength": 1 } },
       "originaltitle": { "type": "string" },
       "showtitle": { "type": "string" },
       "cast": { "$ref": "Video.Cast" },
                 "runtime", "set", "showlink", "streamdetails", "top250", "votes",
                 "firstaired", "season", "episode", "showtitle", "thumbnail", "file",
                 "resume", "artistid", "albumid", "tvshowid", "setid", "watchedepisodes",
-                "disc", "tag" ]
+                "disc", "tag", "art" ]
     }
   },
   "List.Item.All": {
index b4bc928..094fd88 100644 (file)
@@ -30,7 +30,7 @@ namespace XBMCAddon
     {
       DelayedCallGuard dg;
       if (!numBytes)
-        numBytes = file->GetLength();
+        numBytes = (unsigned long)file->GetLength();
       return (unsigned long)file->Read(buffer, numBytes);
     }
 
index d273adb..8416616 100644 (file)
@@ -56,7 +56,7 @@ namespace XBMCAddon
       if (!iconImage.empty())
         item->SetIconImage( iconImage );
       if (!thumbnailImage.empty())
-        item->SetThumbnailImage( thumbnailImage );
+        item->SetArt("thumb",  thumbnailImage );
       if (!path.empty())
         item->SetPath(path);
     }
@@ -126,7 +126,7 @@ namespace XBMCAddon
       if (!item) return;
       {
         LOCKGUI;
-        item->SetThumbnailImage(thumbFilename);
+        item->SetArt("thumb", thumbFilename);
       }
     }
 
index de66659..5369a82 100644 (file)
 
 #include "Application.h"
 #include "ApplicationMessenger.h"
-#ifdef HAS_HTTPAPI
-#include "interfaces/http-api/XBMChttp.h"
-#include "interfaces/http-api/HttpApi.h"
-#endif
 #include "utils/URIUtils.h"
 #include "aojsonrpc.h"
 #ifndef TARGET_WINDOWS
@@ -119,39 +115,7 @@ namespace XBMCAddon
     String executehttpapi(const char* httpcommand) 
     {
       TRACE;
-#ifdef HAS_HTTPAPI
-      String ret;
-      if (! httpcommand)
-        return ret;
-
-      if (!m_pXbmcHttp)
-        m_pXbmcHttp = new CXbmcHttp();
-
-      int open, close;
-      CStdString parameter="", cmd=httpcommand, execute;
-      open = cmd.Find("(");
-      if (open>0)
-        {
-          close=cmd.length();
-          while (close>open && cmd.Mid(close,1)!=")")
-            close--;
-          if (close>open)
-            {
-              parameter = cmd.Mid(open + 1, close - open - 1);
-              parameter.Replace(",",";");
-              execute = cmd.Left(open);
-            }
-          else //open bracket but no close
-            return ret;
-        }
-      else //no parameters
-        execute = cmd;
-
-      CURL::Decode(parameter);
-      return CHttpApi::MethodCall(execute, parameter);
-#else
       THROW_UNIMP("executehttpapi");
-#endif
     }
 
     String executeJSONRPC(const char* jsonrpccommand)
index 6293d3d..b7739ac 100644 (file)
@@ -95,14 +95,7 @@ namespace XBMCAddon
     void executebuiltin(const char* function, bool wait = false);
 
     /**
-     * executehttpapi(httpcommand) -- Execute an HTTP API command.
-     * 
-     * httpcommand    : string - http command to execute.
-     * 
-     * List of commands - http://wiki.xbmc.org/?title=WebServerHTTP-API#The_Commands 
-     * 
-     * example:
-     *   - response = xbmc.executehttpapi('TakeScreenShot(special://temp/test.jpg,0,false,200,-1,90)')
+     * executehttpapi(httpcommand) -- Not implemented anymore.
      */
     String executehttpapi(const char* httpcommand);
 
index 6d9b476..31df77c 100644 (file)
@@ -153,9 +153,7 @@ BOOL   FindNextFile(HANDLE hHandle, LPWIN32_FIND_DATA lpFindData)
 
   struct stat64 fileStat;
   memset(&fileStat, 0, sizeof(fileStat));
-  if (stat64(strFileNameTest, &fileStat) == -1)
-    return FALSE;
+  stat64(strFileNameTest, &fileStat);
 
   bool bIsDir = false;
   if (S_ISDIR(fileStat.st_mode))
index d06801d..90e5941 100644 (file)
@@ -382,7 +382,7 @@ bool CLastFmManager::RequestRadioTracks()
         CStdString coverUrl = child->Value();
         if ((coverUrl != "") && (coverUrl.Find("noimage") == -1) && (coverUrl.Right(1) != "/"))
         {
-          newItem->SetThumbnailImage(coverUrl);
+          newItem->SetArt("thumb", coverUrl);
         }
       }
     }
@@ -423,9 +423,9 @@ void CLastFmManager::CacheTrackThumb(const int nrInitialTracksToAdd)
     CFileItemPtr item = (*m_RadioTrackQueue)[i];
     if (!item->GetMusicInfoTag()->Loaded())
     {
-      if (!item->HasThumbnail())
+      if (!item->HasArt("thumb"))
       {
-        item->SetThumbnailImage("DefaultAlbumCover.png");
+        item->SetArt("thumb", "DefaultAlbumCover.png");
       }
       item->GetMusicInfoTag()->SetLoaded();
     }
index eddf3ea..2617ab1 100644 (file)
@@ -2621,29 +2621,53 @@ void CMusicDatabase::Clean()
   }
 }
 
-bool CMusicDatabase::GetGenresNav(const CStdString& strBaseDir, CFileItemList& items)
+bool CMusicDatabase::GetGenresNav(const CStdString& strBaseDir, CFileItemList& items, const Filter &filter /* = Filter() */, bool countOnly /* = false */)
 {
   try
   {
     if (NULL == m_pDB.get()) return false;
     if (NULL == m_pDS.get()) return false;
 
+    // get primary genres for songs - could be simplified to just SELECT * FROM genre?
+    CStdString strSQL = "SELECT %s FROM genre ";
+
+    Filter extFilter = filter;
     CMusicDbUrl musicUrl;
-    if (!musicUrl.FromString(strBaseDir))
+    if (!musicUrl.FromString(strBaseDir) || !GetFilter(musicUrl, extFilter))
       return false;
 
-    // get primary genres for songs - could be simplified to just SELECT * FROM genre?
-    CStdString strSQL="SELECT * "
-                      "  FROM genre "
-                      " WHERE idGenre IN"
-                      "(SELECT song_genre.idGenre "
-                      "   FROM song_genre) ";
+    // if there are extra WHERE conditions we might need access
+    // to songview or albumview for these conditions
+    if (extFilter.where.size() > 0)
+    {
+      if (extFilter.where.find("artistview") != string::npos)
+        extFilter.AppendJoin("JOIN song_genre ON song_genre.idGenre = genre.idGenre JOIN songview ON songview.idSong = song_genre.idSong "
+                             "JOIN song_artist ON song_artist.idSong = songview.idSong JOIN artistview ON artistview.idArtist = song_artist.idArtist");
+      else if (extFilter.where.find("songview") != string::npos)
+        extFilter.AppendJoin("JOIN song_genre ON song_genre.idGenre = genre.idGenre JOIN songview ON songview.idSong = song_genre.idSong");
+      else if (extFilter.where.find("albumview") != string::npos)
+        extFilter.AppendJoin("JOIN album_genre ON album_genre.idGenre = genre.idGenre JOIN albumview ON albumview.idAlbum = album_genre.idAlbum");
+
+      extFilter.AppendGroup("genre.idGenre");
+    }
+    extFilter.AppendWhere("genre.strGenre != ''");
+
+    if (countOnly)
+    {
+      extFilter.fields = "COUNT(DISTINCT genre.idGenre)";
+      extFilter.group.clear();
+      extFilter.order.clear();
+    }
+
+    CStdString strSQLExtra;
+    if (!BuildSQL(strSQLExtra, extFilter, strSQLExtra))
+      return false;
 
-    // block null strings
-    strSQL += " AND genre.strGenre != \"\"";
+    strSQL = PrepareSQL(strSQL.c_str(), !extFilter.fields.empty() && extFilter.fields.compare("*") != 0 ? extFilter.fields.c_str() : "genre.*") + strSQLExtra;
 
     // run query
     CLog::Log(LOGDEBUG, "%s query: %s", __FUNCTION__, strSQL.c_str());
+
     if (!m_pDS->query(strSQL.c_str()))
       return false;
     int iRowsFound = m_pDS->num_rows();
@@ -2653,15 +2677,25 @@ bool CMusicDatabase::GetGenresNav(const CStdString& strBaseDir, CFileItemList& i
       return true;
     }
 
+    if (countOnly)
+    {
+      CFileItemPtr pItem(new CFileItem());
+      pItem->SetProperty("total", iRowsFound == 1 ? m_pDS->fv(0).get_asInt() : iRowsFound);
+      items.Add(pItem);
+
+      m_pDS->close();
+      return true;
+    }
+
     // get data from returned rows
     while (!m_pDS->eof())
     {
-      CFileItemPtr pItem(new CFileItem(m_pDS->fv("strGenre").get_asString()));
-      pItem->GetMusicInfoTag()->SetGenre(m_pDS->fv("strGenre").get_asString());
-      pItem->GetMusicInfoTag()->SetDatabaseId(m_pDS->fv("idGenre").get_asInt(), "genre");
+      CFileItemPtr pItem(new CFileItem(m_pDS->fv("genre.strGenre").get_asString()));
+      pItem->GetMusicInfoTag()->SetGenre(m_pDS->fv("genre.strGenre").get_asString());
+      pItem->GetMusicInfoTag()->SetDatabaseId(m_pDS->fv("genre.idGenre").get_asInt(), "genre");
 
       CMusicDbUrl itemUrl = musicUrl;
-      CStdString strDir; strDir.Format("%ld/", m_pDS->fv("idGenre").get_asInt());
+      CStdString strDir; strDir.Format("%ld/", m_pDS->fv("genre.idGenre").get_asInt());
       itemUrl.AppendPath(strDir);
       pItem->SetPath(itemUrl.ToString());
 
@@ -2751,7 +2785,100 @@ bool CMusicDatabase::GetAlbumsByYear(const CStdString& strBaseDir, CFileItemList
   return GetAlbumsByWhere(musicUrl.ToString(), filter, items);
 }
 
-bool CMusicDatabase::GetArtistsNav(const CStdString& strBaseDir, CFileItemList& items, bool albumArtistsOnly /* = false */, int idGenre /* = -1 */, int idAlbum /* = -1 */, int idSong /* = -1 */, const SortDescription &sortDescription /* = SortDescription() */)
+bool CMusicDatabase::GetCommonNav(const CStdString &strBaseDir, const CStdString &table, const CStdString &labelField, CFileItemList &items, const Filter &filter /* = Filter() */, bool countOnly /* = false */)
+{
+  if (NULL == m_pDB.get()) return false;
+  if (NULL == m_pDS.get()) return false;
+
+  if (table.empty() || labelField.empty())
+    return false;
+  
+  try
+  {
+    Filter extFilter = filter;
+    CStdString strSQL = "SELECT %s FROM " + table + " ";
+    extFilter.AppendGroup(labelField);
+    extFilter.AppendWhere(labelField + " != ''");
+    
+    if (countOnly)
+    {
+      extFilter.fields = "COUNT(DISTINCT " + labelField + ")";
+      extFilter.group.clear();
+      extFilter.order.clear();
+    }
+    
+    CMusicDbUrl musicUrl;
+    if (!BuildSQL(strBaseDir, strSQL, extFilter, strSQL, musicUrl))
+      return false;
+
+    items.SetPath(musicUrl.ToString());
+    
+    strSQL = PrepareSQL(strSQL, !extFilter.fields.empty() ? extFilter.fields.c_str() : labelField.c_str());
+    
+    // run query
+    CLog::Log(LOGDEBUG, "%s query: %s", __FUNCTION__, strSQL.c_str());
+    if (!m_pDS->query(strSQL.c_str()))
+      return false;
+    
+    int iRowsFound = m_pDS->num_rows();
+    if (iRowsFound <= 0)
+    {
+      m_pDS->close();
+      return false;
+    }
+    
+    if (countOnly)
+    {
+      CFileItemPtr pItem(new CFileItem());
+      pItem->SetProperty("total", iRowsFound == 1 ? m_pDS->fv(0).get_asInt() : iRowsFound);
+      items.Add(pItem);
+      
+      m_pDS->close();
+      return true;
+    }
+    
+    // get data from returned rows
+    while (!m_pDS->eof())
+    {
+      string labelValue = m_pDS->fv(labelField).get_asString();
+      CFileItemPtr pItem(new CFileItem(labelValue));
+      
+      CMusicDbUrl itemUrl = musicUrl;
+      CStdString strDir; strDir.Format("%s/", labelValue.c_str());
+      itemUrl.AppendPath(strDir);
+      pItem->SetPath(itemUrl.ToString());
+      
+      pItem->m_bIsFolder = true;
+      items.Add(pItem);
+      
+      m_pDS->next();
+    }
+    
+    // cleanup
+    m_pDS->close();
+    
+    return true;
+  }
+  catch (...)
+  {
+    m_pDS->close();
+    CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
+  }
+  
+  return false;
+}
+
+bool CMusicDatabase::GetAlbumTypesNav(const CStdString &strBaseDir, CFileItemList &items, const Filter &filter /* = Filter() */, bool countOnly /* = false */)
+{
+  return GetCommonNav(strBaseDir, "albumview", "albumview.strType", items, filter, countOnly);
+}
+
+bool CMusicDatabase::GetMusicLabelsNav(const CStdString &strBaseDir, CFileItemList &items, const Filter &filter /* = Filter() */, bool countOnly /* = false */)
+{
+  return GetCommonNav(strBaseDir, "albumview", "albumview.strLabel", items, filter, countOnly);
+}
+
+bool CMusicDatabase::GetArtistsNav(const CStdString& strBaseDir, CFileItemList& items, bool albumArtistsOnly /* = false */, int idGenre /* = -1 */, int idAlbum /* = -1 */, int idSong /* = -1 */, const Filter &filter /* = Filter() */, const SortDescription &sortDescription /* = SortDescription() */, bool countOnly /* = false */)
 {
   if (NULL == m_pDB.get()) return false;
   if (NULL == m_pDS.get()) return false;
@@ -2772,8 +2899,7 @@ bool CMusicDatabase::GetArtistsNav(const CStdString& strBaseDir, CFileItemList&
 
     musicUrl.AddOption("albumartistsonly", albumArtistsOnly);
 
-    Filter filter;
-    bool result = GetArtistsByWhere(musicUrl.ToString(), filter, items, sortDescription);
+    bool result = GetArtistsByWhere(musicUrl.ToString(), filter, items, sortDescription, countOnly);
     CLog::Log(LOGDEBUG,"Time to retrieve artists from dataset = %i", XbmcThreads::SystemClockMillis() - time);
 
     return result;
@@ -2786,7 +2912,7 @@ bool CMusicDatabase::GetArtistsNav(const CStdString& strBaseDir, CFileItemList&
   return false;
 }
 
-bool CMusicDatabase::GetArtistsByWhere(const CStdString& strBaseDir, const Filter &filter, CFileItemList& items, const SortDescription &sortDescription /* = SortDescription() */)
+bool CMusicDatabase::GetArtistsByWhere(const CStdString& strBaseDir, const Filter &filter, CFileItemList& items, const SortDescription &sortDescription /* = SortDescription() */, bool countOnly /* = false */)
 {
   if (NULL == m_pDB.get()) return false;
   if (NULL == m_pDS.get()) return false;
@@ -2796,7 +2922,7 @@ bool CMusicDatabase::GetArtistsByWhere(const CStdString& strBaseDir, const Filte
     int total = -1;
 
     CStdString strSQL = "SELECT %s FROM artistview ";
-    
+
     Filter extFilter = filter;
     CMusicDbUrl musicUrl;
     if (!musicUrl.FromString(strBaseDir) || !GetFilter(musicUrl, extFilter))
@@ -2822,10 +2948,19 @@ bool CMusicDatabase::GetArtistsByWhere(const CStdString& strBaseDir, const Filte
         extFilter.AppendGroup("artistview.idArtist");
     }
     
+    if (countOnly)
+    {
+      extFilter.fields = "COUNT(DISTINCT artistview.idArtist)";
+      extFilter.group.clear();
+      extFilter.order.clear();
+    }
+
     CStdString strSQLExtra;
     if (!BuildSQL(strSQLExtra, extFilter, strSQLExtra))
       return false;
 
+    items.SetPath(musicUrl.ToString());
+
     // Apply the limiting directly here if there's no special sorting but limiting
     if (extFilter.limit.empty() &&
         sortDescription.sortBy == SortByNone &&
@@ -2847,6 +2982,16 @@ bool CMusicDatabase::GetArtistsByWhere(const CStdString& strBaseDir, const Filte
       return true;
     }
 
+    if (countOnly)
+    {
+      CFileItemPtr pItem(new CFileItem());
+      pItem->SetProperty("total", iRowsFound == 1 ? m_pDS->fv(0).get_asInt() : iRowsFound);
+      items.Add(pItem);
+
+      m_pDS->close();
+      return true;
+    }
+
     // store the total value of items as a property
     if (total < iRowsFound)
       total = iRowsFound;
@@ -2964,7 +3109,7 @@ bool CMusicDatabase::GetAlbumFromSong(const CSong &song, CAlbum &album)
   return false;
 }
 
-bool CMusicDatabase::GetAlbumsNav(const CStdString& strBaseDir, CFileItemList& items, int idGenre /* = -1 */, int idArtist /* = -1 */, const SortDescription &sortDescription /* = SortDescription() */)
+bool CMusicDatabase::GetAlbumsNav(const CStdString& strBaseDir, CFileItemList& items, int idGenre /* = -1 */, int idArtist /* = -1 */, const Filter &filter /* = Filter() */, const SortDescription &sortDescription /* = SortDescription() */, bool countOnly /* = false */)
 {
   CMusicDbUrl musicUrl;
   if (!musicUrl.FromString(strBaseDir))
@@ -2977,11 +3122,10 @@ bool CMusicDatabase::GetAlbumsNav(const CStdString& strBaseDir, CFileItemList& i
   if (idArtist > 0)
     musicUrl.AddOption("artistid", idArtist);
 
-  Filter filter;
-  return GetAlbumsByWhere(musicUrl.ToString(), filter, items, sortDescription);
+  return GetAlbumsByWhere(musicUrl.ToString(), filter, items, sortDescription, countOnly);
 }
 
-bool CMusicDatabase::GetAlbumsByWhere(const CStdString &baseDir, const Filter &filter, CFileItemList &items, const SortDescription &sortDescription /* = SortDescription() */)
+bool CMusicDatabase::GetAlbumsByWhere(const CStdString &baseDir, const Filter &filter, CFileItemList &items, const SortDescription &sortDescription /* = SortDescription() */, bool countOnly /* = false */)
 {
   if (m_pDB.get() == NULL || m_pDS.get() == NULL)
     return false;
@@ -3009,6 +3153,8 @@ bool CMusicDatabase::GetAlbumsByWhere(const CStdString &baseDir, const Filter &f
     if (!BuildSQL(strSQLExtra, extFilter, strSQLExtra))
       return false;
 
+    items.SetPath(musicUrl.ToString());
+
     // Apply the limiting directly here if there's no special sorting but limiting
     if (extFilter.limit.empty() &&
         sortDescription.sortBy == SortByNone &&
@@ -3039,6 +3185,16 @@ bool CMusicDatabase::GetAlbumsByWhere(const CStdString &baseDir, const Filter &f
     if (total < iRowsFound)
       total = iRowsFound;
     items.SetProperty("total", total);
+
+    if (countOnly)
+    {
+      CFileItemPtr pItem(new CFileItem());
+      pItem->SetProperty("total", total);
+      items.Add(pItem);
+
+      m_pDS->close();
+      return true;
+    }
     
     DatabaseResults results;
     results.reserve(iRowsFound);
@@ -3111,6 +3267,8 @@ bool CMusicDatabase::GetSongsByWhere(const CStdString &baseDir, const Filter &fi
     if (!BuildSQL(strSQLExtra, extFilter, strSQLExtra))
       return false;
 
+    items.SetPath(musicUrl.ToString());
+
     // Apply the limiting directly here if there's no special sorting but limiting
     if (extFilter.limit.empty() &&
         sortDescription.sortBy == SortByNone &&
@@ -3168,6 +3326,7 @@ bool CMusicDatabase::GetSongsByWhere(const CStdString &baseDir, const Filter &fi
         return (items.Size() > 0);
       }
     }
+
     // cleanup
     m_pDS->close();
     CLog::Log(LOGDEBUG, "%s(%s) - took %d ms", __FUNCTION__, filter.where.c_str(), XbmcThreads::SystemClockMillis() - time);
@@ -4024,6 +4183,10 @@ bool CMusicDatabase::RemoveSongsFromPath(const CStdString &path1, CSongMap &song
 
       m_pDS->close();
 
+      //TODO: move this below the m_pDS->exec block, once UPnP doesn't rely on this anymore
+      for (unsigned int i = 0; i < ids.size(); i++)
+        AnnounceRemove("song", ids[i]);
+
       // and delete all songs, and anything linked to them
       sql = "delete from song where idSong in " + songIds;
       m_pDS->exec(sql.c_str());
@@ -4034,8 +4197,6 @@ bool CMusicDatabase::RemoveSongsFromPath(const CStdString &path1, CSongMap &song
       sql = "delete from karaokedata where idSong in " + songIds;
       m_pDS->exec(sql.c_str());
 
-      for (unsigned int i = 0; i < ids.size(); i++)
-        AnnounceRemove("song", ids[i]);
     }
     // and remove the path as well (it'll be re-added later on with the new hash if it's non-empty)
     sql = "delete from path" + where;
@@ -5107,7 +5268,7 @@ string CMusicDatabase::GetArtistArtForItem(int mediaId, const string &mediaType,
   return GetSingleValue(query, m_pDS2);
 }
 
-bool CMusicDatabase::GetFilter(const CDbUrl &musicUrl, Filter &filter)
+bool CMusicDatabase::GetFilter(CDbUrl &musicUrl, Filter &filter)
 {
   if (!musicUrl.IsValid())
     return false;
@@ -5234,8 +5395,12 @@ bool CMusicDatabase::GetFilter(const CDbUrl &musicUrl, Filter &filter)
         filter.AppendWhere("albumview.strAlbum <> ''");
     }
   }
-  else if (type == "songs")
+  else if (type == "songs" || type == "singles")
   {
+    option = options.find("singles");
+    if (option != options.end())
+      filter.AppendWhere(PrepareSQL("songview.idAlbum %sIN (SELECT idAlbum FROM album WHERE strAlbum = '')", option->second.asBoolean() ? "" : "NOT "));
+
     option = options.find("year");
     if (option != options.end())
       filter.AppendWhere(PrepareSQL("songview.iYear = %i", (int)option->second.asInteger()));
@@ -5272,8 +5437,6 @@ bool CMusicDatabase::GetFilter(const CDbUrl &musicUrl, Filter &filter)
                                     " OR songview.idSong IN (SELECT song.idSong FROM song JOIN album_artist ON song.idAlbum=album_artist.idAlbum JOIN artist ON artist.idArtist = album_artist.idArtist WHERE artist.strArtist like '%s')", // album artists
                                     option->second.asString().c_str(), option->second.asString().c_str()));
   }
-  else
-    return false;
 
   option = options.find("xsp");
   if (option != options.end())
@@ -5290,5 +5453,23 @@ bool CMusicDatabase::GetFilter(const CDbUrl &musicUrl, Filter &filter)
     }
   }
 
+  option = options.find("filter");
+  if (option != options.end())
+  {
+    CSmartPlaylist xspFilter;
+    if (!xspFilter.LoadFromJson(option->second.asString()))
+      return false;
+
+    // check if the filter playlist matches the item type
+    if (xspFilter.GetType() == type)
+    {
+      std::set<CStdString> playlists;
+      filter.AppendWhere(xspFilter.GetWhereClause(*this, playlists));
+    }
+    // remove the filter if it doesn't match the item type
+    else
+      musicUrl.AddOption("filter", "");
+  }
+
   return true;
 }
index d030c21..d11c265 100644 (file)
@@ -154,16 +154,19 @@ public:
   bool GetPaths(std::set<CStdString> &paths);
   bool SetPathHash(const CStdString &path, const CStdString &hash);
   bool GetPathHash(const CStdString &path, CStdString &hash);
-  bool GetGenresNav(const CStdString& strBaseDir, CFileItemList& items);
+  bool GetGenresNav(const CStdString& strBaseDir, CFileItemList& items, const Filter &filter = Filter(), bool countOnly = false);
   bool GetYearsNav(const CStdString& strBaseDir, CFileItemList& items);
-  bool GetArtistsNav(const CStdString& strBaseDir, CFileItemList& items, bool albumArtistsOnly = false, int idGenre = -1, int idAlbum = -1, int idSong = -1, const SortDescription &sortDescription = SortDescription());
-  bool GetAlbumsNav(const CStdString& strBaseDir, CFileItemList& items, int idGenre = -1, int idArtist = -1, const SortDescription &sortDescription = SortDescription());
+  bool GetArtistsNav(const CStdString& strBaseDir, CFileItemList& items, bool albumArtistsOnly = false, int idGenre = -1, int idAlbum = -1, int idSong = -1, const Filter &filter = Filter(), const SortDescription &sortDescription = SortDescription(), bool countOnly = false);
+  bool GetCommonNav(const CStdString &strBaseDir, const CStdString &table, const CStdString &labelField, CFileItemList &items, const Filter &filter /* = Filter() */, bool countOnly /* = false */);
+  bool GetAlbumTypesNav(const CStdString &strBaseDir, CFileItemList &items, const Filter &filter = Filter(), bool countOnly = false);
+  bool GetMusicLabelsNav(const CStdString &strBaseDir, CFileItemList &items, const Filter &filter = Filter(), bool countOnly = false);
+  bool GetAlbumsNav(const CStdString& strBaseDir, CFileItemList& items, int idGenre = -1, int idArtist = -1, const Filter &filter = Filter(), const SortDescription &sortDescription = SortDescription(), bool countOnly = false);
   bool GetAlbumsByYear(const CStdString &strBaseDir, CFileItemList& items, int year);
   bool GetSongsNav(const CStdString& strBaseDir, CFileItemList& items, int idGenre, int idArtist,int idAlbum, const SortDescription &sortDescription = SortDescription());
   bool GetSongsByYear(const CStdString& baseDir, CFileItemList& items, int year);
   bool GetSongsByWhere(const CStdString &baseDir, const Filter &filter, CFileItemList& items, const SortDescription &sortDescription = SortDescription());
-  bool GetAlbumsByWhere(const CStdString &baseDir, const Filter &filter, CFileItemList &items, const SortDescription &sortDescription = SortDescription());
-  bool GetArtistsByWhere(const CStdString& strBaseDir, const Filter &filter, CFileItemList& items, const SortDescription &sortDescription = SortDescription());
+  bool GetAlbumsByWhere(const CStdString &baseDir, const Filter &filter, CFileItemList &items, const SortDescription &sortDescription = SortDescription(), bool countOnly = false);
+  bool GetArtistsByWhere(const CStdString& strBaseDir, const Filter &filter, CFileItemList& items, const SortDescription &sortDescription = SortDescription(), bool countOnly = false);
   bool GetRandomSong(CFileItem* item, int& idSong, const Filter &filter);
   int GetKaraokeSongsCount();
   int GetSongsCount(const Filter &filter = Filter());
@@ -269,7 +272,7 @@ public:
    */
   std::string GetArtistArtForItem(int mediaId, const std::string &mediaType, const std::string &artType);
 
-  virtual bool GetFilter(const CDbUrl &musicUrl, Filter &filter);
+  virtual bool GetFilter(CDbUrl &musicUrl, Filter &filter);
 
 protected:
   std::map<CStdString, int> m_artistCache;
index d9c157d..d7e675c 100644 (file)
@@ -55,7 +55,6 @@ bool CMusicDbUrl::parse()
     case NODE_TYPE_ALBUM_TOP100:
     case NODE_TYPE_ALBUM_COMPILATIONS:
     case NODE_TYPE_YEAR_ALBUM:
-    case NODE_TYPE_SINGLES:
       m_type = "albums";
       break;
 
@@ -66,6 +65,7 @@ bool CMusicDbUrl::parse()
     case NODE_TYPE_SONG:
     case NODE_TYPE_SONG_TOP100:
     case NODE_TYPE_YEAR_SONG:
+    case NODE_TYPE_SINGLES:
       m_type = "songs";
       break;
 
@@ -94,6 +94,7 @@ bool CMusicDbUrl::parse()
     case NODE_TYPE_ALBUM_COMPILATIONS_SONGS:
     case NODE_TYPE_SONG_TOP100:
     case NODE_TYPE_YEAR_SONG:
+    case NODE_TYPE_SINGLES:
       m_type = "songs";
       break;
 
@@ -109,10 +110,6 @@ bool CMusicDbUrl::parse()
       m_type = "albums";
       break;
 
-    case NODE_TYPE_SINGLES:
-      m_type = "albums";
-      break;
-
     case NODE_TYPE_TOP100:
       m_type = "top100";
       break;
@@ -133,6 +130,10 @@ bool CMusicDbUrl::parse()
   // retrieve and parse all options
   AddOptions(m_url.GetOptions());
 
+  // add options based on the node type
+  if (dirType == NODE_TYPE_SINGLES || childType == NODE_TYPE_SINGLES)
+    AddOption("singles", true);
+
   // add options based on the QueryParams
   if (queryParams.GetArtistId() != -1)
     AddOption("artistid", (int)queryParams.GetArtistId());
index b7b5b2e..d202c11 100644 (file)
@@ -132,7 +132,7 @@ bool CMusicInfoLoader::LoadItem(CFileItem* pItem)
   if (mapItem && mapItem->m_dateTime==pItem->m_dateTime && mapItem->HasMusicInfoTag() && mapItem->GetMusicInfoTag()->Loaded())
   { // Query map if we previously cached the file on HD
     *pItem->GetMusicInfoTag() = *mapItem->GetMusicInfoTag();
-    pItem->SetThumbnailImage(mapItem->GetThumbnailImage());
+    pItem->SetArt("thumb", mapItem->GetArt("thumb"));
     return true;
   }
 
@@ -152,7 +152,7 @@ bool CMusicInfoLoader::LoadItem(CFileItem* pItem)
   if ((song=m_songsMap.Find(pItem->GetPath()))!=NULL)
   {  // Have we loaded this item from database before
     pItem->GetMusicInfoTag()->SetSong(*song);
-    pItem->SetThumbnailImage(song->strThumb);
+    pItem->SetArt("thumb", song->strThumb);
   }
   else if (pItem->IsMusicDb())
   { // a music db item that doesn't have tag loaded - grab details from the database
@@ -162,7 +162,7 @@ bool CMusicInfoLoader::LoadItem(CFileItem* pItem)
     if (m_musicDatabase.GetSongById(param.GetSongId(), song))
     {
       pItem->GetMusicInfoTag()->SetSong(song);
-      pItem->SetThumbnailImage(song.strThumb);
+      pItem->SetArt("thumb", song.strThumb);
     }
   }
   else if (g_guiSettings.GetBool("musicfiles.usetags") || pItem->IsCDDA())
@@ -195,8 +195,7 @@ void CMusicInfoLoader::OnLoaderFinish()
     for (int i = 0; i < m_pVecItems->Size(); ++i)
     {
       CSong song(*m_pVecItems->Get(i)->GetMusicInfoTag());
-      if (m_pVecItems->Get(i)->HasThumbnail())
-        song.strThumb = m_pVecItems->Get(i)->GetThumbnailImage();
+      song.strThumb = m_pVecItems->Get(i)->GetArt("thumb");
       song.idSong = i; // for the lookup below
       songs.push_back(song);
     }
@@ -209,9 +208,9 @@ void CMusicInfoLoader::OnLoaderFinish()
       for (VECSONGS::iterator j = i->songs.begin(); j != i->songs.end(); ++j)
       {
         if (!j->strThumb.empty())
-          m_pVecItems->Get(j->idSong)->SetThumbnailImage(j->strThumb);
+          m_pVecItems->Get(j->idSong)->SetArt("thumb", j->strThumb);
         else
-          m_pVecItems->Get(j->idSong)->SetThumbnailImage(albumArt);
+          m_pVecItems->Get(j->idSong)->SetArt("thumb", albumArt);
       }
     }
   }
index 8f93bdf..c26b071 100644 (file)
@@ -173,7 +173,7 @@ void CGUIDialogMusicInfo::SetAlbum(const CAlbum& album, const CStdString &path)
       if (artwork.find("thumb") != artwork.end())
         m_albumItem->SetProperty("artistthumb", artwork["thumb"]);
       if (artwork.find("fanart") != artwork.end())
-        m_albumItem->SetProperty("fanart_image",artwork["fanart"]);
+        m_albumItem->SetArt("fanart",artwork["fanart"]);
     }
   }
   m_hasUpdatedThumb = false;
@@ -226,9 +226,9 @@ void CGUIDialogMusicInfo::SetDiscography()
     long idAlbum = database.GetAlbumByName(item->GetLabel(),m_artist.strArtist);
 
     if (idAlbum != -1) // we need this slight stupidity to get correct case for the album name
-      item->SetThumbnailImage(database.GetArtForItem(idAlbum, "album", "thumb"));
+      item->SetArt("thumb", database.GetArtForItem(idAlbum, "album", "thumb"));
     else
-      item->SetThumbnailImage("DefaultAlbumCover.png");
+      item->SetArt("thumb", "DefaultAlbumCover.png");
 
     m_albumSongs->Add(item);
   }
@@ -290,7 +290,7 @@ void CGUIDialogMusicInfo::Update()
   {
     CGUIImage* pImageControl = (CGUIImage*)pControl;
     pImageControl->FreeResources();
-    pImageControl->SetFileName(m_albumItem->GetThumbnailImage());
+    pImageControl->SetFileName(m_albumItem->GetArt("thumb"));
   }
 
   // disable the GetThumb button if the user isn't allowed it
@@ -343,10 +343,10 @@ void CGUIDialogMusicInfo::OnGetThumb()
   CFileItemList items;
 
   // Current thumb
-  if (CFile::Exists(m_albumItem->GetThumbnailImage()))
+  if (CFile::Exists(m_albumItem->GetArt("thumb")))
   {
     CFileItemPtr item(new CFileItem("thumb://Current", false));
-    item->SetThumbnailImage(m_albumItem->GetThumbnailImage());
+    item->SetArt("thumb", m_albumItem->GetArt("thumb"));
     item->SetLabel(g_localizeStrings.Get(20016));
     items.Add(item);
   }
@@ -363,7 +363,7 @@ void CGUIDialogMusicInfo::OnGetThumb()
     CStdString strItemPath;
     strItemPath.Format("thumb://Remote%i", i);
     CFileItemPtr item(new CFileItem(strItemPath, false));
-    item->SetThumbnailImage(thumbs[i]);
+    item->SetArt("thumb", thumbs[i]);
     item->SetIconImage("DefaultPicture.png");
     item->SetLabel(g_localizeStrings.Get(20015));
     
@@ -387,7 +387,7 @@ void CGUIDialogMusicInfo::OnGetThumb()
   if (CFile::Exists(localThumb))
   {
     CFileItemPtr item(new CFileItem("thumb://Local", false));
-    item->SetThumbnailImage(localThumb);
+    item->SetArt("thumb", localThumb);
     item->SetLabel(g_localizeStrings.Get(20017));
     items.Add(item);
   }
@@ -433,7 +433,7 @@ void CGUIDialogMusicInfo::OnGetThumb()
     db.Close();
   }
 
-  m_albumItem->SetThumbnailImage(newThumb);
+  m_albumItem->SetArt("thumb", newThumb);
   m_hasUpdatedThumb = true;
 
   // tell our GUI to completely reload all controls (as some of them
@@ -450,10 +450,10 @@ void CGUIDialogMusicInfo::OnGetFanart()
 {
   CFileItemList items;
 
-  if (m_albumItem->HasProperty("fanart_image"))
+  if (m_albumItem->HasArt("fanart"))
   {
     CFileItemPtr itemCurrent(new CFileItem("fanart://Current",false));
-    itemCurrent->SetThumbnailImage(m_albumItem->GetProperty("fanart_image").asString());
+    itemCurrent->SetArt("thumb", m_albumItem->GetArt("fanart"));
     itemCurrent->SetLabel(g_localizeStrings.Get(20440));
     items.Add(itemCurrent);
   }
@@ -465,7 +465,7 @@ void CGUIDialogMusicInfo::OnGetFanart()
     strItemPath.Format("fanart://Remote%i",i);
     CFileItemPtr item(new CFileItem(strItemPath, false));
     CStdString thumb = m_artist.fanart.GetPreviewURL(i);
-    item->SetThumbnailImage(CTextureCache::GetWrappedThumbURL(thumb));
+    item->SetArt("thumb", CTextureCache::GetWrappedThumbURL(thumb));
     item->SetIconImage("DefaultPicture.png");
     item->SetLabel(g_localizeStrings.Get(20441));
 
@@ -484,7 +484,7 @@ void CGUIDialogMusicInfo::OnGetFanart()
   if (!strLocal.IsEmpty())
   {
     CFileItemPtr itemLocal(new CFileItem("fanart://Local",false));
-    itemLocal->SetThumbnailImage(strLocal);
+    itemLocal->SetArt("thumb", strLocal);
     itemLocal->SetLabel(g_localizeStrings.Get(20438));
 
     // TODO: Do we need to clear the cached image?
@@ -534,10 +534,7 @@ void CGUIDialogMusicInfo::OnGetFanart()
     db.Close();
   }
 
-  if (!result.empty())
-    m_albumItem->SetProperty("fanart_image",result);
-  else
-    m_albumItem->ClearProperty("fanart_image");
+  m_albumItem->SetArt("fanart", result);
   m_hasUpdatedThumb = true;
   // tell our GUI to completely reload all controls (as some of them
   // are likely to have had this image in use so will need refreshing)
index beb93e0..db81d66 100644 (file)
@@ -241,16 +241,16 @@ void CGUIDialogSongInfo::OnGetThumb()
   if (DownloadThumbnail(thumbFromWeb))
   {
     CFileItemPtr item(new CFileItem("thumb://allmusic.com", false));
-    item->SetThumbnailImage(thumbFromWeb);
+    item->SetArt("thumb", thumbFromWeb);
     item->SetLabel(g_localizeStrings.Get(20055));
     items.Add(item);
   }*/
 
   // Current thumb
-  if (CFile::Exists(m_song->GetThumbnailImage()))
+  if (CFile::Exists(m_song->GetArt("thumb")))
   {
     CFileItemPtr item(new CFileItem("thumb://Current", false));
-    item->SetThumbnailImage(m_song->GetThumbnailImage());
+    item->SetArt("thumb", m_song->GetArt("thumb"));
     item->SetLabel(g_localizeStrings.Get(20016));
     items.Add(item);
   }
@@ -266,7 +266,7 @@ void CGUIDialogSongInfo::OnGetThumb()
   if (CFile::Exists(localThumb))
   {
     CFileItemPtr item(new CFileItem("thumb://Local", false));
-    item->SetThumbnailImage(localThumb);
+    item->SetArt("thumb", localThumb);
     item->SetLabel(g_localizeStrings.Get(20017));
     items.Add(item);
   }
@@ -275,7 +275,7 @@ void CGUIDialogSongInfo::OnGetThumb()
     // which is probably the allmusic.com thumb.  These could be wrong, so allow the user
     // to delete the incorrect thumb
     CFileItemPtr item(new CFileItem("thumb://None", false));
-    item->SetThumbnailImage("DefaultAlbumCover.png");
+    item->SetArt("thumb", "DefaultAlbumCover.png");
     item->SetLabel(g_localizeStrings.Get(20018));
     items.Add(item);
   }
@@ -308,7 +308,7 @@ void CGUIDialogSongInfo::OnGetThumb()
     db.Close();
   }
 
-  m_song->SetThumbnailImage(newThumb);
+  m_song->SetArt("thumb", newThumb);
 
   // tell our GUI to completely reload all controls (as some of them
   // are likely to have had this image in use so will need refreshing)
index c627d52..8f1bc60 100644 (file)
@@ -173,7 +173,7 @@ void CMusicInfoScanner::Process()
         if (m_handle)
         {
           m_handle->SetText(StringUtils::Join(it->artist, g_advancedSettings.m_musicItemSeparator)+" - "+it->strAlbum);
-          m_handle->SetPercentage(iCurrentItem++/(double)m_albumsToScan.size());
+          m_handle->SetPercentage(iCurrentItem++/(float)m_albumsToScan.size());
         }
 
         CMusicAlbumInfo albumInfo;
@@ -194,7 +194,7 @@ void CMusicInfoScanner::Process()
         if (m_handle)
         {
           m_handle->SetText(it->strArtist);
-          m_handle->SetPercentage(iCurrentItem++/(double)m_artistsToScan.size()*100);
+          m_handle->SetPercentage(iCurrentItem++/(float)m_artistsToScan.size()*100);
         }
 
         DownloadArtistInfo(it->genre[0],it->strArtist,bCanceled); // genre field holds path - see fetchartistinfo()
@@ -440,7 +440,7 @@ bool CMusicInfoScanner::DoScan(const CStdString& strDirectory)
     if (m_handle)
     {
       if (m_itemCount>0)
-        m_handle->SetPercentage(m_currentItem/(double)m_itemCount*100);
+        m_handle->SetPercentage(m_currentItem/(float)m_itemCount*100);
       OnDirectoryScanned(strDirectory);
     }
   }
@@ -512,7 +512,7 @@ int CMusicInfoScanner::RetrieveMusicInfo(CFileItemList& items, const CStdString&
       // if we have the itemcount, update our
       // dialog with the progress we made
       if (m_handle && m_itemCount>0)
-        m_handle->SetPercentage(m_currentItem/(double)m_itemCount*100);
+        m_handle->SetPercentage(m_currentItem/(float)m_itemCount*100);
 
       if (tag.Loaded())
       {
index 4aaef5f..20fffff 100644 (file)
@@ -493,7 +493,7 @@ void CMusicInfoTag::SetReplayGainTrackGain(int trackGain)
 
 void CMusicInfoTag::SetReplayGainAlbumGain(int albumGain)
 {
-  m_iTrackGain = albumGain;
+  m_iAlbumGain = albumGain;
   m_iHasGainInfo |= REPLAY_GAIN_HAS_ALBUM_INFO;
 }
 
index ed25b92..b440867 100644 (file)
@@ -63,7 +63,7 @@ static const vector<string> StringListToVectorString(const StringList& stringLis
 {
   vector<string> values;
   for (StringList::ConstIterator it = stringList.begin(); it != stringList.end(); ++it)
-    values.push_back(it->toCString(true));
+    values.push_back(it->to8Bit(true));
   return values;
 }
 
@@ -197,6 +197,10 @@ bool CTagLoaderTagLib::Load(const string& strFileName, CMusicInfoTag& tag, Embed
   else if (xiph)
     ParseXiphComment(xiph, art, tag);
 
+  // art for flac files is outside the tag
+  if (flacFile)
+    SetFlacArt(flacFile, art, tag);
+
   // Add APE tags over the top of ID3 tags if we want to prioritize them
   if (ape && g_advancedSettings.m_prioritiseAPEv2tags)
     ParseAPETag(ape, art, tag);
@@ -219,32 +223,31 @@ bool CTagLoaderTagLib::ParseASF(ASF::Tag *asf, EmbeddedArt *art, CMusicInfoTag&
   const ASF::AttributeListMap& attributeListMap = asf->attributeListMap();
   for (ASF::AttributeListMap::ConstIterator it = attributeListMap.begin(); it != attributeListMap.end(); ++it)
   {
-    if (it->first == "Author")                           tag.SetArtist(GetASFStringList(it->second));
-    else if (it->first == "WM/AlbumArtist")              tag.SetAlbumArtist(GetASFStringList(it->second));
-    else if (it->first == "WM/AlbumTitle")               tag.SetAlbum(it->second.front().toString().toCString());
+    if (it->first == "Author")                           SetArtist(tag, GetASFStringList(it->second));
+    else if (it->first == "WM/AlbumArtist")              SetAlbumArtist(tag, GetASFStringList(it->second));
+    else if (it->first == "WM/AlbumTitle")               tag.SetAlbum(it->second.front().toString().to8Bit(true));
     else if (it->first == "WM/TrackNumber")              tag.SetTrackNumber(it->second.front().toUInt());
     else if (it->first == "WM/PartOfSet")                tag.SetPartOfSet(it->second.front().toUInt());
-    else if (it->first == "WM/Genre")                    tag.SetGenre(GetASFStringList(it->second));
+    else if (it->first == "WM/Genre")                    SetGenre(tag, GetASFStringList(it->second));
     else if (it->first == "WM/AlbumArtistSortOrder")     {} // Known unsupported, supress warnings
     else if (it->first == "WM/ArtistSortOrder")          {} // Known unsupported, supress warnings
     else if (it->first == "WM/Script")                   {} // Known unsupported, supress warnings
-    else if (it->first == "MusicBrainz/Artist Id")       tag.SetMusicBrainzArtistID(it->second.front().toString().toCString());
-    else if (it->first == "MusicBrainz/Album Id")        tag.SetMusicBrainzAlbumID(it->second.front().toString().toCString());
-    else if (it->first == "MusicBrainz/Album Artist Id") tag.SetMusicBrainzAlbumArtistID(it->second.front().toString().toCString());
-    else if (it->first == "MusicBrainz/Track Id")        tag.SetMusicBrainzTrackID(it->second.front().toString().toCString());
+    else if (it->first == "MusicBrainz/Artist Id")       tag.SetMusicBrainzArtistID(it->second.front().toString().to8Bit(true));
+    else if (it->first == "MusicBrainz/Album Id")        tag.SetMusicBrainzAlbumID(it->second.front().toString().to8Bit(true));
+    else if (it->first == "MusicBrainz/Album Artist Id") tag.SetMusicBrainzAlbumArtistID(it->second.front().toString().to8Bit(true));
+    else if (it->first == "MusicBrainz/Track Id")        tag.SetMusicBrainzTrackID(it->second.front().toString().to8Bit(true));
     else if (it->first == "MusicBrainz/Album Status")    {}
     else if (it->first == "MusicBrainz/Album Type")      {}
     else if (it->first == "MusicIP/PUID")                {}
     else
-      CLog::Log(LOGDEBUG, "unrecognized ASF tag name: %s", it->first.toCString());
+      CLog::Log(LOGDEBUG, "unrecognized ASF tag name: %s", it->first.toCString(true));
   }
   tag.SetLoaded(true);
   return true;
 }
 
-bool CTagLoaderTagLib::ParseID3v2Tag(ID3v2::Tag *id3v2, EmbeddedArt *art, CMusicInfoTag& tag)
+char POPMtoXBMC(int popm)
 {
-  // Notes:
   // Ratings:
   // FROM: http://thiagoarrais.com/repos/banshee/src/Core/Banshee.Core/Banshee.Streaming/StreamRatingTagger.cs
   // The following schemes are used by the other POPM-compatible players:
@@ -256,7 +259,16 @@ bool CTagLoaderTagLib::ParseID3v2Tag(ID3v2::Tag *id3v2, EmbeddedArt *art, CMusic
   // Quod Libet: "quodlibet@lists.sacredchao.net" ratings
   //   (but that email can be changed):
   //   arbitrary scale from 0-255
+  if (popm == 0) return '0';
+  if (popm < 0x40) return '1';
+  if (popm < 0x80) return '2';
+  if (popm < 0xc0) return '3';
+  if (popm < 0xff) return '4';
+  return '5';
+}
 
+bool CTagLoaderTagLib::ParseID3v2Tag(ID3v2::Tag *id3v2, EmbeddedArt *art, CMusicInfoTag& tag)
+{
   //  tag.SetURL(strFile);
   if (!id3v2) return false;
 
@@ -264,23 +276,28 @@ bool CTagLoaderTagLib::ParseID3v2Tag(ID3v2::Tag *id3v2, EmbeddedArt *art, CMusic
   const ID3v2::FrameListMap& frameListMap = id3v2->frameListMap();
   for (ID3v2::FrameListMap::ConstIterator it = frameListMap.begin(); it != frameListMap.end(); ++it)
   {
-    if      (it->first == "TPE1")   tag.SetArtist(GetID3v2StringList(it->second));
-    else if (it->first == "TALB")   tag.SetAlbum(it->second.front()->toString().toCString(true));
-    else if (it->first == "TPE2")   tag.SetAlbumArtist(GetID3v2StringList(it->second));
-    else if (it->first == "TIT2")   tag.SetTitle(it->second.front()->toString().toCString(true));
-    else if (it->first == "TCON")   tag.SetGenre(it->second.front()->toString().toCString(true));
+    if      (it->first == "TPE1")   SetArtist(tag, GetID3v2StringList(it->second));
+    else if (it->first == "TALB")   tag.SetAlbum(it->second.front()->toString().to8Bit(true));
+    else if (it->first == "TPE2")   SetAlbumArtist(tag, GetID3v2StringList(it->second));
+    else if (it->first == "TIT2")   tag.SetTitle(it->second.front()->toString().to8Bit(true));
+    else if (it->first == "TCON")   SetGenre(tag, GetID3v2StringList(it->second));
     else if (it->first == "TRCK")   tag.SetTrackNumber(strtol(it->second.front()->toString().toCString(true), NULL, 10));
     else if (it->first == "TPOS")   tag.SetPartOfSet(strtol(it->second.front()->toString().toCString(true), NULL, 10));
     else if (it->first == "TYER")   tag.SetYear(strtol(it->second.front()->toString().toCString(true), NULL, 10));
     else if (it->first == "TCMP")   tag.SetCompilation((strtol(it->second.front()->toString().toCString(true), NULL, 10) == 0) ? false : true);
     else if (it->first == "TENC")   {} // EncodedBy
+    else if (it->first == "TCOP")   {} // Copyright message
+    else if (it->first == "TDRC")   tag.SetYear(strtol(it->second.front()->toString().toCString(true), NULL, 10));
+    else if (it->first == "TDRL")   tag.SetYear(strtol(it->second.front()->toString().toCString(true), NULL, 10));
+    else if (it->first == "TDTG")   {} // Tagging time
+    else if (it->first == "TLAN")   {} // Languages
     else if (it->first == "USLT")
       // Loop through any lyrics frames. Could there be multiple frames, how to choose?
       for (ID3v2::FrameList::ConstIterator lt = it->second.begin(); lt != it->second.end(); ++lt)
       {
         ID3v2::UnsynchronizedLyricsFrame *lyricsFrame = dynamic_cast<ID3v2::UnsynchronizedLyricsFrame *> (*lt);
         if (lyricsFrame)           
-          tag.SetLyrics(lyricsFrame->text().toCString());
+          tag.SetLyrics(lyricsFrame->text().to8Bit(true));
       }
     else if (it->first == "COMM")
       // Loop through and look for the main (no description) comment
@@ -288,7 +305,7 @@ bool CTagLoaderTagLib::ParseID3v2Tag(ID3v2::Tag *id3v2, EmbeddedArt *art, CMusic
       {
         ID3v2::CommentsFrame *commentsFrame = dynamic_cast<ID3v2::CommentsFrame *> (*ct);
         if (commentsFrame && commentsFrame->description().isEmpty())
-          tag.SetComment(commentsFrame->text().toCString());
+          tag.SetComment(commentsFrame->text().to8Bit(true));
       }
     else if (it->first == "TXXX")
       // Loop through and process the UserTextIdentificationFrames
@@ -300,15 +317,15 @@ bool CTagLoaderTagLib::ParseID3v2Tag(ID3v2::Tag *id3v2, EmbeddedArt *art, CMusic
         // First field is the same as the description
         StringList stringList = frame->fieldList(); 
         stringList.erase(stringList.begin());
-        if      (frame->description() == "MusicBrainz Artist Id")       tag.SetMusicBrainzArtistID(stringList.front().toCString());
-        else if (frame->description() == "MusicBrainz Album Id")        tag.SetMusicBrainzAlbumID(stringList.front().toCString());
-        else if (frame->description() == "MusicBrainz Album Artist Id") tag.SetMusicBrainzAlbumArtistID(stringList.front().toCString());
-        else if (frame->description() == "replaygain_track_gain")       tag.SetReplayGainTrackGain((int)(atof(stringList.front().toCString()) * 100 + 0.5));
-        else if (frame->description() == "replaygain_album_gain")       tag.SetReplayGainAlbumGain((int)(atof(stringList.front().toCString()) * 100 + 0.5));
-        else if (frame->description() == "replaygain_track_peak")       tag.SetReplayGainTrackPeak((float)atof(stringList.front().toCString()));
-        else if (frame->description() == "replaygain_album_peak")       tag.SetReplayGainAlbumPeak((float)atof(stringList.front().toCString()));
+        if      (frame->description() == "MusicBrainz Artist Id")       tag.SetMusicBrainzArtistID(stringList.front().to8Bit(true));
+        else if (frame->description() == "MusicBrainz Album Id")        tag.SetMusicBrainzAlbumID(stringList.front().to8Bit(true));
+        else if (frame->description() == "MusicBrainz Album Artist Id") tag.SetMusicBrainzAlbumArtistID(stringList.front().to8Bit(true));
+        else if (frame->description() == "replaygain_track_gain")       tag.SetReplayGainTrackGain((int)(atof(stringList.front().toCString(true)) * 100 + 0.5));
+        else if (frame->description() == "replaygain_album_gain")       tag.SetReplayGainAlbumGain((int)(atof(stringList.front().toCString(true)) * 100 + 0.5));
+        else if (frame->description() == "replaygain_track_peak")       tag.SetReplayGainTrackPeak((float)atof(stringList.front().toCString(true)));
+        else if (frame->description() == "replaygain_album_peak")       tag.SetReplayGainAlbumPeak((float)atof(stringList.front().toCString(true)));
         else
-          CLog::Log(LOGDEBUG, "unrecognized user text tag detected: TXXX:%s", frame->description().toCString());
+          CLog::Log(LOGDEBUG, "unrecognized user text tag detected: TXXX:%s", frame->description().toCString(true));
       }
     else if (it->first == "UFID")
       // Loop through any UFID frames and set them
@@ -346,14 +363,15 @@ bool CTagLoaderTagLib::ParseID3v2Tag(ID3v2::Tag *id3v2, EmbeddedArt *art, CMusic
         // @xbmc.org ratings trump others (of course)
         if      (popFrame->email() == "ratings@xbmc.org")
           tag.SetRating(popFrame->rating() / 51 + '0');
-        else if (popFrame->email() == "Windows Media Player 9 Series" && tag.GetRating() == '0')  
-          tag.SetRating(popFrame->rating() / 51 + '0');
-        else if (popFrame->email() == "no@email" && tag.GetRating() == '0')                       
-          tag.SetRating(popFrame->rating() / 51 + '0');
-        else if (popFrame->email() == "quodlibet@lists.sacredchao.net" && tag.GetRating() == '0') 
-          tag.SetRating(popFrame->rating() / 51 + '0');
-        else
-          CLog::Log(LOGDEBUG, "unrecognized ratings schema detected: %s", popFrame->email().toCString());
+        else if (tag.GetRating() == '0')
+        {
+          if (popFrame->email() != "Windows Media Player 9 Series" &&
+              popFrame->email() != "no@email" &&
+              popFrame->email() != "quodlibet@lists.sacredchao.net" &&
+              popFrame->email() != "rating@winamp.com")
+            CLog::Log(LOGDEBUG, "unrecognized ratings schema detected: %s", popFrame->email().toCString(true));
+          tag.SetRating(POPMtoXBMC(popFrame->rating()));
+        }
       }
     else
       CLog::Log(LOGDEBUG, "unrecognized ID3 frame detected: %c%c%c%c", it->first[0], it->first[1], it->first[2], it->first[3]);
@@ -363,7 +381,7 @@ bool CTagLoaderTagLib::ParseID3v2Tag(ID3v2::Tag *id3v2, EmbeddedArt *art, CMusic
   for (int i = 0; i < 3; ++i)
     if (pictures[i])
     {
-      string      mime =             pictures[i]->mimeType().toCString();
+      string      mime =             pictures[i]->mimeType().to8Bit(true);
       TagLib::uint size =            pictures[i]->picture().size();
       tag.SetCoverArtInfo(size, mime);
       if (art)
@@ -383,28 +401,28 @@ bool CTagLoaderTagLib::ParseAPETag(APE::Tag *ape, EmbeddedArt *art, CMusicInfoTa
   const APE::ItemListMap itemListMap = ape->itemListMap();
   for (APE::ItemListMap::ConstIterator it = itemListMap.begin(); it != itemListMap.end(); ++it)
   {
-    if (it->first == "ARTIST")                         tag.SetArtist(StringListToVectorString(it->second.toStringList()));
-    else if (it->first == "ALBUM ARTIST")              tag.SetAlbumArtist(StringListToVectorString(it->second.toStringList()));
-    else if (it->first == "ALBUM")                     tag.SetAlbum(it->second.toString().toCString());
-    else if (it->first == "TITLE")                     tag.SetTitle(it->second.toString().toCString());
+    if (it->first == "ARTIST")                         SetArtist(tag, StringListToVectorString(it->second.toStringList()));
+    else if (it->first == "ALBUM ARTIST")              SetAlbumArtist(tag, StringListToVectorString(it->second.toStringList()));
+    else if (it->first == "ALBUM")                     tag.SetAlbum(it->second.toString().to8Bit(true));
+    else if (it->first == "TITLE")                     tag.SetTitle(it->second.toString().to8Bit(true));
     else if (it->first == "TRACKNUMBER")               tag.SetTrackNumber(it->second.toString().toInt());
     else if (it->first == "DISCNUMBER")                tag.SetPartOfSet(it->second.toString().toInt());
     else if (it->first == "YEAR")                      tag.SetYear(it->second.toString().toInt());
-    else if (it->first == "GENRE")                     tag.SetGenre(StringListToVectorString(it->second.toStringList()));
-    else if (it->first == "COMMENT")                   tag.SetComment(it->second.toString().toCString());
+    else if (it->first == "GENRE")                     SetGenre(tag, StringListToVectorString(it->second.toStringList()));
+    else if (it->first == "COMMENT")                   tag.SetComment(it->second.toString().to8Bit(true));
     else if (it->first == "ENCODEDBY")                 {}
     else if (it->first == "COMPILATION")               tag.SetCompilation(it->second.toString().toInt() == 1);
-    else if (it->first == "LYRICS")                    tag.SetLyrics(it->second.toString().toCString());
-    else if (it->first == "REPLAYGAIN_TRACK_GAIN")     tag.SetReplayGainTrackGain((int)(atof(it->second.toString().toCString()) * 100 + 0.5));
-    else if (it->first == "REPLAYGAIN_ALBUM_GAIN")     tag.SetReplayGainAlbumGain((int)(atof(it->second.toString().toCString()) * 100 + 0.5));
-    else if (it->first == "REPLAYGAIN_TRACK_PEAK")     tag.SetReplayGainTrackPeak((float)atof(it->second.toString().toCString()));
-    else if (it->first == "REPLAYGAIN_ALBUM_PEAK")     tag.SetReplayGainAlbumPeak((float)atof(it->second.toString().toCString()));
-    else if (it->first == "MUSICBRAINZ_ARTISTID")      tag.SetMusicBrainzArtistID(it->second.toString().toCString());
-    else if (it->first == "MUSICBRAINZ_ALBUMARTISTID") tag.SetMusicBrainzAlbumArtistID(it->second.toString().toCString());
-    else if (it->first == "MUSICBRAINZ_ALBUMID")       tag.SetMusicBrainzAlbumID(it->second.toString().toCString());
-    else if (it->first == "MUSICBRAINZ_TRACKID")       tag.SetMusicBrainzTrackID(it->second.toString().toCString());
+    else if (it->first == "LYRICS")                    tag.SetLyrics(it->second.toString().to8Bit(true));
+    else if (it->first == "REPLAYGAIN_TRACK_GAIN")     tag.SetReplayGainTrackGain((int)(atof(it->second.toString().toCString(true)) * 100 + 0.5));
+    else if (it->first == "REPLAYGAIN_ALBUM_GAIN")     tag.SetReplayGainAlbumGain((int)(atof(it->second.toString().toCString(true)) * 100 + 0.5));
+    else if (it->first == "REPLAYGAIN_TRACK_PEAK")     tag.SetReplayGainTrackPeak((float)atof(it->second.toString().toCString(true)));
+    else if (it->first == "REPLAYGAIN_ALBUM_PEAK")     tag.SetReplayGainAlbumPeak((float)atof(it->second.toString().toCString(true)));
+    else if (it->first == "MUSICBRAINZ_ARTISTID")      tag.SetMusicBrainzArtistID(it->second.toString().to8Bit(true));
+    else if (it->first == "MUSICBRAINZ_ALBUMARTISTID") tag.SetMusicBrainzAlbumArtistID(it->second.toString().to8Bit(true));
+    else if (it->first == "MUSICBRAINZ_ALBUMID")       tag.SetMusicBrainzAlbumID(it->second.toString().to8Bit(true));
+    else if (it->first == "MUSICBRAINZ_TRACKID")       tag.SetMusicBrainzTrackID(it->second.toString().to8Bit(true));
     else
-      CLog::Log(LOGDEBUG, "unrecognized APE tag: %s", it->first.toCString());
+      CLog::Log(LOGDEBUG, "unrecognized APE tag: %s", it->first.toCString(true));
   }
 
   return true;
@@ -418,26 +436,29 @@ bool CTagLoaderTagLib::ParseXiphComment(Ogg::XiphComment *xiph, EmbeddedArt *art
   const Ogg::FieldListMap& fieldListMap = xiph->fieldListMap();
   for (Ogg::FieldListMap::ConstIterator it = fieldListMap.begin(); it != fieldListMap.end(); ++it)
   {
-    if (it->first == "ARTIST")                         tag.SetArtist(StringListToVectorString(it->second));
-    else if (it->first == "ALBUMARTIST")               tag.SetAlbumArtist(StringListToVectorString(it->second));
-    else if (it->first == "ALBUM")                     tag.SetAlbum(it->second.front().toCString());
-    else if (it->first == "TITLE")                     tag.SetTitle(it->second.front().toCString());
+    if (it->first == "ARTIST")                         SetArtist(tag, StringListToVectorString(it->second));
+    else if (it->first == "ALBUMARTIST")               SetAlbumArtist(tag, StringListToVectorString(it->second));
+    else if (it->first == "ALBUM ARTIST")              SetAlbumArtist(tag, StringListToVectorString(it->second));
+    else if (it->first == "ALBUM")                     tag.SetAlbum(it->second.front().to8Bit(true));
+    else if (it->first == "TITLE")                     tag.SetTitle(it->second.front().to8Bit(true));
     else if (it->first == "TRACKNUMBER")               tag.SetTrackNumber(it->second.front().toInt());
     else if (it->first == "DISCNUMBER")                tag.SetPartOfSet(it->second.front().toInt());
     else if (it->first == "YEAR")                      tag.SetYear(it->second.front().toInt());
-    else if (it->first == "GENRE")                     tag.SetGenre(StringListToVectorString(it->second));
-    else if (it->first == "COMMENT")                   tag.SetComment(it->second.front().toCString());
+    else if (it->first == "DATE")                      tag.SetYear(it->second.front().toInt());
+    else if (it->first == "GENRE")                     SetGenre(tag, StringListToVectorString(it->second));
+    else if (it->first == "COMMENT")                   tag.SetComment(it->second.front().to8Bit(true));
     else if (it->first == "ENCODEDBY")                 {}
+    else if (it->first == "ENSEMBLE")                  {}
     else if (it->first == "COMPILATION")               tag.SetCompilation(it->second.front().toInt() == 1);
-    else if (it->first == "LYRICS")                    tag.SetLyrics(it->second.front().toCString());
-    else if (it->first == "REPLAYGAIN_TRACK_GAIN")     tag.SetReplayGainTrackGain((int)(atof(it->second.front().toCString()) * 100 + 0.5));
-    else if (it->first == "REPLAYGAIN_ALBUM_GAIN")     tag.SetReplayGainAlbumGain((int)(atof(it->second.front().toCString()) * 100 + 0.5));
-    else if (it->first == "REPLAYGAIN_TRACK_PEAK")     tag.SetReplayGainTrackPeak((float)atof(it->second.front().toCString()));
-    else if (it->first == "REPLAYGAIN_ALBUM_PEAK")     tag.SetReplayGainAlbumPeak((float)atof(it->second.front().toCString()));
-    else if (it->first == "MUSICBRAINZ_ARTISTID")      tag.SetMusicBrainzArtistID(it->second.front().toCString());
-    else if (it->first == "MUSICBRAINZ_ALBUMARTISTID") tag.SetMusicBrainzAlbumArtistID(it->second.front().toCString());
-    else if (it->first == "MUSICBRAINZ_ALBUMID")       tag.SetMusicBrainzAlbumID(it->second.front().toCString());
-    else if (it->first == "MUSICBRAINZ_TRACKID")       tag.SetMusicBrainzTrackID(it->second.front().toCString());
+    else if (it->first == "LYRICS")                    tag.SetLyrics(it->second.front().to8Bit(true));
+    else if (it->first == "REPLAYGAIN_TRACK_GAIN")     tag.SetReplayGainTrackGain((int)(atof(it->second.front().toCString(true)) * 100 + 0.5));
+    else if (it->first == "REPLAYGAIN_ALBUM_GAIN")     tag.SetReplayGainAlbumGain((int)(atof(it->second.front().toCString(true)) * 100 + 0.5));
+    else if (it->first == "REPLAYGAIN_TRACK_PEAK")     tag.SetReplayGainTrackPeak((float)atof(it->second.front().toCString(true)));
+    else if (it->first == "REPLAYGAIN_ALBUM_PEAK")     tag.SetReplayGainAlbumPeak((float)atof(it->second.front().toCString(true)));
+    else if (it->first == "MUSICBRAINZ_ARTISTID")      tag.SetMusicBrainzArtistID(it->second.front().to8Bit(true));
+    else if (it->first == "MUSICBRAINZ_ALBUMARTISTID") tag.SetMusicBrainzAlbumArtistID(it->second.front().to8Bit(true));
+    else if (it->first == "MUSICBRAINZ_ALBUMID")       tag.SetMusicBrainzAlbumID(it->second.front().to8Bit(true));
+    else if (it->first == "MUSICBRAINZ_TRACKID")       tag.SetMusicBrainzTrackID(it->second.front().to8Bit(true));
     else if (it->first == "RATING")
     {
       // Vorbis ratings are a mess because the standard forgot to mention anything about them.
@@ -450,7 +471,7 @@ bool CTagLoaderTagLib::ParseXiphComment(Ogg::XiphComment *xiph, EmbeddedArt *art
         tag.SetRating((iRating / 20) + '0');
     }
     else
-      CLog::Log(LOGDEBUG, "unrecognized XipComment name: %s", it->first.toCString());
+      CLog::Log(LOGDEBUG, "unrecognized XipComment name: %s", it->first.toCString(true));
   }
 
   return true;
@@ -464,24 +485,24 @@ bool CTagLoaderTagLib::ParseMP4Tag(MP4::Tag *mp4, EmbeddedArt *art, CMusicInfoTa
   MP4::ItemListMap& itemListMap = mp4->itemListMap();
   for (MP4::ItemListMap::ConstIterator it = itemListMap.begin(); it != itemListMap.end(); ++it)
   {
-    if (it->first == "\251nam")      tag.SetTitle(it->second.toStringList().front().toCString());
-    else if (it->first == "\251ART") tag.SetArtist(StringListToVectorString(it->second.toStringList()));
-    else if (it->first == "\251alb") tag.SetAlbum(it->second.toStringList().front().toCString());
-    else if (it->first == "aART")    tag.SetAlbumArtist(StringListToVectorString(it->second.toStringList()));
-    else if (it->first == "\251gen") tag.SetGenre(StringListToVectorString(it->second.toStringList()));
-    else if (it->first == "\251cmt") tag.SetComment(it->second.toStringList().front().toCString());
+    if (it->first == "\251nam")      tag.SetTitle(it->second.toStringList().front().to8Bit(true));
+    else if (it->first == "\251ART") SetArtist(tag, StringListToVectorString(it->second.toStringList()));
+    else if (it->first == "\251alb") tag.SetAlbum(it->second.toStringList().front().to8Bit(true));
+    else if (it->first == "aART")    SetAlbumArtist(tag, StringListToVectorString(it->second.toStringList()));
+    else if (it->first == "\251gen") SetGenre(tag, StringListToVectorString(it->second.toStringList()));
+    else if (it->first == "\251cmt") tag.SetComment(it->second.toStringList().front().to8Bit(true));
     else if (it->first == "cpil")    tag.SetCompilation(it->second.toBool());
     else if (it->first == "trkn")    tag.SetTrackNumber(it->second.toIntPair().first);
     else if (it->first == "disk")    tag.SetPartOfSet(it->second.toIntPair().first);
     else if (it->first == "\251day") tag.SetYear(it->second.toStringList().front().toInt());
     else if (it->first == "----:com.apple.iTunes:MusicBrainz Artist Id")
-      tag.SetMusicBrainzArtistID(it->second.toStringList().front().toCString());
+      tag.SetMusicBrainzArtistID(it->second.toStringList().front().to8Bit(true));
     else if (it->first == "----:com.apple.iTunes:MusicBrainz Album Artist Id")
-      tag.SetMusicBrainzAlbumArtistID(it->second.toStringList().front().toCString());
+      tag.SetMusicBrainzAlbumArtistID(it->second.toStringList().front().to8Bit(true));
     else if (it->first == "----:com.apple.iTunes:MusicBrainz Album Id")
-      tag.SetMusicBrainzAlbumID(it->second.toStringList().front().toCString());
+      tag.SetMusicBrainzAlbumID(it->second.toStringList().front().to8Bit(true));
     else if (it->first == "----:com.apple.iTunes:MusicBrainz Track Id")
-      tag.SetMusicBrainzTrackID(it->second.toStringList().front().toCString());
+      tag.SetMusicBrainzTrackID(it->second.toStringList().front().to8Bit(true));
     else if (it->first == "covr")
     {
       MP4::CoverArtList coverArtList = it->second.toCoverArtList();
@@ -508,23 +529,47 @@ bool CTagLoaderTagLib::ParseGenericTag(Tag *generic, EmbeddedArt *art, CMusicInf
   PropertyMap properties = generic->properties();
   for (PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it)
   {
-    if (it->first == "ARTIST")                         tag.SetArtist(StringListToVectorString(it->second));
-    else if (it->first == "ALBUM")                     tag.SetArtist(it->second.front().toCString());
-    else if (it->first == "TITLE")                     tag.SetTitle(it->second.front().toCString());
+    if (it->first == "ARTIST")                         SetArtist(tag, StringListToVectorString(it->second));
+    else if (it->first == "ALBUM")                     tag.SetAlbum(it->second.front().to8Bit(true));
+    else if (it->first == "TITLE")                     tag.SetTitle(it->second.front().to8Bit(true));
     else if (it->first == "TRACKNUMBER")               tag.SetTrackNumber(it->second.front().toInt());
     else if (it->first == "YEAR")                      tag.SetYear(it->second.front().toInt());
-    else if (it->first == "GENRE")                     tag.SetGenre(StringListToVectorString(it->second));
-    else if (it->first == "COMMENT")                   tag.SetGenre(it->second.front().toCString());
+    else if (it->first == "GENRE")                     SetGenre(tag, StringListToVectorString(it->second));
+    else if (it->first == "COMMENT")                   tag.SetComment(it->second.front().to8Bit(true));
   }
 
   return true;
 }
 
+void CTagLoaderTagLib::SetFlacArt(FLAC::File *flacFile, EmbeddedArt *art, CMusicInfoTag &tag)
+{
+  FLAC::Picture *cover[2] = {};
+  List<FLAC::Picture *> pictures = flacFile->pictureList();
+  for (List<FLAC::Picture *>::ConstIterator i = pictures.begin(); i != pictures.end(); ++i)
+  {
+    FLAC::Picture *picture = *i;
+    if (picture->type() == FLAC::Picture::FrontCover)
+      cover[0] = picture;
+    else // anything else is taken as second priority
+      cover[1] = picture;
+  }
+  for (unsigned int i = 0; i < 2; i++)
+  {
+    if (cover[i])
+    {
+      tag.SetCoverArtInfo(cover[i]->data().size(), cover[i]->mimeType().to8Bit(true));
+      if (art)
+        art->set((const uint8_t*)cover[i]->data().data(), cover[i]->data().size(), cover[i]->mimeType().to8Bit(true));
+      return; // one is enough
+    }
+  }
+}
+
 const vector<string> CTagLoaderTagLib::GetASFStringList(const List<ASF::Attribute>& list)
 {
   vector<string> values;
   for (List<ASF::Attribute>::ConstIterator at = list.begin(); at != list.end(); ++at)
-    values.push_back(at->toString().toCString());
+    values.push_back(at->toString().to8Bit(true));
   return values;
 }
 
@@ -535,3 +580,27 @@ const vector<string> CTagLoaderTagLib::GetID3v2StringList(const ID3v2::FrameList
     return StringListToVectorString(frame->fieldList());
   return vector<string>();
 }
+
+void CTagLoaderTagLib::SetArtist(CMusicInfoTag &tag, const vector<string> &values)
+{
+  if (values.size() == 1)
+    tag.SetArtist(values[0]);
+  else
+    tag.SetArtist(values);
+}
+
+void CTagLoaderTagLib::SetAlbumArtist(CMusicInfoTag &tag, const vector<string> &values)
+{
+  if (values.size() == 1)
+    tag.SetAlbumArtist(values[0]);
+  else
+    tag.SetAlbumArtist(values);
+}
+
+void CTagLoaderTagLib::SetGenre(CMusicInfoTag &tag, const vector<string> &values)
+{
+  if (values.size() == 1)
+    tag.SetGenre(values[0]);
+  else
+    tag.SetGenre(values);
+}
index 0a868bb..e81b41d 100644 (file)
@@ -68,4 +68,8 @@ private:
   bool                           ParseXiphComment(TagLib::Ogg::XiphComment *id3v2, MUSIC_INFO::EmbeddedArt *art, MUSIC_INFO::CMusicInfoTag& tag);
   bool                           ParseMP4Tag(TagLib::MP4::Tag *mp4, MUSIC_INFO::EmbeddedArt *art, MUSIC_INFO::CMusicInfoTag& tag);
   bool                           ParseGenericTag(TagLib::Tag *generic, MUSIC_INFO::EmbeddedArt *art, MUSIC_INFO::CMusicInfoTag& tag);
+  void                           SetFlacArt(TagLib::FLAC::File *flacFile, MUSIC_INFO::EmbeddedArt *art, MUSIC_INFO::CMusicInfoTag &tag);
+  void                           SetArtist(MUSIC_INFO::CMusicInfoTag &tag, const std::vector<std::string> &values);
+  void                           SetAlbumArtist(MUSIC_INFO::CMusicInfoTag &tag, const std::vector<std::string> &values);
+  void                           SetGenre(MUSIC_INFO::CMusicInfoTag &tag, const std::vector<std::string> &values);
 };
\ No newline at end of file
index 2e7a2e9..552813d 100644 (file)
@@ -1314,11 +1314,38 @@ void CGUIWindowMusicBase::OnRetrieveMusicInfo(CFileItemList& items)
 
 bool CGUIWindowMusicBase::GetDirectory(const CStdString &strDirectory, CFileItemList &items)
 {
-  items.SetThumbnailImage("");
-  bool bResult = CGUIMediaWindow::GetDirectory(strDirectory,items);
+  CStdString directory = strDirectory;
+
+  // check if the path contains a filter and if so load it and
+  // remove it from the path to get proper GUI view states etc
+  CSmartPlaylist filterXsp;
+  CMusicDbUrl musicUrl;
+  if (musicUrl.FromString(strDirectory))
+  {
+    CVariant filter;
+    if (musicUrl.GetOption("filter", filter))
+    {
+      // load the filter and if it's type does not match the
+      // path's item type reset it
+      if (filterXsp.LoadFromJson(filter.asString()) && !filterXsp.GetType().Equals(musicUrl.GetType().c_str()))
+        filterXsp.Reset();
+
+      // remove the "filter" option from the path
+      musicUrl.AddOption("filter", "");
+    }
+    directory = musicUrl.ToString();
+  }
+
+  items.SetArt("thumb", "");
+  bool bResult = CGUIMediaWindow::GetDirectory(directory, items);
   if (bResult)
     CMusicThumbLoader::FillThumb(items);
 
+  // (re-)apply the previously retrieved filter
+  // because it was reset in CGUIMediaWindow::GetDirectory()
+  if (!filterXsp.IsEmpty())
+    m_filter = filterXsp;
+
   // add in the "New Playlist" item if we're in the playlists folder
   if ((items.GetPath() == "special://musicplaylists/") && !items.Contains("newplaylist://"))
   {
@@ -1350,6 +1377,15 @@ void CGUIWindowMusicBase::OnPrepareFileItems(CFileItemList &items)
 {
 }
 
+bool CGUIWindowMusicBase::CheckFilterAdvanced(CFileItemList &items)
+{
+  CStdString content = items.GetContent();
+  if (items.IsMusicDb() && (content.Equals("artists") || content.Equals("albums") || content.Equals("songs")))
+    return true;
+
+  return false;
+}
+
 void CGUIWindowMusicBase::OnInitWindow()
 {
   CGUIMediaWindow::OnInitWindow();
index 1de6b29..2b8fd67 100644 (file)
@@ -71,6 +71,8 @@ protected:
   virtual void OnPrepareFileItems(CFileItemList &items);
   virtual CStdString GetStartFolder(const CStdString &dir);
 
+  virtual bool CheckFilterAdvanced(CFileItemList &items);
+
   // new methods
   virtual void PlayItem(int iItem);
   virtual bool OnPlayMedia(int iItem);
index 88c5514..c24f744 100644 (file)
@@ -272,7 +272,7 @@ bool CGUIWindowMusicNav::Update(const CStdString &strDirectory)
 
   if (CGUIWindowMusicBase::Update(strDirectory))
   {
-    m_thumbLoader.Load(*m_vecItems);
+    m_thumbLoader.Load(*m_unfilteredItems);
     return true;
   }
 
@@ -418,7 +418,7 @@ void CGUIWindowMusicNav::GetContextButtons(int itemNumber, CContextButtons &butt
   CFileItemPtr item;
   if (itemNumber >= 0 && itemNumber < m_vecItems->Size())
     item = m_vecItems->Get(itemNumber);
-  if (item && (item->GetExtraInfo().Find("lastfm") < 0))
+  if (item && (item->GetExtraInfo().Find("lastfm") < 0)  && !item->GetPath().Left(14).Equals("addons://more/"))
   {
     // are we in the playlists location?
     bool inPlaylists = m_vecItems->GetPath().Equals(CUtil::MusicPlaylistsLocation()) ||
@@ -541,7 +541,10 @@ void CGUIWindowMusicNav::GetContextButtons(int itemNumber, CContextButtons &butt
   if (g_application.IsMusicScanning())
     buttons.Add(CONTEXT_BUTTON_STOP_SCANNING, 13353);     // Stop Scanning
   else
-    buttons.Add(CONTEXT_BUTTON_UPDATE_LIBRARY, 653);
+  {
+    if (!m_vecItems->IsPlugin())
+      buttons.Add(CONTEXT_BUTTON_UPDATE_LIBRARY, 653);
+  }
 
   CGUIWindowMusicBase::GetNonContextButtons(buttons);
 }
index 014eb66..6e44967 100644 (file)
@@ -318,7 +318,7 @@ void CGUIWindowMusicSongs::GetContextButtons(int itemNumber, CContextButtons &bu
       CGUIWindowMusicBase::GetContextButtons(itemNumber, buttons);
       if (item->GetProperty("pluginreplacecontextitems").asBoolean())
         return;
-      if (!item->IsPlayList())
+      if (!item->IsPlayList() && !item->IsPlugin() && !item->IsScript())
       {
         if (item->IsAudio() && !item->IsLastFM())
           buttons.Add(CONTEXT_BUTTON_SONG_INFO, 658); // Song Info
@@ -368,6 +368,7 @@ void CGUIWindowMusicSongs::GetContextButtons(int itemNumber, CContextButtons &bu
              !item->IsLastFM()                                         &&
              !item->GetPath().Equals("add") && !item->IsParentFolder() &&
              !item->IsPlugin()                                         &&
+             !item->GetPath().Left(9).Equals("addons://")              &&
             (g_settings.GetCurrentProfile().canWriteDatabases() || g_passwordManager.bMasterUser))
     {
       buttons.Add(CONTEXT_BUTTON_SCAN, 13352);
@@ -375,7 +376,7 @@ void CGUIWindowMusicSongs::GetContextButtons(int itemNumber, CContextButtons &bu
     if (item->IsPlugin() || item->IsScript() || m_vecItems->IsPlugin())
       buttons.Add(CONTEXT_BUTTON_PLUGIN_SETTINGS, 1045);
   }
-  if (!m_vecItems->IsVirtualDirectoryRoot())
+  if (!m_vecItems->IsVirtualDirectoryRoot() && !m_vecItems->IsPlugin())
     buttons.Add(CONTEXT_BUTTON_SWITCH_MEDIA, 523);
   CGUIWindowMusicBase::GetNonContextButtons(buttons);
 }
index 66f2cef..83ac473 100644 (file)
@@ -35,7 +35,8 @@
 #include "ApplicationMessenger.h"
 #include "filesystem/PipeFile.h"
 #include "Application.h"
-#include "cores/paplayer/BXAcodec.h"
+#include "cores/dvdplayer/DVDDemuxers/DVDDemuxBXA.h"
+#include "filesystem/File.h"
 #include "music/tags/MusicInfoTag.h"
 #include "FileItem.h"
 #include "GUIInfoManager.h"
@@ -160,9 +161,9 @@ void* CAirTunesServer::AudioOutputFunctions::audio_init(void *cls, int bits, int
   pipe->OpenForWrite(XFILE::PipesManager::GetInstance().GetUniquePipeName());
   pipe->SetOpenThreashold(300);
 
-  BXA_FmtHeader header;
+  Demux_BXA_FmtHeader header;
   strncpy(header.fourcc, "BXA ", 4);
-  header.type = BXA_PACKET_TYPE_FMT;
+  header.type = BXA_PACKET_TYPE_FMT_DEMUX;
   header.bitsPerSample = bits;
   header.channels = channels;
   header.sampleRate = samplerate;
@@ -328,9 +329,9 @@ ao_device* CAirTunesServer::AudioOutputFunctions::ao_open_live(int driver_id, ao
   device->pipe->OpenForWrite(XFILE::PipesManager::GetInstance().GetUniquePipeName());
   device->pipe->SetOpenThreashold(300);
 
-  BXA_FmtHeader header;
+  Demux_BXA_FmtHeader header;
   strncpy(header.fourcc, "BXA ", 4);
-  header.type = BXA_PACKET_TYPE_FMT;
+  header.type = BXA_PACKET_TYPE_FMT_DEMUX;
   header.bitsPerSample = format->bits;
   header.channels = format->channels;
   header.sampleRate = format->rate;
index 2b5705c..e04d276 100644 (file)
@@ -92,11 +92,11 @@ void CGUIDialogAccessPoints::OnInitWindow()
       CFileItemPtr item(new CFileItem(m_aps[i].getEssId()));
 
       int q = m_aps[i].getQuality();
-      if (q <= 20) item->SetThumbnailImage("ap-signal1.png");
-      else if (q <= 40) item->SetThumbnailImage("ap-signal2.png");
-      else if (q <= 60) item->SetThumbnailImage("ap-signal3.png");
-      else if (q <= 80) item->SetThumbnailImage("ap-signal4.png");
-      else if (q <= 100) item->SetThumbnailImage("ap-signal5.png");
+      if (q <= 20) item->SetArt("thumb", "ap-signal1.png");
+      else if (q <= 40) item->SetArt("thumb", "ap-signal2.png");
+      else if (q <= 60) item->SetArt("thumb", "ap-signal3.png");
+      else if (q <= 80) item->SetArt("thumb", "ap-signal4.png");
+      else if (q <= 100) item->SetArt("thumb", "ap-signal5.png");
 
       if (m_aps[i].getEncryptionMode() != ENC_NONE)
          item->SetIconImage("ap-lock.png");
index ae44fb6..a6a396a 100644 (file)
@@ -575,7 +575,7 @@ void Xcddb::parseData(const char *buffer)
           if (StringUtils::IsNaturalNumber(strGenre))
           {
             int iGenre = strtol(strGenre, NULL, 10);
-            m_strGenre = TagLib::ID3v1::genre(iGenre).toCString();
+            m_strGenre = TagLib::ID3v1::genre(iGenre).to8Bit(true);
           }
         }
       }
diff --git a/xbmc/network/httprequesthandler/HTTPApiHandler.cpp b/xbmc/network/httprequesthandler/HTTPApiHandler.cpp
deleted file mode 100644 (file)
index bd34d23..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- *      Copyright (C) 2011-2012 Team XBMC
- *      http://www.xbmc.org
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with XBMC; see the file COPYING.  If not, see
- *  <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <map>
-
-#include "HTTPApiHandler.h"
-#include "interfaces/http-api/HttpApi.h"
-#include "network/WebServer.h"
-
-using namespace std;
-
-bool CHTTPApiHandler::CheckHTTPRequest(const HTTPRequest &request)
-{
-  return ((request.method == GET || request.method == POST) && request.url.find("/xbmcCmds/xbmcHttp") == 0);
-}
-
-int CHTTPApiHandler::HandleHTTPRequest(const HTTPRequest &request)
-{
-  map<string, string> arguments;
-  if (CWebServer::GetRequestHeaderValues(request.connection, MHD_GET_ARGUMENT_KIND, arguments) > 0)
-  {
-    m_responseCode = MHD_HTTP_OK;
-    m_responseType = HTTPMemoryDownloadNoFreeCopy;
-    CStdString command = arguments["command"];
-    CStdString parameter = arguments["parameter"];
-    m_response = CHttpApi::WebMethodCall(command, parameter);
-
-    return MHD_YES;
-  }
-
-  return MHD_NO;
-}
diff --git a/xbmc/network/httprequesthandler/HTTPApiHandler.h b/xbmc/network/httprequesthandler/HTTPApiHandler.h
deleted file mode 100644 (file)
index 70ea739..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#pragma once
-/*
- *      Copyright (C) 2011-2012 Team XBMC
- *      http://www.xbmc.org
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with XBMC; see the file COPYING.  If not, see
- *  <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "IHTTPRequestHandler.h"
-
-class CHTTPApiHandler : public IHTTPRequestHandler
-{
-public:
-  CHTTPApiHandler() { };
-
-  virtual IHTTPRequestHandler* GetInstance() { return new CHTTPApiHandler(); }
-  virtual bool CheckHTTPRequest(const HTTPRequest &request);
-  virtual int HandleHTTPRequest(const HTTPRequest &request);
-
-  virtual void* GetHTTPResponseData() const { return (void *)m_response.c_str(); };
-  virtual size_t GetHTTPResonseDataLength() const { return m_response.size(); }
-
-  virtual int GetPriority() const { return 2; }
-
-private:
-  std::string m_response;
-};
index 47ca37f..aae8aa5 100644 (file)
@@ -1,5 +1,4 @@
-SRCS=HTTPApiHandler.cpp \
-     HTTPImageHandler.cpp \
+SRCS=HTTPImageHandler.cpp \
      HTTPJsonRpcHandler.cpp \
      HTTPVfsHandler.cpp \
      HTTPWebinterfaceAddonsHandler.cpp \
index e011e04..6081415 100644 (file)
@@ -183,6 +183,7 @@ public:
             path += "/";
         }
 
+        CLog::Log(LOGDEBUG, "UPNP: notfified container update %s", (const char*)path);
         CGUIMessage message(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_PATH);
         message.SetStringParam(path.GetChars());
         g_windowManager.SendThreadMessage(message);
index 8acb55d..9dc1837 100644 (file)
 #include "filesystem/StackDirectory.h"
 #include "filesystem/MusicDatabaseDirectory.h"
 #include "filesystem/VideoDatabaseDirectory.h"
+#include "video/VideoDatabase.h"
 #include "video/VideoInfoTag.h"
+#include "music/MusicDatabase.h"
 #include "music/tags/MusicInfoTag.h"
+#include "TextureCache.h"
+#include "ThumbLoader.h"
 
 using namespace MUSIC_INFO;
 using namespace XFILE;
@@ -206,6 +210,9 @@ PopulateObjectFromTag(CMusicInfoTag&         tag,
     if (object.m_ReferenceID == object.m_ObjectID)
         object.m_ReferenceID = "";
 
+    object.m_MiscInfo.last_time = tag.GetLastPlayed().GetAsDBDate();
+    object.m_MiscInfo.play_count = tag.GetPlayCount();
+
     if (resource) resource->m_Duration = tag.GetDuration();
 
     return NPT_SUCCESS;
@@ -228,27 +235,28 @@ PopulateObjectFromTag(CVideoInfoTag&         tag,
       *file_path = tag.m_strFileNameAndPath;
 
     if (tag.m_iDbId != -1 ) {
-        if (!tag.m_artist.empty()) {
+        if (tag.m_type == "musicvideo") {
           object.m_ObjectClass.type = "object.item.videoItem.musicVideoClip";
           object.m_Creator = StringUtils::Join(tag.m_artist, g_advancedSettings.m_videoItemSeparator);
           object.m_Title = tag.m_strTitle;
           object.m_ReferenceID = NPT_String::Format("videodb://3/2/%i", tag.m_iDbId);
-        } else if (!tag.m_strShowTitle.IsEmpty()) {
+        } else if (tag.m_type == "movie") {
+          object.m_ObjectClass.type = "object.item.videoItem.movie";
+          object.m_Title = tag.m_strTitle;
+          object.m_Date = NPT_String::FromInteger(tag.m_iYear) + "-01-01";
+          object.m_ReferenceID = NPT_String::Format("videodb://1/2/%i", tag.m_iDbId);
+        } else {
           object.m_ObjectClass.type = "object.item.videoItem.videoBroadcast";
           object.m_Recorded.program_title  = "S" + ("0" + NPT_String::FromInteger(tag.m_iSeason)).Right(2);
           object.m_Recorded.program_title += "E" + ("0" + NPT_String::FromInteger(tag.m_iEpisode)).Right(2);
           object.m_Recorded.program_title += " : " + tag.m_strTitle;
           object.m_Recorded.series_title = tag.m_strShowTitle;
-          object.m_Recorded.episode_number = tag.m_iSeason * 100 + tag.m_iEpisode;
+          int season = tag.m_iSeason > 1 ? tag.m_iSeason : 1;
+          object.m_Recorded.episode_number = season * 100 + tag.m_iEpisode;
           object.m_Title = object.m_Recorded.series_title + " - " + object.m_Recorded.program_title;
-          object.m_Date = tag.m_firstAired.GetAsLocalizedDate();
+          object.m_Date = tag.m_firstAired.GetAsDBDate();
           if(tag.m_iSeason != -1)
               object.m_ReferenceID = NPT_String::Format("videodb://2/0/%i", tag.m_iDbId);
-        } else {
-          object.m_ObjectClass.type = "object.item.videoItem.movie";
-          object.m_Title = tag.m_strTitle;
-          object.m_Date = NPT_String::FromInteger(tag.m_iYear) + "-01-01";
-          object.m_ReferenceID = NPT_String::Format("videodb://1/2/%i", tag.m_iDbId);
         }
     }
 
@@ -265,14 +273,28 @@ PopulateObjectFromTag(CVideoInfoTag&         tag,
         object.m_People.actors.Add(it->strName.c_str(), it->strRole.c_str());
     }
 
-    object.m_People.director = StringUtils::Join(tag.m_director, g_advancedSettings.m_videoItemSeparator);
+    for (unsigned int index = 0; index < tag.m_director.size(); index++)
+      object.m_People.directors.Add(tag.m_director[index].c_str());
+
     for (unsigned int index = 0; index < tag.m_writingCredits.size(); index++)
       object.m_People.authors.Add(tag.m_writingCredits[index].c_str());
 
     object.m_Description.description = tag.m_strTagLine;
     object.m_Description.long_description = tag.m_strPlot;
-    if (resource) resource->m_Duration = tag.m_streamDetails.GetVideoDuration();
-    if (resource) resource->m_Resolution = NPT_String::FromInteger(tag.m_streamDetails.GetVideoWidth()) + "x" + NPT_String::FromInteger(tag.m_streamDetails.GetVideoHeight());
+    object.m_Description.rating = tag.m_strMPAARating;
+    object.m_MiscInfo.last_position = (NPT_UInt32)tag.m_resumePoint.timeInSeconds;
+    object.m_MiscInfo.last_time = tag.m_lastPlayed.GetAsDBDate();
+    object.m_MiscInfo.play_count = tag.m_playCount;
+    if (resource) {
+        if (tag.HasStreamDetails()) {
+            const CStreamDetails details = tag.m_streamDetails;
+            resource->m_Duration = details.GetVideoDuration();
+            resource->m_Resolution = NPT_String::FromInteger(details.GetVideoWidth()) + "x" + NPT_String::FromInteger(details.GetVideoHeight());
+        }
+        else {
+            resource->m_Duration = 60*atoi(tag.m_strRuntime.c_str());
+        }
+    }
 
     return NPT_SUCCESS;
 }
@@ -281,14 +303,17 @@ PopulateObjectFromTag(CVideoInfoTag&         tag,
 |   BuildObject
 +---------------------------------------------------------------------*/
 PLT_MediaObject*
-BuildObject(const CFileItem&              item,
+BuildObject(CFileItem&                    item,
             NPT_String&                   file_path,
             bool                          with_count,
+            NPT_Reference<CThumbLoader>&  thumb_loader,
             const PLT_HttpRequestContext* context /* = NULL */,
             CUPnPServer*                  upnp_server /* = NULL */)
 {
     PLT_MediaItemResource resource;
     PLT_MediaObject*      object = NULL;
+    std::string thumb, fanart;
+    bool fetched_art(false);
 
     CLog::Log(LOGDEBUG, "Building didl for object '%s'", (const char*)item.GetPath());
 
@@ -340,17 +365,12 @@ BuildObject(const CFileItem&              item,
 
         // Set the resource file size
         resource.m_Size = item.m_dwSize;
-        if (resource.m_Size == 0) {
-            struct __stat64 info;
-            if(CFile::Stat((const char*)file_path, &info) == 0 && info.st_size >= 0)
-              resource.m_Size = info.st_size;
-        }
         if(resource.m_Size == 0)
           resource.m_Size = (NPT_LargeSize)-1;
 
         // set date
         if (object->m_Date.IsEmpty() && item.m_dateTime.IsValid()) {
-            object->m_Date = item.m_dateTime.GetAsLocalizedDate();
+            object->m_Date = item.m_dateTime.GetAsDBDate();
         }
 
         if (upnp_server) {
@@ -369,6 +389,12 @@ BuildObject(const CFileItem&              item,
             } else {
                 object->m_Resources.Insert(object->m_Resources.GetFirstItem(), resource);
             }
+            // copy across the known metadata
+            for(unsigned i=0; i<object->m_Resources.GetItemCount(); i++) {
+                object->m_Resources[i].m_Size = resource.m_Size;
+                object->m_Resources[i].m_Duration = resource.m_Duration;
+                object->m_Resources[i].m_Resolution = resource.m_Resolution;
+            }
         }
 
         // Some upnp clients expect all audio items to have parent root id 4
@@ -443,19 +469,17 @@ BuildObject(const CFileItem&              item,
                   container->m_Creator = StringUtils::Join(tag.m_artist, g_advancedSettings.m_videoItemSeparator);
                   container->m_Title   = tag.m_strTitle;
                   break;
+                case VIDEODATABASEDIRECTORY::NODE_TYPE_SEASONS:
                 case VIDEODATABASEDIRECTORY::NODE_TYPE_TITLE_TVSHOWS:
                   container->m_ObjectClass.type += ".album.videoAlbum";
-                  container->m_Recorded.program_title  = "S" + ("0" + NPT_String::FromInteger(tag.m_iSeason)).Right(2);
-                  container->m_Recorded.program_title += "E" + ("0" + NPT_String::FromInteger(tag.m_iEpisode)).Right(2);
-                  container->m_Recorded.program_title += " : " + tag.m_strTitle;
                   container->m_Recorded.series_title = tag.m_strShowTitle;
-                  container->m_Recorded.episode_number = tag.m_iSeason * 100 + tag.m_iEpisode;
-                  container->m_Title = container->m_Recorded.series_title + " - " + container->m_Recorded.program_title;
+                  container->m_Recorded.episode_number = tag.m_iEpisode;
+                  container->m_MiscInfo.play_count = tag.m_playCount;
                   container->m_Title = tag.m_strTitle;
                   if(!tag.m_firstAired.IsValid() && tag.m_iYear)
                     container->m_Date = NPT_String::FromInteger(tag.m_iYear) + "-01-01";
                   else
-                    container->m_Date = tag.m_firstAired.GetAsLocalizedDate();
+                    container->m_Date = tag.m_premiered.GetAsDBDate();
 
                   for (unsigned int index = 0; index < tag.m_genre.size(); index++)
                     container->m_Affiliation.genres.Add(tag.m_genre.at(index).c_str());
@@ -464,7 +488,8 @@ BuildObject(const CFileItem&              item,
                       container->m_People.actors.Add(it->strName.c_str(), it->strRole.c_str());
                   }
 
-                  container->m_People.director = StringUtils::Join(tag.m_director, g_advancedSettings.m_videoItemSeparator);;
+                  for (unsigned int index = 0; index < tag.m_director.size(); index++)
+                    container->m_People.directors.Add(tag.m_director[index].c_str());
                   for (unsigned int index = 0; index < tag.m_writingCredits.size(); index++)
                     container->m_People.authors.Add(tag.m_writingCredits[index].c_str());
 
@@ -510,27 +535,30 @@ BuildObject(const CFileItem&              item,
             object->m_Title = title;
         }
     }
-    // set a thumbnail if we have one
-    if (item.HasThumbnail() && upnp_server) {
-       PLT_AlbumArtInfo art;
+
+    // determine the correct artwork for this item
+    if (!thumb_loader.IsNull())
+        fetched_art = thumb_loader->FillLibraryArt(item);
+
+    // finally apply the found artwork
+    if (fetched_art && upnp_server) {
+        PLT_AlbumArtInfo art;
         art.uri = upnp_server->BuildSafeResourceUri(
             rooturi,
             (*ips.GetFirstItem()).ToString(),
-            item.GetThumbnailImage());
+            CTextureCache::GetWrappedImageURL(item.GetArt("thumb")).c_str());
+
         // Set DLNA profileID by extension, defaulting to JPEG.
-        NPT_String ext = URIUtils::GetExtension(item.GetThumbnailImage()).c_str();
+        NPT_String ext = URIUtils::GetExtension(thumb).c_str();
         if (strcmp(ext, ".png") == 0) {
             art.dlna_profile = "PNG_TN";
         } else {
             art.dlna_profile = "JPEG_TN";
         }
-       object->m_ExtraInfo.album_arts.Add(art);
-    }
-
-    if (upnp_server) {
-        if (item.HasProperty("fanart_image")) {
-            upnp_server->AddSafeResourceUri(object, rooturi, ips, item.GetProperty("fanart_image").asString().c_str(), "xbmc.org:*:fanart:*" );
-        }
+        object->m_ExtraInfo.album_arts.Add(art);
+        std::string fanart = item.GetArt("fanart");
+        if (!fanart.empty())
+            upnp_server->AddSafeResourceUri(object, rooturi, ips, CTextureCache::GetWrappedImageURL(fanart), "xbmc.org:*:fanart:*");
     }
 
     return object;
@@ -574,6 +602,10 @@ PopulateTagFromObject(CMusicInfoTag&          tag,
         tag.SetGenre((const char*) *it);
 
     tag.SetAlbum((const char*)object.m_Affiliation.album);
+    CDateTime last;
+    last.SetFromDateString((const char*)object.m_MiscInfo.last_time);
+    tag.SetLastPlayed(last);
+    tag.SetPlayCount(object.m_MiscInfo.play_count);
     if(resource)
         tag.SetDuration(resource->m_Duration);
     tag.SetLoaded();
@@ -590,6 +622,7 @@ PopulateTagFromObject(CVideoInfoTag&         tag,
 
     if(!object.m_Recorded.program_title.IsEmpty())
     {
+        tag.m_type = "episode";
         int episode;
         int season;
         int title = object.m_Recorded.program_title.Find(" : ");
@@ -604,21 +637,46 @@ PopulateTagFromObject(CVideoInfoTag&         tag,
         }
         tag.m_firstAired = date;
     }
+    else if (!object.m_Recorded.series_title.IsEmpty()) {
+        tag.m_type= "season";
+        tag.m_strTitle = object.m_Title; // because could be TV show Title, or Season 1 etc
+        tag.m_iSeason  = object.m_Recorded.episode_number / 100;
+        tag.m_iEpisode = object.m_Recorded.episode_number % 100;
+        tag.m_premiered = date;
+    }
+    else if(object.m_ObjectClass.type == "object.item.videoItem.musicVideoClip") {
+        tag.m_type = "musicvideo";
+    }
     else
     {
+        tag.m_type         = "movie";
         tag.m_strTitle     = object.m_Title;
         tag.m_premiered    = date;
     }
     tag.m_iYear       = date.GetYear();
     for (unsigned int index = 0; index < object.m_Affiliation.genres.GetItemCount(); index++)
       tag.m_genre.push_back(object.m_Affiliation.genres.GetItem(index)->GetChars());
-    tag.m_director = StringUtils::Split((CStdString)object.m_People.director, g_advancedSettings.m_videoItemSeparator);
+    for (unsigned int index = 0; index < object.m_People.directors.GetItemCount(); index++)
+      tag.m_director.push_back(object.m_People.directors.GetItem(index)->name.GetChars());
+    for (unsigned int index = 0; index < object.m_People.authors.GetItemCount(); index++)
+      tag.m_writingCredits.push_back(object.m_People.authors.GetItem(index)->name.GetChars());
     tag.m_strTagLine  = object.m_Description.description;
     tag.m_strPlot     = object.m_Description.long_description;
+    tag.m_strMPAARating = object.m_Description.rating;
     tag.m_strShowTitle = object.m_Recorded.series_title;
+    tag.m_lastPlayed.SetFromDateString((const char*)object.m_MiscInfo.last_time);
+    tag.m_playCount = object.m_MiscInfo.play_count;
 
     if(resource)
-      tag.m_strRuntime.Format("%d",resource->m_Duration);
+    {
+      if (resource->m_Duration)
+        tag.m_strRuntime.Format("%d",resource->m_Duration/60);
+      if (object.m_MiscInfo.last_position > 0 )
+      {
+        tag.m_resumePoint.totalTimeInSeconds = resource->m_Duration;
+        tag.m_resumePoint.timeInSeconds = object.m_MiscInfo.last_position;
+      }
+    }
     return NPT_SUCCESS;
 }
 
index ed388ba..e861da9 100644 (file)
 #include "system.h"
 #include "utils/StdString.h"
 #include "NptTypes.h"
+#include "NptReferences.h"
 
 class CUPnPServer;
 class CFileItem;
+class CThumbLoader;
 class PLT_HttpRequestContext;
 class PLT_MediaItemResource;
 class PLT_MediaObject;
@@ -78,9 +80,10 @@ namespace UPNP
                                           PLT_MediaItemResource* resource,
                                           EClientQuirks          quirks);
 
-  PLT_MediaObject* BuildObject(const CFileItem&              item,
+  PLT_MediaObject* BuildObject(CFileItem&              item,
                                       NPT_String&                   file_path,
                                       bool                          with_count,
+                                      NPT_Reference<CThumbLoader>&  thumb_loader,
                                       const PLT_HttpRequestContext* context = NULL,
                                       CUPnPServer*                  upnp_server = NULL);
 
index f409357..978fdd3 100644 (file)
@@ -5,17 +5,43 @@
 #include "Application.h"
 #include "ApplicationMessenger.h"
 #include "FileItem.h"
+#include "filesystem/SpecialProtocol.h"
 #include "GUIInfoManager.h"
 #include "guilib/GUIWindowManager.h"
 #include "pictures/GUIWindowSlideShow.h"
 #include "pictures/PictureInfoTag.h"
+#include "interfaces/AnnouncementManager.h"
 #include "settings/Settings.h"
+#include "TextureCache.h"
+#include "ThumbLoader.h"
+#include "URL.h"
 #include "utils/URIUtils.h"
+#include "utils/Variant.h"
+
+using namespace ANNOUNCEMENT;
 
 namespace UPNP
 {
 
 /*----------------------------------------------------------------------
+|   CUPnPRenderer::CUPnPRenderer
++---------------------------------------------------------------------*/
+CUPnPRenderer::CUPnPRenderer(const char* friendly_name, bool show_ip /*= false*/,
+                             const char* uuid /*= NULL*/, unsigned int port /*= 0*/)
+    : PLT_MediaRenderer(friendly_name, show_ip, uuid, port)
+{
+    CAnnouncementManager::AddAnnouncer(this);
+}
+
+/*----------------------------------------------------------------------
+|   CUPnPRenderer::~CUPnPRenderer
++---------------------------------------------------------------------*/
+CUPnPRenderer::~CUPnPRenderer()
+{
+    CAnnouncementManager::RemoveAnnouncer(this);
+}
+
+/*----------------------------------------------------------------------
 |   CUPnPRenderer::SetupServices
 +---------------------------------------------------------------------*/
 NPT_Result
@@ -119,7 +145,7 @@ CUPnPRenderer::SetupServices()
 |   CUPnPRenderer::ProcessHttpRequest
 +---------------------------------------------------------------------*/
 NPT_Result
-CUPnPRenderer::ProcessHttpRequest(NPT_HttpRequest&              request,
+CUPnPRenderer::ProcessHttpGetRequest(NPT_HttpRequest&              request,
                                   const NPT_HttpRequestContext& context,
                                   NPT_HttpResponse&             response)
 {
@@ -129,7 +155,7 @@ CUPnPRenderer::ProcessHttpRequest(NPT_HttpRequest&              request,
     NPT_String  protocol   = request.GetProtocol();
     NPT_HttpUrl url        = request.GetUrl();
 
-    if (url.GetPath() == "/thumb.jpg") {
+    if (url.GetPath() == "/thumb") {
         NPT_HttpUrlQuery query(url.GetQuery());
         NPT_String filepath = query.GetField("path");
         if (!filepath.IsEmpty()) {
@@ -143,20 +169,14 @@ CUPnPRenderer::ProcessHttpRequest(NPT_HttpRequest&              request,
                 return NPT_SUCCESS;
             }
 
-            // ensure that the request's path is a valid thumb path
-            if (URIUtils::IsRemote(filepath.GetChars()) ||
-                !filepath.StartsWith(g_settings.GetUserDataFolder())) {
-                response.SetStatus(404, "Not Found");
-                return NPT_SUCCESS;
-            }
-
             // prevent hackers from accessing files outside of our root
             if ((filepath.Find("/..") >= 0) || (filepath.Find("\\..") >=0)) {
                 return NPT_FAILURE;
             }
 
             // open the file
-            NPT_File file(filepath);
+            CStdString path = CURL::Decode((const char*) filepath);
+            NPT_File file(path.c_str());
             NPT_Result result = file.Open(NPT_FILE_OPEN_MODE_READ);
             if (NPT_FAILED(result)) {
                 response.SetStatus(404, "Not Found");
@@ -175,6 +195,58 @@ CUPnPRenderer::ProcessHttpRequest(NPT_HttpRequest&              request,
 }
 
 /*----------------------------------------------------------------------
+|   CUPnPRenderer::Announce
++---------------------------------------------------------------------*/
+void
+CUPnPRenderer::Announce(AnnouncementFlag flag, const char *sender, const char *message, const CVariant &data)
+{
+    if (strcmp(sender, "xbmc") != 0)
+      return;
+
+    NPT_AutoLock lock(m_state);
+    PLT_Service *avt, *rct;
+
+    if (flag == Player) {
+        if (NPT_FAILED(FindServiceByType("urn:schemas-upnp-org:service:AVTransport:1", avt)))
+            return;
+        if (strcmp(message, "OnPlay") == 0) {
+            avt->SetStateVariable("AVTransportURI", g_application.CurrentFile().c_str());
+            avt->SetStateVariable("CurrentTrackURI", g_application.CurrentFile().c_str());
+
+            NPT_String meta;
+            if (NPT_SUCCEEDED(GetMetadata(meta))) {
+                avt->SetStateVariable("CurrentTrackMetadata", meta);
+                avt->SetStateVariable("AVTransportURIMetaData", meta);
+            }
+
+            avt->SetStateVariable("TransportPlaySpeed", NPT_String::FromInteger(data["speed"].asInteger()));
+            avt->SetStateVariable("TransportState", "PLAYING");
+        }
+        else if (strcmp(message, "OnPause") == 0) {
+            avt->SetStateVariable("TransportPlaySpeed", NPT_String::FromInteger(data["speed"].asInteger()));
+            avt->SetStateVariable("TransportState", "PAUSED_PLAYBACK");
+        }
+        else if (strcmp(message, "OnSpeedChanged") == 0) {
+            avt->SetStateVariable("TransportPlaySpeed", NPT_String::FromInteger(data["speed"].asInteger()));
+        }
+    }
+    else if (flag == Application && strcmp(message, "OnVolumeChanged") == 0) {
+        if (NPT_FAILED(FindServiceByType("urn:schemas-upnp-org:service:RenderingControl:1", rct)))
+            return;
+
+        CStdString buffer;
+
+        buffer.Format("%ld", data["volume"].asInteger());
+        rct->SetStateVariable("Volume", buffer.c_str());
+
+        buffer.Format("%ld", 256 * (data["volume"].asInteger() * 60 - 60) / 100);
+        rct->SetStateVariable("VolumeDb", buffer.c_str());
+
+        rct->SetStateVariable("Mute", data["muted"].asBoolean() ? "1" : "0");
+    }
+}
+
+/*----------------------------------------------------------------------
 |   CUPnPRenderer::UpdateState
 +---------------------------------------------------------------------*/
 void
@@ -182,11 +254,10 @@ CUPnPRenderer::UpdateState()
 {
     NPT_AutoLock lock(m_state);
 
-    PLT_Service *avt, *rct;
+    PLT_Service *avt;
+
     if (NPT_FAILED(FindServiceByType("urn:schemas-upnp-org:service:AVTransport:1", avt)))
         return;
-    if (NPT_FAILED(FindServiceByType("urn:schemas-upnp-org:service:RenderingControl:1", rct)))
-        return;
 
     /* don't update state while transitioning */
     NPT_String state;
@@ -194,34 +265,13 @@ CUPnPRenderer::UpdateState()
     if(state == "TRANSITIONING")
         return;
 
-    CStdString buffer;
-    int volume;
-    if (g_settings.m_bMute) {
-        rct->SetStateVariable("Mute", "1");
-    } else {
-        rct->SetStateVariable("Mute", "0");
-    }
-    volume = g_application.GetVolume();
-
-    buffer.Format("%d", volume);
-    rct->SetStateVariable("Volume", buffer.c_str());
-
-    buffer.Format("%d", 256 * (volume * 60 - 60) / 100);
-    rct->SetStateVariable("VolumeDb", buffer.c_str());
+    avt->SetStateVariable("TransportStatus", "OK");
 
     if (g_application.IsPlaying() || g_application.IsPaused()) {
-        if (g_application.IsPaused()) {
-            avt->SetStateVariable("TransportState", "PAUSED_PLAYBACK");
-        } else {
-            avt->SetStateVariable("TransportState", "PLAYING");
-        }
-
-        avt->SetStateVariable("TransportStatus", "OK");
-        avt->SetStateVariable("TransportPlaySpeed", (const char*)NPT_String::FromInteger(g_application.GetPlaySpeed()));
         avt->SetStateVariable("NumberOfTracks", "1");
         avt->SetStateVariable("CurrentTrack", "1");
 
-        buffer = g_infoManager.GetCurrentPlayTime(TIME_FORMAT_HH_MM_SS);
+        CStdString buffer = g_infoManager.GetCurrentPlayTime(TIME_FORMAT_HH_MM_SS);
         avt->SetStateVariable("RelativeTimePosition", buffer.c_str());
         avt->SetStateVariable("AbsoluteTimePosition", buffer.c_str());
 
@@ -234,17 +284,6 @@ CUPnPRenderer::UpdateState()
           avt->SetStateVariable("CurrentMediaDuration", "00:00:00");
         }
 
-        avt->SetStateVariable("AVTransportURI", g_application.CurrentFile().c_str());
-        avt->SetStateVariable("CurrentTrackURI", g_application.CurrentFile().c_str());
-
-        NPT_String metadata;
-        avt->GetStateVariableValue("AVTransportURIMetaData", metadata);
-        // try to recreate the didl dynamically if not set
-        if (metadata.IsEmpty()) {
-            GetMetadata(metadata);
-        }
-        avt->SetStateVariable("CurrentTrackMetadata", metadata);
-        avt->SetStateVariable("AVTransportURIMetaData", metadata);
     } else if (g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW) {
         avt->SetStateVariable("TransportState", "PLAYING");
 
@@ -279,18 +318,45 @@ CUPnPRenderer::UpdateState()
 }
 
 /*----------------------------------------------------------------------
+|   CUPnPRenderer::SetupIcons
++---------------------------------------------------------------------*/
+NPT_Result
+CUPnPRenderer::SetupIcons()
+{
+    NPT_String file_root = CSpecialProtocol::TranslatePath("special://xbmc/media/").c_str();
+    printf("%s\n", (const char*) file_root);
+    AddIcon(
+        PLT_DeviceIcon("image/png", 256, 256, 32, "/icon.png"),
+        file_root);
+    AddIcon(
+        PLT_DeviceIcon("image/png", 32, 32, 32, "/icon32x32.png"),
+        file_root);
+    return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
 |   CUPnPRenderer::GetMetadata
 +---------------------------------------------------------------------*/
 NPT_Result
 CUPnPRenderer::GetMetadata(NPT_String& meta)
 {
     NPT_Result res = NPT_FAILURE;
-    const CFileItem &item = g_application.CurrentFileItem();
-    NPT_String file_path;
-    PLT_MediaObject* object = BuildObject(item, file_path, false);
+    CFileItem item(g_application.CurrentFileItem());
+    NPT_String file_path, tmp;
+
+    // we pass an empty CThumbLoader reference, as it can't be used
+    // without CUPnPServer enabled
+    NPT_Reference<CThumbLoader> thumb_loader;
+    PLT_MediaObject* object = BuildObject(item, file_path, false, thumb_loader);
     if (object) {
-        // fetch the path to the thumbnail
-        CStdString thumb = g_infoManager.GetImage(MUSICPLAYER_COVER, -1); //TODO: Only audio for now
+        // fetch the item's artwork
+        CStdString thumb;
+        if (object->m_ObjectClass.type == "object.item.audioItem.musicTrack")
+            thumb = g_infoManager.GetImage(MUSICPLAYER_COVER, -1);
+        else
+            thumb = g_infoManager.GetImage(VIDEOPLAYER_COVER, -1);
+
+        thumb = CTextureCache::GetWrappedImageURL(thumb);
 
         NPT_String ip;
         if (g_application.getNetwork().GetFirstConnectedInterface()) {
@@ -303,12 +369,19 @@ CUPnPRenderer::GetMetadata(NPT_String& meta)
        art.uri = NPT_HttpUrl(
             ip,
             m_URLDescription.GetPort(),
-            "/thumb.jpg",
+            "/thumb",
             query.ToString()).ToString();
-        art.dlna_profile = "JPEG_TN";
+        // Set DLNA profileID by extension, defaulting to JPEG.
+        NPT_String ext = URIUtils::GetExtension(item.GetArt("thumb")).c_str();
+        if (strcmp(ext, ".png") == 0) {
+            art.dlna_profile = "PNG_TN";
+        } else {
+            art.dlna_profile = "JPEG_TN";
+        }
        object->m_ExtraInfo.album_arts.Add(art);
 
-        res = PLT_Didl::ToDidl(*object, "*", meta);
+        res = PLT_Didl::ToDidl(*object, "*", tmp);
+        meta = didl_header + tmp + didl_footer;
         delete object;
     }
     return res;
@@ -476,7 +549,7 @@ CUPnPRenderer::PlayMedia(const char* uri, const char* meta, PLT_Action* action)
         item.SetLabelPreformated(true);
         if (object->m_ExtraInfo.album_arts.GetItem(0)) {
             //FIXME only considers 1st image
-            item.SetThumbnailImage((const char*)object->m_ExtraInfo.album_arts.GetItem(0)->uri);
+            item.SetArt("thumb", (const char*)object->m_ExtraInfo.album_arts.GetItem(0)->uri);
         }
         if (object->m_ObjectClass.type.StartsWith("object.item.audioItem")) {
             if(NPT_SUCCEEDED(PopulateTagFromObject(*item.GetMusicInfoTag(), *object, res)))
index 0a00ccb..1c158ce 100644 (file)
@@ -19,6 +19,7 @@
  *
  */
 #include "PltMediaRenderer.h"
+#include "interfaces/IAnnouncer.h"
 
 namespace UPNP
 {
@@ -30,19 +31,23 @@ public:
 };
 
 class CUPnPRenderer : public PLT_MediaRenderer
+                    , public ANNOUNCEMENT::IAnnouncer
 {
 public:
     CUPnPRenderer(const char*  friendly_name,
                   bool         show_ip = false,
                   const char*  uuid = NULL,
-                  unsigned int port = 0) : PLT_MediaRenderer(friendly_name, show_ip, uuid, port) {}
+                  unsigned int port = 0);
 
+    virtual ~CUPnPRenderer();
+
+    virtual void Announce(ANNOUNCEMENT::AnnouncementFlag flag, const char *sender, const char *message, const CVariant &data);
     void UpdateState();
 
     // Http server handler
-    virtual NPT_Result ProcessHttpRequest(NPT_HttpRequest&              request,
-                                          const NPT_HttpRequestContext& context,
-                                          NPT_HttpResponse&             response);
+    virtual NPT_Result ProcessHttpGetRequest(NPT_HttpRequest&              request,
+                                             const NPT_HttpRequestContext& context,
+                                             NPT_HttpResponse&             response);
 
     // AVTransport methods
     virtual NPT_Result OnNext(PLT_ActionReference& action);
@@ -59,6 +64,7 @@ public:
 
 private:
     NPT_Result SetupServices();
+    NPT_Result SetupIcons();
     NPT_Result GetMetadata(NPT_String& meta);
     NPT_Result PlayMedia(const char* uri,
                          const char* metadata = NULL,
index 2008582..f1cd7a9 100644 (file)
@@ -1,13 +1,17 @@
 #include "UPnPServer.h"
 #include "UPnPInternal.h"
+#include "Application.h"
 #include "GUIViewState.h"
 #include "Platinum.h"
 #include "ThumbLoader.h"
+#include "interfaces/AnnouncementManager.h"
 #include "filesystem/Directory.h"
 #include "filesystem/MusicDatabaseDirectory.h"
+#include "filesystem/SpecialProtocol.h"
 #include "filesystem/VideoDatabaseDirectory.h"
 #include "guilib/Key.h"
 #include "music/tags/MusicInfoTag.h"
+#include "settings/GUISettings.h"
 #include "utils/log.h"
 #include "utils/md5.h"
 #include "utils/StringUtils.h"
@@ -16,6 +20,7 @@
 #include "video/VideoDatabase.h"
 
 using namespace std;
+using namespace ANNOUNCEMENT;
 using namespace XFILE;
 
 namespace UPNP
@@ -23,6 +28,28 @@ namespace UPNP
 
 NPT_UInt32 CUPnPServer::m_MaxReturnedItems = 0;
 
+const char* audio_containers[] = { "musicdb://1/", "musicdb://2/", "musicdb://3/",
+                                   "musicdb://4/", "musicdb://6/", "musicdb://9/",
+                                   "musicdb://10/" };
+
+const char* video_containers[] = { "videodb://1/2/", "videodb://2/2/", "videodb://4/",
+                                   "videodb://5/"  };
+
+/*----------------------------------------------------------------------
+|   CUPnPServer::CUPnPServer
++---------------------------------------------------------------------*/
+CUPnPServer::CUPnPServer(const char* friendly_name, const char* uuid /*= NULL*/, int port /*= 0*/) :
+    PLT_MediaConnect(friendly_name, false, uuid, port),
+    PLT_FileMediaConnectDelegate("/", "/"),
+    m_scanning(g_application.IsMusicScanning() || g_application.IsVideoScanning())
+{
+}
+
+CUPnPServer::~CUPnPServer()
+{
+    ANNOUNCEMENT::CAnnouncementManager::RemoveAnnouncer(this);
+}
+
 /*----------------------------------------------------------------------
 |   CUPnPServer::ProcessGetSCPD
 +---------------------------------------------------------------------*/
@@ -42,12 +69,117 @@ CUPnPServer::ProcessGetSCPD(PLT_Service*                  service,
 NPT_Result
 CUPnPServer::SetupServices()
 {
-  PLT_MediaConnect::SetupServices();
-  PLT_Service* service = NULL;
-  NPT_Result result = FindServiceById("urn:upnp-org:serviceId:ContentDirectory", service);
-  if (service)
-    service->SetStateVariable("SortCapabilities", "res@duration,res@size,res@bitrate,dc:date,dc:title,dc:size,upnp:album,upnp:artist,upnp:albumArtist,upnp:episodeNumber,upnp:genre,upnp:originalTrackNumber,upnp:rating");
-  return result;
+    PLT_MediaConnect::SetupServices();
+    PLT_Service* service = NULL;
+    NPT_Result result = FindServiceById("urn:upnp-org:serviceId:ContentDirectory", service);
+    if (service)
+      service->SetStateVariable("SortCapabilities", "res@duration,res@size,res@bitrate,dc:date,dc:title,dc:size,upnp:album,upnp:artist,upnp:albumArtist,upnp:episodeNumber,upnp:genre,upnp:originalTrackNumber,upnp:rating");
+
+    m_scanning = true;
+    OnScanCompleted(AudioLibrary);
+    m_scanning = true;
+    OnScanCompleted(VideoLibrary);
+
+    // now safe to start passing on new notifications
+    ANNOUNCEMENT::CAnnouncementManager::AddAnnouncer(this);
+
+    return result;
+}
+
+/*----------------------------------------------------------------------
+|   CUPnPServer::OnScanCompleted
++---------------------------------------------------------------------*/
+void
+CUPnPServer::OnScanCompleted(int type)
+{
+    if (type == AudioLibrary) {
+        for (size_t i = 0; i < sizeof(audio_containers)/sizeof(audio_containers[0]); i++)
+            UpdateContainer(audio_containers[i]);
+    }
+    else if (type == VideoLibrary) {
+        for (size_t i = 0; i < sizeof(video_containers)/sizeof(video_containers[0]); i++)
+            UpdateContainer(video_containers[i]);
+    }
+    else
+        return;
+    m_scanning = false;
+    PropagateUpdates();
+}
+
+/*----------------------------------------------------------------------
+|   CUPnPServer::UpdateContainer
++---------------------------------------------------------------------*/
+void
+CUPnPServer::UpdateContainer(const string& id)
+{
+    map<string,pair<bool, unsigned long> >::iterator itr = m_UpdateIDs.find(id);
+    unsigned long count = 0;
+    if (itr != m_UpdateIDs.end())
+        count = ++itr->second.second;
+    m_UpdateIDs[id] = make_pair(true, count);
+    PropagateUpdates();
+}
+
+/*----------------------------------------------------------------------
+|   CUPnPServer::PropagateUpdates
++---------------------------------------------------------------------*/
+void
+CUPnPServer::PropagateUpdates()
+{
+    PLT_Service* service = NULL;
+    NPT_String current_ids;
+    string buffer;
+    map<string,pair<bool, unsigned long> >::iterator itr;
+
+    if (m_scanning || !g_guiSettings.GetBool("services.upnpannounce"))
+        return;
+
+    NPT_CHECK_LABEL(FindServiceById("urn:upnp-org:serviceId:ContentDirectory", service), failed);
+
+    // we pause, and we must retain any changes which have not been
+    // broadcast yet
+    NPT_CHECK_LABEL(service->PauseEventing(), failed);
+    NPT_CHECK_LABEL(service->GetStateVariableValue("ContainerUpdateIDs", current_ids), failed);
+    buffer = (const char*)current_ids;
+    if (!buffer.empty())
+        buffer.append(",");
+
+    // only broadcast ids with modified bit set
+    for (itr = m_UpdateIDs.begin(); itr != m_UpdateIDs.end(); ++itr) {
+        if (itr->second.first) {
+            buffer.append(StringUtils::Format("%s,%ld,", itr->first.c_str(), itr->second.second).c_str());
+            itr->second.first = false;
+        }
+    }
+
+    // set the value, Platinum will clear ContainerUpdateIDs after sending
+    NPT_CHECK_LABEL(service->SetStateVariable("ContainerUpdateIDs", buffer.substr(0,buffer.size()-1).c_str(), true), failed);
+    NPT_CHECK_LABEL(service->IncStateVariable("SystemUpdateID"), failed);
+
+    service->PauseEventing(false);
+    return;
+
+failed:
+    // should attempt to start eventing on a failure
+    if (service) service->PauseEventing(false);
+    CLog::Log(LOGERROR, "UPNP: Unable to propagate updates");
+}
+
+/*----------------------------------------------------------------------
+|   CUPnPServer::SetupIcons
++---------------------------------------------------------------------*/
+NPT_Result
+CUPnPServer::SetupIcons()
+{
+    NPT_String file_root = CSpecialProtocol::TranslatePath("special://xbmc/media/").c_str();
+    printf("%s\n", (const char*) file_root);
+    AddIcon(
+        PLT_DeviceIcon("image/png", 256, 256, 32, "/icon.png"),
+        file_root);
+    AddIcon(
+        PLT_DeviceIcon("image/png", 32, 32, 32, "/icon32x32.png"),
+        file_root);
+    return NPT_SUCCESS;
 }
 
 /*----------------------------------------------------------------------
@@ -75,6 +207,7 @@ PLT_MediaObject*
 CUPnPServer::Build(CFileItemPtr                  item,
                    bool                          with_count,
                    const PLT_HttpRequestContext& context,
+                   NPT_Reference<CThumbLoader>&  thumb_loader,
                    const char*                   parent_id /* = NULL */)
 {
     PLT_MediaObject* object = NULL;
@@ -104,7 +237,10 @@ CUPnPServer::Build(CFileItemPtr                  item,
             goto failure;
         }
 
-    } else {
+    } else if (path.StartsWith("addons://"))
+        // don't serve addon listings for now
+        goto failure;
+      else {
         // db path handling
         NPT_String file_path, share_name;
         file_path = item->GetPath();
@@ -118,9 +254,6 @@ CUPnPServer::Build(CFileItemPtr                  item,
                 if (!item->HasMusicInfoTag())
                     item->LoadMusicTag();
 
-                if (!item->HasThumbnail() )
-                    item->SetThumbnailImage(CThumbLoader::GetCachedImage(*item, "thumb"));
-
                 if (item->GetLabel().IsEmpty()) {
                     /* if no label try to grab it from node type */
                     CStdString label;
@@ -130,8 +263,8 @@ CUPnPServer::Build(CFileItemPtr                  item,
                     }
                 }
             }
-        } else if (file_path.StartsWith("videodb://")) {
-            if (path == "videodb://" ) {
+        } else if (file_path.StartsWith("library://") || file_path.StartsWith("videodb://")) {
+            if (path == "library://video" ) {
                 item->SetLabel("Video Library");
                 item->SetLabelPreformated(true);
             } else {
@@ -150,6 +283,13 @@ CUPnPServer::Build(CFileItemPtr                  item,
                         db.GetTvShowInfo((const char*)path, *item->GetVideoInfoTag(), params.GetTvShowId());
                 }
 
+                if (item->GetVideoInfoTag()->m_type == "tvshow" || item->GetVideoInfoTag()->m_type == "season") {
+                    // for tvshows and seasons, iEpisode and playCount are
+                    // invalid
+                    item->GetVideoInfoTag()->m_iEpisode = (int)item->GetProperty("totalepisodes").asInteger();
+                    item->GetVideoInfoTag()->m_playCount = (int)item->GetProperty("watchedepisodes").asInteger();
+                }
+
                 // try to grab title from tag
                 if (item->HasVideoInfoTag() && !item->GetVideoInfoTag()->m_strTitle.IsEmpty()) {
                     item->SetLabel(item->GetVideoInfoTag()->m_strTitle);
@@ -164,14 +304,11 @@ CUPnPServer::Build(CFileItemPtr                  item,
                         item->SetLabelPreformated(true);
                     }
                 }
-
-                if (!item->HasThumbnail() )
-                    item->SetThumbnailImage(CThumbLoader::GetCachedImage(*item, "thumb"));
             }
         }
 
         // not a virtual path directory, new system
-        object = BuildObject(*item.get(), file_path, with_count, &context, this);
+        object = BuildObject(*item.get(), file_path, with_count, thumb_loader, &context, this);
 
         // set parent id if passed, otherwise it should have been determined
         if (object && parent_id) {
@@ -188,6 +325,7 @@ CUPnPServer::Build(CFileItemPtr                  item,
         if (object->m_ParentID == "virtualpath://upnproot/")
             object->m_ParentID = "0";
     }
+
     return object;
 
 failure:
@@ -196,6 +334,79 @@ failure:
 }
 
 /*----------------------------------------------------------------------
+|   CUPnPServer::Announce
++---------------------------------------------------------------------*/
+void
+CUPnPServer::Announce(AnnouncementFlag flag, const char *sender, const char *message, const CVariant &data)
+{
+    NPT_String path;
+    int item_id;
+    string item_type;
+
+    if (strcmp(sender, "xbmc"))
+        return;
+
+    if (strcmp(message, "OnUpdate") && strcmp(message, "OnRemove")
+        && strcmp(message, "OnScanStarted") && strcmp(message, "OnScanFinished"))
+        return;
+
+    if (data.isNull()) {
+        if (!strcmp(message, "OnScanStarted")) {
+            m_scanning = true;
+        }
+        else if (!strcmp(message, "OnScanFinished")) {
+            OnScanCompleted(flag);
+        }
+    }
+    else {
+        // handle both updates & removals
+        if (!data["item"].isNull()) {
+            item_id = (int)data["item"]["id"].asInteger();
+            item_type = data["item"]["type"].asString();
+        }
+        else {
+            item_id = (int)data["id"].asInteger();
+            item_type = data["type"].asString();
+        }
+
+        // we always update 'recently added' nodes along with the specific container,
+        // as we don't differentiate 'updates' from 'adds' in RPC interface
+        if (flag == VideoLibrary) {
+            if(item_type == "episode") {
+                CVideoDatabase db;
+                if (!db.Open()) return;
+                int show_id = db.GetTvShowForEpisode(item_id);
+                UpdateContainer(StringUtils::Format("videodb://2/2/%d/", show_id));
+                UpdateContainer("videodb://5/");
+            }
+            else if(item_type == "tvshow") {
+                UpdateContainer("videodb://2/2/");
+                UpdateContainer("videodb://5/");
+            }
+            else if(item_type == "movie") {
+                UpdateContainer("videodb://1/2/");
+                UpdateContainer("videodb://4/");
+            }
+            else if(item_type == "musicvideo") {
+                UpdateContainer("videodb://4/");
+            }
+        }
+        else if (flag == AudioLibrary && item_type == "song") {
+            // we also update the 'songs' container is maybe a performance drop too
+            // high? would need to check if slow clients even cache at all anyway
+            CMusicDatabase db;
+            CAlbum album;
+            if (!db.Open()) return;
+            if (db.GetAlbumFromSong(item_id, album)) {
+                UpdateContainer(StringUtils::Format("musicdb://3/%ld", album.idAlbum));
+                UpdateContainer("musicdb://4/");
+                UpdateContainer("musicdb://6/");
+            }
+        }
+    }
+}
+
+/*----------------------------------------------------------------------
 |   TranslateWMPObjectId
 +---------------------------------------------------------------------*/
 static NPT_String TranslateWMPObjectId(NPT_String id)
@@ -204,7 +415,7 @@ static NPT_String TranslateWMPObjectId(NPT_String id)
         id = "virtualpath://upnproot/";
     } else if (id == "15") {
         // Xbox 360 asking for videos
-        id = "videodb://";
+        id = "library://video";
     } else if (id == "16") {
         // Xbox 360 asking for photos
     } else if (id == "107") {
@@ -243,6 +454,7 @@ CUPnPServer::OnBrowseMetadata(PLT_ActionReference&          action,
     NPT_String                     id = TranslateWMPObjectId(object_id);
     vector<CStdString>             paths;
     CFileItemPtr                   item;
+    NPT_Reference<CThumbLoader>    thumb_loader;
 
     CLog::Log(LOGINFO, "Received UPnP Browse Metadata request for object '%s'", (const char*)object_id);
 
@@ -253,7 +465,7 @@ CUPnPServer::OnBrowseMetadata(PLT_ActionReference&          action,
             item.reset(new CFileItem((const char*)id, true));
             item->SetLabel("Root");
             item->SetLabelPreformated(true);
-            object = Build(item, true, context);
+            object = Build(item, true, context, thumb_loader);
         } else {
             return NPT_FAILURE;
         }
@@ -272,7 +484,16 @@ CUPnPServer::OnBrowseMetadata(PLT_ActionReference&          action,
 //        }
 //#endif
 
-        object = Build(item, true, context, parent.empty()?NULL:parent.c_str());
+        if (item->IsVideoDb()) {
+            thumb_loader = NPT_Reference<CThumbLoader>(new CVideoThumbLoader());
+        }
+        else if (item->IsMusicDb()) {
+            thumb_loader = NPT_Reference<CThumbLoader>(new CMusicThumbLoader());
+        }
+        if (!thumb_loader.IsNull()) {
+            thumb_loader->Initialize();
+        }
+        object = Build(item, true, context, thumb_loader, parent.empty()?NULL:parent.c_str());
     }
 
     if (object.IsNull()) {
@@ -332,7 +553,7 @@ CUPnPServer::OnBrowseDirectChildren(PLT_ActionReference&          action,
             items.Add(item);
 
             // video library
-            item.reset(new CFileItem("videodb://", true));
+            item.reset(new CFileItem("library://video", true));
             item->SetLabel("Video Library");
             item->SetLabelPreformated(true);
             items.Add(item);
@@ -390,17 +611,35 @@ CUPnPServer::BuildResponse(PLT_ActionReference&          action,
         starting_index,
         requested_count);
 
+    // we will reuse this ThumbLoader for all items
+    NPT_Reference<CThumbLoader> thumb_loader;
+
+    // this isn't ideal, just grabbing first item to identify the content type
+    // of this FileItemList, but there's no other option
+    if (!items.IsEmpty() && items.Get(0)->HasVideoInfoTag()) {
+        thumb_loader = NPT_Reference<CThumbLoader>(new CVideoThumbLoader());
+    }
+    else if (!items.IsEmpty() && items.Get(0)->HasMusicInfoTag()) {
+        thumb_loader = NPT_Reference<CThumbLoader>(new CMusicThumbLoader());
+    }
+    if (!thumb_loader.IsNull()) {
+        thumb_loader->Initialize();
+    }
+
     // won't return more than UPNP_MAX_RETURNED_ITEMS items at a time to keep things smooth
     // 0 requested means as many as possible
     NPT_UInt32 max_count  = (requested_count == 0)?m_MaxReturnedItems:min((unsigned long)requested_count, (unsigned long)m_MaxReturnedItems);
     NPT_UInt32 stop_index = min((unsigned long)(starting_index + max_count), (unsigned long)items.Size()); // don't return more than we can
 
     NPT_Cardinal count = 0;
+    NPT_Cardinal total = items.Size();
     NPT_String didl = didl_header;
     PLT_MediaObjectReference object;
     for (unsigned long i=starting_index; i<stop_index; ++i) {
-        object = Build(items[i], true, context, parent_id);
+        object = Build(items[i], true, context, thumb_loader, parent_id);
         if (object.IsNull()) {
+            // don't tell the client this item ever existed
+            --total;
             continue;
         }
 
@@ -419,11 +658,11 @@ CUPnPServer::BuildResponse(PLT_ActionReference&          action,
 
     CLog::Log(LOGDEBUG, "Returning UPnP response with %d items out of %d total matches",
         count,
-        items.Size());
+        total);
 
     NPT_CHECK(action->SetArgumentValue("Result", didl));
     NPT_CHECK(action->SetArgumentValue("NumberReturned", NPT_String::FromInteger(count)));
-    NPT_CHECK(action->SetArgumentValue("TotalMatches", NPT_String::FromInteger(items.Size())));
+    NPT_CHECK(action->SetArgumentValue("TotalMatches", NPT_String::FromInteger(total)));
     NPT_CHECK(action->SetArgumentValue("UpdateId", "0"));
     return NPT_SUCCESS;
 }
index 6f37c61..9d64cd7 100644 (file)
  *
  */
 #include "PltMediaConnect.h"
+#include "interfaces/IAnnouncer.h"
 #include "FileItem.h"
 
+class CThumbLoader;
 class PLT_MediaObject;
 class PLT_HttpRequestContext;
 
@@ -28,13 +30,13 @@ namespace UPNP
 {
 
 class CUPnPServer : public PLT_MediaConnect,
-                    public PLT_FileMediaConnectDelegate
+                    public PLT_FileMediaConnectDelegate,
+                    public ANNOUNCEMENT::IAnnouncer
 {
 public:
-    CUPnPServer(const char* friendly_name, const char* uuid = NULL, int port = 0) :
-        PLT_MediaConnect(friendly_name, false, uuid, port),
-        PLT_FileMediaConnectDelegate("/", "/") {
-    }
+    CUPnPServer(const char* friendly_name, const char* uuid = NULL, int port = 0);
+    ~CUPnPServer();
+    virtual void Announce(ANNOUNCEMENT::AnnouncementFlag flag, const char *sender, const char *message, const CVariant &data);
 
     // PLT_MediaServer methods
     virtual NPT_Result OnBrowseMetadata(PLT_ActionReference&          action,
@@ -73,6 +75,7 @@ public:
                                       NPT_HttpResponse&             response);
 
     virtual NPT_Result SetupServices();
+    virtual NPT_Result SetupIcons();
     NPT_String BuildSafeResourceUri(const NPT_HttpUrl &rooturi,
                                     const char*        host,
                                     const char*        file_path);
@@ -89,9 +92,14 @@ public:
 
 
 private:
+    void OnScanCompleted(int type);
+    void UpdateContainer(const std::string& id);
+    void PropagateUpdates();
+
     PLT_MediaObject* Build(CFileItemPtr                  item,
                            bool                          with_count,
                            const PLT_HttpRequestContext& context,
+                           NPT_Reference<CThumbLoader>&  thumbLoader,
                            const char*                   parent_id = NULL);
     NPT_Result       BuildResponse(PLT_ActionReference&          action,
                                    CFileItemList&                items,
@@ -115,6 +123,8 @@ private:
     NPT_Mutex                       m_FileMutex;
     NPT_Map<NPT_String, NPT_String> m_FileMap;
 
+    std::map<std::string, std::pair<bool, unsigned long> > m_UpdateIDs;
+    bool m_scanning;
 public:
     // class members
     static NPT_UInt32 m_MaxReturnedItems;
index f367ab8..0998e42 100644 (file)
@@ -44,13 +44,18 @@ using namespace ANNOUNCEMENT;
 using namespace CEC;
 using namespace std;
 
-#define CEC_LIB_SUPPORTED_VERSION 0x1700
+#define CEC_LIB_SUPPORTED_VERSION 0x2000
 
 /* time in seconds to ignore standby commands from devices after the screensaver has been activated */
 #define SCREENSAVER_TIMEOUT       10
 #define VOLUME_CHANGE_TIMEOUT     250
 #define VOLUME_REFRESH_TIMEOUT    100
 
+#define LOCALISED_ID_TV           36037
+#define LOCALISED_ID_AVR          36038
+#define LOCALISED_ID_TV_AVR       36039
+#define LOCALISED_ID_NONE         231
+
 class DllLibCECInterface
 {
 public:
@@ -76,27 +81,9 @@ CPeripheralCecAdapter::CPeripheralCecAdapter(const PeripheralType type, const Pe
   CPeripheralHID(type, busType, strLocation, strDeviceName, iVendorId, iProductId),
   CThread("CEC Adapter"),
   m_dll(NULL),
-  m_cecAdapter(NULL),
-  m_bStarted(false),
-  m_bHasButton(false),
-  m_bIsReady(false),
-  m_bHasConnectedAudioSystem(false),
-  m_strMenuLanguage("???"),
-  m_lastKeypress(0),
-  m_lastChange(VOLUME_CHANGE_NONE),
-  m_iExitCode(0),
-  m_bIsMuted(false), // TODO fetch the correct initial value when system audiostatus is implemented in libCEC
-  m_bGoingToStandby(false),
-  m_bIsRunning(false),
-  m_bDeviceRemoved(false),
-  m_bActiveSourcePending(false),
-  m_bStandbyPending(false)
+  m_cecAdapter(NULL)
 {
-  m_currentButton.iButton = 0;
-  m_currentButton.iDuration = 0;
-  m_screensaverLastActivated.SetValid(false);
-
-  m_configuration.Clear();
+  ResetMembers();
   m_features.push_back(FEATURE_CEC);
 }
 
@@ -119,6 +106,34 @@ CPeripheralCecAdapter::~CPeripheralCecAdapter(void)
   }
 }
 
+void CPeripheralCecAdapter::ResetMembers(void)
+{
+  if (m_cecAdapter && m_dll)
+    m_dll->CECDestroy(m_cecAdapter);
+  m_cecAdapter               = NULL;
+  delete m_dll;
+  m_dll                      = NULL;
+  m_bStarted                 = false;
+  m_bHasButton               = false;
+  m_bIsReady                 = false;
+  m_bHasConnectedAudioSystem = false;
+  m_strMenuLanguage          = "???";
+  m_lastKeypress             = 0;
+  m_lastChange               = VOLUME_CHANGE_NONE;
+  m_iExitCode                = 0;
+  m_bIsMuted                 = false; // TODO fetch the correct initial value when system audiostatus is implemented in libCEC
+  m_bGoingToStandby          = false;
+  m_bIsRunning               = false;
+  m_bDeviceRemoved           = false;
+  m_bActiveSourcePending     = false;
+  m_bStandbyPending          = false;
+
+  m_currentButton.iButton    = 0;
+  m_currentButton.iDuration  = 0;
+  m_screensaverLastActivated.SetValid(false);
+  m_configuration.Clear();
+}
+
 void CPeripheralCecAdapter::Announce(AnnouncementFlag flag, const char *sender, const char *message, const CVariant &data)
 {
   if (flag == System && !strcmp(sender, "xbmc") && !strcmp(message, "OnQuit") && m_bIsReady)
@@ -183,6 +198,12 @@ bool CPeripheralCecAdapter::InitialiseFeature(const PeripheralFeature feature)
 {
   if (feature == FEATURE_CEC && !m_bStarted && GetSettingBool("enabled"))
   {
+    // hide settings that have an override set
+    if (!GetSettingString("wake_devices_advanced").IsEmpty())
+      SetSettingVisible("wake_devices", false);
+    if (!GetSettingString("standby_devices_advanced").IsEmpty())
+      SetSettingVisible("standby_devices", false);
+
     SetConfigurationFromSettings();
     m_callbacks.Clear();
     m_callbacks.CBCecLogMessage           = &CecLogMessage;
@@ -211,11 +232,11 @@ bool CPeripheralCecAdapter::InitialiseFeature(const PeripheralFeature feature)
     if (m_configuration.serverVersion < CEC_LIB_SUPPORTED_VERSION)
     {
       /* unsupported libcec version */
-      CLog::Log(LOGERROR, g_localizeStrings.Get(36013).c_str(), m_cecAdapter ? m_configuration.serverVersion : -1, CEC_LIB_SUPPORTED_VERSION);
+      CLog::Log(LOGERROR, g_localizeStrings.Get(36040).c_str(), m_cecAdapter ? m_configuration.serverVersion : -1, CEC_LIB_SUPPORTED_VERSION);
 
       // display warning: incompatible libCEC
       CStdString strMessage;
-      strMessage.Format(g_localizeStrings.Get(36013).c_str(), m_cecAdapter ? m_configuration.serverVersion : -1, CEC_LIB_SUPPORTED_VERSION);
+      strMessage.Format(g_localizeStrings.Get(36040).c_str(), m_cecAdapter ? m_configuration.serverVersion : -1, CEC_LIB_SUPPORTED_VERSION);
       CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error, g_localizeStrings.Get(36000), strMessage);
       m_bError = true;
       if (m_cecAdapter)
@@ -240,15 +261,10 @@ bool CPeripheralCecAdapter::InitialiseFeature(const PeripheralFeature feature)
 
 void CPeripheralCecAdapter::SetVersionInfo(const libcec_configuration &configuration)
 {
-  m_strVersionInfo.Format("libCEC %s", m_cecAdapter->ToString((cec_server_version)configuration.serverVersion));
-
-  // append firmware version number
-  if (configuration.serverVersion >= CEC_SERVER_VERSION_1_6_0)
-    m_strVersionInfo.AppendFormat(" - firmware v%d", configuration.iFirmwareVersion);
+  m_strVersionInfo.Format("libCEC %s - firmware v%d", m_cecAdapter->ToString((cec_server_version)configuration.serverVersion), configuration.iFirmwareVersion);
 
   // append firmware build date
-  if (configuration.serverVersion >= CEC_SERVER_VERSION_1_6_2 &&
-      configuration.iFirmwareBuildDate != CEC_FW_BUILD_UNKNOWN)
+  if (configuration.iFirmwareBuildDate != CEC_FW_BUILD_UNKNOWN)
   {
     CDateTime dt((time_t)configuration.iFirmwareBuildDate);
     m_strVersionInfo.AppendFormat(" (%s)", dt.GetAsDBDate().c_str());
@@ -629,7 +645,7 @@ void CPeripheralCecAdapter::SetMenuLanguage(const char *strLanguage)
     CLog::Log(LOGWARNING, "%s - TV menu language set to unknown value '%s'", __FUNCTION__, strLanguage);
 }
 
-int CPeripheralCecAdapter::CecCommand(void *cbParam, const cec_command &command)
+int CPeripheralCecAdapter::CecCommand(void *cbParam, const cec_command command)
 {
   CPeripheralCecAdapter *adapter = (CPeripheralCecAdapter *)cbParam;
   if (!adapter)
@@ -703,7 +719,7 @@ int CPeripheralCecAdapter::CecCommand(void *cbParam, const cec_command &command)
   return 1;
 }
 
-int CPeripheralCecAdapter::CecConfiguration(void *cbParam, const libcec_configuration &config)
+int CPeripheralCecAdapter::CecConfiguration(void *cbParam, const libcec_configuration config)
 {
   CPeripheralCecAdapter *adapter = (CPeripheralCecAdapter *)cbParam;
   if (!adapter)
@@ -714,7 +730,7 @@ int CPeripheralCecAdapter::CecConfiguration(void *cbParam, const libcec_configur
   return 1;
 }
 
-int CPeripheralCecAdapter::CecAlert(void *cbParam, const libcec_alert alert, const libcec_parameter &data)
+int CPeripheralCecAdapter::CecAlert(void *cbParam, const libcec_alert alert, const libcec_parameter data)
 {
   CPeripheralCecAdapter *adapter = (CPeripheralCecAdapter *)cbParam;
   if (!adapter)
@@ -759,7 +775,7 @@ int CPeripheralCecAdapter::CecAlert(void *cbParam, const libcec_alert alert, con
   return 1;
 }
 
-int CPeripheralCecAdapter::CecKeyPress(void *cbParam, const cec_keypress &key)
+int CPeripheralCecAdapter::CecKeyPress(void *cbParam, const cec_keypress key)
 {
   CPeripheralCecAdapter *adapter = (CPeripheralCecAdapter *)cbParam;
   if (!adapter)
@@ -1168,7 +1184,7 @@ void CPeripheralCecAdapter::CecSourceActivated(void *cbParam, const CEC::cec_log
   }
 }
 
-int CPeripheralCecAdapter::CecLogMessage(void *cbParam, const cec_log_message &message)
+int CPeripheralCecAdapter::CecLogMessage(void *cbParam, const cec_log_message message)
 {
   CPeripheralCecAdapter *adapter = (CPeripheralCecAdapter *)cbParam;
   if (!adapter)
@@ -1224,15 +1240,14 @@ void CPeripheralCecAdapter::SetConfigurationFromLibCEC(const CEC::libcec_configu
   bChanged |= SetSetting("device_type", (int)config.deviceTypes[0]);
 
   // hide the "connected device" and "hdmi port number" settings when the PA was autodetected
-  bool bPAAutoDetected(config.serverVersion >= CEC_SERVER_VERSION_1_7_0 &&
-      config.bAutodetectAddress == 1);
+  bool bPAAutoDetected(config.bAutodetectAddress == 1);
 
   SetSettingVisible("connected_device", !bPAAutoDetected);
   SetSettingVisible("cec_hdmi_port", !bPAAutoDetected);
 
   // set the connected device
   m_configuration.baseDevice = config.baseDevice;
-  bChanged |= SetSetting("connected_device", (int)config.baseDevice);
+  bChanged |= SetSetting("connected_device", config.baseDevice == CECDEVICE_AUDIOSYSTEM ? LOCALISED_ID_AVR : LOCALISED_ID_TV);
 
   // set the HDMI port number
   m_configuration.iHDMIPort = config.iHDMIPort;
@@ -1255,19 +1270,11 @@ void CPeripheralCecAdapter::SetConfigurationFromLibCEC(const CEC::libcec_configu
 
   // set the devices to wake when starting
   m_configuration.wakeDevices = config.wakeDevices;
-  CStdString strWakeDevices;
-  for (unsigned int iPtr = CECDEVICE_TV; iPtr <= CECDEVICE_BROADCAST; iPtr++)
-    if (config.wakeDevices[iPtr])
-      strWakeDevices.AppendFormat(" %X", iPtr);
-  bChanged |= SetSetting("wake_devices", strWakeDevices.Trim());
+  bChanged |= WriteLogicalAddresses(config.wakeDevices, "wake_devices", "wake_devices_advanced");
 
   // set the devices to power off when stopping
   m_configuration.powerOffDevices = config.powerOffDevices;
-  CStdString strPowerOffDevices;
-  for (unsigned int iPtr = CECDEVICE_TV; iPtr <= CECDEVICE_BROADCAST; iPtr++)
-    if (config.powerOffDevices[iPtr])
-      strPowerOffDevices.AppendFormat(" %X", iPtr);
-  bChanged |= SetSetting("standby_devices", strPowerOffDevices.Trim());
+  bChanged |= WriteLogicalAddresses(config.powerOffDevices, "standby_devices", "standby_devices_advanced");
 
   // set the boolean settings
   m_configuration.bUseTVMenuLanguage = config.bUseTVMenuLanguage;
@@ -1281,21 +1288,14 @@ void CPeripheralCecAdapter::SetConfigurationFromLibCEC(const CEC::libcec_configu
 
   m_configuration.bPowerOffOnStandby = config.bPowerOffOnStandby;
 
-  if (config.serverVersion >= CEC_SERVER_VERSION_1_5_1)
-    m_configuration.bSendInactiveSource = config.bSendInactiveSource;
+  m_configuration.bSendInactiveSource = config.bSendInactiveSource;
   bChanged |= SetSetting("send_inactive_source", m_configuration.bSendInactiveSource == 1);
 
-  if (config.serverVersion >= CEC_SERVER_VERSION_1_6_0)
-  {
-    m_configuration.iFirmwareVersion = config.iFirmwareVersion;
-    m_configuration.bShutdownOnStandby = config.bShutdownOnStandby;
-  }
+  m_configuration.iFirmwareVersion = config.iFirmwareVersion;
+  m_configuration.bShutdownOnStandby = config.bShutdownOnStandby;
 
-  if (config.serverVersion >= CEC_SERVER_VERSION_1_6_2)
-  {
-    memcpy(m_configuration.strDeviceLanguage, config.strDeviceLanguage, 3);
-    m_configuration.iFirmwareBuildDate = config.iFirmwareBuildDate;
-  }
+  memcpy(m_configuration.strDeviceLanguage, config.strDeviceLanguage, 3);
+  m_configuration.iFirmwareBuildDate = config.iFirmwareBuildDate;
 
   SetVersionInfo(m_configuration);
 
@@ -1309,8 +1309,8 @@ void CPeripheralCecAdapter::SetConfigurationFromLibCEC(const CEC::libcec_configu
 
 void CPeripheralCecAdapter::SetConfigurationFromSettings(void)
 {
-  // client version 1.7.1
-  m_configuration.clientVersion = CEC_CLIENT_VERSION_1_7_1;
+  // client version 2.0.0
+  m_configuration.clientVersion = CEC_CLIENT_VERSION_2_0_0;
 
   // device name 'XBMC'
   snprintf(m_configuration.strDeviceName, 13, "%s", GetSettingString("device_name").c_str());
@@ -1341,9 +1341,10 @@ void CPeripheralCecAdapter::SetConfigurationFromSettings(void)
 
   // set the connected device
   int iConnectedDevice = GetSettingInt("connected_device");
-  if (iConnectedDevice == CECDEVICE_TV ||
-      iConnectedDevice == CECDEVICE_AUDIOSYSTEM)
-    m_configuration.baseDevice = (cec_logical_address)iConnectedDevice;
+  if (iConnectedDevice == LOCALISED_ID_AVR)
+    m_configuration.baseDevice = CECDEVICE_AUDIOSYSTEM;
+  else if (iConnectedDevice == LOCALISED_ID_TV)
+    m_configuration.baseDevice = CECDEVICE_TV;
 
   // set the HDMI port number
   int iHDMIPort = GetSettingInt("cec_hdmi_port");
@@ -1358,14 +1359,20 @@ void CPeripheralCecAdapter::SetConfigurationFromSettings(void)
     m_configuration.tvVendor = iVendor;
 
   // read the devices to wake when starting
-  CStdString strWakeDevices = CStdString(GetSettingString("wake_devices")).Trim();
+  CStdString strWakeDevices = CStdString(GetSettingString("wake_devices_advanced")).Trim();
   m_configuration.wakeDevices.Clear();
-  ReadLogicalAddresses(strWakeDevices, m_configuration.wakeDevices);
+  if (!strWakeDevices.IsEmpty())
+    ReadLogicalAddresses(strWakeDevices, m_configuration.wakeDevices);
+  else
+    ReadLogicalAddresses(GetSettingInt("wake_devices"), m_configuration.wakeDevices);
 
   // read the devices to power off when stopping
-  CStdString strStandbyDevices = CStdString(GetSettingString("standby_devices")).Trim();
+  CStdString strStandbyDevices = CStdString(GetSettingString("standby_devices_advanced")).Trim();
   m_configuration.powerOffDevices.Clear();
-  ReadLogicalAddresses(strStandbyDevices, m_configuration.powerOffDevices);
+  if (!strStandbyDevices.IsEmpty())
+    ReadLogicalAddresses(strStandbyDevices, m_configuration.powerOffDevices);
+  else
+    ReadLogicalAddresses(GetSettingInt("standby_devices"), m_configuration.powerOffDevices);
 
   // read the boolean settings
   m_configuration.bUseTVMenuLanguage   = GetSettingBool("use_tv_menu_language") ? 1 : 0;
@@ -1377,6 +1384,9 @@ void CPeripheralCecAdapter::SetConfigurationFromSettings(void)
   int iStandbyAction(GetSettingInt("standby_pc_on_tv_standby"));
   m_configuration.bPowerOffOnStandby = iStandbyAction == 13011 ? 1 : 0;
   m_configuration.bShutdownOnStandby = iStandbyAction == 13005 ? 1 : 0;
+
+  // double tap prevention timeout in ms
+  m_configuration.iDoubleTapTimeoutMs = GetSettingInt("double_tap_timeout_ms");
 }
 
 void CPeripheralCecAdapter::ReadLogicalAddresses(const CStdString &strString, cec_logical_addresses &addresses)
@@ -1393,6 +1403,51 @@ void CPeripheralCecAdapter::ReadLogicalAddresses(const CStdString &strString, ce
   }
 }
 
+void CPeripheralCecAdapter::ReadLogicalAddresses(int iLocalisedId, cec_logical_addresses &addresses)
+{
+  addresses.Clear();
+  switch (iLocalisedId)
+  {
+  case LOCALISED_ID_TV:
+    addresses.Set(CECDEVICE_TV);
+    break;
+  case LOCALISED_ID_AVR:
+    addresses.Set(CECDEVICE_AUDIOSYSTEM);
+    break;
+  case LOCALISED_ID_TV_AVR:
+    addresses.Set(CECDEVICE_TV);
+    addresses.Set(CECDEVICE_AUDIOSYSTEM);
+    break;
+  case LOCALISED_ID_NONE:
+  default:
+    break;
+  }
+}
+
+bool CPeripheralCecAdapter::WriteLogicalAddresses(const cec_logical_addresses& addresses, const string& strSettingName, const string& strAdvancedSettingName)
+{
+  bool bChanged(false);
+
+  // only update the advanced setting if it was set by the user
+  if (!GetSettingString(strAdvancedSettingName).IsEmpty())
+  {
+    CStdString strPowerOffDevices;
+    for (unsigned int iPtr = CECDEVICE_TV; iPtr <= CECDEVICE_BROADCAST; iPtr++)
+      if (addresses[iPtr])
+        strPowerOffDevices.AppendFormat(" %X", iPtr);
+    bChanged = SetSetting(strAdvancedSettingName, strPowerOffDevices.Trim());
+  }
+
+  int iSettingPowerOffDevices = LOCALISED_ID_NONE;
+  if (addresses[CECDEVICE_TV] && addresses[CECDEVICE_AUDIOSYSTEM])
+    iSettingPowerOffDevices = LOCALISED_ID_TV_AVR;
+  else if (addresses[CECDEVICE_TV])
+    iSettingPowerOffDevices = LOCALISED_ID_TV;
+  else if (addresses[CECDEVICE_AUDIOSYSTEM])
+    iSettingPowerOffDevices = LOCALISED_ID_AVR;
+  return SetSetting(strSettingName, iSettingPowerOffDevices) || bChanged;
+}
+
 CPeripheralCecAdapterUpdateThread::CPeripheralCecAdapterUpdateThread(CPeripheralCecAdapter *adapter, libcec_configuration *configuration) :
     CThread("CEC Adapter Update Thread"),
     m_adapter(adapter),
@@ -1611,15 +1666,20 @@ void CPeripheralCecAdapter::OnDeviceRemoved(void)
 
 void CPeripheralCecAdapter::ReopenConnection(void)
 {
+  // stop running thread
   {
     CSingleLock lock(m_critSection);
     m_iExitCode = EXITCODE_RESTARTAPP;
     CAnnouncementManager::RemoveAnnouncer(this);
     StopThread(false);
   }
-
   StopThread();
-  Create();
+
+  // reset all members to their defaults
+  ResetMembers();
+
+  // reopen the connection
+  InitialiseFeature(FEATURE_CEC);
 }
 
 void CPeripheralCecAdapter::ActivateSource(void)
index 417b859..10229d2 100644 (file)
@@ -119,12 +119,14 @@ namespace PERIPHERALS
     void SetConfigurationFromLibCEC(const CEC::libcec_configuration &config);
     void SetVersionInfo(const CEC::libcec_configuration &configuration);
     static void ReadLogicalAddresses(const CStdString &strString, CEC::cec_logical_addresses &addresses);
-    static int CecKeyPress(void *cbParam, const CEC::cec_keypress &key);
+    static void ReadLogicalAddresses(int iLocalisedId, CEC::cec_logical_addresses &addresses);
+    bool WriteLogicalAddresses(const CEC::cec_logical_addresses& addresses, const std::string& strSettingName, const std::string& strAdvancedSettingName);
+    static int CecKeyPress(void *cbParam, const CEC::cec_keypress key);
     void PushCecKeypress(const CecButtonPress &key);
-    static int CecLogMessage(void *cbParam, const CEC::cec_log_message &message);
-    static int CecCommand(void *cbParam, const CEC::cec_command &command);
-    static int CecConfiguration(void *cbParam, const CEC::libcec_configuration &config);
-    static int CecAlert(void *cbParam, const CEC::libcec_alert alert, const CEC::libcec_parameter &data);
+    static int CecLogMessage(void *cbParam, const CEC::cec_log_message message);
+    static int CecCommand(void *cbParam, const CEC::cec_command command);
+    static int CecConfiguration(void *cbParam, const CEC::libcec_configuration config);
+    static int CecAlert(void *cbParam, const CEC::libcec_alert alert, const CEC::libcec_parameter data);
     static void CecSourceActivated(void *param, const CEC::cec_logical_address address, const uint8_t activated);
     bool IsRunning(void) const;
     void ReopenConnection(void);
@@ -139,6 +141,8 @@ namespace PERIPHERALS
     static bool FindConfigLocation(CStdString &strString);
     static bool TranslateComPort(CStdString &strPort);
 
+    void ResetMembers(void);
+
     DllLibCEC*                        m_dll;
     CEC::ICECAdapter*                 m_cecAdapter;
     bool                              m_bStarted;
index 8732fc6..f9df4a0 100644 (file)
@@ -264,10 +264,10 @@ bool CGUIWindowPictures::Update(const CStdString &strDirectory)
   if (!CGUIMediaWindow::Update(strDirectory))
     return false;
 
-  m_vecItems->SetThumbnailImage("");
+  m_vecItems->SetArt("thumb", "");
   if (g_guiSettings.GetBool("pictures.generatethumbs"))
     m_thumbLoader.Load(*m_vecItems);
-  m_vecItems->SetThumbnailImage(CPictureThumbLoader::GetCachedImage(*m_vecItems, "thumb"));
+  m_vecItems->SetArt("thumb", CPictureThumbLoader::GetCachedImage(*m_vecItems, "thumb"));
 
   return true;
 }
@@ -455,13 +455,15 @@ void CGUIWindowPictures::GetContextButtons(int itemNumber, CContextButtons &butt
     }
     else
     {
-      if (item)
+      if (item && !item->GetPath().Left(14).Equals("addons://more/"))
       {
         if (!m_vecItems->IsPlugin() && (item->IsPlugin() || item->IsScript()))
           buttons.Add(CONTEXT_BUTTON_INFO, 24003); // Add-on info
         if (!(item->m_bIsFolder || item->IsZIP() || item->IsRAR() || item->IsCBZ() || item->IsCBR() || item->IsScript()))
+        {
           buttons.Add(CONTEXT_BUTTON_INFO, 13406); // picture info
-        buttons.Add(CONTEXT_BUTTON_VIEW_SLIDESHOW, item->m_bIsFolder ? 13317 : 13422);      // View Slideshow
+          buttons.Add(CONTEXT_BUTTON_VIEW_SLIDESHOW, item->m_bIsFolder ? 13317 : 13422);      // View Slideshow
+        }
         if (item->m_bIsFolder)
           buttons.Add(CONTEXT_BUTTON_RECURSIVE_SLIDESHOW, 13318);     // Recursive Slideshow
 
@@ -476,9 +478,11 @@ void CGUIWindowPictures::GetContextButtons(int itemNumber, CContextButtons &butt
 
       if (item->IsPlugin() || item->IsScript() || m_vecItems->IsPlugin())
         buttons.Add(CONTEXT_BUTTON_PLUGIN_SETTINGS, 1045);
-
-      buttons.Add(CONTEXT_BUTTON_GOTO_ROOT, 20128);
-      buttons.Add(CONTEXT_BUTTON_SWITCH_MEDIA, 523);
+      else
+      {
+        buttons.Add(CONTEXT_BUTTON_GOTO_ROOT, 20128);
+        buttons.Add(CONTEXT_BUTTON_SWITCH_MEDIA, 523);
+      }
     }
   }
   CGUIMediaWindow::GetContextButtons(itemNumber, buttons);
index 4c6a74d..44cbe88 100644 (file)
@@ -202,6 +202,16 @@ void CGUIWindowSlideShow::AnnouncePlaylistAdd(const CFileItemPtr& item, int pos)
   ANNOUNCEMENT::CAnnouncementManager::Announce(ANNOUNCEMENT::Playlist, "xbmc", "OnAdd", item, data);
 }
 
+void CGUIWindowSlideShow::AnnouncePropertyChanged(const std::string &strProperty, const CVariant &value)
+{
+  if (strProperty.empty() || value.isNull())
+    return;
+
+  CVariant data;
+  data["player"]["playerid"] = PLAYLIST_PICTURE;
+  data["property"][strProperty] = value;
+  ANNOUNCEMENT::CAnnouncementManager::Announce(ANNOUNCEMENT::Player, "xbmc", "OnPropertyChanged", data);
+}
 
 bool CGUIWindowSlideShow::IsPlaying() const
 {
@@ -1030,6 +1040,8 @@ void CGUIWindowSlideShow::Shuffle()
   m_iCurrentSlide = 0;
   m_iNextSlide = 1;
   m_bShuffled = true;
+
+  AnnouncePropertyChanged("shuffled", true);
 }
 
 int CGUIWindowSlideShow::NumSlides() const
index e881a87..a573301 100644 (file)
@@ -30,6 +30,7 @@
 #include "SortFileItem.h"
 
 class CFileItemList;
+class CVariant;
 
 class CGUIWindowSlideShow;
 
@@ -114,6 +115,7 @@ private:
   void AnnouncePlaylistRemove(int pos);
   void AnnouncePlaylistClear();
   void AnnouncePlaylistAdd(const CFileItemPtr& item, int pos);
+  void AnnouncePropertyChanged(const std::string &strProperty, const CVariant &value);
 
   int m_iCurrentSlide;
   int m_iNextSlide;
index 1f0e3dc..8b07d8e 100644 (file)
@@ -64,7 +64,7 @@ bool CPictureInfoLoader::LoadItem(CFileItem* pItem)
   if (mapItem && mapItem->m_dateTime==pItem->m_dateTime && mapItem->HasPictureInfoTag())
   { // Query map if we previously cached the file on HD
     *pItem->GetPictureInfoTag() = *mapItem->GetPictureInfoTag();
-    pItem->SetThumbnailImage(mapItem->GetThumbnailImage());
+    pItem->SetArt("thumb", mapItem->GetArt("thumb"));
     return true;
   }
 
index 1898389..c6a5a57 100644 (file)
@@ -50,19 +50,19 @@ bool CPictureThumbLoader::LoadItem(CFileItem* pItem)
   if (pItem->m_bIsShareOrDrive) return true;
   if (pItem->IsParentFolder()) return true;
 
-  if (pItem->HasThumbnail() && m_regenerateThumbs)
+  if (pItem->HasArt("thumb") && m_regenerateThumbs)
   {
-    CTextureCache::Get().ClearCachedImage(pItem->GetThumbnailImage());
+    CTextureCache::Get().ClearCachedImage(pItem->GetArt("thumb"));
     CTextureDatabase db;
     if (db.Open())
       db.ClearTextureForPath(pItem->GetPath(), "thumb");
-    pItem->SetThumbnailImage("");
+    pItem->SetArt("thumb", "");
   }
 
   CStdString thumb;
   if (pItem->IsPicture() && !pItem->IsZIP() && !pItem->IsRAR() && !pItem->IsCBZ() && !pItem->IsCBR() && !pItem->IsPlayList())
   { // load the thumb from the image file
-    thumb = pItem->HasThumbnail() ? pItem->GetThumbnailImage() : CTextureCache::GetWrappedThumbURL(pItem->GetPath());
+    thumb = pItem->HasArt("thumb") ? pItem->GetArt("thumb") : CTextureCache::GetWrappedThumbURL(pItem->GetPath());
   }
   else if (pItem->IsVideo() && !pItem->IsZIP() && !pItem->IsRAR() && !pItem->IsCBZ() && !pItem->IsCBR() && !pItem->IsPlayList())
   { // video
@@ -82,14 +82,14 @@ bool CPictureThumbLoader::LoadItem(CFileItem* pItem)
       }
     }
   }
-  else if (!pItem->HasThumbnail())
+  else if (!pItem->HasArt("thumb"))
   { // folder, zip, cbz, rar, cbr, playlist may have a previously cached image
     thumb = GetCachedImage(*pItem, "thumb");
   }
   if (!thumb.IsEmpty())
   {
     CTextureCache::Get().BackgroundCacheImage(thumb);
-    pItem->SetThumbnailImage(thumb);
+    pItem->SetArt("thumb", thumb);
   }
   pItem->FillInDefaultIcon();
   return true;
@@ -116,7 +116,7 @@ void CPictureThumbLoader::OnLoaderFinish()
 
 void CPictureThumbLoader::ProcessFoldersAndArchives(CFileItem *pItem)
 {
-  if (pItem->HasThumbnail())
+  if (pItem->HasArt("thumb"))
     return;
 
   CTextureDatabase db;
@@ -128,7 +128,7 @@ void CPictureThumbLoader::ProcessFoldersAndArchives(CFileItem *pItem)
     {
       db.SetTextureForPath(pItem->GetPath(), "thumb", strTBN);
       CTextureCache::Get().BackgroundCacheImage(strTBN);
-      pItem->SetThumbnailImage(strTBN);
+      pItem->SetArt("thumb", strTBN);
       return;
     }
   }
@@ -154,7 +154,7 @@ void CPictureThumbLoader::ProcessFoldersAndArchives(CFileItem *pItem)
     {
       db.SetTextureForPath(pItem->GetPath(), "thumb", thumb);
       CTextureCache::Get().BackgroundCacheImage(thumb);
-      pItem->SetThumbnailImage(thumb);
+      pItem->SetArt("thumb", thumb);
       return;
     }
     if (!pItem->IsPlugin())
@@ -190,7 +190,7 @@ void CPictureThumbLoader::ProcessFoldersAndArchives(CFileItem *pItem)
             if (item->m_bIsFolder)
             {
               ProcessFoldersAndArchives(item.get());
-              pItem->SetThumbnailImage(items[i]->GetThumbnailImage());
+              pItem->SetArt("thumb", items[i]->GetArt("thumb"));
               pItem->SetIconImage(items[i]->GetIconImage());
               return;
             }
@@ -208,7 +208,7 @@ void CPictureThumbLoader::ProcessFoldersAndArchives(CFileItem *pItem)
         CStdString thumb = CTextureCache::GetWrappedThumbURL(items[0]->GetPath());
         db.SetTextureForPath(pItem->GetPath(), "thumb", thumb);
         CTextureCache::Get().BackgroundCacheImage(thumb);
-        pItem->SetThumbnailImage(thumb);
+        pItem->SetArt("thumb", thumb);
       }
       else
       {
@@ -227,7 +227,7 @@ void CPictureThumbLoader::ProcessFoldersAndArchives(CFileItem *pItem)
           details.height = g_advancedSettings.GetThumbSize();
           CTextureCache::Get().AddCachedTexture(thumb, details);
           db.SetTextureForPath(pItem->GetPath(), "thumb", thumb);
-          pItem->SetThumbnailImage(CTextureCache::GetCachedPath(relativeCacheFile));
+          pItem->SetArt("thumb", CTextureCache::GetCachedPath(relativeCacheFile));
         }
       }
     }
index ee78668..739c0d4 100644 (file)
@@ -132,7 +132,8 @@ static const operatorField operators[] = { { "contains", CSmartPlaylistRule::OPE
                                            { "inthelast", CSmartPlaylistRule::OPERATOR_IN_THE_LAST, 21410 },
                                            { "notinthelast", CSmartPlaylistRule::OPERATOR_NOT_IN_THE_LAST, 21411 },
                                            { "true", CSmartPlaylistRule::OPERATOR_TRUE, 20122 },
-                                           { "false", CSmartPlaylistRule::OPERATOR_FALSE, 20424 }
+                                           { "false", CSmartPlaylistRule::OPERATOR_FALSE, 20424 },
+                                           { "between", CSmartPlaylistRule::OPERATOR_BETWEEN, 21456 }
                                          };
 
 #define NUM_OPERATORS sizeof(operators) / sizeof(operatorField)
@@ -747,6 +748,21 @@ CStdString CSmartPlaylistRule::GetWhereClause(const CDatabase &db, const CStdStr
     }
   }
 
+  // The BETWEEN operator is handled special
+  if (op == OPERATOR_BETWEEN)
+  {
+    if (m_parameter.size() != 2)
+      return "";
+
+    FIELD_TYPE fieldType = GetFieldType(m_field);
+    if (fieldType == NUMERIC_FIELD || m_field == FieldYear)
+      return db.PrepareSQL("CAST(%s as DECIMAL(5,1)) BETWEEN %s AND %s", GetField(m_field, strType).c_str(), m_parameter[0].c_str(), m_parameter[1].c_str());
+    else if (fieldType == SECONDS_FIELD)
+      return db.PrepareSQL("CAST(%s as INTEGER) BETWEEN %s AND %s", GetField(m_field, strType).c_str(), m_parameter[0].c_str(), m_parameter[1].c_str());
+    else
+      return db.PrepareSQL("%s BETWEEN '%s' AND '%s'", GetField(m_field, strType).c_str(), m_parameter[0].c_str(), m_parameter[1].c_str());
+  }
+
   // now the query parameter
   CStdString wholeQuery;
   for (vector<CStdString>::const_iterator it = m_parameter.begin(); it != m_parameter.end(); /* it++ is done further down */)
@@ -810,6 +826,13 @@ CStdString CSmartPlaylistRule::GetWhereClause(const CDatabase &db, const CStdStr
       else if (m_field == FieldAlbumArtist)
         query = GetField(FieldId, strType) + negate + " IN (SELECT album_artist.idAlbum FROM album_artist, artist WHERE album_artist.idArtist = artist.idArtist AND artist.strArtist" + parameter + ")";
     }
+    else if (strType == "artists")
+    {
+      table = "artistview";
+
+      if (m_field == FieldGenre)
+        query = GetField(FieldId, strType) + negate + " IN (SELECT song_artist.idArtist FROM song_artist, song_genre, genre WHERE song_artist.idSong = song_genre.idSong AND song_genre.idGenre = genre.idGenre AND genre.strGenre" + parameter + ")";
+    }
     else if (strType == "movies")
     {
       table = "movieview";
@@ -1093,11 +1116,7 @@ void CSmartPlaylistRuleCombination::AddCombination(const CSmartPlaylistRuleCombi
 
 CSmartPlaylist::CSmartPlaylist()
 {
-  m_ruleCombination.SetType(CSmartPlaylistRuleCombination::CombinationAnd);
-  m_limit = 0;
-  m_orderField = SortByNone;
-  m_orderAscending = true;
-  m_playlistType = "songs"; // sane default
+  Reset();
 }
 
 TiXmlElement *CSmartPlaylist::OpenAndReadName(const CStdString &path)
@@ -1374,6 +1393,17 @@ bool CSmartPlaylist::SaveAsJson(CStdString &json, bool full /* = true */) const
   return json.size() > 0;
 }
 
+void CSmartPlaylist::Reset()
+{
+  m_ruleCombination.m_combinations.clear();
+  m_ruleCombination.m_rules.clear();
+  m_ruleCombination.SetType(CSmartPlaylistRuleCombination::CombinationAnd);
+  m_limit = 0;
+  m_orderField = SortByNone;
+  m_orderAscending = true;
+  m_playlistType = "songs"; // sane default
+}
+
 void CSmartPlaylist::SetName(const CStdString &name)
 {
   m_playlistName = name;
index b8a2374..190abd0 100644 (file)
@@ -60,6 +60,7 @@ public:
                          OPERATOR_NOT_IN_THE_LAST,
                          OPERATOR_TRUE,
                          OPERATOR_FALSE,
+                         OPERATOR_BETWEEN,
                          OPERATOR_END
                        };
 
@@ -137,6 +138,7 @@ public:
 private:
   friend class CSmartPlaylist;
   friend class CGUIDialogSmartPlaylistEditor;
+  friend class CGUIDialogMediaFilter;
 
   Combination m_type;
   CSmartPlaylistRuleCombinations m_combinations;
@@ -159,6 +161,8 @@ public:
   TiXmlElement *OpenAndReadName(const CStdString &path);
   bool LoadFromXML(TiXmlElement *root, const CStdString &encoding = "UTF-8");
 
+  void Reset();
+
   void SetName(const CStdString &name);
   void SetType(const CStdString &type); // music, video, mixed
   const CStdString& GetName() const { return m_playlistName; };
@@ -191,8 +195,10 @@ public:
   static void GetAvailableFields(const std::string &type, std::vector<std::string> &fieldList);
   static void GetAvailableOperators(std::vector<std::string> &operatorList);
 
+  bool IsEmpty() const { return m_ruleCombination.m_rules.empty() && m_ruleCombination.m_combinations.empty(); }
 private:
   friend class CGUIDialogSmartPlaylistEditor;
+  friend class CGUIDialogMediaFilter;
 
   TiXmlElement* readName();
   TiXmlElement *readNameFromXml(const CStdString &xml);
index 13d85cd..726a186 100644 (file)
@@ -78,12 +78,15 @@ void CPVRClient::ResetProperties(int iClientId /* = PVR_INVALID_CLIENT_ID */)
   memset(&m_addonCapabilities, 0, sizeof(m_addonCapabilities));
   ResetQualityData(m_qualityInfo);
   m_apiVersion = AddonVersion("0.0.0");
+  m_bCanPauseStream       = false;
+  m_bCanSeekStream        = false;
 }
 
-bool CPVRClient::Create(int iClientId)
+ADDON_STATUS CPVRClient::Create(int iClientId)
 {
+  ADDON_STATUS status(ADDON_STATUS_UNKNOWN);
   if (iClientId <= PVR_INVALID_CLIENT_ID || iClientId == PVR_VIRTUAL_CLIENT_ID)
-    return false;
+    return status;
 
   /* ensure that a previous instance is destroyed */
   Destroy();
@@ -96,16 +99,14 @@ bool CPVRClient::Create(int iClientId)
   CLog::Log(LOGDEBUG, "PVR - %s - creating PVR add-on instance '%s'", __FUNCTION__, Name().c_str());
   try
   {
-    bReadyToUse = CAddonDll<DllPVRClient, PVRClient, PVR_PROPERTIES>::Create() &&
-        GetAddonProperties();
+    if ((status = CAddonDll<DllPVRClient, PVRClient, PVR_PROPERTIES>::Create()) == ADDON_STATUS_OK)
+      bReadyToUse = GetAddonProperties();
   }
   catch (exception &e) { LogException(e, __FUNCTION__); }
 
   m_bReadyToUse = bReadyToUse;
-  if (!bReadyToUse)
-    ResetProperties(iClientId);
 
-  return bReadyToUse;
+  return status;
 }
 
 bool CPVRClient::DllLoaded(void) const
@@ -918,7 +919,15 @@ bool CPVRClient::SwitchChannel(const CPVRChannel &channel)
   {
     PVR_CHANNEL tag;
     WriteClientChannelInfo(channel, tag);
-    try { bSwitched = m_pStruct->SwitchChannel(tag); }
+    try
+    {
+      bSwitched = m_pStruct->SwitchChannel(tag);
+      if (bSwitched)
+      {
+        m_bCanPauseStream = m_pStruct->CanPauseStream();
+        m_bCanSeekStream = m_pStruct->CanSeekStream();
+      }
+    }
     catch (exception &e) { LogException(e, __FUNCTION__); }
   }
 
@@ -1229,7 +1238,15 @@ bool CPVRClient::OpenStream(const CPVRChannel &channel, bool bIsSwitchingChannel
     PVR_CHANNEL tag;
     WriteClientChannelInfo(channel, tag);
 
-    try { bReturn = m_pStruct->OpenLiveStream(tag); }
+    try
+    {
+      bReturn = m_pStruct->OpenLiveStream(tag);
+      if (bReturn)
+      {
+        m_bCanPauseStream = m_pStruct->CanPauseStream();
+        m_bCanSeekStream = m_pStruct->CanSeekStream();
+      }
+    }
     catch (exception &e) { LogException(e, __FUNCTION__); }
   }
 
@@ -1255,7 +1272,15 @@ bool CPVRClient::OpenStream(const CPVRRecording &recording)
     PVR_RECORDING tag;
     WriteClientRecordingInfo(recording, tag);
 
-    try { bReturn = m_pStruct->OpenRecordedStream(tag); }
+    try
+    {
+      bReturn = m_pStruct->OpenRecordedStream(tag);
+      if (bReturn)
+      {
+        m_bCanPauseStream = m_pStruct->CanPauseStream();
+        m_bCanSeekStream = m_pStruct->CanSeekStream();
+      }
+    }
     catch (exception &e) { LogException(e, __FUNCTION__); }
   }
 
@@ -1282,12 +1307,40 @@ void CPVRClient::CloseStream(void)
   }
   else if (IsPlayingRecording())
   {
-    try { return m_pStruct->CloseRecordedStream(); }
+    try { m_pStruct->CloseRecordedStream(); }
     catch (exception &e) { LogException(e, "CloseRecordedStream()"); }
 
     CSingleLock lock(m_critSection);
     m_bIsPlayingRecording = false;
   }
+
+  m_bCanPauseStream = false;
+  m_bCanSeekStream = false;
+}
+
+void CPVRClient::PauseStream(bool bPaused)
+{
+  if (IsPlaying())
+  {
+    try { m_pStruct->PauseStream(bPaused); }
+    catch (exception &e) { LogException(e, "PauseStream()"); }
+  }
+}
+
+bool CPVRClient::CanPauseStream(void) const
+{
+  if (IsPlaying())
+    return m_bCanPauseStream;
+
+  return false;
+}
+
+bool CPVRClient::CanSeekStream(void) const
+{
+  if (IsPlaying())
+    return m_bCanSeekStream;
+
+  return false;
 }
 
 void CPVRClient::ResetQualityData(PVR_SIGNAL_STATUS &qualityInfo)
index 9106118..fedfcef 100644 (file)
@@ -65,7 +65,7 @@ namespace PVR
      * @brief Initialise the instance of this add-on.
      * @param iClientId The ID of this add-on.
      */
-    bool Create(int iClientId);
+    ADDON_STATUS Create(int iClientId);
 
     /*!
      * @return True when the dll for this add-on was loaded, false otherwise (e.g. unresolved symbols)
@@ -357,6 +357,11 @@ namespace PVR
     int64_t GetStreamLength(void);
 
     /*!
+     * @brief (Un)Pause a stream
+     */
+    void PauseStream(bool bPaused);
+
+    /*!
      * @return The channel number on the server of the live stream that's currently being read.
      */
     int GetCurrentClientChannel(void);
@@ -382,6 +387,16 @@ namespace PVR
      */
     CStdString GetLiveStreamURL(const CPVRChannel &channel);
 
+    /*!
+     * @brief Check whether PVR backend supports pausing the currently playing stream
+     */
+    bool CanPauseStream(void) const;
+
+    /*!
+     * @brief Check whether PVR backend supports seeking for the currently playing stream
+     */
+    bool CanSeekStream(void) const;
+
     //@}
     /** @name PVR recording stream methods */
     //@{
@@ -558,5 +573,7 @@ namespace PVR
     bool           m_bIsPlayingRecording;
     CPVRRecording  m_playingRecording;
     ADDON::AddonVersion m_apiVersion;
+    bool           m_bCanPauseStream;
+    bool           m_bCanSeekStream;
   };
 }
index 51dcacc..f1d183c 100644 (file)
@@ -535,6 +535,30 @@ bool CPVRClients::CanRecordInstantly(void)
       currentChannel->CanRecord();
 }
 
+bool CPVRClients::CanPauseStream(void) const
+{
+  PVR_CLIENT client;
+
+  if (GetPlayingClient(client))
+  {
+    return client->CanPauseStream();
+  }
+
+  return false;
+}
+
+bool CPVRClients::CanSeekStream(void) const
+{
+  PVR_CLIENT client;
+
+  if (GetPlayingClient(client))
+  {
+    return client->CanSeekStream();
+  }
+
+  return false;
+}
+
 PVR_ERROR CPVRClients::GetEPGForChannel(const CPVRChannel &channel, CEpg *epg, time_t start, time_t end)
 {
   PVR_ERROR error(PVR_ERROR_UNKNOWN);
@@ -837,6 +861,7 @@ bool CPVRClients::UpdateAndInitialiseClients(bool bInitialiseAllClients /* = fal
       }
       else
       {
+        ADDON_STATUS status(ADDON_STATUS_UNKNOWN);
         CSingleLock lock(m_critSection);
         
         PVR_CLIENT addon;
@@ -847,10 +872,10 @@ bool CPVRClients::UpdateAndInitialiseClients(bool bInitialiseAllClients /* = fal
           bDisabled = true;
         }
         // re-check the enabled status. newly installed clients get disabled when they're added to the db
-        else if (addon->Enabled() && !addon->Create(iClientId))
+        else if (addon->Enabled() && (status = addon->Create(iClientId)) != ADDON_STATUS_OK)
         {
-          CLog::Log(LOGWARNING, "%s - failed to create add-on %s", __FUNCTION__, clientAddon->Name().c_str());
-          if (!addon.get() || !addon->DllLoaded())
+          CLog::Log(LOGWARNING, "%s - failed to create add-on %s, status = %d", __FUNCTION__, clientAddon->Name().c_str(), status);
+          if (!addon.get() || !addon->DllLoaded() || status == ADDON_STATUS_PERMANENT_FAILURE)
           {
             // failed to load the dll of this add-on, disable it
             CLog::Log(LOGWARNING, "%s - failed to load the dll for add-on %s, disabling it", __FUNCTION__, clientAddon->Name().c_str());
@@ -1260,6 +1285,13 @@ int64_t CPVRClients::GetStreamPosition(void)
   return -EINVAL;
 }
 
+void CPVRClients::PauseStream(bool bPaused)
+{
+  PVR_CLIENT client;
+  if (GetPlayingClient(client))
+    client->PauseStream(bPaused);
+}
+
 CStdString CPVRClients::GetCurrentInputFormat(void) const
 {
   CStdString strReturn;
index aa25bee..7bf0622 100644 (file)
@@ -212,6 +212,21 @@ namespace PVR
     void CloseStream(void);
 
     /*!
+     * @brief (Un)Pause a PVR stream (only called when timeshifting is supported)
+     */
+    void PauseStream(bool bPaused);
+
+    /*!
+     * @brief Check whether it is possible to pause the currently playing livetv or recording stream
+     */
+    bool CanPauseStream(void) const;
+
+    /*!
+     * @brief Check whether it is possible to seek the currently playing livetv or recording stream
+     */
+    bool CanSeekStream(void) const;
+
+    /*!
      * @brief Get the properties of the current playing stream content.
      * @return A pointer to the properties or NULL if no stream is playing.
      */
index 5d1b023..a46eec9 100644 (file)
@@ -1013,7 +1013,7 @@ int CPVRChannelGroup::GetEPGNow(CFileItemList &results)
     CFileItemPtr entry(new CFileItem(epgNow));
     entry->SetLabel2(epgNow.StartAsLocalTime().GetAsLocalizedTime(StringUtils::EmptyString, false));
     entry->SetPath(channel->ChannelName());
-    entry->SetThumbnailImage(channel->IconPath());
+    entry->SetArt("thumb", channel->IconPath());
     results.Add(entry);
   }
 
@@ -1039,7 +1039,7 @@ int CPVRChannelGroup::GetEPGNext(CFileItemList &results)
     CFileItemPtr entry(new CFileItem(epgNow));
     entry->SetLabel2(epgNow.StartAsLocalTime().GetAsLocalizedTime(StringUtils::EmptyString, false));
     entry->SetPath(channel->ChannelName());
-    entry->SetThumbnailImage(channel->IconPath());
+    entry->SetArt("thumb", channel->IconPath());
     results.Add(entry);
   }
 
index 6402a2d..9b256bb 100644 (file)
@@ -209,17 +209,17 @@ CPVRChannelGroupPtr CPVRChannelGroupsContainer::GetSelectedGroup(bool bRadio) co
   return Get(bRadio)->GetSelectedGroup();
 }
 
-CPVRChannelPtr CPVRChannelGroupsContainer::GetByUniqueID(int iClientChannelNumber, int iClientID)
+CPVRChannelPtr CPVRChannelGroupsContainer::GetByUniqueID(int iUniqueChannelId, int iClientID)
 {
   CPVRChannelPtr channel;
   CPVRChannelGroupPtr channelgroup = GetGroupAllTV();
   if (channelgroup)
-    channel = channelgroup->GetByClient(iClientChannelNumber, iClientID);
+    channel = channelgroup->GetByClient(iUniqueChannelId, iClientID);
 
   if (!channelgroup || !channel)
     channelgroup = GetGroupAllRadio();
   if (channelgroup)
-    channel = channelgroup->GetByClient(iClientChannelNumber, iClientID);
+    channel = channelgroup->GetByClient(iUniqueChannelId, iClientID);
 
   return channel;
 }
index 858788f..45779bc 100644 (file)
@@ -156,11 +156,11 @@ namespace PVR
 
     /*!
      * @brief Get a channel given it's channel ID from all containers.
-     * @param iClientChannelNumber The channel number on the client.
+     * @param iUniqueChannelId The unique channel id on the client.
      * @param iClientID The ID of the client.
      * @return The channel or NULL if it wasn't found.
      */
-    CPVRChannelPtr GetByUniqueID(int iClientChannelNumber, int iClientID);
+    CPVRChannelPtr GetByUniqueID(int iUniqueChannelId, int iClientID);
 
     /*!
      * @brief Get a channel given it's channel ID from all containers.
index 254f482..e503e46 100644 (file)
@@ -325,14 +325,14 @@ bool CGUIDialogPVRChannelManager::OnClickButtonChannelLogo(CGUIMessage &message)
   if (!pItem->GetProperty("Icon").asString().empty())
   {
     CFileItemPtr current(new CFileItem("thumb://Current", false));
-    current->SetThumbnailImage(pItem->GetPVRChannelInfoTag()->IconPath());
+    current->SetArt("thumb", pItem->GetPVRChannelInfoTag()->IconPath());
     current->SetLabel(g_localizeStrings.Get(20016));
     items.Add(current);
   }
-  else if (pItem->HasThumbnail())
+  else if (pItem->HasArt("thumb"))
   { // already have a thumb that the share doesn't know about - must be a local one, so we mayaswell reuse it.
     CFileItemPtr current(new CFileItem("thumb://Current", false));
-    current->SetThumbnailImage(pItem->GetThumbnailImage());
+    current->SetArt("thumb", pItem->GetArt("thumb"));
     current->SetLabel(g_localizeStrings.Get(20016));
     items.Add(current);
   }
index 4ca1951..0d33b6c 100644 (file)
@@ -185,7 +185,7 @@ bool CGUIDialogPVRGuideInfo::OnMessage(CGUIMessage& message)
   case GUI_MSG_WINDOW_INIT:
     CGUIDialog::OnMessage(message);
     Update();
-    break;
+    return true;
   case GUI_MSG_CLICKED:
     return OnClickButtonOK(message) ||
            OnClickButtonRecord(message) ||
index 91f7bad..534a623 100644 (file)
@@ -112,10 +112,10 @@ void CPVRRecordings::GetContents(const CStdString &strDirectory, CFileItemList *
       pFileItem->SetIconImage(current->m_strIconPath);
 
     if (!current->m_strThumbnailPath.IsEmpty())
-      pFileItem->SetThumbnailImage(current->m_strThumbnailPath);
+      pFileItem->SetArt("thumb", current->m_strThumbnailPath);
 
     if (!current->m_strFanartPath.IsEmpty())
-      pFileItem->SetProperty("Fanart_Image", current->m_strFanartPath);
+      pFileItem->SetArt("fanart", current->m_strFanartPath);
 
     // Set the play count either directly from client (if supported) or from video db
     if (g_PVRClients->SupportsRecordingPlayCount(pFileItem->GetPVRRecordingInfoTag()->m_iClientId))
@@ -463,7 +463,7 @@ bool CPVRRecordings::GetDirectory(const CStdString& strPath, CFileItemList &item
     {
       CFileItemPtr pFileItem = files.Get(i);
       CFileItemPtr pThumbItem = items.Get(pFileItem->GetPath());
-      if (!pThumbItem->HasThumbnail())
+      if (!pThumbItem->HasArt("thumb"))
         m_thumbLoader.LoadItem(pThumbItem.get());
     }
   }
index 05ff6ab..d499807 100644 (file)
@@ -241,6 +241,12 @@ CStdString CPVRTimerInfoTag::GetStatus() const
     strReturn = g_localizeStrings.Get(13106);
   else if (m_state == PVR_TIMER_STATE_RECORDING)
     strReturn = g_localizeStrings.Get(19162);
+  else if (m_state == PVR_TIMER_STATE_CONFLICT_OK)
+    strReturn = g_localizeStrings.Get(19275);
+  else if (m_state == PVR_TIMER_STATE_CONFLICT_NOK)    
+    strReturn = g_localizeStrings.Get(19276);  
+  else if (m_state == PVR_TIMER_STATE_ERROR)
+    strReturn = g_localizeStrings.Get(257);
 
   return strReturn;
 }
@@ -523,6 +529,13 @@ void CPVRTimerInfoTag::GetNotificationText(CStdString &strText) const
   case PVR_TIMER_STATE_COMPLETED:
     strText.Format("%s: '%s'", g_localizeStrings.Get(19227), m_strTitle.c_str());
     break;
+  case PVR_TIMER_STATE_CONFLICT_OK:    
+  case PVR_TIMER_STATE_CONFLICT_NOK:   
+    strText.Format("%s: '%s'", g_localizeStrings.Get(19277), m_strTitle.c_str());
+    break;
+  case PVR_TIMER_STATE_ERROR:
+    strText.Format("%s: '%s'", g_localizeStrings.Get(19278), m_strTitle.c_str());
+    break;
   default:
     break;
   }
index 8358368..e137dac 100644 (file)
@@ -98,7 +98,15 @@ namespace PVR
 
     void UpdateEpgEvent(bool bClear = false);
 
-    bool IsActive(void) const { return m_state == PVR_TIMER_STATE_SCHEDULED || m_state == PVR_TIMER_STATE_RECORDING; }
+    bool IsActive(void) const 
+    {  
+      return m_state == PVR_TIMER_STATE_SCHEDULED 
+        || m_state == PVR_TIMER_STATE_RECORDING
+        || m_state == PVR_TIMER_STATE_CONFLICT_OK
+        || m_state == PVR_TIMER_STATE_CONFLICT_NOK
+        || m_state == PVR_TIMER_STATE_ERROR;
+    }
+
     bool IsRecording(void) const { return m_state == PVR_TIMER_STATE_RECORDING; }
 
     CDateTime StartAsUTC(void) const;
index fdc8408..01e9550 100644 (file)
@@ -458,15 +458,15 @@ bool CGUIWindowPVRChannels::OnContextButtonSetThumb(CFileItem *item, CONTEXT_BUT
     {
       /* add the current thumb, if available */
       CFileItemPtr current(new CFileItem("thumb://Current", false));
-      current->SetThumbnailImage(channel->IconPath());
+      current->SetArt("thumb", channel->IconPath());
       current->SetLabel(g_localizeStrings.Get(20016));
       items.Add(current);
     }
-    else if (item->HasThumbnail())
+    else if (item->HasArt("thumb"))
     {
       /* already have a thumb that the share doesn't know about - must be a local one, so we may as well reuse it */
       CFileItemPtr current(new CFileItem("thumb://Current", false));
-      current->SetThumbnailImage(item->GetThumbnailImage());
+      current->SetArt("thumb", item->GetArt("thumb"));
       current->SetLabel(g_localizeStrings.Get(20016));
       items.Add(current);
     }
index a360372..1d2202b 100644 (file)
@@ -160,21 +160,21 @@ void CAdvancedSettings::Initialize()
   //m_videoStackRegExps.push_back("(.*?)([ ._-]*[0-9])(.*?)(\\.[^.]+)$");
 
   // foo.s01.e01, foo.s01_e01, S01E02 foo, S01 - E02
-  m_tvshowEnumRegExps.push_back(TVShowRegexp(false,"[Ss]([0-9]+)[][ ._-]*[Ee]([0-9]+(?:[a-i]|\\.[1-9](?![0-9]))?)([^\\\\/]*)$"));
+  m_tvshowEnumRegExps.push_back(TVShowRegexp(false,"[Ss]([0-9]+)[][ ._-]*[Ee]([0-9]+(?:(?:[a-i]|\\.[1-9])(?![0-9]))?)([^\\\\/]*)$"));
   // foo.ep01, foo.EP_01
-  m_tvshowEnumRegExps.push_back(TVShowRegexp(false,"[\\._ -]()[Ee][Pp]_?([0-9]+(?:[a-i]|\\.[1-9](?![0-9]))?)([^\\\\/]*)$"));
+  m_tvshowEnumRegExps.push_back(TVShowRegexp(false,"[\\._ -]()[Ee][Pp]_?([0-9]+(?:(?:[a-i]|\\.[1-9])(?![0-9]))?)([^\\\\/]*)$"));
   // foo.yyyy.mm.dd.* (byDate=true)
   m_tvshowEnumRegExps.push_back(TVShowRegexp(true,"([0-9]{4})[\\.-]([0-9]{2})[\\.-]([0-9]{2})"));
   // foo.mm.dd.yyyy.* (byDate=true)
   m_tvshowEnumRegExps.push_back(TVShowRegexp(true,"([0-9]{2})[\\.-]([0-9]{2})[\\.-]([0-9]{4})"));
   // foo.1x09* or just /1x09*
-  m_tvshowEnumRegExps.push_back(TVShowRegexp(false,"[\\\\/\\._ \\[\\(-]([0-9]+)x([0-9]+(?:[a-i]|\\.[1-9](?![0-9]))?)([^\\\\/]*)$"));
+  m_tvshowEnumRegExps.push_back(TVShowRegexp(false,"[\\\\/\\._ \\[\\(-]([0-9]+)x([0-9]+(?:(?:[a-i]|\\.[1-9])(?![0-9]))?)([^\\\\/]*)$"));
   // foo.103*, 103 foo
-  m_tvshowEnumRegExps.push_back(TVShowRegexp(false,"[\\\\/\\._ -]([0-9]+)([0-9][0-9](?:[a-i]|\\.[1-9](?![0-9]))?)([\\._ -][^\\\\/]*)$"));
+  m_tvshowEnumRegExps.push_back(TVShowRegexp(false,"[\\\\/\\._ -]([0-9]+)([0-9][0-9](?:(?:[a-i]|\\.[1-9])(?![0-9]))?)([\\._ -][^\\\\/]*)$"));
   // Part I, Pt.VI
   m_tvshowEnumRegExps.push_back(TVShowRegexp(false,"[\\/._ -]p(?:ar)?t[_. -]()([ivx]+)([._ -][^\\/]*)$"));
 
-  m_tvshowMultiPartEnumRegExp = "^[-_EeXx]+([0-9]+(?:[a-i]|\\.[1-9](?![0-9]))?)";
+  m_tvshowMultiPartEnumRegExp = "^[-_EeXx]+([0-9]+(?:(?:[a-i]|\\.[1-9])(?![0-9]))?)";
 
   m_remoteDelay = 3;
   m_controllerDeadzone = 0.2f;
index 7f501d9..0204039 100644 (file)
@@ -320,7 +320,7 @@ void CGUIDialogContentSettings::FillListControl()
   {
     CFileItemPtr item(new CFileItem((*iter)->Name()));
     item->SetPath((*iter)->ID());
-    item->SetThumbnailImage((*iter)->Icon());
+    item->SetArt("thumb", (*iter)->Icon());
     if (m_scraper && (*iter)->ID() == m_scraper->ID())
     {
       item->Select(true);
index 4ff4f0e..d34237b 100644 (file)
@@ -157,12 +157,12 @@ void CGUIDialogProfileSettings::OnSettingChanged(SettingInfo &setting)
     if (!m_strThumb.IsEmpty())
     {
       CFileItemPtr item(new CFileItem("thumb://Current", false));
-      item->SetThumbnailImage(m_strThumb);
+      item->SetArt("thumb", m_strThumb);
       item->SetLabel(g_localizeStrings.Get(20016));
       items.Add(item);
     }
     CFileItemPtr item(new CFileItem("thumb://None", false));
-    item->SetThumbnailImage(m_strDefaultImage);
+    item->SetArt("thumb", m_strDefaultImage);
     item->SetLabel(g_localizeStrings.Get(20018));
     items.Add(item);
     if (CGUIDialogFileBrowser::ShowAndGetImage(items,shares,g_localizeStrings.Get(1030),strThumb) &&
index 91b1e3a..5aa16cf 100644 (file)
@@ -198,7 +198,7 @@ void CGUIDialogSettings::UpdateSetting(unsigned int id)
     {
       float value = *(float *)setting.data;
       pControl->SetFloatValue(value);
-      if (setting.formatFunction) pControl->SetTextValue(setting.formatFunction(value, setting.interval));
+      if (setting.formatFunction.standard) pControl->SetTextValue(setting.formatFunction.standard(value, setting.interval));
     }
   }
   else if (setting.type == SettingInfo::BUTTON_DIALOG)
@@ -209,8 +209,8 @@ void CGUIDialogSettings::UpdateSetting(unsigned int id)
   }
   else if (setting.type == SettingInfo::EDIT)
   {
-    CGUIEditControl *pControl = (CGUIEditControl *)GetControl(controlID);
-    if (pControl && setting.data) pControl->SetLabel2(*(CStdString *)setting.data);
+    SET_CONTROL_LABEL(controlID, setting.name);
+    if (setting.data) SET_CONTROL_LABEL2(controlID, string(*(CStdString *)setting.data));
   }
   else if (setting.type == SettingInfo::EDIT_NUM)
   {
@@ -229,6 +229,17 @@ void CGUIDialogSettings::UpdateSetting(unsigned int id)
       strNewValue = "-";
     SET_CONTROL_LABEL2(controlID, strNewValue);
   }
+  else if (setting.type == SettingInfo::RANGE)
+  {
+    CGUISettingsSliderControl *pControl = (CGUISettingsSliderControl *)GetControl(controlID);
+    float** value = (float **)setting.data;
+    if (pControl && setting.data)
+    {
+      pControl->SetFloatValue(*(value[0]), CGUISliderControl::RangeSelectorLower);
+      pControl->SetFloatValue(*(value[1]), CGUISliderControl::RangeSelectorUpper);
+      if (setting.formatFunction.range) pControl->SetTextValue(setting.formatFunction.range(*(value[0]), *(value[1]), setting.interval));
+    }
+  }
 
   if (setting.enabled)
   {
@@ -300,13 +311,13 @@ void CGUIDialogSettings::OnClick(int iID)
   {
     CGUISettingsSliderControl *pControl = (CGUISettingsSliderControl *)GetControl(iID);
     if (setting.data) *(float *)setting.data = pControl->GetFloatValue();
-    if (setting.formatFunction) pControl->SetTextValue(setting.formatFunction(pControl->GetFloatValue(), setting.interval));
+    if (setting.formatFunction.standard) pControl->SetTextValue(setting.formatFunction.standard(pControl->GetFloatValue(), setting.interval));
   }
   else if (setting.type == SettingInfo::BUTTON && m_usePopupSliders && setting.data)
   { // we're using popup sliders
     CGUIDialogSlider::ShowAndGetInput(setting.name, *(float *)setting.data, setting.min, setting.interval, setting.max, this, &setting);
-    if (setting.formatFunction)
-      SET_CONTROL_LABEL2(iID, setting.formatFunction(*(float *)setting.data, setting.interval));
+    if (setting.formatFunction.standard)
+      SET_CONTROL_LABEL2(iID, setting.formatFunction.standard(*(float *)setting.data, setting.interval));
   }
   else if (setting.type == SettingInfo::STRING)
   {
@@ -316,6 +327,19 @@ void CGUIDialogSettings::OnClick(int iID)
       strNewValue = "-";
     SET_CONTROL_LABEL2(iID, strNewValue);
   }
+  else if (setting.type == SettingInfo::RANGE)
+  {
+    CGUISettingsSliderControl *pControl = (CGUISettingsSliderControl *)GetControl(iID);
+    if (setting.data)
+    {
+      *((float **)setting.data)[0] = pControl->GetFloatValue(CGUISliderControl::RangeSelectorLower);
+      *((float **)setting.data)[1] = pControl->GetFloatValue(CGUISliderControl::RangeSelectorUpper);
+    }
+    if (setting.formatFunction.range)
+      pControl->SetTextValue(setting.formatFunction.range(pControl->GetFloatValue(CGUISliderControl::RangeSelectorLower), 
+                                                          pControl->GetFloatValue(CGUISliderControl::RangeSelectorUpper),
+                                                          setting.interval));
+  }
   OnSettingChanged(setting);
 }
 
@@ -346,8 +370,8 @@ void CGUIDialogSettings::AddSetting(SettingInfo &setting, float width, int iCont
     pControl = new CGUIButtonControl(*m_pOriginalSettingsButton);
     if (!pControl) return ;
     ((CGUIButtonControl *)pControl)->SetLabel(setting.name);
-    if (setting.formatFunction)
-      ((CGUIButtonControl *)pControl)->SetLabel2(setting.formatFunction(*(float *)setting.data, setting.interval));
+    if (setting.formatFunction.standard)
+      ((CGUIButtonControl *)pControl)->SetLabel2(setting.formatFunction.standard(*(float *)setting.data, setting.interval));
     pControl->SetWidth(width);
   }
   else if (setting.type == SettingInfo::EDIT && m_pOriginalEdit)
@@ -404,14 +428,14 @@ void CGUIDialogSettings::AddSetting(SettingInfo &setting, float width, int iCont
     if (!pControl) return ;
     pControl->SetWidth(width);
     ((CGUISettingsSliderControl *)pControl)->SetText(setting.name);
-    if (setting.formatFunction)
-      ((CGUISettingsSliderControl *)pControl)->SetTextValue(setting.formatFunction(*(float *)setting.data, setting.interval));
+    if (setting.formatFunction.standard)
+      ((CGUISettingsSliderControl *)pControl)->SetTextValue(setting.formatFunction.standard(*(float *)setting.data, setting.interval));
     ((CGUISettingsSliderControl *)pControl)->SetType(SPIN_CONTROL_TYPE_FLOAT);
     ((CGUISettingsSliderControl *)pControl)->SetFloatRange(setting.min, setting.max);
     ((CGUISettingsSliderControl *)pControl)->SetFloatInterval(setting.interval);
     if (setting.data) ((CGUISettingsSliderControl *)pControl)->SetFloatValue(*(float *)setting.data);
   }
-  if (setting.type == SettingInfo::STRING && m_pOriginalSettingsButton)
+  else if (setting.type == SettingInfo::STRING && m_pOriginalSettingsButton)
   {
     pControl = new CGUIButtonControl(*m_pOriginalSettingsButton);
     if (!pControl) return ;
@@ -422,6 +446,25 @@ void CGUIDialogSettings::AddSetting(SettingInfo &setting, float width, int iCont
     ((CGUIButtonControl *)pControl)->SetLabel2(strValue);
     pControl->SetWidth(width);
   }
+  else if (setting.type == SettingInfo::RANGE)
+  {
+    if (!m_pOriginalSlider) return;
+    pControl = new CGUISettingsSliderControl(*m_pOriginalSlider);
+    if (!pControl) return ;
+    pControl->SetWidth(width);
+    ((CGUISettingsSliderControl *)pControl)->SetText(setting.name);
+    if (setting.formatFunction.range)
+      ((CGUISettingsSliderControl *)pControl)->SetTextValue(setting.formatFunction.range(*((float **)setting.data)[0], *((float **)setting.data)[1], setting.interval));
+    ((CGUISettingsSliderControl *)pControl)->SetType(SPIN_CONTROL_TYPE_FLOAT);
+    ((CGUISettingsSliderControl *)pControl)->SetRangeSelection(true);
+    ((CGUISettingsSliderControl *)pControl)->SetFloatRange(setting.min, setting.max);
+    ((CGUISettingsSliderControl *)pControl)->SetFloatInterval(setting.interval);
+    if (setting.data)
+    {
+      ((CGUISettingsSliderControl *)pControl)->SetFloatValue(*((float **)setting.data)[0], CGUISliderControl::RangeSelectorLower);
+      ((CGUISettingsSliderControl *)pControl)->SetFloatValue(*((float **)setting.data)[1], CGUISliderControl::RangeSelectorUpper);
+    }
+  }
   if (!pControl) return;
 
   pControl->SetID(iControlID);
@@ -469,7 +512,7 @@ void CGUIDialogSettings::AddButton(unsigned int id, int label, float *current, f
   setting.min = min;
   setting.max = max;
   setting.interval = interval;
-  setting.formatFunction = function;
+  setting.formatFunction.standard = function;
   m_settings.push_back(setting);
 }
 
@@ -583,7 +626,26 @@ void CGUIDialogSettings::AddSlider(unsigned int id, int label, float *current, f
   setting.interval = interval;
   setting.max = max;
   setting.data = current;
-  setting.formatFunction = function;
+  setting.formatFunction.standard = function;
+  m_settings.push_back(setting);
+}
+
+void CGUIDialogSettings::AddRangeSlider(unsigned int id, int label, float *currentLower, float* currentUpper, float min, float interval, float max, RANGEFORMATFUNCTION function)
+{
+  SettingInfo setting;
+  setting.id = id;
+  setting.name = g_localizeStrings.Get(label);
+  setting.type = SettingInfo::RANGE;
+  setting.min = min;
+  setting.interval = interval;
+  setting.max = max;
+
+  float** data = new float*[2];
+  data[0] = currentLower;
+  data[1] = currentUpper;
+  setting.data = data;
+
+  setting.formatFunction.range = function;
   m_settings.push_back(setting);
 }
 
@@ -612,8 +674,19 @@ void CGUIDialogSettings::OnSliderChange(void *data, CGUISliderControl *slider)
     return;
 
   SettingInfo *setting = (SettingInfo *)data;
-  *(float *)setting->data = slider->GetFloatValue();
-  OnSettingChanged(*setting);
-  if (setting->formatFunction)
-    slider->SetTextValue(setting->formatFunction(slider->GetFloatValue(), setting->interval));
+  if (setting->type == SettingInfo::SLIDER)
+  {
+    *(float *)setting->data = slider->GetFloatValue();
+    OnSettingChanged(*setting);
+    if (setting->formatFunction.standard)
+      slider->SetTextValue(setting->formatFunction.standard(slider->GetFloatValue(), setting->interval));
+  }
+  else if (setting->type == SettingInfo::RANGE)
+  {
+    *((float **)setting->data)[0] = slider->GetFloatValue(CGUISliderControl::RangeSelectorLower);
+    *((float **)setting->data)[1] = slider->GetFloatValue(CGUISliderControl::RangeSelectorUpper);
+    OnSettingChanged(*setting);
+    if (setting->formatFunction.range)
+      slider->SetTextValue(setting->formatFunction.range(slider->GetFloatValue(CGUISliderControl::RangeSelectorLower), slider->GetFloatValue(CGUISliderControl::RangeSelectorUpper), setting->interval));
+  }
 }
index dc6400f..4d89f51 100644 (file)
@@ -29,14 +29,16 @@ class CGUIRadioButtonControl;
 class CGUISettingsSliderControl;
 class CGUIEditControl;
 class CGUIImage;
+class CGUIEditControl;
 
 typedef std::vector<CStdString> SETTINGSTRINGS;
 typedef CStdString (*FORMATFUNCTION) (float value, float min);
+typedef CStdString (*RANGEFORMATFUNCTION) (float valueLower, float valueUpper, float min);
 
 class SettingInfo
 {
 public:
-  enum SETTING_TYPE { NONE=0, EDIT, EDIT_NUM, BUTTON, BUTTON_DIALOG, CHECK, CHECK_UCHAR, SPIN, SLIDER, SEPARATOR, STRING };
+  enum SETTING_TYPE { NONE=0, EDIT, EDIT_NUM, BUTTON, BUTTON_DIALOG, CHECK, CHECK_UCHAR, SPIN, SLIDER, SEPARATOR, STRING, RANGE };
   SettingInfo()
   {
     id = 0;
@@ -46,7 +48,7 @@ public:
     min = 0;
     max = 0;
     interval = 0;
-    formatFunction = NULL;
+    formatFunction.standard = NULL;
   };
   SETTING_TYPE type;
   CStdString name;
@@ -55,7 +57,11 @@ public:
   float min;
   float max;
   float interval;
-  FORMATFUNCTION formatFunction;
+  union
+  {
+    FORMATFUNCTION standard;
+    RANGEFORMATFUNCTION range;
+  } formatFunction;
   std::vector<std::pair<int, CStdString> > entry;
   bool enabled;
 };
@@ -96,6 +102,7 @@ protected:
   void AddSpin(unsigned int id, int label, int *current, std::vector<std::pair<int, CStdString> > &values);
   void AddSpin(unsigned int id, int label, int *current, std::vector<std::pair<int, int> > &values);
   void AddSlider(unsigned int id, int label, float *current, float min, float interval, float max, FORMATFUNCTION formatFunction, bool allowPopup = true);
+  void AddRangeSlider(unsigned int id, int label, float *currentLower, float* currentUpper, float min, float interval, float max, RANGEFORMATFUNCTION formatFunction);
   void AddSeparator(unsigned int id);
 
   CGUIEditControl *m_pOriginalEdit;
index 6f919ae..44af36f 100644 (file)
@@ -829,6 +829,7 @@ void CGUISettings::Initialize()
 
   CSettingsCategory* srvUpnp = AddCategory(SETTINGS_SERVICE, "upnp", 20187);
   AddBool(srvUpnp, "services.upnpserver", 21360, false);
+  AddBool(srvUpnp, "services.upnpannounce", 20188, true);
   AddBool(srvUpnp, "services.upnprenderer", 21881, false);
 
 #ifdef HAS_WEB_SERVER
@@ -996,7 +997,7 @@ void CGUISettings::Initialize()
   AddBool(pvrpwr, "pvrpowermanagement.enabled", 305, false);
   AddSeparator(pvrpwr, "pvrpowermanagement.sep1");
   AddInt(pvrpwr, "pvrpowermanagement.backendidletime", 19244, 15, 0, 5, 360, SPIN_CONTROL_INT_PLUS, MASK_MINS, TEXT_OFF);
-  AddString(pvrpwr, "pvrpowermanagement.setwakeupcmd", 19245, "/usr/bin/setwakeup.sh", EDIT_CONTROL_INPUT, true);
+  AddString(pvrpwr, "pvrpowermanagement.setwakeupcmd", 19245, "", EDIT_CONTROL_INPUT, true);
   AddInt(pvrpwr, "pvrpowermanagement.prewakeup", 19246, 15, 0, 1, 60, SPIN_CONTROL_INT_PLUS, MASK_MINS, TEXT_OFF);
   AddSeparator(pvrpwr, "pvrpowermanagement.sep2");
   AddBool(pvrpwr, "pvrpowermanagement.dailywakeup", 19247, false);
index c5f2f7a..5ce74c6 100644 (file)
@@ -718,7 +718,7 @@ void CGUIWindowSettingsCategory::UpdateSettings()
     else if (strSetting.Equals("pvrmanager.channelscan"))
     {
       CGUIControl *pControl = (CGUIControl *)GetControl(pSettingControl->GetID());
-      if (pControl) pControl->SetEnabled(g_guiSettings.GetBool("pvrmanager.enabled") && g_PVRClients->GetClientsSupportingChannelScan().size() > 0);
+      if (pControl) pControl->SetEnabled(g_guiSettings.GetBool("pvrmanager.enabled") && g_PVRClients && g_PVRClients->GetClientsSupportingChannelScan().size() > 0);
     }
     else if (strSetting.Equals("pvrmanager.channelmanager") || strSetting.Equals("pvrmenu.searchicons"))
     {
@@ -737,6 +737,11 @@ void CGUIWindowSettingsCategory::UpdateSettings()
       CGUIControl *pControl = (CGUIControl *)GetControl(pSettingControl->GetID());
       if (pControl) pControl->SetEnabled(g_guiSettings.GetBool("services.esenabled"));
     }
+    else if (strSetting.Equals("services.upnpannounce"))
+    {
+      CGUIControl *pControl = (CGUIControl *)GetControl(pSettingControl->GetID());
+      pControl->SetEnabled(g_guiSettings.GetBool("services.upnpserver"));
+    }
     else if (strSetting.Equals("audiocds.quality"))
     { // only visible if we are doing non-WAV ripping
       CGUIControl *pControl = (CGUIControl *)GetControl(pSettingControl->GetID());
@@ -1900,7 +1905,8 @@ void CGUIWindowSettingsCategory::OnSettingChanged(CBaseSettingControl *pSettingC
     g_windowManager.SendMessage(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_WINDOW_RESIZE);
   }
   else if (strSetting.Equals("videolibrary.flattentvshows") ||
-           strSetting.Equals("videolibrary.removeduplicates"))
+           strSetting.Equals("videolibrary.removeduplicates") ||
+           strSetting.Equals("videolibrary.groupmoviesets"))
   {
     CUtil::DeleteVideoDatabaseDirectoryCache();
   }
index 85bb96e..9d4929b 100644 (file)
@@ -183,7 +183,7 @@ void CGUIWindowSettingsProfile::LoadList()
     const CProfile *profile = g_settings.GetProfile(i);
     CFileItemPtr item(new CFileItem(profile->getName()));
     item->SetLabel2(profile->getDate());
-    item->SetThumbnailImage(profile->getThumb());
+    item->SetArt("thumb", profile->getThumb());
     item->SetOverlayImage(profile->getLockMode() == LOCK_MODE_EVERYONE ? CGUIListItem::ICON_OVERLAY_NONE : CGUIListItem::ICON_OVERLAY_LOCKED);
     m_listItems->Add(item);
   }
index 79722aa..b04e7f9 100644 (file)
@@ -124,8 +124,6 @@ void CSettings::Initialize()
   m_watchMode["musicvideos"] = VIDEO_SHOW_ALL;
 
   m_iSystemTimeTotalUp = 0;
-  m_HttpApiBroadcastLevel = 0;
-  m_HttpApiBroadcastPort = 8278;
 
   m_userAgent = g_sysinfo.GetUserAgent();
 
@@ -723,8 +721,6 @@ bool CSettings::LoadSettings(const CStdString& strSettingsFile)
   if (pElement)
   {
     GetInteger(pElement, "systemtotaluptime", m_iSystemTimeTotalUp, 0, 0, INT_MAX);
-    GetInteger(pElement, "httpapibroadcastlevel", m_HttpApiBroadcastLevel, 0, 0, 255);
-    GetInteger(pElement, "httpapibroadcastport", m_HttpApiBroadcastPort, 8278, 1, 65535);
     XMLUtils::GetBoolean(pElement, "addonautoupdate", m_bAddonAutoUpdate);
     XMLUtils::GetBoolean(pElement, "addonnotifications", m_bAddonNotifications);
     XMLUtils::GetBoolean(pElement, "addonforeignfilter", m_bAddonForeignFilter);
@@ -920,8 +916,6 @@ bool CSettings::SaveSettings(const CStdString& strSettingsFile, CGUISettings *lo
   pNode = pRoot->InsertEndChild(generalNode);
   if (!pNode) return false;
   XMLUtils::SetInt(pNode, "systemtotaluptime", m_iSystemTimeTotalUp);
-  XMLUtils::SetInt(pNode, "httpapibroadcastport", m_HttpApiBroadcastPort);
-  XMLUtils::SetInt(pNode, "httpapibroadcastlevel", m_HttpApiBroadcastLevel);
   XMLUtils::SetBoolean(pNode, "addonautoupdate", m_bAddonAutoUpdate);
   XMLUtils::SetBoolean(pNode, "addonnotifications", m_bAddonNotifications);
   XMLUtils::SetBoolean(pNode, "addonforeignfilter", m_bAddonForeignFilter);
index d8cb30b..fdaa4cd 100644 (file)
@@ -211,8 +211,6 @@ public:
 
   int iAdditionalSubtitleDirectoryChecked;
 
-  int m_HttpApiBroadcastPort;
-  int m_HttpApiBroadcastLevel;
   float m_fVolumeLevel;        // float 0.0 - 1.0 range
   bool m_bMute;
   int m_iSystemTimeTotalUp;    // Uptime in minutes!
index 0f34d45..4165c01 100644 (file)
@@ -45,7 +45,6 @@
 #endif
 
 #define HAS_JSONRPC
-#define HAS_HTTPAPI
 
 #ifdef USE_ASAP_CODEC
 #define HAS_ASAP_CODEC
index 76541e9..7b485f6 100644 (file)
@@ -1,5 +1,6 @@
 SRCS=  \
        TestBasicEnvironment.cpp \
+       TestFileItem.cpp \
        TestUtils.cpp \
        xbmc-test.cpp
 
diff --git a/xbmc/test/TestFileItem.cpp b/xbmc/test/TestFileItem.cpp
new file mode 100644 (file)
index 0000000..03c1d8a
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ *      Copyright (C) 2005-2012 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "FileItem.h"
+#include "URL.h"
+#include "settings/AdvancedSettings.h"
+
+#include "gtest/gtest.h"
+
+TEST(TestFileItem, GetLocalArt)
+{
+  typedef struct
+  {
+    const char *file;
+    bool use_folder;
+    const char *base;
+  } testfiles;
+
+  const testfiles test_files[] = {{ "c:\\dir\\filename.avi", false, "c:\\dir\\filename-art.jpg" },
+                                  { "c:\\dir\\filename.avi", true,  "c:\\dir\\art.jpg" },
+                                  { "/dir/filename.avi", false, "/dir/filename-art.jpg" },
+                                  { "/dir/filename.avi", true,  "/dir/art.jpg" },
+                                  { "smb://somepath/file.avi", false, "smb://somepath/file-art.jpg" },
+                                  { "smb://somepath/file.avi", true, "smb://somepath/art.jpg" },
+                                  { "stack:///path/to/movie-cd1.avi , /path/to/movie-cd2.avi", false,  "/path/to/movie-art.jpg" },
+                                  { "stack:///path/to/movie-cd1.avi , /path/to/movie-cd2.avi", true,  "/path/to/art.jpg" },
+                                  { "stack:///path/to/movie_name/cd1/some_file1.avi , /path/to/movie_name/cd2/some_file2.avi", true,  "/path/to/movie_name/art.jpg" },
+                                  { "/home/user/TV Shows/Dexter/S1/1x01.avi", false, "/home/user/TV Shows/Dexter/S1/1x01-art.jpg" },
+                                  { "/home/user/TV Shows/Dexter/S1/1x01.avi", true, "/home/user/TV Shows/Dexter/S1/art.jpg" },
+                                  { "rar://g%3a%5cmultimedia%5cmovies%5cSphere%2erar/Sphere.avi", false, "g:\\multimedia\\movies\\Sphere-art.jpg" },
+                                  { "rar://g%3a%5cmultimedia%5cmovies%5cSphere%2erar/Sphere.avi", true, "g:\\multimedia\\movies\\art.jpg" },
+                                  { "/home/user/movies/movie_name/video_ts/VIDEO_TS.IFO", false, "/home/user/movies/movie_name/art.jpg" },
+                                  { "/home/user/movies/movie_name/video_ts/VIDEO_TS.IFO", true, "/home/user/movies/movie_name/art.jpg" },
+                                  { "/home/user/movies/movie_name/BDMV/index.bdmv", false, "/home/user/movies/movie_name/art.jpg" },
+                                  { "/home/user/movies/movie_name/BDMV/index.bdmv", true, "/home/user/movies/movie_name/art.jpg" }};
+
+  const testfiles test_file2[] = {{ "c:\\dir\\filename.avi", false, "c:\\dir\\filename.tbn" },
+                                  { "/dir/filename.avi", false, "/dir/filename.tbn" },
+                                  { "smb://somepath/file.avi", false, "smb://somepath/file.tbn" },
+                                  { "/home/user/TV Shows/Dexter/S1/1x01.avi", false, "/home/user/TV Shows/Dexter/S1/1x01.tbn" },
+                                  { "rar://g%3a%5cmultimedia%5cmovies%5cSphere%2erar/Sphere.avi", false, "g:\\multimedia\\movies\\Sphere.tbn" }};
+
+  g_advancedSettings.Initialize();
+
+  for (unsigned int i = 0; i < sizeof(test_files) / sizeof(testfiles); i++)
+  {
+    CFileItem item;
+    item.SetPath(test_files[i].file);
+    std::string path = CURL(item.GetLocalArt("art.jpg", test_files[i].use_folder)).Get();
+    std::string compare = CURL(test_files[i].base).Get();
+    EXPECT_EQ(path, compare);
+  }
+
+  for (unsigned int i = 0; i < sizeof(test_file2) / sizeof(testfiles); i++)
+  {
+    CFileItem item;
+    item.SetPath(test_file2[i].file);
+    std::string path = CURL(item.GetLocalArt("", test_file2[i].use_folder)).Get();
+    std::string compare = CURL(test_file2[i].base).Get();
+    EXPECT_EQ(path, compare);
+  }
+}
+
+TEST(TestFileItem, GetBaseMoviePath)
+{
+  typedef struct
+  {
+    const char *file;
+    bool use_folder;
+    const char *base;
+  } testfiles;
+
+  const testfiles test_files[] = {{ "c:\\dir\\filename.avi", false, "c:\\dir\\filename.avi" },
+                                  { "c:\\dir\\filename.avi", true,  "c:\\dir\\" },
+                                  { "/dir/filename.avi", false, "/dir/filename.avi" },
+                                  { "/dir/filename.avi", true,  "/dir/" },
+                                  { "smb://somepath/file.avi", false, "smb://somepath/file.avi" },
+                                  { "smb://somepath/file.avi", true, "smb://somepath/" },
+                                  { "stack:///path/to/movie_name/cd1/some_file1.avi , /path/to/movie_name/cd2/some_file2.avi", false, "stack:///path/to/movie_name/cd1/some_file1.avi , /path/to/movie_name/cd2/some_file2.avi" },
+                                  { "stack:///path/to/movie_name/cd1/some_file1.avi , /path/to/movie_name/cd2/some_file2.avi", true,  "/path/to/movie_name/" },
+                                  { "/home/user/TV Shows/Dexter/S1/1x01.avi", false, "/home/user/TV Shows/Dexter/S1/1x01.avi" },
+                                  { "/home/user/TV Shows/Dexter/S1/1x01.avi", true, "/home/user/TV Shows/Dexter/S1/" },
+                                  { "rar://g%3a%5cmultimedia%5cmovies%5cSphere%2erar/Sphere.avi", true, "g:\\multimedia\\movies\\" },
+                                  { "/home/user/movies/movie_name/video_ts/VIDEO_TS.IFO", false, "/home/user/movies/movie_name/" },
+                                  { "/home/user/movies/movie_name/video_ts/VIDEO_TS.IFO", true, "/home/user/movies/movie_name/" },
+                                  { "/home/user/movies/movie_name/BDMV/index.bdmv", false, "/home/user/movies/movie_name/" },
+                                  { "/home/user/movies/movie_name/BDMV/index.bdmv", true, "/home/user/movies/movie_name/" }};
+
+  for (unsigned int i = 0; i < sizeof(test_files) / sizeof(testfiles); i++)
+  {
+    CFileItem item;
+    item.SetPath(test_files[i].file);
+    std::string path = CURL(item.GetBaseMoviePath(test_files[i].use_folder)).Get();
+    std::string compare = CURL(test_files[i].base).Get();
+    EXPECT_EQ(path, compare);
+  }
+}
index c0d0fcf..4feaf04 100644 (file)
@@ -155,6 +155,30 @@ CArchive& CArchive::operator<<(char c)
   return *this;
 }
 
+CArchive& CArchive::operator<<(const std::string& str)
+{
+  *this << (int)str.size();
+
+  int size = str.size();
+  if (m_BufferPos + size >= BUFFER_MAX)
+    FlushBuffer();
+
+  int iBufferMaxParts=size/BUFFER_MAX;
+  for (int i=0; i<iBufferMaxParts; i++)
+  {
+    memcpy(&m_pBuffer[m_BufferPos], str.c_str()+(i*BUFFER_MAX), BUFFER_MAX);
+    m_BufferPos+=BUFFER_MAX;
+    FlushBuffer();
+  }
+
+  int iPos=iBufferMaxParts*BUFFER_MAX;
+  int iSizeLeft=size-iPos;
+  memcpy(&m_pBuffer[m_BufferPos], str.c_str()+iPos, iSizeLeft);
+  m_BufferPos+=iSizeLeft;
+
+  return *this;
+}
+
 CArchive& CArchive::operator<<(const CStdString& str)
 {
   *this << str.GetLength();
@@ -237,7 +261,7 @@ CArchive& CArchive::operator<<(const CVariant& variant)
     *this << variant.asBoolean();
     break;
   case CVariant::VariantTypeString:
-    *this << CStdString(variant.asString());
+    *this << variant.asString();
     break;
   case CVariant::VariantTypeDouble:
     *this << variant.asDouble();
@@ -251,7 +275,7 @@ CArchive& CArchive::operator<<(const CVariant& variant)
     *this << variant.size();
     for (CVariant::const_iterator_map itr = variant.begin_map(); itr != variant.end_map(); itr++)
     {
-      *this << CStdString(itr->first);
+      *this << itr->first;
       *this << itr->second;
     }
     break;
@@ -268,7 +292,7 @@ CArchive& CArchive::operator<<(const std::vector<std::string>& strArray)
 {
   *this << (unsigned int)strArray.size();
   for (unsigned int index = 0; index < strArray.size(); index++)
-    *this << CStdString(strArray.at(index));
+    *this << strArray.at(index);
 
   return *this;
 }
@@ -338,6 +362,19 @@ CArchive& CArchive::operator>>(char& c)
   return *this;
 }
 
+CArchive& CArchive::operator>>(std::string& str)
+{
+  int iLength = 0;
+  *this >> iLength;
+
+  char *s = new char[iLength];
+  m_pFile->Read(s, iLength);
+  str.assign(s, iLength);
+  delete[] s;
+
+  return *this;
+}
+
 CArchive& CArchive::operator>>(CStdString& str)
 {
   int iLength = 0;
@@ -407,7 +444,7 @@ CArchive& CArchive::operator>>(CVariant& variant)
   }
   case CVariant::VariantTypeString:
   {
-    CStdString value;
+    std::string value;
     *this >> value;
     variant = value;
     break;
@@ -437,7 +474,7 @@ CArchive& CArchive::operator>>(CVariant& variant)
     *this >> size;
     for (; size > 0; size--)
     {
-      CStdString name;
+      std::string name;
       CVariant value;
       *this >> name;
       *this >> value;
@@ -461,7 +498,7 @@ CArchive& CArchive::operator>>(std::vector<std::string>& strArray)
   strArray.clear();
   for (int index = 0; index < size; index++)
   {
-    CStdString str;
+    std::string str;
     *this >> str;
     strArray.push_back(str);
   }
index 4c69b99..a783625 100644 (file)
@@ -52,6 +52,7 @@ public:
   CArchive& operator<<(uint64_t ui64);
   CArchive& operator<<(bool b);
   CArchive& operator<<(char c);
+  CArchive& operator<<(const std::string &str);
   CArchive& operator<<(const CStdString& str);
   CArchive& operator<<(const CStdStringW& str);
   CArchive& operator<<(const SYSTEMTIME& time);
@@ -69,6 +70,7 @@ public:
   CArchive& operator>>(uint64_t& ui64);
   CArchive& operator>>(bool& b);
   CArchive& operator>>(char& c);
+  CArchive& operator>>(std::string &str);
   CArchive& operator>>(CStdString& str);
   CArchive& operator>>(CStdStringW& str);
   CArchive& operator>>(SYSTEMTIME& time);
index 1e31d66..a0009f3 100644 (file)
@@ -252,6 +252,7 @@ std::string DatabaseUtils::GetField(Field field, MediaType mediaType, DatabaseQu
     else if (field == FieldDirector) result.Format("episodeview.c%02d", VIDEODB_ID_EPISODE_DIRECTOR);
     else if (field == FieldSeason) result.Format("episodeview.c%02d", VIDEODB_ID_EPISODE_SEASON);
     else if (field == FieldEpisodeNumber) result.Format("episodeview.c%02d", VIDEODB_ID_EPISODE_EPISODE);
+    else if (field == FieldUniqueId) result.Format("episodeview.c%02d", VIDEODB_ID_EPISODE_UNIQUEID);
     else if (field == FieldEpisodeNumberSpecialSort) result.Format("episodeview.c%02d", VIDEODB_ID_EPISODE_SORTEPISODE);
     else if (field == FieldSeasonSpecialSort) result.Format("episodeview.c%02d", VIDEODB_ID_EPISODE_SORTSEASON);
     else if (field == FieldFilename) return "episodeview.strFilename";
@@ -430,6 +431,7 @@ int DatabaseUtils::GetFieldIndex(Field field, MediaType mediaType)
     else if (field == FieldDirector) index = VIDEODB_ID_EPISODE_DIRECTOR;
     else if (field == FieldSeason) index = VIDEODB_ID_EPISODE_SEASON;
     else if (field == FieldEpisodeNumber) index = VIDEODB_ID_EPISODE_EPISODE;
+    else if (field == FieldUniqueId) index = VIDEODB_ID_EPISODE_UNIQUEID;
     else if (field == FieldEpisodeNumberSpecialSort) index = VIDEODB_ID_EPISODE_SORTEPISODE;
     else if (field == FieldSeasonSpecialSort) index = VIDEODB_ID_EPISODE_SORTSEASON;
     else if (field == FieldFilename) return VIDEODB_DETAILS_EPISODE_FILE;
index 4f40277..6c0c2e9 100644 (file)
@@ -92,6 +92,7 @@ typedef enum {
   FieldWriter,
   FieldAirDate,
   FieldEpisodeNumber,
+  FieldUniqueId,
   FieldSeason,
   FieldEpisodeNumberSpecialSort,
   FieldSeasonSpecialSort,
index 9d6645e..cbbcd05 100644 (file)
@@ -255,7 +255,7 @@ bool CFileOperationJob::CFileOperation::ExecuteOperation(CFileOperationJob *base
   if (base->m_handle)
   {
     base->m_handle->SetText(base->GetCurrentFile());
-    base->m_handle->SetPercentage(current);
+    base->m_handle->SetPercentage((float)current);
   }
 
   DataHolder data = {base, current, opWeight};
@@ -343,7 +343,7 @@ bool CFileOperationJob::CFileOperation::OnFileCallback(void* pContext, int iperc
     line.Format("%s (%s)", data->base->GetCurrentFile().c_str(),
                            data->base->GetAverageSpeed().c_str());
     data->base->m_handle->SetText(line);
-    data->base->m_handle->SetPercentage(current);
+    data->base->m_handle->SetPercentage((float)current);
   }
 
   return !data->base->ShouldCancel((unsigned)current, 100);
index edcf6b9..07ed917 100644 (file)
@@ -73,11 +73,11 @@ bool CRecentlyAddedJob::UpdateVideo()
       home->SetProperty("LatestMovie." + value + ".Path"        , item->GetVideoInfoTag()->m_strFileNameAndPath);
       home->SetProperty("LatestMovie." + value + ".Trailer"     , item->GetVideoInfoTag()->m_strTrailer);
 
-      if (!item->HasThumbnail())
+      if (!item->HasArt("thumb"))
         m_thumbLoader.LoadItem(item.get());
 
-      home->SetProperty("LatestMovie." + value + ".Thumb"       , item->GetThumbnailImage());
-      home->SetProperty("LatestMovie." + value + ".Fanart"      , item->GetProperty("fanart_image"));
+      home->SetProperty("LatestMovie." + value + ".Thumb"       , item->GetArt("thumb"));
+      home->SetProperty("LatestMovie." + value + ".Fanart"      , item->GetArt("fanart"));
     }
   } 
   for (; i < NUM_ITEMS; ++i)
@@ -123,17 +123,17 @@ bool CRecentlyAddedJob::UpdateVideo()
       home->SetProperty("LatestEpisode." + value + ".EpisodeNumber" , EpisodeNumber);
       home->SetProperty("LatestEpisode." + value + ".Path"          , item->GetVideoInfoTag()->m_strFileNameAndPath);
 
-      if (!item->HasThumbnail())
+      if (!item->HasArt("thumb"))
         m_thumbLoader.LoadItem(item.get());
 
       std::string seasonThumb;
       if (item->GetVideoInfoTag()->m_iIdSeason > 0)
         seasonThumb = videodatabase.GetArtForItem(item->GetVideoInfoTag()->m_iIdSeason, "season", "thumb");
 
-      home->SetProperty("LatestEpisode." + value + ".Thumb"         , item->GetThumbnailImage());
-      home->SetProperty("LatestEpisode." + value + ".ShowThumb"     , item->GetProperty("tvshowthumb"));
+      home->SetProperty("LatestEpisode." + value + ".Thumb"         , item->GetArt("thumb"));
+      home->SetProperty("LatestEpisode." + value + ".ShowThumb"     , item->GetArt("tvshowthumb"));
       home->SetProperty("LatestEpisode." + value + ".SeasonThumb"   , seasonThumb);
-      home->SetProperty("LatestEpisode." + value + ".Fanart"        , item->GetProperty("fanart_image"));
+      home->SetProperty("LatestEpisode." + value + ".Fanart"        , item->GetArt("fanart"));
     }
   } 
   for (; i < NUM_ITEMS; ++i)
@@ -172,11 +172,11 @@ bool CRecentlyAddedJob::UpdateVideo()
       home->SetProperty("LatestMusicVideo." + value + ".Path"        , item->GetVideoInfoTag()->m_strFileNameAndPath);
       home->SetProperty("LatestMusicVideo." + value + ".Artist"      , StringUtils::Join(item->GetVideoInfoTag()->m_artist, g_advancedSettings.m_videoItemSeparator));
 
-      if (!item->HasThumbnail())
+      if (!item->HasArt("thumb"))
         m_thumbLoader.LoadItem(item.get());
 
-      home->SetProperty("LatestMusicVideo." + value + ".Thumb"       , item->GetThumbnailImage());
-      home->SetProperty("LatestMusicVideo." + value + ".Fanart"      , item->GetProperty("fanart_image"));
+      home->SetProperty("LatestMusicVideo." + value + ".Thumb"       , item->GetArt("thumb"));
+      home->SetProperty("LatestMusicVideo." + value + ".Fanart"      , item->GetArt("fanart"));
     }
   }
   for (; i < NUM_ITEMS; ++i)
@@ -236,8 +236,8 @@ bool CRecentlyAddedJob::UpdateMusic()
 
         if (loader.LoadItem(item.get()))
         {
-          strAlbumThumb = item->GetThumbnailImage();
-          strAlbumFanart = item->GetProperty("fanart_image").asString();
+          strAlbumThumb = item->GetArt("thumb");
+          strAlbumFanart = item->GetArt("fanart");
         }
       }
 
index 58be860..f1b55cf 100644 (file)
@@ -107,6 +107,9 @@ bool CScraperUrl::ParseElement(const TiXmlElement* element)
     if (szSeason)
       url.m_season = atoi(szSeason);
   }
+  const char *aspect = element->Attribute("aspect");
+  if (aspect)
+    url.m_aspect = aspect;
 
   m_url.push_back(url);
 
@@ -149,11 +152,11 @@ bool CScraperUrl::ParseString(CStdString strUrl)
   return true;
 }
 
-const CScraperUrl::SUrlEntry CScraperUrl::GetFirstThumb() const
+const CScraperUrl::SUrlEntry CScraperUrl::GetFirstThumb(const std::string &type) const
 {
   for (vector<SUrlEntry>::const_iterator iter=m_url.begin();iter != m_url.end();++iter)
   {
-    if (iter->m_type == URL_TYPE_GENERAL)
+    if (iter->m_type == URL_TYPE_GENERAL && (type.empty() || type == "thumb" || iter->m_aspect == type))
       return *iter;
   }
 
@@ -303,14 +306,17 @@ CStdString CScraperUrl::GetThumbURL(const CScraperUrl::SUrlEntry &entry)
   return entry.m_url + "|Referer=" + spoof;
 }
 
-void CScraperUrl::GetThumbURLs(std::vector<CStdString> &thumbs, int season) const
+void CScraperUrl::GetThumbURLs(std::vector<CStdString> &thumbs, const std::string &type, int season) const
 {
   for (vector<SUrlEntry>::const_iterator iter = m_url.begin(); iter != m_url.end(); ++iter)
   {
-    if ((iter->m_type == CScraperUrl::URL_TYPE_GENERAL && season == -1)
-     || (iter->m_type == CScraperUrl::URL_TYPE_SEASON && iter->m_season == season))
+    if (iter->m_aspect == type || type.empty() || type == "thumb")
     {
-      thumbs.push_back(GetThumbURL(*iter));
+      if ((iter->m_type == CScraperUrl::URL_TYPE_GENERAL && season == -1)
+       || (iter->m_type == CScraperUrl::URL_TYPE_SEASON && iter->m_season == season))
+      {
+        thumbs.push_back(GetThumbURL(*iter));
+      }
     }
   }
 }
index 0b417e1..e414f89 100644 (file)
@@ -47,6 +47,7 @@ public:
     CStdString m_spoof;
     CStdString m_url;
     CStdString m_cache;
+    std::string m_aspect;
     URLTYPES m_type;
     bool m_post;
     bool m_isgz;
@@ -58,8 +59,8 @@ public:
   bool ParseElement(const TiXmlElement*);
   bool ParseEpisodeGuide(CStdString strUrls); // copies by intention
 
-  const SUrlEntry GetFirstThumb() const;
-  const SUrlEntry GetSeasonThumb(int) const;
+  const SUrlEntry GetFirstThumb(const std::string &type = "") const;
+  const SUrlEntry GetSeasonThumb(int season) const;
   void GetSeasonThumbs(std::map<int, std::string> &thumbs) const;
 
   /*! \brief fetch the full URL (including referrer) of a thumb
@@ -70,9 +71,10 @@ public:
 
   /*! \brief fetch the full URL (including referrer) of thumbs
    \param thumbs [out] vector of thumb URLs to fill
+   \param type the type of thumb URLs to fetch, if empty (the default) picks any
    \param season number of season that we want thumbs for, -1 indicates no season (the default)
    */
-  void GetThumbURLs(std::vector<CStdString> &thumbs, int season = -1) const;
+  void GetThumbURLs(std::vector<CStdString> &thumbs, const std::string &type = "", int season = -1) const;
   void Clear();
   static bool Get(const SUrlEntry&, std::string&, XFILE::CCurlFile& http,
                  const CStdString& cacheContext);
index 9669344..f0bf920 100644 (file)
@@ -269,7 +269,7 @@ int StringUtils::SplitString(const CStdString& input, const CStdString& delimite
     newPos = input.Find (delimiter, iPos + sizeS2);
   }
 
-  // numFound is the number of delimeters which is one less
+  // numFound is the number of delimiters which is one less
   // than the number of substrings
   unsigned int numFound = positions.size();
   if (iMaxStrings > 0 && numFound >= iMaxStrings)
@@ -322,7 +322,7 @@ vector<string> StringUtils::Split(const CStdString& input, const CStdString& del
   return strArray;
 }
 
-// returns the number of occurences of strFind in strInput.
+// returns the number of occurrences of strFind in strInput.
 int StringUtils::FindNumber(const CStdString& strInput, const CStdString &strFind)
 {
   int pos = strInput.Find(strFind, 0);
@@ -417,17 +417,20 @@ int StringUtils::DateStringToYYYYMMDD(const CStdString &dateString)
 
 long StringUtils::TimeStringToSeconds(const CStdString &timeString)
 {
-  if(timeString.Right(4).Equals(" min"))
+  CStdString strCopy(timeString);
+  strCopy.TrimLeft(" \n\r\t");
+  strCopy.TrimRight(" \n\r\t");
+  if(strCopy.Right(4).Equals(" min"))
   {
     // this is imdb format of "XXX min"
-    return 60 * atoi(timeString.c_str());
+    return 60 * atoi(strCopy.c_str());
   }
   else
   {
     CStdStringArray secs;
-    StringUtils::SplitString(timeString, ":", secs);
+    StringUtils::SplitString(strCopy, ":", secs);
     int timeInSecs = 0;
-    for (unsigned int i = 0; i < secs.size(); i++)
+    for (unsigned int i = 0; i < 3 && i < secs.size(); i++)
     {
       timeInSecs *= 60;
       timeInSecs += atoi(secs[i]);
@@ -704,8 +707,8 @@ size_t StringUtils::utf8_strlen(const char *s)
   size_t length = 0;
   while (*s)
   {
-               if ((*s++ & 0xC0) != 0x80)
-                       length++;
-       }
-       return length;
+    if ((*s++ & 0xC0) != 0x80)
+      length++;
+  }
+  return length;
 }
index 79ff648..c067655 100644 (file)
@@ -138,7 +138,7 @@ bool CTuxBoxUtil::CreateNewItem(const CFileItem& item, CFileItem& item_new)
   //Build new Item
   item_new.SetLabel(item.GetLabel());
   item_new.SetPath(item.GetPath());
-  item_new.SetThumbnailImage(item.GetThumbnailImage());
+  item_new.SetArt("thumb", item.GetArt("thumb"));
 
   if(g_tuxbox.GetZapUrl(item.GetPath(), item_new))
   {
@@ -320,7 +320,7 @@ bool CTuxBoxUtil::ParseChannels(TiXmlElement *root, CFileItemList &items, CURL &
                     pbItem->SetLabel(strItemName);
                     pbItem->SetLabelPreformated(true);
                     pbItem->SetPath("tuxbox://"+url.GetUserName()+":"+url.GetPassWord()+"@"+url.GetHostName()+strPort+"/cgi-bin/zapTo?path="+strItemPath+".ts");
-                    pbItem->SetThumbnailImage(GetPicon(strItemName)); //Set Picon Image
+                    pbItem->SetArt("thumb", GetPicon(strItemName)); //Set Picon Image
 
                     //DEBUG Log
                     CLog::Log(LOGDEBUG, "%s - Name:    %s", __FUNCTION__,strItemName.c_str());
index 8bcd48d..706c237 100644 (file)
@@ -267,6 +267,22 @@ bool URIUtils::GetParentPath(const CStdString& strPath, CStdString& strParent)
     strFile = url.GetHostName();
     return GetParentPath(strFile, strParent);
   }
+  else if ((url.GetProtocol() == "videodb" || url.GetProtocol() == "musicdb") && !url.GetOptions().empty())
+  {
+    CStdString options = url.GetOptions();
+    size_t filterStart = options.find("filter=");
+    if (filterStart != string::npos)
+    {
+      size_t filterEnd = options.find("&", filterStart);
+      options.erase(filterStart, filterEnd - filterStart);
+      if (options.Equals("?"))
+        options.clear();
+
+      url.SetOptions(options);
+      strParent = url.Get();
+      return true;
+    }
+  }
   else if (url.GetProtocol() == "stack")
   {
     CStackDirectory dir;
@@ -938,6 +954,13 @@ void URIUtils::AddFileToFolder(const CStdString& strFolder,
     strResult.Replace('/', '\\');
 }
 
+CStdString URIUtils::GetDirectory(const CStdString &filePath)
+{
+  CStdString directory;
+  GetDirectory(filePath, directory);
+  return directory;
+}
+
 void URIUtils::GetDirectory(const CStdString& strFilePath,
                             CStdString& strDirectoryPath)
 {
index 75a2f6a..56b43d6 100644 (file)
@@ -34,6 +34,8 @@ public:
 
   static void GetDirectory(const CStdString& strFilePath,
                            CStdString& strDirectoryPath);
+  static CStdString GetDirectory(const CStdString &filePath);
+
   static const CStdString GetExtension(const CStdString& strFileName);
   static void GetExtension(const CStdString& strFile, CStdString& strExtension);
   static const CStdString GetFileName(const CStdString& strFileNameAndPath);
index c189a08..f383fa3 100644 (file)
@@ -28,6 +28,11 @@ using namespace std;
 CUrlOptions::CUrlOptions()
 { }
 
+CUrlOptions::CUrlOptions(const std::string &options)
+{
+  AddOptions(options);
+}
+
 CUrlOptions::~CUrlOptions()
 { }
 
@@ -45,6 +50,14 @@ std::string CUrlOptions::GetOptionsString() const
   return options;
 }
 
+void CUrlOptions::AddOption(const std::string &key, const char *value)
+{
+  if (key.empty() || value == NULL)
+    return;
+
+  return AddOption(key, string(value));
+}
+
 void CUrlOptions::AddOption(const std::string &key, const std::string &value)
 {
   if (key.empty())
@@ -120,3 +133,29 @@ void CUrlOptions::AddOptions(const std::string &options)
       AddOption(key, value);
   }
 }
+
+void CUrlOptions::AddOptions(const CUrlOptions &options)
+{
+  m_options.insert(options.m_options.begin(), options.m_options.end());
+}
+
+bool CUrlOptions::HasOption(const std::string &key)
+{
+  if (key.empty())
+    return false;
+
+  return m_options.find(key) != m_options.end();
+}
+
+bool CUrlOptions::GetOption(const std::string &key, CVariant &value)
+{
+  if (key.empty())
+    return false;
+
+  UrlOptions::const_iterator option = m_options.find(key);
+  if (option == m_options.end())
+    return false;
+
+  value = option->second;
+  return true;
+}
index 47c6e51..b7c0fcb 100644 (file)
@@ -29,17 +29,23 @@ public:
   typedef std::map<std::string, CVariant> UrlOptions;
 
   CUrlOptions();
+  CUrlOptions(const std::string &options);
   virtual ~CUrlOptions();
 
   virtual const UrlOptions& GetOptions() const { return m_options; }
   virtual std::string GetOptionsString() const;
 
+  virtual void AddOption(const std::string &key, const char *value);
   virtual void AddOption(const std::string &key, const std::string &value);
   virtual void AddOption(const std::string &key, int value);
   virtual void AddOption(const std::string &key, float value);
   virtual void AddOption(const std::string &key, double value);
   virtual void AddOption(const std::string &key, bool value);
   virtual void AddOptions(const std::string &options);
+  virtual void AddOptions(const CUrlOptions &options);
+
+  virtual bool HasOption(const std::string &key);
+  virtual bool GetOption(const std::string &key, CVariant &value);
 
 protected:
   UrlOptions m_options;
index c6e550f..d71a151 100644 (file)
@@ -233,6 +233,20 @@ CVariant::CVariant(const std::vector<std::string> &strArray)
     m_data.array->push_back(strArray.at(index));
 }
 
+CVariant::CVariant(const std::map<std::string, std::string> &strMap)
+{
+  m_type = VariantTypeObject;
+  m_data.map = new VariantMap;
+  for (std::map<std::string, std::string>::const_iterator it = strMap.begin(); it != strMap.end(); it++)
+    m_data.map->insert(make_pair(it->first, CVariant(it->second)));
+}
+
+CVariant::CVariant(const std::map<std::string, CVariant> &variantMap)
+{
+  m_type = VariantTypeObject;
+  m_data.map = new VariantMap(variantMap.begin(), variantMap.end());
+}
+
 CVariant::CVariant(const CVariant &variant)
 {
   m_type = VariantTypeNull;
index bc031ab..94476f0 100644 (file)
@@ -63,6 +63,8 @@ public:
   CVariant(const wchar_t *str, unsigned int length);
   CVariant(const std::wstring &str);
   CVariant(const std::vector<std::string> &strArray);
+  CVariant(const std::map<std::string, std::string> &strMap);
+  CVariant(const std::map<std::string, CVariant> &variantMap);
   CVariant(const CVariant &variant);
   ~CVariant();
 
index 692e83f..e80d306 100644 (file)
@@ -303,11 +303,18 @@ TEST(TestStringUtils, AlphaNumericCompare)
 
 TEST(TestStringUtils, TimeStringToSeconds)
 {
-  long ref, var;
-
-  ref = 77455;
-  var = StringUtils::TimeStringToSeconds("21:30:55");
-  EXPECT_EQ(ref, var);
+  EXPECT_EQ(77455, StringUtils::TimeStringToSeconds("21:30:55"));
+  EXPECT_EQ(7*60, StringUtils::TimeStringToSeconds("7 min"));
+  EXPECT_EQ(7*60, StringUtils::TimeStringToSeconds("7 min\t"));
+  EXPECT_EQ(154*60, StringUtils::TimeStringToSeconds("   154 min"));
+  EXPECT_EQ(1*60+1, StringUtils::TimeStringToSeconds("1:01"));
+  EXPECT_EQ(4*60+3, StringUtils::TimeStringToSeconds("4:03"));
+  EXPECT_EQ(2*3600+4*60+3, StringUtils::TimeStringToSeconds("2:04:03"));
+  EXPECT_EQ(2*3600+4*60+3, StringUtils::TimeStringToSeconds("   2:4:3"));
+  EXPECT_EQ(2*3600+4*60+3, StringUtils::TimeStringToSeconds("  \t\t 02:04:03 \n "));
+  EXPECT_EQ(1*3600+5*60+2, StringUtils::TimeStringToSeconds("01:05:02:04:03 \n "));
+  EXPECT_EQ(0, StringUtils::TimeStringToSeconds("blah"));
+  EXPECT_EQ(0, StringUtils::TimeStringToSeconds("ля-ля"));
 }
 
 TEST(TestStringUtils, RemoveCRLF)
index 99d2c4b..1bc666c 100644 (file)
@@ -137,6 +137,31 @@ TEST(TestVariant, VariantTypeNull)
   EXPECT_EQ(CVariant::VariantTypeNull, a.type());
 }
 
+TEST(TestVariant, VariantFromMap)
+{
+  std::map<std::string, std::string> strMap;
+  strMap["key"] = "value";
+  CVariant a = strMap;
+  
+  EXPECT_TRUE(a.isObject());
+  EXPECT_TRUE(a.size() == 1);
+  EXPECT_EQ(CVariant::VariantTypeObject, a.type());
+  EXPECT_TRUE(a.isMember("key"));
+  EXPECT_TRUE(a["key"].isString());
+  EXPECT_STREQ(a["key"].asString().c_str(), "value");
+  
+  std::map<std::string, CVariant> variantMap;
+  variantMap["key"] = CVariant("value");
+  CVariant b = variantMap;
+  
+  EXPECT_TRUE(b.isObject());
+  EXPECT_TRUE(b.size() == 1);
+  EXPECT_EQ(CVariant::VariantTypeObject, b.type());
+  EXPECT_TRUE(b.isMember("key"));
+  EXPECT_TRUE(b["key"].isString());
+  EXPECT_STREQ(b["key"].asString().c_str(), "value");
+}
+
 TEST(TestVariant, operatorTest)
 {
   std::vector<std::string> strarray;
index 5b86133..4b79939 100644 (file)
@@ -35,6 +35,7 @@
 #include "filesystem/Directory.h"
 #include "filesystem/File.h"
 #include "filesystem/SpecialProtocol.h"
+#include "dialogs/GUIDialogExtendedProgressBar.h"
 #include "dialogs/GUIDialogProgress.h"
 #include "dialogs/GUIDialogYesNo.h"
 #include "FileItem.h"
@@ -2730,13 +2731,15 @@ void CVideoDatabase::DeleteMovie(const CStdString& strFilenameAndPath, bool bKee
       m_pDS->exec(strSQL.c_str());
     }
 
+    //TODO: move this below CommitTransaction() once UPnP doesn't rely on this anymore
+    if (!bKeepId)
+      AnnounceRemove("movie", idMovie);
+
     CStdString strPath, strFileName;
     SplitPath(strFilenameAndPath,strPath,strFileName);
     InvalidatePathHash(strPath);
     CommitTransaction();
 
-    if (!bKeepId)
-      AnnounceRemove("movie", idMovie);
   }
   catch (...)
   {
@@ -2800,12 +2803,14 @@ void CVideoDatabase::DeleteTvShow(const CStdString& strPath, bool bKeepId /* = f
       m_pDS->exec(strSQL.c_str());
     }
 
+    //TODO: move this below CommitTransaction() once UPnP doesn't rely on this anymore
+    if (!bKeepId)
+      AnnounceRemove("tvshow", idTvShow);
+
     InvalidatePathHash(strPath);
 
     CommitTransaction();
 
-    if (!bKeepId)
-      AnnounceRemove("tvshow", idTvShow);
   }
   catch (...)
   {
@@ -2839,6 +2844,10 @@ void CVideoDatabase::DeleteEpisode(const CStdString& strFilenameAndPath, int idE
       }
     }
 
+    //TODO: move this below CommitTransaction() once UPnP doesn't rely on this anymore
+    if (!bKeepId)
+      AnnounceRemove("episode", idEpisode);
+
     CStdString strSQL;
     strSQL=PrepareSQL("delete from actorlinkepisode where idEpisode=%i", idEpisode);
     m_pDS->exec(strSQL.c_str());
@@ -2861,8 +2870,6 @@ void CVideoDatabase::DeleteEpisode(const CStdString& strFilenameAndPath, int idE
       m_pDS->exec(strSQL.c_str());
     }
 
-    if (!bKeepId)
-      AnnounceRemove("episode", idEpisode);
   }
   catch (...)
   {
@@ -2921,13 +2928,15 @@ void CVideoDatabase::DeleteMusicVideo(const CStdString& strFilenameAndPath, bool
       m_pDS->exec(strSQL.c_str());
     }
 
+    //TODO: move this below CommitTransaction() once UPnP doesn't rely on this anymore
+    if (!bKeepId)
+      AnnounceRemove("musicvideo", idMVideo);
+
     CStdString strPath, strFileName;
     SplitPath(strFilenameAndPath,strPath,strFileName);
     InvalidatePathHash(strPath);
     CommitTransaction();
 
-    if (!bKeepId)
-      AnnounceRemove("musicvideo", idMVideo);
   }
   catch (...)
   {
@@ -3641,6 +3650,7 @@ bool CVideoDatabase::GetTvShowSeasonArt(int showId, map<int, string> &seasonArt)
 
     for (vector< pair<int,int> >::const_iterator i = seasons.begin(); i != seasons.end(); ++i)
       seasonArt.insert(make_pair(i->second,GetArtForItem(i->first, "season", "thumb")));
+    return true;
   }
   catch (...)
   {
@@ -4428,22 +4438,22 @@ void CVideoDatabase::EraseVideoSettings()
   }
 }
 
-bool CVideoDatabase::GetGenresNav(const CStdString& strBaseDir, CFileItemList& items, int idContent /* = -1 */, const Filter &filter /* = Filter() */)
+bool CVideoDatabase::GetGenresNav(const CStdString& strBaseDir, CFileItemList& items, int idContent /* = -1 */, const Filter &filter /* = Filter() */, bool countOnly /* = false */)
 {
-  return GetNavCommon(strBaseDir, items, "genre", idContent, filter);
+  return GetNavCommon(strBaseDir, items, "genre", idContent, filter, countOnly);
 }
 
-bool CVideoDatabase::GetCountriesNav(const CStdString& strBaseDir, CFileItemList& items, int idContent /* = -1 */, const Filter &filter /* = Filter() */)
+bool CVideoDatabase::GetCountriesNav(const CStdString& strBaseDir, CFileItemList& items, int idContent /* = -1 */, const Filter &filter /* = Filter() */, bool countOnly /* = false */)
 {
-  return GetNavCommon(strBaseDir, items, "country", idContent, filter);
+  return GetNavCommon(strBaseDir, items, "country", idContent, filter, countOnly);
 }
 
-bool CVideoDatabase::GetStudiosNav(const CStdString& strBaseDir, CFileItemList& items, int idContent /* = -1 */, const Filter &filter /* = Filter() */)
+bool CVideoDatabase::GetStudiosNav(const CStdString& strBaseDir, CFileItemList& items, int idContent /* = -1 */, const Filter &filter /* = Filter() */, bool countOnly /* = false */)
 {
-  return GetNavCommon(strBaseDir, items, "studio", idContent, filter);
+  return GetNavCommon(strBaseDir, items, "studio", idContent, filter, countOnly);
 }
 
-bool CVideoDatabase::GetNavCommon(const CStdString& strBaseDir, CFileItemList& items, const CStdString &type, int idContent /* = -1 */, const Filter &filter /* = Filter() */)
+bool CVideoDatabase::GetNavCommon(const CStdString& strBaseDir, CFileItemList& items, const CStdString &type, int idContent /* = -1 */, const Filter &filter /* = Filter() */, bool countOnly /* = false */)
 {
   try
   {
@@ -4456,19 +4466,22 @@ bool CVideoDatabase::GetNavCommon(const CStdString& strBaseDir, CFileItemList& i
     {
       if (idContent == VIDEODB_CONTENT_MOVIES)
       {
-        strSQL = PrepareSQL("select %s.id%s, %s.str%s, path.strPath, files.playCount from %s ", type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str());
+        strSQL = "select %s " + PrepareSQL("from %s ", type.c_str());
+        extFilter.fields = PrepareSQL("%s.id%s, %s.str%s, path.strPath, files.playCount", type.c_str(), type.c_str(), type.c_str(), type.c_str());
         extFilter.AppendJoin(PrepareSQL("join %slinkmovie on %s.id%s = %slinkmovie.id%s join movieview on %slinkmovie.idMovie = movieview.idMovie join files on files.idFile = movieview.idFile join path on path.idPath = files.idPath",
                                         type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str()));
       }
       else if (idContent == VIDEODB_CONTENT_TVSHOWS) //this will not get tvshows with 0 episodes
       {
-        strSQL = PrepareSQL("select %s.id%s, %s.str%s, path.strPath from %s ", type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str());
+        strSQL = "select %s " + PrepareSQL("from %s ", type.c_str());
+        extFilter.fields = PrepareSQL("%s.id%s, %s.str%s, path.strPath", type.c_str(), type.c_str(), type.c_str(), type.c_str());
         extFilter.AppendJoin(PrepareSQL("join %slinktvshow on %s.id%s = %slinktvshow.id%s join episodeview on %slinktvshow.idShow = episodeview.idShow join files on files.idFile = episodeview.idFile join path on path.idPath = files.idPath",
                                         type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str()));
       }
       else if (idContent == VIDEODB_CONTENT_MUSICVIDEOS)
       {
-        strSQL = PrepareSQL("select %s.id%s, %s.str%s, path.strPath, files.playCount from %s ", type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str());
+        strSQL = "select %s " + PrepareSQL("from %s ", type.c_str());
+        extFilter.fields = PrepareSQL("%s.id%s, %s.str%s, path.strPath, files.playCount", type.c_str(), type.c_str(), type.c_str(), type.c_str());
         extFilter.AppendJoin(PrepareSQL("join %slinkmusicvideo on %s.id%s = %slinkmusicvideo.id%s join musicvideoview on %slinkmusicvideo.idMVideo = musicvideoview.idMVideo join files on files.idFile = musicvideoview.idFile join path on path.idPath = files.idPath",
                                         type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str()));
       }
@@ -4479,20 +4492,23 @@ bool CVideoDatabase::GetNavCommon(const CStdString& strBaseDir, CFileItemList& i
     {
       if (idContent == VIDEODB_CONTENT_MOVIES)
       {
-        strSQL = PrepareSQL("select %s.id%s, %s.str%s, count(1), count(files.playCount) from %s ", type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str());
+        strSQL = "select %s " + PrepareSQL("from %s ", type.c_str());
+        extFilter.fields = PrepareSQL("%s.id%s, %s.str%s, count(1), count(files.playCount)", type.c_str(), type.c_str(), type.c_str(), type.c_str());
         extFilter.AppendJoin(PrepareSQL("join %slinkmovie on %s.id%s = %slinkmovie.id%s join movieview on %slinkmovie.idMovie = movieview.idMovie join files on files.idFile = movieview.idFile",
                                         type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str()));
         extFilter.AppendGroup(PrepareSQL("%s.id%s", type.c_str(), type.c_str()));
       }
       else if (idContent == VIDEODB_CONTENT_TVSHOWS)
       {
-        strSQL = PrepareSQL("select distinct %s.id%s, %s.str%s from %s ", type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str());
+        strSQL = "select %s " + PrepareSQL("from %s ", type.c_str());
+        extFilter.fields = PrepareSQL("distinct %s.id%s, %s.str%s", type.c_str(), type.c_str(), type.c_str(), type.c_str());
         extFilter.AppendJoin(PrepareSQL("join %slinktvshow on %s.id%s = %slinktvshow.id%s join tvshowview on %slinktvshow.idShow = tvshowview.idShow",
                                         type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str()));
       }
       else if (idContent == VIDEODB_CONTENT_MUSICVIDEOS)
       {
-        strSQL = PrepareSQL("select %s.id%s, %s.str%s, count(1), count(files.playCount) from %s ", type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str());
+        strSQL = "select %s " + PrepareSQL("from %s ", type.c_str());
+        extFilter.fields = PrepareSQL("%s.id%s, %s.str%s, count(1), count(files.playCount)", type.c_str(), type.c_str(), type.c_str(), type.c_str());
         extFilter.AppendJoin(PrepareSQL("join %slinkmusicvideo on %s.id%s = %slinkmusicvideo.id%s join musicvideoview on %slinkmusicvideo.idMVideo = musicvideoview.idMVideo join files on files.idFile = musicvideoview.idFile",
                                         type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str(), type.c_str()));
         extFilter.AppendGroup(PrepareSQL("%s.id%s", type.c_str(), type.c_str()));
@@ -4501,6 +4517,14 @@ bool CVideoDatabase::GetNavCommon(const CStdString& strBaseDir, CFileItemList& i
         return false;
     }
 
+    if (countOnly)
+    {
+      extFilter.fields = PrepareSQL("COUNT(DISTINCT %s.id%s)", type.c_str(), type.c_str());
+      extFilter.group.clear();
+      extFilter.order.clear();
+    }
+    strSQL.Format(strSQL.c_str(), !extFilter.fields.empty() ? extFilter.fields.c_str() : "*");
+
     CVideoDbUrl videoUrl;
     if (!BuildSQL(strBaseDir, strSQL, extFilter, strSQL, videoUrl))
       return false;
@@ -4509,6 +4533,16 @@ bool CVideoDatabase::GetNavCommon(const CStdString& strBaseDir, CFileItemList& i
     if (iRowsFound <= 0)
       return iRowsFound == 0;
 
+    if (countOnly)
+    {
+      CFileItemPtr pItem(new CFileItem());
+      pItem->SetProperty("total", iRowsFound == 1 ? m_pDS->fv(0).get_asInt() : iRowsFound);
+      items.Add(pItem);
+
+      m_pDS->close();
+      return true;
+    }
+
     if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
     {
       map<int, pair<CStdString,int> > mapItems;
@@ -4590,7 +4624,7 @@ bool CVideoDatabase::GetNavCommon(const CStdString& strBaseDir, CFileItemList& i
   return false;
 }
 
-bool CVideoDatabase::GetTagsNav(const CStdString& strBaseDir, CFileItemList& items, int idContent /* = -1 */, const Filter &filter /* = Filter() */)
+bool CVideoDatabase::GetTagsNav(const CStdString& strBaseDir, CFileItemList& items, int idContent /* = -1 */, const Filter &filter /* = Filter() */, bool countOnly /* = false */)
 {
   CStdString mediaType;
   if (idContent == VIDEODB_CONTENT_MOVIES)
@@ -4607,13 +4641,26 @@ bool CVideoDatabase::GetTagsNav(const CStdString& strBaseDir, CFileItemList& ite
     if (NULL == m_pDB.get()) return false;
     if (NULL == m_pDS.get()) return false;
 
-    CStdString strSQL = "SELECT tag.idTag, tag.strTag FROM taglinks ";
+    CStdString strSQL = "SELECT %s FROM taglinks ";
 
     Filter extFilter = filter;
+    extFilter.fields = "tag.idTag, tag.strTag";
     extFilter.AppendJoin("JOIN tag ON tag.idTag = taglinks.idTag");
+
+    if (idContent == (int)VIDEODB_CONTENT_MOVIES)
+      extFilter.AppendJoin("JOIN movieview ON movieview.idMovie = taglinks.idMedia");
+
     extFilter.AppendWhere(PrepareSQL("taglinks.media_type = '%s'", mediaType.c_str()));
     extFilter.AppendGroup("taglinks.idTag");
 
+    if (countOnly)
+    {
+      extFilter.fields = "COUNT(DISTINCT taglinks.idTag)";
+      extFilter.group.clear();
+      extFilter.order.clear();
+    }
+    strSQL.Format(strSQL.c_str(), !extFilter.fields.empty() ? extFilter.fields.c_str() : "*");
+
     // parse the base path to get additional filters
     CVideoDbUrl videoUrl;
     if (!BuildSQL(strBaseDir, strSQL, extFilter, strSQL, videoUrl))
@@ -4623,6 +4670,16 @@ bool CVideoDatabase::GetTagsNav(const CStdString& strBaseDir, CFileItemList& ite
     if (iRowsFound <= 0)
       return iRowsFound == 0;
 
+    if (countOnly)
+    {
+      CFileItemPtr pItem(new CFileItem());
+      pItem->SetProperty("total", iRowsFound == 1 ? m_pDS->fv(0).get_asInt() : iRowsFound);
+      items.Add(pItem);
+
+      m_pDS->close();
+      return true;
+    }
+
     while (!m_pDS->eof())
     {
       int idTag = m_pDS->fv(0).get_asInt();
@@ -4790,23 +4847,23 @@ bool CVideoDatabase::GetSetsByWhere(const CStdString& strBaseDir, const Filter &
   return false;
 }
 
-bool CVideoDatabase::GetMusicVideoAlbumsNav(const CStdString& strBaseDir, CFileItemList& items, int idArtist /* = -1 */, const Filter &filter /* = Filter() */)
+bool CVideoDatabase::GetMusicVideoAlbumsNav(const CStdString& strBaseDir, CFileItemList& items, int idArtist /* = -1 */, const Filter &filter /* = Filter() */, bool countOnly /* = false */)
 {
   try
   {
     if (NULL == m_pDB.get()) return false;
     if (NULL == m_pDS.get()) return false;
 
-    CStdString strSQL;
+    CStdString strSQL = "select %s from musicvideoview ";
     Filter extFilter = filter;
     if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
     {
-      strSQL = PrepareSQL("select musicvideoview.c%02d, musicvideoview.idMVideo, actors.strActor, path.strPath from musicvideoview ", VIDEODB_ID_MUSICVIDEO_ALBUM);
+      extFilter.fields = PrepareSQL("musicvideoview.c%02d, musicvideoview.idMVideo, actors.strActor, path.strPath", VIDEODB_ID_MUSICVIDEO_ALBUM);
       extFilter.AppendJoin("join artistlinkmusicvideo on artistlinkmusicvideo.idMVideo = musicvideoview.idMVideo join actors on actors.idActor = artistlinkmusicvideo.idArtist join files on files.idFile = musicvideoview.idFile join path on path.idPath = files.idPath");
     }
     else
     {
-      strSQL = PrepareSQL("select musicvideoview.c%02d, musicvideoview.idMVideo, actors.strActor from musicvideoview ", VIDEODB_ID_MUSICVIDEO_ALBUM);
+      extFilter.fields = PrepareSQL("musicvideoview.c%02d, musicvideoview.idMVideo, actors.strActor", VIDEODB_ID_MUSICVIDEO_ALBUM);
       extFilter.AppendJoin("join artistlinkmusicvideo on artistlinkmusicvideo.idMVideo = musicvideoview.idMVideo join actors on actors.idActor = artistlinkmusicvideo.idArtist");
     }
     if (idArtist > -1)
@@ -4814,6 +4871,14 @@ bool CVideoDatabase::GetMusicVideoAlbumsNav(const CStdString& strBaseDir, CFileI
 
     extFilter.AppendGroup(PrepareSQL("musicvideoview.c%02d", VIDEODB_ID_MUSICVIDEO_ALBUM));
 
+    if (countOnly)
+    {
+      extFilter.fields = "COUNT(1)";
+      extFilter.group.clear();
+      extFilter.order.clear();
+    }
+    strSQL.Format(strSQL.c_str(), !extFilter.fields.empty() ? extFilter.fields.c_str() : "*");
+
     CVideoDbUrl videoUrl;
     if (!BuildSQL(strBaseDir, strSQL, extFilter, strSQL, videoUrl))
       return false;
@@ -4822,6 +4887,16 @@ bool CVideoDatabase::GetMusicVideoAlbumsNav(const CStdString& strBaseDir, CFileI
     if (iRowsFound <= 0)
       return iRowsFound == 0;
 
+    if (countOnly)
+    {
+      CFileItemPtr pItem(new CFileItem());
+      pItem->SetProperty("total", iRowsFound == 1 ? m_pDS->fv(0).get_asInt() : iRowsFound);
+      items.Add(pItem);
+
+      m_pDS->close();
+      return true;
+    }
+
     if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
     {
       map<int, pair<CStdString,CStdString> > mapAlbums;
@@ -4899,21 +4974,21 @@ bool CVideoDatabase::GetMusicVideoAlbumsNav(const CStdString& strBaseDir, CFileI
   return false;
 }
 
-bool CVideoDatabase::GetWritersNav(const CStdString& strBaseDir, CFileItemList& items, int idContent /* = -1 */, const Filter &filter /* = Filter() */)
+bool CVideoDatabase::GetWritersNav(const CStdString& strBaseDir, CFileItemList& items, int idContent /* = -1 */, const Filter &filter /* = Filter() */, bool countOnly /* = false */)
 {
-  return GetPeopleNav(strBaseDir, items, "writer", idContent, filter);
+  return GetPeopleNav(strBaseDir, items, "writer", idContent, filter, countOnly);
 }
 
-bool CVideoDatabase::GetDirectorsNav(const CStdString& strBaseDir, CFileItemList& items, int idContent /* = -1 */, const Filter &filter /* = Filter() */)
+bool CVideoDatabase::GetDirectorsNav(const CStdString& strBaseDir, CFileItemList& items, int idContent /* = -1 */, const Filter &filter /* = Filter() */, bool countOnly /* = false */)
 {
-  return GetPeopleNav(strBaseDir, items, "director", idContent, filter);
+  return GetPeopleNav(strBaseDir, items, "director", idContent, filter, countOnly);
 }
 
-bool CVideoDatabase::GetActorsNav(const CStdString& strBaseDir, CFileItemList& items, int idContent /* = -1 */, const Filter &filter /* = Filter() */)
+bool CVideoDatabase::GetActorsNav(const CStdString& strBaseDir, CFileItemList& items, int idContent /* = -1 */, const Filter &filter /* = Filter() */, bool countOnly /* = false */)
 {
-  if (GetPeopleNav(strBaseDir, items, (idContent == VIDEODB_CONTENT_MUSICVIDEOS) ? "artist" : "actor", idContent, filter))
+  if (GetPeopleNav(strBaseDir, items, (idContent == VIDEODB_CONTENT_MUSICVIDEOS) ? "artist" : "actor", idContent, filter, countOnly))
   { // set thumbs - ideally this should be in the normal thumb setting routines
-    for (int i = 0; i < items.Size(); i++)
+    for (int i = 0; i < items.Size() && !countOnly; i++)
     {
       CFileItemPtr pItem = items[i];
       if (idContent == VIDEODB_CONTENT_MUSICVIDEOS)
@@ -4926,7 +5001,7 @@ bool CVideoDatabase::GetActorsNav(const CStdString& strBaseDir, CFileItemList& i
   return false;
 }
 
-bool CVideoDatabase::GetPeopleNav(const CStdString& strBaseDir, CFileItemList& items, const CStdString &type, int idContent /* = -1 */, const Filter &filter /* = Filter() */)
+bool CVideoDatabase::GetPeopleNav(const CStdString& strBaseDir, CFileItemList& items, const CStdString &type, int idContent /* = -1 */, const Filter &filter /* = Filter() */, bool countOnly /* = false */)
 {
   if (NULL == m_pDB.get()) return false;
   if (NULL == m_pDS.get()) return false;
@@ -4949,25 +5024,29 @@ bool CVideoDatabase::GetPeopleNav(const CStdString& strBaseDir, CFileItemList& i
     {
       if (idContent == VIDEODB_CONTENT_MOVIES)
       {
-        strSQL = PrepareSQL("select actors.idActor, actors.strActor, actors.strThumb, path.strPath, files.playCount from actors ");
+        strSQL = "select %s from actors ";
+        extFilter.fields = "actors.idActor, actors.strActor, actors.strThumb, path.strPath, files.playCount";
         extFilter.AppendJoin(PrepareSQL("join %slinkmovie on actors.idActor = %slinkmovie.id%s join movieview on %slinkmovie.idMovie = movieview.idMovie join files on files.idFile = movieview.idFile join path on path.idPath = files.idPath",
                                         type.c_str(), type.c_str(), type.c_str(), type.c_str()));
       }
       else if (idContent == VIDEODB_CONTENT_TVSHOWS)
       {
-        strSQL = PrepareSQL("select actors.idActor, actors.strActor, actors.strThumb, path.strPath from actors ");
+        strSQL = "select %s from actors ";
+        extFilter.fields = "actors.idActor, actors.strActor, actors.strThumb, path.strPath";
         extFilter.AppendJoin(PrepareSQL("join %slinktvshow on actors.idActor = %slinktvshow.id%s join episodeview on %slinktvshow.idShow = episodeview.idShow join files on files.idFile = episodeview.idFile join path on path.idPath = files.idPath",
                                         type.c_str(), type.c_str(), type.c_str(), type.c_str()));
       }
       else if (idContent == VIDEODB_CONTENT_EPISODES)
       {
-        strSQL = PrepareSQL("select actors.idActor, actors.strActor, actors.strThumb, path.strPath, files.playCount from actors ");
+        strSQL = "select %s from actors ";
+        extFilter.fields = "actors.idActor, actors.strActor, actors.strThumb, path.strPath, files.playCount";
         extFilter.AppendJoin(PrepareSQL("join %slinkepisode on actors.idActor = %slinkepisode.id%s join episodeview on %slinkepisode.idEpisode = episodeview.idEpisode join files on files.idFile = episodeview.idFile join path on path.idPath = files.idPath",
                                         type.c_str(), type.c_str(), type.c_str(), type.c_str()));
       }
       else if (idContent == VIDEODB_CONTENT_MUSICVIDEOS)
       {
-        strSQL = PrepareSQL("select actors.idActor, actors.strActor, actors.strThumb, path.strPath, files.playCount from actors ");
+        strSQL = "select %s from actors ";
+        extFilter.fields = "actors.idActor, actors.strActor, actors.strThumb, path.strPath, files.playCount";
         extFilter.AppendJoin(PrepareSQL("join %slinkmusicvideo on actors.idActor = %slinkmusicvideo.id%s join musicvideoview on %slinkmusicvideo.idMVideo = musicvideoview.idMVideo join files on files.idFile = musicvideoview.idFile join path on path.idPath = files.idPath",
                                         type.c_str(), type.c_str(), type.c_str(), type.c_str()));
       }
@@ -4978,27 +5057,31 @@ bool CVideoDatabase::GetPeopleNav(const CStdString& strBaseDir, CFileItemList& i
     {
       if (idContent == VIDEODB_CONTENT_MOVIES)
       {
-        strSQL = PrepareSQL("select actors.idActor, actors.strActor, actors.strThumb, count(1), count(files.playCount) from actors ");
+        strSQL ="select %s from actors ";
+        extFilter.fields = "actors.idActor, actors.strActor, actors.strThumb, count(1), count(files.playCount)";
         extFilter.AppendJoin(PrepareSQL("join %slinkmovie on actors.idActor = %slinkmovie.id%s join movieview on %slinkmovie.idMovie = movieview.idMovie join files on files.idFile = movieview.idFile",
                                         type.c_str(), type.c_str(), type.c_str(), type.c_str()));
         extFilter.AppendGroup("actors.idActor");
       }
       else if (idContent == VIDEODB_CONTENT_TVSHOWS)
       {
-        strSQL = PrepareSQL("select distinct actors.idActor, actors.strActor, actors.strThumb from actors, %slinktvshow, tvshowview ", type.c_str());
+        strSQL = "select %s " + PrepareSQL("from actors, %slinktvshow, tvshowview ", type.c_str());
+        extFilter.fields = "distinct actors.idActor, actors.strActor, actors.strThumb";
         extFilter.AppendWhere(PrepareSQL("actors.idActor = %slinktvshow.id%s and %slinktvshow.idShow = tvshowview.idShow",
                                          type.c_str(), type.c_str(), type.c_str()));
       }
       else if (idContent == VIDEODB_CONTENT_EPISODES)
       {
-        strSQL = PrepareSQL("select actors.idActor, actors.strActor, actors.strThumb, count(1), count(files.playCount) from %slinkepisode, actors, episodeview, files ", type.c_str());
+        strSQL = "select %s " + PrepareSQL("%slinkepisode, actors, episodeview, files ", type.c_str());
+        extFilter.fields = "actors.idActor, actors.strActor, actors.strThumb, count(1), count(files.playCount)";
         extFilter.AppendWhere(PrepareSQL("actors.idActor = %slinkepisode.id%s and %slinkepisode.idEpisode = episodeview.idEpisode and files.idFile = episodeview.idFile",
                                          type.c_str(), type.c_str(), type.c_str()));
         extFilter.AppendGroup("actors.idActor");
       }
       else if (idContent == VIDEODB_CONTENT_MUSICVIDEOS)
       {
-        strSQL = PrepareSQL("select actors.idActor, actors.strActor, actors.strThumb, count(1), count(files.playCount) from actors ");
+        strSQL = "select %s from actors ";
+        extFilter.fields = "actors.idActor, actors.strActor, actors.strThumb, count(1), count(files.playCount)";
         extFilter.AppendJoin(PrepareSQL("join %slinkmusicvideo on actors.idActor = %slinkmusicvideo.id%s join musicvideoview on %slinkmusicvideo.idMVideo = musicvideoview.idMVideo join files on files.idFile = musicvideoview.idFile",
                                         type.c_str(), type.c_str(), type.c_str(), type.c_str()));
         extFilter.AppendGroup("actors.idActor");
@@ -5007,6 +5090,14 @@ bool CVideoDatabase::GetPeopleNav(const CStdString& strBaseDir, CFileItemList& i
         return false;
     }
 
+    if (countOnly)
+    {
+      extFilter.fields = "COUNT(1)";
+      extFilter.group.clear();
+      extFilter.order.clear();
+    }
+    strSQL.Format(strSQL.c_str(), !extFilter.fields.empty() ? extFilter.fields.c_str() : "*");
+
     CVideoDbUrl videoUrl;
     if (!BuildSQL(strBaseDir, strSQL, extFilter, strSQL, videoUrl))
       return false;
@@ -5023,6 +5114,16 @@ bool CVideoDatabase::GetPeopleNav(const CStdString& strBaseDir, CFileItemList& i
       return true;
     }
 
+    if (countOnly)
+    {
+      CFileItemPtr pItem(new CFileItem());
+      pItem->SetProperty("total", iRowsFound == 1 ? m_pDS->fv(0).get_asInt() : iRowsFound);
+      items.Add(pItem);
+
+      m_pDS->close();
+      return true;
+    }
+
     if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
     {
       map<int, CActor> mapActors;
@@ -5331,10 +5432,10 @@ bool CVideoDatabase::GetSeasonsNav(const CStdString& strBaseDir, CFileItemList&
 
     CStdString strSQL = PrepareSQL("SELECT episodeview.c%02d, "
                                           "path.strPath, "
-                                          "tvshowview.c%02d, tvshowview.c%02d, tvshowview.c%02d, tvshowview.c%02d, "
+                                          "tvshowview.c%02d, tvshowview.c%02d, tvshowview.c%02d, tvshowview.c%02d, tvshowview.c%02d, tvshowview.c%02d, "
                                           "seasons.idSeason, "
                                           "count(1), count(files.playCount) "
-                                          "FROM episodeview ", VIDEODB_ID_EPISODE_SEASON, VIDEODB_ID_TV_TITLE, VIDEODB_ID_TV_GENRE, VIDEODB_ID_TV_STUDIOS, VIDEODB_ID_TV_MPAA);
+                                          "FROM episodeview ", VIDEODB_ID_EPISODE_SEASON, VIDEODB_ID_TV_TITLE, VIDEODB_ID_TV_PLOT, VIDEODB_ID_TV_PREMIERED, VIDEODB_ID_TV_GENRE, VIDEODB_ID_TV_STUDIOS, VIDEODB_ID_TV_MPAA);
     
     Filter filter;
     filter.join = PrepareSQL("JOIN tvshowview ON tvshowview.idShow = episodeview.idShow "
@@ -5359,14 +5460,18 @@ bool CVideoDatabase::GetSeasonsNav(const CStdString& strBaseDir, CFileItemList&
     if (!BuildSQL(strBaseDir, strSQL, filter, strSQL, videoUrl))
       return false;
 
+    items.SetPath(videoUrl.ToString());
+
     int iRowsFound = RunQuery(strSQL);
     if (iRowsFound <= 0)
       return iRowsFound == 0;
 
-    // show titles, studios and mpaa ratings will be the same
+    // show titles, plots, day of premiere, studios and mpaa ratings will be the same
     CStdString showTitle = m_pDS->fv(2).get_asString();
-    CStdString showStudio = m_pDS->fv(4).get_asString();
-    CStdString showMPAARating = m_pDS->fv(5).get_asString();
+    CStdString showPlot = m_pDS->fv(3).get_asString();
+    CStdString showPremiered = m_pDS->fv(4).get_asString();
+    CStdString showStudio = m_pDS->fv(6).get_asString();
+    CStdString showMPAARating = m_pDS->fv(7).get_asString();
 
     if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
     {
@@ -5386,10 +5491,10 @@ bool CVideoDatabase::GetSeasonsNav(const CStdString& strBaseDir, CFileItemList&
         {
           CSeason season;
           season.path = m_pDS->fv(1).get_asString();
-          season.genre = StringUtils::Split(m_pDS->fv(3).get_asString(), g_advancedSettings.m_videoItemSeparator);
-          season.id = m_pDS->fv(6).get_asInt();
-          season.numEpisodes = m_pDS->fv(7).get_asInt();
-          season.numWatched = m_pDS->fv(8).get_asInt();
+          season.genre = StringUtils::Split(m_pDS->fv(5).get_asString(), g_advancedSettings.m_videoItemSeparator);
+          season.id = m_pDS->fv(8).get_asInt();
+          season.numEpisodes = m_pDS->fv(9).get_asInt();
+          season.numWatched = m_pDS->fv(10).get_asInt();
           mapSeasons.insert(make_pair(iSeason, season));
         }
         m_pDS->next();
@@ -5422,6 +5527,8 @@ bool CVideoDatabase::GetSeasonsNav(const CStdString& strBaseDir, CFileItemList&
         pItem->GetVideoInfoTag()->m_strMPAARating = showMPAARating;
         pItem->GetVideoInfoTag()->m_iIdShow = idShow;
         pItem->GetVideoInfoTag()->m_strShowTitle = showTitle;
+        pItem->GetVideoInfoTag()->m_strPlot = showPlot;
+        pItem->GetVideoInfoTag()->m_premiered.SetFromDBDate(showPremiered);
         pItem->GetVideoInfoTag()->m_iEpisode = it->second.numEpisodes;
         pItem->SetProperty("totalepisodes", it->second.numEpisodes);
         pItem->SetProperty("numepisodes", it->second.numEpisodes); // will be changed later to reflect watchmode setting
@@ -5453,16 +5560,18 @@ bool CVideoDatabase::GetSeasonsNav(const CStdString& strBaseDir, CFileItemList&
         pItem->m_bIsFolder=true;
         pItem->GetVideoInfoTag()->m_strTitle = strLabel;
         pItem->GetVideoInfoTag()->m_iSeason = iSeason;
-        pItem->GetVideoInfoTag()->m_iDbId = m_pDS->fv(6).get_asInt();
+        pItem->GetVideoInfoTag()->m_iDbId = m_pDS->fv(8).get_asInt();
         pItem->GetVideoInfoTag()->m_type = "season";
         pItem->GetVideoInfoTag()->m_strPath = m_pDS->fv(1).get_asString();
-        pItem->GetVideoInfoTag()->m_genre = StringUtils::Split(m_pDS->fv(3).get_asString(), g_advancedSettings.m_videoItemSeparator);
+        pItem->GetVideoInfoTag()->m_genre = StringUtils::Split(m_pDS->fv(5).get_asString(), g_advancedSettings.m_videoItemSeparator);
         pItem->GetVideoInfoTag()->m_studio = StringUtils::Split(showStudio, g_advancedSettings.m_videoItemSeparator);
         pItem->GetVideoInfoTag()->m_strMPAARating = showMPAARating;
         pItem->GetVideoInfoTag()->m_iIdShow = idShow;
         pItem->GetVideoInfoTag()->m_strShowTitle = showTitle;
-        int totalEpisodes = m_pDS->fv(7).get_asInt();
-        int watchedEpisodes = m_pDS->fv(8).get_asInt();
+        pItem->GetVideoInfoTag()->m_strPlot = showPlot;
+        pItem->GetVideoInfoTag()->m_premiered.SetFromDBDate(showPremiered);
+        int totalEpisodes = m_pDS->fv(9).get_asInt();
+        int watchedEpisodes = m_pDS->fv(10).get_asInt();
         pItem->GetVideoInfoTag()->m_iEpisode = totalEpisodes;
         pItem->SetProperty("totalepisodes", totalEpisodes);
         pItem->SetProperty("numepisodes", totalEpisodes); // will be changed later to reflect watchmode setting
@@ -5481,7 +5590,11 @@ bool CVideoDatabase::GetSeasonsNav(const CStdString& strBaseDir, CFileItemList&
     Filter movieFilter;
     movieFilter.join  = PrepareSQL("join movielinktvshow on movielinktvshow.idMovie=movieview.idMovie");
     movieFilter.where = PrepareSQL("movielinktvshow.idShow %s", strIn.c_str());
-    GetMoviesByWhere("videodb://1/2/", movieFilter, items);
+    CFileItemList movieItems;
+    GetMoviesByWhere("videodb://1/2/", movieFilter, movieItems);
+
+    if (movieItems.Size() > 0)
+      items.Append(movieItems);
 
     return true;
   }
@@ -5585,6 +5698,12 @@ bool CVideoDatabase::GetMoviesByWhere(const CStdString& strBaseDir, const Filter
     if (!videoUrl.FromString(strBaseDir) || !GetFilter(videoUrl, extFilter))
       return false;
 
+    // if we have a "setid" option we don't want to retrieve sets
+    CVariant setId;
+    if (fetchSets && videoUrl.GetOption("setid", setId) &&
+        setId.isInteger() && setId.asInteger() > 0)
+      fetchSets = false;
+
     int total = -1;
 
     CStdString strSQL = "select %s from movieview ";
@@ -5626,6 +5745,8 @@ bool CVideoDatabase::GetMoviesByWhere(const CStdString& strBaseDir, const Filter
     if (!CDatabase::BuildSQL(strSQLExtra, extFilter, strSQLExtra))
       return false;
 
+    items.SetPath(videoUrl.ToString());
+
     // Apply the limiting directly here if there's no special sorting but limiting
     if (extFilter.limit.empty() &&
         sortDescription.sortBy == SortByNone &&
@@ -5748,6 +5869,8 @@ bool CVideoDatabase::GetTvShowsByWhere(const CStdString& strBaseDir, const Filte
     if (!BuildSQL(strBaseDir, strSQLExtra, extFilter, strSQLExtra, videoUrl))
       return false;
 
+    items.SetPath(videoUrl.ToString());
+
     // Apply the limiting directly here if there's no special sorting but limiting
     if (extFilter.limit.empty() &&
         sortDescription.sortBy == SortByNone &&
@@ -5841,7 +5964,7 @@ void CVideoDatabase::Stack(CFileItemList& items, VIDEODB_CONTENT_TYPE type, bool
       {
         CFileItemPtr pItem = items.Get(i);
         CStdString strTitle = pItem->GetVideoInfoTag()->m_strTitle;
-        CStdString strFanArt = pItem->GetProperty("fanart_image").asString();
+        CStdString strFanArt = pItem->GetArt("fanart");
 
         int j = i + 1;
         bool bStacked = false;
@@ -5869,7 +5992,7 @@ void CVideoDatabase::Stack(CFileItemList& items, VIDEODB_CONTENT_TYPE type, bool
 
             // check for fanart if not already set
             if (strFanArt.IsEmpty())
-              strFanArt = jItem->GetProperty("fanart_image").asString();
+              strFanArt = jItem->GetArt("fanart");
 
             // remove duplicate entry
             items.Remove(j);
@@ -5884,7 +6007,7 @@ void CVideoDatabase::Stack(CFileItemList& items, VIDEODB_CONTENT_TYPE type, bool
           pItem->GetVideoInfoTag()->m_playCount = (pItem->GetVideoInfoTag()->m_iEpisode == (int)pItem->GetProperty("watchedepisodes").asInteger()) ? 1 : 0;
           pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, (pItem->GetVideoInfoTag()->m_playCount > 0) && (pItem->GetVideoInfoTag()->m_iEpisode > 0));
           if (!strFanArt.IsEmpty())
-            pItem->SetProperty("fanart_image", strFanArt);
+            pItem->SetArt("fanart", strFanArt);
         }
         // increment i to j which is the next item
         i = j;
@@ -5906,7 +6029,7 @@ void CVideoDatabase::Stack(CFileItemList& items, VIDEODB_CONTENT_TYPE type, bool
         CStdString strPath = pItem->GetVideoInfoTag()->m_strPath;
         int iSeason = pItem->GetVideoInfoTag()->m_iSeason;
         int iEpisode = pItem->GetVideoInfoTag()->m_iEpisode;
-        //CStdString strFanArt = pItem->GetProperty("fanart_image");
+        //CStdString strFanArt = pItem->GetArt("fanart");
 
         // do we have a dvd folder, ie foo/VIDEO_TS.IFO or foo/VIDEO_TS/VIDEO_TS.IFO
         CStdString strFileNameAndPath = pItem->GetVideoInfoTag()->m_strFileNameAndPath;
@@ -5951,7 +6074,7 @@ void CVideoDatabase::Stack(CFileItemList& items, VIDEODB_CONTENT_TYPE type, bool
 
                 // episodes dont have fanart yet
                 //if (strFanArt.IsEmpty())
-                //  strFanArt = jItem->GetProperty("fanart_image");
+                //  strFanArt = jItem->GetArt("fanart");
 
                 paths.push_back(jFileNameAndPath);
               }
@@ -5977,7 +6100,7 @@ void CVideoDatabase::Stack(CFileItemList& items, VIDEODB_CONTENT_TYPE type, bool
 
           // episodes dont have fanart yet
           //if (!strFanArt.IsEmpty())
-          //  pItem->SetProperty("fanart_image", strFanArt);
+          //  pItem->SetArt("fanart", strFanArt);
         }
         // increment i to j which is the next item
         i = j;
@@ -6033,7 +6156,11 @@ bool CVideoDatabase::GetEpisodesNav(const CStdString& strBaseDir, CFileItemList&
     Filter movieFilter;
     movieFilter.join  = PrepareSQL("join movielinktvshow on movielinktvshow.idMovie=movieview.idMovie");
     movieFilter.where = PrepareSQL("movielinktvshow.idShow %s", strIn.c_str());
-    GetMoviesByWhere("videodb://1/2/", movieFilter, items);
+    CFileItemList movieItems;
+    GetMoviesByWhere("videodb://1/2/", movieFilter, movieItems);
+
+    if (movieItems.Size() > 0)
+      items.Append(movieItems);
   }
 
   return ret;
@@ -6058,6 +6185,8 @@ bool CVideoDatabase::GetEpisodesByWhere(const CStdString& strBaseDir, const Filt
     if (!BuildSQL(strBaseDir, strSQLExtra, extFilter, strSQLExtra, videoUrl))
       return false;
 
+    items.SetPath(videoUrl.ToString());
+
     // Apply the limiting directly here if there's no special sorting but limiting
     if (extFilter.limit.empty() &&
         sortDescription.sortBy == SortByNone &&
@@ -6105,7 +6234,7 @@ bool CVideoDatabase::GetEpisodesByWhere(const CStdString& strBaseDir, const Filt
 
         CVideoDbUrl itemUrl = videoUrl;
         CStdString path;
-        if (appendFullShowPath)
+        if (appendFullShowPath && videoUrl.GetItemType() != "episodes")
           path.Format("%ld/%ld/%ld", record->at(VIDEODB_DETAILS_EPISODE_TVSHOW_ID).get_asInt(), movie.m_iSeason, idEpisode);
         else
           path.Format("%ld", idEpisode);
@@ -6909,6 +7038,8 @@ bool CVideoDatabase::GetMusicVideosByWhere(const CStdString &baseDir, const Filt
     if (!BuildSQL(baseDir, strSQLExtra, extFilter, strSQLExtra, videoUrl))
       return false;
 
+    items.SetPath(videoUrl.ToString());
+
     // Apply the limiting directly here if there's no special sorting but limiting
     if (extFilter.limit.empty() &&
         sortDescription.sortBy == SortByNone &&
@@ -7473,7 +7604,7 @@ void CVideoDatabase::GetMusicVideoDirectorsByName(const CStdString& strSearch, C
   }
 }
 
-void CVideoDatabase::CleanDatabase(IVideoInfoScannerObserver* pObserver, const set<int>* paths)
+void CVideoDatabase::CleanDatabase(CGUIDialogProgressBarHandle* handle, const set<int>* paths)
 {
   CGUIDialogProgress *progress=NULL;
   try
@@ -7507,7 +7638,7 @@ void CVideoDatabase::CleanDatabase(IVideoInfoScannerObserver* pObserver, const s
     m_pDS->query(sql.c_str());
     if (m_pDS->num_rows() == 0) return;
 
-    if (!pObserver)
+    if (!handle)
     {
       progress = (CGUIDialogProgress *)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
       if (progress)
@@ -7523,10 +7654,8 @@ void CVideoDatabase::CleanDatabase(IVideoInfoScannerObserver* pObserver, const s
     }
     else
     {
-      pObserver->OnDirectoryChanged("");
-      pObserver->OnSetTitle("");
-      pObserver->OnSetCurrentProgress(0,1);
-      pObserver->OnStateChanged(CLEANING_UP_DATABASE);
+      handle->SetTitle(g_localizeStrings.Get(700));
+      handle->SetText("");
     }
 
     CStdString filesToDelete = "";
@@ -7569,7 +7698,7 @@ void CVideoDatabase::CleanDatabase(IVideoInfoScannerObserver* pObserver, const s
           filesToDelete += m_pDS->fv("files.idFile").get_asString() + ",";
       }
 
-      if (!pObserver)
+      if (!handle)
       {
         if (progress)
         {
@@ -7584,7 +7713,7 @@ void CVideoDatabase::CleanDatabase(IVideoInfoScannerObserver* pObserver, const s
         }
       }
       else
-        pObserver->OnSetProgress(current,total);
+        handle->SetPercentage(current/(float)total*100);
 
       m_pDS->next();
       current++;
@@ -7845,8 +7974,8 @@ void CVideoDatabase::CleanDatabase(IVideoInfoScannerObserver* pObserver, const s
 
     CommitTransaction();
 
-    if (pObserver)
-      pObserver->OnStateChanged(COMPRESSING_DATABASE);
+    if (handle)
+      handle->SetTitle(g_localizeStrings.Get(331));
 
     Compress(false);
 
@@ -8029,9 +8158,7 @@ void CVideoDatabase::ExportToXML(const CStdString &path, bool singleFiles /* = f
       }
 
       CFileItem item(movie.m_strFileNameAndPath,false);
-      CFileItem saveItem(item);
-      saveItem.SetArt(artwork);
-      if (singleFiles && CUtil::SupportsFileOperations(movie.m_strFileNameAndPath))
+      if (singleFiles && CUtil::SupportsWriteFileOperations(movie.m_strFileNameAndPath))
       {
         if (!item.Exists(false))
         {
@@ -8073,14 +8200,11 @@ void CVideoDatabase::ExportToXML(const CStdString &path, bool singleFiles /* = f
 
       if (singleFiles && images && !bSkip)
       {
-        CStdString savedThumb(saveItem.GetTBNFile());
-        if (saveItem.HasThumbnail() && (overwrite || !CFile::Exists(savedThumb, false)))
-          CTextureCache::Get().Export(saveItem.GetThumbnailImage(), savedThumb);
-
-        CStdString savedFanart(URIUtils::ReplaceExtension(savedThumb, "-fanart.jpg"));
-        if (saveItem.HasProperty("fanart_image") && (overwrite || !CFile::Exists(savedFanart, false)))
-          CTextureCache::Get().Export(saveItem.GetProperty("fanart_image").asString(), savedFanart);
-
+        for (map<string, string>::const_iterator i = artwork.begin(); i != artwork.end(); ++i)
+        {
+          CStdString savedThumb = item.GetLocalArt(i->first, false);
+          CTextureCache::Get().Export(i->second, savedThumb, overwrite);
+        }
         if (actorThumbs)
           ExportActorThumbs(actorsDir, movie, singleFiles, overwrite);
       }
@@ -8128,9 +8252,7 @@ void CVideoDatabase::ExportToXML(const CStdString &path, bool singleFiles /* = f
       }
 
       CFileItem item(movie.m_strFileNameAndPath,false);
-      CFileItem saveItem(item);
-      saveItem.SetArt(artwork);
-      if (CUtil::SupportsFileOperations(movie.m_strFileNameAndPath) && singleFiles)
+      if (CUtil::SupportsWriteFileOperations(movie.m_strFileNameAndPath) && singleFiles)
       {
         if (!item.Exists(false))
         {
@@ -8166,9 +8288,11 @@ void CVideoDatabase::ExportToXML(const CStdString &path, bool singleFiles /* = f
       }
       if (singleFiles && images && !bSkip)
       {
-        CStdString savedThumb(saveItem.GetTBNFile());
-        if (saveItem.HasThumbnail() && (overwrite || !CFile::Exists(savedThumb, false)))
-          CTextureCache::Get().Export(saveItem.GetThumbnailImage(), savedThumb);
+        for (map<string, string>::const_iterator i = artwork.begin(); i != artwork.end(); ++i)
+        {
+          CStdString savedThumb = item.GetLocalArt(i->first, false);
+          CTextureCache::Get().Export(i->second, savedThumb, overwrite);
+        }
       }
       m_pDS->next();
       current++;
@@ -8225,9 +8349,7 @@ void CVideoDatabase::ExportToXML(const CStdString &path, bool singleFiles /* = f
 
 
       CFileItem item(tvshow.m_strPath, true);
-      CFileItem saveItem(item);
-      saveItem.SetArt(artwork);
-      if (singleFiles && CUtil::SupportsFileOperations(tvshow.m_strPath))
+      if (singleFiles && CUtil::SupportsWriteFileOperations(tvshow.m_strPath))
       {
         if (!item.Exists(false))
         {
@@ -8264,13 +8386,11 @@ void CVideoDatabase::ExportToXML(const CStdString &path, bool singleFiles /* = f
       }
       if (singleFiles && images && !bSkip)
       {
-        CStdString savedThumb(saveItem.GetFolderThumb());
-        if (saveItem.HasThumbnail() && (overwrite || !CFile::Exists(savedThumb, false)))
-          CTextureCache::Get().Export(saveItem.GetThumbnailImage(), savedThumb);
-
-        CStdString savedFanart(saveItem.GetFolderThumb("fanart.jpg"));
-        if (saveItem.HasProperty("fanart_image") && (overwrite || !CFile::Exists(savedFanart, false)))
-          CTextureCache::Get().Export(saveItem.GetProperty("fanart_image").asString(), savedFanart);
+        for (map<string, string>::const_iterator i = artwork.begin(); i != artwork.end(); ++i)
+        {
+          CStdString savedThumb = item.GetLocalArt(i->first, true);
+          CTextureCache::Get().Export(i->second, savedThumb, overwrite);
+        }
 
         if (actorThumbs)
           ExportActorThumbs(actorsDir, tvshow, singleFiles, overwrite);
@@ -8280,21 +8400,21 @@ void CVideoDatabase::ExportToXML(const CStdString &path, bool singleFiles /* = f
         {
           CStdString seasonThumb;
           if (i->first == -1)
-            seasonThumb = "season-all.tbn";
+            seasonThumb = "season-all";
           else if (i->first == 0)
-            seasonThumb = "season-specials.tbn";
+            seasonThumb = "season-specials";
           else
-            seasonThumb.Format("season%02i.tbn", i->first);
-          CStdString savedThumb(saveItem.GetFolderThumb(seasonThumb));
-          if (!i->second.empty() && (overwrite || !CFile::Exists(savedThumb, false)))
-            CTextureCache::Get().Export(i->second, savedThumb);
+            seasonThumb.Format("season%02i", i->first);
+          CStdString savedThumb(item.GetLocalArt(seasonThumb, true));
+          if (!i->second.empty())
+            CTextureCache::Get().Export(i->second, savedThumb, overwrite);
         }
       }
 
       // now save the episodes from this show
       sql = PrepareSQL("select * from episodeview where idShow=%i order by strFileName, idEpisode",tvshow.m_iDbId);
       pDS->query(sql.c_str());
-      CStdString showDir(saveItem.GetPath());
+      CStdString showDir(item.GetPath());
 
       while (!pDS->eof())
       {
@@ -8325,8 +8445,6 @@ void CVideoDatabase::ExportToXML(const CStdString &path, bool singleFiles /* = f
         bool bSkip = false;
 
         CFileItem item(episode.m_strFileNameAndPath, false);
-        CFileItem saveItem(item);
-        saveItem.SetArt(artwork);
         if (singleFiles)
         {
           if (!item.Exists(false))
@@ -8364,10 +8482,11 @@ void CVideoDatabase::ExportToXML(const CStdString &path, bool singleFiles /* = f
 
         if (singleFiles && images && !bSkip)
         {
-          CStdString savedThumb(saveItem.GetTBNFile());
-          if (saveItem.HasThumbnail() && (overwrite || !CFile::Exists(savedThumb, false)))
-            CTextureCache::Get().Export(saveItem.GetThumbnailImage(), savedThumb);
-
+          for (map<string, string>::const_iterator i = artwork.begin(); i != artwork.end(); ++i)
+          {
+            CStdString savedThumb = item.GetLocalArt(i->first, false);
+            CTextureCache::Get().Export(i->second, savedThumb, overwrite);
+          }
           if (actorThumbs)
             ExportActorThumbs(actorsDir, episode, singleFiles, overwrite);
         }
@@ -8438,9 +8557,8 @@ void CVideoDatabase::ExportActorThumbs(const CStdString &strDir, const CVideoInf
     item.SetLabel(iter->strName);
     if (!iter->thumb.IsEmpty())
     {
-      CStdString thumbFile(GetSafeFile(strPath, iter->strName) + ".tbn");
-      if (overwrite || !CFile::Exists(thumbFile))
-        CTextureCache::Get().Export(iter->thumb, thumbFile);
+      CStdString thumbFile(GetSafeFile(strPath, iter->strName));
+      CTextureCache::Get().Export(iter->thumb, thumbFile, overwrite);
     }
   }
 }
@@ -8551,7 +8669,7 @@ void CVideoDatabase::ImportFromXML(const CStdString &path)
         if (ImportArtFromXML(movie->FirstChild("art"), artwork))
           item.SetArt(artwork);
         bool useFolders = info.m_basePath.IsEmpty() ? LookupByFolders(item.GetPath()) : false;
-        scanner.AddVideo(&item, CONTENT_MOVIES, useFolders, true, -1, true);
+        scanner.AddVideo(&item, CONTENT_MOVIES, useFolders, true, NULL, true);
         CStdString strFileName(info.m_strTitle);
         if (iVersion >= 1 && info.m_iYear > 0)
           strFileName.AppendFormat("_%i", info.m_iYear);
@@ -8565,7 +8683,7 @@ void CVideoDatabase::ImportFromXML(const CStdString &path)
         if (ImportArtFromXML(movie->FirstChild("art"), artwork))
           item.SetArt(artwork);
         bool useFolders = info.m_basePath.IsEmpty() ? LookupByFolders(item.GetPath()) : false;
-        scanner.AddVideo(&item, CONTENT_MUSICVIDEOS, useFolders, true, -1, true);
+        scanner.AddVideo(&item, CONTENT_MUSICVIDEOS, useFolders, true, NULL, true);
         CStdString strFileName(StringUtils::Join(info.m_artist, g_advancedSettings.m_videoItemSeparator) + "." + info.m_strTitle);
         if (iVersion >= 1 && info.m_iYear > 0)
           strFileName.AppendFormat("_%i", info.m_iYear);
@@ -8578,12 +8696,12 @@ void CVideoDatabase::ImportFromXML(const CStdString &path)
         info.Load(movie);
         URIUtils::AddSlashAtEnd(info.m_strPath);
         DeleteTvShow(info.m_strPath);
-        CFileItem item(info);
+        CFileItem showItem(info);
         map<string, string> artwork;
         if (ImportArtFromXML(movie->FirstChild("art"), artwork))
-          item.SetArt(artwork);
-        bool useFolders = info.m_basePath.IsEmpty() ? LookupByFolders(item.GetPath(), true) : false;
-        int showID = scanner.AddVideo(&item, CONTENT_TVSHOWS, useFolders, true, -1, true);
+          showItem.SetArt(artwork);
+        bool useFolders = info.m_basePath.IsEmpty() ? LookupByFolders(showItem.GetPath(), true) : false;
+        int showID = scanner.AddVideo(&showItem, CONTENT_TVSHOWS, useFolders, true, NULL, true);
         // season artwork
         TiXmlNode *art = movie->FirstChild("art");
         if (art)
@@ -8614,9 +8732,9 @@ void CVideoDatabase::ImportFromXML(const CStdString &path)
           info.Load(episode);
           CFileItem item(info);
           map<string, string> artwork;
-          if (ImportArtFromXML(movie->FirstChild("art"), artwork))
+          if (ImportArtFromXML(episode->FirstChild("art"), artwork))
             item.SetArt(artwork);
-          scanner.AddVideo(&item,CONTENT_TVSHOWS, false, false, showID, true);
+          scanner.AddVideo(&item,CONTENT_TVSHOWS, false, false, showItem.GetVideoInfoTag(), true);
           episode = episode->NextSiblingElement("episodedetails");
         }
       }
@@ -8880,7 +8998,7 @@ bool CVideoDatabase::GetItemsForPath(const CStdString &content, const CStdString
   return items.Size() > 0;
 }
 
-bool CVideoDatabase::GetFilter(const CDbUrl &videoUrl, Filter &filter)
+bool CVideoDatabase::GetFilter(CDbUrl &videoUrl, Filter &filter)
 {
   if (!videoUrl.IsValid())
     return false;
@@ -9152,7 +9270,7 @@ bool CVideoDatabase::GetFilter(const CDbUrl &videoUrl, Filter &filter)
         {
           condition = true;
           filter.AppendJoin(PrepareSQL("join actorlinktvshow on actorlinktvshow.idShow = episodeview.idShow"));
-          filter.AppendWhere(PrepareSQL("episodeview.idShow = %i and actorlinktvshow.idActor = %s", idShow, (int)option->second.asInteger()));
+          filter.AppendWhere(PrepareSQL("episodeview.idShow = %i and actorlinktvshow.idActor = %i", idShow, (int)option->second.asInteger()));
         }
 
         option = options.find("actor");
@@ -9298,5 +9416,23 @@ bool CVideoDatabase::GetFilter(const CDbUrl &videoUrl, Filter &filter)
     }
   }
 
+  option = options.find("filter");
+  if (option != options.end())
+  {
+    CSmartPlaylist xspFilter;
+    if (!xspFilter.LoadFromJson(option->second.asString()))
+      return false;
+
+    // check if the filter playlist matches the item type
+    if (xspFilter.GetType() == itemType)
+    {
+      std::set<CStdString> playlists;
+      filter.AppendWhere(xspFilter.GetWhereClause(*this, playlists));
+    }
+    // remove the filter if it doesn't match the item type
+    else
+      videoUrl.AddOption("filter", "");
+  }
+
   return true;
 }
index 16fdfca..ee87292 100644 (file)
@@ -32,6 +32,7 @@ class CFileItem;
 class CFileItemList;
 class CVideoSettings;
 class CGUIDialogProgress;
+class CGUIDialogProgressBarHandle;
 
 namespace dbiplus
 {
@@ -258,6 +259,7 @@ typedef enum // this enum MUST match the offset struct further down!! and make s
   VIDEODB_ID_EPISODE_BOOKMARK = 17,
   VIDEODB_ID_EPISODE_BASEPATH = 18,
   VIDEODB_ID_EPISODE_PARENTPATHID = 19,
+  VIDEODB_ID_EPISODE_UNIQUEID = 20,
   VIDEODB_ID_EPISODE_MAX
 } VIDEODB_EPISODE_IDS;
 
@@ -282,7 +284,8 @@ const struct SDbTableOffsets DbEpisodeOffsets[] =
   { VIDEODB_TYPE_INT, my_offsetof(CVideoInfoTag,m_iSpecialSortEpisode) },
   { VIDEODB_TYPE_INT, my_offsetof(CVideoInfoTag,m_iBookmarkId) },
   { VIDEODB_TYPE_STRING, my_offsetof(CVideoInfoTag,m_basePath) },
-  { VIDEODB_TYPE_INT, my_offsetof(CVideoInfoTag,m_parentPathID) }
+  { VIDEODB_TYPE_INT, my_offsetof(CVideoInfoTag,m_parentPathID) },
+  { VIDEODB_TYPE_STRING, my_offsetof(CVideoInfoTag,m_strUniqueId) }
 };
 
 typedef enum // this enum MUST match the offset struct further down!! and make sure to keep min and max at -1 and sizeof(offsets)
@@ -577,16 +580,16 @@ public:
   bool ArbitraryExec(const CStdString& strExec);
 
   // general browsing
-  bool GetGenresNav(const CStdString& strBaseDir, CFileItemList& items, int idContent=-1, const Filter &filter = Filter());
-  bool GetCountriesNav(const CStdString& strBaseDir, CFileItemList& items, int idContent=-1, const Filter &filter = Filter());
-  bool GetStudiosNav(const CStdString& strBaseDir, CFileItemList& items, int idContent=-1, const Filter &filter = Filter());
+  bool GetGenresNav(const CStdString& strBaseDir, CFileItemList& items, int idContent=-1, const Filter &filter = Filter(), bool countOnly = false);
+  bool GetCountriesNav(const CStdString& strBaseDir, CFileItemList& items, int idContent=-1, const Filter &filter = Filter(), bool countOnly = false);
+  bool GetStudiosNav(const CStdString& strBaseDir, CFileItemList& items, int idContent=-1, const Filter &filter = Filter(), bool countOnly = false);
   bool GetYearsNav(const CStdString& strBaseDir, CFileItemList& items, int idContent=-1, const Filter &filter = Filter());
-  bool GetActorsNav(const CStdString& strBaseDir, CFileItemList& items, int idContent=-1, const Filter &filter = Filter());
-  bool GetDirectorsNav(const CStdString& strBaseDir, CFileItemList& items, int idContent=-1, const Filter &filter = Filter());
-  bool GetWritersNav(const CStdString& strBaseDir, CFileItemList& items, int idContent=-1, const Filter &filter = Filter());
+  bool GetActorsNav(const CStdString& strBaseDir, CFileItemList& items, int idContent=-1, const Filter &filter = Filter(), bool countOnly = false);
+  bool GetDirectorsNav(const CStdString& strBaseDir, CFileItemList& items, int idContent=-1, const Filter &filter = Filter(), bool countOnly = false);
+  bool GetWritersNav(const CStdString& strBaseDir, CFileItemList& items, int idContent=-1, const Filter &filter = Filter(), bool countOnly = false);
   bool GetSetsNav(const CStdString& strBaseDir, CFileItemList& items, int idContent=-1);
-  bool GetTagsNav(const CStdString& strBaseDir, CFileItemList& items, int idContent=-1, const Filter &filter = Filter());
-  bool GetMusicVideoAlbumsNav(const CStdString& strBaseDir, CFileItemList& items, int idArtist, const Filter &filter = Filter());
+  bool GetTagsNav(const CStdString& strBaseDir, CFileItemList& items, int idContent=-1, const Filter &filter = Filter(), bool countOnly = false);
+  bool GetMusicVideoAlbumsNav(const CStdString& strBaseDir, CFileItemList& items, int idArtist, const Filter &filter = Filter(), bool countOnly = false);
 
   bool GetMoviesNav(const CStdString& strBaseDir, CFileItemList& items, int idGenre=-1, int idYear=-1, int idActor=-1, int idDirector=-1, int idStudio=-1, int idCountry=-1, int idSet=-1, int idTag=-1, const SortDescription &sortDescription = SortDescription());
   bool GetTvShowsNav(const CStdString& strBaseDir, CFileItemList& items, int idGenre=-1, int idYear=-1, int idActor=-1, int idDirector=-1, int idStudio=-1, int idTag=-1, const SortDescription &sortDescription = SortDescription());
@@ -602,7 +605,7 @@ public:
   bool HasContent(VIDEODB_CONTENT_TYPE type);
   bool HasSets() const;
 
-  void CleanDatabase(VIDEO::IVideoInfoScannerObserver* pObserver=NULL, const std::set<int>* paths=NULL);
+  void CleanDatabase(CGUIDialogProgressBarHandle* handle=NULL, const std::set<int>* paths=NULL);
 
   /*! \brief Add a file to the database, if necessary
    If the file is already in the database, we simply return its id.
@@ -686,7 +689,7 @@ public:
   void AddTagToItem(int idItem, int idTag, const std::string &type);
   void RemoveTagFromItem(int idItem, int idTag, const std::string &type);
 
-  virtual bool GetFilter(const CDbUrl &videoUrl, Filter &filter);
+  virtual bool GetFilter(CDbUrl &videoUrl, Filter &filter);
 
 protected:
   int GetMovieId(const CStdString& strFilenameAndPath);
@@ -755,8 +758,8 @@ protected:
   CVideoInfoTag GetDetailsForEpisode(const dbiplus::sql_record* const record, bool needsCast = false);
   CVideoInfoTag GetDetailsForMusicVideo(std::auto_ptr<dbiplus::Dataset> &pDS);
   CVideoInfoTag GetDetailsForMusicVideo(const dbiplus::sql_record* const record);
-  bool GetPeopleNav(const CStdString& strBaseDir, CFileItemList& items, const CStdString& type, int idContent=-1, const Filter &filter = Filter());
-  bool GetNavCommon(const CStdString& strBaseDir, CFileItemList& items, const CStdString& type, int idContent=-1, const Filter &filter = Filter());
+  bool GetPeopleNav(const CStdString& strBaseDir, CFileItemList& items, const CStdString& type, int idContent=-1, const Filter &filter = Filter(), bool countOnly = false);
+  bool GetNavCommon(const CStdString& strBaseDir, CFileItemList& items, const CStdString& type, int idContent=-1, const Filter &filter = Filter(), bool countOnly = false);
   void GetCast(const CStdString &table, const CStdString &table_id, int type_id, std::vector<SActorInfo> &cast);
 
   void GetDetailsFromDB(std::auto_ptr<dbiplus::Dataset> &pDS, int min, int max, const SDbTableOffsets *offsets, CVideoInfoTag &details, int idxOffset = 2);
index 53552c5..26f21b4 100644 (file)
@@ -31,6 +31,7 @@
 #include "VideoInfoDownloader.h"
 #include "GUIInfoManager.h"
 #include "filesystem/File.h"
+#include "dialogs/GUIDialogExtendedProgressBar.h"
 #include "dialogs/GUIDialogProgress.h"
 #include "dialogs/GUIDialogYesNo.h"
 #include "dialogs/GUIDialogOK.h"
 #include "settings/Settings.h"
 #include "utils/StringUtils.h"
 #include "guilib/LocalizeStrings.h"
+#include "guilib/GUIWindowManager.h"
 #include "utils/TimeUtils.h"
 #include "utils/log.h"
 #include "utils/URIUtils.h"
 #include "utils/Variant.h"
 #include "ThumbLoader.h"
 #include "TextureCache.h"
+#include "GUIUserMessages.h"
 #include "URL.h"
 
 using namespace std;
@@ -58,7 +61,8 @@ namespace VIDEO
   CVideoInfoScanner::CVideoInfoScanner() : CThread("CVideoInfoScanner")
   {
     m_bRunning = false;
-    m_pObserver = NULL;
+    m_handle = NULL;
+    m_showDialog = false;
     m_bCanInterrupt = false;
     m_currentItem = 0;
     m_itemCount = 0;
@@ -78,8 +82,12 @@ namespace VIDEO
 
       m_database.Open();
 
-      if (m_pObserver)
-        m_pObserver->OnStateChanged(PREPARING);
+      if (m_showDialog && !g_guiSettings.GetBool("videolibrary.backgroundupdate"))
+      {
+        CGUIDialogExtendedProgressBar* dialog =
+          (CGUIDialogExtendedProgressBar*)g_windowManager.GetWindow(WINDOW_DIALOG_EXT_PROGRESS);
+        m_handle = dialog->GetHandle(g_localizeStrings.Get(314));
+      }
 
       m_bCanInterrupt = true;
 
@@ -114,11 +122,11 @@ namespace VIDEO
       if (!bCancelled)
       {
         if (m_bClean)
-          CleanDatabase(m_pObserver,&m_pathsToClean);
+          CleanDatabase(m_handle,&m_pathsToClean);
         else
         {
-          if (m_pObserver)
-            m_pObserver->OnStateChanged(COMPRESSING_DATABASE);
+          if (m_handle)
+            m_handle->SetTitle(g_localizeStrings.Get(331));
           m_database.Compress(false);
         }
       }
@@ -130,13 +138,14 @@ namespace VIDEO
       ANNOUNCEMENT::CAnnouncementManager::Announce(ANNOUNCEMENT::VideoLibrary, "xbmc", "OnScanFinished");
       
       m_bRunning = false;
-      if (m_pObserver)
-        m_pObserver->OnFinished();
     }
     catch (...)
     {
       CLog::Log(LOGERROR, "VideoInfoScanner: Exception while scanning.");
     }
+    if (m_handle)
+      m_handle->MarkFinished();
+    m_handle = NULL;
   }
 
   void CVideoInfoScanner::Start(const CStdString& strDirectory, bool scanAll)
@@ -177,26 +186,37 @@ namespace VIDEO
     StopThread();
   }
 
-  void CVideoInfoScanner::CleanDatabase(IVideoInfoScannerObserver* pObserver /*= NULL */, const set<int>* paths /*= NULL */)
+  void CVideoInfoScanner::CleanDatabase(CGUIDialogProgressBarHandle* handle /*= NULL */, const set<int>* paths /*= NULL */)
   {
     m_bRunning = true;
     m_database.Open();
-    m_database.CleanDatabase(pObserver, paths);
+    m_database.CleanDatabase(handle, paths);
     m_database.Close();
     m_bRunning = false;
   }
 
-  void CVideoInfoScanner::SetObserver(IVideoInfoScannerObserver* pObserver)
+  static void OnDirectoryScanned(const CStdString& strDirectory)
   {
-    m_pObserver = pObserver;
+    CGUIMessage msg(GUI_MSG_DIRECTORY_SCANNED, 0, 0, 0);
+    msg.SetStringParam(strDirectory);
+    g_windowManager.SendThreadMessage(msg);
+  }
+
+  static CStdString Prettify(const CStdString& strDirectory)
+  {
+    CURL url(strDirectory);
+    CStdString strStrippedPath = url.GetWithoutUserDetails();
+    CURL::Decode(strStrippedPath);
+
+    return strStrippedPath;
   }
 
   bool CVideoInfoScanner::DoScan(const CStdString& strDirectory)
   {
-    if (m_pObserver)
+    if (m_handle)
     {
-      m_pObserver->OnDirectoryChanged(strDirectory);
-      m_pObserver->OnSetTitle(g_localizeStrings.Get(20415));
+      m_handle->SetTitle(g_localizeStrings.Get(20415));
+      m_handle->SetText(Prettify(strDirectory));
     }
 
     /*
@@ -231,8 +251,11 @@ namespace VIDEO
     CStdString hash, dbHash;
     if (content == CONTENT_MOVIES ||content == CONTENT_MUSICVIDEOS)
     {
-      if (m_pObserver)
-        m_pObserver->OnStateChanged(content == CONTENT_MOVIES ? FETCHING_MOVIE_INFO : FETCHING_MUSICVIDEO_INFO);
+      if (m_handle)
+      {
+        int str = content == CONTENT_MOVIES ? 20374:20408;
+        m_handle->SetTitle(g_localizeStrings.Get(str));
+      }
 
       CStdString fastHash = GetFastHash(strDirectory);
       if (m_database.GetPathHash(strDirectory, dbHash) && !fastHash.IsEmpty() && fastHash == dbHash)
@@ -264,8 +287,8 @@ namespace VIDEO
           else
             CLog::Log(LOGDEBUG, "VideoInfoScanner: Skipping dir '%s' due to no change", strDirectory.c_str());
           bSkip = true;
-          if (m_pObserver)
-            m_pObserver->OnDirectoryScanned(strDirectory);
+          if (m_handle)
+            OnDirectoryScanned(strDirectory);
         }
         // update the hash to a fast hash if needed
         if (CanFastHash(items) && !fastHash.IsEmpty())
@@ -274,8 +297,8 @@ namespace VIDEO
     }
     else if (content == CONTENT_TVSHOWS)
     {
-      if (m_pObserver)
-        m_pObserver->OnStateChanged(FETCHING_TVSHOW_INFO);
+      if (m_handle)
+        m_handle->SetTitle(g_localizeStrings.Get(20409));
 
       if (foundDirectly && !settings.parent_name_root)
       {
@@ -323,8 +346,8 @@ namespace VIDEO
       m_database.SetPathHash(strDirectory, hash);
     }
 
-    if (m_pObserver)
-      m_pObserver->OnDirectoryScanned(strDirectory);
+    if (m_handle)
+      OnDirectoryScanned(strDirectory);
 
     for (int i = 0; i < items.Size(); ++i)
     {
@@ -382,13 +405,8 @@ namespace VIDEO
 
       if (info2->Content() == CONTENT_MOVIES || info2->Content() == CONTENT_MUSICVIDEOS)
       {
-        if (m_pObserver)
-        {
-          m_pObserver->OnSetCurrentProgress(i, items.Size());
-          if (!pItem->m_bIsFolder && m_itemCount)
-            m_pObserver->OnSetProgress(m_currentItem++, m_itemCount);
-        }
-
+        if (m_handle)
+          m_handle->SetPercentage(i*100.f/items.Size());
       }
 
       // clear our scraper cache
@@ -619,11 +637,12 @@ namespace VIDEO
     if (m_bStop || (progress && progress->IsCanceled()))
       return INFO_CANCELLED;
 
-    if (m_pObserver)
-      m_pObserver->OnDirectoryChanged(item->GetPath());
+    if (m_handle)
+      m_handle->SetText(Prettify(item->GetPath()));
 
-    CStdString showTitle = m_database.GetTvShowTitleById(showID);
-    return OnProcessSeriesFolder(files, scraper, useLocal, showID, showTitle, progress);
+    CVideoInfoTag showInfo;
+    m_database.GetTvShowInfo("", showInfo, showID);
+    return OnProcessSeriesFolder(files, scraper, useLocal, showInfo, progress);
   }
 
   void CVideoInfoScanner::EnumerateSeriesFolder(CFileItem* item, EPISODELIST& episodeList)
@@ -640,15 +659,13 @@ namespace VIDEO
       {
         m_currentItem += numFilesInFolder;
 
-        // notify our observer of our progress
-        if (m_pObserver)
+        // update our dialog with our progress
+        if (m_handle)
         {
           if (m_itemCount>0)
-          {
-            m_pObserver->OnSetProgress(m_currentItem, m_itemCount);
-            m_pObserver->OnSetCurrentProgress(numFilesInFolder, numFilesInFolder);
-          }
-          m_pObserver->OnDirectoryScanned(item->GetPath());
+            m_handle->SetPercentage(m_currentItem*100.f/m_itemCount);
+
+          OnDirectoryScanned(item->GetPath());
         }
         return;
       }
@@ -1019,13 +1036,13 @@ namespace VIDEO
     return episodeInfo.cDate.IsValid();
   }
 
-  long CVideoInfoScanner::AddVideo(CFileItem *pItem, const CONTENT_TYPE &content, bool videoFolder /* = false */, bool useLocal /* = true */, int idShow /* = -1 */, bool libraryImport /* = false */)
+  long CVideoInfoScanner::AddVideo(CFileItem *pItem, const CONTENT_TYPE &content, bool videoFolder /* = false */, bool useLocal /* = true */, const CVideoInfoTag *showInfo /* = NULL */, bool libraryImport /* = false */)
   {
     // ensure our database is open (this can get called via other classes)
     if (!m_database.Open())
       return -1;
 
-    GetArtwork(pItem, content, videoFolder, useLocal);
+    GetArtwork(pItem, content, videoFolder, useLocal, showInfo ? showInfo->m_strPath : "");
     // ensure the art map isn't completely empty by specifying an empty thumb
     map<string, string> art = pItem->GetArt();
     if (art.empty())
@@ -1043,14 +1060,13 @@ namespace VIDEO
 
     CStdString strTitle(movieDetails.m_strTitle);
 
-    if (idShow > -1 && content == CONTENT_TVSHOWS)
+    if (showInfo && content == CONTENT_TVSHOWS)
     {
-      CStdString strShowTitle = m_database.GetTvShowTitleById(idShow);
-      strTitle.Format("%s - %ix%i - %s", strShowTitle.c_str(), movieDetails.m_iSeason, movieDetails.m_iEpisode, strTitle.c_str());
+      strTitle.Format("%s - %ix%i - %s", showInfo->m_strTitle.c_str(), movieDetails.m_iSeason, movieDetails.m_iEpisode, strTitle.c_str());
     }
 
-    if (m_pObserver)
-      m_pObserver->OnSetTitle(strTitle);
+    if (m_handle)
+      m_handle->SetText(strTitle);
 
     CLog::Log(LOGDEBUG, "VideoInfoScanner: Adding new item to %s:%s", TranslateContent(content).c_str(), pItem->GetPath().c_str());
     long lResult = -1;
@@ -1064,6 +1080,7 @@ namespace VIDEO
 
       lResult = m_database.SetDetailsForMovie(pItem->GetPath(), movieDetails, art);
       movieDetails.m_iDbId = lResult;
+      movieDetails.m_type = "movie";
 
       // setup links to shows if the linked shows are in the db
       for (unsigned int i=0; i < movieDetails.m_showLink.size(); ++i)
@@ -1085,14 +1102,18 @@ namespace VIDEO
         GetSeasonThumbs(movieDetails, seasonArt);
         lResult = m_database.SetDetailsForTvShow(pItem->GetPath(), movieDetails, art, seasonArt);
         movieDetails.m_iDbId = lResult;
+        movieDetails.m_type = "tvshow";
       }
       else
       {
         // we add episode then set details, as otherwise set details will delete the
         // episode then add, which breaks multi-episode files.
+        int idShow = showInfo ? showInfo->m_iDbId : -1;
         int idEpisode = m_database.AddEpisode(idShow, pItem->GetPath());
         lResult = m_database.SetDetailsForEpisode(pItem->GetPath(), movieDetails, art, idShow, idEpisode);
         movieDetails.m_iDbId = lResult;
+        movieDetails.m_type = "episode";
+        movieDetails.m_strShowTitle = showInfo ? showInfo->m_strTitle : "";
         if (movieDetails.m_fEpBookmark > 0)
         {
           movieDetails.m_strFileNameAndPath = pItem->GetPath();
@@ -1108,6 +1129,7 @@ namespace VIDEO
     {
       lResult = m_database.SetDetailsForMusicVideo(pItem->GetPath(), movieDetails, art);
       movieDetails.m_iDbId = lResult;
+      movieDetails.m_type = "musicvideo";
     }
 
     if (g_advancedSettings.m_bVideoLibraryImportWatchedState || libraryImport)
@@ -1120,64 +1142,84 @@ namespace VIDEO
     m_database.Close();
 
     CFileItemPtr itemCopy = CFileItemPtr(new CFileItem(*pItem));
-    // Hack to make sure CVideoInfoTag::m_strShowTitle is set for tvshows
-    // to make sure CAnnouncementManager provides the correct type for the item
-    if (content == CONTENT_TVSHOWS && !pItem->m_bIsFolder && itemCopy->HasVideoInfoTag())
-      itemCopy->GetVideoInfoTag()->m_strShowTitle = itemCopy->GetVideoInfoTag()->m_strTitle;
     ANNOUNCEMENT::CAnnouncementManager::Announce(ANNOUNCEMENT::VideoLibrary, "xbmc", "OnUpdate", itemCopy);
     return lResult;
   }
 
-  void CVideoInfoScanner::GetArtwork(CFileItem *pItem, const CONTENT_TYPE &content, bool bApplyToDir, bool useLocal)
+  string ContentToMediaType(CONTENT_TYPE content, bool folder)
+  {
+    switch (content)
+    {
+      case CONTENT_MOVIES:
+        return "movie";
+      case CONTENT_MUSICVIDEOS:
+        return "musicvideo";
+      case CONTENT_TVSHOWS:
+        return folder ? "tvshow" : "episode";
+      default:
+        return "";
+    }
+  }
+
+  void CVideoInfoScanner::GetArtwork(CFileItem *pItem, const CONTENT_TYPE &content, bool bApplyToDir, bool useLocal, const std::string &actorArtPath)
   {
     CVideoInfoTag &movieDetails = *pItem->GetVideoInfoTag();
     movieDetails.m_fanart.Unpack();
     movieDetails.m_strPictureURL.Parse();
 
-    // get & save fanart image
+    CGUIListItem::ArtMap art;
+    // get & save fanart image (treated separately due to it being stored in m_fanart)
     bool isEpisode = (content == CONTENT_TVSHOWS && !pItem->m_bIsFolder);
     if (!isEpisode)
     {
-      CStdString fanart;
-      if (pItem->HasProperty("fanart_image"))
-        fanart = pItem->GetProperty("fanart_image").asString();
-      else if (useLocal)
-        fanart = pItem->GetLocalFanart();
+      CStdString fanart = pItem->GetArt("fanart");
+      if (fanart.empty() && useLocal)
+        fanart = pItem->FindLocalArt("fanart.jpg", true);
       if (fanart.IsEmpty())
         fanart = movieDetails.m_fanart.GetImageURL();
       if (!fanart.IsEmpty())
-      {
-        CTextureCache::Get().BackgroundCacheImage(fanart);
-        pItem->SetProperty("fanart_image", fanart);
-      }
+        art.insert(make_pair("fanart", fanart));
     }
 
-    // get and cache thumb image
-    CStdString thumb;
-    if (pItem->HasThumbnail())
-      thumb = pItem->GetThumbnailImage();
-    else if (useLocal)
+    // get and cache thumb images
+    vector<string> artTypes = CVideoThumbLoader::GetArtTypes(ContentToMediaType(content, pItem->m_bIsFolder));
+    for (vector<string>::const_iterator i = artTypes.begin(); i != artTypes.end(); ++i)
     {
-      thumb = pItem->GetUserVideoThumb();
-      if (bApplyToDir && thumb.IsEmpty())
-      {
-        CStdString strParent;
-        URIUtils::GetParentPath(pItem->GetPath(), strParent);
-        CFileItem folderItem(*pItem);
-        folderItem.SetPath(strParent);
-        folderItem.m_bIsFolder = true;
-        thumb = folderItem.GetUserVideoThumb();
-      }
+      string type = *i;
+      if (type == "fanart")
+        continue; // handled above
+      std::string image = GetImage(pItem, useLocal, bApplyToDir, type);
+      if (!image.empty())
+        art.insert(make_pair(type, image));
     }
 
-    if (thumb.IsEmpty())
+    for (CGUIListItem::ArtMap::const_iterator i = art.begin(); i != art.end(); ++i)
+      CTextureCache::Get().BackgroundCacheImage(i->second);
+
+    pItem->SetArt(art);
+
+    // parent folder to apply the thumb to and to search for local actor thumbs
+    CStdString parentDir = GetParentDir(*pItem);
+    if (g_guiSettings.GetBool("videolibrary.actorthumbs"))
+      FetchActorThumbs(movieDetails.m_cast, actorArtPath.empty() ? parentDir : actorArtPath);
+    if (bApplyToDir)
+      ApplyThumbToFolder(parentDir, art["thumb"]);
+  }
+
+  std::string CVideoInfoScanner::GetImage(CFileItem *pItem, bool useLocal, bool bApplyToDir, const std::string &type)
+  {
+    std::string thumb;
+    if (useLocal)
+      thumb = CVideoThumbLoader::GetLocalArt(*pItem, type, bApplyToDir);
+
+    if (thumb.empty())
     {
-      thumb = CScraperUrl::GetThumbURL(movieDetails.m_strPictureURL.GetFirstThumb());
-      if (!thumb.IsEmpty())
+      thumb = CScraperUrl::GetThumbURL(pItem->GetVideoInfoTag()->m_strPictureURL.GetFirstThumb(type));
+      if (!thumb.empty())
       {
-        if (thumb.Find("http://") < 0 &&
-            thumb.Find("/") < 0 &&
-            thumb.Find("\\") < 0)
+        if (thumb.find("http://") == string::npos &&
+            thumb.find("/") == string::npos &&
+            thumb.find("\\") == string::npos)
         {
           CStdString strPath;
           URIUtils::GetDirectory(pItem->GetPath(), strPath);
@@ -1185,25 +1227,14 @@ namespace VIDEO
         }
       }
     }
-    if (!thumb.IsEmpty())
-    {
-      CTextureCache::Get().BackgroundCacheImage(thumb);
-      pItem->SetThumbnailImage(thumb);
-    }
-
-    // parent folder to apply the thumb to and to search for local actor thumbs
-    CStdString parentDir = GetParentDir(*pItem);
-    if (g_guiSettings.GetBool("videolibrary.actorthumbs"))
-      FetchActorThumbs(movieDetails.m_cast, parentDir);
-    if (bApplyToDir)
-      ApplyThumbToFolder(parentDir, thumb);
+    return thumb;
   }
 
-  INFO_RET CVideoInfoScanner::OnProcessSeriesFolder(EPISODELIST& files, const ADDON::ScraperPtr &scraper, bool useLocal, int idShow, const CStdString& strShowTitle, CGUIDialogProgress* pDlgProgress /* = NULL */)
+  INFO_RET CVideoInfoScanner::OnProcessSeriesFolder(EPISODELIST& files, const ADDON::ScraperPtr &scraper, bool useLocal, const CVideoInfoTag& showInfo, CGUIDialogProgress* pDlgProgress /* = NULL */)
   {
     if (pDlgProgress)
     {
-      pDlgProgress->SetLine(1, strShowTitle);
+      pDlgProgress->SetLine(1, showInfo.m_strTitle);
       pDlgProgress->SetLine(2, 20361);
       pDlgProgress->SetPercentage(0);
       pDlgProgress->ShowProgressBar(true);
@@ -1224,19 +1255,16 @@ namespace VIDEO
         pDlgProgress->SetPercentage((int)((float)(iCurr++)/iMax*100));
         pDlgProgress->Progress();
       }
-      if (m_pObserver)
-      {
-        if (m_itemCount > 0)
-          m_pObserver->OnSetProgress(m_currentItem++, m_itemCount);
-        m_pObserver->OnSetCurrentProgress(iCurr++, iMax);
-      }
+      if (m_handle)
+        m_handle->SetPercentage(100.f*iCurr++/iMax);
+
       if ((pDlgProgress && pDlgProgress->IsCanceled()) || m_bStop)
         return INFO_CANCELLED;
 
       if (m_database.GetEpisodeId(file->strPath, file->iEpisode, file->iSeason) > -1)
       {
-        if (m_pObserver)
-          m_pObserver->OnSetTitle(g_localizeStrings.Get(20415));
+        if (m_handle)
+          m_handle->SetTitle(g_localizeStrings.Get(20415));
         continue;
       }
 
@@ -1253,7 +1281,7 @@ namespace VIDEO
       if (result == CNfoFile::FULL_NFO)
       {
         m_nfoReader.GetDetails(*item.GetVideoInfoTag());
-        if (AddVideo(&item, CONTENT_TVSHOWS, file->isFolder, true, idShow) < 0)
+        if (AddVideo(&item, CONTENT_TVSHOWS, file->isFolder, true, &showInfo) < 0)
           return INFO_ERROR;
         continue;
       }
@@ -1261,12 +1289,10 @@ namespace VIDEO
       if (!hasEpisodeGuide)
       {
         // fetch episode guide
-        CVideoInfoTag details;
-        m_database.GetTvShowInfo(item.GetPath(), details, idShow);
-        if (!details.m_strEpisodeGuide.IsEmpty())
+        if (!showInfo.m_strEpisodeGuide.IsEmpty())
         {
           CScraperUrl url;
-          url.ParseEpisodeGuide(details.m_strEpisodeGuide);
+          url.ParseEpisodeGuide(showInfo.m_strEpisodeGuide);
 
           if (pDlgProgress)
           {
@@ -1353,7 +1379,7 @@ namespace VIDEO
             guide = candidates->begin() + index;
             bFound = true;
             CLog::Log(LOGDEBUG,"%s fuzzy title match for show: '%s', title: '%s', match: '%s', score: %f >= %f",
-                      __FUNCTION__, strShowTitle.c_str(), file->strTitle.c_str(), titles[index].c_str(), matchscore, minscore);
+                      __FUNCTION__, showInfo.m_strTitle.c_str(), file->strTitle.c_str(), titles[index].c_str(), matchscore, minscore);
           }
         }
       }
@@ -1372,13 +1398,13 @@ namespace VIDEO
         if (item.GetVideoInfoTag()->m_iEpisode == -1)
           item.GetVideoInfoTag()->m_iEpisode = guide->iEpisode;
           
-        if (AddVideo(&item, CONTENT_TVSHOWS, file->isFolder, useLocal, idShow) < 0)
+        if (AddVideo(&item, CONTENT_TVSHOWS, file->isFolder, useLocal, &showInfo) < 0)
           return INFO_ERROR;
       }
       else
       {
         CLog::Log(LOGDEBUG,"%s - no match for show: '%s', season: %d, episode: %d.%d, airdate: '%s', title: '%s'",
-                  __FUNCTION__, strShowTitle.c_str(), file->iSeason, file->iEpisode, file->iSubepisode,
+                  __FUNCTION__, showInfo.m_strTitle.c_str(), file->iSeason, file->iEpisode, file->iSubepisode,
                   file->cDate.GetAsLocalizedDate().c_str(), file->strTitle.c_str());
       }
     }
@@ -1510,8 +1536,8 @@ namespace VIDEO
       if (nfoFile)
         nfoFile->GetDetails(movieDetails,NULL,true);
 
-      if (m_pObserver && url.strTitle.IsEmpty())
-        m_pObserver->OnSetTitle(movieDetails.m_strTitle);
+      if (m_handle && url.strTitle.IsEmpty())
+        m_handle->SetText(movieDetails.m_strTitle);
 
       if (pDialog)
       {
@@ -1590,26 +1616,26 @@ namespace VIDEO
     if (useLocal)
     {
       CFileItemList items;
-      CDirectory::GetDirectory(show.m_strPath, items, ".tbn");
+      CDirectory::GetDirectory(show.m_strPath, items, ".png|.jpg|.tbn", DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_NO_FILE_INFO);
       // run through all these items and see which ones match
       CRegExp reg;
-      if (items.Size() && reg.RegComp("season[ ._-]?([0-9]+)\\.tbn"))
+      if (items.Size() && reg.RegComp("season[ ._-]?([0-9]+)\\.(tbn|jpg|png)"))
       {
         for (int i = 0; i < items.Size(); i++)
         {
           CStdString name = URIUtils::GetFileName(items[i]->GetPath());
-          name.ToLower();
-          if (name == "season-all.tbn")
-            art.insert(make_pair(-1, items[i]->GetPath()));
-          else if (name == "season-specials.tbn")
-            art.insert(make_pair(0, items[i]->GetPath()));
+          URIUtils::RemoveExtension(name);
+          if (name == "season-all")
+            art[-1] = items[i]->GetPath();
+          else if (name == "season-specials")
+            art[0] = items[i]->GetPath();
           else if (reg.RegFind(name) > -1)
           {
             char* seasonStr = reg.GetReplaceString("\\1");
             int season = atoi(seasonStr);
             free(seasonStr);
 
-            art.insert(make_pair(season, items[i]->GetPath()));
+            art[season] = items[i]->GetPath();
           }
         }
       }
@@ -1621,17 +1647,25 @@ namespace VIDEO
 
   void CVideoInfoScanner::FetchActorThumbs(vector<SActorInfo>& actors, const CStdString& strPath)
   {
+    CFileItemList items;
+    CDirectory::GetDirectory(URIUtils::AddFileToFolder(strPath, ".actors"), items, ".png|.jpg|.tbn", DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_NO_FILE_INFO);
     for (vector<SActorInfo>::iterator i = actors.begin(); i != actors.end(); ++i)
     {
       if (i->thumb.IsEmpty())
       {
         CStdString thumbFile = i->strName;
         thumbFile.Replace(" ","_");
-        thumbFile += ".tbn";
-        CStdString strLocal = URIUtils::AddFileToFolder(URIUtils::AddFileToFolder(strPath, ".actors"), thumbFile);
-        if (CFile::Exists(strLocal))
-          i->thumb = strLocal;
-        else if (!i->thumbUrl.GetFirstThumb().m_url.IsEmpty())
+        for (int j = 0; j < items.Size(); j++)
+        {
+          CStdString compare = URIUtils::GetFileName(items[j]->GetPath());
+          URIUtils::RemoveExtension(compare);
+          if (!items[j]->m_bIsFolder && compare == thumbFile)
+          {
+            i->thumb = compare;
+            break;
+          }
+        }
+        if (i->thumb.IsEmpty() && !i->thumbUrl.GetFirstThumb().m_url.IsEmpty())
           i->thumb = CScraperUrl::GetThumbURL(i->thumbUrl.GetFirstThumb());
         if (!i->thumb.IsEmpty())
           CTextureCache::Get().BackgroundCacheImage(i->thumb);
index 4aaa342..0a45187 100644 (file)
@@ -37,21 +37,6 @@ namespace VIDEO
     bool exclude;           /* exclude this path from scraping */
   } SScanSettings;
 
-  enum SCAN_STATE { PREPARING = 0, REMOVING_OLD, CLEANING_UP_DATABASE, FETCHING_MOVIE_INFO, FETCHING_MUSICVIDEO_INFO, FETCHING_TVSHOW_INFO, COMPRESSING_DATABASE, WRITING_CHANGES };
-
-  class IVideoInfoScannerObserver
-  {
-  public:
-    virtual ~IVideoInfoScannerObserver() { }
-    virtual void OnStateChanged(SCAN_STATE state) = 0;
-    virtual void OnDirectoryChanged(const CStdString& strDirectory) = 0;
-    virtual void OnDirectoryScanned(const CStdString& strDirectory) = 0;
-    virtual void OnSetProgress(int currentItem, int itemCount)=0;
-    virtual void OnSetCurrentProgress(int currentItem, int itemCount)=0;
-    virtual void OnSetTitle(const CStdString& strTitle) = 0;
-    virtual void OnFinished() = 0;
-  };
-
   /*! \brief return values from the information lookup functions
    */
   enum INFO_RET { INFO_CANCELLED,
@@ -73,20 +58,22 @@ namespace VIDEO
      */
     void Start(const CStdString& strDirectory, bool scanAll = false);
     bool IsScanning();
-    void CleanDatabase(IVideoInfoScannerObserver* pObserver=NULL, const std::set<int>* paths=NULL);
+    void CleanDatabase(CGUIDialogProgressBarHandle* handle=NULL, const std::set<int>* paths=NULL);
     void Stop();
-    void SetObserver(IVideoInfoScannerObserver* pObserver);
+
+    //! \brief Set whether or not to show a progress dialog
+    void ShowDialog(bool show) { m_showDialog = show; }
 
     /*! \brief Add an item to the database.
      \param pItem item to add to the database.
      \param content content type of the item.
      \param videoFolder whether the video is represented by a folder (single movie per folder). Defaults to false.
      \param useLocal whether to use local information for artwork etc.
-     \param idShow database id of the tvshow if we're adding an episode.  Defaults to -1.
+     \param showInfo pointer to CVideoInfoTag details for the show if this is an episode. Defaults to NULL.
      \param libraryImport Whether this call belongs to a full library import or not. Defaults to false.
      \return database id of the added item, or -1 on failure.
      */
-    long AddVideo(CFileItem *pItem, const CONTENT_TYPE &content, bool videoFolder = false, bool useLocal = true, int idShow = -1, bool libraryImport = false);
+    long AddVideo(CFileItem *pItem, const CONTENT_TYPE &content, bool videoFolder = false, bool useLocal = true, const CVideoInfoTag *showInfo = NULL, bool libraryImport = false);
 
     /*! \brief Retrieve information for a list of items and add them to the database.
      \param items list of items to retrieve info for.
@@ -109,8 +96,9 @@ namespace VIDEO
      \param content content type of the item.
      \param bApplyToDir whether we should apply any thumbs to a folder.  Defaults to false.
      \param useLocal whether we should use local thumbs. Defaults to true.
+     \param actorArtPath the path to search for actor thumbs. Defaults to empty.
      */
-    void GetArtwork(CFileItem *pItem, const CONTENT_TYPE &content, bool bApplyToDir=false, bool useLocal=true);
+    void GetArtwork(CFileItem *pItem, const CONTENT_TYPE &content, bool bApplyToDir=false, bool useLocal=true, const std::string &actorArtPath = "");
 
     /*! \brief Get season thumbs for a tvshow.
      All seasons (regardless of whether the user has episodes) are added to the art map.
@@ -119,6 +107,7 @@ namespace VIDEO
      \param useLocal whether to use local thumbs, defaults to true
      */
     static void GetSeasonThumbs(const CVideoInfoTag &show, std::map<int, std::string> &art, bool useLocal = true);
+    static std::string GetImage(CFileItem *pItem, bool useLocal, bool bApplyToDir, const std::string &type = "");
 
   protected:
     virtual void Process();
@@ -205,13 +194,12 @@ namespace VIDEO
      the episodes. INFO_ADDED then indicates we've added one or more episodes.
      \param files the episode files to process.
      \param scraper scraper to use for finding online info
-     \param idShow the database id of the show.
-     \param strShowTitle the title of the show.
+     \param showInfo information for the show.
      \param pDlgProcess progress dialog to update during processing.  Defaults to NULL.
      \return INFO_ERROR on failure, INFO_CANCELLED on cancellation,
      INFO_NOT_FOUND if an episode isn't found, or INFO_ADDED if all episodes are added.
      */
-    INFO_RET OnProcessSeriesFolder(EPISODELIST& files, const ADDON::ScraperPtr &scraper, bool useLocal, int idShow, const CStdString& strShowTitle, CGUIDialogProgress* pDlgProgress = NULL);
+    INFO_RET OnProcessSeriesFolder(EPISODELIST& files, const ADDON::ScraperPtr &scraper, bool useLocal, const CVideoInfoTag& showInfo, CGUIDialogProgress* pDlgProgress = NULL);
 
     void EnumerateSeriesFolder(CFileItem* item, EPISODELIST& episodeList);
     bool EnumerateEpisodeItem(const CFileItemPtr item, EPISODELIST& episodeList);
@@ -225,7 +213,8 @@ namespace VIDEO
      */
     CStdString GetParentDir(const CFileItem &item) const;
 
-    IVideoInfoScannerObserver* m_pObserver;
+    bool m_showDialog;
+    CGUIDialogProgressBarHandle* m_handle;
     int m_currentItem;
     int m_itemCount;
     bool m_bRunning;
index 7878aca..2aca636 100644 (file)
@@ -70,6 +70,7 @@ void CVideoInfoTag::Reset()
   m_iYear = 0;
   m_iSeason = -1;
   m_iEpisode = -1;
+  m_strUniqueId.clear();
   m_iSpecialSortSeason = -1;
   m_iSpecialSortEpisode = -1;
   m_fRating = 0.0f;
@@ -120,6 +121,7 @@ bool CVideoInfoTag::Save(TiXmlNode *node, const CStdString &tag, bool savePathIn
   {
     XMLUtils::SetInt(movie, "season", m_iSeason);
     XMLUtils::SetInt(movie, "episode", m_iEpisode);
+    XMLUtils::SetString(movie, "uniqueid", m_strUniqueId);
     XMLUtils::SetInt(movie, "displayseason",m_iSpecialSortSeason);
     XMLUtils::SetInt(movie, "displayepisode",m_iSpecialSortEpisode);
   }
@@ -314,6 +316,7 @@ void CVideoInfoTag::Archive(CArchive& ar)
     ar << m_iYear;
     ar << m_iSeason;
     ar << m_iEpisode;
+    ar << m_strUniqueId;
     ar << m_fRating;
     ar << m_iDbId;
     ar << m_iFileId;
@@ -391,6 +394,7 @@ void CVideoInfoTag::Archive(CArchive& ar)
     ar >> m_iYear;
     ar >> m_iSeason;
     ar >> m_iEpisode;
+    ar >> m_strUniqueId;
     ar >> m_fRating;
     ar >> m_iDbId;
     ar >> m_iFileId;
@@ -464,6 +468,7 @@ void CVideoInfoTag::Serialize(CVariant& value) const
   value["year"] = m_iYear;
   value["season"] = m_iSeason;
   value["episode"] = m_iEpisode;
+  value["uniqueid"]["unknown"] = m_strUniqueId;
   value["rating"] = m_fRating;
   value["dbid"] = m_iDbId;
   value["fileid"] = m_iFileId;
@@ -570,6 +575,7 @@ void CVideoInfoTag::ParseNative(const TiXmlElement* movie, bool prioritise)
   XMLUtils::GetInt(movie, "season", m_iSeason);
   XMLUtils::GetInt(movie, "episode", m_iEpisode);
   XMLUtils::GetInt(movie, "track", m_iTrack);
+  XMLUtils::GetString(movie, "uniqueid", m_strUniqueId);
   XMLUtils::GetInt(movie, "displayseason", m_iSpecialSortSeason);
   XMLUtils::GetInt(movie, "displayepisode", m_iSpecialSortEpisode);
   int after=0;
index ef3fb06..5ac8946 100644 (file)
@@ -120,6 +120,7 @@ public:
   int m_iYear;
   int m_iSeason;
   int m_iEpisode;
+  CStdString m_strUniqueId;
   int m_iDbId;
   int m_iFileId;
   int m_iSpecialSortSeason;
index 1b280e6..acaf595 100644 (file)
@@ -73,33 +73,47 @@ void CGUIDialogAudioSubtitleSettings::CreateSettings()
 {
   m_usePopupSliders = g_SkinInfo->HasSkinFile("DialogSlider.xml");
 
+  if (g_application.m_pPlayer)
+  {
+    g_application.m_pPlayer->GetAudioCapabilities(m_audioCaps);
+    g_application.m_pPlayer->GetSubtitleCapabilities(m_subCaps);
+  }
+
   // clear out any old settings
   m_settings.clear();
   // create our settings
   m_volume = g_settings.m_fVolumeLevel;
   AddSlider(AUDIO_SETTINGS_VOLUME, 13376, &m_volume, VOLUME_MINIMUM, VOLUME_MAXIMUM / 100.0f, VOLUME_MAXIMUM, PercentAsDecibel, false);
-  AddSlider(AUDIO_SETTINGS_VOLUME_AMPLIFICATION, 660, &g_settings.m_currentVideoSettings.m_VolumeAmplification, VOLUME_DRC_MINIMUM * 0.01f, (VOLUME_DRC_MAXIMUM - VOLUME_DRC_MINIMUM) / 6000.0f, VOLUME_DRC_MAXIMUM * 0.01f, FormatDecibel, false);
+  if (SupportsAudioFeature(IPC_AUD_AMP))
+    AddSlider(AUDIO_SETTINGS_VOLUME_AMPLIFICATION, 660, &g_settings.m_currentVideoSettings.m_VolumeAmplification, VOLUME_DRC_MINIMUM * 0.01f, (VOLUME_DRC_MAXIMUM - VOLUME_DRC_MINIMUM) / 6000.0f, VOLUME_DRC_MAXIMUM * 0.01f, FormatDecibel, false);
   if (g_application.m_pPlayer && g_application.m_pPlayer->IsPassthrough())
   {
     EnableSettings(AUDIO_SETTINGS_VOLUME,false);
     EnableSettings(AUDIO_SETTINGS_VOLUME_AMPLIFICATION,false);
   }
-  AddSlider(AUDIO_SETTINGS_DELAY, 297, &g_settings.m_currentVideoSettings.m_AudioDelay, -g_advancedSettings.m_videoAudioDelayRange, .025f, g_advancedSettings.m_videoAudioDelayRange, FormatDelay);
-  AddAudioStreams(AUDIO_SETTINGS_STREAM);
+  if (SupportsAudioFeature(IPC_AUD_OFFSET))
+    AddSlider(AUDIO_SETTINGS_DELAY, 297, &g_settings.m_currentVideoSettings.m_AudioDelay, -g_advancedSettings.m_videoAudioDelayRange, .025f, g_advancedSettings.m_videoAudioDelayRange, FormatDelay);
+  if (SupportsAudioFeature(IPC_AUD_SELECT_STREAM))
+    AddAudioStreams(AUDIO_SETTINGS_STREAM);
 
   // only show stuff available in digital mode if we have digital output
-  AddBool(AUDIO_SETTINGS_OUTPUT_TO_ALL_SPEAKERS, 252, &g_settings.m_currentVideoSettings.m_OutputToAllSpeakers, AUDIO_IS_BITSTREAM(g_guiSettings.GetInt("audiooutput.mode")));
+  if (SupportsAudioFeature(IPC_AUD_OUTPUT_STEREO))
+    AddBool(AUDIO_SETTINGS_OUTPUT_TO_ALL_SPEAKERS, 252, &g_settings.m_currentVideoSettings.m_OutputToAllSpeakers, AUDIO_IS_BITSTREAM(g_guiSettings.GetInt("audiooutput.mode")));
 
   int settings[3] = { 338, 339, 420 }; //ANALOG, IEC958, HDMI
   m_outputmode = g_guiSettings.GetInt("audiooutput.mode");
-  AddSpin(AUDIO_SETTINGS_DIGITAL_ANALOG, 337, &m_outputmode, 3, settings);
+  if (SupportsAudioFeature(IPC_AUD_SELECT_OUTPUT))
+    AddSpin(AUDIO_SETTINGS_DIGITAL_ANALOG, 337, &m_outputmode, 3, settings);
 
   AddSeparator(7);
   m_subtitleVisible = g_application.m_pPlayer->GetSubtitleVisible();
   AddBool(SUBTITLE_SETTINGS_ENABLE, 13397, &m_subtitleVisible);
-  AddSlider(SUBTITLE_SETTINGS_DELAY, 22006, &g_settings.m_currentVideoSettings.m_SubtitleDelay, -g_advancedSettings.m_videoSubsDelayRange, 0.1f, g_advancedSettings.m_videoSubsDelayRange, FormatDelay);
-  AddSubtitleStreams(SUBTITLE_SETTINGS_STREAM);
-  AddButton(SUBTITLE_SETTINGS_BROWSER,13250);
+  if (SupportsSubtitleFeature(IPC_SUBS_OFFSET))
+    AddSlider(SUBTITLE_SETTINGS_DELAY, 22006, &g_settings.m_currentVideoSettings.m_SubtitleDelay, -g_advancedSettings.m_videoSubsDelayRange, 0.1f, g_advancedSettings.m_videoSubsDelayRange, FormatDelay);
+  if (SupportsSubtitleFeature(IPC_SUBS_SELECT))
+    AddSubtitleStreams(SUBTITLE_SETTINGS_STREAM);
+  if (SupportsSubtitleFeature(IPC_SUBS_EXTERNAL))
+    AddButton(SUBTITLE_SETTINGS_BROWSER,13250);
   AddButton(AUDIO_SETTINGS_MAKE_DEFAULT, 12376);
 }
 
@@ -394,3 +408,22 @@ CStdString CGUIDialogAudioSubtitleSettings::FormatDelay(float value, float inter
   return text;
 }
 
+bool CGUIDialogAudioSubtitleSettings::SupportsAudioFeature(int feature)
+{
+  for (Features::iterator itr = m_audioCaps.begin(); itr != m_audioCaps.end(); itr++)
+  {
+    if(*itr == feature || *itr == IPC_AUD_ALL)
+      return true;
+  }
+  return false;
+}
+
+bool CGUIDialogAudioSubtitleSettings::SupportsSubtitleFeature(int feature)
+{
+  for (Features::iterator itr = m_subCaps.begin(); itr != m_subCaps.end(); itr++)
+  {
+    if(*itr == feature || *itr == IPC_SUBS_ALL)
+      return true;
+  }
+  return false;
+}
index 84a5898..5414905 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 #include "settings/GUIDialogSettings.h"
+typedef std::vector<int> Features;
 
 class CGUIDialogAudioSubtitleSettings :
       public CGUIDialogSettings
@@ -40,10 +41,14 @@ protected:
 
   void AddAudioStreams(unsigned int id);
   void AddSubtitleStreams(unsigned int id);
+  bool SupportsAudioFeature(int feature);
+  bool SupportsSubtitleFeature(int feature);
 
   float m_volume;
   int m_audioStream;
   int m_subtitleStream;
   int m_outputmode;
   bool m_subtitleVisible;
+  Features m_audioCaps;
+  Features m_subCaps;
 };
index a23d156..e173ad0 100644 (file)
@@ -194,7 +194,7 @@ void CGUIDialogVideoBookmarks::Update()
       bookmarkTime = StringUtils::SecondsToTimeString((long)m_bookmarks[i].timeInSeconds, TIME_FORMAT_HH_MM_SS);
 
     CFileItemPtr item(new CFileItem(bookmarkTime));
-    item->SetThumbnailImage(m_bookmarks[i].thumbNailImage);
+    item->SetArt("thumb", m_bookmarks[i].thumbNailImage);
     m_vecItems->Add(item);
   }
   m_viewControl.SetItems(*m_vecItems);
index 5d03dcb..bbec3a5 100644 (file)
@@ -167,7 +167,7 @@ bool CGUIDialogVideoInfo::OnMessage(CGUIMessage& message)
       }
       else if (iControl == CONTROL_BTN_GET_THUMB)
       {
-        OnGetThumb();
+        OnGetArt();
       }
       else if (iControl == CONTROL_BTN_PLAY_TRAILER)
       {
@@ -211,8 +211,8 @@ bool CGUIDialogVideoInfo::OnMessage(CGUIMessage& message)
         CFileItemPtr item = boost::static_pointer_cast<CFileItem>(message.GetItem());
         if (item && m_movieItem->GetPath().Equals(item->GetPath()))
         { // Just copy over the stream details and the thumb if we don't already have one
-          if (!m_movieItem->HasThumbnail())
-            m_movieItem->SetThumbnailImage(item->GetThumbnailImage());
+          if (!m_movieItem->HasArt("thumb"))
+            m_movieItem->SetArt("thumb", item->GetArt("thumb"));
           m_movieItem->GetVideoInfoTag()->m_streamDetails = item->GetVideoInfoTag()->m_streamDetails;
         }
         return true;
@@ -243,7 +243,7 @@ void CGUIDialogVideoInfo::SetMovie(const CFileItem *item)
       CStdString thumb = database.GetArtForItem(idArtist, "artist", "thumb");
       CFileItemPtr item(new CFileItem(*it));
       if (!thumb.empty())
-        item->SetThumbnailImage(thumb);
+        item->SetArt("thumb", thumb);
       item->SetIconImage("DefaultArtist.png");
       m_castList->Add(item);
     }
@@ -260,13 +260,13 @@ void CGUIDialogVideoInfo::SetMovie(const CFileItem *item)
         character.Format("%s %s %s", it->strName.c_str(), g_localizeStrings.Get(20347).c_str(), it->strRole.c_str());
       CFileItemPtr item(new CFileItem(it->strName));
       if (!it->thumb.IsEmpty())
-        item->SetThumbnailImage(it->thumb);
+        item->SetArt("thumb", it->thumb);
       else if (g_guiSettings.GetBool("videolibrary.actorthumbs"))
       { // backward compatibility
         CStdString thumb = CScraperUrl::GetThumbURL(it->thumbUrl.GetFirstThumb());
         if (!thumb.IsEmpty())
         {
-          item->SetThumbnailImage(thumb);
+          item->SetArt("thumb", thumb);
           CTextureCache::Get().BackgroundCacheImage(thumb);
         }
       }
@@ -308,7 +308,7 @@ void CGUIDialogVideoInfo::SetMovie(const CFileItem *item)
                                       m_movieItem->GetVideoInfoTag()->m_iSeason);
           string thumb = db.GetArtForItem(seasonID, "season", "thumb");
           if (!thumb.empty())
-            m_movieItem->SetProperty("seasonthumb", thumb);
+            m_movieItem->SetArt("seasonthumb", thumb);
         }
         db.Close();
       }
@@ -395,7 +395,7 @@ void CGUIDialogVideoInfo::Update()
   {
     CGUIImage* pImageControl = (CGUIImage*)pControl;
     pImageControl->FreeResources();
-    pImageControl->SetFileName(m_movieItem->GetThumbnailImage());
+    pImageControl->SetFileName(m_movieItem->GetArt("thumb"));
   }
   // tell our GUI to completely reload all controls (as some of them
   // are likely to have had this image in use so will need refreshing)
@@ -587,43 +587,76 @@ void CGUIDialogVideoInfo::Play(bool resume)
 // 2.  IMDb thumb
 // 3.  Local thumb
 // 4.  No thumb (if no Local thumb is available)
-void CGUIDialogVideoInfo::OnGetThumb()
+void CGUIDialogVideoInfo::OnGetArt()
 {
+  // prompt for choice
+  CGUIDialogSelect *dialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
+  if (!dialog)
+    return;
+
   CFileItemList items;
+  dialog->SetHeading(13511);
+  dialog->Reset();
+  dialog->SetUseDetails(true);
+
+  vector<string> artTypes = CVideoThumbLoader::GetArtTypes(m_movieItem->GetVideoInfoTag()->m_type);
+  for (vector<string>::const_iterator i = artTypes.begin(); i != artTypes.end(); ++i)
+  {
+    string type = *i;
+    CFileItemPtr item(new CFileItem(type, "false"));
+    item->SetLabel(type);
+    if (m_movieItem->HasArt(type))
+      item->SetArt("thumb", m_movieItem->GetArt(type));
+    items.Add(item);
+  }
 
+  dialog->SetItems(&items);
+  dialog->DoModal();
+
+  string type = dialog->GetSelectedItem()->GetLabel();
+  if (type.empty())
+    return; // cancelled
+
+  if (type == "fanart")
+  { // TODO: this can be removed once these are unified.
+    OnGetFanart();
+    return;
+  }
+
+  items.Clear();
   // Current thumb
-  if (CFile::Exists(m_movieItem->GetThumbnailImage()))
+  if (CFile::Exists(m_movieItem->GetArt(type)))
   {
     CFileItemPtr item(new CFileItem("thumb://Current", false));
-    item->SetThumbnailImage(m_movieItem->GetThumbnailImage());
-    item->SetLabel(g_localizeStrings.Get(20016));
+    item->SetArt("thumb", m_movieItem->GetArt(type));
+    item->SetLabel(g_localizeStrings.Get(13512));
     items.Add(item);
   }
 
   // Grab the thumbnails from the web
   vector<CStdString> thumbs;
-  m_movieItem->GetVideoInfoTag()->m_strPictureURL.GetThumbURLs(thumbs);
+  m_movieItem->GetVideoInfoTag()->m_strPictureURL.GetThumbURLs(thumbs, type);
 
   for (unsigned int i = 0; i < thumbs.size(); ++i)
   {
     CStdString strItemPath;
     strItemPath.Format("thumb://Remote%i", i);
     CFileItemPtr item(new CFileItem(strItemPath, false));
-    item->SetThumbnailImage(thumbs[i]);
+    item->SetArt("thumb", thumbs[i]);
     item->SetIconImage("DefaultPicture.png");
-    item->SetLabel(g_localizeStrings.Get(20015));
+    item->SetLabel(g_localizeStrings.Get(13513));
 
     // TODO: Do we need to clear the cached image?
     //    CTextureCache::Get().ClearCachedImage(thumb);
     items.Add(item);
   }
 
-  CStdString localThumb(m_movieItem->GetUserVideoThumb());
-  if (CFile::Exists(localThumb))
+  CStdString localThumb = CVideoThumbLoader::GetLocalArt(*m_movieItem, type);
+  if (!localThumb.empty())
   {
     CFileItemPtr item(new CFileItem("thumb://Local", false));
-    item->SetThumbnailImage(localThumb);
-    item->SetLabel(g_localizeStrings.Get(20017));
+    item->SetArt("thumb", localThumb);
+    item->SetLabel(g_localizeStrings.Get(13514));
     items.Add(item);
   }
   else
@@ -632,14 +665,14 @@ void CGUIDialogVideoInfo::OnGetThumb()
     // to delete the incorrect thumb
     CFileItemPtr item(new CFileItem("thumb://None", false));
     item->SetIconImage("DefaultVideo.png");
-    item->SetLabel(g_localizeStrings.Get(20018));
+    item->SetLabel(g_localizeStrings.Get(13515));
     items.Add(item);
   }
 
   CStdString result;
   VECSOURCES sources(g_settings.m_videoSources);
   g_mediaManager.GetLocalDrives(sources);
-  if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(20019), result))
+  if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(13511), result))
     return;   // user cancelled
 
   if (result == "thumb://Current")
@@ -662,12 +695,12 @@ void CGUIDialogVideoInfo::OnGetThumb()
   CVideoDatabase db;
   if (db.Open())
   {
-    db.SetArtForItem(m_movieItem->GetVideoInfoTag()->m_iDbId, m_movieItem->GetVideoInfoTag()->m_type, "thumb", newThumb);
+    db.SetArtForItem(m_movieItem->GetVideoInfoTag()->m_iDbId, m_movieItem->GetVideoInfoTag()->m_type, type, newThumb);
     db.Close();
   }
 
   CUtil::DeleteVideoDatabaseDirectoryCache(); // to get them new thumbs to show
-  m_movieItem->SetThumbnailImage(newThumb);
+  m_movieItem->SetArt(type, newThumb);
   if (m_movieItem->HasProperty("set_folder_thumb"))
   { // have a folder thumb to set as well
     VIDEO::CVideoInfoScanner::ApplyThumbToFolder(m_movieItem->GetProperty("set_folder_thumb").asString(), newThumb);
@@ -684,10 +717,10 @@ void CGUIDialogVideoInfo::OnGetFanart()
   CFileItemList items;
 
   CFileItem item(*m_movieItem->GetVideoInfoTag());
-  if (item.HasProperty("fanart_image"))
+  if (item.HasArt("fanart"))
   {
     CFileItemPtr itemCurrent(new CFileItem("fanart://Current",false));
-    itemCurrent->SetThumbnailImage(item.GetProperty("fanart_image").asString());
+    itemCurrent->SetArt("thumb", item.GetArt("fanart"));
     itemCurrent->SetLabel(g_localizeStrings.Get(20440));
     items.Add(itemCurrent);
   }
@@ -702,7 +735,7 @@ void CGUIDialogVideoInfo::OnGetFanart()
     strItemPath.Format("fanart://Remote%i",i);
     CFileItemPtr item(new CFileItem(strItemPath, false));
     CStdString thumb = m_movieItem->GetVideoInfoTag()->m_fanart.GetPreviewURL(i);
-    item->SetThumbnailImage(CTextureCache::GetWrappedThumbURL(thumb));
+    item->SetArt("thumb", CTextureCache::GetWrappedThumbURL(thumb));
     item->SetIconImage("DefaultPicture.png");
     item->SetLabel(g_localizeStrings.Get(20441));
 
@@ -715,7 +748,7 @@ void CGUIDialogVideoInfo::OnGetFanart()
   if (!strLocal.IsEmpty())
   {
     CFileItemPtr itemLocal(new CFileItem("fanart://Local",false));
-    itemLocal->SetThumbnailImage(strLocal);
+    itemLocal->SetArt("thumb", strLocal);
     itemLocal->SetLabel(g_localizeStrings.Get(20438));
 
     // TODO: Do we need to clear the cached image?
@@ -767,10 +800,7 @@ void CGUIDialogVideoInfo::OnGetFanart()
   }
 
   CUtil::DeleteVideoDatabaseDirectoryCache(); // to get them new thumbs to show
-  if (!result.IsEmpty())
-    m_movieItem->SetProperty("fanart_image", result);
-  else
-    m_movieItem->ClearProperty("fanart_image");
+  m_movieItem->SetArt("fanart", result);
   m_hasUpdatedThumb = true;
 
   // Update our screen
@@ -784,7 +814,7 @@ void CGUIDialogVideoInfo::PlayTrailer()
   *item.GetVideoInfoTag() = *m_movieItem->GetVideoInfoTag();
   item.GetVideoInfoTag()->m_streamDetails.Reset();
   item.GetVideoInfoTag()->m_strTitle.Format("%s (%s)",m_movieItem->GetVideoInfoTag()->m_strTitle.c_str(),g_localizeStrings.Get(20410));
-  item.SetThumbnailImage(m_movieItem->GetThumbnailImage());
+  item.SetArt("thumb", m_movieItem->GetArt("thumb"));
   item.GetVideoInfoTag()->m_iDbId = -1;
   item.GetVideoInfoTag()->m_iFileId = -1;
 
@@ -809,7 +839,7 @@ void CGUIDialogVideoInfo::SetLabel(int iControl, const CStdString &strLabel)
   }
 }
 
-const CStdString& CGUIDialogVideoInfo::GetThumbnail() const
+std::string CGUIDialogVideoInfo::GetThumbnail() const
 {
-  return m_movieItem->GetThumbnailImage();
+  return m_movieItem->GetArt("thumb");
 }
index 3851c4d..7cb6601 100644 (file)
@@ -39,7 +39,7 @@ public:
   bool RefreshAll() const;
   bool HasUpdatedThumb() const { return m_hasUpdatedThumb; };
 
-  const CStdString &GetThumbnail() const;
+  std::string GetThumbnail() const;
   virtual CFileItemPtr GetCurrentListItem(int offset = 0) { return m_movieItem; }
   const CFileItemList& CurrentDirectory() const { return *m_castList; };
   virtual bool HasListItems() const { return true; };
@@ -53,7 +53,7 @@ protected:
   void DoSearch(CStdString& strSearch, CFileItemList& items);
   void OnSearchItemFound(const CFileItem* pItem);
   void Play(bool resume = false);
-  void OnGetThumb();
+  void OnGetArt();
   void OnGetFanart();
   void PlayTrailer();
 
diff --git a/xbmc/video/dialogs/GUIDialogVideoScan.cpp b/xbmc/video/dialogs/GUIDialogVideoScan.cpp
deleted file mode 100644 (file)
index a1938ec..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- *      Copyright (C) 2005-2012 Team XBMC
- *      http://www.xbmc.org
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with XBMC; see the file COPYING.  If not, see
- *  <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "GUIDialogVideoScan.h"
-#include "guilib/GUIProgressControl.h"
-#include "GUIUserMessages.h"
-#include "Util.h"
-#include "guilib/GUIWindowManager.h"
-#include "settings/GUISettings.h"
-#include "ApplicationMessenger.h"
-#include "threads/SingleLock.h"
-#include "utils/log.h"
-#include "URL.h"
-
-#define CONTROL_LABELSTATUS       401
-#define CONTROL_LABELDIRECTORY    402
-#define CONTROL_PROGRESS          403
-#define CONTROL_CURRENT_PROGRESS  404
-#define CONTROL_LABELTITLE        405
-
-using namespace VIDEO;
-
-CGUIDialogVideoScan::CGUIDialogVideoScan(void)
-: CGUIDialog(WINDOW_DIALOG_VIDEO_SCAN, "DialogVideoScan.xml")
-{
-  m_loadType = KEEP_IN_MEMORY;
-}
-
-CGUIDialogVideoScan::~CGUIDialogVideoScan(void)
-{
-}
-
-bool CGUIDialogVideoScan::OnMessage(CGUIMessage& message)
-{
-  switch ( message.GetMessage() )
-  {
-  case GUI_MSG_WINDOW_INIT:
-    {
-      CGUIDialog::OnMessage(message);
-
-      m_strCurrentDir.Empty();
-      m_strTitle.Empty();
-
-      m_fPercentDone=-1.0f;
-      m_fCurrentPercentDone=-1.0f;
-
-      UpdateState();
-      return true;
-    }
-    break;
-  }
-
-  return CGUIDialog::OnMessage(message);
-}
-
-void CGUIDialogVideoScan::FrameMove()
-{
-  if (m_active)
-    UpdateState();
-
-  CGUIDialog::FrameMove();
-}
-
-void CGUIDialogVideoScan::OnDirectoryChanged(const CStdString& strDirectory)
-{
-  CSingleLock lock (m_critical);
-
-  m_strCurrentDir = strDirectory;
-}
-
-void CGUIDialogVideoScan::OnStateChanged(SCAN_STATE state)
-{
-  CSingleLock lock (m_critical);
-
-  m_ScanState = state;
-}
-
-void CGUIDialogVideoScan::OnSetProgress(int currentItem, int itemCount)
-{
-  CSingleLock lock (m_critical);
-
-  m_fPercentDone=(float)((currentItem*100)/itemCount);
-  if (m_fPercentDone>100.0F) m_fPercentDone=100.0F;
-}
-
-void CGUIDialogVideoScan::OnSetCurrentProgress(int currentItem, int itemCount)
-{
-  CSingleLock lock (m_critical);
-
-  m_fCurrentPercentDone=(float)((currentItem*100)/itemCount);
-  if (m_fCurrentPercentDone>100.0F) m_fCurrentPercentDone=100.0F;
-}
-
-void CGUIDialogVideoScan::OnSetTitle(const CStdString& strTitle)
-{
-  CSingleLock lock (m_critical);
-
-  m_strTitle = strTitle;
-}
-
-void CGUIDialogVideoScan::ShowScan()
-{
-  m_ScanState = PREPARING;
-  Show();
-}
-
-void CGUIDialogVideoScan::OnDirectoryScanned(const CStdString& strDirectory)
-{
-  CGUIMessage msg(GUI_MSG_DIRECTORY_SCANNED, 0, 0, 0);
-  msg.SetStringParam(strDirectory);
-  g_windowManager.SendThreadMessage(msg);
-}
-
-void CGUIDialogVideoScan::OnFinished()
-{
-  // clear cache
-  CUtil::DeleteVideoDatabaseDirectoryCache();
-
-  // send message
-  CGUIMessage msg(GUI_MSG_SCAN_FINISHED, 0, 0, 0);
-  g_windowManager.SendThreadMessage(msg);
-
-  // be sure to restore the settings
-  CLog::Log(LOGINFO,"Video scan was stopped or finished ... restoring FindRemoteThumbs");
-
-  if (!g_guiSettings.GetBool("videolibrary.backgroundupdate"))
-  {
-    CApplicationMessenger::Get().Close(this,false,false);
-  }
-}
-
-void CGUIDialogVideoScan::UpdateState()
-{
-  CSingleLock lock (m_critical);
-
-  SET_CONTROL_LABEL(CONTROL_LABELSTATUS, GetStateString());
-
-  if (m_ScanState == FETCHING_MOVIE_INFO || m_ScanState == FETCHING_MUSICVIDEO_INFO || m_ScanState == FETCHING_TVSHOW_INFO || m_ScanState == CLEANING_UP_DATABASE)
-  {
-    CURL url(m_strCurrentDir);
-    CStdString strStrippedPath = url.GetWithoutUserDetails();
-    CURL::Decode(strStrippedPath);
-
-    SET_CONTROL_LABEL(CONTROL_LABELDIRECTORY, strStrippedPath);
-    SET_CONTROL_LABEL(CONTROL_LABELTITLE, m_strTitle);
-
-    if (m_fCurrentPercentDone>-1.0f)
-    {
-      SET_CONTROL_VISIBLE(CONTROL_CURRENT_PROGRESS);
-      CGUIProgressControl* pProgressCtrl=(CGUIProgressControl*)GetControl(CONTROL_CURRENT_PROGRESS);
-      if (pProgressCtrl) pProgressCtrl->SetPercentage(m_fCurrentPercentDone);
-    }
-    else
-      SET_CONTROL_HIDDEN(CONTROL_CURRENT_PROGRESS);
-
-    if (m_fPercentDone>-1.0f)
-    {
-      SET_CONTROL_VISIBLE(CONTROL_PROGRESS);
-      CGUIProgressControl* pProgressCtrl=(CGUIProgressControl*)GetControl(CONTROL_PROGRESS);
-      if (pProgressCtrl) pProgressCtrl->SetPercentage(m_fPercentDone);
-    }
-    else
-      SET_CONTROL_HIDDEN(CONTROL_PROGRESS);
-  }
-  else
-  {
-    SET_CONTROL_LABEL(CONTROL_LABELDIRECTORY, "");
-    SET_CONTROL_LABEL(CONTROL_LABELTITLE, "");
-    SET_CONTROL_HIDDEN(CONTROL_PROGRESS);
-    SET_CONTROL_HIDDEN(CONTROL_CURRENT_PROGRESS);
-  }
-}
-
-int CGUIDialogVideoScan::GetStateString()
-{
-  if (m_ScanState == PREPARING)
-    return 314;
-  else if (m_ScanState == REMOVING_OLD)
-    return 701;
-  else if (m_ScanState == CLEANING_UP_DATABASE)
-    return 700;
-  else if (m_ScanState == FETCHING_MOVIE_INFO)
-    return 20374;
-  else if (m_ScanState == FETCHING_MUSICVIDEO_INFO)
-    return 20408;
-  else if (m_ScanState == FETCHING_TVSHOW_INFO)
-    return 20409;
-  else if (m_ScanState == COMPRESSING_DATABASE)
-    return 331;
-  else if (m_ScanState == WRITING_CHANGES)
-    return 328;
-
-  return -1;
-}
diff --git a/xbmc/video/dialogs/GUIDialogVideoScan.h b/xbmc/video/dialogs/GUIDialogVideoScan.h
deleted file mode 100644 (file)
index f15f29e..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-#pragma once
-
-/*
- *      Copyright (C) 2005-2012 Team XBMC
- *      http://www.xbmc.org
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with XBMC; see the file COPYING.  If not, see
- *  <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "guilib/GUIDialog.h"
-#include "video/VideoInfoScanner.h"
-#include "threads/CriticalSection.h"
-
-class CGUIDialogVideoScan: public CGUIDialog, public VIDEO::IVideoInfoScannerObserver
-{
-public:
-  CGUIDialogVideoScan(void);
-  virtual ~CGUIDialogVideoScan(void);
-  virtual bool OnMessage(CGUIMessage& message);
-  virtual void FrameMove();
-
-  void ShowScan();
-
-  void UpdateState();
-protected:
-  int GetStateString();
-  virtual void OnDirectoryChanged(const CStdString& strDirectory);
-  virtual void OnDirectoryScanned(const CStdString& strDirectory);
-  virtual void OnFinished();
-  virtual void OnStateChanged(VIDEO::SCAN_STATE state);
-  virtual void OnSetProgress(int currentItem, int itemCount);
-  virtual void OnSetCurrentProgress(int currentItem, int itemCount);
-  virtual void OnSetTitle(const CStdString& strTitle);
-
-  VIDEO::SCAN_STATE m_ScanState;
-  CStdString m_strCurrentDir;
-  CStdString m_strTitle;
-
-  CCriticalSection m_critical;
-
-  float m_fPercentDone;
-  float m_fCurrentPercentDone;
-  int m_currentItem;
-  int m_itemCount;
-};
index 27e2c5c..ac5f007 100644 (file)
@@ -76,24 +76,19 @@ void CGUIDialogVideoSettings::CreateSettings()
   // create our settings
   {
     vector<pair<int, int> > entries;
-    entries.push_back(make_pair(VS_DEINTERLACEMODE_OFF    , 16039));
-#ifndef TARGET_RASPBERRY_PI
-    entries.push_back(make_pair(VS_DEINTERLACEMODE_AUTO   , 16040));
-#endif
-    entries.push_back(make_pair(VS_DEINTERLACEMODE_FORCE  , 16041));
 
-    /* remove unsupported methods */
-    for(vector<pair<int, int> >::iterator it = entries.begin(); it != entries.end();)
-    {
-      if(g_renderManager.Supports((EDEINTERLACEMODE)it->first))
-        it++;
-      else
-        it = entries.erase(it);
-    }
+    if (g_renderManager.Supports(VS_DEINTERLACEMODE_OFF))
+      entries.push_back(make_pair(VS_DEINTERLACEMODE_OFF    , 16039));
+
+    if (g_renderManager.Supports(VS_DEINTERLACEMODE_AUTO))
+      entries.push_back(make_pair(VS_DEINTERLACEMODE_AUTO   , 16040));
+
+    if (g_renderManager.Supports(VS_DEINTERLACEMODE_FORCE))
+      entries.push_back(make_pair(VS_DEINTERLACEMODE_FORCE  , 16041));
 
-    AddSpin(VIDEO_SETTINGS_DEINTERLACEMODE, 16037, (int*)&g_settings.m_currentVideoSettings.m_DeinterlaceMode, entries);
+    if (entries.size())
+      AddSpin(VIDEO_SETTINGS_DEINTERLACEMODE, 16037, (int*)&g_settings.m_currentVideoSettings.m_DeinterlaceMode, entries);
   }
-#ifndef TARGET_RASPBERRY_PI
   {
     vector<pair<int, int> > entries;
     entries.push_back(make_pair(VS_INTERLACEMETHOD_AUTO                 , 16019));
@@ -125,9 +120,12 @@ void CGUIDialogVideoSettings::CreateSettings()
         it = entries.erase(it);
     }
 
-    AddSpin(VIDEO_SETTINGS_INTERLACEMETHOD, 16038, (int*)&g_settings.m_currentVideoSettings.m_InterlaceMethod, entries);
-    if (g_settings.m_currentVideoSettings.m_DeinterlaceMode == VS_DEINTERLACEMODE_OFF)
-      EnableSettings(VIDEO_SETTINGS_INTERLACEMETHOD, false);
+    if (entries.size() > 1)
+    {
+      AddSpin(VIDEO_SETTINGS_INTERLACEMETHOD, 16038, (int*)&g_settings.m_currentVideoSettings.m_InterlaceMethod, entries);
+      if (g_settings.m_currentVideoSettings.m_DeinterlaceMode == VS_DEINTERLACEMODE_OFF)
+        EnableSettings(VIDEO_SETTINGS_INTERLACEMETHOD, false);
+    }
   }
   {
     vector<pair<int, int> > entries;
@@ -159,16 +157,21 @@ void CGUIDialogVideoSettings::CreateSettings()
 
     AddSpin(VIDEO_SETTINGS_SCALINGMETHOD, 16300, (int*)&g_settings.m_currentVideoSettings.m_ScalingMethod, entries);
   }
-#endif
-  AddBool(VIDEO_SETTINGS_CROP, 644, &g_settings.m_currentVideoSettings.m_Crop);
+  if (g_renderManager.Supports(RENDERFEATURE_CROP))
+    AddBool(VIDEO_SETTINGS_CROP, 644, &g_settings.m_currentVideoSettings.m_Crop);
+  if (g_renderManager.Supports(RENDERFEATURE_STRETCH) || g_renderManager.Supports(RENDERFEATURE_PIXEL_RATIO))
   {
     const int entries[] = {630, 631, 632, 633, 634, 635, 636 };
     AddSpin(VIDEO_SETTINGS_VIEW_MODE, 629, &g_settings.m_currentVideoSettings.m_ViewMode, 7, entries);
   }
-  AddSlider(VIDEO_SETTINGS_ZOOM, 216, &g_settings.m_currentVideoSettings.m_CustomZoomAmount, 0.5f, 0.01f, 2.0f, FormatFloat);
-  AddSlider(VIDEO_SETTINGS_VERTICAL_SHIFT, 225, &g_settings.m_currentVideoSettings.m_CustomVerticalShift, -2.0f, 0.01f, 2.0f, FormatFloat);
-  AddSlider(VIDEO_SETTINGS_PIXEL_RATIO, 217, &g_settings.m_currentVideoSettings.m_CustomPixelRatio, 0.5f, 0.01f, 2.0f, FormatFloat);
-  AddBool(VIDEO_SETTINGS_POSTPROCESS, 16400, &g_settings.m_currentVideoSettings.m_PostProcess);
+  if (g_renderManager.Supports(RENDERFEATURE_ZOOM))
+    AddSlider(VIDEO_SETTINGS_ZOOM, 216, &g_settings.m_currentVideoSettings.m_CustomZoomAmount, 0.5f, 0.01f, 2.0f, FormatFloat);
+  if (g_renderManager.Supports(RENDERFEATURE_VERTICAL_SHIFT))
+    AddSlider(VIDEO_SETTINGS_VERTICAL_SHIFT, 225, &g_settings.m_currentVideoSettings.m_CustomVerticalShift, -2.0f, 0.01f, 2.0f, FormatFloat);
+  if (g_renderManager.Supports(RENDERFEATURE_PIXEL_RATIO))
+    AddSlider(VIDEO_SETTINGS_PIXEL_RATIO, 217, &g_settings.m_currentVideoSettings.m_CustomPixelRatio, 0.5f, 0.01f, 2.0f, FormatFloat);
+  if (g_renderManager.Supports(RENDERFEATURE_POSTPROCESS))
+    AddBool(VIDEO_SETTINGS_POSTPROCESS, 16400, &g_settings.m_currentVideoSettings.m_PostProcess);
 
 #ifdef HAS_VIDEO_PLAYBACK
   if (g_renderManager.Supports(RENDERFEATURE_BRIGHTNESS))
index cb66a75..b080a2a 100644 (file)
@@ -6,7 +6,6 @@ SRCS=GUIDialogAudioSubtitleSettings.cpp \
      GUIDialogVideoInfo.cpp \
      GUIDialogVideoOSD.cpp \
      GUIDialogVideoOverlay.cpp \
-     GUIDialogVideoScan.cpp \
      GUIDialogVideoSettings.cpp \
 
 LIB=videodialogs.a
index 58657c9..7a0ed7e 100644 (file)
@@ -22,6 +22,7 @@
 #include "GUIWindowVideoBase.h"
 #include "Util.h"
 #include "video/VideoInfoDownloader.h"
+#include "video/VideoInfoScanner.h"
 #include "utils/RegExp.h"
 #include "utils/Variant.h"
 #include "addons/AddonManager.h"
@@ -29,7 +30,6 @@
 #include "addons/IAddon.h"
 #include "video/dialogs/GUIDialogVideoInfo.h"
 #include "GUIWindowVideoNav.h"
-#include "video/dialogs/GUIDialogVideoScan.h"
 #include "dialogs/GUIDialogSmartPlaylistEditor.h"
 #include "dialogs/GUIDialogProgress.h"
 #include "dialogs/GUIDialogYesNo.h"
@@ -586,8 +586,8 @@ bool CGUIWindowVideoBase::ShowIMDB(CFileItem *item, const ScraperPtr &info2)
       // show dialog that we're downloading the movie info
 
       // clear artwork
-      item->SetThumbnailImage("");
-      item->ClearProperty("fanart_image");
+      item->SetArt("thumb", "");
+      item->SetArt("fanart", "");
 
       CFileItemList list;
       CStdString strPath=item->GetPath();
@@ -674,7 +674,7 @@ bool CGUIWindowVideoBase::ShowIMDB(CFileItem *item, const ScraperPtr &info2)
         *item->GetVideoInfoTag() = movieDetails;
         pDlgInfo->SetMovie(item);
         pDlgInfo->DoModal();
-        item->SetThumbnailImage(pDlgInfo->GetThumbnail());
+        item->SetArt("thumb", pDlgInfo->GetThumbnail());
         needsRefresh = pDlgInfo->NeedRefresh();
         listNeedsUpdating = true;
       }
@@ -750,7 +750,7 @@ void CGUIWindowVideoBase::AddItemToPlayList(const CFileItemPtr &pItem, CFileItem
     GetDirectory(pItem->GetPath(), items);
     FormatAndSort(items);
 
-    int watchedMode = g_settings.GetWatchMode(m_vecItems->GetContent());
+    int watchedMode = g_settings.GetWatchMode(items.GetContent());
     bool unwatchedOnly = watchedMode == VIDEO_SHOW_UNWATCHED;
     bool watchedOnly = watchedMode == VIDEO_SHOW_WATCHED;
     for (int i = 0; i < items.Size(); ++i)
@@ -1220,10 +1220,10 @@ void CGUIWindowVideoBase::GetContextButtons(int itemNumber, CContextButtons &but
       {
         buttons.Add(CONTEXT_BUTTON_RESUME_ITEM, GetResumeString(*(item.get())));     // Resume Video
       }
-      //if the item isn't a folder, is a member of a list rather than a single item
+      //if the item isn't a folder or script, is a member of a list rather than a single item
       //and we're not on the last element of the list, 
       //then add add either 'play from here' or 'play only this' depending on default behaviour
-      if (!item->m_bIsFolder && m_vecItems->Size() > 1 && itemNumber < m_vecItems->Size()-1)
+      if (!(item->m_bIsFolder || item->IsScript()) && m_vecItems->Size() > 1 && itemNumber < m_vecItems->Size()-1)
       {
         if (!g_guiSettings.GetBool("videoplayer.autoplaynextitem"))
           buttons.Add(CONTEXT_BUTTON_PLAY_AND_QUEUE, 13412);
@@ -1595,7 +1595,7 @@ void CGUIWindowVideoBase::OnDeleteItem(CFileItemPtr item)
   }
 
   if (g_guiSettings.GetBool("filelists.allowfiledeletion") &&
-      CUtil::SupportsFileOperations(item->GetPath()))
+      CUtil::SupportsWriteFileOperations(item->GetPath()))
     CFileUtils::DeleteItem(item);
 }
 
@@ -1783,7 +1783,34 @@ bool CGUIWindowVideoBase::Update(const CStdString &strDirectory)
 
 bool CGUIWindowVideoBase::GetDirectory(const CStdString &strDirectory, CFileItemList &items)
 {
-  bool bResult = CGUIMediaWindow::GetDirectory(strDirectory,items);
+  CStdString directory = strDirectory;
+
+  // check if the path contains a filter and if so load it and
+  // remove it from the path to get proper GUI view states etc
+  CSmartPlaylist filterXsp;
+  CVideoDbUrl videoUrl;
+  if (videoUrl.FromString(strDirectory))
+  {
+    CVariant filter;
+    if (videoUrl.GetOption("filter", filter))
+    {
+      // load the filter and if it's type does not match the
+      // path's item type reset it
+      if (filterXsp.LoadFromJson(filter.asString()) && !filterXsp.GetType().Equals(videoUrl.GetItemType().c_str()))
+        filterXsp.Reset();
+
+      // remove the "filter" option from the path
+      videoUrl.AddOption("filter", "");
+    }
+    directory = videoUrl.ToString();
+  }
+
+  bool bResult = CGUIMediaWindow::GetDirectory(directory, items);
+
+  // (re-)apply the previously retrieved filter
+  // because it was reset in CGUIMediaWindow::GetDirectory()
+  if (!filterXsp.IsEmpty())
+    m_filter = filterXsp;
 
   // add in the "New Playlist" item if we're in the playlists folder
   if ((items.GetPath() == "special://videoplaylists/") && !items.Contains("newplaylist://"))
@@ -1809,7 +1836,7 @@ bool CGUIWindowVideoBase::GetDirectory(const CStdString &strDirectory, CFileItem
   // we may also be in a tvshow files listing
   // (ideally this should be removed, and our stack regexps tidied up if necessary
   // No "normal" episodes should stack, and multi-parts should be supported)
-  ADDON::ScraperPtr info = m_database.GetScraperForPath(strDirectory);
+  ADDON::ScraperPtr info = m_database.GetScraperForPath(directory);
   if (info && info->Content() == CONTENT_TVSHOWS)
     m_stackingAvailable = false;
 
@@ -1830,6 +1857,15 @@ void CGUIWindowVideoBase::OnPrepareFileItems(CFileItemList &items)
 {
 }
 
+bool CGUIWindowVideoBase::CheckFilterAdvanced(CFileItemList &items)
+{
+  CStdString content = items.GetContent();
+  if (items.IsVideoDb() && (content.Equals("movies") || content.Equals("tvshows") || content.Equals("episodes") || content.Equals("musicvideos")))
+    return true;
+
+  return false;
+}
+
 void CGUIWindowVideoBase::AddToDatabase(int iItem)
 {
   if (iItem < 0 || iItem >= m_vecItems->Size())
index 9deadaf..78d94b5 100644 (file)
@@ -89,6 +89,8 @@ protected:
   virtual void OnItemLoaded(CFileItem* pItem) {};
   virtual void OnPrepareFileItems(CFileItemList &items);
 
+  virtual bool CheckFilterAdvanced(CFileItemList &items);
+
   virtual void GetContextButtons(int itemNumber, CContextButtons &buttons);
   void GetNonContextButtons(int itemNumber, CContextButtons &buttons);
   virtual bool OnContextButton(int itemNumber, CONTEXT_BUTTON button);
index 3ae64ca..844396d 100644 (file)
@@ -29,7 +29,6 @@
 #include "dialogs/GUIDialogFileBrowser.h"
 #include "filesystem/VideoDatabaseDirectory.h"
 #include "playlists/PlayListFactory.h"
-#include "video/dialogs/GUIDialogVideoScan.h"
 #include "dialogs/GUIDialogOK.h"
 #include "addons/AddonManager.h"
 #include "PartyModeManager.h"
@@ -52,6 +51,7 @@
 #include "utils/StringUtils.h"
 #include "TextureCache.h"
 #include "guilib/GUIKeyboardFactory.h"
+#include "video/VideoInfoScanner.h"
 
 using namespace XFILE;
 using namespace VIDEODATABASEDIRECTORY;
@@ -280,7 +280,7 @@ bool CGUIWindowVideoNav::GetDirectory(const CStdString &strDirectory, CFileItemL
       dir.GetQueryParams(items.GetPath(),params);
       VIDEODATABASEDIRECTORY::NODE_TYPE node = dir.GetDirectoryChildType(items.GetPath());
 
-      items.SetThumbnailImage("");
+      items.SetArt("thumb", "");
       if (node == VIDEODATABASEDIRECTORY::NODE_TYPE_EPISODES ||
           node == NODE_TYPE_SEASONS                          ||
           node == NODE_TYPE_RECENTLY_ADDED_EPISODES)
@@ -293,9 +293,9 @@ bool CGUIWindowVideoNav::GetDirectory(const CStdString &strDirectory, CFileItemL
         if (m_database.GetArtForItem(details.m_iDbId, details.m_type, art))
         {
           if (art.find("thumb") != art.end())
-            items.SetProperty("tvshowthumb", art["thumb"]);
+            items.SetArt("tvshowthumb", art["thumb"]);
           if (art.find("fanart") != art.end())
-            items.SetProperty("fanart_image", art["fanart"]);
+            items.SetArt("fanart", art["fanart"]);
         }
         CFileItem showItem(details.m_strShowPath, true);
 
@@ -316,18 +316,17 @@ bool CGUIWindowVideoNav::GetDirectory(const CStdString &strDirectory, CFileItemL
           string seasonThumb = m_database.GetArtForItem(seasonID, "season", "thumb");
           if (!seasonThumb.empty())
           {
-            items.SetProperty("seasonthumb",seasonThumb);
-            items.SetThumbnailImage(seasonThumb);
+            items.SetArt("seasonthumb",seasonThumb);
+            items.SetArt("thumb", seasonThumb);
           }
         }
         else
         {
           items.SetContent("seasons");
-          items.SetThumbnailImage(showItem.GetThumbnailImage());
+          items.SetArt("thumb", showItem.GetArt("thumb"));
         }
       }
       else if (node == NODE_TYPE_TITLE_MOVIES ||
-               node == NODE_TYPE_SETS ||
                node == NODE_TYPE_RECENTLY_ADDED_MOVIES)
         items.SetContent("movies");
       else if (node == NODE_TYPE_TITLE_TVSHOWS)
@@ -354,6 +353,8 @@ bool CGUIWindowVideoNav::GetDirectory(const CStdString &strDirectory, CFileItemL
         items.SetContent("years");
       else if (node == NODE_TYPE_MUSICVIDEOS_ALBUM)
         items.SetContent("albums");
+      else if (node == NODE_TYPE_SETS)
+        items.SetContent("sets");
       else if (node == NODE_TYPE_TAGS)
         items.SetContent("tags");
       else
@@ -527,8 +528,24 @@ void CGUIWindowVideoNav::UpdateButtons()
 
 bool CGUIWindowVideoNav::GetFilteredItems(const CStdString &filter, CFileItemList &items)
 {
-  bool listchanged = CGUIMediaWindow::GetFilteredItems(filter, items);
+  bool listchanged = false;
+  bool updateItems = false;
+  if (!m_canFilterAdvanced)
+    listchanged = CGUIMediaWindow::GetFilteredItems(filter, items);
+  else
+    listchanged = CGUIMediaWindow::GetAdvanceFilteredItems(items, updateItems);
+
   listchanged |= ApplyWatchedFilter(items);
+
+  // there are new items so we need to run the thumbloader
+  if (updateItems)
+  {
+    if (m_thumbLoader.IsLoading())
+      m_thumbLoader.StopThread();
+
+    m_thumbLoader.Load(items);
+  }
+
   return listchanged;
 }
 
@@ -725,7 +742,7 @@ void CGUIWindowVideoNav::OnDeleteItem(CFileItemPtr pItem)
       pItem->m_bIsFolder=true;
 
     if (g_guiSettings.GetBool("filelists.allowfiledeletion") &&
-        CUtil::SupportsFileOperations(strDeletePath))
+        CUtil::SupportsWriteFileOperations(strDeletePath))
     {
       pItem->SetPath(strDeletePath);
       CGUIWindowVideoBase::OnDeleteItem(pItem);
@@ -1014,13 +1031,16 @@ void CGUIWindowVideoNav::GetContextButtons(int itemNumber, CContextButtons &butt
             buttons.Add(CONTEXT_BUTTON_STOP_SCANNING, 13353);
         }
         else
-          buttons.Add(CONTEXT_BUTTON_UPDATE_LIBRARY, 653);
+        {
+          if (!(item->IsPlugin() || item->IsScript() || m_vecItems->IsPlugin()))
+            buttons.Add(CONTEXT_BUTTON_UPDATE_LIBRARY, 653);
+        }
       }
 
       if (!m_vecItems->IsVideoDb() && !m_vecItems->IsVirtualDirectoryRoot())
       { // non-video db items, file operations are allowed
         if ((g_guiSettings.GetBool("filelists.allowfiledeletion") &&
-            CUtil::SupportsFileOperations(item->GetPath())) ||
+            CUtil::SupportsWriteFileOperations(item->GetPath())) ||
             (inPlaylists && !URIUtils::GetFileName(item->GetPath()).Equals("PartyMode-Video.xsp")
                          && (item->IsPlayList() || item->IsSmartPlayList())))
         {
@@ -1098,7 +1118,7 @@ bool CGUIWindowVideoNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
       if (!currentThumb.IsEmpty() && CFile::Exists(currentThumb))
       {
         CFileItemPtr item(new CFileItem("thumb://Current", false));
-        item->SetThumbnailImage(currentThumb);
+        item->SetArt("thumb", currentThumb);
         item->SetLabel(g_localizeStrings.Get(20016));
         items.Add(item);
       }
@@ -1114,7 +1134,7 @@ bool CGUIWindowVideoNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
         else
           tag = *m_vecItems->Get(itemNumber)->GetVideoInfoTag();
         if (button == CONTEXT_BUTTON_SET_SEASON_THUMB)
-          tag.m_strPictureURL.GetThumbURLs(thumbs, m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iSeason);
+          tag.m_strPictureURL.GetThumbURLs(thumbs, "", m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iSeason);
         else
           tag.m_strPictureURL.GetThumbURLs(thumbs);
 
@@ -1123,7 +1143,7 @@ bool CGUIWindowVideoNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
           CStdString strItemPath;
           strItemPath.Format("thumb://Remote%i",i);
           CFileItemPtr item(new CFileItem(strItemPath, false));
-          item->SetThumbnailImage(thumbs[i]);
+          item->SetArt("thumb", thumbs[i]);
           item->SetIconImage("DefaultPicture.png");
           item->SetLabel(g_localizeStrings.Get(20015));
           items.Add(item);
@@ -1142,7 +1162,7 @@ bool CGUIWindowVideoNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
         {
           CFileItemPtr pItem(new CFileItem(strThumb,false));
           pItem->SetLabel(g_localizeStrings.Get(20017));
-          pItem->SetThumbnailImage(strThumb);
+          pItem->SetArt("thumb", strThumb);
           items.Add(pItem);
           local = true;
         }
@@ -1159,7 +1179,7 @@ bool CGUIWindowVideoNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
         {
           CFileItemPtr pItem(new CFileItem(strThumb,false));
           pItem->SetLabel(g_localizeStrings.Get(20017));
-          pItem->SetThumbnailImage(strThumb);
+          pItem->SetArt("thumb", strThumb);
           items.Add(pItem);
           local = true;
         }
@@ -1220,10 +1240,10 @@ bool CGUIWindowVideoNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
       CVideoThumbLoader loader;
       loader.LoadItem(item.get());
 
-      if (item->HasProperty("fanart_image"))
+      if (item->HasArt("fanart"))
       {
         CFileItemPtr itemCurrent(new CFileItem("fanart://Current",false));
-        itemCurrent->SetThumbnailImage(item->GetProperty("fanart_image").asString());
+        itemCurrent->SetArt("thumb", item->GetArt("fanart"));
         itemCurrent->SetLabel(g_localizeStrings.Get(20440));
         items.Add(itemCurrent);
       }
index 96fd721..39280b6 100644 (file)
@@ -36,7 +36,7 @@
 #include "X11/WinSystemX11GLES.h"
 
 #elif defined(TARGET_LINUX)   && defined(HAS_GLES) && defined(HAS_EGL)
-#include "egl/WinSystemGLES.h"
+#include "egl/WinSystemEGL.h"
 
 #elif defined(TARGET_FREEBSD)   && defined(HAS_GL)   && defined(HAVE_X11)
 #include "X11/WinSystemX11GL.h"
diff --git a/xbmc/windowing/egl/EGLNativeType.h b/xbmc/windowing/egl/EGLNativeType.h
new file mode 100644 (file)
index 0000000..bd53a30
--- /dev/null
@@ -0,0 +1,147 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2012 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <EGL/egl.h>
+#include "guilib/Resolution.h"
+#include "EGLQuirks.h"
+
+/*!
+This class provides extra functionality on top of EGL in order to facilitate
+the implementation-dependent functionality relating to creating, maintaining,
+and destroying screens and displays.
+
+Each implementation is required to implement each function, though it can
+simply return false to signify that the functionality does not exist.
+
+Internal state should be maintained by each implementation as little as possible.
+If any information needs to be saved outside of the NativeWindow and NativeDisplay
+for later retrieval, there is most likely a bug in the implementation, or in that
+platform's EGL implementation.
+
+Each implementation will be instantiated at runtime to see if it qualifies for use
+until one is found. For this reason, each should avoid operations in its ctors and
+dtors, instead using the provided Initialize() and Destroy() functions which are
+only called once the implementation has been selected.
+*/
+
+class CEGLNativeType
+{
+public:
+
+ /*! \brief Do NOT clean up in the destructor, use the Destroy function
+    instead.
+
+    \sa: Destroy() */
+  virtual ~CEGLNativeType(){};
+
+/*! \brief Unique identifier for this EGL implementaiton.
+
+   It should be unique enough to set it apart from other possible implementations
+   on a similar platform. */
+  virtual std::string GetNativeName() const = 0;
+
+/*! \brief A function for testing whether this implementation should be used.
+
+  On platforms where several implementations are possible, it should provide a
+  stringent test to rule out false-positives. */
+  virtual bool  CheckCompatibility() = 0;
+
+/*! \brief Initialize any local variables and/or structures here.
+
+    This is called after the implementation has been chosen, which is why this
+    should be used rather than the ctor. */
+  virtual void  Initialize() = 0;
+
+/*! \brief Destroy any local variables and/or structures here.
+
+    This is called when the WindowSystem has been destroyed. */
+  virtual void  Destroy() = 0;
+
+/*! \brief EGL implementation quirks.
+
+    Set any EGL oddities here so that they can be queried during the window's
+    life-cycle. */
+  virtual int   GetQuirks() = 0;
+
+/*! \brief Create the EGL Native Display
+
+    An Implementation-dependent method should be used to create a native
+    display and store it in m_nativeDisplay. XBMC will terminate if this
+    fails */
+  virtual bool  CreateNativeDisplay() = 0;
+
+/*! \brief Create the EGL Native Window
+
+    An Implementation-dependent method should be used to create a native
+    window and store it in m_nativeWindow. XBMC Will terminate if this fails.
+    If possible, the created window should use the current display's geometry
+    and allocate as needed so that it is immediately available for use.
+    If not, it must be made ready by SetNativeResolution(). */
+  virtual bool  CreateNativeWindow() = 0;
+
+/*! \brief Returns the current Native Display */
+  virtual bool  GetNativeDisplay(EGLNativeDisplayType **nativeDisplay) const = 0;
+
+/*! \brief Returns the current Native Window */
+  virtual bool  GetNativeWindow(EGLNativeWindowType **nativeWindow) const = 0;
+
+/*! \brief Destroy the Native Window
+
+    An Implementation-dependent method should be used to destroy the current
+    Native Window */
+  virtual bool  DestroyNativeWindow() = 0;
+
+/*! \brief Destroy The Native Display
+
+    An Implementation-dependent method should be used to destroy the current
+    Native Display */
+  virtual bool  DestroyNativeDisplay() = 0;
+
+/*! \brief Return the current display's resolution
+
+    This is completely independent of XBMC's internal resolution */
+  virtual bool  GetNativeResolution(RESOLUTION_INFO *res) const = 0;
+
+/*! \brief Set the current display's resolution
+
+    This is completely independent of XBMC's internal resolution */
+  virtual bool  SetNativeResolution(const RESOLUTION_INFO &res) = 0;
+
+/*! \brief Query the display for all possible resolutions */
+  virtual bool  ProbeResolutions(std::vector<RESOLUTION_INFO> &resolutions) = 0;
+
+/*! \brief Provide a fall-back resolution
+
+    If all queried resolutions fail, this one is guaranteed to be compatible
+    with the display */
+  virtual bool  GetPreferredResolution(RESOLUTION_INFO *res) const = 0;
+
+/*! \brief Show/Hide the current window
+
+    A platform-independent way of hiding XBMC (for example blanking the current
+    framebuffer */
+  virtual bool  ShowWindow(bool show) = 0;
+
+protected:
+  EGLNativeDisplayType m_nativeDisplay;
+  EGLNativeWindowType  m_nativeWindow;
+};
diff --git a/xbmc/windowing/egl/EGLNativeTypeAmlogic.cpp b/xbmc/windowing/egl/EGLNativeTypeAmlogic.cpp
new file mode 100644 (file)
index 0000000..19337ea
--- /dev/null
@@ -0,0 +1,435 @@
+/*
+ *      Copyright (C) 2011-2012 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include "EGLNativeTypeAmlogic.h"
+#include <stdlib.h>
+#include <linux/fb.h>
+#include <sys/ioctl.h>
+#include "utils/StringUtils.h"
+#include "guilib/gui3d.h"
+#define m_framebuffer_name "fb0"
+
+CEGLNativeTypeAmlogic::CEGLNativeTypeAmlogic()
+{
+}
+
+CEGLNativeTypeAmlogic::~CEGLNativeTypeAmlogic()
+{
+}
+
+bool CEGLNativeTypeAmlogic::CheckCompatibility()
+{
+  char name[256] = {0};
+  get_sysfs_str("/sys/class/graphics/fb0/device/modalias", name, 255);
+  CStdString strName = name;
+  strName.Trim();
+  if (strName == "platform:mesonfb")
+    return true;
+  return false;
+}
+
+void CEGLNativeTypeAmlogic::Initialize()
+{
+  SetCpuMinLimit(true);
+  return;
+}
+void CEGLNativeTypeAmlogic::Destroy()
+{
+  SetCpuMinLimit(false);
+  return;
+}
+
+bool CEGLNativeTypeAmlogic::CreateNativeDisplay()
+{
+  m_nativeDisplay = EGL_DEFAULT_DISPLAY;
+  return true;
+}
+
+bool CEGLNativeTypeAmlogic::CreateNativeWindow()
+{
+#if defined(_FBDEV_WINDOW_H_)
+  m_nativeWindow = new fbdev_window;
+  m_nativeWindow->width = 1280;
+  m_nativeWindow->height = 720;
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool CEGLNativeTypeAmlogic::GetNativeDisplay(EGLNativeDisplayType **nativeDisplay) const
+{
+  *nativeDisplay = (EGLNativeDisplayType*) &m_nativeDisplay;
+  return true;
+}
+
+bool CEGLNativeTypeAmlogic::GetNativeWindow(EGLNativeWindowType **nativeWindow) const
+{
+  *nativeWindow = (EGLNativeWindowType*) &m_nativeWindow;
+  return true;
+}
+
+bool CEGLNativeTypeAmlogic::DestroyNativeDisplay()
+{
+  return true;
+}
+
+bool CEGLNativeTypeAmlogic::DestroyNativeWindow()
+{
+  free(m_nativeWindow);
+  return true;
+}
+
+bool CEGLNativeTypeAmlogic::GetNativeResolution(RESOLUTION_INFO *res) const
+{
+  char mode[256] = {0};
+  get_sysfs_str("/sys/class/display/mode", mode, 255);
+  return ModeToResolution(mode, res);
+}
+
+bool CEGLNativeTypeAmlogic::SetNativeResolution(const RESOLUTION_INFO &res)
+{
+  if (res.iScreenWidth == 1920 && res.iScreenHeight == 1080)
+  {
+    if (res.dwFlags & D3DPRESENTFLAG_INTERLACED)
+    {
+      if ((int)res.fRefreshRate == 60)
+        SetDisplayResolution("1080i");
+      else
+        SetDisplayResolution("1080i50hz");
+    }
+    else
+    {
+      if ((int)res.fRefreshRate == 60)
+        SetDisplayResolution("1080p");
+      else
+        SetDisplayResolution("1080p50hz");
+    }
+  }
+  else if (res.iScreenWidth == 1280 && res.iScreenHeight == 720)
+  {
+    if ((int)res.fRefreshRate == 60)
+      SetDisplayResolution("720p");
+    else
+      SetDisplayResolution("720p50hz");
+  }
+  else if (res.iScreenWidth == 720  && res.iScreenHeight == 480)
+  {
+    SetDisplayResolution("480p");
+  }
+  return true;
+}
+
+bool CEGLNativeTypeAmlogic::ProbeResolutions(std::vector<RESOLUTION_INFO> &resolutions)
+{
+  char valstr[256] = {0};
+  get_sysfs_str("/sys/class/amhdmitx/amhdmitx0/disp_cap", valstr, 255);
+  std::vector<CStdString> probe_str;
+  StringUtils::SplitString(valstr, "\n", probe_str);
+
+  resolutions.clear();
+  RESOLUTION_INFO res;
+  for (size_t i = 0; i < probe_str.size(); i++)
+  {
+    if(ModeToResolution(probe_str[i].c_str(), &res))
+      resolutions.push_back(res);
+  }
+  return resolutions.size() > 0;
+
+}
+
+bool CEGLNativeTypeAmlogic::GetPreferredResolution(RESOLUTION_INFO *res) const
+{
+  res->iWidth = 1280;
+  res->iHeight= 720;
+  res->fRefreshRate = 60;
+  res->dwFlags= D3DPRESENTFLAG_PROGRESSIVE;
+  res->iScreen       = 0;
+  res->bFullScreen   = true;
+  res->iSubtitles    = (int)(0.965 * res->iHeight);
+  res->fPixelRatio   = 1.0f;
+  res->iScreenWidth  = res->iWidth;
+  res->iScreenHeight = res->iHeight;
+  res->strMode.Format("%dx%d @ %.2f%s - Full Screen", res->iScreenWidth, res->iScreenHeight, res->fRefreshRate,
+     res->dwFlags & D3DPRESENTFLAG_INTERLACED ? "i" : "");
+  return true;
+}
+
+bool CEGLNativeTypeAmlogic::ShowWindow(bool show)
+{
+  std::string blank_framebuffer = "/sys/class/graphics/fb0/blank";
+  set_sysfs_int(blank_framebuffer.c_str(), show ? 0 : 1);
+  return true;
+}
+
+int CEGLNativeTypeAmlogic::get_sysfs_str(const char *path, char *valstr, const int size) const
+{
+  int fd = open(path, O_RDONLY);
+  if (fd >= 0)
+  {
+    int len = read(fd, valstr, size - 1);
+    if (len != -1 )
+      valstr[len] = '\0';
+    close(fd);
+  }
+  else
+  {
+    sprintf(valstr, "%s", "fail");
+    return -1;
+  }
+  return 0;
+}
+
+int CEGLNativeTypeAmlogic::set_sysfs_str(const char *path, const char *val) const
+{
+  int fd = open(path, O_CREAT | O_RDWR | O_TRUNC, 0644);
+  if (fd >= 0)
+  {
+    write(fd, val, strlen(val));
+    close(fd);
+    return 0;
+  }
+  return -1;
+}
+
+int CEGLNativeTypeAmlogic::set_sysfs_int(const char *path, const int val) const
+{
+  char bcmd[16];
+  int fd = open(path, O_CREAT | O_RDWR | O_TRUNC, 0644);
+  if (fd >= 0)
+  {
+    sprintf(bcmd, "%d", val);
+    write(fd, bcmd, strlen(bcmd));
+    close(fd);
+    return 0;
+  }
+  return -1;
+}
+
+int CEGLNativeTypeAmlogic::get_sysfs_int(const char *path) const
+{
+  int val = 0;
+  char bcmd[16];
+  int fd = open(path, O_RDONLY);
+  if (fd >= 0)
+  {
+    read(fd, bcmd, sizeof(bcmd));
+    val = strtol(bcmd, NULL, 16);
+    close(fd);
+  }
+  return val;
+}
+
+bool CEGLNativeTypeAmlogic::SetDisplayResolution(const char *resolution)
+{
+  CStdString modestr = resolution;
+  // switch display resolution
+  set_sysfs_str("/sys/class/display/mode", modestr.c_str());
+  usleep(250 * 1000);
+
+  // setup gui freescale depending on display resolution
+  DisableFreeScale();
+  if (modestr.Left(4).Equals("1080"))
+  {
+    EnableFreeScale();
+  }
+
+  return true;
+}
+
+bool CEGLNativeTypeAmlogic::ModeToResolution(const char *mode, RESOLUTION_INFO *res) const
+{
+  if (!res)
+    return false;
+
+  res->iWidth = 0;
+  res->iHeight= 0;
+
+  if(!mode)
+    return false;
+
+  CStdString fromMode = mode;
+  fromMode.Trim();
+  // strips, for example, 720p* to 720p
+  if (fromMode.Right(1) == "*")
+    fromMode = fromMode.Left(std::max(0, (int)fromMode.size() - 1));
+
+  if (fromMode.Equals("720p"))
+  {
+    res->iWidth = 1280;
+    res->iHeight= 720;
+    res->iScreenWidth  = res->iWidth;
+    res->iScreenHeight = res->iHeight;
+    res->fRefreshRate = 60;
+    res->dwFlags= D3DPRESENTFLAG_PROGRESSIVE;
+  }
+  else if (fromMode.Equals("720p50hz"))
+  {
+    res->iWidth = 1280;
+    res->iHeight= 720;
+    res->iScreenWidth  = res->iWidth;
+    res->iScreenHeight = res->iHeight;
+    res->fRefreshRate = 50;
+    res->dwFlags= D3DPRESENTFLAG_PROGRESSIVE;
+  }
+  else if (fromMode.Equals("1080p"))
+  {
+    res->iWidth = 1280;
+    res->iHeight= 720;
+    res->iScreenWidth  = 1920;
+    res->iScreenHeight = 1080;
+    res->fRefreshRate = 60;
+    res->dwFlags= D3DPRESENTFLAG_PROGRESSIVE;
+  }
+  else if (fromMode.Equals("1080p50hz"))
+  {
+    res->iScreenWidth = 1920;
+    res->iScreenHeight= 1080;
+    res->iWidth = 1280;
+    res->iHeight= 720;
+    res->fRefreshRate = 50;
+    res->dwFlags= D3DPRESENTFLAG_PROGRESSIVE;
+  }
+  else if (fromMode.Equals("1080i"))
+  {
+    res->iScreenWidth = 1920;
+    res->iScreenHeight= 1080;
+    res->iWidth = 1280;
+    res->iHeight= 720;
+    res->fRefreshRate = 60;
+    res->dwFlags= D3DPRESENTFLAG_INTERLACED;
+  }
+  else if (fromMode.Equals("1080i50hz"))
+  {
+    res->iWidth = 1920;
+    res->iHeight= 1080;
+    res->iScreenWidth = 1280;
+    res->iScreenHeight= 720;
+    res->fRefreshRate = 50;
+    res->dwFlags= D3DPRESENTFLAG_INTERLACED;
+  }
+
+  res->iScreen       = 0;
+  res->bFullScreen   = true;
+  res->iSubtitles    = (int)(0.965 * res->iHeight);
+  res->fPixelRatio   = 1.0f;
+  res->strMode.Format("%dx%d @ %.2f%s - Full Screen", res->iScreenWidth, res->iScreenHeight, res->fRefreshRate,
+    res->dwFlags & D3DPRESENTFLAG_INTERLACED ? "i" : "");
+
+  return res->iWidth > 0 && res->iHeight> 0;
+}
+
+void CEGLNativeTypeAmlogic::EnableFreeScale()
+{
+  // remove default OSD and video path (default_osd default)
+  set_sysfs_str("/sys/class/vfm/map", "rm all");
+  usleep(60 * 1000);
+
+  // add OSD path
+  set_sysfs_str("/sys/class/vfm/map", "add osdpath osd amvideo");
+  // enable OSD free scale using frame buffer size of 720p
+  set_sysfs_int("/sys/class/graphics/fb0/free_scale", 0);
+  set_sysfs_int("/sys/class/graphics/fb1/free_scale", 0);
+  set_sysfs_int("/sys/class/graphics/fb0/scale_width",  1280);
+  set_sysfs_int("/sys/class/graphics/fb0/scale_height", 720);
+  set_sysfs_int("/sys/class/graphics/fb1/scale_width",  1280);
+  set_sysfs_int("/sys/class/graphics/fb1/scale_height", 720);
+  set_sysfs_int("/sys/class/graphics/fb0/free_scale", 1);
+  set_sysfs_int("/sys/class/graphics/fb1/free_scale", 1);
+  usleep(60 * 1000);
+  // remove OSD path
+  set_sysfs_int("/sys/class/graphics/fb0/free_scale", 0);
+  set_sysfs_int("/sys/class/graphics/fb1/free_scale", 0);
+  set_sysfs_str("/sys/class/vfm/map", "rm osdpath");
+  usleep(60 * 1000);
+  // add video path
+  set_sysfs_str("/sys/class/vfm/map", "add videopath decoder ppmgr amvideo");
+  // enable video free scale (scaling to 1920x1080 with frame buffer size 1280x720)
+  set_sysfs_int("/sys/class/ppmgr/ppscaler", 0);
+  set_sysfs_int("/sys/class/video/disable_video", 1);
+  set_sysfs_int("/sys/class/ppmgr/ppscaler", 1);
+  set_sysfs_str("/sys/class/ppmgr/ppscaler_rect", "0 0 1919 1079 0");
+  set_sysfs_str("/sys/class/ppmgr/disp", "1280 720");
+  usleep(60 * 1000);
+  //
+  set_sysfs_int("/sys/class/graphics/fb0/free_scale", 0);
+  set_sysfs_int("/sys/class/graphics/fb1/free_scale", 0);
+  set_sysfs_int("/sys/class/graphics/fb0/scale_width",  1280);
+  set_sysfs_int("/sys/class/graphics/fb0/scale_height", 720);
+  set_sysfs_int("/sys/class/graphics/fb1/scale_width",  1280);
+  set_sysfs_int("/sys/class/graphics/fb1/scale_height", 720);
+  set_sysfs_int("/sys/class/graphics/fb0/free_scale", 1);
+  set_sysfs_int("/sys/class/graphics/fb1/free_scale", 1);
+  usleep(60 * 1000);
+  //
+  set_sysfs_int("/sys/class/video/disable_video", 2);
+  set_sysfs_str("/sys/class/display/axis", "0 0 1279 719 0 0 0 0");
+  set_sysfs_str("/sys/class/ppmgr/ppscaler_rect", "0 0 1279 719 1");
+}
+
+void CEGLNativeTypeAmlogic::DisableFreeScale()
+{
+  // turn off frame buffer freescale
+  set_sysfs_int("/sys/class/graphics/fb0/free_scale", 0);
+  set_sysfs_int("/sys/class/graphics/fb1/free_scale", 0);
+  // revert to default video paths
+  set_sysfs_str("/sys/class/vfm/map", "rm all");
+  set_sysfs_str("/sys/class/vfm/map", "add default_osd osd amvideo");
+  set_sysfs_str("/sys/class/vfm/map", "add default decoder ppmgr amvideo");
+  // disable post processing scaler and disable_video special mode
+  set_sysfs_int("/sys/class/ppmgr/ppscaler", 0);
+  set_sysfs_int("/sys/class/video/disable_video", 0);
+
+  // revert display axis
+  int fd0;
+  std::string framebuffer = "/dev/fbo";
+
+  if ((fd0 = open(framebuffer.c_str(), O_RDWR)) >= 0)
+  {
+    struct fb_var_screeninfo vinfo;
+    if (ioctl(fd0, FBIOGET_VSCREENINFO, &vinfo) == 0)
+    {
+      char daxis_str[255] = {0};
+      sprintf(daxis_str, "%d %d %d %d 0 0 0 0", 0, 0, vinfo.xres, vinfo.yres);
+      set_sysfs_str("/sys/class/display/axis", daxis_str);
+    }
+    close(fd0);
+  }
+}
+
+void CEGLNativeTypeAmlogic::SetCpuMinLimit(bool limit)
+{
+  // when playing hw decoded audio, we cannot drop below 600MHz
+  // or risk hw audio issues. AML code does a 2X scaling based off
+  // /sys/class/audiodsp/codec_mips but tests show that this is
+  // seems risky so we just clamp to 600Mhz to be safe.
+
+  // only adjust if we are running "ondemand"
+  char scaling_governor[256] = {0};
+  get_sysfs_str("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor", scaling_governor, 255);
+  if (strncmp(scaling_governor, "ondemand", 255))
+    return;
+
+  int freq;
+  if (limit)
+    freq = 600000;
+  else
+    freq = get_sysfs_int("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq");
+  set_sysfs_int("/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq", freq);
+}
diff --git a/xbmc/windowing/egl/EGLNativeTypeAmlogic.h b/xbmc/windowing/egl/EGLNativeTypeAmlogic.h
new file mode 100644 (file)
index 0000000..42f7a0e
--- /dev/null
@@ -0,0 +1,61 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2012 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "EGLNativeType.h"
+class CEGLNativeTypeAmlogic : public CEGLNativeType
+{
+public:
+  CEGLNativeTypeAmlogic();
+  virtual ~CEGLNativeTypeAmlogic();
+  virtual std::string GetNativeName() const { return "amlogic"; };
+  virtual bool  CheckCompatibility();
+  virtual void  Initialize();
+  virtual void  Destroy();
+  virtual int   GetQuirks() { return EGL_QUIRK_NONE; };
+
+  virtual bool  CreateNativeDisplay();
+  virtual bool  CreateNativeWindow();
+  virtual bool  GetNativeDisplay(EGLNativeDisplayType **nativeDisplay) const;
+  virtual bool  GetNativeWindow(EGLNativeWindowType **nativeWindow) const;
+
+  virtual bool  DestroyNativeWindow();
+  virtual bool  DestroyNativeDisplay();
+
+  virtual bool  GetNativeResolution(RESOLUTION_INFO *res) const;
+  virtual bool  SetNativeResolution(const RESOLUTION_INFO &res);
+  virtual bool  ProbeResolutions(std::vector<RESOLUTION_INFO> &resolutions);
+  virtual bool  GetPreferredResolution(RESOLUTION_INFO *res) const;
+
+  virtual bool  ShowWindow(bool show);
+
+protected:
+  int get_sysfs_str(const char *path, char *valstr, const int size) const;
+  int set_sysfs_str(const char *path, const char *val) const;
+  int set_sysfs_int(const char *path, const int val) const;
+  int get_sysfs_int(const char *path) const;
+
+  bool SetDisplayResolution(const char *resolution);
+  bool ModeToResolution(const char *mode, RESOLUTION_INFO *res) const;
+  void EnableFreeScale();
+  void DisableFreeScale();
+  void SetCpuMinLimit(bool limit);
+};
diff --git a/xbmc/windowing/egl/EGLNativeTypeAndroid.cpp b/xbmc/windowing/egl/EGLNativeTypeAndroid.cpp
new file mode 100644 (file)
index 0000000..c06f4a2
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ *      Copyright (C) 2011-2012 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include "system.h"
+#include "EGLNativeTypeAndroid.h"
+#include "utils/log.h"
+#include "guilib/gui3d.h"
+#if defined(TARGET_ANDROID)
+#include "android/activity/XBMCApp.h"
+#endif
+CEGLNativeTypeAndroid::CEGLNativeTypeAndroid()
+{
+}
+
+CEGLNativeTypeAndroid::~CEGLNativeTypeAndroid()
+{
+} 
+
+bool CEGLNativeTypeAndroid::CheckCompatibility()
+{
+#if defined(TARGET_ANDROID)
+  return true;
+#endif
+  return false;
+}
+
+void CEGLNativeTypeAndroid::Initialize()
+{
+  return;
+}
+void CEGLNativeTypeAndroid::Destroy()
+{
+  return;
+}
+
+bool CEGLNativeTypeAndroid::CreateNativeDisplay()
+{
+  m_nativeDisplay = EGL_DEFAULT_DISPLAY;
+  return true;
+}
+
+bool CEGLNativeTypeAndroid::CreateNativeWindow()
+{
+#if defined(TARGET_ANDROID)
+  m_nativeWindow = CXBMCApp::GetNativeWindow();
+  return true;
+#else
+  return false;
+#endif
+}  
+
+bool CEGLNativeTypeAndroid::GetNativeDisplay(EGLNativeDisplayType **nativeDisplay) const
+{
+  *nativeDisplay = (EGLNativeDisplayType*) &m_nativeDisplay;
+  return true;
+}
+
+bool CEGLNativeTypeAndroid::GetNativeWindow(EGLNativeWindowType **nativeWindow) const
+{
+  *nativeWindow = (EGLNativeWindowType*) &m_nativeWindow;
+  return true;
+}
+
+bool CEGLNativeTypeAndroid::DestroyNativeDisplay()
+{
+  return true;
+}
+
+bool CEGLNativeTypeAndroid::DestroyNativeWindow()
+{
+  return true;
+}
+
+bool CEGLNativeTypeAndroid::GetNativeResolution(RESOLUTION_INFO *res) const
+{
+#if defined(TARGET_ANDROID)
+  ANativeWindow_acquire(m_nativeWindow);
+  res->iWidth = ANativeWindow_getWidth(m_nativeWindow);
+  res->iHeight= ANativeWindow_getHeight(m_nativeWindow);
+  ANativeWindow_release(m_nativeWindow);
+
+  res->fRefreshRate = 60;
+  res->dwFlags= D3DPRESENTFLAG_PROGRESSIVE;
+  res->iScreen       = 0;
+  res->bFullScreen   = true;
+  res->iSubtitles    = (int)(0.965 * res->iHeight);
+  res->fPixelRatio   = 1.0f;
+  res->iScreenWidth  = res->iWidth;
+  res->iScreenHeight = res->iHeight;
+  res->strMode.Format("%dx%d @ %.2f%s - Full Screen", res->iScreenWidth, res->iScreenHeight, res->fRefreshRate,
+  res->dwFlags & D3DPRESENTFLAG_INTERLACED ? "i" : "");
+  CLog::Log(LOGNOTICE,"Current resolution: %s\n",res->strMode.c_str());
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool CEGLNativeTypeAndroid::SetNativeResolution(const RESOLUTION_INFO &res)
+{
+  return false;
+}
+
+bool CEGLNativeTypeAndroid::ProbeResolutions(std::vector<RESOLUTION_INFO> &resolutions)
+{
+  RESOLUTION_INFO res;
+  bool ret = false;
+  ret = GetNativeResolution(&res);
+  if (ret && res.iWidth > 1 && res.iHeight > 1)
+  {
+    resolutions.push_back(res);
+    return true;
+  }
+  return false;
+}
+
+bool CEGLNativeTypeAndroid::GetPreferredResolution(RESOLUTION_INFO *res) const
+{
+  return false;
+}
+
+bool CEGLNativeTypeAndroid::ShowWindow(bool show)
+{
+  return false;
+}
\ No newline at end of file
diff --git a/xbmc/windowing/egl/EGLNativeTypeAndroid.h b/xbmc/windowing/egl/EGLNativeTypeAndroid.h
new file mode 100644 (file)
index 0000000..eb7afbf
--- /dev/null
@@ -0,0 +1,49 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2012 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "EGLNativeType.h"
+class CEGLNativeTypeAndroid : public CEGLNativeType
+{
+public:
+  CEGLNativeTypeAndroid();
+  virtual ~CEGLNativeTypeAndroid();
+  virtual std::string GetNativeName() const { return "android"; };
+  virtual bool  CheckCompatibility();
+  virtual void  Initialize();
+  virtual void  Destroy();
+  virtual int   GetQuirks() { return EGL_QUIRK_NEED_WINDOW_FOR_RES; };
+
+  virtual bool  CreateNativeDisplay();
+  virtual bool  CreateNativeWindow();
+  virtual bool  GetNativeDisplay(EGLNativeDisplayType **nativeDisplay) const;
+  virtual bool  GetNativeWindow(EGLNativeWindowType **nativeWindow) const;
+
+  virtual bool  DestroyNativeWindow();
+  virtual bool  DestroyNativeDisplay();
+
+  virtual bool  GetNativeResolution(RESOLUTION_INFO *res) const;
+  virtual bool  SetNativeResolution(const RESOLUTION_INFO &res);
+  virtual bool  ProbeResolutions(std::vector<RESOLUTION_INFO> &resolutions);
+  virtual bool  GetPreferredResolution(RESOLUTION_INFO *res) const;
+
+  virtual bool  ShowWindow(bool show);
+};
diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
new file mode 100644 (file)
index 0000000..a4b1b07
--- /dev/null
@@ -0,0 +1,573 @@
+/*
+ *      Copyright (C) 2011-2012 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include "system.h"
+
+#include "EGLNativeTypeRaspberryPI.h"
+#include "utils/log.h"
+#include "guilib/gui3d.h"
+#include "linux/DllBCM.h"
+
+#ifndef __VIDEOCORE4__
+#define __VIDEOCORE4__
+#endif
+
+#define __VCCOREVER__ 0x04000000
+
+#define IS_WIDESCREEN(m) ( m == 3 || m == 7 || m == 9 || \
+    m == 11 || m == 13 || m == 15 || m == 18 || m == 22 || \
+    m == 24 || m == 26 || m == 28 || m == 30 || m == 36 || \
+    m == 38 || m == 43 || m == 45 || m == 49 || m == 51 || \
+    m == 53 || m == 55 || m == 57 || m == 59)
+
+#define MAKEFLAGS(group, mode, interlace, mode3d) \
+  ( ( (mode)<<24 ) | ( (group)<<16 ) | \
+   ( (interlace) != 0 ? D3DPRESENTFLAG_INTERLACED : D3DPRESENTFLAG_PROGRESSIVE) | \
+   ( ((group) == HDMI_RES_GROUP_CEA && IS_WIDESCREEN(mode) ) ? D3DPRESENTFLAG_WIDESCREEN : 0) | \
+   ( (mode3d) != 0 ? D3DPRESENTFLAG_MODE3DSBS : 0 ))
+
+#define GETFLAGS_INTERLACE(f)   ( ( (f) & D3DPRESENTFLAG_INTERLACED ) != 0)
+#define GETFLAGS_WIDESCREEN(f)  ( ( (f) & D3DPRESENTFLAG_WIDESCREEN ) != 0)
+#define GETFLAGS_GROUP(f)       ( (HDMI_RES_GROUP_T)( ((f) >> 16) & 0xff ))
+#define GETFLAGS_MODE(f)        ( ( (f) >>24 ) & 0xff )
+#define GETFLAGS_MODE3D(f)      ( ( (f) & D3DPRESENTFLAG_MODE3DSBS ) !=0 )
+
+#define TV_MAX_SUPPORTED_MODES 60
+
+//#ifndef DEBUG_PRINT
+//#define DEBUG_PRINT 1
+//#endif
+
+#if defined(DEBUG_PRINT)
+# define DLOG(fmt, args...) printf(fmt, ##args)
+#else
+# define DLOG(fmt, args...)
+#endif
+
+
+CEGLNativeTypeRaspberryPI::CEGLNativeTypeRaspberryPI()
+{
+#if defined(TARGET_RASPBERRY_PI)
+  m_DllBcmHost    = NULL;
+  m_nativeWindow  = NULL;
+#endif
+}
+
+CEGLNativeTypeRaspberryPI::~CEGLNativeTypeRaspberryPI()
+{
+#if defined(TARGET_RASPBERRY_PI)
+  delete m_DllBcmHost;
+  if(m_nativeWindow)
+    free(m_nativeWindow);
+#endif
+} 
+
+bool CEGLNativeTypeRaspberryPI::CheckCompatibility()
+{
+#if defined(TARGET_RASPBERRY_PI)
+  DLOG("CEGLNativeTypeRaspberryPI::CheckCompatibility\n");
+  return true;
+#else
+  return false;
+#endif
+}
+
+void CEGLNativeTypeRaspberryPI::Initialize()
+{
+#if defined(TARGET_RASPBERRY_PI)
+  m_DllBcmHost              = NULL;
+  m_dispman_element         = DISPMANX_NO_HANDLE;
+  m_dispman_element2        = DISPMANX_NO_HANDLE;
+  m_dispman_display         = DISPMANX_NO_HANDLE;
+
+  m_width                   = 1280;
+  m_height                  = 720;
+  m_initDesktopRes          = true;
+
+  m_DllBcmHost = new DllBcmHost;
+  m_DllBcmHost->Load();
+#endif
+}
+
+void CEGLNativeTypeRaspberryPI::Destroy()
+{
+#if defined(TARGET_RASPBERRY_PI)
+  if(m_DllBcmHost && m_DllBcmHost->IsLoaded())
+    m_DllBcmHost->Unload();
+  delete m_DllBcmHost;
+  m_DllBcmHost = NULL;
+#endif
+}
+
+bool CEGLNativeTypeRaspberryPI::CreateNativeDisplay()
+{
+  m_nativeDisplay = EGL_DEFAULT_DISPLAY;
+  return true;
+}
+
+bool CEGLNativeTypeRaspberryPI::CreateNativeWindow()
+{
+#if defined(TARGET_RASPBERRY_PI)
+  if(!m_nativeWindow)
+    m_nativeWindow = (EGLNativeWindowType) calloc(1,sizeof( EGL_DISPMANX_WINDOW_T));
+  DLOG("CEGLNativeTypeRaspberryPI::CEGLNativeTypeRaspberryPI\n");
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool CEGLNativeTypeRaspberryPI::GetNativeDisplay(EGLNativeDisplayType **nativeDisplay) const
+{
+  *nativeDisplay = (EGLNativeDisplayType*) &m_nativeDisplay;
+  return true;
+}
+
+bool CEGLNativeTypeRaspberryPI::GetNativeWindow(EGLNativeWindowType **nativeWindow) const
+{
+  *nativeWindow = (EGLNativeWindowType*) &m_nativeWindow;
+  DLOG("CEGLNativeTypeRaspberryPI::GetNativeWindow\n");
+  return true;
+}  
+
+bool CEGLNativeTypeRaspberryPI::DestroyNativeDisplay()
+{
+  DLOG("CEGLNativeTypeRaspberryPI::DestroyNativeDisplay\n");
+  return true;
+}
+
+bool CEGLNativeTypeRaspberryPI::DestroyNativeWindow()
+{
+#if defined(TARGET_RASPBERRY_PI)
+  DestroyDispmaxWindow();
+  free(m_nativeWindow);
+  m_nativeWindow = NULL;
+  DLOG("CEGLNativeTypeRaspberryPI::DestroyNativeWindow\n");
+  return true;
+#else
+  return false;
+#endif  
+}
+
+bool CEGLNativeTypeRaspberryPI::GetNativeResolution(RESOLUTION_INFO *res) const
+{
+#if defined(TARGET_RASPBERRY_PI)
+  *res = m_desktopRes;
+
+  DLOG("CEGLNativeTypeRaspberryPI::GetNativeResolution %s\n", res->strMode.c_str());
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool CEGLNativeTypeRaspberryPI::SetNativeResolution(const RESOLUTION_INFO &res)
+{
+#if defined(TARGET_RASPBERRY_PI)
+  bool bFound = false;
+
+  if(!m_DllBcmHost || !m_nativeWindow)
+    return false;
+
+  DestroyDispmaxWindow();
+
+  RESOLUTION_INFO resSearch;
+
+  int best_score = 0;
+
+  for (size_t i = 0; i < m_res.size(); i++)
+  {
+    if(m_res[i].iScreenWidth == res.iScreenWidth && m_res[i].iScreenHeight == res.iScreenHeight && m_res[i].fRefreshRate == res.fRefreshRate)
+    {
+      int score = 0;
+
+      /* prefere progressive over interlaced */
+      if(!GETFLAGS_INTERLACE(m_res[i].dwFlags))
+        score = 1;
+
+      if(score >= best_score)
+      {
+        resSearch = m_res[i];
+        bFound = true;
+      }
+    }
+  }
+
+  if(bFound && !m_fixedMode)
+  {
+    sem_init(&m_tv_synced, 0, 0);
+    m_DllBcmHost->vc_tv_register_callback(CallbackTvServiceCallback, this);
+
+    int success = m_DllBcmHost->vc_tv_hdmi_power_on_explicit(HDMI_MODE_HDMI, GETFLAGS_GROUP(resSearch.dwFlags), GETFLAGS_MODE(resSearch.dwFlags));
+
+    if (success == 0)
+    {
+      CLog::Log(LOGDEBUG, "EGL set HDMI mode (%d,%d,%d)=%d\n",
+                          GETFLAGS_MODE3D(resSearch.dwFlags) ? HDMI_MODE_3D:HDMI_MODE_HDMI, GETFLAGS_GROUP(resSearch.dwFlags),
+                          GETFLAGS_MODE(resSearch.dwFlags), success);
+      sem_wait(&m_tv_synced);
+    }
+    else
+    {
+      CLog::Log(LOGERROR, "EGL failed to set HDMI mode (%d,%d,%d)=%d\n",
+                          GETFLAGS_MODE3D(resSearch.dwFlags) ? HDMI_MODE_3D:HDMI_MODE_HDMI, GETFLAGS_GROUP(resSearch.dwFlags),
+                          GETFLAGS_MODE(resSearch.dwFlags), success);
+    }
+    m_DllBcmHost->vc_tv_unregister_callback(CallbackTvServiceCallback);
+    sem_destroy(&m_tv_synced);
+
+    m_desktopRes = resSearch;
+  }
+
+  m_dispman_display = m_DllBcmHost->vc_dispmanx_display_open(0);
+
+  m_width   = res.iWidth;
+  m_height  = res.iHeight;
+
+  VC_RECT_T dst_rect;
+  VC_RECT_T src_rect;
+
+  dst_rect.x      = 0;
+  dst_rect.y      = 0;
+  dst_rect.width  = res.iScreenWidth;
+  dst_rect.height = res.iScreenHeight;
+
+  src_rect.x      = 0;
+  src_rect.y      = 0;
+  src_rect.width  = m_width << 16;
+  src_rect.height = m_height << 16;
+
+  VC_DISPMANX_ALPHA_T alpha;
+  memset(&alpha, 0x0, sizeof(VC_DISPMANX_ALPHA_T));
+  alpha.flags = DISPMANX_FLAGS_ALPHA_FROM_SOURCE;
+
+  DISPMANX_CLAMP_T clamp;
+  memset(&clamp, 0x0, sizeof(DISPMANX_CLAMP_T));
+
+  DISPMANX_TRANSFORM_T transform = DISPMANX_NO_ROTATE;
+  DISPMANX_UPDATE_HANDLE_T dispman_update = m_DllBcmHost->vc_dispmanx_update_start(0);
+
+  CLog::Log(LOGDEBUG, "EGL set resolution %dx%d -> %dx%d @ %.2f fps\n",
+      m_width, m_height, dst_rect.width, dst_rect.height, bFound ? resSearch.fRefreshRate : res.fRefreshRate);
+
+  // The trick for SBS is that we stick two dispman elements together 
+  // and the PI firmware knows that we are in SBS mode and it renders the gui in SBS
+  if(bFound && (resSearch.dwFlags & D3DPRESENTFLAG_MODE3DSBS))
+  {
+    // right side
+    dst_rect.x = res.iScreenWidth;
+    dst_rect.width = res.iScreenWidth;
+
+    m_dispman_element2 = m_DllBcmHost->vc_dispmanx_element_add(dispman_update,
+      m_dispman_display,
+      1,                              // layer
+      &dst_rect,
+      (DISPMANX_RESOURCE_HANDLE_T)0,  // src
+      &src_rect,
+      DISPMANX_PROTECTION_NONE,
+      &alpha,                         // alpha
+      &clamp,                         // clamp
+      transform);                     // transform
+      assert(m_dispman_element2 != DISPMANX_NO_HANDLE);
+      assert(m_dispman_element2 != (unsigned)DISPMANX_INVALID);
+
+    // left side - fall through
+    dst_rect.x = 0;
+    dst_rect.width = res.iScreenWidth;
+  }
+
+  m_dispman_element = m_DllBcmHost->vc_dispmanx_element_add(dispman_update,
+    m_dispman_display,
+    1,                              // layer
+    &dst_rect,
+    (DISPMANX_RESOURCE_HANDLE_T)0,  // src
+    &src_rect,
+    DISPMANX_PROTECTION_NONE,
+    &alpha,                         //alphe
+    &clamp,                         //clamp
+    transform);                     // transform
+
+  assert(m_dispman_element != DISPMANX_NO_HANDLE);
+  assert(m_dispman_element != (unsigned)DISPMANX_INVALID);
+
+  memset(m_nativeWindow, 0, sizeof(EGL_DISPMANX_WINDOW_T));
+
+  EGL_DISPMANX_WINDOW_T *nativeWindow = (EGL_DISPMANX_WINDOW_T *)m_nativeWindow;
+
+  nativeWindow->element = m_dispman_element;
+  nativeWindow->width   = m_width;
+  nativeWindow->height  = m_height;
+
+  m_DllBcmHost->vc_dispmanx_display_set_background(dispman_update, m_dispman_display, 0x00, 0x00, 0x00);
+  m_DllBcmHost->vc_dispmanx_update_submit_sync(dispman_update);
+
+  DLOG("CEGLNativeTypeRaspberryPI::SetNativeResolution\n");
+
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector<RESOLUTION_INFO> &resolutions)
+{
+#if defined(TARGET_RASPBERRY_PI)
+  resolutions.clear();
+  m_res.clear();
+
+  if(!m_DllBcmHost)
+    return false;
+
+  m_fixedMode               = false;
+
+  /* read initial desktop resolution before probe resolutions.
+   * probing will replace the desktop resolution when it finds the same one.
+   * we raplace it because probing will generate more detailed 
+   * resolution flags we don't get with vc_tv_get_state.
+   */
+
+  if(m_initDesktopRes)
+  {
+    TV_GET_STATE_RESP_T tv_state;
+
+    // get current display settings state
+    memset(&tv_state, 0, sizeof(TV_GET_STATE_RESP_T));
+    m_DllBcmHost->vc_tv_get_state(&tv_state);
+
+    m_desktopRes.iScreen      = 0;
+    m_desktopRes.bFullScreen  = true;
+    m_desktopRes.iWidth       = tv_state.width;
+    m_desktopRes.iHeight      = tv_state.height;
+    m_desktopRes.iScreenWidth = tv_state.width;
+    m_desktopRes.iScreenHeight= tv_state.height;
+    m_desktopRes.dwFlags      = tv_state.scan_mode ? D3DPRESENTFLAG_INTERLACED : D3DPRESENTFLAG_PROGRESSIVE;
+    m_desktopRes.fRefreshRate = (float)tv_state.frame_rate;
+    m_desktopRes.strMode.Format("%dx%d", tv_state.width, tv_state.height);
+    if((float)tv_state.frame_rate > 1)
+    {
+        m_desktopRes.strMode.Format("%s @ %.2f%s - Full Screen", m_desktopRes.strMode, (float)tv_state.frame_rate,
+            m_desktopRes.dwFlags & D3DPRESENTFLAG_INTERLACED ? "i" : "");
+    }
+    m_initDesktopRes = false;
+
+    int gui_width  = m_desktopRes.iWidth;
+    int gui_height = m_desktopRes.iHeight;
+
+    ClampToGUIDisplayLimits(gui_width, gui_height);
+
+    m_desktopRes.iWidth = gui_width;
+    m_desktopRes.iHeight = gui_height;
+
+    m_desktopRes.iSubtitles   = (int)(0.965 * m_desktopRes.iHeight);
+
+    CLog::Log(LOGDEBUG, "EGL initial desktop resolution %s\n", m_desktopRes.strMode.c_str());
+  }
+
+
+  GetSupportedModes(HDMI_RES_GROUP_CEA, resolutions);
+  GetSupportedModes(HDMI_RES_GROUP_DMT, resolutions);
+  GetSupportedModes(HDMI_RES_GROUP_CEA_3D, resolutions);
+
+  if(resolutions.size() == 0)
+  {
+    TV_GET_STATE_RESP_T tv;
+    m_DllBcmHost->vc_tv_get_state(&tv);
+
+    RESOLUTION_INFO res;
+    CLog::Log(LOGDEBUG, "EGL probe resolution %dx%d@%f %s:%x\n",
+        m_desktopRes.iWidth, m_desktopRes.iHeight, m_desktopRes.fRefreshRate,
+        m_desktopRes.dwFlags & D3DPRESENTFLAG_INTERLACED ? "i" : "p");
+
+    m_res.push_back(m_desktopRes);
+    resolutions.push_back(m_desktopRes);
+  }
+
+  if(resolutions.size() < 2)
+    m_fixedMode = true;
+
+  DLOG("CEGLNativeTypeRaspberryPI::ProbeResolutions\n");
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool CEGLNativeTypeRaspberryPI::GetPreferredResolution(RESOLUTION_INFO *res) const
+{
+  DLOG("CEGLNativeTypeRaspberryPI::GetPreferredResolution\n");
+  return false;
+}
+
+bool CEGLNativeTypeRaspberryPI::ShowWindow(bool show)
+{
+  DLOG("CEGLNativeTypeRaspberryPI::ShowWindow\n");
+  return false;
+}
+
+#if defined(TARGET_RASPBERRY_PI)
+void CEGLNativeTypeRaspberryPI::DestroyDispmaxWindow()
+{
+  if(!m_DllBcmHost)
+    return;
+
+  DISPMANX_UPDATE_HANDLE_T dispman_update = m_DllBcmHost->vc_dispmanx_update_start(0);
+
+  if (m_dispman_element != DISPMANX_NO_HANDLE)
+  {
+    m_DllBcmHost->vc_dispmanx_element_remove(dispman_update, m_dispman_element);
+    m_dispman_element = DISPMANX_NO_HANDLE;
+  }
+  if (m_dispman_element2 != DISPMANX_NO_HANDLE)
+  {
+    m_DllBcmHost->vc_dispmanx_element_remove(dispman_update, m_dispman_element2);
+    m_dispman_element2 = DISPMANX_NO_HANDLE;
+  }
+  m_DllBcmHost->vc_dispmanx_update_submit_sync(dispman_update);
+
+  if (m_dispman_display != DISPMANX_NO_HANDLE)
+  {
+    m_DllBcmHost->vc_dispmanx_display_close(m_dispman_display);
+    m_dispman_display = DISPMANX_NO_HANDLE;
+  }
+  DLOG("CEGLNativeTypeRaspberryPI::DestroyDispmaxWindow\n");
+}
+
+void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::vector<RESOLUTION_INFO> &resolutions)
+{
+  if(!m_DllBcmHost)
+    return;
+
+  //Supported HDMI CEA/DMT resolutions, first one will be preferred resolution
+  TV_SUPPORTED_MODE_T supported_modes[TV_MAX_SUPPORTED_MODES];
+  int32_t num_modes;
+  HDMI_RES_GROUP_T prefer_group;
+  uint32_t prefer_mode;
+  int i;
+
+  num_modes = m_DllBcmHost->vc_tv_hdmi_get_supported_modes(group,
+      supported_modes, TV_MAX_SUPPORTED_MODES, &prefer_group, &prefer_mode);
+
+  CLog::Log(LOGDEBUG, "EGL get supported modes (%d) = %d, prefer_group=%x, prefer_mode=%x\n",
+      group, num_modes, prefer_group, prefer_mode);
+
+  if (num_modes > 0 && prefer_group != HDMI_RES_GROUP_INVALID)
+  {
+    TV_SUPPORTED_MODE_T *tv = supported_modes;
+    for (i=0; i < num_modes; i++, tv++)
+    {
+      // treat 3D modes as half-width SBS
+      unsigned int width = (group == HDMI_RES_GROUP_CEA_3D) ? tv->width>>1 : tv->width;
+      RESOLUTION_INFO res;
+      CLog::Log(LOGDEBUG, "EGL mode %d: %dx%d@%d %s%s:%x\n", i, width, tv->height, tv->frame_rate,
+          tv->native ? "N" : "", tv->scan_mode ? "I" : "", tv->code);
+
+      res.iScreen       = 0;
+      res.bFullScreen   = true;
+      res.dwFlags       = MAKEFLAGS(group, tv->code, tv->scan_mode, group==HDMI_RES_GROUP_CEA_3D);
+      res.fRefreshRate  = (float)tv->frame_rate;
+      res.fPixelRatio   = 1.0f;
+      res.iWidth        = width;
+      res.iHeight       = tv->height;
+      res.iScreenWidth  = width;
+      res.iScreenHeight = tv->height;
+      res.strMode.Format("%dx%d", width, tv->height);
+      if((float)tv->frame_rate > 1)
+      {
+        res.strMode.Format("%dx%d @ %.2f%s - Full Screen", res.iScreenWidth, res.iScreenHeight, res.fRefreshRate,
+          res.dwFlags & D3DPRESENTFLAG_INTERLACED ? "i" : "");
+      }
+
+      int gui_width  = res.iWidth;
+      int gui_height = res.iHeight;
+
+      ClampToGUIDisplayLimits(gui_width, gui_height);
+
+      res.iWidth = gui_width;
+      res.iHeight = gui_height;
+
+      res.iSubtitles    = (int)(0.965 * res.iHeight);
+
+      resolutions.push_back(res);
+
+      /* replace initial desktop resolution with probed hdmi resolution */
+      if(m_desktopRes.iWidth == res.iWidth && m_desktopRes.iHeight == res.iHeight &&
+          m_desktopRes.iScreenWidth == res.iScreenWidth && m_desktopRes.iScreenHeight == res.iScreenHeight &&
+          m_desktopRes.fRefreshRate == res.fRefreshRate)
+      {
+        m_desktopRes = res;
+        CLog::Log(LOGDEBUG, "EGL desktop replacement resolution %dx%d@%d %s%s:%x\n",
+            width, tv->height, tv->frame_rate, tv->native ? "N" : "", tv->scan_mode ? "I" : "", tv->code);
+      }
+
+      m_res.push_back(res);
+    }
+  }
+}
+
+void CEGLNativeTypeRaspberryPI::TvServiceCallback(uint32_t reason, uint32_t param1, uint32_t param2)
+{
+  CLog::Log(LOGDEBUG, "EGL tv_service_callback (%d,%d,%d)\n", reason, param1, param2);
+  switch(reason)
+  {
+  case VC_HDMI_UNPLUGGED:
+    break;
+  case VC_HDMI_STANDBY:
+    break;
+  case VC_SDTV_NTSC:
+  case VC_SDTV_PAL:
+  case VC_HDMI_HDMI:
+  case VC_HDMI_DVI:
+    //Signal we are ready now
+    sem_post(&m_tv_synced);
+    break;
+  default:
+     break;
+  }
+}
+
+void CEGLNativeTypeRaspberryPI::CallbackTvServiceCallback(void *userdata, uint32_t reason, uint32_t param1, uint32_t param2)
+{
+   CEGLNativeTypeRaspberryPI *callback = static_cast<CEGLNativeTypeRaspberryPI*>(userdata);
+   callback->TvServiceCallback(reason, param1, param2);
+}
+
+bool CEGLNativeTypeRaspberryPI::ClampToGUIDisplayLimits(int &width, int &height)
+{
+  const int max_width = 1280, max_height = 720;
+  float ar = (float)width/(float)height;
+  // bigger than maximum, so need to clamp
+  if (width > max_width || height > max_height) {
+    // wider than max, so clamp width first
+    if (ar > (float)max_width/(float)max_height)
+    {
+      width = max_width;
+      height = (float)max_width / ar + 0.5f;
+    // taller than max, so clamp height first
+    } else {
+      height = max_height;
+      width = (float)max_height * ar + 0.5f;
+    }
+    return true;
+  }
+
+  return false;
+}
+
+#endif
+
diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.h b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.h
new file mode 100644 (file)
index 0000000..73440e2
--- /dev/null
@@ -0,0 +1,74 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2012 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "EGLNativeType.h"
+#include <semaphore.h>
+
+class DllBcmHost;
+class CEGLNativeTypeRaspberryPI : public CEGLNativeType
+{
+public:
+  CEGLNativeTypeRaspberryPI();
+  virtual ~CEGLNativeTypeRaspberryPI();
+  virtual std::string GetNativeName() const { return "raspberrypi"; };
+  virtual bool  CheckCompatibility();
+  virtual void  Initialize();
+  virtual void  Destroy();
+  virtual int   GetQuirks() { return EGL_QUIRK_NONE; };
+
+  virtual bool  CreateNativeDisplay();
+  virtual bool  CreateNativeWindow();
+  virtual bool  GetNativeDisplay(EGLNativeDisplayType **nativeDisplay) const;
+  virtual bool  GetNativeWindow(EGLNativeWindowType **nativeWindow) const;
+
+  virtual bool  DestroyNativeWindow();
+  virtual bool  DestroyNativeDisplay();
+
+  virtual bool  GetNativeResolution(RESOLUTION_INFO *res) const;
+  virtual bool  SetNativeResolution(const RESOLUTION_INFO &res);
+  virtual bool  ProbeResolutions(std::vector<RESOLUTION_INFO> &resolutions);
+  virtual bool  GetPreferredResolution(RESOLUTION_INFO *res) const;
+
+  virtual bool  ShowWindow(bool show);
+#if defined(TARGET_RASPBERRY_PI)
+private:
+  DllBcmHost                    *m_DllBcmHost;
+  DISPMANX_ELEMENT_HANDLE_T     m_dispman_display;
+  DISPMANX_ELEMENT_HANDLE_T     m_dispman_element;
+  DISPMANX_ELEMENT_HANDLE_T     m_dispman_element2;
+  TV_GET_STATE_RESP_T           m_tv_state;
+  sem_t                         m_tv_synced;
+  bool                          m_fixedMode;
+  std::vector<RESOLUTION_INFO>  m_res;
+  RESOLUTION_INFO               m_desktopRes;
+  int                           m_width;
+  int                           m_height;
+  int                           m_initDesktopRes;
+
+  void GetSupportedModes(HDMI_RES_GROUP_T group, std::vector<RESOLUTION_INFO> &resolutions);
+  void TvServiceCallback(uint32_t reason, uint32_t param1, uint32_t param2);
+  static void CallbackTvServiceCallback(void *userdata, uint32_t reason, uint32_t param1, uint32_t param2);
+
+  void DestroyDispmaxWindow();
+  bool ClampToGUIDisplayLimits(int &width, int &height);
+#endif
+};
diff --git a/xbmc/windowing/egl/EGLQuirks.h b/xbmc/windowing/egl/EGLQuirks.h
new file mode 100644 (file)
index 0000000..5b4d6b9
--- /dev/null
@@ -0,0 +1,24 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2012 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#define EGL_QUIRK_NONE 0
+#define EGL_QUIRK_NEED_WINDOW_FOR_RES 1
diff --git a/xbmc/windowing/egl/EGLWrapper.cpp b/xbmc/windowing/egl/EGLWrapper.cpp
new file mode 100644 (file)
index 0000000..c8bb3ca
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ *      Copyright (C) 2005-2012 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "system.h"
+
+#ifdef HAS_EGL
+
+#include "utils/log.h"
+#include "EGLNativeTypeAndroid.h"
+#include "EGLNativeTypeAmlogic.h"
+#include "EGLNativeTypeRaspberryPI.h"
+#include "EGLWrapper.h"
+
+#define CheckError() m_result = eglGetError(); if(m_result != EGL_SUCCESS) CLog::Log(LOGERROR, "EGL error in %s: %x",__FUNCTION__, m_result);
+
+CEGLWrapper::CEGLWrapper()
+{
+  m_nativeTypes = NULL;
+  m_result = EGL_SUCCESS;
+}
+
+CEGLWrapper::~CEGLWrapper()
+{
+  Destroy();
+}
+
+bool CEGLWrapper::Initialize(const std::string &implementation)
+{
+  bool ret = false;
+  CEGLNativeType *nativeGuess = NULL;
+
+  nativeGuess = new CEGLNativeTypeAndroid;
+  if (nativeGuess->CheckCompatibility())
+  {
+    if(implementation == nativeGuess->GetNativeName() || implementation == "auto")
+    {
+      m_nativeTypes = nativeGuess;
+      ret = true;
+    }
+  }
+
+  if (!ret)
+  {
+    delete nativeGuess;
+    nativeGuess = new CEGLNativeTypeAmlogic;
+    if (nativeGuess->CheckCompatibility())
+    {
+      if(implementation == nativeGuess->GetNativeName() || implementation == "auto")
+      {
+        m_nativeTypes = nativeGuess;
+        ret = true;
+      }
+    }
+  }
+
+  if (!ret)
+  {
+    delete nativeGuess;
+    nativeGuess = new CEGLNativeTypeRaspberryPI;
+    if (nativeGuess->CheckCompatibility())
+    {
+      if(implementation == nativeGuess->GetNativeName() || implementation == "auto")
+      {
+        m_nativeTypes = nativeGuess;
+        ret = true;
+      }
+    }
+  }
+
+  if (ret && m_nativeTypes)
+    m_nativeTypes->Initialize();
+
+  return ret;
+}
+
+bool CEGLWrapper::Destroy()
+{
+  if (!m_nativeTypes)
+    return false;
+
+  m_nativeTypes->Destroy();
+
+  delete m_nativeTypes;
+  m_nativeTypes = NULL;
+  return true;
+}
+
+std::string CEGLWrapper::GetNativeName()
+{
+  if (m_nativeTypes)
+    return m_nativeTypes->GetNativeName();
+  return "";
+}
+
+bool CEGLWrapper::CreateNativeDisplay()
+{
+  if(!m_nativeTypes)
+    return false;
+
+  return m_nativeTypes->CreateNativeDisplay();
+}
+
+bool CEGLWrapper::CreateNativeWindow()
+{
+  if(!m_nativeTypes)
+    return false;
+
+  return m_nativeTypes->CreateNativeWindow();
+}
+
+void CEGLWrapper::DestroyNativeDisplay()
+{
+  if(m_nativeTypes)
+    m_nativeTypes->DestroyNativeDisplay();
+}
+
+void CEGLWrapper::DestroyNativeWindow()
+{
+  if(m_nativeTypes)
+    m_nativeTypes->DestroyNativeWindow();
+}
+
+bool CEGLWrapper::SetNativeResolution(RESOLUTION_INFO& res)
+{
+  if (!m_nativeTypes)
+    return false;
+  return m_nativeTypes->SetNativeResolution(res);
+}
+
+bool CEGLWrapper::ProbeResolutions(std::vector<RESOLUTION_INFO> &resolutions)
+{
+  if (!m_nativeTypes)
+    return false;
+  return m_nativeTypes->ProbeResolutions(resolutions);
+}
+
+bool CEGLWrapper::GetPreferredResolution(RESOLUTION_INFO *res)
+{
+  if(!m_nativeTypes || !res)
+    return false;
+
+  return m_nativeTypes->GetPreferredResolution(res);
+}
+
+bool CEGLWrapper::GetNativeResolution(RESOLUTION_INFO *res)
+{
+  if(!m_nativeTypes || !res)
+    return false;
+
+  return m_nativeTypes->GetNativeResolution(res);
+}
+
+bool CEGLWrapper::ShowWindow(bool show)
+{
+  if (!m_nativeTypes)
+    return false;
+  
+  return m_nativeTypes->ShowWindow(show);
+}
+
+bool CEGLWrapper::GetQuirks(int *quirks)
+{
+  if (!m_nativeTypes || !quirks)
+    return false;
+  *quirks = m_nativeTypes->GetQuirks();
+  return true;
+}
+
+bool CEGLWrapper::InitDisplay(EGLDisplay *display)
+{
+  if (!display || !m_nativeTypes)
+    return false;
+
+  //nativeDisplay can be (and usually is) NULL. Don't use if(nativeDisplay) as a test!
+  EGLint status;
+  EGLNativeDisplayType *nativeDisplay = NULL;
+  if (!m_nativeTypes->GetNativeDisplay(&nativeDisplay))
+    return false;
+
+  *display = eglGetDisplay(*nativeDisplay);
+  CheckError();
+  if (*display == EGL_NO_DISPLAY) 
+  {
+    CLog::Log(LOGERROR, "EGL failed to obtain display");
+    return false;
+  }
+
+  status = eglInitialize(*display, 0, 0);
+  CheckError();
+  return status;
+}
+
+bool CEGLWrapper::ChooseConfig(EGLDisplay display, EGLint *configAttrs, EGLConfig *config)
+{
+  EGLBoolean eglStatus = true;
+  EGLint     configCount = 0;
+  EGLConfig* configList = NULL;
+
+  // Find out how many configurations suit our needs  
+  eglStatus = eglChooseConfig(display, configAttrs, NULL, 0, &configCount);
+  CheckError();
+
+  if (!eglStatus || !configCount)
+  {
+    CLog::Log(LOGERROR, "EGL failed to return any matching configurations: %i", configCount);
+    return false;
+  }
+
+  // Allocate room for the list of matching configurations
+  configList = (EGLConfig*)malloc(configCount * sizeof(EGLConfig));
+  if (!configList)
+  {
+    CLog::Log(LOGERROR, "EGL failure obtaining configuration list");
+    return false;
+  }
+
+  // Obtain the configuration list from EGL
+  eglStatus = eglChooseConfig(display, configAttrs, configList, configCount, &configCount);
+  CheckError();
+  if (!eglStatus || !configCount)
+  {
+    CLog::Log(LOGERROR, "EGL failed to populate configuration list: %d", eglStatus);
+    return false;
+  }
+
+  // Select an EGL configuration that matches the native window
+  *config = configList[0];
+
+  free(configList);
+  return m_result == EGL_SUCCESS;
+}
+
+bool CEGLWrapper::CreateContext(EGLDisplay display, EGLConfig config, EGLint *contextAttrs, EGLContext *context)
+{
+  if (!context)
+    return false;
+
+  *context = eglCreateContext(display, config, NULL, contextAttrs);
+  CheckError();
+  return *context != EGL_NO_CONTEXT;
+}
+
+bool CEGLWrapper::CreateSurface(EGLDisplay display, EGLConfig config, EGLSurface *surface)
+{
+  if (!surface || !m_nativeTypes)
+    return false;
+
+  EGLNativeWindowType *nativeWindow=NULL;
+  if (!m_nativeTypes->GetNativeWindow(&nativeWindow))
+    return false;
+
+  *surface = eglCreateWindowSurface(display, config, *nativeWindow, NULL);
+  CheckError();
+  return *surface != EGL_NO_SURFACE;
+}
+
+bool CEGLWrapper::GetSurfaceSize(EGLDisplay display, EGLSurface surface, EGLint *width, EGLint *height)
+{
+  if (!width || !height)
+    return false;
+
+  if (!eglQuerySurface(display, surface, EGL_WIDTH, width)     ||
+        !eglQuerySurface(display, surface, EGL_HEIGHT, height) ||
+        *width <= 0 || *height <= 0)
+  return false;
+
+  return true;
+}
+
+bool CEGLWrapper::BindContext(EGLDisplay display, EGLSurface surface, EGLContext context)
+{
+  EGLBoolean status;
+  status = eglMakeCurrent(display, surface, surface, context);
+  CheckError();
+  return status;
+}
+
+bool CEGLWrapper::BindAPI(EGLint type)
+{
+  EGLBoolean status;
+  status = eglBindAPI(type);
+  CheckError();
+  return status && m_result == EGL_SUCCESS;
+}
+
+bool CEGLWrapper::ReleaseContext(EGLDisplay display)
+{
+  EGLBoolean status;
+  if (display == EGL_NO_DISPLAY)
+    return false;
+  status = eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+  CheckError();
+  return status;
+}
+
+bool CEGLWrapper::DestroyContext(EGLDisplay display, EGLContext context)
+{
+  EGLBoolean status;
+  if (display == EGL_NO_DISPLAY)
+    return false;
+  status = eglDestroyContext(display, context);
+  CheckError();
+  return status;
+}
+
+bool CEGLWrapper::DestroySurface(EGLSurface surface, EGLDisplay display)
+{
+  EGLBoolean status;
+
+  status = eglDestroySurface(display, surface);
+  CheckError();
+  return status;
+}
+
+bool CEGLWrapper::DestroyDisplay(EGLDisplay display)
+{
+  EGLBoolean eglStatus;
+
+  eglStatus = eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+  CheckError();
+  if (!eglStatus)
+    return false;
+
+  eglStatus = eglTerminate(display);
+  CheckError();
+  if (!eglStatus)
+    return false;
+
+  return true;
+}
+
+std::string CEGLWrapper::GetExtensions(EGLDisplay display)
+{
+  std::string extensions = eglQueryString(display, EGL_EXTENSIONS);
+  CheckError();
+  return " " + extensions + " ";
+}
+
+bool CEGLWrapper::SetVSync(EGLDisplay display, bool enable)
+{
+  EGLBoolean status;
+  // depending how buffers are setup, eglSwapInterval
+  // might fail so let caller decide if this is an error.
+  status = eglSwapInterval(display, enable ? 1 : 0);
+  CheckError();
+  return status;
+}
+
+void CEGLWrapper::SwapBuffers(EGLDisplay display, EGLSurface surface)
+{
+  if ((display == EGL_NO_DISPLAY) || (surface == EGL_NO_SURFACE))
+    return;
+  eglSwapBuffers(display, surface);
+}
+
+bool CEGLWrapper::GetConfigAttrib(EGLDisplay display, EGLConfig config, EGLint attribute, EGLint *value)
+{
+  if (display == EGL_NO_DISPLAY || !config || !attribute)
+    return eglGetConfigAttrib(display, config, attribute, value);
+  return false;
+}
+#endif
+
diff --git a/xbmc/windowing/egl/EGLWrapper.h b/xbmc/windowing/egl/EGLWrapper.h
new file mode 100644 (file)
index 0000000..c0335f6
--- /dev/null
@@ -0,0 +1,69 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2012 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "guilib/Resolution.h"
+class CEGLNativeType;
+class CEGLWrapper
+{
+public:
+  CEGLWrapper();
+  ~CEGLWrapper();
+
+  bool Initialize(const std::string &implementation = "auto");
+  bool Destroy();
+  std::string GetNativeName();
+
+  bool CreateNativeDisplay();
+  bool CreateNativeWindow();
+  void DestroyNativeDisplay();
+  void DestroyNativeWindow();
+
+  bool SetNativeResolution(RESOLUTION_INFO& res);
+  bool ProbeResolutions(std::vector<RESOLUTION_INFO> &resolutions);
+  bool ShowWindow(bool show);
+  bool GetQuirks(int *quirks);
+  bool GetPreferredResolution(RESOLUTION_INFO *res);
+  bool GetNativeResolution(RESOLUTION_INFO *res);
+
+  bool InitDisplay(EGLDisplay *display);
+  bool ChooseConfig(EGLDisplay display, EGLint *configAttrs, EGLConfig *config);
+  bool CreateContext(EGLDisplay display, EGLConfig config, EGLint *contextAttrs, EGLContext *context);
+  bool CreateSurface(EGLDisplay display, EGLConfig config, EGLSurface *surface);
+  bool GetSurfaceSize(EGLDisplay display, EGLSurface surface, EGLint *width, EGLint *height);
+  bool BindContext(EGLDisplay display, EGLSurface surface, EGLContext context);
+  bool BindAPI(EGLint type);
+  bool ReleaseContext(EGLDisplay display);
+  bool DestroyContext(EGLDisplay display, EGLContext context);
+  bool DestroySurface(EGLSurface surface, EGLDisplay display);
+  bool DestroyDisplay(EGLDisplay display);
+
+  std::string GetExtensions(EGLDisplay display);
+  void SwapBuffers(EGLDisplay display, EGLSurface surface);
+  bool SetVSync(EGLDisplay display, bool enable);
+  bool IsExtSupported(const char* extension);
+  bool GetConfigAttrib(EGLDisplay display, EGLConfig config, EGLint attribute, EGLint *value);
+
+private:
+    CEGLNativeType          *m_nativeTypes;
+    EGLint                  m_result;
+};
+
index a9fe48b..241220a 100644 (file)
@@ -1,10 +1,11 @@
 INCLUDES=-I.
 
-SRCS = WinSystemGLES.cpp
-SRCS+= WinEGLPlatformGeneric.cpp
-SRCS+= WinEGLPlatformAndroid.cpp
-SRCS+= WinEGLPlatformRaspberryPI.cpp
-     
+SRCS = WinSystemEGL.cpp
+SRCS+= EGLNativeTypeAmlogic.cpp
+SRCS+= EGLNativeTypeAndroid.cpp
+SRCS+= EGLNativeTypeRaspberryPI.cpp
+SRCS+= EGLWrapper.cpp
+
 LIB = windowing_egl.a
 
 include ../../../Makefile.include
diff --git a/xbmc/windowing/egl/WinEGLPlatform.h b/xbmc/windowing/egl/WinEGLPlatform.h
deleted file mode 100644 (file)
index 4b25355..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-#pragma once
-/*
- *      Copyright (C) 2012 Team XBMC
- *      http://www.xbmc.org
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with XBMC; see the file COPYING.  If not, see
- *  <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifdef HAS_EGL
-
-#include "system.h"
-
-#if   defined(TARGET_RASPBERRY_PI)
-  #include "xbmc/windowing/egl/WinEGLPlatformRaspberryPI.h"
-  class CWinEGLPlatformRaspberryPI;
-    #define CWinEGLPlatform CWinEGLPlatformRaspberryPI
-#elif   defined(TARGET_ANDROID)
-  #include "xbmc/windowing/egl/WinEGLPlatformAndroid.h"
-  class CWinEGLPlatformAndroid;
-  #define CWinEGLPlatform CWinEGLPlatformAndroid
-
-#else
-  #include "xbmc/windowing/egl/WinEGLPlatformGeneric.h"
-  class CWinEGLPlatformGeneric;
-  #define CWinEGLPlatform CWinEGLPlatformGeneric
-
-#endif
-
-#endif
diff --git a/xbmc/windowing/egl/WinEGLPlatformAndroid.cpp b/xbmc/windowing/egl/WinEGLPlatformAndroid.cpp
deleted file mode 100644 (file)
index d4a451a..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- *      Copyright (C) 2012 Team XBMC
- *      http://www.xbmc.org
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with XBMC; see the file COPYING.  If not, see
- *  <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "system.h"
-
-#if defined(TARGET_ANDROID)
-
-#include <unistd.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <linux/fb.h>
-#include <sys/ioctl.h>
-
-#include "WinEGLPlatformAndroid.h"
-#include "android/activity/XBMCApp.h"
-////////////////////////////////////////////////////////////////////////////////////////////
-EGLNativeWindowType CWinEGLPlatformAndroid::InitWindowSystem(EGLNativeDisplayType nativeDisplay, int width, int height, int bpp)
-{
-  if (CXBMCApp::GetNativeWindow() == NULL)
-    return 0;
-
-  CWinEGLPlatformGeneric::InitWindowSystem(nativeDisplay, width, height, bpp);
-  
-  return getNativeWindow();
-}
-
-void CWinEGLPlatformAndroid::DestroyWindowSystem(EGLNativeWindowType native_window)
-{
-  CWinEGLPlatformGeneric::DestroyWindowSystem(native_window);
-}
-
-bool CWinEGLPlatformAndroid::ClampToGUIDisplayLimits(int &width, int &height)
-{
-  return false;
-}
-
-bool CWinEGLPlatformAndroid::CreateWindow()
-{
-  EGLint format;
-  // EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
-  // guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
-  // As soon as we picked a EGLConfig, we can safely reconfigure the
-  // ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID.
-  eglGetConfigAttrib(m_display, m_config, EGL_NATIVE_VISUAL_ID, &format);
-
-  CXBMCApp::SetBuffersGeometry(0, 0, format);
-  
-  CWinEGLPlatformGeneric::CreateWindow();
-  return true;
-}
-
-EGLNativeWindowType CWinEGLPlatformAndroid::getNativeWindow()
-{
-  return (EGLNativeWindowType)CXBMCApp::GetNativeWindow();
-}
-
-#endif
diff --git a/xbmc/windowing/egl/WinEGLPlatformAndroid.h b/xbmc/windowing/egl/WinEGLPlatformAndroid.h
deleted file mode 100644 (file)
index d836fe8..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-#pragma once
-/*
- *      Copyright (C) 2012 Team XBMC
- *      http://www.xbmc.org
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with XBMC; see the file COPYING.  If not, see
- *  <http://www.gnu.org/licenses/>.
- *
- */
-
-#if defined(TARGET_ANDROID)
-
-#include "WinEGLPlatformGeneric.h"
-
-class CWinEGLPlatformAndroid : public CWinEGLPlatformGeneric
-{
-public:
-  virtual EGLNativeWindowType InitWindowSystem(EGLNativeDisplayType nativeDisplay, int width, int height, int bpp);
-  virtual void DestroyWindowSystem(EGLNativeWindowType native_window);
-  virtual bool ClampToGUIDisplayLimits(int &width, int &height);
-  
-  virtual bool CreateWindow();
-  
-protected:
-  virtual EGLNativeWindowType getNativeWindow();
-};
-
-#endif
diff --git a/xbmc/windowing/egl/WinEGLPlatformGeneric.cpp b/xbmc/windowing/egl/WinEGLPlatformGeneric.cpp
deleted file mode 100644 (file)
index b6dec7e..0000000
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
- *      Copyright (C) 2005-2012 Team XBMC
- *      http://www.xbmc.org
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with XBMC; see the file COPYING.  If not, see
- *  <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "system.h"
-
-#include "system_gl.h"
-
-#ifdef HAS_EGL
-
-#include "WinEGLPlatformGeneric.h"
-#include "utils/log.h"
-
-#include <string>
-
-CWinEGLPlatformGeneric::CWinEGLPlatformGeneric()
-{
-  m_surface = EGL_NO_SURFACE;
-  m_context = EGL_NO_CONTEXT;
-  m_display = EGL_NO_DISPLAY;
-  
-  // most egl platforms cannot render 1080p
-  // default to 720p
-  m_width  = 1280;
-  m_height = 720;
-
-  m_desktopRes.iScreen = 0;
-  m_desktopRes.iWidth  = 1280;
-  m_desktopRes.iHeight = 720;
-  m_desktopRes.iScreenWidth  = 1280;
-  m_desktopRes.iScreenHeight = 720;
-  m_desktopRes.fRefreshRate = 60.0f;
-  m_desktopRes.bFullScreen = true;
-  m_desktopRes.iSubtitles = (int)(0.965 * 720);
-  m_desktopRes.dwFlags = D3DPRESENTFLAG_PROGRESSIVE | D3DPRESENTFLAG_WIDESCREEN;
-  m_desktopRes.fPixelRatio = 1.0f;
-  m_desktopRes.strMode = "720p 16:9";
-}
-
-CWinEGLPlatformGeneric::~CWinEGLPlatformGeneric()
-{
-  UninitializeDisplay();
-}
-
-EGLNativeWindowType CWinEGLPlatformGeneric::InitWindowSystem(EGLNativeDisplayType nativeDisplay, int width, int height, int bpp)
-{
-  m_nativeDisplay = nativeDisplay;
-  m_width = width;
-  m_height = height;
-
-  return getNativeWindow();
-}
-
-void CWinEGLPlatformGeneric::DestroyWindowSystem(EGLNativeWindowType native_window)
-{
-  UninitializeDisplay();
-}
-
-bool CWinEGLPlatformGeneric::SetDisplayResolution(RESOLUTION_INFO& res)
-{
-  return false;
-}
-
-bool CWinEGLPlatformGeneric::ClampToGUIDisplayLimits(int &width, int &height)
-{
-  width  = m_width;
-  height = m_height;
-  return true;
-}
-
-bool CWinEGLPlatformGeneric::ProbeDisplayResolutions(std::vector<RESOLUTION_INFO> &resolutions)
-{
-  int gui_width  = m_width;
-  int gui_height = m_height;
-  float gui_refresh = 60.0f;
-  RESOLUTION_INFO res;
-
-  ClampToGUIDisplayLimits(gui_width, gui_height);
-
-  res.iScreen       = 0;
-  res.bFullScreen   = true;
-  res.iSubtitles    = (int)(0.965 * gui_height);
-  res.dwFlags       = D3DPRESENTFLAG_PROGRESSIVE;
-  res.fRefreshRate  = gui_refresh;
-  res.fPixelRatio   = 1.0f;
-  res.iWidth        = gui_width;
-  res.iHeight       = gui_height;
-  res.iScreenWidth  = gui_width;
-  res.iScreenHeight = gui_height;
-  res.dwFlags       = D3DPRESENTFLAG_PROGRESSIVE | D3DPRESENTFLAG_WIDESCREEN;
-  res.strMode.Format("%dx%d @ %.2f - Full Screen", gui_width, gui_height, gui_refresh);
-
-  resolutions.push_back(res);
-  return true;
-}
-
-bool CWinEGLPlatformGeneric::InitializeDisplay()
-{
-  if (m_display != EGL_NO_DISPLAY && m_config != NULL)
-    return true;
-
-  EGLBoolean eglStatus;
-  EGLint     configCount;
-  EGLConfig* configList = NULL;
-
-  m_display = eglGetDisplay(m_nativeDisplay);
-  if (m_display == EGL_NO_DISPLAY) 
-  {
-    CLog::Log(LOGERROR, "EGL failed to obtain display");
-    return false;
-  }
-  
-  if (!eglInitialize(m_display, 0, 0)) 
-  {
-    CLog::Log(LOGERROR, "EGL failed to initialize");
-    return false;
-  } 
-  
-  EGLint configAttrs[] = {
-        EGL_RED_SIZE,        8,
-        EGL_GREEN_SIZE,      8,
-        EGL_BLUE_SIZE,       8,
-        EGL_ALPHA_SIZE,      8,
-        EGL_DEPTH_SIZE,     16,
-        EGL_STENCIL_SIZE,    0,
-        EGL_SAMPLE_BUFFERS,  0,
-        EGL_SAMPLES,         0,
-        EGL_SURFACE_TYPE,    EGL_WINDOW_BIT,
-        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-        EGL_NONE
-  };
-
-  // Find out how many configurations suit our needs  
-  eglStatus = eglChooseConfig(m_display, configAttrs, NULL, 0, &configCount);
-  if (!eglStatus || !configCount) 
-  {
-    CLog::Log(LOGERROR, "EGL failed to return any matching configurations: %d", eglStatus);
-    return false;
-  }
-
-  // Allocate room for the list of matching configurations
-  configList = (EGLConfig*)malloc(configCount * sizeof(EGLConfig));
-  if (!configList) 
-  {
-    CLog::Log(LOGERROR, "kdMalloc failure obtaining configuration list");
-    return false;
-  }
-
-  // Obtain the configuration list from EGL
-  eglStatus = eglChooseConfig(m_display, configAttrs,
-                                configList, configCount, &configCount);
-  if (!eglStatus || !configCount) 
-  {
-    CLog::Log(LOGERROR, "EGL failed to populate configuration list: %d", eglStatus);
-    return false;
-  }
-
-  // Select an EGL configuration that matches the native window
-  m_config = configList[0];
-
-  if (m_surface != EGL_NO_SURFACE)
-    ReleaseSurface();
-  free(configList);
-  return true;
-}
-
-bool CWinEGLPlatformGeneric::UninitializeDisplay()
-{
-  EGLBoolean eglStatus;
-  
-  DestroyWindow();
-
-  if (m_display != EGL_NO_DISPLAY)
-  {
-    eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-
-    eglStatus = eglTerminate(m_display);
-    if (!eglStatus)
-      CLog::Log(LOGERROR, "Error terminating EGL");
-    m_display = EGL_NO_DISPLAY;
-  }
-
-  return true;
-}
-
-bool CWinEGLPlatformGeneric::CreateWindow()
-{
-  if (m_display == EGL_NO_DISPLAY || m_config == NULL)
-  {
-    if (!InitializeDisplay())
-      return false;
-  }
-  
-  if (m_surface != EGL_NO_SURFACE)
-    return true;
-  
-  m_nativeWindow = getNativeWindow();
-
-  m_surface = eglCreateWindowSurface(m_display, m_config, m_nativeWindow, NULL);
-  if (!m_surface)
-  {
-    CLog::Log(LOGERROR, "EGL couldn't create window surface");
-    return false;
-  }
-
-  // Let's get the current width and height
-  EGLint width, height;
-  if (!eglQuerySurface(m_display, m_surface, EGL_WIDTH, &width) || !eglQuerySurface(m_display, m_surface, EGL_HEIGHT, &height) ||
-      width <= 0 || height <= 0)
-  {
-    CLog::Log(LOGERROR, "EGL couldn't provide the surface's width and/or height");
-    return false;
-  }
-
-  m_width = width;
-  m_height = height;
-  
-  return true;
-}
-
-bool CWinEGLPlatformGeneric::DestroyWindow()
-{
-  EGLBoolean eglStatus;
-  
-  ReleaseSurface();
-
-  if (m_surface == EGL_NO_SURFACE)
-    return true;
-
-  eglStatus = eglDestroySurface(m_display, m_surface);
-  if (!eglStatus)
-  {
-    CLog::Log(LOGERROR, "Error destroying EGL surface");
-    return false;
-  }
-
-  m_surface = EGL_NO_SURFACE;
-  m_width = 0;
-  m_height = 0;
-
-  return true;
-}
-
-bool CWinEGLPlatformGeneric::BindSurface()
-{
-  EGLBoolean eglStatus;
-  
-  if (m_display == EGL_NO_DISPLAY || m_surface == EGL_NO_SURFACE || m_config == NULL)
-  {
-    CLog::Log(LOGINFO, "EGL not configured correctly. Let's try to do that now...");
-    if (!CreateWindow())
-    {
-      CLog::Log(LOGERROR, "EGL not configured correctly to create a surface");
-      return false;
-    }
-  }
-
-  eglStatus = eglBindAPI(EGL_OPENGL_ES_API);
-  if (!eglStatus) 
-  {
-    CLog::Log(LOGERROR, "EGL failed to bind API: %d", eglStatus);
-    return false;
-  }
-
-  EGLint contextAttrs[] = 
-  {
-    EGL_CONTEXT_CLIENT_VERSION, 2,
-    EGL_NONE
-  };
-
-  // Create an EGL context
-  if (m_context == EGL_NO_CONTEXT)
-  {
-    m_context = eglCreateContext(m_display, m_config, NULL, contextAttrs);
-    if (!m_context)
-    {
-      CLog::Log(LOGERROR, "EGL couldn't create context");
-      return false;
-    }
-  }
-
-  // Make the context and surface current to this thread for rendering
-  eglStatus = eglMakeCurrent(m_display, m_surface, m_surface, m_context);
-  if (!eglStatus) 
-  {
-    CLog::Log(LOGERROR, "EGL couldn't make context/surface current: %d", eglStatus);
-    return false;
-  }
-
-  eglSwapInterval(m_display, 0);
-
-  // For EGL backend, it needs to clear all the back buffers of the window
-  // surface before drawing anything, otherwise the image will be blinking
-  // heavily.  The default eglWindowSurface has 3 gdl surfaces as the back
-  // buffer, that's why glClear should be called 3 times.
-  glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
-  glClear (GL_COLOR_BUFFER_BIT);
-  eglSwapBuffers(m_display, m_surface);
-
-  glClear (GL_COLOR_BUFFER_BIT);
-  eglSwapBuffers(m_display, m_surface);
-
-  glClear (GL_COLOR_BUFFER_BIT);
-  eglSwapBuffers(m_display, m_surface);
-
-  m_eglext  = " ";
-  m_eglext += eglQueryString(m_display, EGL_EXTENSIONS);
-  m_eglext += " ";
-  CLog::Log(LOGDEBUG, "EGL extensions:%s", m_eglext.c_str());
-
-  // setup for vsync disabled
-  eglSwapInterval(m_display, 0);
-
-  CLog::Log(LOGINFO, "EGL window and context creation complete");
-
-  return true;
-}
-
-bool CWinEGLPlatformGeneric::ReleaseSurface()
-{
-  EGLBoolean eglStatus;
-  
-  if (m_context != EGL_NO_CONTEXT)
-  {
-    eglStatus = eglDestroyContext(m_display, m_context);
-    if (!eglStatus)
-      CLog::Log(LOGERROR, "Error destroying EGL context");
-    m_context = EGL_NO_CONTEXT;
-  }
-
-  if (m_display != EGL_NO_DISPLAY)
-    eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-
-  return true;
-}
-
-bool CWinEGLPlatformGeneric::ShowWindow(bool show)
-{
-  return true;
-}
-
-void CWinEGLPlatformGeneric::SwapBuffers()
-{
-  eglSwapBuffers(m_display, m_surface);
-}
-
-bool CWinEGLPlatformGeneric::SetVSync(bool enable)
-{
-  // depending how buffers are setup, eglSwapInterval
-  // might fail so let caller decide if this is an error.
-  return eglSwapInterval(m_display, enable ? 1 : 0);
-}
-
-bool CWinEGLPlatformGeneric::IsExtSupported(const char* extension)
-{
-  CStdString name;
-
-  name  = " ";
-  name += extension;
-  name += " ";
-
-  return m_eglext.find(name) != std::string::npos;
-}
-
-EGLNativeWindowType CWinEGLPlatformGeneric::getNativeWindow()
-{
-  // most egl platforms can handle EGLNativeWindowType == 0
-  return 0;
-}
-
-EGLDisplay CWinEGLPlatformGeneric::GetEGLDisplay()
-{
-  return m_display;
-}
-
-EGLSurface CWinEGLPlatformGeneric::GetEGLSurface()
-{
-  return m_surface;
-}
-
-EGLContext CWinEGLPlatformGeneric::GetEGLContext()
-{
-  return m_context;
-}
-
-#endif
diff --git a/xbmc/windowing/egl/WinEGLPlatformGeneric.h b/xbmc/windowing/egl/WinEGLPlatformGeneric.h
deleted file mode 100644 (file)
index 26b9d03..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-#pragma once
-/*
- *      Copyright (C) 2005-2012 Team XBMC
- *      http://www.xbmc.org
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with XBMC; see the file COPYING.  If not, see
- *  <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "utils/StringUtils.h"
-
-#include <EGL/egl.h>
-#ifndef TARGET_WINDOWS
-#include <EGL/eglext.h>
-#endif
-
-#include "guilib/gui3d.h"
-#include "guilib/Resolution.h"
-
-class CWinEGLPlatformGeneric
-{
-public:
-  CWinEGLPlatformGeneric();
-  virtual ~CWinEGLPlatformGeneric();
-
-  virtual EGLNativeWindowType InitWindowSystem(EGLNativeDisplayType nativeDisplay, int width, int height, int bpp);
-  virtual void DestroyWindowSystem(EGLNativeWindowType native_window);
-  virtual bool SetDisplayResolution(RESOLUTION_INFO& res);
-  virtual bool ClampToGUIDisplayLimits(int &width, int &height);
-  virtual bool ProbeDisplayResolutions(std::vector<RESOLUTION_INFO> &resolutions);
-  
-  virtual bool InitializeDisplay();
-  virtual bool UninitializeDisplay();
-  virtual bool CreateWindow();
-  virtual bool DestroyWindow();
-  virtual bool BindSurface();
-  virtual bool ReleaseSurface();
-  
-  virtual bool ShowWindow(bool show);
-  virtual void SwapBuffers();
-  virtual bool SetVSync(bool enable);
-  virtual bool IsExtSupported(const char* extension);
-
-  virtual EGLDisplay GetEGLDisplay();
-  virtual EGLSurface GetEGLSurface();
-  virtual EGLContext GetEGLContext();
-
-  virtual bool                  FixedDesktop() { return true; }
-  virtual RESOLUTION_INFO       GetDesktopRes() { return m_desktopRes; }
-  virtual bool                  Support3D() { return false; }
-
-protected:
-  virtual EGLNativeWindowType getNativeWindow();
-
-  EGLNativeWindowType   m_nativeWindow;
-  EGLNativeDisplayType  m_nativeDisplay;
-  EGLDisplay            m_display;
-  EGLSurface            m_surface;
-  EGLConfig             m_config;
-  EGLContext            m_context;
-  CStdString            m_eglext;
-  int                   m_width;
-  int                   m_height;
-  RESOLUTION_INFO       m_desktopRes;
-};
diff --git a/xbmc/windowing/egl/WinEGLPlatformRaspberryPI.cpp b/xbmc/windowing/egl/WinEGLPlatformRaspberryPI.cpp
deleted file mode 100644 (file)
index 8435c33..0000000
+++ /dev/null
@@ -1,743 +0,0 @@
-/*
- *      Copyright (C) 2005-2012 Team XBMC
- *      http://www.xbmc.org
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with XBMC; see the file COPYING.  If not, see
- *  <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "system.h"
-
-#if defined(TARGET_RASPBERRY_PI)
-
-#include "system_gl.h"
-
-#ifdef HAS_EGL
-
-#include "WinEGLPlatformRaspberryPI.h"
-#include "utils/log.h"
-#include "guilib/gui3d.h"
-#include "xbmc/cores/VideoRenderers/RenderManager.h"
-#include "settings/Settings.h"
-
-#include <string>
-
-#ifndef __VIDEOCORE4__
-#define __VIDEOCORE4__
-#endif
-
-#define __VCCOREVER__ 0x04000000
-
-#define IS_WIDESCREEN(m) ( m == 3 || m == 7 || m == 9 || \
-    m == 11 || m == 13 || m == 15 || m == 18 || m == 22 || \
-    m == 24 || m == 26 || m == 28 || m == 30 || m == 36 || \
-    m == 38 || m == 43 || m == 45 || m == 49 || m == 51 || \
-    m == 53 || m == 55 || m == 57 || m == 59)
-
-#define MAKEFLAGS(group, mode, interlace, mode3d) \
-  ( ( (mode)<<24 ) | ( (group)<<16 ) | \
-   ( (interlace) != 0 ? D3DPRESENTFLAG_INTERLACED : D3DPRESENTFLAG_PROGRESSIVE) | \
-   ( ((group) == HDMI_RES_GROUP_CEA && IS_WIDESCREEN(mode) ) ? D3DPRESENTFLAG_WIDESCREEN : 0) | \
-   ( (mode3d) != 0 ? D3DPRESENTFLAG_MODE3DSBS : 0 ))
-
-#define GETFLAGS_INTERLACE(f)   ( ( (f) & D3DPRESENTFLAG_INTERLACED ) != 0)
-#define GETFLAGS_WIDESCREEN(f)  ( ( (f) & D3DPRESENTFLAG_WIDESCREEN ) != 0)
-#define GETFLAGS_GROUP(f)       ( (HDMI_RES_GROUP_T)( ((f) >> 16) & 0xff ))
-#define GETFLAGS_MODE(f)        ( ( (f) >>24 ) & 0xff )
-#define GETFLAGS_MODE3D(f)      ( ( (f) & D3DPRESENTFLAG_MODE3DSBS ) !=0 )
-
-#define TV_MAX_SUPPORTED_MODES 60
-
-CWinEGLPlatformRaspberryPI::CWinEGLPlatformRaspberryPI()
-{
-  m_surface                 = EGL_NO_SURFACE;
-  m_context                 = EGL_NO_CONTEXT;
-  m_display                 = EGL_NO_DISPLAY;
-
-  m_dispman_element         = DISPMANX_NO_HANDLE;
-  m_dispman_element2        = DISPMANX_NO_HANDLE;
-  m_dispman_display         = DISPMANX_NO_HANDLE;
-
-  m_fixedMode               = false;
-
-  m_nativeWindow = (EGL_DISPMANX_WINDOW_T *)malloc(sizeof(EGL_DISPMANX_WINDOW_T));
-  memset(m_nativeWindow, 0x0, sizeof(EGL_DISPMANX_WINDOW_T));
-
-  m_initDesktopRes          = true;
-}
-
-CWinEGLPlatformRaspberryPI::~CWinEGLPlatformRaspberryPI()
-{
-  UninitializeDisplay();
-
-  free(m_nativeWindow);
-
-  if(m_DllBcmHost.IsLoaded())
-    m_DllBcmHost.Unload();
-}
-
-bool CWinEGLPlatformRaspberryPI::SetDisplayResolution(RESOLUTION_INFO& res)
-{
-  bool bFound = false;
-
-  DestroyDispmaxWindow();
-
-  RESOLUTION_INFO resSearch;
-
-  int best_score = 0;
-
-  for (size_t i = 0; i < m_res.size(); i++)
-  {
-    if(m_res[i].iScreenWidth == res.iScreenWidth && m_res[i].iScreenHeight == res.iScreenHeight && m_res[i].fRefreshRate == res.fRefreshRate)
-    {
-      int score = 0;
-
-      /* prefere progressive over interlaced */
-      if(!GETFLAGS_INTERLACE(m_res[i].dwFlags))
-        score = 1;
-
-      if(score >= best_score)
-      {
-        resSearch = m_res[i];
-        bFound = true;
-      }
-    }
-  }
-
-  if(bFound && !m_fixedMode)
-  {
-    sem_init(&m_tv_synced, 0, 0);
-    m_DllBcmHost.vc_tv_register_callback(CallbackTvServiceCallback, this);
-  
-    int success = m_DllBcmHost.vc_tv_hdmi_power_on_explicit(HDMI_MODE_HDMI, GETFLAGS_GROUP(resSearch.dwFlags), GETFLAGS_MODE(resSearch.dwFlags));
-
-    if (success == 0) 
-    {
-      CLog::Log(LOGDEBUG, "EGL set HDMI mode (%d,%d,%d)=%d\n", 
-                          GETFLAGS_MODE3D(resSearch.dwFlags) ? HDMI_MODE_3D:HDMI_MODE_HDMI, GETFLAGS_GROUP(resSearch.dwFlags), 
-                          GETFLAGS_MODE(resSearch.dwFlags), success);
-      sem_wait(&m_tv_synced);
-    } 
-    else 
-    {
-      CLog::Log(LOGERROR, "EGL failed to set HDMI mode (%d,%d,%d)=%d\n", 
-                          GETFLAGS_MODE3D(resSearch.dwFlags) ? HDMI_MODE_3D:HDMI_MODE_HDMI, GETFLAGS_GROUP(resSearch.dwFlags), 
-                          GETFLAGS_MODE(resSearch.dwFlags), success);
-    }
-    m_DllBcmHost.vc_tv_unregister_callback(CallbackTvServiceCallback);
-    sem_destroy(&m_tv_synced);
-
-    m_desktopRes = resSearch; 
-  }
-
-  m_dispman_display = m_DllBcmHost.vc_dispmanx_display_open(0);
-
-  m_width   = res.iWidth;
-  m_height  = res.iHeight;
-
-  VC_RECT_T dst_rect;
-  VC_RECT_T src_rect;
-
-  dst_rect.x      = 0;
-  dst_rect.y      = 0;
-  dst_rect.width  = res.iScreenWidth;
-  dst_rect.height = res.iScreenHeight;
-
-  src_rect.x      = 0;
-  src_rect.y      = 0;
-  src_rect.width  = m_width << 16;
-  src_rect.height = m_height << 16;
-
-  VC_DISPMANX_ALPHA_T alpha;
-  memset(&alpha, 0x0, sizeof(VC_DISPMANX_ALPHA_T));
-  alpha.flags = DISPMANX_FLAGS_ALPHA_FROM_SOURCE;
-
-  DISPMANX_CLAMP_T clamp;
-  memset(&clamp, 0x0, sizeof(DISPMANX_CLAMP_T));
-
-  DISPMANX_TRANSFORM_T transform = DISPMANX_NO_ROTATE;
-  DISPMANX_UPDATE_HANDLE_T dispman_update = m_DllBcmHost.vc_dispmanx_update_start(0);
-
-  CLog::Log(LOGDEBUG, "EGL set resolution %dx%d -> %dx%d @ %.2f fps\n", 
-      m_width, m_height, dst_rect.width, dst_rect.height, bFound ? resSearch.fRefreshRate : res.fRefreshRate);
-
-  // The trick for SBS is that we stick two dispman elements together 
-  // and the PI firmware knows that we are in SBS mode and it renders the gui in SBS
-  if(bFound && (resSearch.dwFlags & D3DPRESENTFLAG_MODE3DSBS))
-  {
-    // right side
-    dst_rect.x = res.iScreenWidth;
-    dst_rect.width = res.iScreenWidth;
-
-    m_dispman_element2 = m_DllBcmHost.vc_dispmanx_element_add(dispman_update,
-      m_dispman_display,
-      1,                              // layer
-      &dst_rect,
-      (DISPMANX_RESOURCE_HANDLE_T)0,  // src
-      &src_rect,
-      DISPMANX_PROTECTION_NONE,
-      &alpha,                         // alpha
-      &clamp,                         // clamp
-      transform);                     // transform
-      assert(m_dispman_element2 != DISPMANX_NO_HANDLE);
-      assert(m_dispman_element2 != (unsigned)DISPMANX_INVALID);
-
-    // left side - fall through
-    dst_rect.x = 0;
-    dst_rect.width = res.iScreenWidth;
-  }
-
-  m_dispman_element = m_DllBcmHost.vc_dispmanx_element_add(dispman_update,
-    m_dispman_display,
-    1,                              // layer
-    &dst_rect,
-    (DISPMANX_RESOURCE_HANDLE_T)0,  // src
-    &src_rect,
-    DISPMANX_PROTECTION_NONE,
-    &alpha,                         //alphe
-    &clamp,                         //clamp
-    transform);                     // transform
-
-  assert(m_dispman_element != DISPMANX_NO_HANDLE);
-  assert(m_dispman_element != (unsigned)DISPMANX_INVALID);
-
-  memset(m_nativeWindow, 0, sizeof(EGL_DISPMANX_WINDOW_T));
-
-  m_nativeWindow->element = m_dispman_element;
-  m_nativeWindow->width   = m_width;
-  m_nativeWindow->height  = m_height;
-
-  m_DllBcmHost.vc_dispmanx_display_set_background(dispman_update, m_dispman_display, 0x00, 0x00, 0x00);
-  m_DllBcmHost.vc_dispmanx_update_submit_sync(dispman_update);
-
-  return true;
-}
-
-bool CWinEGLPlatformRaspberryPI::ClampToGUIDisplayLimits(int &width, int &height)
-{
-  const int max_width = 1280, max_height = 720;
-  float ar = (float)width/(float)height;
-  // bigger than maximum, so need to clamp
-  if (width > max_width || height > max_height) {
-    // wider than max, so clamp width first
-    if (ar > (float)max_width/(float)max_height)
-    {
-      width = max_width;
-      height = (float)max_width / ar + 0.5f;
-    // taller than max, so clamp height first
-    } else {
-      height = max_height;
-      width = (float)max_height * ar + 0.5f;
-    }
-    return true;
-  }
-  return false;
-}
-
-bool CWinEGLPlatformRaspberryPI::ProbeDisplayResolutions(std::vector<RESOLUTION_INFO> &resolutions)
-{
-  resolutions.clear();
-  m_res.clear();
-  
-  m_fixedMode               = false;
-
-  /* read initial desktop resolution before probe resolutions.
-   * probing will replace the desktop resolution when it finds the same one.
-   * we raplace it because probing will generate more detailed 
-   * resolution flags we don't get with vc_tv_get_state.
-   */
-
-  if(m_initDesktopRes)
-  {
-    TV_GET_STATE_RESP_T tv_state;
-
-    // get current display settings state
-    memset(&tv_state, 0, sizeof(TV_GET_STATE_RESP_T));
-    m_DllBcmHost.vc_tv_get_state(&tv_state);
-
-    m_desktopRes.iScreen      = 0;
-    m_desktopRes.bFullScreen  = true;
-    m_desktopRes.iSubtitles   = (int)(0.965 * tv_state.height);
-    m_desktopRes.iWidth       = tv_state.width;
-    m_desktopRes.iHeight      = tv_state.height;
-    m_desktopRes.iScreenWidth = tv_state.width;
-    m_desktopRes.iScreenHeight= tv_state.height;
-    m_desktopRes.dwFlags      = tv_state.scan_mode ? D3DPRESENTFLAG_INTERLACED : D3DPRESENTFLAG_PROGRESSIVE;
-    m_desktopRes.fRefreshRate = (float)tv_state.frame_rate;
-    m_desktopRes.strMode.Format("%dx%d", tv_state.width, tv_state.height);
-    if((float)tv_state.frame_rate > 1)
-    {
-        m_desktopRes.strMode.Format("%s @ %.2f%s - Full Screen", m_desktopRes.strMode, (float)tv_state.frame_rate, 
-            m_desktopRes.dwFlags & D3DPRESENTFLAG_INTERLACED ? "i" : "");
-    }
-    m_initDesktopRes = false;
-
-    CLog::Log(LOGDEBUG, "EGL initial desktop resolution %s\n", m_desktopRes.strMode.c_str());
-  }
-
-  GetSupportedModes(HDMI_RES_GROUP_CEA, resolutions);
-  GetSupportedModes(HDMI_RES_GROUP_DMT, resolutions);
-  GetSupportedModes(HDMI_RES_GROUP_CEA_3D, resolutions);
-
-  if(resolutions.size() == 0)
-  {
-    TV_GET_STATE_RESP_T tv;
-    m_DllBcmHost.vc_tv_get_state(&tv);
-
-    RESOLUTION_INFO res;
-    CLog::Log(LOGDEBUG, "EGL probe resolution %dx%d@%f %s:%x\n",
-        m_desktopRes.iWidth, m_desktopRes.iHeight, m_desktopRes.fRefreshRate,
-        m_desktopRes.dwFlags & D3DPRESENTFLAG_INTERLACED ? "i" : "p");
-
-    m_res.push_back(m_desktopRes);
-    resolutions.push_back(m_desktopRes);
-  }
-
-  if(resolutions.size() < 2)
-    m_fixedMode = true;
-
-  return true;
-}
-
-EGLNativeWindowType CWinEGLPlatformRaspberryPI::InitWindowSystem(EGLNativeDisplayType nativeDisplay, int width, int height, int bpp)
-{
-  m_nativeDisplay = nativeDisplay;
-  m_width         = width;
-  m_height        = height;
-
-  m_DllBcmHost.Load();
-
-  return getNativeWindow();
-}
-
-void CWinEGLPlatformRaspberryPI::DestroyWindowSystem(EGLNativeWindowType native_window)
-{
-  UninitializeDisplay();
-}
-
-bool CWinEGLPlatformRaspberryPI::InitializeDisplay()
-{
-  EGLBoolean eglStatus;
-  EGLint     configCount;
-  EGLConfig* configList = NULL;
-
-  m_display = eglGetDisplay(m_nativeDisplay);
-  if (m_display == EGL_NO_DISPLAY)
-  {
-    CLog::Log(LOGERROR, "EGL failed to obtain display");
-    return false;
-  }
-
-  if (!eglInitialize(m_display, 0, 0))
-  {
-    CLog::Log(LOGERROR, "EGL failed to initialize");
-    return false;
-  }
-
-  EGLint configAttrs[] = {
-        EGL_RED_SIZE,        8,
-        EGL_GREEN_SIZE,      8,
-        EGL_BLUE_SIZE,       8,
-        EGL_ALPHA_SIZE,      8,
-        EGL_SURFACE_TYPE,    EGL_WINDOW_BIT,
-        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-        EGL_DEPTH_SIZE,      16,
-        EGL_SAMPLE_BUFFERS,  1,
-        EGL_NONE
-  };
-
-  // Find out how many configurations suit our needs  
-  eglStatus = eglChooseConfig(m_display, configAttrs, NULL, 0, &configCount);
-  if (!eglStatus || !configCount)
-  {
-    CLog::Log(LOGERROR, "EGL failed to return any matching configurations: %d error : 0x%08x", eglStatus, eglGetError());
-    return false;
-  }
-
-  // Allocate room for the list of matching configurations
-  configList = (EGLConfig*)malloc(configCount * sizeof(EGLConfig));
-  if (!configList)
-  {
-    CLog::Log(LOGERROR, "EGL malloc failure obtaining configuration list");
-    return false;
-  }
-
-  // Obtain the configuration list from EGL
-  eglStatus = eglChooseConfig(m_display, configAttrs,
-                                configList, configCount, &configCount);
-  if (!eglStatus || !configCount)
-  {
-    CLog::Log(LOGERROR, "EGL failed to populate configuration list: %d error : 0x%08x", eglStatus, eglGetError());
-    return false;
-  }
-
-  // Select an EGL configuration that matches the native window
-  m_config = configList[0];
-
-  if (m_surface != EGL_NO_SURFACE)
-    ReleaseSurface();
-
-  free(configList);
-
-  return true;
-}
-
-bool CWinEGLPlatformRaspberryPI::UninitializeDisplay()
-{
-  EGLBoolean eglStatus;
-
-  // Recreate a new rendering context doesn't work on the PI.
-  // We have to keep the first created context alive until we exit.
-  if (m_context != EGL_NO_CONTEXT)
-  {
-    eglStatus = eglDestroyContext(m_display, m_context);
-    if (!eglStatus)
-      CLog::Log(LOGERROR, "EGL destroy context error : 0x%08x", eglGetError());
-    m_context = EGL_NO_CONTEXT;
-  }
-
-  DestroyWindow();
-
-  DestroyDispmaxWindow();
-
-  if (m_display != EGL_NO_DISPLAY)
-  {
-    eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-
-    eglStatus = eglTerminate(m_display);
-    if (!eglStatus)
-      CLog::Log(LOGERROR, "EGL terminate error 0x%08x", eglGetError());
-    m_display = EGL_NO_DISPLAY;
-  }
-
-  return true;
-}
-
-bool CWinEGLPlatformRaspberryPI::CreateWindow()
-{
-  if (m_display == EGL_NO_DISPLAY || m_config == NULL)
-  {
-    if (!InitializeDisplay())
-      return false;
-  }
-
-  if (m_surface != EGL_NO_SURFACE)
-    return true;
-
-  m_nativeWindow = (EGL_DISPMANX_WINDOW_T *)getNativeWindow();
-
-  m_surface = eglCreateWindowSurface(m_display, m_config, m_nativeWindow, NULL);
-  if (!m_surface)
-  {
-    CLog::Log(LOGERROR, "EGL couldn't create window surface");
-    return false;
-  }
-
-  // Let's get the current width and height
-  EGLint width, height;
-  if (!eglQuerySurface(m_display, m_surface, EGL_WIDTH, &width) || !eglQuerySurface(m_display, m_surface, EGL_HEIGHT, &height) ||
-      width <= 0 || height <= 0)
-  {
-    CLog::Log(LOGERROR, "EGL couldn't provide the surface's width and/or height");
-    return false;
-  }
-
-  m_width = width;
-  m_height = height;
-
-  return true;
-}
-
-void CWinEGLPlatformRaspberryPI::DestroyDispmaxWindow()
-{
-  DISPMANX_UPDATE_HANDLE_T dispman_update = m_DllBcmHost.vc_dispmanx_update_start(0);
-
-  if (m_dispman_element != DISPMANX_NO_HANDLE)
-  {
-    m_DllBcmHost.vc_dispmanx_element_remove(dispman_update, m_dispman_element);
-    m_dispman_element = DISPMANX_NO_HANDLE;
-  }
-  if (m_dispman_element2 != DISPMANX_NO_HANDLE)
-  {
-    m_DllBcmHost.vc_dispmanx_element_remove(dispman_update, m_dispman_element2);
-    m_dispman_element2 = DISPMANX_NO_HANDLE;
-  }
-  m_DllBcmHost.vc_dispmanx_update_submit_sync(dispman_update);
-
-  if (m_dispman_display != DISPMANX_NO_HANDLE)
-  {
-    m_DllBcmHost.vc_dispmanx_display_close(m_dispman_display);
-    m_dispman_display = DISPMANX_NO_HANDLE;
-  }
-}
-
-bool CWinEGLPlatformRaspberryPI::DestroyWindow()
-{
-  EGLBoolean eglStatus;
-
-  ReleaseSurface();
-
-  if (m_surface == EGL_NO_SURFACE)
-    return true;
-
-  eglStatus = eglDestroySurface(m_display, m_surface);
-  if (!eglStatus)
-  {
-    CLog::Log(LOGERROR, "EGL destroy surface error : 0x%08x", eglGetError());
-    return false;
-  }
-
-  m_surface = EGL_NO_SURFACE;
-  m_width = 0;
-  m_height = 0;
-
-  return true;
-}
-
-bool CWinEGLPlatformRaspberryPI::BindSurface()
-{
-  EGLBoolean eglStatus;
-
-  if (m_display == EGL_NO_DISPLAY || m_surface == EGL_NO_SURFACE || m_config == NULL)
-  {
-    CLog::Log(LOGINFO, "EGL not configured correctly. Let's try to do that now...");
-    if (!CreateWindow())
-    {
-      CLog::Log(LOGERROR, "EGL not configured correctly to create a surface");
-      return false;
-    }
-  }
-
-  eglStatus = eglBindAPI(EGL_OPENGL_ES_API);
-  if (!eglStatus)
-  {
-    CLog::Log(LOGERROR, "EGL failed to bind API: %d error 0x%08x", eglStatus, eglGetError());
-    return false;
-  }
-
-  EGLint contextAttrs[] =
-  {
-    EGL_CONTEXT_CLIENT_VERSION, 2,
-    EGL_NONE
-  };
-
-  // Create an EGL context
-  if (m_context == EGL_NO_CONTEXT)
-  {
-    m_context = eglCreateContext(m_display, m_config, EGL_NO_CONTEXT, contextAttrs);
-    if (!m_context)
-    {
-      CLog::Log(LOGERROR, "EGL couldn't create context");
-      return false;
-    }
-  }
-
-  // Make the context and surface current to this thread for rendering
-  eglStatus = eglMakeCurrent(m_display, m_surface, m_surface, m_context);
-  if (!eglStatus)
-  {
-    CLog::Log(LOGERROR, "EGL couldn't make context/surface current: %d error : 0x%08x", eglStatus, eglGetError());
-    return false;
-  }
-
-  eglSwapInterval(m_display, 0);
-
-  // For EGL backend, it needs to clear all the back buffers of the window
-  // surface before drawing anything, otherwise the image will be blinking
-  // heavily.  The default eglWindowSurface has 3 gdl surfaces as the back
-  // buffer, that's why glClear should be called 3 times.
-  glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
-  glClear (GL_COLOR_BUFFER_BIT);
-  eglSwapBuffers(m_display, m_surface);
-
-  glClear (GL_COLOR_BUFFER_BIT);
-  eglSwapBuffers(m_display, m_surface);
-
-  glClear (GL_COLOR_BUFFER_BIT);
-  eglSwapBuffers(m_display, m_surface);
-
-  m_eglext  = " ";
-  m_eglext += eglQueryString(m_display, EGL_EXTENSIONS);
-  m_eglext += " ";
-  CLog::Log(LOGDEBUG, "EGL extensions:%s", m_eglext.c_str());
-
-  // setup for vsync disabled
-  eglSwapInterval(m_display, 0);
-
-  CLog::Log(LOGINFO, "EGL window and context creation complete");
-
-  return true;
-}
-
-bool CWinEGLPlatformRaspberryPI::ReleaseSurface()
-{
-  EGLBoolean eglStatus;
-
-  if (m_display != EGL_NO_DISPLAY)
-    eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-
-  // Recreate a new rendering context doesn't work on the PI.
-  // We have to keep the first created context alive until we exit.
-  /*
-  if (m_context != EGL_NO_CONTEXT)
-  {
-    eglStatus = eglDestroyContext(m_display, m_context);
-    if (!eglStatus)
-      CLog::Log(LOGERROR, "Error destroying EGL context 0x%08x", eglGetError());
-    m_context = EGL_NO_CONTEXT;
-  }
-  */
-
-  return true;
-}
-
-bool CWinEGLPlatformRaspberryPI::ShowWindow(bool show)
-{
-  return true;
-}
-
-void CWinEGLPlatformRaspberryPI::SwapBuffers()
-{
-  eglSwapBuffers(m_display, m_surface);
-}
-
-bool CWinEGLPlatformRaspberryPI::SetVSync(bool enable)
-{
-  // depending how buffers are setup, eglSwapInterval
-  // might fail so let caller decide if this is an error.
-  return eglSwapInterval(m_display, enable ? 1 : 0);
-}
-
-bool CWinEGLPlatformRaspberryPI::IsExtSupported(const char* extension)
-{
-  CStdString name;
-
-  name  = " ";
-  name += extension;
-  name += " ";
-
-  return m_eglext.find(name) != std::string::npos;
-}
-
-EGLNativeWindowType CWinEGLPlatformRaspberryPI::getNativeWindow()
-{
-  return (EGLNativeWindowType)m_nativeWindow;
-}
-
-EGLDisplay CWinEGLPlatformRaspberryPI::GetEGLDisplay()
-{
-  return m_display;
-}
-
-EGLSurface CWinEGLPlatformRaspberryPI::GetEGLSurface()
-{
-  return m_surface;
-}
-
-EGLContext CWinEGLPlatformRaspberryPI::GetEGLContext()
-{
-  return m_context;
-}
-
-void CWinEGLPlatformRaspberryPI::TvServiceCallback(uint32_t reason, uint32_t param1, uint32_t param2)
-{
-  CLog::Log(LOGDEBUG, "EGL tv_service_callback (%d,%d,%d)\n", reason, param1, param2);
-  switch(reason)
-  {
-  case VC_HDMI_UNPLUGGED:
-    break;
-  case VC_HDMI_STANDBY:
-    break;
-  case VC_SDTV_NTSC:
-  case VC_SDTV_PAL:
-  case VC_HDMI_HDMI:
-  case VC_HDMI_DVI:
-    //Signal we are ready now
-    sem_post(&m_tv_synced);
-    break;
-  default:
-     break;
-  }
-}
-
-void CWinEGLPlatformRaspberryPI::CallbackTvServiceCallback(void *userdata, uint32_t reason, uint32_t param1, uint32_t param2)
-{
-   CWinEGLPlatformRaspberryPI *callback = static_cast<CWinEGLPlatformRaspberryPI*>(userdata);
-   callback->TvServiceCallback(reason, param1, param2);
-}
-
-void CWinEGLPlatformRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::vector<RESOLUTION_INFO> &resolutions)
-{
-  //Supported HDMI CEA/DMT resolutions, first one will be preferred resolution
-  TV_SUPPORTED_MODE_T supported_modes[TV_MAX_SUPPORTED_MODES];
-  int32_t num_modes;
-  HDMI_RES_GROUP_T prefer_group;
-  uint32_t prefer_mode;
-  int i;
-
-  num_modes = m_DllBcmHost.vc_tv_hdmi_get_supported_modes(group,
-      supported_modes, TV_MAX_SUPPORTED_MODES, &prefer_group, &prefer_mode);
-
-  CLog::Log(LOGDEBUG, "EGL get supported modes (%d) = %d, prefer_group=%x, prefer_mode=%x\n", 
-      group, num_modes, prefer_group, prefer_mode);
-
-  if (num_modes > 0 && prefer_group != HDMI_RES_GROUP_INVALID)
-  {
-    TV_SUPPORTED_MODE_T *tv = supported_modes;
-    for (i=0; i < num_modes; i++, tv++)
-    {
-      // treat 3D modes as half-width SBS
-      unsigned int width = (group == HDMI_RES_GROUP_CEA_3D) ? tv->width>>1 : tv->width;
-      RESOLUTION_INFO res;
-      CLog::Log(LOGDEBUG, "EGL mode %d: %dx%d@%d %s%s:%x\n", i, width, tv->height, tv->frame_rate, 
-          tv->native ? "N" : "", tv->scan_mode ? "I" : "", tv->code);
-
-      res.iScreen       = 0;
-      res.bFullScreen   = true;
-      res.iSubtitles    = (int)(0.965 * tv->height);
-      res.dwFlags       = MAKEFLAGS(group, tv->code, tv->scan_mode, group==HDMI_RES_GROUP_CEA_3D);
-      res.fRefreshRate  = (float)tv->frame_rate;
-      res.fPixelRatio   = 1.0f;
-      res.iWidth        = width;
-      res.iHeight       = tv->height;
-      res.iScreenWidth  = width;
-      res.iScreenHeight = tv->height;
-      res.strMode.Format("%dx%d", width, tv->height);
-      if((float)tv->frame_rate > 1)
-      {
-        res.strMode.Format("%s @ %.2f%s - Full Screen", res.strMode, (float)tv->frame_rate, 
-            res.dwFlags & D3DPRESENTFLAG_INTERLACED ? "i" : "");
-      }
-
-      resolutions.push_back(res);
-
-      /* replace initial desktop resolution with probed hdmi resolution */
-      if(m_desktopRes.iWidth == res.iWidth && m_desktopRes.iHeight == res.iHeight &&
-          m_desktopRes.iScreenWidth == res.iScreenWidth && m_desktopRes.iScreenHeight == res.iScreenHeight &&
-          m_desktopRes.fRefreshRate == res.fRefreshRate)
-      {
-        m_desktopRes = res;
-        CLog::Log(LOGDEBUG, "EGL desktop replacement resolution %dx%d@%d %s%s:%x\n", 
-            width, tv->height, tv->frame_rate, tv->native ? "N" : "", tv->scan_mode ? "I" : "", tv->code);
-      }
-
-      m_res.push_back(res);
-    }
-  }
-}
-
-#endif
-
-#endif
diff --git a/xbmc/windowing/egl/WinEGLPlatformRaspberryPI.h b/xbmc/windowing/egl/WinEGLPlatformRaspberryPI.h
deleted file mode 100644 (file)
index 51aa46b..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-#pragma once
-/*
- *      Copyright (C) 2005-2012 Team XBMC
- *      http://www.xbmc.org
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with XBMC; see the file COPYING.  If not, see
- *  <http://www.gnu.org/licenses/>.
- *
- */
-
-#if defined(TARGET_RASPBERRY_PI)
-
-#include "WinEGLPlatformGeneric.h"
-#include "utils/StringUtils.h"
-#include "guilib/Resolution.h"
-
-#include <semaphore.h>
-
-#include "linux/DllBCM.h"
-
-class CWinEGLPlatformRaspberryPI
-{
-public:
-  CWinEGLPlatformRaspberryPI();
-  virtual ~CWinEGLPlatformRaspberryPI();
-
-  virtual bool SetDisplayResolution(RESOLUTION_INFO &res);
-  virtual bool ClampToGUIDisplayLimits(int &width, int &height);
-  virtual bool ProbeDisplayResolutions(std::vector<RESOLUTION_INFO> &resolutions);
-
-  virtual EGLNativeWindowType InitWindowSystem(EGLNativeDisplayType nativeDisplay, int width, int height, int bpp);
-  virtual void DestroyWindowSystem(EGLNativeWindowType native_window);
-
-  virtual bool InitializeDisplay();
-  virtual bool UninitializeDisplay();
-  virtual bool BindSurface();
-  virtual bool CreateWindow();
-  virtual bool DestroyWindow();
-  virtual bool ShowWindow(bool show);
-  virtual bool ReleaseSurface();
-
-  virtual void SwapBuffers();
-  virtual bool SetVSync(bool enable);
-  virtual bool IsExtSupported(const char* extension);
-
-  virtual EGLDisplay        GetEGLDisplay();
-  virtual EGLSurface        GetEGLSurface();
-  virtual EGLContext        GetEGLContext();
-  virtual bool              FixedDesktop()  { return true; }
-  virtual RESOLUTION_INFO   GetDesktopRes() { return m_desktopRes; }
-
-protected:
-  virtual EGLNativeWindowType getNativeWindow();
-  void DestroyDispmaxWindow();
-
-  EGL_DISPMANX_WINDOW_T *m_nativeWindow;
-  EGLNativeDisplayType  m_nativeDisplay;
-  EGLDisplay            m_display;
-  EGLSurface            m_surface;
-  EGLConfig             m_config;
-  EGLContext            m_context;
-  CStdString            m_eglext;
-  int                   m_width;
-  int                   m_height;
-
-  DllBcmHost            m_DllBcmHost;
-
-  DISPMANX_ELEMENT_HANDLE_T m_dispman_element;
-  DISPMANX_ELEMENT_HANDLE_T m_dispman_element2;
-  DISPMANX_DISPLAY_HANDLE_T m_dispman_display;
-  sem_t                 m_tv_synced;
-
-  void GetSupportedModes(HDMI_RES_GROUP_T group, std::vector<RESOLUTION_INFO> &resolutions);
-  void TvServiceCallback(uint32_t reason, uint32_t param1, uint32_t param2);
-  static void CallbackTvServiceCallback(void *userdata, uint32_t reason, uint32_t param1, uint32_t param2);
-
-  std::vector<RESOLUTION_INFO> m_res;
-
-  RESOLUTION_INFO m_desktopRes;
-
-  bool                m_fixedMode;
-  bool                m_initDesktopRes;
-};
-
-#endif
diff --git a/xbmc/windowing/egl/WinSystemEGL.cpp b/xbmc/windowing/egl/WinSystemEGL.cpp
new file mode 100644 (file)
index 0000000..f089eb5
--- /dev/null
@@ -0,0 +1,470 @@
+/*
+ *      Copyright (C) 2011-2012 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include "system.h"
+
+#ifdef HAS_EGL
+
+#include "WinSystemEGL.h"
+#include "filesystem/SpecialProtocol.h"
+#include "settings/Settings.h"
+#include "utils/log.h"
+#include "EGLWrapper.h"
+#include "EGLQuirks.h"
+#include <vector>
+////////////////////////////////////////////////////////////////////////////////////////////
+CWinSystemEGL::CWinSystemEGL() : CWinSystemBase()
+{
+  m_eWindowSystem = WINDOW_SYSTEM_EGL;
+
+  m_displayWidth      = 0;
+  m_displayHeight     = 0;
+
+  m_display           = EGL_NO_DISPLAY;
+  m_surface           = EGL_NO_SURFACE;
+  m_context           = EGL_NO_CONTEXT;
+  m_config            = NULL;
+
+  m_egl               = NULL;
+  m_iVSyncMode        = false;
+}
+
+CWinSystemEGL::~CWinSystemEGL()
+{
+  if (m_egl)
+  {
+    DestroyWindowSystem();
+    delete m_egl;
+  }
+}
+
+bool CWinSystemEGL::InitWindowSystem()
+{
+  RESOLUTION_INFO preferred_resolution;
+  if (!m_egl)
+    m_egl = new CEGLWrapper;
+
+  if (!m_egl)
+  {
+    CLog::Log(LOGERROR, "%s: EGL not in a good state",__FUNCTION__);
+    return false;
+  }
+
+  if (!m_egl->Initialize("auto"))
+  {
+    CLog::Log(LOGERROR, "%s: Could not initialize",__FUNCTION__);
+    return false;
+  }
+
+  CLog::Log(LOGNOTICE, "%s: Using EGL Implementation: %s",__FUNCTION__,m_egl->GetNativeName().c_str());
+
+  if (!m_egl->CreateNativeDisplay())
+  {
+    CLog::Log(LOGERROR, "%s: Could not get native display",__FUNCTION__);
+    return false;
+  }
+
+  if (!m_egl->CreateNativeWindow())
+  {
+    CLog::Log(LOGERROR, "%s: Could not get native window",__FUNCTION__);
+    return false;
+  }
+
+  if (!m_egl->InitDisplay(&m_display))
+  {
+    CLog::Log(LOGERROR, "%s: Could not create display",__FUNCTION__);
+    return false;
+  }
+
+  EGLint configAttrs [] = {
+        EGL_RED_SIZE,        8,
+        EGL_GREEN_SIZE,      8,
+        EGL_BLUE_SIZE,       8,
+        EGL_ALPHA_SIZE,      8,
+        EGL_DEPTH_SIZE,     16,
+        EGL_STENCIL_SIZE,    0,
+        EGL_SAMPLE_BUFFERS,  0,
+        EGL_SAMPLES,         0,
+        EGL_SURFACE_TYPE,    EGL_WINDOW_BIT,
+        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+        EGL_NONE
+  };
+
+  if (!m_egl->ChooseConfig(m_display, configAttrs, &m_config))
+  {
+    CLog::Log(LOGERROR, "%s: Could not find a compatible configuration",__FUNCTION__);
+    return false;
+  }
+
+  // Some platforms require a surface before we can probe the resolution.
+  // Create the window here, then the creation in CreateNewWindow() will be skipped.
+  int quirks;
+  m_egl->GetQuirks(&quirks);
+  if (quirks & EGL_QUIRK_NEED_WINDOW_FOR_RES)
+  {
+    RESOLUTION_INFO temp;
+    CreateWindow(temp);
+  }
+
+  m_extensions = m_egl->GetExtensions(m_display);
+  return CWinSystemBase::InitWindowSystem();
+}
+
+bool CWinSystemEGL::CreateWindow(RESOLUTION_INFO &res)
+{
+  if (!m_egl)
+  {
+    CLog::Log(LOGERROR, "CWinSystemEGL::CreateWindow no EGL!");
+    return false;
+  }
+
+  if(m_egl)
+    m_egl->SetNativeResolution(res);
+
+  if (!m_egl->CreateSurface(m_display, m_config, &m_surface))
+  {
+    CLog::Log(LOGNOTICE, "%s: Could not create a surface. Trying with a fresh Native Window.",__FUNCTION__);
+    m_egl->DestroyNativeWindow();
+    if (!m_egl->CreateNativeWindow())
+    {
+      CLog::Log(LOGERROR, "%s: Could not get native window",__FUNCTION__);
+      return false;
+    }
+
+    if (!m_egl->CreateSurface(m_display, m_config, &m_surface))
+    {
+      CLog::Log(LOGERROR, "%s: Could not create surface",__FUNCTION__);
+      return false;
+    }
+  }
+
+  int width = 0, height = 0;
+  if (!m_egl->GetSurfaceSize(m_display, m_surface, &width, &height))
+  {
+    CLog::Log(LOGERROR, "%s: Surface is invalid",__FUNCTION__);
+    return false;
+  }
+  CLog::Log(LOGDEBUG, "%s: Created surface of size %ix%i",__FUNCTION__, width, height);
+
+  EGLint contextAttrs[] =
+  {
+    EGL_CONTEXT_CLIENT_VERSION, 2,
+    EGL_NONE
+  };
+
+  if (!m_egl->BindAPI(EGL_OPENGL_ES_API))
+  {
+    CLog::Log(LOGERROR, "%s: Could not bind %i api",__FUNCTION__, EGL_OPENGL_ES_API);
+    return false;
+  }
+
+  if (m_context == EGL_NO_CONTEXT)
+  {
+    if (!m_egl->CreateContext(m_display, m_config, contextAttrs, &m_context))
+    {
+      CLog::Log(LOGERROR, "%s: Could not create context",__FUNCTION__);
+      return false;
+    }
+  }
+
+  if (!m_egl->BindContext(m_display, m_surface, m_context))
+  {
+    CLog::Log(LOGERROR, "%s: Could not bind to context",__FUNCTION__);
+    return false;
+  }
+
+  m_bWindowCreated = true;
+
+  return true;
+}
+
+bool CWinSystemEGL::DestroyWindowSystem()
+{
+  if (!m_egl)
+    return true;
+
+  DestroyWindow();
+
+  if (m_context != EGL_NO_CONTEXT)
+    m_egl->DestroyContext(m_display, m_context);
+  m_context = EGL_NO_CONTEXT;
+
+  if (m_display != EGL_NO_DISPLAY)
+    m_egl->DestroyDisplay(m_display);
+  m_display = EGL_NO_DISPLAY;
+
+  m_egl->DestroyNativeWindow();
+
+  m_egl->DestroyNativeDisplay();
+
+  m_egl->Destroy();
+  delete m_egl;
+  m_egl = NULL;
+
+  return true;
+}
+
+bool CWinSystemEGL::CreateNewWindow(const CStdString& name, bool fullScreen, RESOLUTION_INFO& res, PHANDLE_EVENT_FUNC userFunction)
+{
+  RESOLUTION_INFO current_resolution;
+  current_resolution.iWidth = current_resolution.iHeight = 0;
+
+  m_nWidth        = res.iWidth;    
+  m_nHeight       = res.iHeight;
+  m_displayWidth  = res.iScreenWidth;
+  m_displayHeight = res.iScreenHeight;
+  m_fRefreshRate  = res.fRefreshRate;
+
+  if ((m_bWindowCreated && m_egl && m_egl->GetNativeResolution(&current_resolution)) &&
+    current_resolution.iWidth == res.iWidth && current_resolution.iHeight == res.iHeight &&
+    current_resolution.iScreenWidth == res.iScreenWidth && current_resolution.iScreenHeight == res.iScreenHeight &&
+    m_bFullScreen == fullScreen && current_resolution.fRefreshRate == res.fRefreshRate)
+  {
+    CLog::Log(LOGDEBUG, "CWinSystemEGL::CreateNewWindow: No need to create a new window");
+    return true;
+  }
+
+  m_bFullScreen   = fullScreen;
+  // Destroy any existing window
+  if (m_surface != EGL_NO_SURFACE)
+    DestroyWindow();
+
+  // If we previously destroyed an existing window we need to create a new one
+  // (otherwise this is taken care of by InitWindowSystem())
+  if (!CreateWindow(res))
+  {
+    CLog::Log(LOGERROR, "%s: Could not create new window",__FUNCTION__);
+    return false;
+  }
+  Show();
+
+  return true;
+}
+
+bool CWinSystemEGL::DestroyWindow()
+{
+  if (!m_egl)
+    return false;
+
+  m_egl->ReleaseContext(m_display);
+  if (m_surface != EGL_NO_SURFACE)
+    m_egl->DestroySurface(m_surface, m_display);
+
+  m_surface = EGL_NO_SURFACE;
+  m_bWindowCreated = false;
+  return true;
+}
+
+bool CWinSystemEGL::ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop)
+{
+  CRenderSystemGLES::ResetRenderSystem(newWidth, newHeight, true, 0);
+  SetVSyncImpl(m_iVSyncMode);
+  return true;
+}
+
+bool CWinSystemEGL::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays)
+{
+  CreateNewWindow("", fullScreen, res, NULL);
+  CRenderSystemGLES::ResetRenderSystem(res.iWidth, res.iHeight, fullScreen, res.fRefreshRate);
+  SetVSyncImpl(m_iVSyncMode);
+  return true;
+}
+
+void CWinSystemEGL::UpdateResolutions()
+{
+  CWinSystemBase::UpdateResolutions();
+
+  RESOLUTION_INFO resDesktop, curDisplay;
+  std::vector<RESOLUTION_INFO> resolutions;
+
+  if (!m_egl->ProbeResolutions(resolutions) || !resolutions.size())
+  {
+    CLog::Log(LOGERROR, "%s: Could not find any possible resolutions",__FUNCTION__);
+    return;
+  }
+
+  /* ProbeResolutions includes already all resolutions.
+   * Only get desktop resolution so we can replace xbmc's desktop res
+   */
+  if (m_egl->GetNativeResolution(&curDisplay))
+    resDesktop = curDisplay;
+
+
+  RESOLUTION ResDesktop = RES_INVALID;
+  RESOLUTION res_index  = RES_DESKTOP;
+
+  for (size_t i = 0; i < resolutions.size(); i++)
+  {
+    // if this is a new setting,
+    // create a new empty setting to fill in.
+    if ((int)g_settings.m_ResInfo.size() <= res_index)
+    {
+      RESOLUTION_INFO res;
+
+      g_settings.m_ResInfo.push_back(res);
+    }
+
+    g_graphicsContext.ResetOverscan(resolutions[i]);
+    g_settings.m_ResInfo[res_index] = resolutions[i];
+
+    CLog::Log(LOGNOTICE, "Found resolution %d x %d for display %d with %d x %d%s @ %f Hz\n",
+      resolutions[i].iWidth,
+      resolutions[i].iHeight,
+      resolutions[i].iScreen,
+      resolutions[i].iScreenWidth,
+      resolutions[i].iScreenHeight,
+      resolutions[i].dwFlags & D3DPRESENTFLAG_INTERLACED ? "i" : "",
+      resolutions[i].fRefreshRate);
+
+    if(resDesktop.iWidth == resolutions[i].iWidth &&
+       resDesktop.iHeight == resolutions[i].iHeight &&
+       resDesktop.iScreenWidth == resolutions[i].iScreenWidth &&
+       resDesktop.iScreenHeight == resolutions[i].iScreenHeight &&
+       resDesktop.fRefreshRate == resolutions[i].fRefreshRate)
+    {
+      ResDesktop = res_index;
+    }
+
+    res_index = (RESOLUTION)((int)res_index + 1);
+  }
+
+  // swap desktop index for desktop res if available
+  if (ResDesktop != RES_INVALID)
+  {
+    CLog::Log(LOGNOTICE, "Found (%dx%d%s@%f) at %d, setting to RES_DESKTOP at %d",
+      resDesktop.iWidth, resDesktop.iHeight,
+      resDesktop.dwFlags & D3DPRESENTFLAG_INTERLACED ? "i" : "",
+      resDesktop.fRefreshRate,
+      (int)ResDesktop, (int)RES_DESKTOP);
+
+    RESOLUTION_INFO desktop = g_settings.m_ResInfo[RES_DESKTOP];
+    g_settings.m_ResInfo[RES_DESKTOP] = g_settings.m_ResInfo[ResDesktop];
+    g_settings.m_ResInfo[ResDesktop] = desktop;
+  }
+}
+
+bool CWinSystemEGL::IsExtSupported(const char* extension)
+{
+  std::string name;
+
+  name  = " ";
+  name += extension;
+  name += " ";
+
+  return m_extensions.find(name) != std::string::npos;
+}
+
+bool CWinSystemEGL::PresentRenderImpl(const CDirtyRegionList &dirty)
+{
+  m_egl->SwapBuffers(m_display, m_surface);
+  return true;
+}
+
+void CWinSystemEGL::SetVSyncImpl(bool enable)
+{
+  if (!m_egl->SetVSync(m_display, enable))
+    CLog::Log(LOGERROR, "%s,Could not set egl vsync", __FUNCTION__);
+}
+
+void CWinSystemEGL::ShowOSMouse(bool show)
+{
+}
+
+bool CWinSystemEGL::HasCursor()
+{
+#ifdef TARGET_ANDROID
+  return false;
+#else
+  return true;
+#endif
+}
+
+void CWinSystemEGL::NotifyAppActiveChange(bool bActivated)
+{
+}
+
+bool CWinSystemEGL::Minimize()
+{
+  Hide();
+  return true;
+}
+
+bool CWinSystemEGL::Restore()
+{
+  Show(true);
+  return false;
+}
+
+bool CWinSystemEGL::Hide()
+{
+  return m_egl->ShowWindow(false);
+}
+
+bool CWinSystemEGL::Show(bool raise)
+{
+  return m_egl->ShowWindow(true);
+}
+
+EGLDisplay CWinSystemEGL::GetEGLDisplay()
+{
+  return m_display;
+}
+
+EGLContext CWinSystemEGL::GetEGLContext()
+{
+  return m_context;
+}
+
+bool CWinSystemEGL::Support3D(int width, int height, uint32_t mode) const
+{
+  bool bFound = false;
+  int searchMode = 0;
+  int searchWidth = width;
+  int searchHeight = height;
+
+  if (mode & D3DPRESENTFLAG_MODE3DSBS)
+  {
+    searchWidth /= 2;
+    searchMode = D3DPRESENTFLAG_MODE3DSBS;
+  }
+  else if (mode & D3DPRESENTFLAG_MODE3DTB)
+  {
+    searchHeight /= 2;
+    searchMode = D3DPRESENTFLAG_MODE3DTB;
+  }
+
+  for (unsigned int i = 0; i < g_settings.m_ResInfo.size(); i++)
+  {
+    RESOLUTION_INFO res = g_settings.m_ResInfo[i];
+
+    if(res.iWidth == searchWidth && res.iHeight == searchHeight && (res.dwFlags & searchMode))
+      return true;
+  }
+
+  return bFound;
+}
+
+bool CWinSystemEGL::ClampToGUIDisplayLimits(int &width, int &height)
+{
+  width = width > m_nWidth ? m_nWidth : width;
+  height = height > m_nHeight ? m_nHeight : height;
+  return true;
+}
+
+#endif
diff --git a/xbmc/windowing/egl/WinSystemEGL.h b/xbmc/windowing/egl/WinSystemEGL.h
new file mode 100644 (file)
index 0000000..fae528c
--- /dev/null
@@ -0,0 +1,85 @@
+#ifndef WINDOW_SYSTEM_EGL_H
+#define WINDOW_SYSTEM_EGL_H
+
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2012 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "rendering/gles/RenderSystemGLES.h"
+#include "utils/GlobalsHandling.h"
+#include <EGL/egl.h>
+#include "windowing/WinSystem.h"
+
+class CEGLWrapper;
+
+class CWinSystemEGL : public CWinSystemBase, public CRenderSystemGLES
+{
+public:
+  CWinSystemEGL();
+  virtual ~CWinSystemEGL();
+
+  virtual bool  InitWindowSystem();
+  virtual bool  DestroyWindowSystem();
+  virtual bool  CreateNewWindow(const CStdString& name, bool fullScreen, RESOLUTION_INFO& res, PHANDLE_EVENT_FUNC userFunction);
+  virtual bool  DestroyWindow();
+  virtual bool  ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop);
+  virtual bool  SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays);
+  virtual void  UpdateResolutions();
+  virtual bool  IsExtSupported(const char* extension);
+
+  virtual void  ShowOSMouse(bool show);
+  virtual bool  HasCursor();
+
+  virtual void  NotifyAppActiveChange(bool bActivated);
+
+  virtual bool  Minimize();
+  virtual bool  Restore() ;
+  virtual bool  Hide();
+  virtual bool  Show(bool raise = true);
+
+  virtual bool  Support3D(int width, int height, uint32_t mode)     const;
+  virtual bool  ClampToGUIDisplayLimits(int &width, int &height);
+
+protected:
+  virtual bool  PresentRenderImpl(const CDirtyRegionList &dirty);
+  virtual void  SetVSyncImpl(bool enable);
+
+  bool          CreateWindow(RESOLUTION_INFO &res);
+  EGLDisplay    GetEGLDisplay();
+  EGLContext    GetEGLContext();
+
+  int                   m_displayWidth;
+  int                   m_displayHeight;
+
+  EGLDisplay            m_display;
+  EGLSurface            m_surface;
+  EGLContext            m_context;
+  EGLConfig             m_config;
+
+  CEGLWrapper           *m_egl;
+  bool                  m_iVSyncMode;
+  std::string           m_extensions;
+};
+
+XBMC_GLOBAL_REF(CWinSystemEGL,g_Windowing);
+#define g_Windowing XBMC_GLOBAL_USE(CWinSystemEGL)
+
+#endif // WINDOW_SYSTEM_EGL_H
diff --git a/xbmc/windowing/egl/WinSystemGLES.cpp b/xbmc/windowing/egl/WinSystemGLES.cpp
deleted file mode 100644 (file)
index 6ffe486..0000000
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- *      Copyright (C) 2011-2012 Team XBMC
- *      http://www.xbmc.org
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with XBMC; see the file COPYING.  If not, see
- *  <http://www.gnu.org/licenses/>.
- *
- */
-#include "system.h"
-
-#ifdef HAS_EGL
-
-#include "WinSystemGLES.h"
-#include "filesystem/SpecialProtocol.h"
-#include "settings/Settings.h"
-#include "guilib/Texture.h"
-#include "utils/log.h"
-
-#include <vector>
-
-////////////////////////////////////////////////////////////////////////////////////////////
-CWinSystemGLES::CWinSystemGLES() : CWinSystemBase()
-{
-  m_window = NULL;
-  m_eglplatform = new CWinEGLPlatform();
-  m_eWindowSystem = WINDOW_SYSTEM_EGL;
-}
-
-CWinSystemGLES::~CWinSystemGLES()
-{
-  DestroyWindowSystem();
-  delete m_eglplatform;
-}
-
-bool CWinSystemGLES::InitWindowSystem()
-{
-  m_display = EGL_DEFAULT_DISPLAY;
-  m_window = m_eglplatform->InitWindowSystem(m_display, 1920, 1080, 8);
-  
-  // Initialize the display
-  // This needs to happen before the call to CWinSystemBase::InitWindowSystem()
-  // (at least for Android)
-  if (!m_eglplatform->InitializeDisplay())
-    return false;
-  
-  // Create a window to get valid width and height values
-  // This needs to happen before the call to CWinSystemBase::InitWindowSystem()
-  // (at least for Android)
-#if defined(TARGET_ANDROID)
-  if(!m_eglplatform->CreateWindow())
-    return false;
-#endif
-
-  if (!CWinSystemBase::InitWindowSystem())
-    return false;
-
-  return true;
-}
-
-bool CWinSystemGLES::DestroyWindowSystem()
-{
-  m_eglplatform->DestroyWindowSystem(m_window);
-  m_window = NULL;
-
-  return true;
-}
-
-bool CWinSystemGLES::CreateNewWindow(const CStdString& name, bool fullScreen, RESOLUTION_INFO& res, PHANDLE_EVENT_FUNC userFunction)
-{
-  if (m_bWindowCreated &&
-    m_nWidth == res.iWidth && m_nHeight == res.iHeight &&
-    m_nScreenWidth == res.iScreenWidth && m_nScreenHeight == res.iScreenHeight &&
-    m_bFullScreen  == fullScreen &&
-    m_fRefreshRate == res.fRefreshRate)
-  {
-    CLog::Log(LOGDEBUG, "CWinSystemGLES::CreateNewWindow: No need to create a new window");
-    return true;
-  }
-
-  m_nWidth  = res.iWidth;
-  m_nHeight = res.iHeight;
-  m_nScreenWidth  = res.iScreenWidth;
-  m_nScreenHeight = res.iScreenHeight;
-  m_bFullScreen   = fullScreen;
-  m_fRefreshRate  = res.fRefreshRate;
-  
-  // Destroy any existing window
-  if (m_bWindowCreated)
-    m_eglplatform->DestroyWindow();
-
-  m_eglplatform->SetDisplayResolution(res);
-    
-  // If we previously destroyed an existing window we need to create a new one
-  // (otherwise this is taken care of by InitWindowSystem())
-  if (m_bWindowCreated)
-    m_eglplatform->CreateWindow();
-
-  if (!m_eglplatform->BindSurface())
-  {
-    m_eglplatform->DestroyWindow();
-    return false;
-  }
-
-  m_bWindowCreated = true;
-
-  return true;
-}
-
-bool CWinSystemGLES::DestroyWindow()
-{
-  if (!m_eglplatform->DestroyWindow())
-    return false;
-
-  m_bWindowCreated = false;
-
-  return true;
-}
-
-bool CWinSystemGLES::ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop)
-{
-  CRenderSystemGLES::ResetRenderSystem(newWidth, newHeight, true, 0);
-  return true;
-}
-
-bool CWinSystemGLES::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays)
-{
-  CreateNewWindow("", fullScreen, res, NULL);
-  CRenderSystemGLES::ResetRenderSystem(res.iWidth, res.iHeight, fullScreen, res.fRefreshRate);
-  return true;
-}
-
-void CWinSystemGLES::UpdateResolutions()
-{
-  CWinSystemBase::UpdateResolutions();
-
-  std::vector<RESOLUTION_INFO> resolutions;
-
-  m_eglplatform->ProbeDisplayResolutions(resolutions);
-
-  RESOLUTION_INFO resDesktop = m_eglplatform->GetDesktopRes();
-
-  RESOLUTION ResDesktop = RES_INVALID;
-  RESOLUTION res_index  = RES_DESKTOP;
-
-  for (size_t i = 0; i < resolutions.size(); i++)
-  {
-    int gui_width  = resolutions[i].iWidth;
-    int gui_height = resolutions[i].iHeight;
-
-    m_eglplatform->ClampToGUIDisplayLimits(gui_width, gui_height);
-
-    resolutions[i].iWidth = gui_width;
-    resolutions[i].iHeight = gui_height;
-
-    // if this is a new setting,
-    // create a new empty setting to fill in.
-    if ((int)g_settings.m_ResInfo.size() <= res_index)
-    {
-      RESOLUTION_INFO res;
-
-      g_settings.m_ResInfo.push_back(res);
-    }
-
-    g_graphicsContext.ResetOverscan(resolutions[i]);
-    g_settings.m_ResInfo[res_index] = resolutions[i];
-
-    CLog::Log(LOGNOTICE, "Found resolution %d x %d for display %d with %d x %d%s @ %f Hz\n",
-      resolutions[i].iWidth,
-      resolutions[i].iHeight,
-      resolutions[i].iScreen,
-      resolutions[i].iScreenWidth,
-      resolutions[i].iScreenHeight,
-      resolutions[i].dwFlags & D3DPRESENTFLAG_INTERLACED ? "i" : "",
-      resolutions[i].fRefreshRate);
-
-    if(m_eglplatform->FixedDesktop())
-    {
-      if(resDesktop.iWidth == resolutions[i].iWidth &&
-         resDesktop.iHeight == resolutions[i].iHeight &&
-         resDesktop.iScreenWidth == resolutions[i].iScreenWidth &&
-         resDesktop.iScreenHeight == resolutions[i].iScreenHeight &&
-         resDesktop.fRefreshRate == resolutions[i].fRefreshRate &&
-         resDesktop.dwFlags == resolutions[i].dwFlags)
-      {
-        ResDesktop = res_index;
-      }
-    }
-
-    res_index = (RESOLUTION)((int)res_index + 1);
-  }
-
-  // swap desktop index for desktop res if available
-  if (ResDesktop != RES_INVALID)
-  {
-    CLog::Log(LOGNOTICE, "Found (%dx%d%s@%f) at %d, setting to RES_DESKTOP at %d",
-      resDesktop.iWidth, resDesktop.iHeight,
-      resDesktop.dwFlags & D3DPRESENTFLAG_INTERLACED ? "i" : "",
-      resDesktop.fRefreshRate,
-      (int)ResDesktop, (int)RES_DESKTOP);
-
-    RESOLUTION_INFO desktop = g_settings.m_ResInfo[RES_DESKTOP];
-    g_settings.m_ResInfo[RES_DESKTOP] = g_settings.m_ResInfo[ResDesktop];
-    g_settings.m_ResInfo[ResDesktop] = desktop;
-  }
-}
-
-bool CWinSystemGLES::IsExtSupported(const char* extension)
-{
-  if(strncmp(extension, "EGL_", 4) != 0)
-    return CRenderSystemGLES::IsExtSupported(extension);
-
-  return m_eglplatform->IsExtSupported(extension);
-}
-
-bool CWinSystemGLES::PresentRenderImpl(const CDirtyRegionList &dirty)
-{
-  m_eglplatform->SwapBuffers();
-
-  return true;
-}
-
-void CWinSystemGLES::SetVSyncImpl(bool enable)
-{
-  m_iVSyncMode = enable ? 10 : 0;
-  if (m_eglplatform->SetVSync(enable) == FALSE)
-    CLog::Log(LOGERROR, "CWinSystemDFB::SetVSyncImpl: Could not set egl vsync");
-}
-
-void CWinSystemGLES::ShowOSMouse(bool show)
-{
-}
-
-bool CWinSystemGLES::HasCursor()
-{
-#ifdef TARGET_ANDROID
-  return false;
-#else
-  return true;
-#endif
-}
-
-void CWinSystemGLES::NotifyAppActiveChange(bool bActivated)
-{
-}
-
-bool CWinSystemGLES::Minimize()
-{
-  Hide();
-  return true;
-}
-
-bool CWinSystemGLES::Restore()
-{
-  Show(true);
-  return false;
-}
-
-bool CWinSystemGLES::Hide()
-{
-  return m_eglplatform->ShowWindow(false);
-}
-
-bool CWinSystemGLES::Show(bool raise)
-{
-  return m_eglplatform->ShowWindow(true);
-}
-
-EGLDisplay CWinSystemGLES::GetEGLDisplay()
-{
-  return m_eglplatform->GetEGLDisplay();
-}
-
-EGLContext CWinSystemGLES::GetEGLContext()
-{
-  return m_eglplatform->GetEGLContext();
-}
-
-bool CWinSystemGLES::Support3D(int width, int height, uint32_t mode) const
-{
-  bool bFound = false;
-  int searchMode = 0;
-  int searchWidth = width;
-  int searchHeight = height;
-
-  if(mode & D3DPRESENTFLAG_MODE3DSBS)
-  {
-    searchWidth /= 2;
-    searchMode = D3DPRESENTFLAG_MODE3DSBS;
-  }
-  else if(mode & D3DPRESENTFLAG_MODE3DTB)
-  {
-    searchHeight /= 2;
-    searchMode = D3DPRESENTFLAG_MODE3DTB;
-  }
-
-  for(int i = 0; i < g_settings.m_ResInfo.size(); i++)
-  {
-    RESOLUTION_INFO res = g_settings.m_ResInfo[i];
-
-    if(res.iWidth == searchWidth && res.iHeight == searchHeight && (res.dwFlags & searchMode))
-    {
-      return true;
-    }
-  }
-
-  return bFound;
-}
-
-bool CWinSystemGLES::ClampToGUIDisplayLimits(int &width, int &height)
-{
-  return m_eglplatform->ClampToGUIDisplayLimits(width, height);
-}
-
-
-#endif
diff --git a/xbmc/windowing/egl/WinSystemGLES.h b/xbmc/windowing/egl/WinSystemGLES.h
deleted file mode 100644 (file)
index abbe3c6..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-#ifndef WINDOW_SYSTEM_EGLGLES_H
-#define WINDOW_SYSTEM_EGLGLES_H
-
-#pragma once
-
-/*
- *      Copyright (C) 2011-2012 Team XBMC
- *      http://www.xbmc.org
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with XBMC; see the file COPYING.  If not, see
- *  <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "rendering/gles/RenderSystemGLES.h"
-#include "utils/GlobalsHandling.h"
-#include "windowing/egl/WinEGLPlatform.h"
-#include "windowing/WinSystem.h"
-
-class CWinSystemGLES : public CWinSystemBase, public CRenderSystemGLES
-{
-public:
-  CWinSystemGLES();
-  virtual ~CWinSystemGLES();
-
-  virtual bool  InitWindowSystem();
-  virtual bool  DestroyWindowSystem();
-  virtual bool  CreateNewWindow(const CStdString& name, bool fullScreen, RESOLUTION_INFO& res, PHANDLE_EVENT_FUNC userFunction);
-  virtual bool  DestroyWindow();
-  virtual bool  ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop);
-  virtual bool  SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays);
-  virtual void  UpdateResolutions();
-  virtual bool  IsExtSupported(const char* extension);
-
-  virtual void  ShowOSMouse(bool show);
-  virtual bool  HasCursor();
-
-  virtual void  NotifyAppActiveChange(bool bActivated);
-
-  virtual bool  Minimize();
-  virtual bool  Restore() ;
-  virtual bool  Hide();
-  virtual bool  Show(bool raise = true);
-
-  EGLDisplay    GetEGLDisplay();
-  EGLContext    GetEGLContext();
-  virtual bool  Support3D(int width, int height, uint32_t mode)     const;
-  virtual bool  ClampToGUIDisplayLimits(int &width, int &height);
-
-protected:
-  virtual bool  PresentRenderImpl(const CDirtyRegionList &dirty);
-  virtual void  SetVSyncImpl(bool enable);
-  void                  *m_display;
-  EGLNativeWindowType   m_window;
-  CWinEGLPlatform       *m_eglplatform;
-  int                   m_nScreenWidth;
-  int                   m_nScreenHeight;
-};
-
-XBMC_GLOBAL_REF(CWinSystemGLES,g_Windowing);
-#define g_Windowing XBMC_GLOBAL_USE(CWinSystemGLES)
-
-#endif // WINDOW_SYSTEM_EGLGLES_H
index 6cbe81c..89e08b8 100644 (file)
 #include "interfaces/python/XBPython.h"
 #endif
 #include "interfaces/Builtins.h"
+#include "dialogs/GUIDialogMediaFilter.h"
+#include "filesystem/SmartPlaylistDirectory.h"
 #if defined(TARGET_ANDROID)
 #include "xbmc/android/activity/XBMCApp.h"
 #endif
 
-#define CONTROL_BTNVIEWASICONS     2
-#define CONTROL_BTNSORTBY          3
-#define CONTROL_BTNSORTASC         4
-#define CONTROL_BTN_FILTER        19
+#define CONTROL_BTNVIEWASICONS       2
+#define CONTROL_BTNSORTBY            3
+#define CONTROL_BTNSORTASC           4
+#define CONTROL_BTN_FILTER          19
 
-#define CONTROL_LABELFILES        12
+#define CONTROL_LABELFILES          12
 
 using namespace std;
 using namespace ADDON;
@@ -87,6 +89,7 @@ CGUIMediaWindow::CGUIMediaWindow(int id, const char *xmlFile)
   m_vecItems->SetPath("?");
   m_iLastControl = -1;
   m_iSelectedItem = -1;
+  m_canFilterAdvanced = false;
 
   m_guiState.reset(CGUIViewState::GetViewState(GetID(), *m_vecItems));
 }
@@ -175,6 +178,9 @@ bool CGUIMediaWindow::OnAction(const CAction &action)
   if (CGUIWindow::OnAction(action))
     return true;
 
+  if (action.GetID() == ACTION_FILTER)
+    return Filter();
+
   // live filtering
   if (action.GetID() == ACTION_FILTER_CLEAR)
   {
@@ -226,6 +232,13 @@ bool CGUIMediaWindow::OnMessage(CGUIMessage& message)
       CGUIDialogContextMenu* pDlg = (CGUIDialogContextMenu*)g_windowManager.GetWindow(WINDOW_DIALOG_CONTEXT_MENU);
       if (pDlg && pDlg->IsActive())
         pDlg->Close();
+
+      // get rid of any active filtering
+      if (m_canFilterAdvanced)
+      {
+        m_canFilterAdvanced = false;
+        m_filter.Reset();
+      }
       
       // Call ClearFileItems() after our window has finished doing any WindowClose
       // animations
@@ -273,22 +286,10 @@ bool CGUIMediaWindow::OnMessage(CGUIMessage& message)
       }
       else if (iControl == CONTROL_BTN_FILTER)
       {
-        if (GetControl(iControl)->GetControlType() == CGUIControl::GUICONTROL_EDIT)
-        { // filter updated
-          CGUIMessage selected(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_BTN_FILTER);
-          OnMessage(selected);
-          OnFilterItems(selected.GetLabel());
+        if (m_canFilterAdvanced)
           return true;
-        }
-        if (GetProperty("filter").empty())
-        {
-          CStdString filter = GetProperty("filter").asString();
-          CGUIKeyboardFactory::ShowAndGetFilter(filter, false);
-          SetProperty("filter", filter);
-        }
-        else
-          OnFilterItems("");
-        return true;
+
+        return Filter();
       }
       else if (m_viewControl.HasControl(iControl))  // list/thumb control
       {
@@ -415,16 +416,21 @@ bool CGUIMediaWindow::OnMessage(CGUIMessage& message)
       }
       else if (message.GetParam1() == GUI_MSG_FILTER_ITEMS && IsActive())
       {
-        CStdString filter(GetProperty("filter").asString());
-        if (message.GetParam2() == 1) // append
-          filter += message.GetStringParam();
-        else if (message.GetParam2() == 2)
-        { // delete
-          if (filter.size())
-            filter = filter.Left(filter.size() - 1);
+        CStdString filter;
+        // check if this is meant for advanced filtering
+        if (message.GetParam2() != 10)
+        {
+          filter = GetProperty("filter").asString();
+          if (message.GetParam2() == 1) // append
+            filter += message.GetStringParam();
+          else if (message.GetParam2() == 2)
+          { // delete
+            if (filter.size())
+              filter = filter.Left(filter.size() - 1);
+          }
+          else
+            filter = message.GetStringParam();
         }
-        else
-          filter = message.GetStringParam();
         OnFilterItems(filter);
         return true;
       }
@@ -561,10 +567,8 @@ void CGUIMediaWindow::UpdateButtons()
   items.Format("%i %s", m_vecItems->GetObjectCount(), g_localizeStrings.Get(127).c_str());
   SET_CONTROL_LABEL(CONTROL_LABELFILES, items);
 
-  //#ifdef PRE_SKIN_VERSION_3
-  SET_CONTROL_SELECTED(GetID(),CONTROL_BTN_FILTER, !GetProperty("filter").empty());
-  SET_CONTROL_LABEL2(CONTROL_BTN_FILTER, GetProperty("filter").asString());
-  //#endif
+  if (!m_canFilterAdvanced)
+    SET_CONTROL_LABEL2(CONTROL_BTN_FILTER, GetProperty("filter").asString());
 }
 
 void CGUIMediaWindow::ClearFileItems()
@@ -637,7 +641,7 @@ bool CGUIMediaWindow::GetDirectory(const CStdString &strDirectory, CFileItemList
   if (items.Size())
     items.Clear();
 
-  CStdString strParentPath=m_history.GetParentPath();
+  CStdString strParentPath = m_history.GetParentPath();
 
   CLog::Log(LOGDEBUG,"CGUIMediaWindow::GetDirectory (%s)", strDirectory.c_str());
   CLog::Log(LOGDEBUG,"  ParentPath = [%s]", strParentPath.c_str());
@@ -700,6 +704,8 @@ bool CGUIMediaWindow::GetDirectory(const CStdString &strDirectory, CFileItemList
 
   // clear the filter
   SetProperty("filter", "");
+  m_canFilterAdvanced = false;
+  m_filter.Reset();
   return true;
 }
 
@@ -723,10 +729,10 @@ bool CGUIMediaWindow::Update(const CStdString &strDirectory)
       GetDirectoryHistoryString(pItem.get(), strSelectedItem);
     }
   }
+  
+  CStdString strCurrentDirectory = m_vecItems->GetPath();
 
-  CStdString strOldDirectory = m_vecItems->GetPath();
-
-  m_history.SetSelectedItem(strSelectedItem, strOldDirectory);
+  m_history.SetSelectedItem(strSelectedItem, strCurrentDirectory);
 
   CFileItemList items;
   if (!GetDirectory(strDirectory, items))
@@ -734,7 +740,7 @@ bool CGUIMediaWindow::Update(const CStdString &strDirectory)
     CLog::Log(LOGERROR,"CGUIMediaWindow::GetDirectory(%s) failed", strDirectory.c_str());
     // if the directory is the same as the old directory, then we'll return
     // false.  Else, we assume we can get the previous directory
-    if (strDirectory.Equals(strOldDirectory))
+    if (strDirectory.Equals(strCurrentDirectory))
       return false;
 
     // We assume, we can get the parent
@@ -781,6 +787,11 @@ bool CGUIMediaWindow::Update(const CStdString &strDirectory)
   }
   m_iLastControl = GetFocusedControlID();
 
+  // Check whether to enabled advanced filtering based on the content type
+  m_canFilterAdvanced = CheckFilterAdvanced(*m_vecItems);
+  if (m_canFilterAdvanced)
+    m_filter.SetType(m_vecItems->GetContent());
+
   //  Ask the derived class if it wants to load additional info
   //  for the fileitems like media info or additional
   //  filtering on the items, setting thumbs.
@@ -943,6 +954,13 @@ bool CGUIMediaWindow::OnClick(int iItem)
     if (!items.AlwaysCache())
       items.RemoveDiscCache(GetID());
 
+    // if we have a filtered list, we need to add the filtered
+    // path to be able to come back to the filtered view
+    CStdString strCurrentDirectory = m_vecItems->GetPath();
+    if (m_canFilterAdvanced && !m_filter.IsEmpty() &&
+        !m_unfilteredItems->GetPath().Equals(strCurrentDirectory))
+      m_history.AddPath(strCurrentDirectory);
+
     CFileItem directory(*pItem);
     if (!Update(directory.GetPath()))
       ShowShareErrorMessage(&directory);
@@ -1095,7 +1113,6 @@ void CGUIMediaWindow::GoParentFolder()
 
   // if vector is not empty, pop parent
   // if vector is empty, parent is root source listing
-  CStdString strOldPath(m_vecItems->GetPath());
   strParent = m_history.RemoveParentPath();
   Update(strParent);
 }
@@ -1543,7 +1560,34 @@ void CGUIMediaWindow::OnFilterItems(const CStdString &filter)
   {
     m_vecItems->ClearItems();
     m_vecItems->Append(items);
-    SetProperty("filter", filter);
+
+    if (!m_canFilterAdvanced)
+      SetProperty("filter", filter);
+    else
+    {
+      m_vecItems->SetPath(items.GetPath());
+
+      // to be able to select the same item as before we need to adjust
+      // the path of the item i.e. add or remove the "filter=" URL option
+      CURL curUrl(currentItem), newUrl(items.GetPath());
+      CUrlOptions curOptions(curUrl.GetOptions()), newOptions(newUrl.GetOptions());
+
+      if (newOptions.HasOption("filter"))
+      {
+        CVariant filter;
+        if (newOptions.GetOption("filter", filter) && filter.isString())
+          curOptions.AddOption("filter", filter.asString());
+      }
+      else if (curOptions.HasOption("filter"))
+        curOptions.AddOption("filter", "");
+
+      string options = curOptions.GetOptionsString();
+      if (!options.empty())
+        curUrl.SetOptions("?" + options);
+      else
+        curUrl.SetOptions("");
+      currentItem = curUrl.Get();
+    }
   }
   
   // and update our view control + buttons
@@ -1554,6 +1598,12 @@ void CGUIMediaWindow::OnFilterItems(const CStdString &filter)
 
 bool CGUIMediaWindow::GetFilteredItems(const CStdString &filter, CFileItemList &items)
 {
+  if (m_canFilterAdvanced)
+  {
+    bool hasNewItems;
+    return GetAdvanceFilteredItems(items, hasNewItems);
+  }
+
   CStdString trimmedFilter(filter);
   trimmedFilter.TrimLeft().ToLower();
   
@@ -1593,7 +1643,120 @@ bool CGUIMediaWindow::GetFilteredItems(const CStdString &filter, CFileItemList &
 
   items.ClearItems();
   items.Append(filteredItems);
-  return (items.GetObjectCount() > 0);
+
+  return items.GetObjectCount() > 0;
+}
+
+bool CGUIMediaWindow::GetAdvanceFilteredItems(CFileItemList &items, bool &hasNewItems)
+{
+  hasNewItems = false;
+
+  // don't run the advanced filter if the filter is empty
+  // and there hasn't been a filter applied before which
+  // would have to be removed
+  CURL url(m_vecItems->GetPath());
+  CUrlOptions urlOptions(url.GetOptions());
+  if (m_filter.IsEmpty() && !urlOptions.HasOption("filter"))
+    return true;
+
+  CFileItemList resultItems;
+  XFILE::CSmartPlaylistDirectory::GetDirectory(m_filter, resultItems, m_vecItems->GetPath(), true);
+
+  // put together a lookup map for faster path comparison
+  map<CStdString, CFileItemPtr> lookup;
+  for (int j = 0; j < resultItems.Size(); j++)
+  {
+    CStdString itemPath = resultItems[j]->GetPath();
+    size_t pos = itemPath.find('?');
+    if (pos != string::npos)
+      itemPath.erase(pos);
+    itemPath.ToLower();
+
+    lookup[itemPath] = resultItems[j];
+  }
+
+  // loop through all the original items and find
+  // those which are still part of the filter
+  CFileItemList filteredItems;
+  for (int i = 0; i < items.Size(); i++)
+  {
+    CFileItemPtr item = items.Get(i);
+    if (item->IsParentFolder())
+    {
+      filteredItems.Add(item);
+      continue;
+    }
+
+    // check if the item is part of the resultItems list
+    // by comparing their paths (but ignoring any special
+    // options because they differ from filter to filter)
+    CStdString path = item->GetPath();
+    size_t pos = path.find('?');
+    if (pos != string::npos)
+      path.erase(pos);
+    path.ToLower();
+
+    map<CStdString, CFileItemPtr>::iterator itItem = lookup.find(path);
+    if (itItem != lookup.end())
+    {
+      // we need to copy the path of the filtered
+      // item to be able to keep the applied filters
+      item->SetPath(itItem->second->GetPath());
+
+      // add the item to the list of filtered items
+      filteredItems.Add(item);
+
+      // remove the item from the lists
+      resultItems.Remove(itItem->second.get());
+      lookup.erase(itItem);
+    }
+  }
+
+  if (resultItems.Size() > 0)
+  {
+    filteredItems.Append(resultItems);
+    hasNewItems = true;
+  }
+
+  items.ClearItems();
+  items.Append(filteredItems);
+  items.SetPath(resultItems.GetPath());
+  return true;
+}
+
+bool CGUIMediaWindow::IsFiltered()
+{
+  return (!m_canFilterAdvanced && !GetProperty("filter").empty()) ||
+         (m_canFilterAdvanced && !m_filter.IsEmpty());
+}
+
+bool CGUIMediaWindow::Filter()
+{
+  // basic filtering
+  if (!m_canFilterAdvanced)
+  {
+    const CGUIControl *btnFilter = GetControl(CONTROL_BTN_FILTER);
+    if (btnFilter != NULL && btnFilter->GetControlType() == CGUIControl::GUICONTROL_EDIT)
+    { // filter updated
+      CGUIMessage selected(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_BTN_FILTER);
+      OnMessage(selected);
+      OnFilterItems(selected.GetLabel());
+      return true;
+    }
+    if (GetProperty("filter").empty())
+    {
+      CStdString filter = GetProperty("filter").asString();
+      CGUIKeyboardFactory::ShowAndGetFilter(filter, false);
+      SetProperty("filter", filter);
+    }
+    else
+      OnFilterItems("");
+  }
+  // advanced filtering
+  else
+    CGUIDialogMediaFilter::ShowAndEditMediaFilter(m_vecItems->GetPath(), m_filter);
+
+  return true;
 }
 
 CStdString CGUIMediaWindow::GetStartFolder(const CStdString &dir)
index 4421aff..8dc7521 100644 (file)
@@ -25,6 +25,7 @@
 #include "filesystem/DirectoryHistory.h"
 #include "GUIViewControl.h"
 #include "dialogs/GUIDialogContextMenu.h"
+#include "playlists/SmartPlayList.h"
 
 class CFileItemList;
 
@@ -47,6 +48,9 @@ public:
   virtual CFileItemPtr GetCurrentListItem(int offset = 0);
   const CGUIViewState *GetViewState() const;
 
+  virtual bool CanFilterAdvanced() { return m_canFilterAdvanced; }
+  virtual bool IsFiltered();
+
 protected:
   virtual void LoadAdditionalTags(TiXmlElement *root);
   CGUIControl *GetFirstFocusableControl(int id);
@@ -73,6 +77,9 @@ protected:
   void ClearFileItems();
   virtual void SortItems(CFileItemList &items);
 
+  virtual bool CheckFilterAdvanced(CFileItemList &items) { return false; }
+  virtual bool Filter();
+
   /* \brief Called on response to a GUI_MSG_FILTER_ITEMS message
    Filters the current list with the given filter using FilterItems()
    \param filter the filter to use.
@@ -87,6 +94,14 @@ protected:
    */
   virtual bool GetFilteredItems(const CStdString &filter, CFileItemList &items);
 
+  /* \brief Retrieve the advance filtered item list
+  \param items CFileItemList to filter
+  \param hasNewItems Whether the filtered item list contains new items
+                     which were not present in the original list
+  \sa GetFilteredItems
+  */
+  virtual bool GetAdvanceFilteredItems(CFileItemList &items, bool &hasNewItems);
+
   // check for a disc or connection
   virtual bool HaveDiscOrConnection(const CStdString& strPath, int iDriveType);
   void ShowShareErrorMessage(CFileItem* pItem);
@@ -121,4 +136,7 @@ protected:
   int m_iLastControl;
   int m_iSelectedItem;
   CStdString m_startDirectory;
+
+  CSmartPlaylist m_filter;
+  bool m_canFilterAdvanced;
 };
index 3fe7fc5..9dc4033 100644 (file)
@@ -511,7 +511,7 @@ bool CGUIWindowFileManager::Update(int iList, const CStdString &strDirectory)
   {
     CFileItemPtr pItem(new CFileItem("special://profile/", true));
     pItem->SetLabel(g_localizeStrings.Get(20070));
-    pItem->SetThumbnailImage("DefaultFolder.png");
+    pItem->SetArt("thumb", "DefaultFolder.png");
     pItem->SetLabelPreformated(true);
     m_vecItems[iList]->Add(pItem);
   }
@@ -524,7 +524,7 @@ bool CGUIWindowFileManager::Update(int iList, const CStdString &strDirectory)
     URIUtils::GetExtension(pItem->GetPath(), strExtension);
     if (pItem->IsHD() && strExtension == ".tbn")
     {
-      pItem->SetThumbnailImage(pItem->GetPath());
+      pItem->SetArt("thumb", pItem->GetPath());
     }
   }
   m_vecItems[iList]->FillInDefaultIcons();
@@ -906,6 +906,8 @@ bool CGUIWindowFileManager::CanCopy(int iList)
   // can't copy if the destination is not writeable, or if the source is a share!
   // TODO: Perhaps if the source is removeable media (DVD/CD etc.) we could
   // put ripping/backup in here.
+  if (!CUtil::SupportsReadFileOperations(m_Directory[iList]->GetPath())) return false;
+  if (m_Directory[iList]->IsVirtualDirectoryRoot()) return false;
   if (m_Directory[1 - iList]->IsVirtualDirectoryRoot()) return false;
   if (m_Directory[iList]->IsVirtualDirectoryRoot()) return false;
   if (m_Directory[1 -iList]->IsReadOnly()) return false;
index 1cdfb16..0455b3a 100644 (file)
@@ -198,9 +198,9 @@ void CGUIWindowLoginScreen::Update()
     else
       strLabel.Format(g_localizeStrings.Get(20112), profile->getDate());
     item->SetLabel2(strLabel);
-    item->SetThumbnailImage(profile->getThumb());
+    item->SetArt("thumb", profile->getThumb());
     if (profile->getThumb().IsEmpty() || profile->getThumb().Equals("-"))
-      item->SetThumbnailImage("unknown-user.png");
+      item->SetArt("thumb", "unknown-user.png");
     item->SetLabelPreformated(true);
     m_vecItems->Add(item);
   }