def __init__(self, parent, logger, smoothScaling, minOpacity, maxOpacity):
        super(RemotePicturesGui, self).__init__(parent)
        
        self.logger = logger
        self.good = True
        self.settings = None
        self.categoryPictures = {}
        self.currentCategory = None
        self.curPicIndex = 0
        self.categoryModel = CategoriesModel(logger)
        self.sortProxy = None
        
        self.categoryView = QListView(self)
        self.categoryView.setViewMode(QListView.IconMode);
        self.categoryView.setIconSize(QSize(200,200));
        self.categoryView.setResizeMode(QListView.Adjust);
        self.categoryView.doubleClicked.connect(self._itemDoubleClicked)
        self.categoryView.setFrameShape(QFrame.NoFrame)
        
        self.sortProxy = QSortFilterProxyModel(self)
        self.sortProxy.setSortCaseSensitivity(Qt.CaseInsensitive)
        self.sortProxy.setSortRole(CategoriesModel.SORT_ROLE)
        self.sortProxy.setDynamicSortFilter(True)
        self.sortProxy.setSourceModel(self.categoryModel)
        self.sortProxy.sort(0)
        self.categoryView.setModel(self.sortProxy)

        self.addWidget(self.categoryView)
        
        self.imageLabel = ResizingWebImageLabel(self, self.logger, smooth_scaling=smoothScaling)
        self.imageLabel.imageDownloaded.connect(self.pictureDownloadedSlot)
        self.imageLabel.setContextMenuPolicy(Qt.CustomContextMenu)
        self.imageLabel.customContextMenuRequested.connect(self._showImageContextMenu)
        imageViewerLayout = QVBoxLayout(self.imageLabel)
        imageViewerLayout.setContentsMargins(0, 0, 0, 0)
        imageViewerLayout.setSpacing(0)
        
        defaultFont = self.font()
        self.categoryLabel = HiddenLabel(self.imageLabel, self.logger, fontSize=16, fontOptions=QFont.Bold)
        topLayout = QHBoxLayout(self.categoryLabel)
        topLayout.setContentsMargins(0, 0, 0, 0)
        backButton = QToolButton(self.categoryLabel)
        backButton.setFont(QFont(defaultFont.family(), defaultFont.pointSize(), 0))
        backButton.setFocusPolicy(Qt.NoFocus)
        backButton.setArrowType(Qt.LeftArrow)
        backButton.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        backButton.setText("Categories")
        topLayout.addWidget(backButton, 0, Qt.AlignLeft)
        imageViewerLayout.addWidget(self.categoryLabel, 0)
        
        navButtonsWidget = QWidget(self.imageLabel)
        navButtonsLayout = QHBoxLayout(navButtonsWidget)
        navButtonsLayout.setContentsMargins(0, 0, 0, 0)
        
        self.prevButton = HiddenToolButton(self.imageLabel, self.logger)
        self.prevButton.setArrowType(Qt.LeftArrow)
        self.prevButton.setEnabled(False)
        self.prevButton.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.MinimumExpanding)
        navButtonsLayout.addWidget(self.prevButton, 0, Qt.AlignLeft)
        
        self.nextButton = HiddenToolButton(self.imageLabel, self.logger)
        self.nextButton.setArrowType(Qt.RightArrow)
        self.nextButton.setEnabled(False)
        self.nextButton.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.MinimumExpanding)
        navButtonsLayout.addWidget(self.nextButton, 0, Qt.AlignRight)
        
        imageViewerLayout.addWidget(navButtonsWidget, 1)
        
        self.descriptionLabel = HiddenLabel(self.imageLabel, self.logger, fontSize=14)
        self.descriptionLabel.setWordWrap(True)
        imageViewerLayout.addWidget(self.descriptionLabel, 0)
                
        self.addWidget(self.imageLabel)
        
        self.nextButton.clicked.connect(self._displayNextImage)
        self.prevButton.clicked.connect(self._displayPreviousImage)
        backButton.clicked.connect(partial(self.setCurrentIndex, 0))
        self._initializeHiddenWidget(self.categoryLabel)
        self._initializeHiddenWidget(self.prevButton)
        self._initializeHiddenWidget(self.nextButton)
        self._initializeHiddenWidget(self.descriptionLabel)
        
        self.minOpacityChanged.emit(float(minOpacity) / 100.)
        self.maxOpacityChanged.emit(float(maxOpacity) / 100.)
class RemotePicturesGui(QStackedWidget):
    openCategory = pyqtSignal(object) # category
    displayNext = pyqtSignal(object, int) # current category, current ID
    displayPrev = pyqtSignal(object, int) # current category, current ID
    pictureDownloaded = pyqtSignal(object, object, object) # current category, url, pic data
    
    minOpacityChanged = pyqtSignal(float)
    maxOpacityChanged = pyqtSignal(float)
    
    setCategoryThumbnail = pyqtSignal(object, QImage) # category, thumbnail pixmap
    
    _categoryOpened = pyqtSignal() # used to flash hidden widgets
    
    def __init__(self, parent, logger, smoothScaling, minOpacity, maxOpacity):
        super(RemotePicturesGui, self).__init__(parent)
        
        self.logger = logger
        self.good = True
        self.settings = None
        self.categoryPictures = {}
        self.currentCategory = None
        self.curPicIndex = 0
        self.categoryModel = CategoriesModel(logger)
        self.sortProxy = None
        
        self.categoryView = QListView(self)
        self.categoryView.setViewMode(QListView.IconMode);
        self.categoryView.setIconSize(QSize(200,200));
        self.categoryView.setResizeMode(QListView.Adjust);
        self.categoryView.doubleClicked.connect(self._itemDoubleClicked)
        self.categoryView.setFrameShape(QFrame.NoFrame)
        
        self.sortProxy = QSortFilterProxyModel(self)
        self.sortProxy.setSortCaseSensitivity(Qt.CaseInsensitive)
        self.sortProxy.setSortRole(CategoriesModel.SORT_ROLE)
        self.sortProxy.setDynamicSortFilter(True)
        self.sortProxy.setSourceModel(self.categoryModel)
        self.sortProxy.sort(0)
        self.categoryView.setModel(self.sortProxy)

        self.addWidget(self.categoryView)
        
        self.imageLabel = ResizingWebImageLabel(self, self.logger, smooth_scaling=smoothScaling)
        self.imageLabel.imageDownloaded.connect(self.pictureDownloadedSlot)
        self.imageLabel.setContextMenuPolicy(Qt.CustomContextMenu)
        self.imageLabel.customContextMenuRequested.connect(self._showImageContextMenu)
        imageViewerLayout = QVBoxLayout(self.imageLabel)
        imageViewerLayout.setContentsMargins(0, 0, 0, 0)
        imageViewerLayout.setSpacing(0)
        
        defaultFont = self.font()
        self.categoryLabel = HiddenLabel(self.imageLabel, self.logger, fontSize=16, fontOptions=QFont.Bold)
        topLayout = QHBoxLayout(self.categoryLabel)
        topLayout.setContentsMargins(0, 0, 0, 0)
        backButton = QToolButton(self.categoryLabel)
        backButton.setFont(QFont(defaultFont.family(), defaultFont.pointSize(), 0))
        backButton.setFocusPolicy(Qt.NoFocus)
        backButton.setArrowType(Qt.LeftArrow)
        backButton.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        backButton.setText("Categories")
        topLayout.addWidget(backButton, 0, Qt.AlignLeft)
        imageViewerLayout.addWidget(self.categoryLabel, 0)
        
        navButtonsWidget = QWidget(self.imageLabel)
        navButtonsLayout = QHBoxLayout(navButtonsWidget)
        navButtonsLayout.setContentsMargins(0, 0, 0, 0)
        
        self.prevButton = HiddenToolButton(self.imageLabel, self.logger)
        self.prevButton.setArrowType(Qt.LeftArrow)
        self.prevButton.setEnabled(False)
        self.prevButton.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.MinimumExpanding)
        navButtonsLayout.addWidget(self.prevButton, 0, Qt.AlignLeft)
        
        self.nextButton = HiddenToolButton(self.imageLabel, self.logger)
        self.nextButton.setArrowType(Qt.RightArrow)
        self.nextButton.setEnabled(False)
        self.nextButton.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.MinimumExpanding)
        navButtonsLayout.addWidget(self.nextButton, 0, Qt.AlignRight)
        
        imageViewerLayout.addWidget(navButtonsWidget, 1)
        
        self.descriptionLabel = HiddenLabel(self.imageLabel, self.logger, fontSize=14)
        self.descriptionLabel.setWordWrap(True)
        imageViewerLayout.addWidget(self.descriptionLabel, 0)
                
        self.addWidget(self.imageLabel)
        
        self.nextButton.clicked.connect(self._displayNextImage)
        self.prevButton.clicked.connect(self._displayPreviousImage)
        backButton.clicked.connect(partial(self.setCurrentIndex, 0))
        self._initializeHiddenWidget(self.categoryLabel)
        self._initializeHiddenWidget(self.prevButton)
        self._initializeHiddenWidget(self.nextButton)
        self._initializeHiddenWidget(self.descriptionLabel)
        
        self.minOpacityChanged.emit(float(minOpacity) / 100.)
        self.maxOpacityChanged.emit(float(maxOpacity) / 100.)
    
    def getCategoryIcon(self, cat):
        return self.categoryModel.getCategoryIcon(cat)
        
    @loggingSlot(QPoint)
    def _showImageContextMenu(self, _point):
        pixmap = self.imageLabel.getRawPixmap()
        if pixmap is None or pixmap.isNull():
            return
        m = QMenu()
        m.addAction(u"Set as category thumbnail", self._setCurrentPictureAsThumbnail)
        m.exec_(QCursor.pos())
        m.deleteLater()
        
    @loggingSlot()
    def _setCurrentPictureAsThumbnail(self):
        if self.currentCategory is None:
            self.logger.error("Current category is None")
            return
        pixmap = self.imageLabel.getRawPixmap()
        if pixmap is None or pixmap.isNull():
            self.logger.warning("NULL pixmap")
            return
        image = pixmap.toImage()
        if image.isNull():
            self.logger.error("Error converting pixmap to image")
            return
        self.setCategoryThumbnail.emit(self.currentCategory, image)
        
    def _initializeHiddenWidget(self, w):
        self._categoryOpened.connect(w.showTemporarily)
        self.minOpacityChanged.connect(w.setMinOpacity)
        self.maxOpacityChanged.connect(w.setMaxOpacity)

    @loggingSlot(QModelIndex)
    def _itemDoubleClicked(self, index):
        index = self.sortProxy.mapToSource(index)
        item = self.categoryModel.item(index.row())
        cat = item.data(CategoriesModel.CAT_ROLE).toString()
        self.openCategory.emit(cat)
        
    def _deactivateButtons(self):
        self.nextButton.setEnabled(False)
        self.prevButton.setEnabled(False)
        
    @loggingSlot()
    def _displayNextImage(self):
        self._deactivateButtons()
        self.displayNext.emit(self.currentCategory, self.curPicIndex)
    
    @loggingSlot()
    def _displayPreviousImage(self):
        self._deactivateButtons()
        self.displayPrev.emit(self.currentCategory, self.curPicIndex)
    
    @loggingSlot(object, int, list, bool, bool)
    def displayImage(self, cat, picID, picRow, hasPrev, hasNext):
        cat = convert_string(cat)
        picURL = convert_string(picRow[RemotePicturesStorage.PIC_URL_COL])
        picFile = convert_string(picRow[RemotePicturesStorage.PIC_FILE_COL])
        picDesc = convert_string(picRow[RemotePicturesStorage.PIC_DESC_COL])
        if picDesc is None:
            picDesc = u""
        picSender = convert_string(picRow[RemotePicturesStorage.PIC_SENDER_COL])
        picTime = picRow[RemotePicturesStorage.PIC_ADDED_COL]
        
        self.currentCategory = cat
        self.categoryLabel.setText(cat)
        
        self.curPicIndex = picID
        if picFile and os.path.exists(picFile):
            self.imageLabel.setImage(picFile)
        elif picURL:
            self.imageLabel.setURL(picURL)
        else:
            self.logger.warning("No image source specified")
            self.imageLabel.displayFallbackPic()
        
        if picSender:
            self.imageLabel.setToolTip(u"Sent to you by %s,\nSent %s" % (get_peers().getDisplayedPeerName(pID=picSender),
                                                                         formatTime(localtime(picTime))))
        else:
            self.imageLabel.setToolTip(u"")
            
        self.descriptionLabel.setText(picDesc)
        self.setCurrentIndex(1)
        
        self.prevButton.setEnabled(hasPrev)
        self.nextButton.setEnabled(hasNext)
        
        self._categoryOpened.emit()
    
    def thumbnailSizeChanged(self, newValue):
        self.categoryModel.thumbnailSizeChanged(newValue)
        
    def setSmoothScaling(self, newValue):
        self.imageLabel.setSmoothScaling(newValue)
        
    def isShowingCategory(self, category):
        return self.currentIndex() == 1 and category == self.currentCategory
        
    def destroyWidget(self):
        pass
    
    @loggingSlot(object, object)
    def pictureDownloadedSlot(self, url, picData):
        if self.currentCategory is not None:
            self.pictureDownloaded.emit(self.currentCategory, url, picData)